Farewell to HPKP, hello to DNS-01 and ECDSA

A few months back I switched on HTTP public key pinning, a security scheme designed to make it more difficult for attackers to do nefarious things with the BigDino web server. HPKP is difficult to implement and comes with a long list of configuration pitfalls—and, as of today, I’m done with it.

Sixty-one days ago I stopped sending out HPKP headers, which I’d set to a sixty day duration. This morning, I ripped out the scaffolding of Certbot scripts and cron jobs that kept LetsEncrypt running properly with HPKP, and replaced them all with the blissful simplicity of Neilpang’s acme.sh coupled with DNS-based validation.

HPKP is dead

The primary reason I wanted to drop HPKP is because I’m terribly interested in taking advantage of LetsEncrypt’s almost-here wildcard certificates, and LE will only allow wildcard certs with DNS validation. In trying to figure out DNS validation, I quickly realized that it would further complicate my already over-complicated LetsEncrypt setup, and that I should probably be looking at ways to simplify things, rather than complexificating them.

My decision was made a lot easier by the fact that as of May 2018, Chrome will no longer support HPKP, leaving Firefox as the only important browser with HPKP support. About 50% of visitors to all of this server’s web sites are running Chrome, and putting time and effort into supporting something that Chrome doesn’t do anymore is a waste of time.

HPKP is like a loaded gun—if you don’t take care with your implementation, you could wind up killing your site. If you don’t take care with your maintenance, you could end up killing your site. And, if you put too much confidence in its ability to protect you from malicious actors and not enough time on an overall defense-in-depth strategy…you could end up killing your site.

So goodbye, HPKP. I won’t miss how much you complicated my life.

Acme DNS-01 validation: it’s so good

At the same time, I’ve dropped Certbot and HTTP-01 validation both from my LetsEncrypt setup. Anyone dealing with LE on a server with more than the most basic configuration knows that the default LE client (good old Certbot) can be a bitch to work with once you go off the beaten path. Fortunately, there are excellent Certbot alternatives out there, and my favorite by a mile is acme.sh, which you can grab via Github.

In addition to coming with its own built-in automation, the acme.sh script features outstanding support for DNS-01 validation, which allows LetsEncrypt to check your ownership of a domain name by programatically setting and then checking a TXT record in your DNS zone file. The script supports a wide variety of DNS providers, including Cloudflare, which is my current preferred DNS solution.

After running the script’s installation process and getting it set up, issuing my first certificate and automating its renewal requires only a single command:

$ acme.sh --issue --keylength ec-384 --dns dns_cf \
-d bigdinosaur.org -d www.bigdinosaur.org --post-hook \
/usr/local/bin/acme-bigdino-post.sh

SANs are supplied with multiple instances of the -d parameter—here, for example, I’m issuing the certificate for both bigdinosaur.org and www.bigdinosaur.org. I’m also using a 384-bit elliptical curve public/private key pair, which I’ll talk about in a moment.

The --post-hook script concatenates the issued certificate with its key (which I need to do because I use HAProxy for SSL termination and HAProxy prefers its certificates and keys bundled together) and then reloads HAProxy so it picks up the new certificate. The script is very short:

#!/bin/bash

cat /home/me/.acme.sh/bigdinosaur.org_ecc/\
{fullchain.cer,bigdinosaur.org.key} \
> /etc/haproxy/ssl-dns/bigdinosaur.org.pem

systemctl reload haproxy

Once you’ve successfully issued a certificate with acme.sh, the script handles renewal all on its own. It’s pretty awesome and I’m a fan.

Bend it like Koblitz & Miller

Finally, I’ve switched 100% over to elliptical curve-based keys. It seemed to be a good time to make the switch away from RSA, since I was already screwing around with stuff under the hood anyway.

Elliptical curve cryptography—”ECC,” or also potentially “ECDSA” for “elliptical curve digital signature algorithm”—differs from RSA in that the math is simultaneously simpler (primarily because it offers equivalent security with much smaller numbers) and (at least for now) harder to break. It uses iterative math involving the addition of points on a specific kind of curve (the eponymous “elliptical curve”), which tends to look something like this:

Rather than bloat this entry with the how and why, I’ll simply embed Computerphile’s excellent (and short!) explainer video below:

The tl;dw is that ECC depends on math that’s easy to do one way (find the point that results from performing N iterations of this function) and damn near impossible to do the other way (given a specific point, find how many iterations of this function were performed to get there).

Currently, LetsEncrypt allows users to generate certificates using ECDSA keypairs, but its certificate authority still signs those certificates with an RSA key. This will be changing midway through this year (at least according to LE’s current timeline) when LE rolls out ECDSA root and intermediate certificate authorities.

The future is here, and it looks curvey.