A TLS Pinning Journey, Part #1

Antoine Marandon
Eureka Engineering
Published in
4 min readOct 8, 2020

Some time ago, I pitched the idea of implementing certificate/pubkey pinning in our apps. Altho the idea was well received, I wanted to come with better data to understand the implications of this implementation.

What is TLS pinning ?

Overview

When a client talk to a server, it use TLS to cipher and authentify the connection with the server. The authentification (making sure you are talking to the server you intend to speak to), is done by the server presenting a certificate to the client.

What is a certificate?

To summary, a certificate contains:

  • A public key (used by the client to cypher the data sent to the server)
  • Some optional fields about the organization that owns the certificate (company name, location, …)
  • The domain (or subdomain) it is valid for.
  • A validity period
  • An issuer (who created the certificate)

The chain of trust

How do I know I can trust a certificate ?

Well, you trust it because the certificate issuer said you could trust it.

How do I trust the issuer ?

Because the issuer has a certificate too! The issuer have an Intermediate Certificate, that is used to sign the server certificate, This certificate is usually sent together with the website certificate, but accessible through an other request.

How do I trust the issuer’s certificate ?

You have a list of root certificates: They are pre installed on your computer either bundled by your browser or operating system (or both).

Threat model

This looks good! Why do we need pinning?

  • An intermediate certificate authority could issue bogus certificates, either by malice or because it was hacked.
  • The user could have installed a bogus root certificate.

Are this threats credible?

Yes.

  • Certificate authority have been compromised in the past, have issued bad certificates, and overall and are prime target for nation state attackers.
  • Users are often prompted by malware to install malicious root certificates
  • Companies often ask users to install root certificates.

In all these cases, it enable Man In the Middle attacks (MITM):

  • The attacker can impersonate your server by presenting a certificate claiming to be your server, but signed by one of his own certificate authority (root or intermediate)
  • The attacker can run a TLS proxy: Connect to your server himself and forward the client’s requests, while presenting the client a fake (but trusted) certificated.

TLS pinning protects exactly against these. Since we bypass the chain of trust mechanism and embedding the public key or certificate in the app, the client can make sure that the certificate is legitimate.

Implementing TLS pinning must be done very carefully

TLS pinning is neat, but it’s a double edged sword. It require an additional involvment on the developer side, and any mistake might disable all network connectivity in your app. Users who are being presented fake certificates will also (depending on your implementation) not be able to access your server. That might be the whole point of TLS pinning, but there are some legitimate use cases of TLS proxies:

  • Companies uses it to monitor their employees
  • Ad blocking software sometimes uses it
  • Parent Control system can make use of it
  • The user might want to inspect the data you send over to internet

So… what to do?

As a first impact study, I decided to investigate how many users could be affected by TLS pinning.

FoundationURLPubKeyExtractor

I created a small library for iOS to extract the public key associated with an HTTPS URL.

This allow us to check how many users are getting TLS proxied, and understand better the impact of any implementation decision.

How does it works? (Swift/Fundation implementation)

Implementation

1. Setup a URLSessionDelegate

Explanation:

  1. Create a new URLSession, and assign a URLSessionDelegate
  2. Create a request to the parameter URL, and send it to the URLSession (effectively, launch a query to the URL to retrieve the TLS informations)
  3. Provide a callback during the TLS handcheck

2. Extract the key

Now that we have the raw key data, we could send it as is, or base64 encoded for JSON serialization. Since we don’t really care about the actual value (we just want to know wether it’s the same as ours or not), and we must keep a low data usage, we hash it:

Conclusion

Implementing TLS pinning can improve the security of your apps, but have some serious implications. Using this tool, we can give an estimate of how many users would be affected by TLS pinning. You can also associate it with user ids to help us troubleshot individual connectivity issues.

--

--