错误: SSL握手已中止:ssl = 0x676a5680: SSL库中的失败,通常是协议错误
根据此Android doc,API 16+支持 TLS 1.1 和 1.2 ,但直到API 20+才默认启用。我找到了一些解决方案(here,here,here和here)来启用对OkHttp的TLS 1.1和1.2支持。如何为Exoplayer启用TLS 1.1 / 1.2支持?我发现唯一支持Exoplayer TLS 1.1 / 1.2的帖子来自此github issue,建议在此处提问。
“ 07-27 13:21:09.817 8925-9065 / com.ftsgps.monarch E / ExoPlayerImplInternal:源错误。 com.google.android.exoplayer2.upstream.HttpDataSource $ HttpDataSourceException: 无法连接到https://liveStream/LIVE-0089000D05/manifest.mpd 在 com.google.android.exoplayer2.upstream.DefaultHttpDataSource.open(DefaultHttpDataSource.java:194) 在 com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:147) 在 com.google.android.exoplayer2.upstream.DataSourceInputStream.checkOpened(DataSourceInputStream.java:102) 在 com.google.android.exoplayer2.upstream.DataSourceInputStream.open(DataSourceInputStream.java:65) 在 com.google.android.exoplayer2.upstream.ParsingLoadable.load(ParsingLoadable.java:129) 在 com.google.android.exoplayer2.upstream.Loader $ LoadTask.run(Loader.java:308) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 在 java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:587) 在java.lang.Thread.run(Thread.java:841)导致原因: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException:SSL握手已中止: ssl = 0x722c3af8:SSL库失败,通常是协议错误 错误:14077410:SSL例程:SSL23_GET_SERVER_HELLO:sslv3警报 握手失败(external / openssl / ssl / s23_clnt.c:744 0x689d8f10:0x00000000)“
仅在API 21版本(棒棒糖)以下才发生这种情况。服务器是 使用TLS1.2协议,Lollipop以下的Android不支持该协议 版本。
答案 0 :(得分:2)
DefaultHttpDataSource
使用HttpsURLConnection
,其中有一个默认值为SSLSocketFactory
的静态字段。除非在实例上调用HttpsURLConnection
,否则SSLSocketFactory
的所有新实例将分配此默认值setSSLSocketFactory()
。因此,从技术上讲,如果您在实例化SSLSocketFactory
之前在之前调用设置默认的DefaultHttpsDataSource
,
HttpsURLConnection.setDefaultSSLSocketFactory(new MyCustomSSLSocketFactory());
其中MyCustomSSLSocketFactoy
可能看起来像这样:
class MyCustomSSLSocketFactory extends SSLSocketFactory {
private javax.net.ssl.SSLSocketFactory internalSSLSocketFactory;
public MyCustomSSLSocketFactory () throws KeyManagementException, NoSuchAlgorithmException {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
internalSSLSocketFactory = context.getSocketFactory();
}
@Override
public String[] getDefaultCipherSuites() {
return internalSSLSocketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return internalSSLSocketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket() throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket());
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
}
private Socket enableTLSOnSocket(Socket socket) {
if(socket != null && (socket instanceof SSLSocket)) {
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
}
return socket;
}
}
但是请记住,这可能会更改应用程序在意外地方的行为(极不可能,但永远不会感到谨慎),为避免这种情况,您可以在使用{{之后,将默认SSLSocketFactory还原为旧的SSLSocketFactory。 1}}。
但是,还有另一个更可靠的解决方案。
您可以使用DefaultHttpDataSource
来在构造函数中传递OkHttpDataSource
实例。可以将此OkHttpClient
实例配置为使用我们的自定义OkHttpClient
。看起来像这样:
SSLSocketFactory
okhttpclient.sslSocketFactory(new MyCustomSSLSocketFactory());
答案 1 :(得分:0)
深入研究之后,我要做的就是使用ProviderInstaller在应用程序类中启用TLS1.2。我已经通过服务器提供了不接受TLS1.0的视频内容来对其进行了验证,并且可以正常工作。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
try {
// Google Play will install latest OpenSSL
ProviderInstaller.installIfNeeded(getApplicationContext());
SSLContext sslContext;
sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, null);
sslContext.createSSLEngine();
} catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException
| NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
}
}
参考:
https://guides.codepath.com/android/Using-OkHttp#enabling-tls-v1-2-on-older-devices