Errors in DKIM records

TXT Records

DKIM public keys live in DNS TXT records. A DNS TXT record contains strings of text, and each string is limited to be no more than 255 characters long.

Recommended practice for DKIM at the moment is to use 2048 bit keys (1024 bit keys aren’t insecure, but they’re looking a bit weak and 2048 is where folks have mostly decided to move to).

But a 2048 bit DKIM key is going to be around 400 characters long. So how do we fit that into a TXT record?

A TXT record can contain more than one string, so we can split the 400 character public key into two strings, put both of those strings in a single TXT record and the DKIM validator will join those two strings back together and use them to validate the email.

A single TXT record containing three strings

Editing your DNS

Unfortunately, user-interface support for adding TXT records is not all it could be.

The “standard” way of sharing DNS configuration in a human editable form is “bind format” (it’s defined as a standard in RFC 1035, but it’s the “native” format of bind, an older name server). For many records – A, MX, AAAA, NS and so on – the format is well understood and widely supported, but for TXT records … not so much.

The bind format for TXT records looks something like this, for a TXT record with two strings:

example.com 3600 IN TXT "first string" "second string"

Many DNS editing UIs, though, don’t use this format. Often they’ll just have a single text entry box for the payload. If you enter more than 255 characters of text in it they might return an error, or they might silently truncate it, or – if you’re lucky – they’ll split it into multiple strings for you behind the scenes. Fortunately for DKIM records the multiple strings are just concatenated when they’re used, so it doesn’t matter where the original key is split.

Sometimes they’ll have a way to add multiple text boxes, one for each string in the TXT record.

A very common thing, though, is that they accept just the text. They don’t require the double quotes around each string. Older UIs may remove leading and trailing double quotes, which is good enough for simple cases.

Common errors

This mismatch between bind format TXT records, as created by DKIM key generators, and the web interfaces users add them to their domains with leads to a couple of common errors with DKIM public keys.

One is that there are stray double quotes inside the key, so it’ll look something like this:

example.com 3600 IN TXT "abcde\"\"fghij"

Here there are two stray double quotes in the middle of the string. Command line lookup tools, such as dig, will usually display that as a double quote escaped with a backslash.

A variant of that is:

example.com 3600 IN TXT "abcde\"" "\"fghij"

Here there are two strings in the TXT record, and copying and pasting the bind format into a web form has left it with a trailing double quote on the first string and a leading one on the second.

Another error is even trickier to spot, it’s whitespace in the middle of the TXT record. If you paste a multiline string into a web form for a TXT record the line breaks may be left in the published record. There are some unexpected constraints on what whitespace is allowed in a DKIM key, meaning some checkers will error out with valid whitespace, so avoiding whitespace altogether avoids unexpected errors.

Either of these errors will cause a DKIM public key to be unusable, leading to mail to be treated by recipients as unsigned.

It was DNS

I was helping someone diagnose why an online checker was flagging their DKIM records as “invalid key for “p” tag! It must not be empty and must be in base64 format“.

There were some stray double quotes in the key as published, so I was sure it was an error pasting it into a cpanel dns editing form. But cpanel itself didn’t show the double quotes. And trying to replicate the issue, there really weren’t any double quotes being entered into the form.

Just before throwing up my hands and I checked the published records again and now they were valid. And we hadn’t been editing them. That’s usually a sign of DNS issues – caching, inconsistent zone data, bad glue, all the DNS standards.

I checked, and the domain with problems had four authoritative nameservers. Two were from their IT provider, and two were secondary DNS provided by a third party.

Secondary DNS is configured by continually copying the zone configured in the primary servers, so you expect them to provide identical answers, give or take a few seconds delay in changes.

So I checked the dns zone on all four. They had the same serial number in their SOA records, so they were serving the same zone, and the secondaries were up to date with the primaries.

But the TXT record for DKIM was correct on the primary servers and had stray double quotes on the secondaries. They should have been identical.

That meant that some fraction of DKIM checks would get the right key and pass, the rest would get the corrupted key and fail validation. Some DNS resolvers prefer authoritative servers that answer faster, and the secondaries consistently answered a lot faster than the primaries, so more than half of queries would fail, so more than half of mail sent would fail.

There’s no way of telling exactly what the bug in the secondary DNS service is, but from the outside it looks very much as if they’re doing an AXFR from the primary servers, converting them to bind format, then parsing that to publish the data to their secondary servers. And somewhere in that process their code is making the same mistake around double quotes and multiple strings in TXT records that humans do.

It was DNS.

Related Posts

Four things to check before your next mailing

Like many bits of technology, email is often set-and-forget. Everything is checked and rechecked during setup, and then no one goes back and looks at it again. But mail programs are not static, and people make changes. These changes don’t really break things, but over time they can create their own set of problems.
Setting aside some time every quarter or even every year to check and make sure all the bits of mail are configured correctly is a good idea.

Read More

A brief history of TXT Records

txt
When the Domain Name System was designed thirty years ago the concept behind it was pretty simple. It’s mostly just a distributed database that lets you map hostname / query-type pairs to values.
If you want to know the IP address of cnn.com, you look up {cnn.com, A} and get back a couple of IP addresses. If you want to know where to send mail for aol.com users, you look up {aol.com, MX} and you get a set of four hostname / preference pairs back. If you want to know the hostname for the IP address 206.190.36.45 you look up {45.36.190.206.in-addr.arpa, PTR} and get a hostname back.
There’s a well-defined meaning to each of those query types  – A is for IP addresses, MX is for mailservers, PTR is for hostnames – and that was always the intent for how DNS should work.
When DNS was first standardized, though, there was one query type that didn’t really have any semantic meaning:

Read More

Are they using DKIM?

It’s easy to tell if a domain is using SPF – look up the TXT record for the domain and see if any of them begin with “v=spf1”. If one does, they’re using SPF. If none do, they’re not. (If more than one does? They’re publishing invalid SPF.)
AOL are publishing SPF. Geocities aren’t.
For DKIM it’s harder, as a DKIM key isn’t published at a well-known place in DNS. Instead, each signed email includes a “selector” and you look up a record by combining that selector with the fixed string “._domainkey.” and the domain.
If you have DKIM-signed mail from them then you can find the selector (s=) in the DKIM-Signature header and look up the key. For example, Amazon are using a selector of “taugkdi5ljtmsua4uibbmo5mda3r2q3v”, so I can look up TXT records for “taugkdi5ljtmsua4uibbmo5mda3r2q3v._domainkey.amazon.com“, see that there’s a TXT record returned and know there’s a DKIM key.
That’s a particularly obscure selector, probably one they’re using to track DKIM lookups to the user the mail was sent to, but even if a company is using a selector like “jun2016” you’re unlikely to be able to guess it.
But there’s a detail in the DNS spec that says that if a hostname exists, meaning it’s in DNS, then all the hostnames “above” it in the DNS tree also exist (even if there are no DNS records for them). So if anything,_domainkey.example.com exists in DNS, so does _domainkey.example.com. And, conversely, if _domainkey.example.com doesn’t exist, no subdomain of it exists either.
What does it mean for a hostname to exist in DNS? That’s defined by the two most common responses you get to a DNS query.
One is “NOERROR” – it means that the hostname you asked about exists, even if there are no resource records returned for the particular record type you asked about.
The other is “NXDOMAIN” – it means that the hostname you asked about doesn’t exist, for any record type.
So if you look up _domainkey.aol.com you’ll see a “NOERROR” response, and know that AOL have published DKIM public keys and so are probably using DKIM.
(This is where Steve tries to find a domain that isn’t publishing DKIM keys … Ah! Al’s blog!)
If you look up _domainkey.spamresource.com you’ll see an “NXDOMAIN” response, so you know Al isn’t publishing any DKIM public keys, so isn’t sending any DKIM signed mail using that domain.
This isn’t 100% reliable, unfortunately. Some nameservers will (wrongly) return an NXDOMAIN even if there are subdomains, so you might sometimes get an NXDOMAIN even for a domain that is publishing DKIM. shrug
Sometimes you’ll see an actual TXT record in response – e.g. Yahoo or EBay – that’s detritus left over from the days of DomainKeys, a DomainKeys policy record, and it means nothing today.

Read More