Photo of me

Hugo Osvaldo Barrera

Software Developer. Python Lover. IT Consultant.

Using letsencrypt with HKPK

HKPK (RFC7469) is a standard that tells browser to cache a certain TLS certificate’s signature, and validate that future visits use that certificate (or a defined backup).

I intended on enabling this on my servers, but since letsencrypt renews your certificates every few months, it would mean updating this setting on my nginx configuration. It also means that if something catastrophic happens (like a disk failure), the certificate would be lost, but browsers would still expect to see that same one.

After some quick searching, I didn’t find anything in letsencrypt’s docs on how to quickly do this.

The solution is merely to pin the root certificates - or the intermediate ones.

Pinning the intermediate one (and the backup intermediate certificate) seem like a good compromise: There’s no need to update anything upon renewals, but in case of lost certificates, there would be no issue using new ones.

To do this, I tailored the Public-Key-Pins header on my server (in my case, nginx) sends.

You can copy-paste these into nginx’s settings if that’s what you’re using:

add_header Public-Key-Pins 'pin-sha256="YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg="; pin-sha256="sRHdihwgkaib1P1gxX8HFszlD+7/gTfNvuAybgLPNis="; max-age=5184000; includeSubDomains';

This also sets the max-age to six months, which is generally a good compromise.

I you don’t want to copy-paste security-related settings from a random website, you can get these hashes yourself.

First of all, grab letsencrypt’s intermediate certificates. Once you have them, you need to get the key’s SHA256 hash (do this for both):

openssl x509 -noout -in lets-encrypt-x1-cross-signed.pem -pubkey | \
openssl rsa -pubin -outform der | \
openssl dgst -sha256 -binary | \

Note that these are the same hashes in the above:

add_header Public-Key-Pins 'pin-sha256="HASH1="; pin-sha256="HASH2"; max-age=5184000; includeSubDomains';

Now tell nginx to reload your settings, and you’re done. Visitors for you domain will pin the intermediate certificate for six months, blocking any MITMs done with rogue certificates, etc.

comments powered by Disqus