Rodrigo Salomao
Rodrigo Salomao

Reputation: 153

Unable to connect to API with TLS 1.2 on Android 4.x devices (no Google Play Services)

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:

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

Answers (1)

Yuri Schimke
Yuri Schimke

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

Related Questions