如何为Exoplayer启用/支持TLS 1.1,1.2?

时间:2019-10-18 19:01:55

标签: android tls1.2 exoplayer

错误: SSL握手已中止:ssl = 0x676a5680: SSL库中的失败,通常是协议错误

根据此Android doc,API 16+支持 TLS 1.1 1.2 ,但直到API 20+才默认启用。我找到了一些解决方案(herehereherehere)来启用对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不支持该协议   版本。

2 个答案:

答案 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();
        }
    }
}

参考:

Javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: Failure in SSL library, usually a protocol error

https://guides.codepath.com/android/Using-OkHttp#enabling-tls-v1-2-on-older-devices