DomainKey Identified Mail (DKIM)
DKIM is a specification ( RFC 6376)for cryptographically signing certain parts of an email message. Signing using DKIM allows for domain name holders to vouch for the integrity of headers and/or body text. The public keys for the signatures are available through DNS so only the DNS administrators corresponding to claimed domains in the signed components will be able to produce valid signatures.
DKIM affects Mailman in several ways. Most importantly, the transformations that Mailman can inflict on original postings can break DKIM signatures. Mailman can remove headers, add headers, concatenate header or footer text, add or remove MIME parts, completely reorganize the MIME structure of a message, perform character set transformations, and more. Any one of these things can break a DKIM signature.
Other ways in which Mailman and DKIM interact include whether Mailman should validate DKIM signatures on incoming messages and whether Mailman should sign outgoing list copies with its DKIM signature. (Note that when I say Mailman above, I really mean Mailman proper or any assistive mail component Mailman relies upon, such as the incoming or outgoing MTA.)
It is important to note, as per the IETF charter, that DKIM is an anti-spoofing mechanism, not an anti-spam mechanism.
Signature breakage
Mailman's transformations can break DKIM signatures. The official DKIM specifications about best common practices in the face of message transforming mailing list remailers are still in draft form - dkim deployment RFC (link is not resolving). Of larger importance than DKIM signatures is the effect of RFC5617 Author Domain Signing Practiceswhich defines which domains are DKIM signing all email. RFC 6377 directly addresses issues involving DKIM and MLMs.
The question then is, are these best common practices for mailing lists generally acceptable to the administrators that run them? Make no mistake, though, DKIM cannot be ignored; the big players such as Y! and G, Cisco, government departments, banks etc. are already signing messages, and sites are already using DKIM signature validity as part of their mail filtering processes.
Once upon a time this topic was briefly being hotly debated on the mailman-developers mailing list. In September 2009 Daniel Black asked for solutions from the DKIM developers email list. Several opinions were mentioned though without concensus.
There are several options for dealing with DKIM signature breakage. They are not necessarily mutually exclusive.
Option | Pros | Cons |
Ignore the problem | This is the simplest solution because it means we don't have to change Mailman at all. If the original message has DKIM-Signatureheaders, we just leave them in there even if Mailman's transformations break the signature. We do no parsing or verification of the signature, nor do we limit any Mailman transformations we would otherwise apply to the message because of the signature. | The effects of this are that recipients of list copies of the message may fail to verify the signature, potentially treating the message as spammy. Ignoring the problem limits the ability of recipients to filter based on DKIM signatures (not just for email lists) |
Parse the DKIM-Signature header in order to adjust the effects of Mailman transformations on it. | Allows recipients to validate and filter based on DKIM | will end up lots of exception handling code and inconstant emails to the subscriber that may not meet the list owner's policy |
Remove all original DKIM-Signature headers if after parsing the DKIM-Signature header we've broken the signature. | Simple. Solves DKIM validation. | ADSP tells the recipient that a signature should exist where a From address contains the author's domain. Removing DKIM-Signatures is just as bad as invalidating them in the and will result in ADSP rejections. |
sign list-ID headers and ask verifiers to check for list-id tags in a spamminess way | simple | complicates verification provides spoofing loophole as DKIM is antispoofing more that antispam |
remove DKIM-Signature always | as per other similar option (up 2) | as per other similar option (up 2). This solution seems to be strongly disfavored by DKIM proponents. |
rewrite From: email header field to contain the list domain in the From header field. e.g. mailman-users-relay+daniel=cacert.org@python.org | simple - few code changes required Although all modifications of DKIM email signature still occur, it is not as critical as the email is no longer the author domain (based on the from address). As the From: address is now belonging to the list operator, DKIM signing by mailman will be able to be cleanly validated by recipients without having to manage as many whitelists of DKIM-signature invalidating intermediaries. Doing this by default will enable DKIM validation to occur easier. |
Fiddling with From: email header could bring up unknown behaviors. If a reply-to address doesn't exist in the email headers add the from address here to preserve MUA behavior. Desirable is a remap from the From address back to the user validated in a way that it cannot be used as an arbitrary spam address. e.g. validating against the list subscribers. |
Mailman verifying headers
As a remailer, the mailman is in a unique position where there are unlikely to be email lists chained together. The upshot of this is that there is unlikely to be email invalidated before reaching mailman's input. Applying a strong filtering policy on mailman's input is easy - invalid signatures, drop/reject, ADSP failures (dkim=all and dkim=discard) - drop/reject.
As mentioned on the dkim-dev email list dropping emails from subscribers with a ADSP policy of dkim=discardable is recommended on lists that will break DKIM signatures. DKIM discardable ADSP policies are inherently incompatible with current lists.
Mailman signing headers
Signing headers and content provides a mechanism for the recipient to determine if any modification occurred after the mailing list server processed the message. There is no explicit or implicit meaning beyond this. List operators are free to place more assertion here at their peril.
A misconception is that when Mailman (or its downstream components) signs list copies, it means that the list server system is vouching for the validity of the message. Answer no - the RFCs talk in terms of email integrity and not validity - this is mentioned explicitly in draft-ietf-dkim-deployment rfc
Because Mailman is a remailer, such resigning could open an attack vector where spoofed email is sent through the list suddenly gets relayed without verification. This could potentially legitimatize otherwise illegitimate messages. Thus, if Mailman were to add its own DKIM signatures, you'd want to make sure Mailman were also checking the DKIM signatures of messages it receives, and potentially putting a hold (or rejecting or dropping) on messages that had a broken or non-existent signature. You probably also want to do more aggressive spam filtering on the message before it even hits Mailman (disputed - recipients shouldn't be using DKIM as a spam bias score - doing so will just ensure spammers DKIM sign emails. Aggressive spam filtering before mailman will not gain anything DKIM wise).
Spam directly mailed to the list isn't the only problem, though; a much more likely scenario for some lists are that messages gated from Usenet come from a totally unverifiable source. Of course, Usenet gating is a pretty rare use case these days, but still, we shouldn't ignore it. Already python.org occasionally gets labeled as a spam source because of its gating of spam messages from comp.lang.python. It probably makes the most sense to simply not sign gated messages.
Proposal
Because we're in feature freeze for Mailman 2.1, we can't add any new functionality. However, in Mailman 2.1.9, we explicitly began stripping DKIM-Signature headers from incoming messages. This is what sparked the above-mentioned developers thread. The original impetus for this change was a broken DKIM Sendmail milter which refused to sign outgoing messages that already contained a signature.
The proposal for Mailman 2.1.10 then is to add a variable to Defaults.py.in (configurable via mm_cfg.py) that controls whether DKIM-Signature headers are removed or not in outgoing list copies, e.g.:
# Controls whether all existing DKIM-Signature headers in posted messages # get stripped in the outgoing list copies. In general, you should leave # this disabled so that original DKIM signatures will be retained for # forensic purposes, even if broken. Enable this feature only if your site # has specific problems with outgoing pre-signed (broken or unbroken) messages. STRIP_DKIM_SIGNATURE = No
The default is No in order to restore the behavior that came to be expected before the 2.1.9 release.
For Mailman 2.2/3.0 then, we should explore adding DKIM signing code as a handler module, such that definitely List-ID, possibly Sender and potentially other Mailman added headers get valid signatures. However, if we do this, we'll need to have a way to tell the outgoing MTA not to sign certain messages (e.g. Usenet posts). That might require an MTA-specific solution.
We should also encourage the site's incoming MTA to check the validity of any DKIM-Signature header on posted messages. We'd like to see something like a ''DKIM''DKIM validity status header (RFC5451) validity status header added to the message Mailman sees. Then Mailman can put a hold on messages that its upstream MTA tells it has a bad DKIM signature.
We should enable our user's to configure their Mailman system to not break any DKIM-Signature. Perhaps by offering a dkimfriendly=true global option.
Finally, we should encourage the DKIM working group to include language in the spec specifically relating to mailing list interoperability. We cannot ask verifiers to just favorably upon, a valid signed List-ID header as this will just ensure spammers and phishers add List-ID headers to spam.
To develop standards to assist with email lists as an alternative to the last option above that provides a neat solution, there could be a third-party domain signing policies. Some standard that allows senders to define which third party signatures recipients should receive, even if the author domain signature is broken. An example could be DNS records like list_python_org._3p._domainkey.example.com to indicate that recipients should accept a list.python.org third party DKIM signature. The same validation hierarchy could also be used by verifiers of arbitrary domains to see which domains really operate email lists.
References:
A paper Daniel Black wrote on DKIM and email lists - https://community.cacert.org/dkim. Feedback/discussions welcome on dkim-ops list, personally or on dkim-user/dev lists.
Comments
Looking favorably on List-Id tags is just opening a big bypass in dkim email checking. I really like the propositions that say we're going to get with DKIM and continue on to a brave new internet.
Good practice plan:
1. Encourage List managers to reject email with broken signatures or that conflicts with http://tools.ietf.org/html/draft-ietf-dkim-ssp-03 Author Signing Practices. I think this will deal with the "vouching for the validity" problem of signing.
2. Encourage List managers to DKIM sign content. This is just making a statement that the content came through the server and that you've done DKIM checking on the input.
3. Provide a mechanism for List managers not to mangle DKIM signatures. Provide or refer to "DKIM - A list managers' guide"
4. Encourage DKIM implementers to have a policy of configuring favorable DKIM signatures that will allow an email though even if the Author Signing Practices fail. This is mainly for those List managers that insist on breaking signatures.
DKIM IETF Working Group have started DomainKeys Identified Mail (DKIM) Development, Deployment and Operations Draft RFC that covers what Mailing List List Managers should do with DKIM and list email.
I think you have to take the message as it originally came in, extract the DKIM signature and headers that it covers, and then re-sign all those headers and content (after modification).
Think of it like a chain of custody. You get a message that is signed, and which may have some additional stuff associated with it that is not signed (like the "Received:" headers). Because you're going to do something that is likely to destroy the signature and the original message as you received it, you need to re-sign the stuff you got which was signed on input, to be able to demonstrate to others that it had come into you signed, that you verified that signature, and you're certifying what it is that you verified.
I have a suggestion on how this can be fixed:
Take the *whole mail* as sent as the user, and put this into a new message/rfc822 container, that has the envelope from *AND* "From:" set to the list mailing adress (eg the mail adress that users send their list posts to).
So a list mail like this:
From: listuser@example.org To: list@list.org Subject: Fix this Content-Type: text/plain
This is broken.
Can be sent out from the list as:
From: list@list.org To: list_subscriber@someotherhost.org Subject: Fwd: Fix this Content-Type: message/rfc822; boundary="
1234"
This is a MIME Message
1234 From: listuser@example.org To: list@list.org Subject: Fix this Content-Type: text/plain
This is broken.
1234--
The fixed mail can additionally be DKIM signed by the list software.
The advantages of this, is that it will BOTH fix DKIM problems (since the signing is done from the list domain and not the sender domain), *AND* SPF, since the SPF will then be validated against the list domain and not sender domain).
Another advantage by encapsulating the mail into a new message/rfc822 container, is that you don't break any previous DKIM signatures, and also do not break any S/MIME or PGP signatures.
The suggestion in the comment by SebastianNielsen is exactly what is done by the from_is_list Wrap Message setting first implemented in Mailman 2.1.16 and made more generally available (not requiring site option to enable) in Mailman 2.1.18. See DEV/DMARC.
Re: Problems with Mailman signing headers
You write that a Mailman signature could potentially "legitimize otherwise illegitimate message". Technically, this is confusing language. "Legitimate" is a local policy decision and will surely vary from site to site. I would express this kind of idea as "result in recipients accepting spam and undesired messages that they otherwise would reject."
You suggest not signing gated messages. This has its own problems, specifically that (1) it is useful to promise to sign all messages, but the list is deliberately not signing some of its output (2) many sites that know that this list signs will drop all unsigned posts. A plausible alternative strategy would be to sign Usenet-gated posts with a different key. I don't think this is generally going to be more than minor extra effort, as any decent signing agent will be prepared to deal with selectors. (I suppose this is mandated by DKIM, but I haven't checked.)
Re: Proposal
The language for 2.1.10 is excellent.
For 2.2/3.0, shouldn't all RFC 2369 headers be signed to prevent phishing attacks? Sender should be signed for Mailman's own potential benefit, I think, and of course DKIM itself mandates signing From.
The discussion of the DKIM status header should remark that DKIM does not even suggest a format for these headers, so they will be implementation-dependent. I think a call for Mailman advocates to participate in specification of a standard header, as well as to help with implementations' headers in the meantime, may be warranted.
Regarding the call for verifiers to "look favorably on" verified list signatures, I'm of two minds. Technically, I think it's a bug in the DKIM spec that it doesn't thoroughly distinguish between verifiers and policy agents (not to mention that it fails to mention the role of policy agents for the signing decision at all!) So I don't like language that suggests that verifiers make policy decisions. There's plenty of precedent for it in the latest DKIM draft, though.
Language to the effect that verifiers MAY make extra effort to find a valid list signature in the case where broken signatures are found is definitely appropriate, though.
As Michael has repeatedly emphasized, very little is known about the pragmatics of re-signing. Nonetheless, I think that a better way to try to accomplish this is to have a Mailman implementation that wants to take responsibility for broken signatures is to sign those signatures. (Remember, it can also create another signature without signing them. Then the signature signature might fail due to an intermediary reordering DKIM signatures, but the signature of the post itself would succeed.)
Then the BCP for policy agents could say that the presence of a broken signature which is nonetheless verified by a valid signature SHOULD be considered an indication that the verified signer verified the broken signatures on the way in, and that the verified signer then broke them. (This doesn't mean that a policy agent should trust the broken signature. That depends on how much it trusts the verified signer.)
Without signing the signatures, there's an obvious vector for reply attacks. I don't think that can be written into the standard or BCP.