One DKIM Signature for multiple Mail-Domains

The importance of a certain anti-spam-method is not always easy to measure: with DKIM, the DomainKeys Identified Mail, it gets harder again.

What DKIM is about should best be explained by different sites:

That being said, DKIM is simplified a solution to ensure that a given already signed message is verifiable being sent from the server mentioned in the message. The method relies on asymmetrics cryptography with the public key being deployed as a DNS record.

A pair of private and public keys is generated with a given “selector” and a domain name. The public key is stored in a TXT record in the form of “$selector._domainkey.$domain”, the private key should not be exposed to the public ;-). With said private key, messages are signed. The signature may then be later verified using the public key from DNS.

DKIM is not a solution to identify a certain given message as spam, but to ensure the verifiable upstream of a message. This allows to identify Phishing mails using the orginal sender domain (like @paypal.com, @ebay.com etc.), as they cannot use the correct DKIM keys.

On Debian Wheezy with Postfix as a MTA, OpenDKIM as a milter is the preferred way. There are other solutions like using amavisd-new or dkim-filter as well, but those did pose other problems, especially when using multiple domains on one server.

Amavis requires a different key for each domain, so the deployment for new domains is complicated.

With OpenDKIM, multiple domains on a single server may be signed with only one selector.

This blogpost does rely on the following external sources. Please visit the pages for additional information, if required:

The domain used for signing the mails is the same as the hostname of Postfix ("$myhostname"). The selector contains the (short) hostname and the current year (to allow the yearly change of the signing key as well as a verification of old signatures after the change), resulting in my case in:

The required steps to fully enable DKIM signatures when sending messages are the following:

aptitude install opendkim opendkim-tools
    mkdir /etc/opendkim /var/log/opendkim
    chmod 0700 /etc/opendkim /var/log/opendkim
    chown opendkim:opendkim /etc/opendkim /var/log/opendkim
    SOCKET="inet:8891@localhost"
    Syslog yes
    SyslogSuccess yes
    LogWhy yes
    UMask 002
    KeyFile /etc/opendkim/dkim.key
    Selector OURSELECTOR
    OversignHeaders From
    AutoRestart yes
    Background yes
    Canonicalization relaxed/relaxed
    DNSTimeout 5
    Mode sv
    SignatureAlgorithm rsa-sha256
    SubDomains no
    Statistics /var/log/opendkim/dkim-stats
    KeyTable /etc/opendkim/dkim-keytable
    SigningTable refile:/etc/opendkim/dkim-signingtable
    ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
    InternalHosts refile:/etc/opendkim/TrustedHosts

The value for the “Selector”-Parameter should be changed to your needs, as described above! Note the “refile:"-specification of the filename. Without this, OpenDKIM would treat the given “datastet” as a single Key-Value-store. With “refile:”, the key is treated as a regular expression, allowing the use of wildcards.

127.0.0.1
localhost

Mail sent from a SASL authenticated connection will be signed anyway.

hermes2014._domainkey.a1a-server.de a1a-server.de:hermes2014:/etc/opendkim/dkim.key

Again, use the selector and the domainname previously specified!

* hermes2014._domainkey.a1a-server.de
openssl genrsa -out /etc/opendkim/dkim.key 1024
openssl rsa -in /etc/opendkim/dkim.key -out /etc/opendkim/rsa.public -pubout -outform PEM

OpenSSL does not embed any information as in X.509-certificates, so the key is independent of any certain host. Also, it does not need to be signed by a CA, as it isn’t a certificate at all 🙂

chown opendkim:opendkim /etc/opendkim/dkim.*
chmod 0600 /etc/opendkim/dkim.*
"v=DKIM1; p=$PUBLICKEY"

The placeholder “$PUBLICKEY” has to be replaced by the contents of the public key, without the first and last line and without any line breaks. How to actually create the DNS record is beyond this tutorial 🙂 To verify the entry, I’d like to use “dig”:

# dig +short -t TXT hermes2014._domainkey.a1a-server.de
"v=DKIM1\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6+19du037xwYRo0vVckAQcpi9A3sGpcfxZEo5zNarCmcsOIZyf0Chek7BYOoLGbOqwvWy26o3ByJwriHK2x1NMu4tS/DUO5PmO1zy/y432L3VoBfmAjT20NxFEvRCxNuQYYS1SthpFnOdRLmGbdqNXY37MI/2+Oa2hVn40Bi1NwIDAQAB"
# DKIM
milter_default_action = accept
milter_protocol = 2
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891

Make sure to specify the same inet-socket as in /etc/default/opendkim!

Jan  1 02:31:10 hermes.a1a-server.de opendkim[22680]: 9F95E4037C: DKIM-Signature header added (s=hermes2014, d=a1a-server.de)

OpenDKIM signs every message submitted using auth credentials and additionally all messages received from trusted hosts.

Jan 1 02:31:44 hermes.a1a-server.de opendkim[22680]: 0B2A94037B: outmail017.prn2.facebook.com [66.220.144.144] not internal
Jan 1 02:31:44 hermes.a1a-server.de opendkim[22680]: 0B2A94037B: not authenticated
Jan 1 02:31:44 hermes.a1a-server.de opendkim[22680]: 0B2A94037B: DKIM verification successful

SpamAssassin uses the signatures as well. As DKIM itself does not ensure proper spam/antispam, SA only uses larger scores if the verification of the signature fails.

If this poses an issue, each domain should receive an individual DKIM key – but makes this page obsolete 🙂

At the end, some additional remarks: