Using DKIM in Exim
Since Exim 4.70, DKIM (DomainKeys Indentified Mail - RFC4871) has been supported by default.
The current implementation supports signing outgoing mail, as well as verifying signatures in incoming messages, using the acl_smtp_dkim ACL. By default, DKIM signatures are verified as new messages come in, though no action is taken unless you've implicitly configured rules in the DKIM ACL.
After installing Exim (>= 4.70), you should see debug logs for incoming mail from servers that have DKIM signatures setup- they look like:
DKIM: d=gmail.com s=gamma c=relaxed/relaxed a=rsa-sha256 [verification succeeded]
Verifying Incoming Mail
By default, Exim does not filter any mail based on the validity of the DKIM signature- it's up to you to add ACL rules to control what happens when you receive messages with "bad" signatures.
First add an ACL section for the DKIM processing; this should be included with your other ACL statements:
acl_smtp_dkim = acl_check_dkim
Next, after the "begin acl", section, add your DKIM ACL section, and by default, accept all messages in this ACL:
acl_check_dkim: accept
Now you need to decide what kind of rules you want to setup- you probably don't want to put a rule that applies to all domains- though, if the company went to the trouble of adding DKIM signatures to their e-mail, you'd hope they'd get it right, and not publish invalid public keys.
For now, let's add a simple rule for gmail; google knows what they're doing, so their systems should be setup correctly:
acl_check_dkim: # # check the DKIM signature for gmail # deny message = Common guys, what's going on? sender_domains = gmail.com dkim_signers = gmail.com dkim_status = none:invalid:fail accept
You can add as many rules, for whatever domains you want in this ACL.
Signing Outgoing Mail
Now that you're checking incoming mail, you probably want to sign mail coming out of your system. This is a relatively easy process, that I've broken down into three steps:
Step1- Generate a private and public key to sign your messages; you can do this easily with openssl:
#openssl genrsa -out dkim.private.key 768
Then extract the public key from the private key:
#openssl rsa -in dkim.private.key -out dkim.public.key -pubout -outform PEM
Step2- Configure the Exim remote-smtp transport to sign outgoing messages, using your new private key. You'll need to pick a domain and a selector for this process.
When remote SMTP servers validate your DKIM signatures, they simply do a DNS look up, based on the selector and your domain- the domain needs to (obviously) be a valid domain you own, that you can add DNS entries to, and the selector can be any string you want. So, for example, using the domain "example.com", and the selector "x", you would add to the remote_smtp transport in Exim:
remote_smtp:
driver = smtp
dkim_domain = example.com
dkim_selector = x
dkim_private_key = dkim.private.key
dkim_canon = relaxed
This tells Exim to sign any outbound e-mail, using the domain example.com, the selector "x", and the private key we just generated. The dkim_canon = relaxed, sets the canonicalization method to use when signing messages. DKIM supports "simple" and "relaxed" algorithms- to understand the difference, see section 3.4 of the DKIM RFC.
Step3- add your DKIM public key to your DNS.
The DKIM public key generated above is advertised to other SMTP servers, using a DNS TXT record. In DNS for the domain example.com, add a new TXT record:
x._domainkey.example.com. TXT v=DKIM1; t=y; k=rsa; p=<public key>
Where "x" is the selector you used above, and <public key> is the public key data (minus the key header/footer text).
When setup correctly, your DKIM text record should look something like this:
# host -t txt x._domainkey.example.com x._domainkey.example.com descriptive text "v=DKIM1\; t=y\; k=rsa\; p=MIGfMA0GCS qGSIb3DQEBAQUAA4GNADCBiQKBgQC5k8yUyuyu9UAVHHU7Al4ppTDtxFWsZ6Pqd9NWZnomtewBdz8I 2LJkqmA/3Cyb5Eiaqk4NulPFfDbfA0Lkw7SNyOS9BRN02KGtKIWjFqDwjB99haaWYw9H4IZcuJp0Y q0kySCdBp/sPP+iTotdBiE85Jakw3tzgYkdvaS05ZUdBwIDAQAB"
(lines breaks were added for readability- your entry should be one continuous line)
This DNS record is referred to as the "selector" record; you need to also setup a "policy" record. The policy record is your domains policy for domain keys- you should start with something like:
_domainkey.example.com. t=y; o=~;
The t=y specifies that you are in test mode and this should be removed when you are certain that your domain key setup is functioning properly. The "~" in the o=~ specifies that some of the mail from your domain is signed, but not all. You could also specify o=- if all of the mail coming from your domain will be signed.
Once you have all of that in-place, restart Exim, and send out a message using the remote-smtp transport. You should now see a DKIM-Signature: header listed in the message headers, which lists your domain (as d=), and selector (as s=), as well as a signature for this e-mail, which can be validated against your public DKIM key, that you've published in DNS.
For more information, see the Exim DKIM page, or the DKIM RFC.
UPDATE:
Once you've set everything up, you can test your DKIM (and SPF and SenderID, etc) install, by using the port25.com validation service.
Just send an e-mail to check-auth@verifier.port25.com, and it will auto-respond with a validation report
February 13th, 2010 - 07:34
Thanks for the info. This is the first complete description that I found on the net which is really understandable.
Theres a small and easily detectable spelling error in acl_check_dkim however:
sender_domain = gmail.com
should really be
sender_domains = gmail.com
What I am still looking for now is a real-live validation test. dkim-test@testing.dkim.org seems to be down, so except seeing that a dkim sig. is included I cannot yet check if the signature is really fully valid.
February 13th, 2010 - 13:19
@Marcel
Thanks for the pointing out that mistake Marcel.
As far as the live validation; port25.com has a similar auto-reply service; just send to check-auth@verifier.port25.com; their system also validates SPF, Sender-ID, and a few other things.
Cheers,
Mike
February 23rd, 2010 - 14:59
Yup, found it as well in thee meantime. All working nicely now. Only one listserver sometimes breaking the signature, but all other messages seem to work perfect.
One thing to add is that one should perhaps also add an AuthorDomainSigningPolicy record:
_adsp._domainkey.yourdromain.something
as a text record containing “dkim=all” to indicate one signs all messages. Other option would be “dkim=unknown” to indicate only some mail is signed (for testing that is probably recommended).
February 24th, 2010 - 13:13
Thanks for an excellent explanation. Please forgive my newbie question. I have multiple domains sending mail from the same server. Should there be a separate entry for each in the Exim configure file. How should they look?
February 26th, 2010 - 20:04
Jim,
You don’t necessarily have to setup something different per domain- you can sign all your outbound e-mail from the same domain/selector.
If you wanted to have a different config, based on the domain of the sender address, you could technically do a lookup based on the sender domain, and return values for each of the dkim_domain, dkim_selector and dkim_private_key values.
Then you could store these values in a lookup db, or SQL database by sender domain.
So as a quick (un-tested) example, you could do something like this:
remote_smtp:driver = smtp
dkim_domain = $sender_address_domain
dkim_selector = x
dkim_private_key = ${lookup pgsql{select key from dkim where domain = ${quote_pgsql:$sender_address_domain}}{$value}}
dkim_canon = relaxed
Which would use a common selector of “x”, the domain of the sender e-mail, and a SSL key looked up from a PostgreSQL database by domain.
March 7th, 2010 - 13:21
@mike
Thanks. I am using the same domain/selector and getting a “pass” from check-auth@verifier.port25.com for “DKIM check” for all domains.
Again, thanks for the excellent tutorial.
May 10th, 2010 - 14:00
Thanks a bunch for this great tutorial. I have a couple questions though. For starters, I’m on Debian and Nginx and I installed exim with this command: “apt-get -t lenny-backports install exim4″ which installed version 4.71. I then followed your tutorial for signing emails but my emails still don’t get signed. Step 1 seems to have gone off without a hitch as I can verify that both those files now exist and have data that looks right.
I added the following lines to /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp under driver = smtp:
dkim_domain = dostuffright.com
dkim_selector = whizbang-dkim
dkim_private_key = /dkim.private.key
dkim_canon = relaxed
And restarted exim. I then added the txt record to my domain as you instructed. The problem is that my emails don’t seem to be getting signed. I’ve tried looking at the raw headers and sending emails to six different rotator services and I’m quite positive my emails aren’t getting signed. So my questions are:
1) Is there something I need to do to turn signing on besides adding those lines to that file?
2) What is the “selector”? Is it just some random word that has to be in both the header and the txt record?
3) Is dkim_private_key just the path to the dkim public key on my server? That’s what I’m assuming it is.
Thanks a bunch!
Beau
May 12th, 2010 - 12:37
@Beau
Hey Beau,
I’m not 100% familiar with the Debian install; it seems to break the file up into components- usually I install from source and have just one big configure file- but this looks like the right spot.
1) That should be all you need to at least sign out-going messages.
2) Yup, the selector is just a random word that is specified in your config; it uses this word to do the DNS lookup against your domain- most of the time it’s kept really short (like a single character), but as long as it’s a valid hostname, it’s fine.
3) Yes, that’s the full path to the private key; so in your example, your private key would have to be in /- is that correct? maybe it’s not signing your e-mails because it can’t find the key?
Also, have you confirmed that messages are being sent through exim? can you see messages coming in/out in your main exim log file?
Mike
June 20th, 2010 - 01:53
Hi Mike,
Thanks for this great topic, I did that but I got permerror (key failed) for dkim and no sig for domainkeys.
Authentication-Results: mta1045.mail.sk1.yahoo.com from=developers-heaven.net; domainkeys=neutral (no sig); from=developers-heaven.net; dkim=permerror (key failed)
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=developers-heaven.net; s=x; h=Content-Transfer-Encoding:Content-Type:MIME-Version:Message-ID:Date:Subject:To:From; bh=dZwg0roqeT4Z81/Gk6beBXednOetUVdfKD0HSi0smMw=; b=iwjc2Fu7aQAZ3nSb9Asu1DaPh27Lut0Ig2xEZ9FS5Frwnq57fJa8Vo4iaOKu/RokAIDVtgMUtZoh0JyBlpG18yJJILwuPO4ORzstS/fP9EGxfyLZBDZLtcSQOFRhc/dr;
DKIM check details:
———————————————————-
Result: permerror (invalid key: error reading public key: 3071417264:error:0D07209B:asn1 encoding routines:ASN1_get_object:too long:asn1_lib.c:142:;3071417264:error:0D068066:asn1 encoding routines:ASN1_CHECK_TLEN:bad object header:tasn_dec.c:1281:;3071417264:error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error:tasn_dec.c:380:Type=X509_PUBKEY;)
May you please guide me how to fix.