Skip to content
Last updated: April 27, 2024

Testing Custom Certificate Stores and Certificate Pinning


Static Analysis

Verify that the server certificate is pinned. Pinning can be implemented on various levels in terms of the certificate tree presented by the server:

  1. Including server's certificate in the application bundle and performing verification on each connection. This requires an update mechanisms whenever the certificate on the server is updated.
  2. Limiting certificate issuer to e.g. one entity and bundling the intermediate CA's public key into the application. In this way we limit the attack surface and have a valid certificate.
  3. Owning and managing your own PKI. The application would contain the intermediate CA's public key. This avoids updating the application every time you change the certificate on the server, due to e.g. expiration. Note that using your own CA would cause the certificate to be self-singed.

The latest approach recommended by Apple is to specify a pinned CA public key in the Info.plist file under App Transport Security Settings. You can find an example in their article Identity Pinning: How to configure server certificates for your app.

Another common approach is to use the connection:willSendRequestForAuthenticationChallenge: method of NSURLConnectionDelegate to check if the certificate provided by the server is valid and matches the certificate stored in the app. You can find more details in the HTTPS Server Trust Evaluation technical note.

The following third-party libraries include pinning functionality:

  • TrustKit: here you can pin by setting the public key hashes in your Info.plist or provide the hashes in a dictionary. See their README for more details.
  • AlamoFire: here you can define a ServerTrustPolicy per domain for which you can define a PinnedCertificatesTrustEvaluator. See its documentation for more details.
  • AFNetworking: here you can set an AFSecurityPolicy to configure your pinning.

Dynamic Analysis

Server certificate pinning

Follow the instructions from the Dynamic Analysis section of "Testing Endpoint Identity Verification. If doing so doesn't lead to traffic being proxied, it may mean that certificate pinning is actually implemented and all security measures are in place. Does the same happen for all domains?

As a quick smoke test, you can try to bypass certificate pinning using objection as described in "Bypassing Certificate Pinning". Pinning related APIs being hooked by objection should appear in objection's output.

However, keep in mind that:

  • the APIs might not be complete.
  • if nothing is hooked, that doesn't necessarily mean that the app doesn't implement pinning.

In both cases, the app or some of its components might implement custom pinning in a way that is supported by objection. Please check the static analysis section for specific pinning indicators and more in-depth testing.

Client certificate validation

Some applications use mTLS (mutual TLS), meaning that the application verifies the server's certificate and the server verifies the client's certificate. You can notice this if there is an error in Burp Alerts tab indicating that client failed to negotiate connection.

There are a couple of things worth noting:

  1. The client certificate contains a private key that will be used for the key exchange.
  2. Usually the certificate would also need a password to use (decrypt) it.
  3. The certificate can be stored in the binary itself, data directory or in the Keychain.

The most common and improper way of using mTLS is to store the client certificate within the application bundle and hardcode the password. This obviously does not bring much security, because all clients will share the same certificate.

Second way of storing the certificate (and possibly password) is to use the Keychain. Upon first login, the application should download the personal certificate and store it securely in the Keychain.

Sometimes applications have one certificate that is hardcoded and use it for the first login and then the personal certificate is downloaded. In this case, check if it's possible to still use the 'generic' certificate to connect to the server.

Once you have extracted the certificate from the application (e.g. using Frida), add it as client certificate in Burp, and you will be able to intercept the traffic.