HTTP Public Key Pinning (HPKP) is a security measure for the HTTPS enabled websites to prevent/protect from impersonation using fraudulent certificates issued by rogue or compromised certificate authorities. This is done by a technique called ‘pinning’ the fingerprint of specific public keys, that the browser is allowed to trust going forwards. These keys could be the domain’s own keys(leaf) or end entity (EE), the intermediate key or a root key. By effectively reducing the number of trusted authorities who can authenticate the domain during the lifetime of the pin, it will lower the risk of man-in-the-middle attacks due to compromised Certification Authorities.
The site owner defines pin rules for his domain name via HTTP header. The major downside is, that HPKP is a ‘Trust on First Use’ (TOFU) mechanism. It assumes that user has a first clean connection to the site.
Now, let me explain the process of Pinning.
Pinning associates a host with their expected X509 certificate or public key. Once a certificate or public key is known or seen for a host, the certificate or public key is associated or ‘pinned’ to the host. If more than one certificate or public key is acceptable, then the program holds a pinset.
Next, we need to decide on what to pin. The different options are,
1) Pin the certificate
2) Certificate signing request (CSR)
3) Public key
If we are choosing public keys, there are two additional choices:
(a) Subject Public Key Info
(b) RSA Public Key or DSA Public Key
To set this up, HPKP has no special Web Server requirements other than mod_headers module. We just need to add a new header.
It requires a base64-encode of a SHA256 hash of one of the certificates on the website’s authentic certificate chain, along with a backup pin and a period of time during which the user agent will enforce Public Key Pinning.
A Backup Pin is a fingerprint for the public key of a secondary, not-yet-deployed key pair. A new key pair should be generated offline, and can use it as backup pin in the HPKP header. Then, in case we lose control of the primary private key, we can deploy the backup key pair. User Agents, who have had the backup key pair pinned (when it was set in previous valid Pinning Headers), can connect to the host without error.
Pinning the Leaf
A “leaf certificate” is commonly known as end-entity certificate. Certificates come in chains, starting with the root CA, each certificate being the CA which issued (signed) the next one. The last certificate is the non-CA certificate which contains the public key you actually want to use.
When we pin the leaf, we’re telling the browser to only ever trust this particular public key and no other. If another CA were to issue a rogue certificate for your domain, the browser would reject it as it would be using a different public key.
HPKP forces you to create backup pins and in this situation, you would need to create some backup key pairs and pin the public key from those. Your backup pins can be used, if private key gets compromised or when the existing certificate expires. You can move to one of the backup pins, remove the old pin and then replace the backup pin that you used with a new backup key pair.
The main problem you can face is if you lose the associated key pairs for your backup pins. In this case, when the current certificate expires you would have to use the same key pair to generate a new, valid certificate and you needn’t renew your keys. If your existing key pair was compromised, this represents a significant problem and you can’t obtain a certificate for your site. So it is recommended to create at least 2 backup pins and store the associated key pairs in 2 separate, secure locations.
Things to note while pinning your leaf:
- Most secure level to pin at.
- Always create and maintain backup key pairs
- Risk of DoS if not properly configured.
- Any CA you like to sign.
Pinning the intermediate
An intermediate certificate is a subordinate certificate issued by the trusted root specifically to issue end-entity server certificates.
Pinning at the intermediate have some key advantages and the most notable of these is that you don’t need to manage your own backup pins if you don’t want to. Because the intermediate is pinned, the browser will trust any certificate that is issued by that intermediate. If your private key is ever compromised, or you need to renew your certificate, you can just obtain a new certificate that is signed by the same intermediate and the browser will accept it. No changes to the HPKP policy are required and there is no risk of down time. Regarding the backup pin, you can create a new key pair to keep offline as a backup like we did before, and should anything ever happen to your certificate authority or their intermediate, you can create a CSR and have your new certificate signed by any other CA. This would be back to us pinning a leaf certificate public key
You do also have the option of pinning the intermediate of another CA as your backup pin. This means something happen to your existing CA, you could go to your backup CA and have them issue you a new certificate that the browser would trust.
You can also pin your 2 intermediate certificates and your own backup pin as an additional layer of protection. In this, you can choose either CA to issue your new certificate, or use your backup pin with any other CA of your choice, without exposing the risk of them being able to issue rogue certificates in the first instance.
Things to note while pinning the intermediate:
- Less secure than pinning the leaf.
- The intermediate that you pin can still issue rogue certificates.
- Can also create your own backup pin, to be on safer side.
- Pin the intermediate of another CA as a backup.
- Less risk of a DoS.
- No keys to create/store for backup if you only pin intermediates.
Pinning the root
Pinning your trusted roots and a single backup pin gives you a fair level of protection against rogue certificate issuance and offer a large amount of flexibility going forward. One thing that you do need to consider is that clients might not build a chain to the root. In this scenario the client shouldn’t accept the policy if it doesn’t find at least one valid pin, it would mean they didn’t have the protection of your HPKP policy. If you pin to a root that is subsequently removed, you’d need to migrate to certificates issued by your backup CA or use the backup pin to have a new certificate signed.
If you wish, you can create and store a backup key and pin, so you can go to a third, non-pinned root using that. Just like the intermediates, you can pin your own backup with your 2 trusted roots, or in place of one of them.
Things to note while pinning the root:
- Less secure than pinning your leaf.
- The root (and any intermediate it signs) can still issue rogue certificates.
- Create your own backup pin if you like
- Pin the root of another CA as a backup.
- Less risk of a DoS.
- No keys to create/store for backup if you only pin roots.
- Need to consider multiple trusted paths to root.
- Need to consider removal of trust path.
openssl x509 -pubkey < domain.com.crt | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64
openssl x509:In order to get the information about our certificate.
-pubkey : Get the Subject Public Key Info (SPKI) block in PEM format.
domain.com.crt: Our Certificate.
openssl pkey: Allows keys to be converted between forms.
-pubin : Indicates we are providing a public key.
-outform der: Print the output format to DER.
openssl dgst: Output the digest of the provided file.
-sha256: Use the SHA256 hash on the input.
-binary: Output the signature in binary format.
base64: Get the fingerprint
# openssl x509 -pubkey < domain.crt | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64
Then add the following lines to the virtualhost entry of the domain.
Header set Public-Key-Pins “pin-sha256=\”XXX\”; pin-sha256=\”YYY\”; max-age=xs; includeSubDomains”
max-age: The time in seconds, that the browser should remember thiss site is only accessed using one of the defined keys. We should keep it low enough that we can survive it, if something went wrong.
includeSubDomains: It is directive to include all subdomains of the domain.
Validating Pinned Connections
I’ve pinned a cert, and a backup key. HPKP mandates that hosts MUST provide a backup pin- a pin that is not present in the chain that the client validates.Incase, we lose control of the current private keys and need to re-key the site and get new certificates. We don’t want the site to have any down time and certainly not to be bricked! Unless clients have already pinned the backup key, the site would be bricked until the max-age timed out.
Finally, check to make sure that the browser can read and understand the key pins. If the connection has no errors, then the UA will determine whether to apply a new, additional correctness check:
A UA should perform Pin Validation whenever connecting to a Known Pinned Host. In the below screenshot it is clear that the pins are accepted and enabled.
The whole purpose of public key pinning is to detect, when the public key of a certificate for a specific host has changed. That may happen when an attacker compromises a CA such that they are able to issue valid certificates for any domain. A foreign CA might also just be the attacker, think of state-owned CAs that you do not want to be able to MITM your site. Any attacker intercepting a connection from a visitor to your server with a forged certificate can only be prevented by detecting that the public key has changed. After establishing a TLS session with the server, the browser will look up any stored pins for the given hostname and check whether any of those stored pins match any of the SPKI fingerprints (the output of applying SHA-256 to the public key information) in the certificate chain. The connection must be terminated immediately if pin validation fails.
The Public Key Pinning specification includes a reporting mechanism. Key validation failures are reported to the URI specified by the optional report-uri directive. This is useful not only for debugging your own use of Public Key Pinning but also for detecting MITM attacks against your users.
pem1, … pemN
pem1, … pemN
known-pin1, … known-pinN
It’s easy to make your site inaccessible if you set up HPKP wrong way.
Consider really carefully if key pinning is worth it for your site. If you’re running a major bank or a secure site for whistleblowers, you’ll no doubt want to do anything you can to avoid possible man in the middle attacks. But if you’re running a content-driven website, I don’t think HPKP is worth it. As you know, going offline is a much more severe threat than getting exposed to a sophisticated man-in-the-middle attack.
If we are to implement a report uri, either the customer has to set this up in some other domain, or we need a centralized reporting system to track similar attacks. As per a recent survey, only 0.09% of all secure websites certificates are making use of HPKP headers.