Using SSL in an Android app is easy, however ensuring that the connection is actually secure is a different matter. A man-in-the-middle attack can be carried out using several methods including ARP cache poisoning and DNS spoofing.
Core to SSL (Secure Socket Layer) is the X509 certificate, and trust in the chain of certificates that leads from your leaf certificate through an intermediate certificate authority (CA) to a root certificate authority. This chain is determined when the SSL connection is established. The First Few Milliseconds of an HTTPS Connection talks a little about the process of creating a secure connection.
Root certificates come pre-installed on Android devices with around 150 included in Android N. You can check what’s on your own device by going to Settings > Security > Trusted Credentials. There is an assumption that none of these root CAs or the 1000’s of intermediate CAs these root certificates trust will mis-issue leaf certificates for domain names they shouldn’t. If you don’t believe me read about the CAs DigiNotar, GlobalSign and Comodo. In addition to all this the users device could be compromised with a rogue certificate installed on it through social engineering.
SSL pinning also known as Public Key Pinning is an attempt to solve these issues, ensuring that the certificate chain used is the one your app expects by checking a particular public key or certificate appears in the chain.
More recently, pinning is starting to fall out of favour with certificate transparency gaining some traction. The article Android Security: Certificate Transparency talks about what this is and how you can implement it on Android. Indeed, Google now advise against implementing pinning.
A video covering some of the content of this video is also available.
Implementing SSL pinning
Before writing any code there are a few decisions you need to make from the certificate you use for pinning to what you do when things go wrong. So lets start…