在一些旧的 Android 版本 (< API 21) 上,只有SSLv3
并且TLSv1
可用:
服务器接受最小值TLSv1
,握手SSL
被拒绝。因此,为了让 Glide 正确加载图像,我使用了一个自定义 okhttp 客户端和一个使用TLSv1
.
@GlideModule
public class TlsGlideModule extends AppGlideModule {
@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
super.registerComponents(context, glide, registry);
OkHttpClient.Builder client = new OkHttpClient.Builder();
enableTls1(client);
registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(client.build()));
}
}
private static void enableTls1(OkHttpClient.Builder client) {
SSLContext sc = SSLContext.getInstance("TLSv1");
sc.init(null, null, null);
client.sslSocketFactory(new TlsSocketFactory(sc.getSocketFactory()));
ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
.tlsVersions(TlsVersion.TLS_1_0)
.build();
List<ConnectionSpec> specs = new ArrayList<>();
specs.add(cs);
client.connectionSpecs(specs);
}
public class TlsSocketFactory extends SSLSocketFactory {
private static final String[] allowedTlsVersions = {"TLSv1"};
private final SSLSocketFactory delegate;
public TlsSocketFactory(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 {
return patch(delegate.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
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(allowedTlsVersions);
}
return s;
}
}
当我在这些方法中设置断点时,我看到它们在 Glide 初始化时被调用,但图像仍然没有加载,错误仍然是:
Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb987bb88: Failure in SSL library, usually a protocol error
error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE (third_party/openssl/boringssl/src/ssl/tls_record.cc:592 0xb980d4d8:0x00000001)
error:1000009a:SSL routines:OPENSSL_internal:HANDSHAKE_FAILURE_ON_CLIENT_HELLO (third_party/openssl/boringssl/src/ssl/handshake.cc:589 0x8696ec03:0x00000000)
at com.google.android.gms.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
...
如果我删除上面的所有代码并在应用程序启动时调用它,图像加载正常:
ProviderInstaller.installIfNeeded(App.getInstance().getApplicationContext());
但是根据SSLContext
,该设备已经TLSv1
在设备上可用,所以我更喜欢没有 Google Play Services 依赖项。
这是为什么?