The DNSSEC Diaries, Ch. 4: A Schema For TXT
Right. Enough theory. Lets get down to bits and bytes. As of 1.02, the basic name/key mapping for http://www.hospital-link.org looks roughly like:
http://www.hospital-link.org IN TXT “v=key1 ha=sha1 h=f1d2d2f924e986ac86fdf7b36c94bcdf32beec15”
Lets break this down:
- http://www.hospital-link.org: We’re attaching the key record directly
- v=key1: The subtype of this TXT record is key, version 1.
- ha=sha1: The hash algorithm used on the attached data is SHA-1.
- h=f1d2d2f924e986ac86fdf7b36c94bcdf32beec15: When connecting to http://www.hospital-link.org, a certificate will be presented. The hash of this certificate will be f1d2d2f924e986ac86fdf7b36c94bcdf32beec15, as per the hash algorithm declared in ha.
Yes, it really can be this easy. One of the expensive aspects of X.509 was learning how to generate and maintain certificates. Doing the above is much simpler.
Of course, that’s not allowed to be the end of the story. What else might we put in there?
(Later, we’ll discuss the finer points of this particular grammar, effectively a space delimited flat key-value pair architecture. There are other approaches, and I could be convinced to shift to them. But this is what we’re using now, mainly for parity with most everything else using TXT.)
The power of DNSSEC is the ability to bootstrap trust. There’s a very interesting technology out there called Strict-Transport-Security, that’s slowly being integrated into each browser. Strict-Transport-Security, or STS, enforces the use of TLS when accessing web sites. In effect, it turns off insecure HTTP.
In an era where hijacking HTTP sessions is as easy as burning sheep, this is a big deal.
STS has a problem — right now, use of it requires something of a “leap of faith” — the first time a site is connected to, there will be no STS bit to enforce that initial use being insecure. And there’s a second problem — once you’ve cached a value for STS, what if you’re wrong? As my friend Damon Cortesi pointed out:
Just spent the past hour debugging what turned out to be HSTS – http://bit.ly/9on39S – This is why developers hate security!
Why should it be any harder to find out whether to use TLS, than it is to discover the IP to connect to? Wouldn’t it be nice if you could ask via DNSSEC?
It would. Thus, though Phreebird (Phreeload, really) isn’t really in a position to enforce STS, not being in the HTTP pipeline, KEY1 is explicitly supporting sts=1 as a way of securely expressing TLS only. The idea has come up before, in Barth and Jackson’s ForceHTTPS, and it’s a good one. We basically end up with the following in DNS:
http://www.hospital-link.org IN TXT “v=key1 ha=sha1 h=f1d2d2f924e986ac86fdf7b36c94bcdf32beec15 sts=1”
Is this enough? I’m not sure.
Another thing I’m supporting is sn=1 — Marsh Ray did some pretty severe things against TLS a while back, and fixing them required a breaking change to the TLS protocol. Right now, there’s no safe way to know if the host you’re communicating with has Marsh et al’s fix. We can put a bit into this record saying Secure Negotiation is supported.
This does mean, by the way, that we’re mixing identity and policy. I’m not convinced that’s a bad thing. I am convinced that I don’t want to run a new query for each individual bit of policy that’s attached to a name. It’s not necessarily slow — when you query TXT, you get all TXT records, as opposed to having to burn an RRTYPE on each policy bit — but it invites confusion attacks where it’s unclear which bits of policy apply to which representation of identity. That, I am scared of.
But neither of the above tricks actually addresses key retrieval itself. One case that I am intentionally supporting right now is that of the server farm which contains too many individual keys to place in DNS in advance. By standard security theory, bits are cheap, so if you have a hundred TLS accelerators, you should never move one private key into all of them. Instead, you should make a hundred different keys, and sign them all with the same Certificate Authority. Well, a hundred private keys means a hundred public keys, and that’s too much for us. Instead, I support something called Livehashing. If “lh=1” shows up in the TXT KEY1 record, and the hash of the certificate is unrecognized, I’ll do a second lookup — this one, actually containing the hash of the witnessed cert. So, for example, if I connect to http://www.hospital-link.org, get a certificate with the hash of e242ed3bffccdf271b7fbaf34ed72d089537b42f, and see:
http://www.hospital-link.org IN TXT “v=key1 ha=sha1 lh=1”
I will do a second lookup, for:
At present, if I get any secure record back from this name, I’ll assume that means the name and hash are acceptably linked. A future release will have a better mechanism for confirmation.
Though this method adds a round trip, it significantly improves deployability for large sites. That matters. It also only adds that round trip in circumstances where the large site would otherwise be unable to deploy the technology, rather than slowing everyone down for the benefit of a few. That matters even more.
It also causes issues with CNAMEs and Wildcards, as discussed in Ch. 1. I think I know how to address that, though.
Another area of significant controversy is precisely what is stored in the DNS. There’s basically the choice of the certificate vs. the public key, and whether the data is stored hashed or not. Right now, I have an option called hr, for Hash Range. If hr=cert, or is unset, then the thing to hash is the entire certificate. If hr=pubkey, then the data to be hashed is simply the public key of the endpoint.
What’s the difference? Ah, welcome to the weeds. If one hashes the certificate, then the data asserted by DNSSEC includes all the policies embedded in X.509. Important: That doesn’t mean you can necessarily trust said policies — in fact, there are policies that we know we can’t trust when exclusively asserted by DNSSEC, like EV — but the semantics are at least there to continue supporting them.
However, if one hashes the public key, that means an implementation doesn’t need to support X.509, or even ASN.1 at all. That’s potentially a significant reduction in complexity.
So, that’s what we have now as optional settings: sts=[0|1], sn=[0|1], lh=[0|1], and hr=[cert|pubkey].
What’s coming soon, or at least being considered? We’ll talk about that in the next post.