HPKP pinning carries an inherent risk of bricking your site and requires great care. For that reason, it is not presently supported by the Let’s Encrypt client, and will not be until we have a lot of time to perform quality control on an implementation, if ever.
But @intchloe asked a question on GitHub about how to roll their own HPKP pins:
Will Let’s Encrypt always use ‘Let’s Encrypt Authority X1’ in its cert chain? So the hash “YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=” can be used on all websites issued by Let’s Encrypt?
I’m going to try to answer this here. But first, some general points about HPKP:
- First, don’t use HPKP unless you have read and understood the specifications, and are extremely careful. Know that if you get something wrong, you can render your domain unusable.
- Never pin exclusively to Let’s Encrypt (or any single CA). Make sure you have at a couple of backups / alternatives that you can work with if something catastrophic or simply buggy happens to your first choice
- If the domain is of any value to you, test a deployment on a less valuable domain, and test your backup CA with it.
- Use the -Report-Only header and the
report-uri
field before you actually deploy HPKP, to see how many visitors report breakage. - Pinning works on public keys, not certificates, and a pinned key can occur anywhere in a cert chain: root, intermediate, or leaf.
Now, to attempt to answer the question. Since this advice has not been tested, only try this on domains you don’t care about, and are willing to see permanently broken.
- First, generate a backup keypair, and include the SPKI hash of the public key in your HPKP header. Keep this keypair somewhere safe. You will use it in an emergency to request a leaf certificate from some other CA in case you are unable to issue from any of your pinned CAs for some reason.
- Let’s Encrypt will not always use the current Let’s Encrypt Authority X1 cross-signed intermediate cert, so you shouldn’t pin exclusively to it. We currently have a Let’s Encrypt Authority X2 intermediate CA as well, and will have other intermediate certs in the future.
- Always include the public keys hashes from the ISRG Root X1 and DST Root X3 certs in your pin set.
- Somewhat surprisingly, clients validate the trust path they build, which doesn’t necessarily have anything to do with the intermediate certificates your server provides in the handshake. This trust path varies based on what intermediates the client has cached, and what cross-signatures the intermediates and/or roots have. Because of this it’s possible for pinning to break even without any changes on your server. To avoid that, it’s highly advisable to pin one of the two public key hashes that is guaranteed to be in the built chain: the one from your leaf cert (cert.pem) or the one from the intermediate that issued it (chain.pem). Make sure to update this pin with each renewal, since intermediates can change without notice.
- Remember to pin to at least two non-Let’s Encrypt CAs!
The above advice has not been tested and may well contain errors. Perhaps those who are willing to test them on sacrificial domain names can report back and share knowledge in this thread.
[Edit: fixed some inaccuracies]
[Edit: changed title]