[This post provided as part of documentation of the Security Headers WordPress plugin]
HTTP Public Key Pinning (HPKP) is a method of supplementing the Certificate Authority model with a “Trust on First Use” (TOFU) security model.
The threat addressed is a valid certificate being issued by a certificate authority in error, someone who obtains such a certificate is then able to create a website indistinguishable from the original. This has occurred with government surveillance under some repressive regimes. Some sites, notably many of Google’s domains, have the acceptable Certificate Authorities hard coded into common browsers, which is another way to mitigate the same risk.
With HPKP we include a list of public key hashes in an HTTP header in HTTPS requests. The browser can then cache this for a given time (max-age), and refuse to accept keys not in the list for that period.
Any site choosing to deploy HPKP must choose which keys to pin. You need to do it carefully as a mistake could lock users out of your website (or websites on subdomains of your website).
Unless you control a Certificate Authority (like Google), or have your keys issued automatically (or by a third party), it makes sense to pin the public key of your own web site (the leaf key).
Pinning the leaf key places the least amount of trust in the existing CAs (which is our goal), whilst avoiding the complexity of dealing with multiple trust paths. It is the simplest method to understand, and doesn’t place any additional trust in any certificate authority.
You then need backup keys (HPKP requires at least one backup key, but I’d suggest a minimum of two). Again since our goal is to avoid trusting the CAs more than needed the natural approach is to generate your own keys locally (not on your web server, since it they might be compromised with the current key), and pin those as your backup. Keep them in a safe place, and rotate them in when it is time to renew the certificate (assuming you rotate your server key when you get a certificate re-issued, if not consider starting), so you get practiced in rotating the keys (and the HPKP details).
Tools for Keys
You need a base64 encoded SHA256 of the public key with a “=” on the end (the equal sign is due to the vagaries of base64).
Mozilla have a list of commands to extract the string to pin from key, certificate, and CSR using openssl.
report-uri.io have a web tool which list current keys out, leaf key first.
Generating backup keys
You need to make sure the method is compatible with your web hosting software, and systems. Although if you mess up you might be able to use an SSL proxy, or SSL proxy service, that accepts your key pair.
You need to do this on a trusted system, and store the resulting “pem” files somewhere safe.
For web servers that accept 2048-bit RSA keys this method should work (but test it).
openssl genrsa 2048 >backup-key1
openssl genrsa 2048 >backup-key2
openssl rsa -in backup-key1 -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64
openssl rsa -in backup-key2 -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64