DomainKeys Identified Mail
Introduction
DomainKeys Identified Mail (DKIM) is used to detect if an e-mail is spoofed (forged). It is used to prevent spam and phishing. Signing mail with DKIM will helps detect spam that pretends to come from an unrelated domain. Many spam filters require mail be signed with DKIM to get delivered into the inbox.
With DKIM, a letter is signed with a private key. This allows the receiver to check if the email comes from the domain it claims to be from. The receiver looks up the sender's public key in the domain's DNS record. A valid signature guarantees that the sending mail server has access to the private key and that the email body has not been tampered with during transit.
DKIM, SPF, and DMARC are designed to work together.
DKIM Header
When the sending mail server signs a message with its private key, it prepends a DKIM header like the one below:
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; s=mail; bh=gVJEBqfjoVwtQhV vV3FHh0UQBW0m9unTpuaaGORFGKI=; h=subject:date:from; d=example.com; b=Jv/9zpB2AJGosO4/uYlZxFEm1UFOTy56JBi/nhsjg Am5Qe+rkuKYru5mSqvP01ii/sQRI4exNbG/S8ihdcEXsr5fr8yK4IvLkY8jO5O0xMhblyS PbFGMw7SW2AwLWu95OyHK5teZPzE/SS5U39Zlqs7tS1m8iZo2tPBa70t9204na8/eOT6N7 8IzNIfRHJfF4dNGVX61t9xknkcJrJdC6npO0l4MVTky66safTbcCjlM6JihbUd5j4uOU5I WREE02CLQKWg5c/UnjQQ96Dt308f2RvxeWA6P8hxsjD/FLDIR2U1ZEQyo7k03KCJbdRVw8 IHJTdENGGL3p7aM1v8wdg==
Tag | Indicates | Example |
---|---|---|
v | version | v=1 |
a | algorithm | a=rsa-sha256 |
d | domain | d=example.com |
s | selector | s=mail |
c | canonicalization algorithm | c=simple/simple |
h | header fields | h=subject:date:from |
bh | body hash | bh=gVJEBqfjoVwtQhVvV3FHh0UQBW0m9unTpuaaGORFGKI= |
b | signature | b=Jv/9zpB2AJGosO4/uYlZxFEm1UFOTy56JBi/nhsjgAm5Qe+rku KYru5mSqvP01ii/sQRI4exNbG/S8ihdcEXsr5fr8yK4IvLkY8j O5O0xMhblySPbFGMw7SW2AwLWu95OyHK5teZPzE/SS5U39Zlqs 7tS1m8iZo2tPBa70t9204na8/eOT6N78IzNIfRHJfF4dNGVX61 t9xknkcJrJdC6npO0l4MVTky66safTbcCjlM6JihbUd5j4uOU5 IWREE02CLQKWg5c/UnjQQ96Dt308f2RvxeWA6P8hxsjD/FLDIR 2U1ZEQyo7k03KCJbdRVw8IHJTdENGGL3p7aM1v8wdg== |
Tip: Many mail clients provide the ability to view the headers in mail. When headers are displayed, a DKIM header should be visible if DKIM-signing is configured properly.
A receiving mail server will perform a DNS lookup based on the domain name and
selector. In the example above, it will look up the TXT record of
mail._domainkey.example.com
. The TXT record returned should
look like below:
"k=rsa; t=s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDmzRmJRQxLEuyYiyMg4suA2Sy MwR5MGHpP9diNT1hRiwUd/mZp1ro7kIDTKS8ttkI6z6eTRW9e9dDOxzSxNuXmume60Cjbu08gOyhPG3 GfWdg7QkdN6kR4V75MFlw624VY35DaXBvnlTJTgRg/EW72O1DiYVThkyCgpSYS8nmEQIDAQAB"
Security Notes
DKIM-signatures can be used to prove that a mail server sent a letter. Only the sending mail server should have access to its private key. So, when a signature is verified by the corresponding public key, it can provide proof of origin.
Note: DKIM does not provide end-to-end integrity. For this, both sender and receiver will need to use PGP?.
OpenSMTPd and DKIM
For OpenSMTPd to sign mail with DKIM, a private key and its corresponding public key must be created:
$ doas -u _dkimsign openssl genrsa -out /etc/mail/dkim/private.key 1024 $ doas -u _dkimsign openssl rsa -in /etc/mail/dkim/private.key -pubout -out /etc/mail/dkim/public.key $ doas -u _dkimsign chmod 400 /etc/mail/dkim/private.key $ doas -u _dkimsign chmod 444 /etc/mail/dkim/public.key
Next, a TXT record? will be created from the public key, so that the receiving mail server can verify the DKIM signature. The script below will remove the first and last line of the public key, then join the remaining lines together:
$ doas -u _dkimsign cat /etc/mail/dkim/public.key | awk '/-----/{if (NR!=1)print "";next}{printf $0}' -
This command should produce text like the following:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmseF9Dm8Dx1LtmLMD56d628JBNaQus8aEcdYYzvBVQ4rhetZzv/ZMafjTEf2RLoOQ+pb7pqL4G86lCZSF+Eeu2ODWQQGYqGVV0xUK5QJSnsGF5UKKscrxmTHSPPtoAQJt25fxNd3PtvH2ZonAGkZkntk+u6Wn5xxlI9hMOVxLUwIDAQAB
This key should go into the DNS TXT records below:
_adsp._domainkey 3600 IN TXT "dkim=discardable;" mail._domainkey 3600 IN TXT "k=rsa; t=s; p=<public key>"
The final result should look like this:
_adsp._domainkey 3600 IN TXT "dkim=discardable;" mail._domainkey 3600 IN TXT "k=rsa; t=s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmseF9Dm8Dx1LtmLMD56d628JBNaQus8aEcdYYzvBVQ4rhetZzv/ZMafjTEf2RLoOQ+pb7pqL4G86lCZSF+Eeu2ODWQQGYqGVV0xUK5QJSnsGF5UKKscrxmTHSPPtoAQJt25fxNd3PtvH2ZonAGkZkntk+u6Wn5xxlI9hMOVxLUwIDAQAB"
Note: the _adsp
records come from RFC5617 which was marked as historic in 2013. More testing is necessary to determine if these records are really needed.
Troubleshooting
smtpd(8) may not start up properly. This can be verified with pgrep(1):
$ pgrep smtpd
If no process ID numbers appear, then
smtpd(8) is not running. Check the
maillog (by default, /var/log/maillog
):
File Permissions
OpenBSD strictly checks ownership and file permissions listed in
/etc/mtree/special
as part of its security checks.
Jul 17 14:46:18 example smtpd[20780]: info: OpenSMTPD 7.7.0 starting Jul 17 14:46:18 example smtpd[17229]: dkimsign: Can't open key file (/etc/mail/dkim/private.key): Permission denied Jul 17 14:46:18 example smtpd[42894]: warn: lost processor: dkimsign exited abnormally Jul 17 14:46:18 example smtpd[42894]: Exiting
This indicates a file permissions issue with /etc/mail/dkim/
. Simply
restore the correct file permissions, then start
smtpd(8):
# chown -R _dkimsign:_dkimsign /etc/mail/dkim/ # chmod 770 /etc/mail/dkim/ # chmod 400 /etc/mail/dkim/private.key # chmod 440 /etc/mail/dkim/public.key # rcctl start smtpd