What is Certificate Pinning?

Certificate Pinning refers to a technique of associating a host with an expected X.509 certificate, which is a digital certificate using the accepted international X.509 Public Key Infrastructure standard. By creating such an association, a browser or app is able to detect a change in the certificate used by a host, which might, in turn, indicate that a so-called man-in-the-middle attack (MITM) by a black-hat hacker is in progress. A MITM attack can allow the hacker to block, re-route, or look at the contents of traffic between your computer and resources on the internet.

To achieve this certainly used to be not as complex as you some people might assume, especially where people were using older browsers like Internet Explorer and some older SSL security protocols, although now in 2019 it’s now a lot harder for a hacker intercept your web traffic. It’s something that very much could (in the past) be done just by learning some of the clever tools bundled with custom Linux installations such as Kali Linux. With these it was possible to crack wifi using tools such as aircrack and reaver for some WPS passwords (and a custom wifi card), you could employ SSL Stripping (using a range of common tools), or use an “Evil Twin” attack (to clone / impersonate a wireless access points), and especially cases where people might choose to use public wifi connections without running through a VPN (Ref#: X).

N.B. People often refer to website certificates as “SSL certificates” whereas these are X.509 certificates used with TLS (Transport Layer Security), which is the more secure successor to SSL

So “Certificate Pinning” means this linking process; it means that by retaining a record of a pre-existing relationship between a local device like a laptop or smartphone, and a remote party or service. Essentially it’s a strict “form of trust evaluation that requires that the server use a specific certificate or a certificate containing a specific public key” (Ref#: Q).  The use of such techniques is one tool that app developers can use in order to counter the threat of MITM attack vectors, and additional to provide an increased level of security to customers and to prevent competitors and hackers knowing the details of the private APIs our apps use (Ref#: E).

What is Certificate Authority Pinning? (Public Key Pinning)

As well as certificate pinning by extracting the public key from the server’s certificate (potentially in-app by using SecTrustCopyPublicKey) you can also take a looser but potentially less problematic approach of “certificate authority pinning” – checking that the certificate the of the URL your connecting to was issued by the same certificate authority as you were expecting. This variety of pinning then begins with the inclusion of a copy of the certificate authority’s root certificate in your app, then you can create a certificate object from the certificate data SecCertificateCreateWithData and then set that certificate as the only trusted anchor for the trust object SecTrustSetAnchorCertificates, finally you can “evaluate the trust object; if the evaluation succeeds, you know that the server’s certificate is valid and was issued by the certificate authority that you specified” (Ref#: Q).

How can we Implement Certificate Pinning on iOS?

Do it Yourself

URLSession and URLSessionDelegate

In order to achieve pinning using URLSessionDelegate we will implement the:

Delegate method which will request “credentials from the delegate in response to a session-level authentication request from the remote server” (Ref#: R). This has an escaping completion handler that can return an AuthChallengeDisposition based on the logic we place inside it. For example, this could be .cancelAuthenticationChanllenge if or checks fail or .useCredential if or certificate seems to match the one the remote server is giving us back.

Getting a Certificate for a Given Site

When using the native methods, or something like Alamofire, what we could do as a first step is to use OpenSSL from the command line in a terminal window to get a certificate file which we then are able to bundle with our app, like this:

openssl s_client -connect www.apple.com:443 -servername www.apple.com < /dev/null | openssl x509 -outform DER > appleCert.cer

The above would create a local file called appleCert.cer which would store a local copy of the certificate found for the www.apple.com domain name (Ref#: V). We are then able to add the cer file to our app bundle and refer to it from our code.

Example Code:

What happens in this code is we are using some CF or Core Foundation type methods, which means they are written in C. So in the below for example methods like SecTrustGetCertificateAtIndex are in the Security framework but return CFTypes.

We can use code like this to see if the “challenge” contains at least one certificate, “we check for a so-called trust in the challenge. This trust can contain certificates, and we check that it contains at least one. The trust object is a C data structure, so we have to use a specific method to count the certificates”(Ref#: U) :

Then what we want to do is to compare the content of the certificate we find with our local certificate and check that they match. If they do match we call the completion handler and pass an AuthChallengeDisposition of .useCredential. If we don’t get a match we will fall through to calling our completion handler with .cancelAuthenticationChallenge.

We see that “certificate validation should still be performed throughout the chain, which can be achieved by invoking SecTrustEvaluate in the delegate, before the custom certificate checks”(Ref#: E)

Use a Library 

As well as creating your own methods to implement certificate pinning, you could also opt to use a library for this, potentially enabling easier implementation.

TrustKithttps://github.com/datatheorem/TrustKit

This is a newer library that should allow you to define a policy upfront, and to store save some public key hashes which TrustKit will then check against a particular URL when you try and use it to detect any changes in certificates which could point to a MITM attack or insecure connection.

Details for specific implementation can be found on the GitHub page for this library.

AlamoFire

An approach that is not likely to be less popular due to the widespread replacement of AlamoFire with native networking is to use AlamoFire for certificate pinning. This again involved getting the certificate for a given site and defining rules to check this, but with a different and perhaps easier to read syntax to employ when putting this into place.

For specific implementation details see here: https://www.vincentrenais.com/posts/adding-certificate-pinning-to-your-ios-app

What are the Disadvantages of Pinning?

What can happen if a pinned certificate expires and your app isn’t updated to reflect this?

Well, this strictness could be costly if it ends up leading to downtime in your app where you may have bundled an obsolete certificate with your app and have not built in a process of remotely updating this in a secure way. Meaning you may actually need a new build in order to resolve the matter (unless you can get special help from a certificate provider). A scenario like the one we have mentioned happened to Barclays in 2016:

Image result for didReceiveAuthenticationChallenge replacement

Defeating Pinning Locally

Tools to allow pinned traffic to be read or reverse-engineered include:

  • SSLKillSwitch
  • Burp Mobile Assistant
  • Objection and Frida (to override the logic behind certificate validation on jailbroken devices)
  • Using disassemblers to modify the IPA file (such as Hopper or IDA).

For an example use case: as part of a penetration testing (pen testing) process (perhaps commissioned by a company for their new app), an app might be evacuated using these tools to ensure that hackers can’t compromise our systems by using tool like the above to see more details then they should be able to see.

Extra Techniques to Stop the Cracking Tools

We can mitigate the risk of the above cracking methods using hook detection code.  Essentially, we can use what is known as a “trampoline” and then “If a function’s implementation is known in advance, the first few bytes of the found function can be compared to the known bytes, effectively ‘pinning’ the function implementation”(Ref#: D).

Another technique we can use is name obfuscation which involves “using a tool to obfuscate Swift and Objective-C metadata” in your app, but this only works for tools tapping into your own custom methods but not “Tools that work by hooking system frameworks”.

Other techniques include string encryption (encrypting public key hashes) and control flow obfuscation (obfuscating the control flow of your app could make it a lot more difficult to do a manual analysis of the code).

Companies such as approov sell pre-baked solutions to certificate pinning attacks. These try to use some techniques similar to those mentioned above around checking the app bundle data with the aim of detecting modification, and server-side certificate validation to block any snooping using alternate certificates using some proxy tool like Charles Proxy or mitmproxy.

Conclusion

Exploring certificate pinning we have covered what this is, different forms of this and how we can go about implementing it in our iOS apps using either the native Cocoa framework methods or using a third-party library such as TrustKit to try and make the implementation cleaner and simpler to implement. We have seen that the advantages of using certificate pinning include stopping so-called Man-in-The-Middle (MITM) attacks, and it can stop the reverse engineering of your app by competitors hoping to examine the API calls that your app is making using a tool such as Charles Proxy or similar. However, we have also seen some disadvantages to the approach, particularly with the ability to update the pinning after we have shipped our apps, and that this could lead our apps to stop working if the app believes the connection is not secure due to a change or renewal or certificate, or some change in the issuing certificate authority, which the app has not been programmed to accept (as we saw with Barclays in 2016 for example).

 

References

A: https://infinum.co/the-capsized-eight/how-to-make-your-ios-apps-more-secure-with-ssl-pinning

B: https://infinum.co/the-capsized-eight/ssl-pinning-revisited

C: https://medium.com/@dzungnguyen.hcm/ios-ssl-pinning-bffd2ee9efc

D: https://www.guardsquare.com/en/blog/iOS-SSL-certificate-pinning-bypassing

E: https://labs.nettitude.com/tutorials/tls-certificate-pinning-101/

F: https://developer.apple.com/documentation/foundation/nsurlconnectiondelegate/1417135-connection?language=objc

G: https://medium.com/@kPrajakta/ssl-pinning-in-swift-ios-2df85d8f532a

H: https://infinum.co/the-capsized-eight/how-to-make-your-ios-apps-more-secure-with-ssl-pinning

I: https://developer.apple.com/documentation/foundation/nsurlsessiondelegate/1409308-urlsession?language=objc

J: https://developer.apple.com/documentation/foundation/urlsessiondelegate/1409308-urlsession

K: https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/1411595-urlsession

L: https://stackoverflow.com/questions/34223291/ios-certificate-pinning-with-swift-and-nsurlsession

M: https://www.thegeekstuff.com/2012/01/arp-cache-poisoning/

N: https://developer.apple.com/documentation/foundation/url_loading_system/handling_an_authentication_challenge

O: https://medium.com/@kennethpoon/lets-write-swift-code-to-intercept-ssl-pinning-https-requests-12446303cc9d     ***

P: https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#iOS

Q: https://developer.apple.com/library/archive/technotes/tn2232/_index.html

R: https://developer.apple.com/documentation/foundation/urlsession/authchallengedisposition

S: https://blog.netspi.com/four-ways-to-bypass-ios-ssl-verification-and-certificate-pinning/

T: https://github.com/nabla-c0d3/ssl-kill-switch2

U: https://talk.objc.io/episodes/S01E57-certificate-pinning

V: https://www.vincentrenais.com/posts/adding-certificate-pinning-to-your-ios-app

W: https://www.prolificinteractive.com/2015/04/17/ios-workaround-for-public-key-pinning/

X: https://www.udemy.com/penetration-testing/learn

XA: https://www.youtube.com/watch?v=bHYZl1IC9SE

XB: https://blog.approov.io/steal-that-api-key-with-a-man-in-the-middle-attack

XC: https://blog.approov.io/toughen-up-soft-certificate-pinning-with-approov

XD: https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning

XE: https://www.symantec.com/content/dam/symantec/docs/white-papers/certificate-pinning-en.pdf

XF: https://developer.apple.com/documentation/security/preventing_insecure_network_connections

Updated: 31th May 2019

Last modified: February 7, 2020

Author

Comments

Comments