Having recently released my HPKP toolset, I thought I'd give some guidance on the various ways you can setup HPKP and the benefits and drawbacks of each.
HTTP Public Key Pinning
If you aren't familiar with HPKP then you should start by reading my introductory blog, HPKP: HTTP Public Key Pinning. HPKP gives us the ability to stop a rogue Certificate Authority (CA) from issuing certificates for our domain. It does this by allowing us to "pin" the fingerprint of specific public keys that the browser is allowed to trust going forwards. These keys could be our own keys, from the leaf or end entity (EE) as it's known, an intermediate key or a root key. In this blog I'm going to look at the effects of pinning at each of these levels.
Pinning the leaf
The leaf certificate is the last certificate in the chain and the one that bears your domain name/s. You can see my leaf certificate here:
This certificate is signed by the 'StartCom Class 1 Primary Intermediate Server CA' certificate which is in turn signed by the 'StartCom Certification Authority' root certificate. The root certificate is the certificate that the browser trusts and we have established a valid 'chain' back to this certificate so everything checks out. 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. This is the strongest possible configuration for HPKP but, as usual with security, the most secure configuration is the one that carries the most risk. 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 backups are used should your private key ever be compromised or when you come to renew your existing certificate when it expires. You move to one of the backup pins, remove the old pin and then replace the backup pin that you used with a new backup. At all times you're using a valid pin from your policy and can continue to move forwards by rolling through the backups in this manner. The whole process looks a little like this.
You issue your HPKP policy with your current leaf pin and at least one backup.
When it's time to renew you take your backup pin and get a CA to sign your new certificate with your new public key. This certificate then goes into production and is now what you present to visitors. The previous pin can be removed from your HPKP policy as it is now redundant.
Once the transition has taken place, you need to regenerate a new backup pin to add to your policy to maintain the number of backups. Generate the new key pair, create the pin for the public key and add it to the HPKP policy.
The biggest problem you can face is if you lose the associated key pairs for your backup pins. In this scenario, once the current certificate expires you would have to use the same key pair to generate a new, valid certificate and you couldn'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. This is the reason I suggest you create at least 2 backup pins and store the associated key pairs in 2 separate, secure locations. There is no reason you can't create more should you feel the need but it is essential that these backups are stored offline and not online. I hope there was enough emphasis there!
Update: The above paragraph was updated to better reflect that you can use your existing key pair at renewal and that you don't need to move to a backup key pair.
Summary of pinning your leaf:
- Most secure level to pin at.
- You are responsible for creating and maintaining backups.
- Risk of DoS if you make a mistake.
- Can use any CA you like to sign.
Pinning the intermediate
The next option you have is to pin the public key of the intermediate certificate.
Pinning at the intermediate has a couple of 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. It does leave us with the problem of what to do for a backup pin though. The HPKP specification requires that a policy has 1 pin that is in the certificate chain, in this case the intermediate, and one pin that is not, our backup pin. Now, 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 but would get you back up and running and then you can go about creating new backup pins however you like.
You do also have the option of pinning the intermediate of another CA as your backup pin. This means should anything happen to your existing CA, like they closed down, you could go to your backup CA and have them issue you a new certificate that the browser would trust.
To me, pinning at the intermediate level saves us some of the troubles compared to pinning a leaf, but instead it'd be better to pin a root certificate instead. You have still narrowed down the number of CAs that can issue certificates for your site to 2 (instead of every trusted CA on the planet), but there is a higher likelihood of something happening to an intermediate certificate, or the CA issuing from a new intermediate, than there is of the root certificate. You can also pin your 2 intermediate certificates and issue your own backup pin as an additional layer of protection.
This way, you have the choice of either CA to issue your new certificate, or you can use your backup pin with any other CA of your choosing, without exposing yourself to the risk of them being able to issue rogue certificates in the first instance.
Summary of pinning the intermediate:
- Less secure than pinning your leaf.
- The intermediate that you pin can still issue rogue certificates.
- Create your own backup pin if you like or
- 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 at the root level offers some nice advantages over pinning the leaf but, much like pinning an intermediate, it has a couple of drawbacks too.
When you pin at the root level it means that you want to trust any certificate that particular CA issues for your domain. Similar to pinning at the intermediate level, if you pin another CA root as your backup pin, then you don't have to create and store any backup keys of your own. The 2 CAs that you pin will always be able to sign a certificate for your site that the browser will trust. Should your key be compromised or your current certificate expires, you simply request that the CA sign your new certificate and it will drop right in without any problems. There's not even a need to alter your HPKP policy. Likewise if a CA closes down or has a breach causing key revocation, you can have a new certificate issued right away by your backup CA.
If you like you can still create and store a backup key and pin that too so you can go to a third, non-pinned root using that. Just like the intermediates, you can pin your own backup alongside your 2 trusted roots, or in place of one of them.
Pinning your 2 trusted roots and a single backup pin gives you a fair level of protection against rogue certificate issuance and still offers a large amount of flexibility going forwards. One thing that you do need to consider though is that clients might not build a chain to the root you expect. Whilst 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. You can read an example of this here on the Qualys Community or Microsoft Support. There is also the possibility the root store could vary across devices or that it could change if something like a Windows udpate comes along and removes a certificate that you had pinned. 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.
Summary of 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 or
- 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.
Which should I choose?
For me personally, on my blog and on other websites that I run, I've pinned at the leaf certificate level. It does come with the problem that you're responsible for the backups, yes, but the risk can be mitigated with a robust backup solution. The HPKP specification only requires 1 backup pin, but there is no reason you can't create more. I create 2 backups and keep them in separate, secure locations. With these backup pins, I can take my Certificate Signing Request (CSR) to any CA of my choosing and have them sign the certificate to put into use. That said, I can also see the attraction of pinning at the root level too. I don't really see the need to pin at the intermediate as you may as well just use the root certificate. With this, you can always use either of the 2 CAs that you pin to sign a new certificate at any point. No changes to your policy are required and you can just drop the new certificate right in. If you do go down this route, you can only ever get a certificate from the 2 CAs you pin unless, and I'd always suggest doing this, you add your own backup pin. You can still generate a single key pair and keep them offline should you ever want or need to go to a 3rd CA to sign your certificate.
You can see my pins here on the HPKP Analyser:
GitHub are a good example of pinning at the root level and they pin both the DigiCert and VeriSign roots. You can see their policy on the HPKP Analyser too.
The final choice is really down to you and your circumstances. Pinning at the root level reduces the number of CAs that can issue certificates for your domain from every CA in the world, to just the 2 (or however many) you pin. Pinning at the leaf is the ultimate level of security and means that you don't even want to trust a small number of CAs. You retain control of exactly which certificates the browser will trust and can use any CA you like to sign them. Always be careful when using HPKP, start with the Report Only version of the header and use my HPKP Toolset to check things over from the start! It can be a pain if you get it wrong, but it's also not too difficult to get right. You should also enable the reporting feature using report-uri.io to keep an eye on exactly what's happening with your policy in the wild. If you issue an enforced policy and start having problems, you will know about them quickly rather than waiting for feedback.
- Always start by issuing a report-only header for testing.
- Enable reporting with report-uri.io or your own service.
- You can't send reports to the same domain, it has to be a different domain.
- When enforcing a policy, start with a low max-age and work up.
- Don't set a large max-age until you have gone through the renewal process.
- HPKP is risky, use it with care.