SSL Pinning with Alamofire 5.

Oleksandr Stepanov
Nov 4 · 7 min read
photo source

In the previous story, it has been reviewed several approaches to implement SSL pinning from the theoretical aspect. In this story, we are going to review the practical side of problem with the help of the well known for Apple platform developers Alamofire framework.

It’s important to note, that according to investigations, a big part of applications that implement SSL pinning do this wrong. This leads to the false perception of safety, which is even worse than not having the pinning implemented at all. That is why it is very important to use known and widely used solutions instead of copy-paste of the first code snippet found in Google.

ServerTrust API in Alamofire 4 vs 5

The Server Trust API has been significantly revised between 4.x.x and 5.x.x Alamofire versions.

In the previous implementation, ServerTrustPolicy was enum with all the options to evaluate against. SSL pinning is just one of the security evaluation form. Policy could be used in the map of hosts to initialize ServerTrustPolicyManager instance with. This manager then may be used as a parameter in the initializer of SessionManager, which is responsible for performing actual HTTPS requests. Such design, when the manager is initialized with a map where each key is a host, leads to the fact that it’s not possible to use several evaluation techniques for the same host.

I am going to describe ServerTrust API from the 5th major version of Alamofire, which by the time of writing this post is in 5.0.0-rc.3 stage. In this version, Policies are transformed into Evaluators and each of them is a final class implementing the ServerTrustEvaluating protocol. The map of hosts to evaluators is passed then in the ServerTrustManager initializer, which is used as a parameter of the Session object. Design is quite similar to version 4, but the presence of CompositeTrustEvaluator solves the issue with several evaluations for the same host mentioned above.

I am going to review next evaluators in details:

  • RevocationTrustEvaluator.
  • PublicKeysTrustEvaluator.
  • PinnedCertificatesTrustEvaluator.

Pinning against SPKI, which is recommended approach by OWASP, is not implemented as part of Alamofire atm. There is an open PR with SPKI evaluator implementation though. I will update this post if it will pass through, but I have doubts, to be honest. There is a dedicated TrustKit library with SPKI pinning implementation. I’m personally not a big fan of it, and I’m not alone. Google has deprecated HPKP support in Chrome in favor of Certificate Transparency Logs infrastructure .

RevocationTrustEvaluator

This evaluator uses the default and revoked server trust evaluations. It supports both revocation checks available in Apple’s Security.framework for the moment: CLR and OCSP.

CLR

CLR (Certificate Revocation Lists) contains a list of certificate serial numbers that have been revoked by the CA. The client looks for the serial number from the obtained certificate against this list. If found – the check is failed. The main disadvantage of this approach is its overhead: the client must download the list and make a search. This slow downs requests a lot, taking into account that the list may be of several Mb size.

This method is represented with .crl option. Combined with .networkAccessDisabled previously cached list will be checked if exist.

OCSP

OCSP (Online Certificate Status Protocol) enhances CLR by providing API to check particular certificate in the list, not requiring to download it manually. While such approach is slightly better, but it doesn’t mitigate all the issues. The client still requires additional request to check, which may produce a huge workload on CA servers. Another issue: request may be intercepted by the MitM attack resulting in a fake positive response from CA.

This method is represented with .ocsp option and by default is preferred over CLR.

OCSP Stapling

OCSP Stapling resolves the overhead issues of OCSP by having the certificate holder (i.e the server) periodically performing the OCSP Request. Signed OCSP Response is then sent back to the client (i.e stapled) during the SSL handshake. In other words, OCSP request is moved from the client to the server.

Worth to note, that OCSP stapling must be configured on the server-side, and it may be not an easy task for DevOps on your project. In cases when you don’t own the server you are validating requests from, this option may be not feasible at all.

Moreover, Apple documentation is not quite clear on how to perform OCSP stapling. According to the research made in rdar://716337334, this type of check could be achieved by specifying [.ocsp, .networkAccessDisabled] options for the RevocationTrustEvaluator.

NOTE: Both methods may be combined with .requirePositiveResponse option, which will require a positive response for the check. By default, if the server couldn’t be achieved, the check is not considered as not passed.

PublicKeysTrustEvaluator

This evaluator uses the pinned public keys to validate the server’s trust. The server trust is considered valid if one of the pinned public keys match one of the server certificate public keys.

This type of check mitigates most, if not all MitM attack vectors. The reason is that public key in asymmetric encryption algorithms has some common part with the private key called modulus, and even faking certificate with known public key like described here, does not produce a valid certificate to establish HTTPS/TLS connection. Eavesdropper simply will not be able to establish a TLS handshake itself without the corresponding private key.

PublicKeysTrustEvaluator initializer takes 3 arguments:

  • keys. This is an array of SecKey objects, which represents public keys you are pinning against. By default, they are initialized with the public keys extracted from the certificates located in the main Bundle. Alamofire is looking for files with extensions .cer, .crt and .der, case-insensitive tries to parse them as a certificate in DER format and extract the key.
  • performDefaultValidation. This parameter determines whether there is a need to perform validation of the certificate chain additionally to public key check. This is, actually, evaluation of SecPolicyCreateSSL without hostname validation. Such evaluation prevents attack on certificate roles. Must be on for the release configuration.
  • validateHost. With this parameter set to true, the evaluation of SecPolicyCreateSSL will happen with the hostname validation. As for the previous parameter, must be on for the release configuration.

PinnedCertificatesTrustEvaluator.

This evaluator uses pinned certificates to validate the server’s trust. The server trust is considered valid if one of the pinned certificates matches one of the server certificates in the chain.

Like the public key pinning, this type of validation covers all MitM attack vectors. Even if the malefactor will be able to get a valid certificate from rouge CA, as this happened in DigiNotar case, the certificate parameters can’t be duplicated without knowing your private key. That is a cornerstone of asymmetric encryption algorithms.

PinnedCertificatesTrustEvaluator initializer takes 4 arguments:

  • certificates. This is an array of SecCertificate objects, which represents the certificates you want to pin. Just as in PublicKeysTrustEvaluator case, Alamofire will look for the certificates in the main bundle. Note that they must be in DER format.
  • acceptSelfSignedCertificates. This flag controls whether self-signed certificates are accepted. This may be useful for debugging purposes when dev or stage backend API environment doesn’t have a valid certificate and uses a self-signed one. This flag should be off in production.
  • performDefaultValidation and validateHost have the same meaning as for PublicKeysTrustEvaluator.

In general, it’s ok to store certificates in the app bundle, because they doesn’t contain any private information. However, techniques of iOS Code Injection described here, and .ipa patch tools like this are making it very easy to replace the certificate file in your app bundle with another public key, and thus, make your app vulnerable for MitM attacks.

To work around this issue, I would recommend to extract and bake the certificate data in code as base64 string, convert it to SecCertificate and pass it to PinnedCertificatesTrustEvaluator initializer. Here is a step-by-step guide:

  • First, you need the certificate in the DER format. You may get it from a browser or use the next command in bash:
  • Next, get base64 encoding representation of the certificate file:
  • Copy the output from the command above and place it in the next snippet:

Storing the certificate this way will not prevent one from hacking your app at all, but at least it will require way another set of skills and motivation to do this.

NOTE: Inquisitive reader may argument that using code injection techniques the malefactor doesn’t really require to change the certificate or key you are pinning in the app. It would be enough to disable pinning at all by swizzling the URLSessionTaskDelegate method func urlSession(_ session:, task:, didReceive challenge:, completionHandler:). However this topic is out of the post bounds and I plan to cover defense approaches to this attack in one of the next stories.


The list of the evaluators available in Alamofire framework would not be the full without these two:

  • CompositeTrustEvaluator. It must be initialized with the list of evaluators. The trust is only considered valid if all of the evaluators consider it valid.
  • DisabledEvaluator. This evaluator is for Debug builds only and may be used if the backend server temporary doesn’t provide a valid certificate. THIS EVALUATOR SHOULD NEVER BE USED IN PRODUCTION.

Conclusion

Alamofire framework provides a very good API to implement SSL pinning in an app targeting any Apple platform. It’s a well-known solution with a good coverage by tests. Nevertheless, usage of a widely used framework does not guarantee you are secure from the bugs and possible threats in the future. So it’s always important to keep an eye on the updates of security solutions you use on your project.

Oleksandr Stepanov

Written by

Lead iOS developer at Clario Tech.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade