在Android 4.1+中强制开启TLSv1.1和TLSv1.2

在做MQTT时遇到了android4.4手机没法连接服务端的情况,查阅发现是因为系统默认没有开启TLSv1.1和TLSv1.2的支持。抛出的错误如下:

1
2
3
 MqttException (0) – javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x7861ada8: Failure in SSL library, usually a protocol error
 
error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version (external/openssl/ssl/s23_clnt.c:741 0x71e78cf8:0x00000000)

Android 4.1开始支持TLSv1.1和TLSv1.2,但是在4.1~4.4版本中默认都是关闭。在某些情况下可能会导致SSL链接建立失败的问题(服务端强制使用1.1和/或1.2,而android 4.1~4.4中没有开启。),这时需要开启TLSv1.1和TLSv1.2。

我们需要使用自定义的SSLSocketFactory去创建SSL链接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class CustomSslSocketFactory extends SSLSocketFactory {
 
    private SSLSocketFactory sslSocketFactory;
 
    public CustomSslSocketFactory(TrustManager[] trustManager) throws KeyManagementException, NoSuchAlgorithmException {
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, trustManager, null);
        sslSocketFactory = context.getSocketFactory();
    }
 
    @Override
    public String[] getDefaultCipherSuites() {
        return sslSocketFactory.getDefaultCipherSuites();
    }
 
    @Override
    public String[] getSupportedCipherSuites() {
        return sslSocketFactory.getSupportedCipherSuites();
    }
 
    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return enableTLSOnSocket(sslSocketFactory.createSocket(s, host, port, autoClose));
    }
 
    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return enableTLSOnSocket(sslSocketFactory.createSocket(host, port));
    }
 
    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
        return enableTLSOnSocket(sslSocketFactory.createSocket(host, port, localHost, localPort));
    }
 
    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return enableTLSOnSocket(sslSocketFactory.createSocket(host, port));
    }
 
    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return enableTLSOnSocket(sslSocketFactory.createSocket(address, port, localAddress, localPort));
    }
 
    @Override
    public Socket createSocket() throws IOException {
        return enableTLSOnSocket(sslSocketFactory.createSocket());
    }
 
    private Socket enableTLSOnSocket(Socket socket) {
        ((SSLSocket) socket).setEnabledProtocols(new String[] {"TLSv1.2", "TLSv1.1"});
        return socket;
    }
}

需要注意的是如果遇到如下错误,那需要override一个空参数的createSocket()方法。

1
2
3
4
5
6
7
Error:java.net.SocketException: Unconnected is not implemented 
 
//Override createSocket()
    @Override
    public Socket createSocket() throws IOException {
        return enableTLSOnSocket(sslSocketFactory.createSocket());
    }

使用这个自定义的SSLSocketFactory类就可以去做TLSv1.1和TLSv1.2的SSL链接就可以了。

Leave a Reply