Search code examples
emailoutlookhotmaildkimexim

Exim's DKIM signatures do not verify on Microsoft servers (outlook, hotmail) *only*


Gmail as well as a local ISP passes DKIM for Exim emails, but Microsoft does not, with the fail noted in the header:

Authentication-Results: spf=pass (sender IP is [correct IP]) smtp.mailfrom=[correct domain].co.uk; outlook.com; dkim=fail (signature did not verify) header.d=[correct domain];outlook.com; dmarc=bestguesspass action=none header.from=[correct domain];

What I have tried:

I sent an email to outlook from the same domain through Google Apps (G Suite) email (using a different DKIM selector, i.e. another public key in another DNS TXT record) to compare the message sources - Google's message passed DKIM.

I noticed two things:

  1. Google included far fewer headers in the "h" tag , so I reconfigured Exim to also use precisely these, but to no avail.

  2. Google included the header names in lower-case in the "h" tag, whereas Exim does not, even though I entered them in lower-case in Exim's configuration. I read that header names should be lower-cased when generating the header signature hash, but the text does not state that the same applies to the header names in the "h" tag (http://dkimcore.org/specification.html section 3.2), yet Google seems to do this. I imagine overriding this in Exim would be quite hard?

I also noticed that besides the differences in "h", the DKIM-Signature header structure is exactly the same in both bar some whitespace differences (the exim one also only has spaces and new lines after the semicolon separators, so it appears to be fine, it's just broken up differently). At first I thought maybe Exim wasn't setting some required tags, but in such a case the error should be different anyway.

Exim Version: 4.87 Running on a cPanel 11 centOS 7.2 server Exim DKIM configuration:

dkim_remote_smtp:
  driver = smtp
  interface = <; ${if exists {/etc/mailips}{${lookup{${lc:$sender_address_domain}}lsearch{/etc/maili
ps}{$value}{${lookup{${lc:$sender_address_domain}}lsearch{/etc/mailips}{$value}{${lookup{${perl{get_
sender_from_uid}}}lsearch*{/etc/mailips}{$value}{}}}}}}}}
  helo_data = ${if exists {/etc/mailhelo}{${lookup{${lc:$sender_address_domain}}lsearch{/etc/mailhel
o}{$value}{${lookup{${lc:$sender_address_domain}}lsearch{/etc/mailhelo}{$value}{${lookup{${perl{get_
sender_from_uid}}}lsearch*{/etc/mailhelo}{$value}{$primary_hostname}}}}}}}{$primary_hostname}}
  dkim_domain = ${lc:$sender_address_domain}
  dkim_selector = default
  dkim_private_key = "/var/cpanel/domain_keys/private/${dkim_domain}"
  dkim_canon = relaxed
  dkim_sign_headers = to:from:subject:message-id:date:user-agent:mime-version:content-transfer-encoding

(The last line was added by me - it did not work before either)

As it seems the error specifically relates to the signature verification, I do not believe the following is relevant, but I include it anyway:

The Exim email is being sent by Mr nobody on the server, but the envelope-from and the Return-Path header is the correct email address of the intended sender. There shouldn't be any problems in this area since SPF, even on MS, is passing.

While the email sent from Google has

Message-ID: <[id]@[domain of sender]>

the email sent by Exim has

Message-ID: <[id]@[server host name]>

Any help/ideas?


Solution

  • Wow that was lucky! I found the answer by quite a chance when hopelessly searching Exim's user mailing list before posting there. One of the announcement messages that I opened was also posted to exim-dev and so right at the bottom the archive viewer displayed the previous message in this mailing list, which happened to be about an old, resolved DKIM bug "Headers included in dkim_sign_headers are not in the signature when not in the message".

    However, this gave me the idea to exclude the headers that were not in my Exim generated email from dkim_sign_headers... And it worked :)

    dkim=pass (signature was verified)

    It seems DKIM signatures are supposed to be calculated using non-existent headers that are specified in the "h" tag to make the signature fail if they are subsequently added to the email (makes some security sense), so my guess would be MS is messing up the calculation, but I don't know for sure.