Linux Setup Notes

name and address
created mar. 15, 2007

Setting up DKIM with Sendmail

What is DKIM

DKIM is a new standard for preventing forgery of email headers. Fake email headers, created mainly by spammers, are an especially serious threat to small networks. Large ISPs have a big financial incentive to drop messages from small networks in order to give preference to messages from their own servers. If a spammer forges your headers, it gives the Internet companies an excuse to blacklist your network and drop all email from your domain. DKIM takes away that excuse by providing a guarantee that the only mail with your network's name on it is what you actually sent.

In other words, DKIM does not protect you against spam, but it protects you against anti-spam fascists and large ISPs who have difficulty identifying and implementing appropriate anti-spam measures. In many ways, these anti-spam tactics are a bigger threat than spam, because while spam is an annoyance, excessive anti-spam measures interfere with connectivity.

To implement DKIM, you, the domain owner, add a public key to your DNS server. You then install DKIM software, which interacts with your mail transport agent (in this case, sendmail), and creates a signature based on the public key, your private key, and the headers and message body of each outgoing email message. This signature is added to the headers. Therefore, each outgoing message has a different signature. If the message or headers are altered in transit, the signature becomes invalid. The recipient uses public key cryptography to validate the signature in the email message against the public key in the DNS record. If it validates, this authenticates the message sent by your server.

The advantage of DKIM is that it's sent automatically, and it's transparent, since the email message is signed in the headers instead of the message body. DKIM only proves the sender's hostname has not been forged. It doesn't mean the email message is not spam. It just means it's your spam and not somebody else's.

One disadvantage is that spam checkers like Spam Assassin and spam appliances like Barracuda which rewrite the mail headers could invalidate the DKIM signature unless special precautions are taken. This document describes how to set up DKIM to work with sendmail. Interacting with spam appliances will be discussed elsewhere.

Requirements

  1. Access to the DNS records for your domain.
  2. OpenSSL library (version 0.9.8 or higher) installed.
  3. Sendmail 8.13 or higher installed.
  4. Berkeley sleepycat DB library (libdb) installed.
  5. Dkim-milter version 2.5.0 or higher.

Installation

  1. Rebuild sendmail to include milter support, and build the libmilter libraries (which are included with sendmail), as described in linuxsetup56.html. The libmilter.a library is required for dkim to compile. (It is not necessary to compile or install the clmilter library or the other clamav stuff.)

    Restart sendmail and make sure your mail is still working.

  2. Download, build, and install openSSL version 0.9.8 or higher. This is essential to get SHA256 support. It may be necessary to manually delete the links to earlier versions of libssl.so in /usr/lib, and add new ones, to ensure that the correct library is used.

  3. Download and detar dkim-milter:
    tar -xzvf dkim-milter-2.5.0.tar.gz

  4. Edit site.config.m4 and include the extra statements if needed to make it compile. You will need libmilter from sendmail and the header files from openssl-0.9.8.

    cp site.config.m4.dist site.config.m4
    (edit file)
    cp site.config.m4 devtools/Site/
    

    Note: if you change the site.config.m4 file, it is necessary to use sh Build -c or it will have no effect. I added following two lines to site.config.m4:

    APPENDDEF(`bld_dkim_filter_INCDIRS', `-I/home/tjnelson/sendmail/sendmail-8.13.6/include')
    APPENDDEF(`bld_dkim_filter_LIBDIRS', `-L/home/tjnelson/sendmail/sendmail-8.13.6/libmilter')
    
  5. Build and install dkim-milter.

    cd dkim-milter-2.5.0
    sh Build
    su
    sh Build install
    
  6. As a regular user, generate the key pair.

    openssl genrsa -out rsa.private 1024
    openssl rsa -in rsa.private -out rsa.public -pubout -outform PEM
    

    This will create two keys in your current directory, named rsa.private and rsa.public.

  7. Rename the private key to mail.key.pem and move it to the dkim directory. The prefix "mail" is what DKIM calls your "selector." Having different selectors lets you have different keys for more complex configurations.

    mv rsa.private mail.key.pem
    su
    mkdir /var/db
    mkdir /var/db/dkim
    cp mail.key.pem /var/db/dkim/
    
  8. Go to your DNS server and add a DNS TXT record for the public mail key to the forward (names → IP numbers) zonefile.

    For example, if this is your public key

    -----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOK861e3Ymestv7aW1HCaZaID4
    QUIngg166FKaV6roemnt1XCyIiiFnRjdAXD7R4kHJLUJaOoDatGmFd2oZh4AAsY4
    SG8JP+mE6yrjVyPOA3rRyRlS0LEWKpF6NKtPtZS7iaQu5Ma0kt/OXSpCcbcKCg7v
    L/Bv2RWu2vfwTtBI/QIDAQAB
    -----END PUBLIC KEY-----
    

    You would use the text starting with 'M', with all spaces and newlines removed. Stop named and add the following line to your zone file:

    mail._domainkey IN TXT "v=DKIM1; g=*; k=rsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOK861e3Ymestv7aW1HCaZaID4QUIngg166FKaV6roemnt1XCyIiiFnRjdAXD7R4kHJLUJaOoDatGmFd2oZh4AAsY4SG8JP+mE6yrjVyPOA3rRyRlS0LEWKpF6NKtPtZS7iaQu5Ma0kt/OXSpCcbcKCg7vL/Bv2RWu2vfwTtBI/QIDAQAB"
    

    Then restart named. The prefix ("mail" in this example) can be anything, but it must match the Selector entry in /etc/dkim.conf and the prefix of your public key. You could also use dkim-genkey to generate a key suitable for DNS by typing: dkim-genkey -d my_domain_name.com -s mail -t. This key is placed in a file named mail.txt, and the matching private key is placed in mail.private. The '-t' option means "test mode", which means that other servers should ignore it.

    There is also a utility called dkim-testkey that tests the key:

    dkim-testkey -d my_domain_name.com -k /var/db/dkim/mail.key.pem -s mail
    

    If all is well, it should say, and I quote, " ".

  9. Create an unprivileged user for milter, e.g., dkim, with shell set to /bin/false.

  10. Create a config file named /etc/dkim.conf similar to the following:

    Canonicalization simple
    Domain host1.my_domain_name.com
    KeyFile /var/db/dkim/mail.key.pem
    MTA MSA
    Selector mail
    Socket inet:8891@localhost
    SignatureAlgorithm rsa-sha1
    Syslog Yes
    Userid dkim
    X-Header Yes
    Mode sv
    InternalHosts /etc/dkim-internal-hosts
    

    The word after "Selector" (mail) must match the first part of mail.key.pem. The entry "MSA" should be entered verbatim. See man dkim-filter.conf for more details.
    Note that although it asks for "Domain", you should enter your fully qualified domain name (that is, your hostname + domain name combination) instead. Remember to change the hostname in this file to match your network.

  11. Create a file named /etc/dkim-internal-hosts containing the fully-qualified names of whatever hosts will be sending mail, one per line. Only these hosts will have their outgoing messages signed. All others will be authenticated instead.

    host1.my_domain_name.com
    127.0.0.1
    

    Remember to change the hostnames in this file to match your network.

  12. Edit your sendmail.mc and add the following line:

    INPUT_MAIL_FILTER(`dkim-filter', `S=inet:8891@localhost')
    

    and rebuild the sendmail.cf file

    sh Build sendmail.cf 
    su
    make install-cf
    

    and restart sendmail. Don't put it in submit.cf, or you will get two DKIM signatures.

  13. Start the milter:

    /usr/sbin/dkim-filter -x /etc/dkim.conf 

    or, if you prefer, use a long command line

    /usr/sbin/dkim-filter -d my_domain_name.com -v -l -h -p inet:8891@localhost  -c simple  -k /var/db/dkim/mail.key.pem -s mail -S rsa-sha256 -u dkim -m MTA -i /etc/dkim-internal-hosts
    

    (The v (verbose) option actually has no effect.) Add this command to /etc/rc.d/local or some other place where it will start up automatically if the system is rebooted. Alternatively, you could use a standard startup script.

    When it starts up, it should write to the system logs. One problem is that it doesn't do much other than give basic start/stop information.

    Mar 15 16:11:42 entropy dkim-filter[12965]: Sendmail DKIM Filter v2.5.0 starting (args: -x /etc/dkim.conf)
    Mar 15 16:12:41 entropy dkim-filter[12965]: Sendmail DKIM Filter: mi_stop=1
    Mar 15 16:12:41 entropy dkim-filter[12965]: Sendmail DKIM Filter v2.5.0 terminating with status 0, errno = 0
    Mar 15 16:14:33 entropy dkim-filter[13033]: Sendmail DKIM Filter v2.5.0 starting (args: -x /etc/dkim.conf)
    

Debugging and Testing

  1. If you send a message to autorespond+dkim at dk.elandsys.com, the system will return a response to let you know if DKIM is working. Also, examine the headers of incoming email to make sure your system is checking the DKIM signatures.

  2. Read man dkim-filter.conf and man dkim-filter for additional options.

  3. Check your DNS with dig to make sure the correct public key is being read:

    dig +short mail._domainkey.my_domain_name.com txt @dandruff.my_domain_name.com
    

    where "dandruff" is your name server. It should say:

    "k=rsa; v=DKIM1; g=*; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOK861e3Ymestv7aW1HCaZaID4QUIngg166FKaV6roemnt1XCyIiiFnRjdAXD7R4kHJLUJaOoDatGmFd2oZh4AAsY4SG8JP+mE6yrjVyPOA3rRyRlS0LEWKpF6NKtPtZS7iaQu5Ma0kt/OXSpCcbcKCg7vL/Bv2RWu2vfwTtBI/QIDAQAB"
    

    Or use the host command:

    host -t txt mail._domainkey.your_domain_name.com
    

    It should say:

    mail._domainkey IN TXT "k=rsa; v=DKIM1; g=*; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOK861e3Ymestv7aW1HCaZaID4QUIngg166FKaV6roemnt1XCyIiiFnRjdAXD7R4kHJLUJaOoDatGmFd2oZh4AAsY4SG8JP+mE6yrjVyPOA3rRyRlS0LEWKpF6NKtPtZS7iaQu5Ma0kt/OXSpCcbcKCg7vL/Bv2RWu2vfwTtBI/QIDAQAB"
    

Problems

  1. Dkim-filter not signing messages.

    Solution: This most often means an error in the domain name. The documentation for dkim-filter often says "domain name" when it actually means "Fully-qualified domain name (FQDN)". If you put just your domain name (e.g., example.com) instead of your FQDN (e.g., diarrhea.example.com) in these files, it won't sign the messages.

    Other common problems are putting your domain name in your Internal-Hosts file instead of your hostname-domain name combination, and having a mismatch between your DNS entry and the config files.

  2. Socket in use.

    If it says "socket in use" or something to that effect, it means you already have some version of dkim running.

  3. Milter (dkim-filter): error connecting to filter: Connection refused by localhost Milter (dkim-filter): to error state

    Dkim-filter is not running.

  4. Rejecting config options.

    Watch out for version 2.5.0. The dkim-filter binary was moved from /usr/bin to /usr/sbin. If you haven't updated your startup scripts, the wrong version will start.

  5. SSL error:04075075:rsa routines:RSA_sign:unknown algorithm type

    Openssl is not handling SHA256 correctly. Use SHA1 instead (see dkim.conf above).

  6. Dkim-filter not running.

    Make sure all files needed by dkim-filter are readable by the dkim user and all paths leading to the executable and its config files are traversable.

Here is a typical outgoing message that has been signed with DKIM. Because sendmail adds these headers after the email client (in this case, pine) is through with it, the DKIM headers only show up in the received message, not the "sent-mail" file.

From root at host1.my_domain_name.com Sat Mar 15 16:14:50 2008
X-Spam-Checker-Version: SpamAssassin 3.1.4 (2006-07-25) on 
     host1.my_domain_name.com
X-Spam-Level: 
X-Spam-Status: No, score=-4.4 required=1.6 tests=ALL_TRUSTED,BAYES_00,
     SPF_HELO_PASS autolearn=ham version=3.1.4
Received: from host1.my_domain_name.com (localhost [127.0.0.1])
     by host1.my_domain_name.com (8.13.6/8.13.6) with ESMTP id m2FKEjXQ013043
     for <tjnelson at host1.my_domain_name.com> Sat, 15 Mar 2008 16:14:50 -0400
X-DKIM: Sendmail DKIM Filter v2.5.0 host1.my_domain_name.com m2FKEjXQ013043
DKIM-Signature: v=1; a=rsa-sha1; c=simple/simple; d=host1.my_domain_name.com;
     s=mail; t=1205612090; bh=uoq1oCgLlTqpdDX/iUbLy7J1Wic=; h=Date:From:
      To:Subject:Message-ID:MIME-Version:Content-Type; b=y4chS8QQT6u4s0E
     yCdfUw7TBRqW3y9tk4rZgE8c9pkGJOMbzDwJ5D3aXgAnZY6D2A1GA3l+5tuFy5Kw/+3
     QYEunD7oKyO9Z0MsVVl5Ywr35EhM5u/u10BrPshkplXWpON0LPQl8KLyVtJFTgVrmNp
     YmyGAR6Co5hUXpQE4zFOK4=
Received: from localhost (root at localhost)
     by host1.my_domain_name.com (8.13.6/8.13.6/Submit) with ESMTP id m2FKEjNi013040
     for <tjnelson at host1.my_domain_name.com> Sat, 15 Mar 2008 16:14:45 -0400
Date: Sat, 15 Mar 2008 16:14:45 -0400 (EDT)
From: root <root at host1.my_domain_name.com>
To: "Your Name Here" <your_name at host1.my_domain_name.com>
Subject: test106
Message-ID: <Pine.LNX.4.58.0803151614400.13039 at host1.my_domain_name.com>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
ΨΩd   ʕ▽王  ∠ηᚆ ႶθΨ

Back