4
votes

I am trying an android app where an HLS link for my nginx server is passed to ExoPlayer to play. Initially I kept getting the

"Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found."

error after which on doing research I found two possible solutions.

The first being to follow the steps in https://knowledge.digicert.com/solution/SO17482.html to get an immediate CA certificate and the second being to disable certificate checks. I have attempted both but still get the

"Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found." error

The code for my player is:

public class PlayerActivity extends AppCompatActivity implements VideoRendererEventListener {

String url;

private static final String TAG = "Twende Live";
private PlayerView simpleExoPlayerView;
private SimpleExoPlayer player;
private TextView resolutionTextView;
private final TrustManager[] trustAllCerts= new TrustManager[] { new X509TrustManager() {
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return new java.security.cert.X509Certificate[]{};
    }

    public void checkClientTrusted(X509Certificate[] chain,
                                   String authType) throws CertificateException {
    }

    public void checkServerTrusted(X509Certificate[] chain,
                                   String authType) throws CertificateException {
    }
} };

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_player);

    //url = getIntent().getStringExtra("STREAM_URL");

    try {
        ProviderInstaller.installIfNeeded(getApplicationContext());
        SSLContext sslContext;
        sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, trustAllCerts, null);
        sslContext.createSSLEngine();
    } catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException
            | NoSuchAlgorithmException | KeyManagementException e) {
        e.printStackTrace();
    }

    Uri mp4VideoUri =Uri.parse(getIntent().getStringExtra("STREAM_URL"));

    DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(); //test

    TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
    TrackSelector trackSelector =
            new DefaultTrackSelector(videoTrackSelectionFactory);

    //create player
    player = ExoPlayerFactory.newSimpleInstance(this, trackSelector);
    simpleExoPlayerView = new SimpleExoPlayerView(this);
    simpleExoPlayerView = (SimpleExoPlayerView) findViewById(R.id.player_view);

    int h = simpleExoPlayerView.getResources().getConfiguration().screenHeightDp;
    int w = simpleExoPlayerView.getResources().getConfiguration().screenWidthDp;
    Log.v(TAG, "height : " + h + " weight: " + w);
    ////Set media controller
    simpleExoPlayerView.setUseController(false);//set to true or false to see controllers
    simpleExoPlayerView.requestFocus();
    // Bind the player to the view.
    simpleExoPlayerView.setPlayer(player);


    DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "Twende"), bandwidthMeter);

    MediaSource videoSource = new HlsMediaSource(mp4VideoUri, dataSourceFactory, 1, null, null);
    final LoopingMediaSource loopingSource = new LoopingMediaSource(videoSource);
    // Prepare the player with the source.
    player.prepare(videoSource);

    player.addListener(new ExoPlayer.EventListener() {


        @Override
        public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {

        }

        @Override
        public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
            Log.v(TAG, "Listener-onTracksChanged... ");
        }

        @Override
        public void onLoadingChanged(boolean isLoading) {

        }

        @Override
        public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
            Log.v(TAG, "Listener-onPlayerStateChanged..." + playbackState+"|||isDrawingCacheEnabled():"+simpleExoPlayerView.isDrawingCacheEnabled());
        }

        @Override
        public void onRepeatModeChanged(int repeatMode) {

        }

        @Override
        public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {

        }

        @Override
        public void onPlayerError(ExoPlaybackException error) {
            Log.v(TAG, "Listener-onPlayerError...");
            player.stop();
            player.prepare(loopingSource);
            player.setPlayWhenReady(true);
        }

        @Override
        public void onPositionDiscontinuity(int reason) {

        }

        @Override
        public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {

        }

        @Override
        public void onSeekProcessed() {

        }
    });
    player.setPlayWhenReady(true); //run file/link when ready to play.
    player.setVideoDebugListener(this);


}

@Override
public void onVideoEnabled(DecoderCounters counters) {

}

@Override
public void onVideoDecoderInitialized(String decoderName, long initializedTimestampMs, long initializationDurationMs) {

}

@Override
public void onVideoInputFormatChanged(Format format) {

}

@Override
public void onDroppedFrames(int count, long elapsedMs) {

}

@Override
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
    Log.v(TAG, "onVideoSizeChanged [" + " width: " + width + " height: " + height + "]");
    resolutionTextView.setText("RES:(WxH):" + width + "X" + height + "\n           " + height + "p");//shows video info
}

@Override
public void onRenderedFirstFrame(Surface surface) {

}

@Override
public void onVideoDisabled(DecoderCounters counters) {

}


@Override
protected void onStop() {
    super.onStop();
    Log.v(TAG, "onStop()...");
}

@Override
protected void onStart() {
    super.onStart();
    Log.v(TAG, "onStart()...");
}

@Override
protected void onResume() {
    super.onResume();
    Log.v(TAG, "onResume()...");
}

@Override
protected void onPause() {
    super.onPause();
    Log.v(TAG, "onPause()...");
}

@Override
protected void onDestroy() {
    super.onDestroy();
    Log.v(TAG, "onDestroy()...");
    player.release();
}
}

What am I doing wrong?

1
You are creating an SSLContext and an SSLEngine and throwing them both away. No wonder it doesn't work.user207421

1 Answers

6
votes

Try out below (Ignore certificate for HttpURLConnection):

//Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
    new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers()
        {
            return null;
        }
        public void checkClientTrusted(X509Certificate[] certs, String authType)
        {
            //
        }
        public void checkServerTrusted(X509Certificate[] certs, String authType)
        {
            //
        }
    }
};

//Install the all-trusting trust manager
try {
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (KeyManagementException|NoSuchAlgorithmException e) {
        e.printStackTrace();
}

OR if you are using retrofit+OkHttp and want to use secure (httpps) connection then create the trustStore file (.BKS file) and pass this to TrustManagerFactory. The TrustManager decides which certificate authorities to use.
See this https://stackoverflow.com/a/28785936/5685911 and https://developer.android.com/training/articles/security-ssl#java for more details.