Public key pinning vs Certificate Pinning in mobile apps

Viewed 3040

Scenario :

  • I have pinned public key pin SHAs of 3 certificates : Root CA , Intermediate CA and Leaf CA in my android application.

What I have understood ( Please correct me if I'm wrong anyway here ) :

  • Public key pinning is used so that we can check if the public key of the cert that our server is issuing is changed or not. source

  • A certificate is valid if its public key SHA is the one which we have "pinned" in our application. To check the public key , first it will decrypt the signature using the public key and makes sure that the same public key is in the data of that signature also.

  • When the Leaf cert has expired but is corresponding to the valid "pinned" public key SHA, the chain of certificates is checked to see if they are valid and if one of them is valid , the certificate is accepted and the connection is established.

  • When the Leaf cert I got is having an invalid public key but is not expired , then that means I got a wrong certificate from someone which may be an attacker.

Question :

  • Does public key pinning in any way help in security , if an attacker compromises a client and installs his own trusted CA and then does an MITM on the client to intercept all communication by presenting his own forged certificate signed by the CA he has installed on the client device.

  • How does direct certificate pinning VS public key pinning make a difference here in any way ?

  • What is the implication of using a self signed certificate in the above questions.

Please help me understand this with as much detail as possible...

2 Answers

When the Leaf cert has expired but is corresponding to the valid "pinned" public key SHA, the chain of certificates is checked to see if they are valid and if one of them is valid , the certificate is accepted and the connection is established.

No. An expired certificate is not accepted. Pinning does not override that basic principal of TLS but enhances it to reduce the number of certificates accepted.

Does public key pinning in any way help in security , if an attacker compromises a client and installs his own trusted CA and then does an MITM on the client to intercept all communication by presenting his own forged certificate signed by the CA he has installed on the client device.

For browsers, manually installed trusted CAs are exempt from pinning requirements. To me this is a fundamental flaw in pinning. Though to be honest once you have access to install root certs on a machine it’s pretty much game over. Anyway, this exception is necessary to allow Virus scanners, Corporate proxies and other intercepting proxies to work - otherwise any pinned site could not be accessed when behind one of these proxies though it does weaken HPKP (HTTP Public Key Pining) in my mind.

For apps (your use case) pinning can be useful to prevent MITM attacks.

How does direct certificate pinning VS public key pinning make a difference here in any way ?

Don’t understand? When you pin a direct certificate you basically pin the public key of that certificate (well actually the SHA of the private key that cert is linked too).

This means you can reissue the certificate from same private key (bad practice in IMHO) and not have to update pins.

You can also pin from the intermediate or even root public key. This means you can get your CA to reissue a cert and again not have to update the pin. That of course ties you into that CA but at least doesn’t allow some random CA to issue a cert for your site.

What is the implication of using a self-signed certificate in the above questions.

For browsers, pinning basically can’t be used with a self-signed cert. because either it’s not recognised by browser (so pining won’t work) or its is by trusting by manually installing the issuer - at which point pinning is ignored as per point above.

For apps (again your use case), I understand self-signed certificates can be pinned. Though it depends on which HTTP library you use and how that can be configured.

One of the downsides of pinning the certificate itself (which might be the only way to do it, if it's a single leak self-signed certificate), is that reissuing the certificate will invalidate the old pins (unless you reuse the same private key but this may not be possible if the re-issue reason is due to key compromise). So if you app makes an HTTP call home to check if there is a new version or such like, then that call might fail if certificate is re-issued and new version of the app has not been downloaded yet.

Nearly browsers have deprecated HPKP as it was massively high risk compared to the benefits and there were numerous cases of breakages due to pinning. See Wikipedia: https://en.m.wikipedia.org/wiki/HTTP_Public_Key_Pinning. Monitoring for mis-issued certificates through Certificate Transparency is seen as a safer option.

Pinning still seems somewhat popular in mobile app space because you have greater control over an app and can re-release a new version in case of issues. But it is still complicated and risky.

My Answer Context

Scenario :

I have pinned public key pin SHAs of 3 certificates : Root CA , Intermediate CA and Leaf CA in my android application.

My answer will be in the context of pinning in a mobile app. anyway the new browsers don't support pinning any-more.

Pinning and Security

Does public key pinning in any way help in security

It helps a lot, because your mobile app only communicates with a server that presents the certificate with a matching pin. For example, if you do public key pinning and you rotate the certificates in your backend while signing it with a different private/public key pair then your mobile app will refuse to connect to your own server until you release a new version of the mobile app with the new pins.

MitM attack and Pinning

if an attacker compromises a client and installs his own trusted CA and then does an MITM on the client to intercept all communication by presenting his own forged certificate signed by the CA he has installed on the client device.

When you are pinning the connection the attacker will not succeed, because this is for what pinning was designed for, to protect against manipulation of the certificates trust store on the device in order to carry on a MitM attack. From Android API 24 user provided certificates are not trusted by default, unless the developer opts-in to trust on them via the network security config file:

<base-config cleartextTrafficPermitted="false">
    <trust-anchors>
        <!-- THE DEFAULT BEHAVIOUR -->
        <certificates src="system" />

        <!-- DEVELOPER ENABLES TRUST IN USER PROVIDED CERTIFICATES -->
        <certificates src="user" />
    </trust-anchors>
</base-config>

You can read the article I wrote to see pinning in action and not allowing for a MitM attack to succeed:

In order to demonstrate how to use certificate pinning for protecting the https traffic between your mobile app and your API server, we will use the same Currency Converter Demo mobile app that I used in the previous article.

In this article we will learn what certificate pinning is, when to use it, how to implement it in an Android app, and how it can prevent a MitM attack.

In the article I go into detail how to implement pinning, but nowadays I recommend instead the use of the Mobile Certificate Pinning Generator online tool, that will generate the correct network security config file to add to your Android app. For more details on how to use this tool I recommend you to read the section Preventing MitM Attacks in this answer I gave to another question where you will learn how to implement static certificate pinning and how to bypass it:

The easiest and quick way you can go about implementing static certificate pinning in a mobile app is by using the [Mobile Certificate Pinning Generator](Mobile Certificate Pinning Generator) that accepts a list of domains you want to pin against and generates for you the correct certificate pinning configurations to use on Android and iOS.

Give it a list of domains to pin:

Config tab on the mobile certificate pinning generator web page

And the tool generates for you the Android configuration:

Android certificate pinning configuration

The tool even as instructions how to go about adding the configurations to your mobile app, that you can find below the certificate pinning configuration box. They also provide an hands on example Pin Test App for Android and for iOS that are a step by step tutorial.

This approach will not require a release of a new mobile app each time the certificate is renewed with the same private/public key pair.

Certificate Pinning vs Public Key Pinning

How does direct certificate pinning VS public key pinning make a difference here in any way ?

When using certificate pinning a new mobile app needs to be released and users forced to update each time the server certificate is rotated, while with public key pinning no need for this unless the private/public key pair used to sign the certificate changes. For example, if your server uses LetsEncrypt for the certificates you don't need to release a new mobile app version each time they are renewed.

Self Signed Certificates

What is the implication of using a self signed certificate in the above questions.

You will need to opt-in via the network security config file for the Android OS to trust in user provided certificates and instruct the user to add it to his mobile device. This will make an attacker life easier if pinning is not being used. I would recommend you to stay away of using self signed certificates.

Related