Skip to content

Instantly share code, notes, and snippets.

@peter279k
Forked from GAS85/apache2_HPKP.md
Created January 25, 2024 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peter279k/8167f9def1899240eaba5bb1e51353c1 to your computer and use it in GitHub Desktop.
Save peter279k/8167f9def1899240eaba5bb1e51353c1 to your computer and use it in GitHub Desktop.
Activating HTTP Public Key Pinning (HPKP) on Let's Encrypt

Activating HTTP Public Key Pinning (HPKP) on Let's Encrypt

Source: https://lilleengen.io/blog/index.php/posts/activating-http-public-key-pinning-hpkp-on-lets-encrypt

  • Disclaimer: This might break your website, don't preceded if you don't know what you're doing.

Since the letsencrypt seems to create a new private key every time the certificate is renewed and Let's Encrypt requires you to renew you certificate once every ~80 days pinning using your certificate's SPKI is probably not the way to go. So, what should we pin then? Let's Encrypt is currently issuing from Authority X3, and using Authority X4 as a backup, so these two is a great place to start. We should also include the ISRG Root so this might support new Authorities with other SPKIs as well.

Generate HASH of Private Keys

To generate the hash of the SPKI of these certificates run the following commands

cat /etc/letsencrypt/live/YourDomain/cert.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64

Again replace path with your domain.

Generate the ISRG Root X1, Let’s Encrypt Authority X3 and Let’s Encrypt Authority X4 SPKI-hash using the following command:

curl -s https://letsencrypt.org/certs/lets-encrypt-x4-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64
curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64
curl -s https://letsencrypt.org/certs/isrgrootx1.pem | openssl x509 -pubkey | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64

Config

Now take all the hashes you have generated and combine them into a config, replace Hash1 - Hash4 with the hashes. This will set max age to 1 minute, so you can verify that your config is working before going all in.

Apache

Header always set Public-Key-Pins "pin-sha256=\"Hash1\"; pin-sha256=\"Hash2\"; pin-sha256=\"Hash3\"; pin-sha256=\"Hash4\"; max-age=60;"

Test your config

To test your config head over to Report URIs HPKP Analyser

If your config works you can now increase max-age. I have chosen 5184000, which is roughly 2 months. You can also add includeSubDomains after max-age if you want the policy to apply to sub-domains as well.

Please note that this will limit the certificates a browser will accept for your website to certificates issued by Let's Encrypt, but will not have any effect against a breech of Let's Encrypt or you.

You probably would like to automate renewing of those hashes via cron job and this script https://github.com/GAS85/cubietruck/blob/master/publicKeyPinning.sh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment