The various meanings of DKIM signing message headers

November 4, 2023

When I talked about the issue of what headers to include in email DKIM signatures, I didn't really cover the specifics of how you DKIM sign email headers and what the various options mean. The specifics can matter, especially since they help you (me) understand and navigate through the options that mailers (such as Exim) offer here.

In email messages, DKIM signatures appear in a DKIM-Signature header, which lists a bunch of parameters:

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed;
   d=list.zfsonlinux.org;
   h=from:to:subject:message-id:in-reply-to:references:date
   [....]

The 'h=' list (which isn't complete here) is a list of headers that have been signed. More specifically, it's a list of instances of headers. If there are multiple instances of a given header in a message, DKIM defines an order to them and the instances of the header are checked (or used) in that order. So if you include 'from' once in the DKIM header list, you are saying that your DKIM signature includes DKIM's first 'From:' header in the message. If a second 'From:' header is added to the message, it's not included what's covered by your DKIM signature; it can have any value and the message will still pass DKIM validation.

As mentioned last time, including a header that doesn't exist in the DKIM signature signs its absence; if that header is then added to the message, the DKIM signature will become invalid. DKIM signing things that aren't there is sometimes called oversigning a header; you're not just signing what's present, you're also signing what's not. As a corollary of this, if you want to seal a message against having extra copies of some headers added, you can deliberately oversign existing headers. This is done by including their names an extra time in the h= list; the first time signs the existing header, and the second time signs that there's no second header. So if we wanted to make sure no one added a second 'From:' to a message, we'd sign 'h=from:from:[....]'.

One reason to oversign existing headers that should only appear once is that anyone who adds a second 'From:', 'Date:' or whatever to your message is probably up to no good. Another reason is that it's hard to predict which instance of the header a mail client will show to people reading the message, and there are probably some mail clients that will show the wrong instance of the header (the instance that isn't covered by your DKIM signature and so can be set to anything by an attacker).

This creates several options and decisions:

  • do you make it so that certain headers can't be added to the message later, like the List-* and Resent-* families, or allow them to be added later?
  • what headers do you sign if they're present? For example, should you sign Resent-* or List-* headers at all?
  • do you oversign some existing headers so that no additional copies can be added?

Based on a quick skim of email that I have handy, relatively few sources of mail seem to be oversigning existing headers. However, GMail does oversign at least some email for core headers like From: and Subject:. Since Google is one of the eight hundred pound gorillas of email, if they're doing it people's DKIM signature validation is at least prepared to cope with this.

(I suspect that having two From:, Subject:, or so on headers trips enough spam detection systems that attackers don't normally do it.)

Written on 04 November 2023.
« Our varying levels of what you could charitably call 'physical security'
Exim's options for how to DKIM sign various email headers »

Page tools: View Source.
Search:
Login: Password:

Last modified: Sat Nov 4 22:34:22 2023
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.