我正在使用Exoplayer开发广播应用。 如果是this播客,则Exoplayer会抛出SSLHandshakeException。
要解决此问题,我尝试过:
1。通过调用 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。将https替换为http
在这种情况下,Exoplayer抛出异常,错误代码为308(重定向异常)。
3。通过像描述here
那样调用HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl)
来使用NetCipher 而不是HttpUrlConnection
4。使用here
中所述的NoSSLv3SocketFactory5。通过调用
禁用SSL证书检查 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。创建customTrust
要获取证书,我运行open ssl命令:
OpenSSL> s_client -connect simplecast.com:443
7。从here下载.crt文件,并按照Google的建议运行
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。使用here
中的代码仅启用TLSv1.2我用于测试的设备是Samsung SM-t111 Android 4.2.2。它已安装了Google Play服务,但由于客户端的设备没有安装此服务,因此我尝试不使用Google Play服务来解决此问题。
请提出什么可行的解决方案?
答案 0 :(得分:0)
就我而言,这是密码套件问题。要确定是否也是您的情况,您需要:
OpenSSL> s_client -connect YOUR_HOST_NAME.com:443
CN = COMODO RSA Certification Authority
Settings > Security > Trusted credentials > System
,然后检查证书颁发机构是否被列为受信任证书。 COMODO是众所周知的证书颁发机构,因此已在此处列出,这意味着问题不在证书中。Protocol : TLSv1.2
和Cipher : ECDHE-RSA-AES256-GCM-SHA384
密码套件是给定SSL连接使用的密码算法的组合。中 在协商过程中,服务器和客户端必须就双方都可用的密码套件达成协议 环境。客户端将支持的密码列表发送到服务器,服务器选择一个,然后 加密开始。如果没有这样的通用套件,则无法建立SSL连接,并且 没有数据可以交换。
YOUR_HOST_NAME.com
。要了解为什么未在其中列出Android 4.2,我发现了the list of all Cipher Suites supported by Android 4.2。我将服务器的密码套件与Android 4.2进行了比较,但我发现它们之间没有通用的密码套件。 我在official list of cipher suites supported by Android system中搜索TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,他们说对于API级别20+支持的此密码套件(实际上是API级别21-Android 5.0导致API级别20为KITKAT_WATCH)。
就我而言,如果没有适当的解决方案,则无法在客户端解决该问题 服务器配置。 2.无法使用HTTP而不是HTTPS,因为Podcast使用Proxy服务器,因为 其中,播客中没有最终链接。如果只是将HTTPS更改为HTTP 重定向前链接-exoplayer进入无限循环尝试打开连接。 3.在没有Google Play的设备上,我们无法更新支持的密码套件的列表。
如果可以在客户端解决不支持Google Play服务的Android设备上的密码套件问题,并且您知道如何在下方添加答案或发表评论。