SSL pinning. How to make it right.

Oleksandr Stepanov
10 min readSep 26, 2019

Many developers assume that using HTTPS in a network layer is enough to be sure that user data transfer will be fully secured and not compromised by a Man-in-the-Middle (MitM) attack. In most cases that is true, but not always.

Disclaimer: This post covers theoretical part of the problem, describing well-known and widely used approaches alone with the one, which is based on the latest initiatives in Public Key Infrastructure. The practical aspects are covered in another story from the series.

HTTPS and TLS protocols will not save you if the Certificate Authority (CA) which issued your root certificate is compromised, as this happened in the DigiNotar case. The same will happen if your device Certificate Trust Store has a self-signed root or intermediate certificate installed, which can be used for signing secured requests. Have to admit, that nowadays it’s not very easy to put such a certificate in the system trust store. In iOS, the user will be presented with warning alerts several times, and one must enter the device PIN in order to get this job done. On macOS, the user must add this item to keychain by entering an administrator password. So, it’s hard to imagine that a user may accidentally install such certificate by connecting to public WiFi. Nevertheless, this doesn’t discard intentional cases, like parent control and corporate devices. The second category very often has self-signed certificates installed in the trust store to enable users to connect to internal services and portals without browser errors. But the same certificates may be used in transparent proxy setup to listen and even intercept encrypted HTTPS/TLS traffic of other websites and services like Facebook, Twitter, LinkedIn, if the system admins of your company are evil enough and want to trick you. The use of Mobile Device Management solutions even makes remote installation of such certificates possible.

Luckily, things are not so bad, and most of the popular apps and websites nowadays implement SSL pinning as one more layer of defense against MitM. In this post, we will review the details of SSL pinning implementations like:

  • Subject Public Key Info pinning
  • Public Key pinning
  • Certificate pinning
  • Root certificate pinning with usage of Certificate Transparency logs infrastructure.

Subject Public Key Info pinning

The Subject Public Key Info (SPKI) is a key with additional information, such as the algorithm used for encoding and any parameters, which the public component is to be used with. Usually pinning is implemented by taking a hash of this information for the certificate to pin, embedding it in the application, and using it to compare with the same hash during connection establishment.

This is a recommended approach by OWASP community and there are various out-of-the-box solutions for different platforms. For example, for Apple platforms there is TrustKit library, which is widely used in the apps for iOS. There is a version of TrustKit for Android l from the same vendor.

Have to note that SPKI is obtained from Certificate Signing Request (CSR), which in its turn is obtained from the pair of public and private keys. It means that in order to retain the same SPKI on certificate renewal, one must request a new certificate from CA with the same CSR, which prevents the rotation of both public and private keys. Changing even one of them leads to changes in CSR and thus in SPKI.

Ultimately, SPKI pinning is very similar to Certificate one, because every time the certificate on the server changes, you must update SPKI hashes embedded in the app to continue its operation. Unless you rotate your pair of public and private keys, this update is not required. But this is not a recommended approach.

SPKI pinning was implemented as part of the browsers standard known as HTTP Public Key Pinning(HPKP) headers mechanism. It’s recommended to embed backup pins for SPKI to keep your application running without mandatory update when the server certificate is renewed. However, it’s necessary to note that in this case, it’s on you to store these keys securely. In case they are compromised or leaked, the malefactor will be able to create a self-signed certificate, or, if lucky enough, even issue the certificate from CA with the SPKI you have backed up in your application. And that is why most experts nowadays tend to the idea that HPKP has failed.

The main practical problem of SPKI pinning implementation, as well as Certificate one, is that in some cases new certificates of your API may be issued too often. This is the case for automatic HTTPS/TLS setup in AWS Certificate Manager, where certificates are issued by Amazon automatically and have 1 year lifetime.

Pros

  • It is OWASP recommended way to implement SSL pinning in application, with out-of-the-box solutions for various platforms.
  • HPKP headers mechanism, based on SPKI pinning, is the industry standard implemented in all modern browsers.

Cons

  • If you don’t want to release a mandatory update on every certificate renewal as with certificate pinning, you should have backup pins embedded in the app, but it’s fully your responsibility to store these backups securely. Compromising them leads to mandatory update and bricking old versions of your app.
  • Another option is to use the same CSR in the certificate renewal process. But this violates the key rotation principle.
  • Not convenient to use in cases when certificate on server rotates too often, and/or your app uses many network services with different certificates.

Public Key pinning

Public key pinning is verification, that the public key of the certificate used to establish a secure connection is the one we can trust. In other words, we compare it with the one embedded in our application and continue connection only when it matches.

In general public key pinning is very similar to SPKI one, with the difference that in SPKI you are pinning public key with an additional info about certificate.

Pros

  • Implementation is straightforward and simple enough, although extraction of public key from certificate may seem to be a non-trivial task.
  • It’s possible to keep the same public key of the certificate if making CSR from the certificate with another private key. That means it’s possible to request another certificate from CA by rotated private key but the same public one.

UPDATE: The previous statement is apparently wrong. Although there exist -force_pubkey option in openssl x509, which could be used in the way described here, the certificate produced with such substitution will be simply invalid, meaning one won’t be able to use it in TLS/SSL connection. The reason is that asymmetric key encryption algorithms used in PKI, like RSA, DSA, ECDSA etc. always have something in common between public and private key called modulus. When someone replaces public key from the Certificate Signing Request, it loses this common part with the private key and thus become invalid. The Con statement below is updated accordingly.

Cons

  • They are basically the same as for SPKI pinning: you have to either use the same CSR when requesting new certificate to persist the public key, either include several pins, i.e. public keys, in the app for future certificates. In both options you will have to rotate the keys and issue a new certificate, and release the mandatory update of your app in the case if the current keys are compromised, e.g. stolen by your ex-employee.

Certificate pinning

While secure connection is establishing the app retrieves the server’s certificate in the callback and compares it with the known certificate embedded in the app. If the comparison fails, then the connection fails as well.

This is the easiest option to implement, because one may fetch the certificate out of band for the website right from the browser. However, when the certificate expires you must update your application with the new certificate and force your users to do this as well, otherwise once the new certificate is installed on your server, your app turns into a brick.

This approach works well if your server uses a limited number of certificates and they don’t rotate too often. There is, however, the limit of lifetime for leaf certificate issued by any CA, which equals 2 years atm. The most frequent lifetime of a leaf certificate is 1 year though, because such certificates are less expensive and are widely used in web service providers setup, like in AWS Certificate Manager.

Pros

  • Easy and straightforward to implement
  • You are totally secure from MitM attack unless your CA is compromised.

Cons

  • Users must be ready to update your application on each change of the certificate for your server or API. In case of frequent certificate rotation, this may cause some issues. Moreover, you must care about strict procedure and force update mechanism in the app for the certificate changed scenario to prevent bricking the app and poor user experience.

Certificate Transparency logs

Google’s Certificate Transparency project aims at fixing several structural flaws in the SSL certificate system. The idea behind it is quite simple.

When Certificate Authorities issue certificates they record this issuance in public Certificate Transparency (CT) logs. CT logs are large databases managed by Cloudflare, Google, and others, that collectively document all valid certificates. Some CT logs provide subscription feature to be notified whenever an SSL certificate is issued for your domain, i.e. it emails an alert whenever your domain is recognized in this CT log. This allows you to confirm the legitimacy of SSL certificates associated with your domain.

In fact, this Google initiative follows Blockchain idea of having several logs that record events in parallel, and in order to prove the authenticity of an event, it should be recorded in several places. In CT this approach is implemented in a way that for the certificate to be trusted, it must have so-called Signed Certificate Timestamp (SCT) records, which are issued by CT logs. Apple requires at least 2 SCT records presented in the certificate to consider it trusted, and even more depending on the certificate lifetime.

SCT check is not required in all browsers nowadays, because the initiative is relatively new, and thus requires time for adoption. But it will certainly become an industry-standard in some near future.

Certificate Authority Authorization

The downside of CT logs monitoring is that you need to make sure it is set correctly. If you don’t react to malicious certificate issuing on time, an attacker may be able to impersonate you within some time. There is another tool that makes this attack a lot harder — Certificate Authority Authorization(CAA).

CAA is a way for you to indicate exactly who is allowed to issue certificates for your domain. It’s implemented as a record to be placed in DNS settings of your naming provider. There are tools online which may help you to form such a record for your domain in the proper format. And in order to use it, your DNS provider must support CAA record.

Root certificate pinning solution with usage of CT logs

Now, having all this information, we may form the next solution for SSL pinning in your app:

  1. Monitor certificates issued for your domain using subscription feature of CT logs. Monitoring 2 sources should be totally enough.
  2. Use CAA DNS record with CA you use to issue trusted certificates for your domain.
  3. Pin against all known root certificates of CA you use, using SPKI hash or fingerprint to check against. Additionally, check for hostname in the leaf certificate to prevent DNS forwarding attacks.

The first and second item in conjunction will help you identify certificates issued by non-authorized CAs, and monitor certificates issued by an authorized one.

Relying on Certificate Transparency logs infrastructure allows you to pin the root certificate only. It has a long enough lifetime, longer than one of an average project or major version of an application at least. You may get all root certificates of your CA by looking in trust storage of the system you are developing for or request them directly from CA you use.

Let’s consider possible MitM attack vectors.

  • Intruding by placing self-signed certificate in device trust storage
  • Issuing certificate for your domain from another CA
  • Issuing certificate from your CA for another domain and applying DNS forwarding

This all won’t work due to the root pinning with the domain check in the leaf certificate. The only case that will work, is issuing a certificate from your trusted CA for your domain. In fact, this may happen if some of your current or ex-employee with necessary permissions wants to harm you. Basically, this means that IT policy in your company is broken. And even in this case you almost certainly will receive notification from CT log and will be able to react properly.

However, there are situations, when your app still may be bricked and require mandatory update:

  • Root CA certificates you are pinning against are compromised and will not be used for signing your domain leaf certificate.
  • Root CA certificates expired.

Have to note, that the frequency of such events is dramatically low, as is the chance that you will require to push mandatory update due to the broken SSL pinning. Nevertheless, it’s recommended to have a mandatory update mechanism implemented in your app, because it may be required in case of other issues as well, e.g. security breaches.

Pros

  • Due to long enough lifetime or the root certificates, and their revocation happens hardly ever, pinning against them will make your app safe from regular mandatory updates due to the expiry of SSL certificate, like in the previous cases.
  • Using CT logs notification mechanism along with CAA DNS record is making it very hard to issue a valid certificate for your domain without you to notice that.

Cons

  • Your app may still require a mandatory update mechanism, to manage rare cases, when the set of root certificates it’s pinning against must be updated.

Conclusion

SSL pinning is a must-have for modern applications that respect user data security and privacy and is an essential part of OWASP guides for several platforms. However, implementation may be not straightforward and require additional features, policies and procedures implemented for your app and the company. Mostly, because Public Key Infrastructure design is not perfect and has some weaknesses. Luckily, the community is developing and providing new approaches to level down these points, which may be used to solve issues of SSL pinning implementation as well.

--

--