How to calculate certificate pin for OkHttp
It’s quite popular to use OkHttp in Android project nowadays. OkHttp provides an easy-to-use class CertificatePinner for certificate pinning. It accepts 2 types of pins, SHA-256 and SHA-1 as mentioned on OkHttp document.
This class currently pins a certificate’s Subject Public Key Info as described on Adam Langley’s Weblog. Pins are either base64 SHA-256 hashes as in HTTP Public Key Pinning (HPKP) or SHA-1 base64 hashes as in Chromium’s static certificates.
Preparation
Before the calculation of certificate pin, there are a couple of questions needs to be answered.
- Which certificate in the certificate chain are we going to pin?
- Do we pin the whole certificate or only the public key field?
- Which hash algorithm to use?
Which certificate in the certificate chain do we pin
For a completed certificate chain, normally there are 3 certificates: root, intermediate and server certificate. Only sever certificate is representing the owner’s entity, CN inside the server certificate is your domain. So it’s better to pin the server certificate.
Do we pin the whole certificate or only the public key field
These also are 2 very common practices for certificate pinning.
- Certificate fingerprint pining, certificate fingerprint is the hash calculated from the whole certificate.
- Public key pinning, actually it is not only pin the public key. It will includes some extra information, for example the algorithm of the public key or elliptic curve type. The most common format of public key to pin is the one OkHttp is using, Public Key with Subject Public Key Info.
Between these 2 practices, which one is better? I can only say, public key pinning is more flexible. Sometimes we will renew the certificate with same public key. Or even sometimes we can generate a CSR ahead of time and embed the certificate pin inside the application. This CSR will be issued to certificates with CA a couple of years later, and we won’t need to update the application in that time because the certificate pin has already been there.
Which hash algorithm to use
Common hash algorithms are used: md5, SHA-1, SHA-256, SHA-384, SHA-512, etc.
As md5 and SHA-1 are not safe any more, SHA-256 is recommended for certificate pin.
After we answered above 3 questions, now we know what we are looking for. There are a couple of tools can help us to get the certificate pin.
Calculate certificate pin by SSLLabs
There are a lot of tools that can help you to get the SHA-256 of public key in your certificate. The one I am using is SSLLabs, because it can give me all the details info inside the certificate.
- Open SSLLabs in browser
- Submit the hostname of your domain want to pin
- After a couple of minutes, it will list down all the info of the certificate chain
- Look for Certification Paths and click to expand it
- Go to Android tab, look for the certificate that the CN is matching your domain, “Pin SHA256“ is the certificate pin we need.
Calculate certificate pin by OpenSSL
It’s more flexible to run with openssl commands.
Replace <domain> with one you want to pin, and run below command from terminal.
openssl s_client -servername <domain> -connect <domain>:443 |
openssl x509 -pubkey -noout |
openssl rsa -pubin -outform der |
openssl dgst -sha256 -binary |
openssl enc -base64
If the certificate is an Elliptic Curve certificate, replace rsa with ec. If the hash algorithm is not SHA-256, replace -sha256 with the one you want.
If you don’t want to follow the suggestions above, you want to pin another certificate in the chain. OpenSSL also can help you.
Extract the the certificate to be pinned from browser, replace <cer file path> with the extracted file path, and run below command from terminal.
openssl x509 -inform der -in <cer file path> -pubkey -noout |
openssl rsa -pubin -outform der |
openssl dgst -sha256 -binary |
openssl enc -base64
Conclusion
Certificate pinning is still an common practice to avoid MiTM attack in Android application, because Certificate Transparency is not mature in Android. The tools introduced here are not only for OkHttp, as long as you are using certificate pinning, the way to calculate certificate pin is still similar. Maybe some of the requirement are different, but OpenSSL is flexible enough to handle most of the requirements.