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.
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.
Great breakdown of DKIM record errors! This post is a lifesaver for anyone navigating email authentication. Thanks for sharing these insights!