Bugsee

  • Pricing
  • Docs
  • FAQ
  • Blog
  • Is Bugsee Any Good?
  • Live demo
  • Login
  • Free Sign Up
Dashboard

SSL certificate pinning on iOS using TrustKit

Posted By

Dmitry Fink

Posted On

July 18, 2017

We have already covered why certificate pinning in mobile apps is important and have shown how to implement it both in iOS and Android. For the sake of simplicity, we had to omit a lot of nasty details and corner cases from our example. In the real world, the code might get complex with time very quickly, when you have to support various legacy iOS platforms, various popular networking libraries out there etc. Luckily, nice folks at DataTheorem have created and open-sourced a framework for SSL pinning which eliminates that simplifies most of it. The framework, called TrustKit, and makes it very easy to integrate pinning into your mobile application. In the following tutorial we’ll show how to use it on iOS.

Installing the framework

It is trivial to install the TrustKit framework using CocoaPods.

Just run the following to your Podfile:

pod 'TrustKit'

and run:

pod install

Alternatively, TrustKit is available through Carthage as well.

Add the following line to your Cartfile:

github "datatheorem/TrustKit"

and run:

carthage build --platform iOS

Preparing the pins

As we explained in our introduction tutorial, you can pin either the certificate itself or the public key from within the certificate. The latter is preferred, since on many occasions, for security reasons, the certificates are being rotated regularly and we will have to re-deploy our application with the new certificate, with a risk of some users becoming locked out. We’ve also shown that it is better for the app to store just the hash of the public key, not the key itself. TrustKit takes the same approach. For each domain it expects to have a list of hashes of public keys to pin. It does however expects them in a base64 encoded format, so for convenience reason a special tool is provided within the TrustKit package to help prepare them.

As with the previous example, we will use www.google.com as an example. Lets first extract the certificate from the domain:

openssl s_client -connect www.google.com:443 -showcerts < /dev/null | openssl x509 -outform DER > google.der

Now lets run the provided helper script to extract the hash of the public key:

python get_pin_from_certificate.py --type DER ../google.der

In our example we are using a binary DER format when working with certificates. You have your certificate provided to you in a different text PEM format. In that case, simply omit the –type DER part and call the script on your PEM file directly.

The result is going to be the following:

CERTIFICATE INFO
----------------
subject= /C=US/ST=California/L=Mountain View/O=Google Inc/CN=www.google.com
issuer= /C=US/O=Google Inc/CN=Google Internet Authority G2
SHA1 Fingerprint=FB:BD:7E:87:A8:A6:EB:FC:3E:E0:BE:F8:2E:3A:EB:9C:7D:86:7F:AA
TRUSTKIT CONFIGURATION
----------------------
kTSKPublicKeyHashes: @[@"U9GGUC1+PGI7SLb8XVVuuBPLkQKbQ2LnfU5Wfe7WAAg="] // You will also need to configure a backup pin
kTSKPublicKeyAlgorithms: @[kTSKAlgorithmRsa2048]

Note that the output of the script has both the hash and the algorithm used. This is in fact a nice touch, TrustKit supports several algorithms and will autodetect and handle it automatically for us. Notice the output of that script is even giving us Objective-C elements so we can copy paste them into our code directly. Unfortunately we will be using Swift for our example, but TrustKit gets extra points for this.

Initializing TrustKit

Now its time to initialize the framework:

        let trustKitConfig = [
            kTSKSwizzleNetworkDelegates: false,
            kTSKPinnedDomains: [
                "google.com": [
                    kTSKIncludeSubdomains : true,
                    kTSKPublicKeyAlgorithms: [kTSKAlgorithmRsa2048],
                    kTSKPublicKeyHashes: [
                        "U9GGUC1+PGI7SLb8XVVuuBPLkQKbQ2LnfU5Wfe7WAAg=",
                        "WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18="
                    ],]]] as [String : Any]
        TrustKit.initialize(withConfiguration: trustKitConfig)

The pinned domains is an array, so we can actually pin several different domains in our application, each with a specific set of hashes and settings.

Why do we have 2 hashes in the hashes list? TrustKit will actually fail and not let you start with one. The idea is you have to create a backup key, so in case your primary gets compromised, you will have a way to replace the certificates on your server without locking out your users.

Validating secure connections

Now that everything is set up, we are ready to use the TrustKit mechanism to actually validate each and every connection our application is going to open. In order to do this, we will make sure our URLSession delegate implements the didReceive challenge method:

    func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void) {
        // Let TrustKit handle it
        TSKPinningValidator.handle(challenge, completionHandler: completionHandler)
    }

Thats it, we are done. Every time our URLSession will try to establish an SSL connection to google.com or one of its subdomains, TrustKit will make sure to extract the certificate and the public key, hash the key and compare it to the list we’ve passed during initialization. And it will work on all iOS/watchOS/tvOS and macOS versions.

Uncategorized

←SSL certificate pinning in iOS applications
Using Fastlane to create iOS Ad-Hoc distribution on Amazon S3→

Recent Posts

  • iOS App Testing Tools, Techniques, & Best Practices for Modern QA Teams

    May 1, 2025
  • Best Apache Cordova Alternatives in 2025: A CTO’s Migration Guide

    April 23, 2025
  • Complete Guide to React Native Deployment for iOS and Android

    April 10, 2025

Recent Categories

  • Uncategorized

Post Archive

  • May 2025
  • April 2025
  • March 2025
  • February 2025
  • January 2025
  • September 2022
  • January 2019
  • June 2018
  • March 2018
  • December 2017
  • October 2017
  • July 2017
  • June 2017
  • May 2017
  • April 2017
  • March 2017
  • January 2017
  • December 2016
  • November 2016
  • August 2016

Category Tags

iOS

Connect With Us

  • Facebook
  • X
  • LinkedIn

Products

Bugsee for iOS

Bugsee for Android

Bugsee for React Native

Bugsee for Cordova

Bugsee for .NET/MAUI

Bugsee for Xamarin

Bugsee for Flutter

Bugsee for Unity

Learn

About

FAQ

Documentation

Blog

Contact

Email

Chat

  • Facebook
  • X
  • LinkedIn

@ 2024 Bugsee Inc

All rights reserved

Privacy policy

Terms of Service