Certificates form the basis for secure communications on the web. However, what if the proposed certificate for a website comes from a trusted certificate authority (CA) that has been surreptitiously compromised by fraudsters and is now used in the context of attacks? Public key pinning seeks to close this gap. It involves extracting the underlying public key of a certificate to resolve that certificate to a specific domain. The security tip described here shows how to implement the procedure.
Currently, numerous IT security experts are faced by this topic: HTTP Public Key Pinning (HPKP). Currently still a draft, the HTTPS extension will soon be standardized by the Internet Engineering Task Force (IETF). In the future, many problems relating to issued certificates and CAs could be fixed with HPKP. The basic principle of common certification authorities is very simple: CAs typically issue certificates, which are then used to secure websites using TLS. A certificate ensures, for example, that the user is indeed connected with the correct web address and not with a spoofed website when connecting to a specific domain (e.g., http://www.linuxmagazine.com).
In the recent past, however, many spoofed certificates were issued and attackers were able to intercept supposedly secure communications unnoticed. The basic problem is that, by default, huge numbers of CAs are anchored in various browsers or the operating system itself. These CAs are typically trusted automatically, which means that each CA could issue fake certificates at will, that would in turn be considered trustworthy.
It is precisely here that a new approach (RFC 7469) enters the scene, geared to safeguard the world of SSL/TLS encryption. To be specific, this is an extension of the HTTP protocol. With the help of public key pinning, a host or an operator of publicly accessible systems or services can determine which certificates a browser should classify as trustworthy for a domain in future, and which it should not. Currently, this extension only with works with the Google Chrome, Mozilla Firefox, and Opera browsers. Microsoft's Internet Explorer and Edge, as well as Apple Safari, do not follow the Internet standard introduced by the IETF.
The purpose behind public key pinning is to detect changes to the public key that is assigned to a certificate. The process is called trust-on-first-use (TOFU). The method is only effective the first time a connection to a selected host is established and the host presents its valid certificate. During this initial connection to a host, the client receives the information it needs to perform PIN validations in the future. This mechanism does not recognize a fake certificate that is presented on the first visit. The browser trusts the public key it first sees for a domain.
When connections to a domain are opened later, the browser checks the public key for the hostname in question. The program checks whether the public key is the same as the entries in the SPKI fingerprints (SHA-256 hash) in the certificate chain. The connection is terminated if PIN validation does not return a valid result. If the fingerprint matches, the certificate is viewed as trusted, and the browser establishes a secure connection. A certificate is accepted even if the browser cannot find any of the stored PINs for the currently accessed hostname. This is usually the case if the host supports public key pinning, and no HPKP headers are transmitted to the client.
Make Your Own Server HPKP-Capable
To equip a host with the required feature, you only need to generate an HPKP header for your site. To do this, the following steps are necessary in an OpenSSL environment. To begin, generate your SHA-256 key:
pin-sha256="base64=="; max-age=expireTime [; includeSubdomains] [; report-uri="reportURI"]
pin-sha256 string must include the Base64-encoded Subject Public Key Information (SPKI) fingerprint. It is possible to define multiple PINs for different public keys. The value of
max-age is the time in seconds before a browser notices that the corresponding site can only be reached with the help of pinned keys. The
includeSubdomains parameter includes all the subdomains in this configuration. The
report-uri parameter is optional. If this parameter is used, all unsuccessful PIN checks are reported to the target to be reached.
The next step is extracting the Base64-encrypted public key information. You first need to encode the public key information from the corresponding certificate or key file in Base64 format. The following command does the trick:
openssl rsa -in my-key-file.key -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64
To encode with the help of a certificate request, do:
openssl req -in my-signing-request.csr -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
It also works with a certificate, of course:
openssl x509 -in my-certificate.crt -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
Now, create an HPKP header by extracting the Base64-encrypted data for a website with the command:
openssl s_client -connect www.example.com:443 | openssl x509 -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
A sample HPKP header is shown in Listing 1.
Listing 1: Sample HPKP Header
Public-Key-Pins: pin-sha256=" F1lYgMAWJed1UM9BWAk3PKUxZhtSATn8LV17W9Uw6MKA="; pin-sha256=" UGNuJ8wOBY9-qt6K4eulsEY6vC0sOhhf1FoJVT1W6V49Q="; max-age=5184000; includeSubdomains; report-uri="https://www.example.de/hpkp-error-report"
The settings listed in the sample thus mean that the first hash value,
F1lYgMAWJed1UM9BWAk3PKUxZhtSATn8LV17W9Uw6MKA=, verifies the authenticity of the public key of the host system in production use.
The second hash value,
UGNuJ8wOBY9qt6K4eulsEY6vC0sOhhf1FoJVT1W6V49Q=, acts as a backup key. This is necessary to be able to modify the primary key, say, for a certificate renewal. Previously established and validated connections to clients thus remain valid. Additionally, this step is necessary if the public key or the certificate has been compromised.
The timestamp in the
max-age option tells the client to store the information for two months. This timing is best practice according to the IETF RFC. The option
includeSubdomains includes all subdomains, as already described. The
report-uri option defines the location at which failed pin validations will be saved.
To facilitate implementation of this example for the popular web server variants, we'll show a couple of implementation examples. Of course, we can assume no responsibility for the configuration of the settings listed here.
To enable the HPKP header for an Apache server, add the following code to the web server's configuration file. Keep in mind that additional
mod_headers must be enabled:
Header always set Public-Key-Pins "pin-sha256=\"base64+primary==\";pin-sha256=\"base64+backup==\";max-age=5184000; includeSubDomains"
You would use the following configuration for an Nginx server if you want to enable the HPKP header, for which you need the
add_header Public-Key-Pins 'pin-sha256="base64+primary==";pin-sha256="base64+backup==";max-age=5184000; includeSubDomains';
The next example enables the HPKP header for the Lighttpd server:
setenv.add-response-header = ( "Public-Key-Pins" => "pin-sha256=\"base64+primary==\";pin-sha256=\"base64+backup==\"; max-age=5184000; includeSubDomains" )
mod_setenv server module, loaded with
server.modules += ( "mod_setenv" )
is required for configuring a Lighttpd server.
The new HTTP public key pinning gives rise to hope that the security of certificates can be restored. The cooperation of all major vendors is necessary to achieve this. Numerous attempts have been made to do this in the past, but none of these projects succeeded thus far. Because several well-known browsers still do not support HPKP, it will probably take some time until the procedure becomes a basic web standard.