DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Performance Optimization Techniques in Flutter 3.41 for Mobile App Development
  • GraphQL vs REST — Which Is Better?
  • 5 Challenges and Solutions in Mobile App Testing
  • Scaling QA Processes for Enterprise App Development: A Practical Guide

Trending

  • How RAG Cuts Hallucinations in Generative AI Chatbots
  • What Nobody Tells You About Running AI Models in Docker
  • How to Break Up Swift Concurrency
  • TensorFlow vs PyTorch: The Real Difference Isn’t Accuracy

SSL Certificate Pinning on iOS Using TrustKit

With the proliferation of mobile and wearable tech, the security of these devices has never been more important. Learn how to better secure your iOS code.

By 
Dmitry Fink user avatar
Dmitry Fink
·
Jul. 26, 17 · Tutorial
Likes (0)
Comment
Save
Tweet
Share
8.7K Views

Join the DZone community and get the full member experience.

Join For Free

In past posts, I covered why certificate pinning in mobile apps is important and illustrated 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 very quickly, when you have to support various legacy iOS platforms, various popular networking libraries out there, etc. Luckily, the nice folks at DataTheorem have created and open-sourced a framework for SSL pinning that simplifies most of this process. The framework, called TrustKit, makes it very easy to integrate pinning into your mobile application. In the following tutorial, we’ll show you 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 redeploy our application with the new certificate, with a risk of some users getting 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, expect them in a base64 encoded format, so, for reasons of convenience, 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. Let's 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, let's 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 auto-detect 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 it's 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)
    }

That's it, we're 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.

mobile app

Published at DZone with permission of Dmitry Fink. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Performance Optimization Techniques in Flutter 3.41 for Mobile App Development
  • GraphQL vs REST — Which Is Better?
  • 5 Challenges and Solutions in Mobile App Testing
  • Scaling QA Processes for Enterprise App Development: A Practical Guide

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook