Android 5.0以下Glide加载https图片问题

问题描述

Glide加载https图片:https://futurestud.io/tutorials/glide-module-example-accepting-self-signed-https-certificates#0

Android 5.0以下Glide加载https图片报错:

1
2
3
4
class com.bumptech.glide.load.engine.GlideException: Failed to load resource
There were 2 causes:
javax.net.ssl.SSLHandshakeException(javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x5dbb9b40: 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 0x59da6890:0x00000000))

问题原因

https单向认证问题。Android 4.4没有启用TLSv1.1 和 TLSv1.2 传输层安全协议:https://developer.android.com/reference/javax/net/ssl/SSLSocket

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+

可以看出虽然Android 16就已经支持TLS1.1和TLS1.2,但是默认并没有开启,API 20才默认开启

问题解决

为请求的网络客户端设置一个特殊的SSLSocketFactory

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
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;
}
}

设置OkHttpClient

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
public class SSLHelper {

private static 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.
}
}

private static TrustManager[] getTrustManagers(InputStream... certificates) {
if (certificates == null || certificates.length <= 0) return null;
try {
//构造CertificateFactory对象
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
int index = 0;
for (InputStream certificate : certificates) {
String certificateAlias = Integer.toString(index++);
//得到Certificate并放入到keyStore中
keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
try {
if (certificate != null)
certificate.close();
} catch (IOException e) {
}
}
//利用keyStore初始化TrustManagerFactory
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
return trustManagers;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

public static OkHttpClient.Builder enableTls12OnPreLollipop(OkHttpClient.Builder client, InputStream... certificates) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
Tls12SocketFactory socketFactory = null;
TrustManager[] trustManagers = null;
try {
trustManagers = getTrustManagers(certificates);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, null);
socketFactory = new Tls12SocketFactory(sslContext.getSocketFactory());
client.sslSocketFactory(socketFactory, (X509TrustManager) trustManagers[0]);
} catch (Exception e) {
Log.e("yezhou", "Error while setting TLS", e);
if (trustManagers != null) {
try {
SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(null, trustManagers, null);
socketFactory = new Tls12SocketFactory(sc.getSocketFactory());
client.sslSocketFactory(socketFactory, (X509TrustManager) trustManagers[0]);
} catch (Exception e12) {
Log.e("yezhou", "Error while setting TLS 1.2", e12);
}
}
}

ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.build();

List<ConnectionSpec> specs = new ArrayList<>();
specs.add(cs);
specs.add(ConnectionSpec.COMPATIBLE_TLS);
specs.add(ConnectionSpec.CLEARTEXT);

client.connectionSpecs(specs);
}
return client;
}
}

设置AppGlideModule

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
@GlideModule
public final class MyAppGlideModule extends AppGlideModule {

@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
Log.i("yezhou", "MyAppGlideModule.registerComponents: " + Build.VERSION.SDK_INT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
.followRedirects(true)
.followSslRedirects(true)
.retryOnConnectionFailure(true)
.cache(null)
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS);
InputStream is = null;
try {
is = context.getAssets().open("appblog.cer");
} catch (IOException e) {
e.printStackTrace();
}
ModelLoaderFactory factory = new OkHttpUrlLoader.Factory(SSLHelper.enableTls12OnPreLollipop(clientBuilder, is).build());

registry.replace(GlideUrl.class, InputStream.class, factory);
}
}

}

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2020 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :