Feature request: add config option to require d=... signing domain to be either the FROM domain, or a subdomain of it
Feature request: I would like to make OpenDKIM set Authentication-Results to some kind of failure mode if the d=... domain entry doesn't match the FROM or a subdomain of it. For example, if a mail comes from @gmail.com, I would like it to not mark that as a pass unless the valid DKIM signature uses either the domain gmail.com or any.sub.domain.of.gmail.com. It would be nice to have a config option for this, and from reading the manual it seems like currently there isn't one.
Alternatives considered: I'm guessing OpenDKIM's Lua scripting API might allow this, but I couldn't find a good example of this in the wild and it seems like an easy thing to do incorrectly. Therefore, doing this with a config switch would be safer and less error prone for the user.
Reasoning, or why I consider this useful: I've only seen meaningless third-party signatures use other domains, e.g. mailing lists that aren't inherently trustworthy and of which the signature doesn't indicate to me the original e-mail wasn't spoofed.
I understand a mailing list's DKIM signature from a sender-unrelated domain might still indicate the e-mail has at least been unaltered from the mailing list server to me, but 1. I personally don't consider that worthwhile the risk that addons like "DKIM Verifier" might make the user believe the e-mail isn't spoofed when to my understanding, it often still have might been. Also, 2. it seems to me like security aware mailing lists will often rewrite FROM to themselves anyway and e.g. put the receiver into Reply-To, in which case they can sign with the actual origin domain.
Therefore, in practice any signatures not relating to the FROM domain in any meaningful matter seem to be at best not of much use for figuring out if an e-mail was spoofed, and at worst may confuse and mislead users about the actual security level present.
I don't think it is good idea to use (modifying the meaning of) Authentication-Results: header for this purpose even if the feature is off by default, because it is not compliant to RFCs. I think the porpose of this feature request is to make it easy to rejector to quarantine the message by the local policy that described above, and it can be accomplished by other ways, by rejecting or quaranting directly in the milter, or by adding some X-foo header. (2024-10-26T17:04UTC correction: "Authentication-Result" -> "Authentication-Results")
(This is my subjective opinion, and does not intend to deny the idea itself.)
I do however not wish to reject or quarantine, what I want is to have a clear indication on the client side that this e-mail may not in fact have a trustworthy DKIM signature (which, in my opinion, is usually going to be true for these cases, whether the RFC allows them or not). An X-foo header won't be shown by common DKIM-aware e-mail clients, sadly.
Perhaps an example Lua script for this purpose could be added to OpenDKIM? While I can figure out this specific check in Lua, I don't trust myself to set up the script such that all other behavior remains as before.
A small example of screen script which is described in opendkim-lua(3) can be implemented like:
fdomain = string.lower(odkim.get_fromdomain(ctx))
for idx = 0, odkim.get_sigcount(ctx) - 1 do
sig = odkim.get_sighandle(ctx, idx)
if string.lower(odkim.sig_getdomain(sig)) ~= fdomain then
odkim.sig_ignore(sig)
end
end
return nil
It seems this is almost what you want, except the condition when the milter ignores a signature. As far as I tried, the result of dkim verification on the signature ignored by the milter is recoreded as 'dkim=fail'.
Thanks for the idea! Wouldn't I need to add extra code below to invoke the normal verification after that? The example scripts seem to always do that, it looks fairly complicated. That's why I think a config option would be ideal, since this seems like a rather common sense use case to me.
I found almost same code I wrote above, but more robust, is already in OpenDKIM source tree as opendkim/screen.lua.sample.
I need to add extra code below to invoke the normal verification after that? The example scripts seem to always do that, it looks fairly complicated.
The section about screen script in opendkim-lua(3) says: https://github.com/trusteddomainproject/OpenDKIM/blob/551ab3820476234def82eb2223ca6c7b45b45076/opendkim/opendkim-lua.3.in#L31-L38
Isn't this the answer of your question?
Good find! As far as I can tell, this script doesn't allow subdomains: https://github.com/trusteddomainproject/OpenDKIM/blob/develop/opendkim/screen.lua.sample From my test of real world e-mails, subdomain signatures aren't uncommon. So it's somewhat close.
As far as I can tell, this script doesn't allow subdomains
Yes, so I wrote the condition differs what you want. To accomplish it you need to write a new condition to compaire fdomain and sdomain, by using Lua's string manipulation functions (This link is for Lua 5.4).
Interesting! Isn't this type of check also a common DMARC policy? However, to my understanding mailing lists mean that in practice that's often not used in strict mode. But in my opinion it suggests there might be demand for this check as an easily available thing.
Isn't this type of check also a common DMARC policy?
Yes, and it is not a part of (current version of) DKIM specification. That is why I'm not positive to add it as a config option, and try to treating as a part of local policy script.
By the way, the result of "ignore" some signatures above are "dkim=fail" in AR header on current code, but I think it is incorrect and should not included in AR header (as I described in issue #233). How do you think about it? Do you want "dkim=fail" result for this policy, or is it acceptable to exclude from AR header?
I usually use the option to always include an Authentication-Results header because otherwise, improperly written e-mail clients may assume an attacker-specified header farther down in the return path is a trustworthy one. (E.g. "DKIM Verifier" for Thunderbird by default might pick up on any header.) In that scenario, there would need to be some sort of dkim= entry, and I assume dkim=none might confuse some clients even more if there is actually a DKIM signature present. But I don't really care what value it would be set to, as long as it's not dkim=pass.
Per RFC8601 Sec 2.7.1., it seems that we should use dkim=policy in such a case. I'll comment it to issue #233 and make a PR.
dkim=policy seems like a good choice :blush: thank you so much for looking into this!