Certificate Pinning in Retrofit,Android using CertificatePinner

Usage Scenario :

We may have often connected our client side apps to a lot of web servers. We may build our apps this way easily, but how can we ensure that we are communicating with the right web servers that we actually intend to communicate with? What if we are accessing some malicious web servers thinking that it is actually our servers ? Now this is where https comes into role. Apart from putting a secure label in front of your url at the address bar, it actually does more. It actually adds a security layer where in all the communication between your client and web server are encrypted.

Now one way of making sure that you are connecting to an appropriate web server is by using a method called Certificate Pinning. The idea behind Certificate Pinning is that we actually pins the public key hash of a particular host within our client side app. So during SSL Handshake, we are actually checking if the public key hash matches with the web server that we are connecting to.

Note : One major disadvantage with Certificate Pinning is that we may need to update our app if the web server gets it certificate updated. That is we need to change the public key hash which is hardcoded in the app
You may find more details about retrofit ssl pinning by visiting here

So first thing we need is to get the public key hash of the host which we are trying to connect to. Suppose that our host is api.github.com. Then we may get its public key hash by the following method

First go to https://www.ssllabs.com/ssltest/ and type in api.github.com inside the hostname field and tap submit like shown below

When you tap submit, you get the ssl test result from which you can see the following section called "Certification Paths". Here select the android tab like shown below


Now copy the public key hash labelled Pin SHA256 in the "In trust store" section. Great! now we have successfully obtained the public key hash for the host api.github.com. Now save this value somewhere since we need this for the next step. We will be pinning this hash value in our app using the CertificatePinner which can be added to the OkHttpClient. Now add this client to our retrofit network call.

 Now we can take a look at the code implementation.
OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();
        CertificatePinner certificatePinner = new CertificatePinner.Builder()
                .add("api.github.com", "sha256/WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18=")
                .build();

        OkHttpClient client1 = httpBuilder.certificatePinner(certificatePinner).build();
        

        Retrofit retrofit1 = new Retrofit.Builder()
                .client(client1)
                .baseUrl("https://api.github.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();


        UserService userClient = retrofit1.create(UserService.class);
        GithubServise githubServise = retrofit1.create(GithubServise.class);

        Call<ResponseBody> call = githubServise.getGithub();
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                Toast.makeText(MainActivity.this, "got response" , Toast.LENGTH_SHORT).show();
            }

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

Thats it! we have now successfully pinned our client side with the public key hash of api.github.com. retrofit ssl pinning is now successfully implemented.

1 comment:

  1. I admire this article for the well-researched content and excellent wording. I got so involved in this material that I couldn’t stop reading. I am impressed with your work and skill. Thank you so much.
    android development company in chennai

    ReplyDelete