In order to check DKIM keys for vulnerabilities, I had to first collect a large number of keys. However, this is not straightforward.
A DKIM signature comes with a "selector", which is part of the hostname where the key can be found. This is best explained with an example: If the domain example.com chooses the selector "key" then a signature might look like this:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=example.com; i=@example.com; q=dns/txt; s=key; t=1714897430; h=from : to : subject : message-id : date : content-type : content-transfer-encoding : mime-version : from; bh=B4Sdwm/LsvO9X1e98hS643RXXxvU5oFkgjJHmUF8s3k=; b=S2FkgsXfvp8++uSKecRYdDTE+mtw7VH3tLM7ThnrhG3c84gbtaqCDVFWBYiCLIVd9taWM b6thq+FLiKYLlnFh0wBi7Nj7uTMJRNXWi3fVVKq9Mzn1pcRG6tA+Bu0T5f5ieazITMgN6Sy WmM9AMxBRmkw6dB/eqsjgU6Xlav7zEWZR9t+wLE6urq1idm+tN/LVPf+2mqc/C2Xambc60v rX88ZKWqYnQwaco+DaljH5/ZX+MmF7UJEeI7BpOE4tj1j0W3sRO1R6s2PHMDmAVO9P5J3Eo D+EmUYlVvh82KR92frnK7BHHkTNaJ4h9nsMdWLUNjQ3DKftzuc9MjfkSYTiA==
The variable s= contains the selector, d= contains the domain name.
To verify this signature, a mail server needs to get the public key by looking up the TXT DNS record at [selector]._domainkey.[domain] - in this case key._domainkey.example.com.
The selector can be freely chosen by the sender. Therefore, without access to mails it is not reliably possible to find the DKIM key used by a domain.
One way of collecting DKIM keys is to extract selectors and domains from DKIM signatures in emails. I have created a script to do that.
The script will extract selector/domain combinations. It supports both maildir and mbox. Apart from DKIM signatures, it will also check renamed DKIM signature headers, ARC signatures and old-style DomainKey signatures, which all use the same type of keys.
However, that approach requires access to large collections of emails. While I tried this both with my personal mail archive and with publicly accessible archives (e.g., mailing lists), it was difficult to get a large number of keys with this approach. I eventually got around 35,000 selector/domain combinations with that approach. Not all of them contained a key. This is not surprising, as some will simply be obsolete.
While DKIM selectors can be chosen freely, many choose obvious values like "dkim" or "mail". Therefore, a more fruitful approach was to scan popular domains for the use of common selectors. By taking a set of common selectors and bruteforcing them with popular domains from the Tranco Top 1 Million list, I was able to get a larger set of DKIM keys.
By checking the selectors I already had, I used the following list of common selectors:
default dkim domk k1 key1 key2 mail s1 selector1 selector2
I chose them half-manually by taking the most common selectors while skipping common but uninteresting selectors (e.g., it would not be interesting to scan Gmail's standard DKIM key thousands of times).
It should be noted that these different approaches lead to different biases in the data. The first approach will only give selectors that have been in active use, and it will obviously be biased toward the type of mail that is used as input. (E.g., I mostly used mails from open source and tech mailing lists, as these were available to me, but that biases the data towards the mail setups of a tech-savy population.)
The bruteforce approach can find DKIM keys that have never or rarely been used. This is interesting, as even DKIM keys unused by their owners can obviously be used by attackers if they are affected by vulnerabilities that allow recovering the private key.
Hanno Böck
First published:
Last update: