Reputation: 153
I'm having trouble connecting to my API on Android 4.x devices after removing TLS 1.1 support. While updating the OkHttpClient
configuration has been successful for devices with API level 21 and above, Android 4.x devices are causing significant problems.
Understanding:
It seems that Android 4.x doesn't have TLS 1.2 or 1.3 enabled by default.
Attempted Solutions:
I've tried the following approaches:
SocketFactory
ConnectionSpec
ProviderInstaller.installIfNeeded(this)
(but it's unavailable due to the absence of Google Play Services on company-managed devices)Code Snippet:
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_1, TlsVersion.TLS_1_2)
.cipherSuites(
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA
)
.build();
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder.connectTimeout(10, TimeUnit.SECONDS);
okHttpClientBuilder.readTimeout(10, TimeUnit.SECONDS);
okHttpClientBuilder.connectionSpecs(Arrays.asList(spec));
okHttpClientBuilder.addInterceptor(new Interceptor() {
@NonNull
@Override
public Response intercept(@NonNull Chain chain) {
Request request = chain.request().newBuilder()
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Basic ....")
.build();
try {
return chain.proceed(request);
} catch (NoSuchElementException | IOException e) {
e.printStackTrace();
return new Response.Builder()
.protocol(Protocol.HTTP_1_1)
.code(500).build();
}
}
});
try {
okHttpClientBuilder.sslSocketFactory(new TlsSniSocketFactory(), getTrustManager());
} catch (KeyManagementException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (KeyStoreException e) {
throw new RuntimeException(e);
}
OkHttpClient okHttpClient = okHttpClientBuilder.build();
retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("....")
.client(okHttpClient)
.build();
TestTLSService testTLSService = retrofit.create(TestTLSService.class);
updateAppRemoteCall = testTLSService.fetchAPKForUpdate();
try {
ProviderInstaller.installIfNeeded(this);
} catch (GooglePlayServicesRepairableException e) {
GooglePlayServicesUtil.getErrorDialog(e.getConnectionStatusCode(), this, 0);
} catch (GooglePlayServicesNotAvailableException e) {
Log.e("SecurityException", "Google Play Services not available.");
}
try {
updateAppRemoteCall.enqueue(new Callback<List<UpdateAppRemote>>() {
@Override
public void onResponse(Call<List<UpdateAppRemote>> call, retrofit2.Response<List<UpdateAppRemote>> response) {
Log.d("DEBBUG", ""+response.code());
Log.d("DEBBUG", ""+call.request().url());
Log.d("DEBBUG", ""+response.body().toString());
}
@Override
public void onFailure(Call<List<UpdateAppRemote>> call, Throwable t) {
t.printStackTrace();
}
});
}catch (Exception e){
e.printStackTrace();
}
Error:
Despite these efforts, I continue to receive the following error:
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:744 0x67c32ec8:0x00000000)at .startHandshake(OpenSSLSocketImpl.java:449)
... (stack trace)
Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x6c9573e0: Failure in SSL library, usually a protocol error
... (stack trace)
Additional Information:
The devices in question are company-managed and lack Google Play Services.
Questions:
Upvotes: 1
Views: 33
Reputation: 13488
If ProviderInstaller.installIfNeeded
is failing because of the lack of play services, you can always embed the Conscrypt library in your app directly.
Then before creating the client call
val provider =
Conscrypt.newProviderBuilder()
.provideTrustManager(true)
.build()
Security.insertProviderAt(provider, 1)
https://stackoverflow.com/a/59346159/1542667
Upvotes: 0