I am working on radio app using Exoplayer. In case of this podcast the Exoplayer throws SSLHandshakeException.
To fix this I tried:
1. Update security provider with Provider installer by calling ProviderInstaller.installIfNeededAsync
.
public class MainActivity extends Activity
implements ProviderInstaller.ProviderInstallListener {
private static final int ERROR_DIALOG_REQUEST_CODE = 1;
private boolean mRetryProviderInstall;
//Update the security provider when the activity is created.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ProviderInstaller.installIfNeededAsync(this, this);
}
/**
* This method is only called if the provider is successfully
updated (or is already up-to-date).
*/
@Override
protected void onProviderInstalled() {
// Provider is up-to-date, app can make secure network calls.
}
/**
* This method is called if updating fails; the error code indicates
* whether the error is recoverable.
*/
@Override
protected void onProviderInstallFailed(int errorCode, Intent recoveryIntent) {
GoogleApiAvailability availability = GoogleApiAvailability.getInstance();
if (availability.isUserRecoverableError(errorCode)) {
// Recoverable error. Show a dialog prompting the user to
// install/update/enable Google Play services.
availability.showErrorDialogFragment(
this,
errorCode,
ERROR_DIALOG_REQUEST_CODE,
new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
// The user chose not to take the recovery action
onProviderInstallerNotAvailable();
}
});
} else {
// Google Play services is not available.
onProviderInstallerNotAvailable();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ERROR_DIALOG_REQUEST_CODE) {
// Adding a fragment via GoogleApiAvailability.showErrorDialogFragment
// before the instance state is restored throws an error. So instead,
// set a flag here, which will cause the fragment to delay until
// onPostResume.
mRetryProviderInstall = true;
}
}
/**
* On resume, check to see if we flagged that we need to reinstall the provider.
*/
@Override
protected void onPostResume() {
super.onPostResume();
if (mRetryProviderInstall) {
// We can now safely retry installation.
ProviderInstaller.installIfNeededAsync(this, this);
}
mRetryProviderInstall = false;
}
private void onProviderInstallerNotAvailable() {
// This is reached if the provider cannot be updated for some reason.
// App should consider all HTTP communication to be vulnerable,
// and take appropriate action.
}
}
2. Replace https to http
In this case, Exoplayer throws an Exception with error code 308 (redirection exception).
3. Use NetCipher instead of HttpUrlConnection by calling HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl)
like described here
4. Use NoSSLv3SocketFactory like described here
5. Disable SSL certificate Checking by calling
private static void disableSSLCertificateChecking() {
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
// Not implemented
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
// Not implemented
}
} };
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
6. Create customTrust
To get certificates I run the open ssl command:
OpenSSL> s_client -connect simplecast.com:443
7. Download the .crt file from here and as Google suggests run
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(new
FileInputStream("my_downloaded.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
8. Enable TLSv1.2 only using a code from here
The device that I use for testing is Samsung SM-t111 Android 4.2.2. It has google play services installed, but I am trying to fix the issue without using Google Play services because the client's device does not have it.
Please suggest what should be the working solution?