Android

Android 4.2 TLS1.2支持

2019-12-17  本文已影响0人  jxcyly1985

[TOC]

背景

对比http协议,https对传输内容进行加密,天然的支持防篡改,提升了安全性。

https架构

1576565338401.png

现在越来越多的服务器处于安全的考虑切换HTTPS协议,同时对于安全性较低的协议,TLS1.2以下的协议很多都取消了支持,但是andorid4.2设置是默认不开启TLS1.2,这块从官方文档可以得到信息。

https://developer.android.google.cn/reference/kotlin/javax/net/ssl/SSLSocket?hl=en

Client socket:

Protocol Supported (API Levels) Enabled by default (API Levels)
SSLv3 1–25 1–22
TLSv1 1+ 1+
TLSv1.1 16+ 20+
TLSv1.2 16+ 20+
TLSv1.3 29+ 29+

异常

如果协议不支持,在请求的时候,是会报出下面的异常,异常会给出服务器支持的协议版本,已经当前系统套接字支持的版本。

java.net.UnknownServiceException: Unable to find acceptable protocols. 
isFallback=false, modes=[ConnectionSpec(cipherSuites=[TLS_AES_128_GCM_SHA256,
TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_GCM_SHA256,
TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, 
SSL_RSA_WITH_3DES_EDE_CBC_SHA], tlsVersions=[TLS_1_3, TLS_1_2], supportsTlsExtensions=true),
ConnectionSpec()], supported protocols=[SSLv3, TLSv1]

既然官方文档上说android4.2是支持TLS1.0,TLS1.2的,只是默认不开启,那我们看看开启的方式。

TLS版本差别

详细的差别可以看下面链接的介绍,从这个差别可以看出一个信息,TLS版本的更新和加密套件是独立两套,加密套件是独立于TLS版本的内部处理逻辑的。

两者的关系类似于码头吊机和集装箱。

https://blog.csdn.net/mrpre/article/details/77978293

服务器TLS分析

https://www.ssllabs.com/ssltest/index.html

1576572356964.png

开启TLS1.2

在开启TLS1.2之前,我们需要先熟悉一下android的javax.net.ssl包结构

javax.net.ssl属于java的jsse安全体系。

关于java安全体系方面的内容,可参考以下链接

https://blog.csdn.net/hqy1719239337/article/details/88663814

1576568448756.png

对应jsse实现

/libcore/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/

1576569219527.png
类名称 类作用
SSLParameters SSL连接相关的参数信息
SSLContext SSLSocket协议实现的类,可以使用自定义的密钥管理,和证书管理进行初始化,通过这个实例获取套件字工厂
SSLSocketFactory 工厂方法模式,生成具体的SSLSocket

SSLSocket提供了设置安全协议版本,加密套件,启动握手等接口用于应用层调用

开启

核心方式就是替换成自定义的套件字工厂

在这里需要注意一下,不要直接设置一个自己创建的SSLSocketFactory,需要使用SSLContext创建的SSLSocketFactory,因为这里面包含了相关的平台信息

public class Tls12SocketFactory extends SSLSocketFactory {
    private static final String[] TLS_V12_ONLY = {"TLSv1.2"};

    final SSLSocketFactory delegate;

    public Tls12SocketFactory(SSLSocketFactory base) {
        this.delegate = base;
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return delegate.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket() throws IOException {
        return patch(delegate.createSocket());
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return patch(delegate.createSocket(s, host, port, autoClose));
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return patch(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
        return patch(delegate.createSocket(host, port, localHost, localPort));
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return patch(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return patch(delegate.createSocket(address, port, localAddress, localPort));
    }

    private Socket patch(Socket s) {
        if (s instanceof SSLSocket) {
            Logger.d("Tls12SocketFactory", "patch socket=" + s.getClass().getName());
            Logger.d("Tls12SocketFactory", "patch setEnabledProtocols");
            for (String pro : ((SSLSocket) s).getSupportedProtocols()) {
                Log.d("Tls12SocketFactory", "patch getSupportedProtocols=" + pro);
            }

            for (String pro : ((SSLSocket) s).getSSLParameters().getProtocols()) {
                Log.d("Tls12SocketFactory", "patch SSLParameters=" + pro);
            }

            ((SSLSocket) s).setEnabledProtocols(TLS_V12_ONLY);
            ((SSLSocket) s).setEnabledCipherSuites(new String[]{
                    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
                    "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
                    "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
                    "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
                    "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
                    "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
                    "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
                    "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
                    "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
                    "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"});
            for (String pro : ((SSLSocket) s).getSSLParameters().getProtocols()) {
                Log.d("Tls12SocketFactory", "patch SSLParameters2=" + pro);
            }

            for (String pro : ((SSLSocket) s).getEnabledProtocols()) {
                Log.d("Tls12SocketFactory", "patch SSLParameters3=" + pro);
            }


        }
        return s;
    }

    @Override
    public String toString() {
        return "Tls12SocketFactory";
    }
}

调用网络库设置工厂接口

HttpsURLConnection.setSSLSocketFactory    //HttpsURLConnection方式
builder.sslSocketFactory(sslSocketFactory, trustManager);  //okhttp方式

验证

通过对请求进行抓网络包,再使用工具查看,已经切换到TLSv1.2协议,证明开启方式有效

1576569976576.png

加密套件支持

到这一步只是开启了TLSv1.2协议,但是和服务器通信能否成功,还需要看加密套件是否也支持

在这里,我们可以使用ssllab网站测试https的ssl配置情况

https://www.ssllabs.com/ssltest/index.html

在中间输入域名,执行完之后,会得到一份输出分析报告

如图所示,这个是后台服务器支持的协议版本

1576571135923.png

后台支持的加密套件

1576571232375.png

对比官方文档的加密套件版本支持,如果当前版本不支持该加密套件,即使开启了TLSv1.2的版本支持,在执行握手操作的时候,依然会失败

https://developer.android.google.cn/reference/javax/net/ssl/SSLSocket?hl=zh#cipher-suites

开启加密套件支持

对比系统openssl.so库版本,最好升级到android5.1的openssl.so版本

通过跟踪发现这块的配置信息是在NativeCrypto.java中

luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java

 static {
        // Note these are added in priority order
        add("SSL_RSA_WITH_RC4_128_MD5",              "RC4-MD5");
        add("SSL_RSA_WITH_RC4_128_SHA",              "RC4-SHA");
        add("TLS_RSA_WITH_AES_128_CBC_SHA",          "AES128-SHA");
        add("TLS_RSA_WITH_AES_256_CBC_SHA",          "AES256-SHA");
        add("TLS_ECDH_ECDSA_WITH_RC4_128_SHA",       "ECDH-ECDSA-RC4-SHA");
        add("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",   "ECDH-ECDSA-AES128-SHA");
        add("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",   "ECDH-ECDSA-AES256-SHA");
        add("TLS_ECDH_RSA_WITH_RC4_128_SHA",         "ECDH-RSA-RC4-SHA");
        add("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",     "ECDH-RSA-AES128-SHA");
        add("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",     "ECDH-RSA-AES256-SHA");
        add("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",      "ECDHE-ECDSA-RC4-SHA");
        add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",  "ECDHE-ECDSA-AES128-SHA");
        add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",  "ECDHE-ECDSA-AES256-SHA");
        add("TLS_ECDHE_RSA_WITH_RC4_128_SHA",        "ECDHE-RSA-RC4-SHA");
        add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",    "ECDHE-RSA-AES128-SHA");
        add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",    "ECDHE-RSA-AES256-SHA");
        add("TLS_DHE_RSA_WITH_AES_128_CBC_SHA",      "DHE-RSA-AES128-SHA");
        add("TLS_DHE_RSA_WITH_AES_256_CBC_SHA",      "DHE-RSA-AES256-SHA");
        add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA",      "DHE-DSS-AES128-SHA");
        add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA",      "DHE-DSS-AES256-SHA");
        add("SSL_RSA_WITH_3DES_EDE_CBC_SHA",         "DES-CBC3-SHA");
        add("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",  "ECDH-ECDSA-DES-CBC3-SHA");
        add("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",    "ECDH-RSA-DES-CBC3-SHA");
        add("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "ECDHE-ECDSA-DES-CBC3-SHA");
        add("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",   "ECDHE-RSA-DES-CBC3-SHA");
        add("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",     "EDH-RSA-DES-CBC3-SHA");
        add("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",     "EDH-DSS-DES-CBC3-SHA");
        add("SSL_RSA_WITH_DES_CBC_SHA",              "DES-CBC-SHA");
        add("SSL_DHE_RSA_WITH_DES_CBC_SHA",          "EDH-RSA-DES-CBC-SHA");
        add("SSL_DHE_DSS_WITH_DES_CBC_SHA",          "EDH-DSS-DES-CBC-SHA");
        add("SSL_RSA_EXPORT_WITH_RC4_40_MD5",        "EXP-RC4-MD5");
        add("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",     "EXP-DES-CBC-SHA");
        add("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "EXP-EDH-RSA-DES-CBC-SHA");
        add("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", "EXP-EDH-DSS-DES-CBC-SHA");
        add("SSL_RSA_WITH_NULL_MD5",                 "NULL-MD5");
        add("SSL_RSA_WITH_NULL_SHA",                 "NULL-SHA");
        add("TLS_ECDH_ECDSA_WITH_NULL_SHA",          "ECDH-ECDSA-NULL-SHA");
        add("TLS_ECDH_RSA_WITH_NULL_SHA",            "ECDH-RSA-NULL-SHA");
        add("TLS_ECDHE_ECDSA_WITH_NULL_SHA",         "ECDHE-ECDSA-NULL-SHA");
        add("TLS_ECDHE_RSA_WITH_NULL_SHA",           "ECDHE-RSA-NULL-SHA");
        add("SSL_DH_anon_WITH_RC4_128_MD5",          "ADH-RC4-MD5");
        add("TLS_DH_anon_WITH_AES_128_CBC_SHA",      "ADH-AES128-SHA");
        add("TLS_DH_anon_WITH_AES_256_CBC_SHA",      "ADH-AES256-SHA");
        add("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",     "ADH-DES-CBC3-SHA");
        add("SSL_DH_anon_WITH_DES_CBC_SHA",          "ADH-DES-CBC-SHA");
        add("TLS_ECDH_anon_WITH_RC4_128_SHA",        "AECDH-RC4-SHA");
        add("TLS_ECDH_anon_WITH_AES_128_CBC_SHA",    "AECDH-AES128-SHA");
        add("TLS_ECDH_anon_WITH_AES_256_CBC_SHA",    "AECDH-AES256-SHA");
        add("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",   "AECDH-DES-CBC3-SHA");
        add("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",    "EXP-ADH-RC4-MD5");
        add("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", "EXP-ADH-DES-CBC-SHA");
        add("TLS_ECDH_anon_WITH_NULL_SHA",           "AECDH-NULL-SHA");

        // TLSv1.2 cipher suites
        add("TLS_RSA_WITH_NULL_SHA256",                "NULL-SHA256");
        add("TLS_RSA_WITH_AES_128_CBC_SHA256",         "AES128-SHA256");
        add("TLS_RSA_WITH_AES_256_CBC_SHA256",         "AES256-SHA256");
        add("TLS_RSA_WITH_AES_128_GCM_SHA256",         "AES128-GCM-SHA256");
        add("TLS_RSA_WITH_AES_256_GCM_SHA384",         "AES256-GCM-SHA384");
        add("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",     "DHE-RSA-AES128-SHA256");
        add("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",     "DHE-RSA-AES256-SHA256");
        add("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",     "DHE-RSA-AES128-GCM-SHA256");
        add("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",     "DHE-RSA-AES256-GCM-SHA384");
        add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",     "DHE-DSS-AES128-SHA256");
        add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",     "DHE-DSS-AES256-SHA256");
        add("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",     "DHE-DSS-AES128-GCM-SHA256");
        add("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",     "DHE-DSS-AES256-GCM-SHA384");
        add("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",    "ECDH-RSA-AES128-SHA256");
        add("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",    "ECDH-RSA-AES256-SHA384");
        add("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",    "ECDH-RSA-AES128-GCM-SHA256");
        add("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",    "ECDH-RSA-AES256-GCM-SHA384");
        add("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",  "ECDH-ECDSA-AES128-SHA256");
        add("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",  "ECDH-ECDSA-AES256-SHA384");
        add("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",  "ECDH-ECDSA-AES128-GCM-SHA256");
        add("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",  "ECDH-ECDSA-AES256-GCM-SHA384");
        add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",   "ECDHE-RSA-AES128-SHA256");
        add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",   "ECDHE-RSA-AES256-SHA384");
        add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",   "ECDHE-RSA-AES128-GCM-SHA256");
        add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",   "ECDHE-RSA-AES256-GCM-SHA384");
        add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "ECDHE-ECDSA-AES128-SHA256");
        add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "ECDHE-ECDSA-AES256-SHA384");
        add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "ECDHE-ECDSA-AES128-GCM-SHA256");
        add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "ECDHE-ECDSA-AES256-GCM-SHA384");
        add("TLS_DH_anon_WITH_AES_128_CBC_SHA256",     "ADH-AES128-SHA256");
        add("TLS_DH_anon_WITH_AES_256_CBC_SHA256",     "ADH-AES256-SHA256");
        add("TLS_DH_anon_WITH_AES_128_GCM_SHA256",     "ADH-AES128-GCM-SHA256");
        add("TLS_DH_anon_WITH_AES_256_GCM_SHA384",     "ADH-AES256-GCM-SHA384");

添加默认加密套件

 public static String[] getDefaultCipherSuites() {
        return new String[] {
            "SSL_RSA_WITH_RC4_128_MD5",
            "SSL_RSA_WITH_RC4_128_SHA",
            "TLS_RSA_WITH_AES_128_CBC_SHA",
            "TLS_RSA_WITH_AES_256_CBC_SHA",
            "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
            "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
            "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
            "TLS_ECDH_RSA_WITH_RC4_128_SHA",
            "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
            "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
            "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
            "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
            "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
            "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
            "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
            "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
            "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
            "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
            "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
            "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
            "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
            "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
            "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
            "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
            "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
            "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
            "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
            "SSL_RSA_WITH_DES_CBC_SHA",
            "SSL_DHE_RSA_WITH_DES_CBC_SHA",
            "SSL_DHE_DSS_WITH_DES_CBC_SHA",
            "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
            "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
            "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
            "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
            "TLS_RSA_WITH_NULL_SHA256", 
            "TLS_RSA_WITH_AES_128_CBC_SHA256", 
            "TLS_RSA_WITH_AES_256_CBC_SHA256",
            "TLS_RSA_WITH_AES_128_GCM_SHA256", 
            "TLS_RSA_WITH_AES_256_GCM_SHA384",    
            "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
            "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
            "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 
            "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 
            "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
            "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", 
            "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",   
            "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 
            "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", 
            "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
            "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",  
            "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
            "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
            "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
            "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
            "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
            "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
            "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", 
            "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
            "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 
            "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
            "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
            "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
            "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
            "TLS_DH_anon_WITH_AES_128_CBC_SHA256", 
            "TLS_DH_anon_WITH_AES_256_CBC_SHA256", 
            "TLS_DH_anon_WITH_AES_128_GCM_SHA256", 
            "TLS_DH_anon_WITH_AES_256_GCM_SHA384", 
            TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        };
    }

既然都修改到了框架层,索性直接默认开启TLSv1.1 TLSv1.2

    public static String[] getDefaultProtocols() {
        return new String[] { SUPPORTED_PROTOCOL_SSLV3,
                              SUPPORTED_PROTOCOL_TLSV1,
                              SUPPORTED_PROTOCOL_TLSV1_1, // 默认开启1.1
                              SUPPORTED_PROTOCOL_TLSV1_2, // 默认开启1.2
        };
    }

FQA

okhttp版本

OKHTTP4.x 默认关闭了对TLSv1.0,TLSv1.1的支持 ,在未开启TLSv1.2的机器上,会出现回滚SSLv3握手异常

HTTP FAILED: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x590f0de8: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0x542b1d90:0x00000000)

如果需要支持TLSv1.0, TLSv1.1需要使用okhttp3.x的版本

okhttp设置自定义socket工厂

sslSocketFactory
public OkHttpClient.Builder sslSocketFactory(SSLSocketFactory sslSocketFactory,
                                             X509TrustManager trustManager)
Sets the socket factory and trust manager used to secure HTTPS connections. If unset, the system defaults will be used.
Most applications should not call this method, and instead use the system defaults. Those classes include special optimizations that can be lost if the implementations are decorated.

If necessary, you can create and configure the defaults yourself with the following code:

   

   TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
       TrustManagerFactory.getDefaultAlgorithm());
   trustManagerFactory.init((KeyStore) null);
   TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
   if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
     throw new IllegalStateException("Unexpected default trust managers:"
         + Arrays.toString(trustManagers));
   }
   X509TrustManager trustManager = (X509TrustManager) trustManagers[0];

   SSLContext sslContext = SSLContext.getInstance("TLS");
   sslContext.init(null, new TrustManager[] { trustManager }, null);
   SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

   OkHttpClient client = new OkHttpClient.Builder()
       .sslSocketFactory(sslSocketFactory, trustManager)
       .build();

证书不规范问题

证书和域名不一致

HTTP FAILED: javax.net.ssl.SSLPeerUnverifiedException: Hostname open.mos.csvw.com not verified:certificate: sha256/23d8uredpHICqIWpMrXdn0Q0hUzUyGmjI 2x 70TF/4=DN: CN=open.mos.csvw.com,OU=SC,O=SAIC VOLKSWAGEN AUTOMOTIVE CO,. LTD.,ST=shanghai,C=CNsubjectAltNames: []

builder.hostnameVerifier(new HostnameVerifier() {

    @Override

    public boolean verify(String hostname, SSLSession session) {

        return true;

    }

});

POSTMAN设置客户端证书

端上用postman来验证后台接口,有的后台需要安装特定的证书才能访问,因此需要在postman上也需要添加本地证书

1576573600738.png

代码添加证书

cf = CertificateFactory.getInstance("X.509");
InputStream caInput;
Certificate ca;
try {
        caInput = context.getResources().openRawResource(R.raw.verification);
        ca = cf.generateCertificate(caInput);
    } finally {
        if (caInput != null) {
            caInput.close();
        }
    
}

// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);

// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
上一篇下一篇

猜你喜欢

热点阅读