DKIM Validation: An Email Authentication Best Practice
When we speak of “Email Authentication”, we’re referring to a technique that provides to the recipient of a message some level of certainty that the message actually originated with the claimed source of the message. The idea behind such techniques is to achieve some level of defense against fraudulent email, such as phishing and spoofing, mail that could erode a recipient’s trust in receiving email. That said, the act of sending authenticated email does not assert that the email is good or wanted email; it only means that the mail is such that a reputation for the authenticated party can be reliably established and used in email acceptance and placement decisions.
There are two forms of email authentication in use today:
Sender Policy Framework (SPF)
Domain Keys Identifed Mail (DKIM)
In today’s post, I’m covering what DKIM is and how it works.
Unlike its authentication counterpart SPF, which provides a way for a domain to authorize a host to send mail on its behalf, DKIM provides a way for an entity (domain, organization, person, etc.) to take responsibility for a message, independent of the entity that actually sent the message. While in many cases the responsible entity and the sending entity will be the same, or at least closely related, with DKIM there’s no requirement that this be so.
My goals for you with this post are that you learn and understand the following concepts about DKIM:
DKIM is a “content-based” authentication, unlike the “path-based” SPF.
The responsible entity asserts its responsibility by “signing” the message with a pair of cryptographic hashes inserted in a message header.
DKIM validation is done by the receiving domain attempting to generate the same two hashes.
DKIM validation cannot be completed in many cases until the full message has been transmitted by the sending server.
Validation failures can be difficult to troubleshoot.
DKIM is referred to as “content-based” authentication, rather than “path-based”, because whether or not a message passes DKIM validation is based solely on whether or not the content has changed between the time it was signed and the time validation was attempted.
DKIM Signing and Validation
Organizations wishing to DKIM sign mail will first generate two cryptographic keys. One of the keys is kept private and available to the sending server for the signing of mail, and the other is to be made public in DNS for use by receiving domains in attempts to validate the signature. The methods for generating these keys and installing them are platform-dependent and beyond the scope of this post, although later I will describe the publishing in DNS of the public DKIM key.
The DKIM-Signature Header
To begin our understanding of DKIM, let’s first look at a DKIM-Signature header:
DKIM-Signature: v=1; a=rsa-sha256; d=welcome.foo.com; s=notices; c=relaxed/relaxed; q=dns/txt; firstname.lastname@example.org; t=1454417737; h=From:Reply-To:Subject:Date:Message-ID:To:MIME-Version:Content-Type; bh=e+6RkdhJe69wcQKtRKw9rpDgkkPPbZ8Xwj/2Hi243Sc=; b=KhK4OjejS4QEBr1RwL/naZKBNLoFnR/3lmDOWZC3av4c2aH5Yg/D4vqhh1CpcyfP vRm7cp5EvrnPEsOA7r3E15jarzNFNHXtwjxCFn4g8StsXFOio9vHkO7bmp6t2aLu 8bPkX6cNHgULYS6TdqYd65y5xCDMEaQ9a3mnhF2TQss=;
The DKIM-Signature header is a series of key-value pairs, some of more interest to the reader than others, but I’ll describe all of them here.
First, we’ll look at the ones that are mostly of passing interested to the reader:
v=1; – Specifies the DKIM version (1 is the only valid value)
a=rsa-sha256; – The algorithm used to construct the cryptographic hashes
c=relaxed/relaxed; – There are two sets of rules regarding removal of whitespace in the headers and body that can be applied when creating the hashes in a DKIM signature; these rules are called “canonicalization rules” (hence the key of c) and the rulesets are either “relaxed” or “strict”.
t=1454417737; – The timestamp of when the signature was created.
These three header parts contain the actual signature information:
bh=e+6RkdhJe69wcQKtRKw9rpDgkkPPbZ8Xwj/2Hi243Sc=; – This is the hash of the body of the message.
h=From:Reply-To:Subject:Date:Message-ID:To:MIME-Version:Content-Type; – This is a list of the headers that were used to create the signature data shown below.
b=KhK4OjejS4QEBr1RwL/naZKBNLoFnR/3lmDOWZC3av4c2aH5Yg/D4vqhh1CpcyfPvRm7cp5EvrnPEsOA7r3E15jarzNFNHXtwjxCFn4g8StsXFOio9vHkO7bmp6t2aLu8bPkX6cNHgULYS6TdqYd65y5xCDMEaQ9a3mnhF2TQss=; – This is the acutal DKIM signature data
These three parts are of most interest to the receiving server that will be validating the signature:
d=welcome.foo.com; – This identifies the domain that signed the message
s=notices; – The selector; domains can have multiple selectors that they use when signing messages.
email@example.com; – This is the identity on whose behalf the message was signed. Syntactically, this will look like an email address, and might even be one; the localpart of the email address can be empty, as in this example, and the domain part must be the same as, or a subdomain of, the domain in the d= part of the signature.
The reason these parts are of interest to the receiving server is that they provide the information necessary to help the receiver validate the signatures.
In addition to the requirement mentioned that the i= domain must be the same as or a sub-domain of the d= domain, the d= and s= bits are used by the validator to look up the signer’s public DKIM key in DNS. The key is a TXT record in DNS, and it’s always found at the location selector._domainkey.domain. So, in our example here, with s=notices and d=welcome.foo.com, the public DKIM key would be found in DNS at notices._domainkey.welcome.foo.com, and it might look something like this:
notices._domainkey.welcome.foo.com. descriptive text "v=DKIM1\; h=sha256\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlXNDEHOstbxTkS0tjqy9qw2J 1mnjW5FBWQ4dyrYfrkr8/9VrtAY+eWcKMLUcR3mGFpk9QeHCXoILMJ22TmP1JfhzN NoCcMLffy39eWZKmtm4/Ry29qWBFvn2LKl5W3BBC3e4wQ14l+CQqY4C0QifIrPBwR pod8n+//qIpQIDAQAB\; s=email"
The validator uses that key (the p= bits) to produce its own set of hashes of the message; if those hashes match, then the message hasn’t been altered in transit, and so the message can contribute to, and perhaps benefit from, whatever reputation is in place for the signer of the message.
Validation Failure and Troubleshooting
I mentioned above that DKIM failures can be difficult to troubleshoot, and I’ll explain why that’s so here.
Some DKIM validation failures have obvious causes, such as the message not being signed, or the signing domain’s public key not being found in DNS or not being syntactically correct, or perhaps the message was obviously altered in transit. When those kinds of failures happen, it’s easy to figure out the problem and recommend a solution. The tough ones, though, and the ones which lead to the most frustrating support experience, are the cases where the message was signed, the public key exists in DNS, and the message wasn’t obviously altered, but the validator reports that the signature failed to validate.
The reason that these are tough to troubleshoot is because there’s no real way for either side to reproduce the conditions under which the message was signed and validated. The message has in its DKIM-Signature header the hashes that were generated by the signer at the time of signing, but the validator likely has no access to the signer’s infrastructure and so cannot try to reproduce the signature under the signer’s conditions. Similarly, the signer likely has no access to the validator’s infrastructure and so has no way to try to validate the message in the way that the validator did.
Failures like I’m describing here are rare occurrences, and DKIM validation failures by themselves usually don’t have an impact on delivery placement. It’s been my experience that such failures drive more support tickets than any other kind of DKIM issue.