On some old Android versions (< API 21), there is only SSLv3
and TLSv1
available:
The server accepts minimum TLSv1
, handshakes with SSL
are rejected. So for Glide to load images properly, I use a custom okhttp client with a Socket Factory that uses 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;
}
}
When I set breakpoints in these methods, I see that they are getting called when Glide initializes, but the images are still not loading, the error is still:
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)
...
If I remove all of the code above and just call this on app launch, the images are loading fine:
ProviderInstaller.installIfNeeded(App.getInstance().getApplicationContext());
But according to the SSLContext
, the device already has TLSv1
on the device available, so I prefer to not have a Google Play Services dependency.
Why is that?
You need to tell OkHttp to use it's less secure ConnectionSpec, COMPATIBLE_TLS.
OkHttpClient client = new OkHttpClient.Builder()
.connectionSpecs(Arrays.asList(ConnectionSpec.COMPATIBLE_TLS))
.build();
User contributions licensed under CC BY-SA 3.0