Retrofit 2 — How to Trust Unsafe SSL certificates (Self-signed, Expired)

We were hesitant to write this tutorial, but due to the many, many requests: in this tutorial you will learn how to ignore the connection's security handshake and let Retrofit accept any, even bad SSL certificates. This includes revoked, expired or self-signed SSL certificates.

Warning: ignoring SSL certificate validity is incredibly dangerous and opens up your app and users for all kinds of security problems.

If you are aware of what you're doing, keep reading.

Retrofit Series Overview

  1. Callbacks (Coming soon)
  2. Annotations (Coming soon)
  3. Fluent Interface with Builders (Coming soon)

Accept Any SSL Certificate

In the next few minutes, we'll use BadSSL.com for our testing purposes. It gives us a wide variety of SSL certificates that no client should accept. By default, Retrofit will not connect to the subdomains (e.g., https://expired.badssl.com/ with bad SSL certificates.

Retrofit Call

Let's see if we change this behavior. Because the SSL certificate check is in the network layer, we'll need to change the OkHttp client instance. The rest of the Retrofit call will stay the same:

OkHttpClient okHttpClient = UnsafeOkHttpClient.getUnsafeOkHttpClient();

Retrofit.Builder builder = new Retrofit.Builder()  
        .baseUrl("http://10.0.2.2:3000/")
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create());

Retrofit retrofit = builder.build();

UserService userClient = retrofit.create(UserService.class);

Call<ResponseBody> call = userClient.profilePicture("https://revoked.badssl.com/");  
call.enqueue(new Callback<ResponseBody>() {  
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        Toast.makeText(BadSSLActivity.this, "got response" , Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Toast.makeText(BadSSLActivity.this, "SSL error?" , Toast.LENGTH_SHORT).show();
    }
});

Unsafe OkHttp Client

Next, it's time to look at the heart of this solution, the getUnsafeOkHttpClient() method, which offers us an OkHttp client that completely ignores any SSL certificate issues:

public class UnsafeOkHttpClient {  
    public static OkHttpClient getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[] {
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });

            OkHttpClient okHttpClient = builder.build();
            return okHttpClient;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

This code snippet is based on sonxurxo's answer on stackoverflow. It basically creates a new OkHttp client instance with custom SSL verification, which accepts every certificate.

Using this unsafe OkHttp client allows us to connect to the dangerous subdomains of BadSSL.com.

Better Solution: Accept Only Your Certificate

Again, accepting all SSL certificates is usually not the ideal scenario. Slightly better is to only accept your specific SSL certificate using a custom trust.

Summary

In this tutorial you've seen how you can disengage all connection security with a custom OkHttp client. If you really need to implement this, use caution!

Do you have further questions on this topic or about Retrofit in general? Just let us know on Twitter @futurestud_io or leave a comment below.

Enjoy coding & make it rock!

Explore the Library

Find interesting tutorials and solutions for your problems.

Miscellaneous