Android 4.2 TLS1.2支持
[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);