SSL Pinning in iOS Without Bundled Certificates

Hello,

We recently implemented SSL pinning in our iOS app (Objective-C) using the common approach of embedding the server certificate (.cer) in the app bundle and comparing it in URLSession:didReceiveChallenge:. This worked fine initially, but when our backend team updated the server certificate (same domain, new cert from CA), the app immediately started failing because the bundled certificate no longer matched.

We’d like to avoid shipping and updating our app every time the server’s certificate changes. Instead, we are looking for the Apple-recommended / correct approach to implement SSL pinning without embedding the actual certificate file in the app bundle.

Specifically:

. Is there a supported way to implement pinning based on the public key hash or SPKI hash (like sha256/... pins) rather than the full certificate?

. How can this be safely implemented using NSURLSession / SecTrustEvaluate (iOS 15+ APIs, considering that SecTrustGetCertificateAtIndex is deprecated)?

. Are there Apple-endorsed best practices for handling certificate rotation while still maintaining strong pinning?

Any guidance or code samples would be greatly appreciated. We want to make sure we are following best practices and not relying on brittle implementations.

Thanks in advance!

Answered by DTS Engineer in 855498022
Are there Apple-endorsed best practices for handling certificate rotation while still maintaining strong pinning?

No. TLS pinning is very much a two-edge sword, and you’ll have to make your own determination as to whether you want to implement it or not [1].

On the technical side of this, there are two ways you can approach TLS pinning:

  • Starting with iOS 14, App Transport Security supports various declarative options. For more on that, see the NSPinnedDomains property.
  • If that’s not sufficient, you can modify the technique you’re already using to pin the public key. Call SecTrustCopyCertificateChain to get the certificate chain from your trust object. Call SecCertificateCopyKey to get the public key from a certificate. Call SecKeyCopyExternalRepresentation to get the raw bytes from the public key.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] TLS pinning will cause your app to fail in the presence of TLS inspection. While some uses of TLS inspector are malicious, some are absolutely legitimate. For example, various enterprises deploy TLS inspection as part of their security policy. If you deploy TLS pinning, your app won’t work in such environments.

Are there Apple-endorsed best practices for handling certificate rotation while still maintaining strong pinning?

No. TLS pinning is very much a two-edge sword, and you’ll have to make your own determination as to whether you want to implement it or not [1].

On the technical side of this, there are two ways you can approach TLS pinning:

  • Starting with iOS 14, App Transport Security supports various declarative options. For more on that, see the NSPinnedDomains property.
  • If that’s not sufficient, you can modify the technique you’re already using to pin the public key. Call SecTrustCopyCertificateChain to get the certificate chain from your trust object. Call SecCertificateCopyKey to get the public key from a certificate. Call SecKeyCopyExternalRepresentation to get the raw bytes from the public key.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] TLS pinning will cause your app to fail in the presence of TLS inspection. While some uses of TLS inspector are malicious, some are absolutely legitimate. For example, various enterprises deploy TLS inspection as part of their security policy. If you deploy TLS pinning, your app won’t work in such environments.

SSL Pinning in iOS Without Bundled Certificates
 
 
Q