Search code examples
sslhttpsssl-certificatetls1.2starttls

Public key pinning vs Certificate Pinning in mobile apps


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...


Solution

  • 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.