异常如下
javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x610df808: 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 0x410f976a:0x00000000) at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:412) at okhttp3.internal.connection.RealConnection.connectTls(Paramount:281) at okhttp3.internal.connection.RealConnection.establishProtocol(Paramount:251) at okhttp3.internal.connection.RealConnection.connect(Paramount:151) at okhttp3.internal.connection.StreamAllocation.findConnection(Paramount:192) at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(Paramount:121) at okhttp3.internal.connection.StreamAllocation.newStream(Paramount:100) at okhttp3.internal.connection.ConnectInterceptor.intercept(Paramount:42) at okhttp3.internal.http.RealInterceptorChain.proceed(Paramount:92) at okhttp3.internal.http.RealInterceptorChain.proceed(Paramount:67) at okhttp3.internal.cache.CacheInterceptor.intercept(Paramount:93) at okhttp3.internal.http.RealInterceptorChain.proceed(Paramount:92) at okhttp3.internal.http.RealInterceptorChain.proceed(Paramount:67) at okhttp3.internal.http.BridgeInterceptor.intercept(Paramount:93) at okhttp3.internal.http.RealInterceptorChain.proceed(Paramount:92) at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(Paramount:120) at okhttp3.internal.http.RealInterceptorChain.proceed(Paramount:92) at okhttp3.internal.http.RealInterceptorChain.proceed(Paramount:67) at okhttp3.RealCall.getResponseWithInterceptorChain(Paramount:185) at okhttp3.RealCall.execute(Paramount:69) at com.qihoo.mm.paramount.tools.glide.j.b(Paramount:44) at com.qihoo.mm.paramount.tools.glide.j.a(Paramount:21) at com.bumptech.glide.load.b.f$a.b(Paramount:70) at com.bumptech.glide.load.b.f$a.a(Paramount:53) at com.bumptech.glide.load.engine.a.e(Paramount:170) at com.bumptech.glide.load.engine.a.c(Paramount:128) at com.bumptech.glide.load.engine.h.f(Paramount:122) at com.bumptech.glide.load.engine.h.d(Paramount:101) at com.bumptech.glide.load.engine.h.run(Paramount:58) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:442) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) at java.util.concurrent.FutureTask.run(FutureTask.java:137) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) at java.lang.Thread.run(Thread.java:856) at com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor$a$1.run(Paramount:118) Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x610df808: 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 0x410f976a:0x00000000) at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method) at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:371) ... 35 more
由于集成的 SSL 库版本不同,不同 Android 版本的默认 SSL/TLS 版本配置如下表:
Protocol | Supported (API Levels) | Enabled by default (API Levels) |
---|---|---|
SSLv3 | 1–TBD | 1–22 |
TLSv1 | 1+ | 1+ |
TLSv1.1 | 20+ | 20+ |
TLSv1.2 | 20+ | 20+ |
在 Android 5.0 之前,最高支持的 SSL/TLS 版本为 TLSv1,而这个版本实际上是一个安全性并不是太好的版本,当前已经有许多网站配置为不再支持这种老版本的 SSL/TLS 。在用 Android 5.0 之前的设备,访问一些不再支持 TLSv1 及之前 SSL/TLS 版本的网站的时候,就会出现一些问题。
在 Android 4.3、Android 4.2.2 和 Android 4.1.1 上,用相同版本的 OkHttp 访问前面配置为最低支持 TLSv1.1 的 HTTP 服务器时,抛出了完全相同的异常。
客户端版本低于服务器支持的最低 SSL/TLS 版本时,HTTPS 连接会在握手阶段失败。
为请求的网络客户端设置一个特殊的SSLSocketFactory
import android.os.Build import android.util.Log import com.android.core.Arrays import com.qihoo.mm.paramount.env.AppEnv import okhttp3.OkHttpClient import java.io.IOException import java.net.InetAddress import java.net.Socket import java.net.UnknownHostException import java.security.GeneralSecurityException import java.security.KeyStore import javax.net.ssl.* public class Tls12SocketFactory extends SSLSocketFactory { private static final String[] TLS_SUPPORT_VERSION = {"TLSv1.1", "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(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) { ((SSLSocket) s).setEnabledProtocols(TLS_SUPPORT_VERSION); } return s; } }
修改默认X509TrustManager
private X509TrustManager getDefaultTrustManager() { try { 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)); } return (X509TrustManager) trustManagers[0]; } catch (GeneralSecurityException e) { throw new AssertionError(); // The system has no TLS. Just give up. } }
设置OkHttpClient
private OkHttpClient initOkHttpClient() { OkHttpClient builder = OkHttpClient.Builder() try { if(DEBUG){ Log.i(TAG,"initOkHttpClient") } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { Tls12SocketFactory.enableTls12OnPreLollipop(builder) } builder.readTimeout(10L, TimeUnit.SECONDS)//设置读取超时时间 builder.writeTimeout(10L, TimeUnit.SECONDS)//设置写的超时时间 builder.connectTimeout(10L, TimeUnit.SECONDS)//设置连接超时时间 } catch (e: Exception) { if(DEBUG){ Log.e(TAG,"",e) } } return builder.build() } public static OkHttpClient.Builder enableTls12OnPreLollipop(OkHttpClient.Builder client) { if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT < 22) { try { val sslContext = SSLContext.getInstance("TLS") sslContext .init(null, null, null) val socketFactory = Tls12SocketFactory(sslContext.socketFactory) client.sslSocketFactory(socketFactory, getDefaultTrustManager()) } catch (exc: Exception) { if (AppEnv.bAppdebug) { Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc) } try { SSLContext sc = SSLContext.getInstance("TLSv1.2"); sc.init(null, null, null); client.sslSocketFactory(new Tls12SocketFactory(sc.getSocketFactory())); client.sslSocketFactory(socketFactory, getDefaultTrustManager()) client.connectionSpecs(specs); } catch (Exception exc) { if (AppEnv.bAppdebug) { Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc); } } } return client; }