The impromptu midnight DNSSEC tutorial I gave last Saturday during the Ansible meetup in Utrecht was quite successful: only one third of the participants fell asleep (a good turnout for me), but I attribute that solely to the Gin&Tonics which were consumed during the tutorial. Be that as it may, one of the participants was particularly attentive: Serge apparently really paid attention because after extolling the benefit of potentially being able to do away with the need for X.509 Certification Authorities by using DANE, the DNS-based Authentication of Named Entities, he actually had the nerve to ask me why this site wasn’t using DANE.

It wasn’t. It does now.

DANE validation

To be honest, I simply forgot, and I thought it would be a little complicated if not outright impossible, because this site is on a shared-hosting site. But I’m very lucky: the great people of Uberspace have a simple procedure for uploading any amount of certificates, even self-signed ones.

So, after issuing an X.509 TLS certificate from my private Certification Authority (CA) and having the Ubernauten add that to my domain, I got cracking, and created a DNS TLSA record for it. I decided I’d use the following fields:

  • Certificate Usage 3 with which I’ll specify the certificate or public key which must match what the HTTP server responds with in the TLS session.
  • Selector of 0 which means full certificate
  • Matching Type of 1 for the SHA-256 hash of the binary certificate content.

Since I settled for certificate usage of 3, I need the “fingerprint” of the binary content. There are two ways I know to get the required certificate fingerprint which I need for building the record record:

$ openssl x509 -in jpmens.net.crt -outform DER | shasum -a 256 | awk '{print $1;}'
2f32249d9c9bd8fa245dafc722c55f5087c3b2b8c236d194ebc912f30be20cb5

$ openssl x509 -in jpmens.net.crt -noout -fingerprint -sha256 | sed -e 's/^.*=//' -e 's/://g'
2F32249D9C9BD8FA245DAFC722C55F5087C3B2B8C236D194EBC912F30BE20CB5

Other than upper/lowercase hex, there is no difference in the value. So, what I now need to do is to create the actual TLSA record in the DNS, and sign the zone. Here we go (and I’m very grateful to Florian for the combination of dig flags which show header and answer only – I’ve been wanting that for donkey’s ages :-)

$ dig +nocmd +noadditional +noauthority +nostats +noquestion _443._tcp.jpmens.net TLSA
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38211
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; ANSWER SECTION:
_443._tcp.jpmens.net.	79948	IN	TLSA	3 0 1 2F32249D9C9BD8FA245DAFC722C55F5087C3B2B8C236D194EBC912F3 0BE20CB5

Note how the 3 0 1 I chose as flags are part of the rdata of the record.

If you don’t feel like doing all that OpenSSL stuff, Shumon Huque has created a marvellous TLSA Record Generator which does all this for you; you just copy/paste the result into your DNS zone and sign it.

TLSA Record Generator

So, I now have a TLS-protected Web site, and I have a TLSA record in the DNSSEC-signed zone. And now?

If tech life were really good, the large browser vendors would have implemented support for TLSA and that would be it. As it stands, none of them have, maybe because they’re shy of doing away with a lot of cash they’re getting from the hundreds of Certification Authorities whose CA root certificates the carry in the Web browsers we use? Peter tells me the reasons are actually technical in nature: the latency resulting from an out-of-band checking which has to be done via the DNS to obtain the TLSA record and signatures and verify these, and the fact that most consumer equipment (CPE) just won’t handle DNSSEC properly. There’s probably some truth in both.

Be that as it may, in order to test this, I’ve installed the TLSA Validator from the cz.nic team. This Web browser add-on is rather well documented, and its source code is available.

The result? It works, as you can see from the screenshot at the top of this page.

My impression of the validator is that it’s a bit flaky: I couldn’t get it to work at all on FireFox for OS X (or for Windows), but it worked out of the box for Chrome OS X. I’d like to hear of your experiences with it. What I like a lot is that I can specify which resolver it should use, and I just pointed it do the DNSSEC-trigger I run anyway.

Before you try all this at home, do make sure you’re actually using a DNSSEC-validating resolver (a.k.a is the top right of this page green?).

I’m reminded in a comment below, that there are other utilities, such as ldns-dane from the ldns project. ldns-dane can create a TLSA record from a TLS connection, and it can verify a a TLSA setup:

$ ldns-dane -4 create jpmens.net 443
_443._tcp.jpmens.net.	3600	IN	TLSA	3 0 1 2f32249d9c9bd8fa245dafc722c55f5087c3b2b8c236d194ebc912f30be20cb5

$ ldns-dane -4 verify jpmens.net 443
95.143.172.28 dane-validated successfully

Further reading:

DANE and DNSSEC :: 04 Mar 2015 :: e-mail