Home > Server Admin > DKIM and DomainKeys for qmail

DKIM and DomainKeys for qmail

March 19th, 2009

DomainKeys and its successor DomainKeys Identified Mail (DKIM) are technologies that allow organizations to take responsibility for a message. This is done by cryptographically signing an email as it leaves an organization in route to its destination. The signature can be verified using the DNS system to establish trust. In theory the technologies help cut down on spam by proving a message originated from the domain it says it does.

Support for DomainKeys in qmail has existed for a while thanks to a patch by Russel Nelson. Kyle Wheeler created a set of wrapper scripts that can be used to provide support for DKIM and DomainKeys. Mihai Secasiu has some wrapper scripts similar to Kyle’s that provide support for DKIM via the libdkim library instead of Perl’s Mail::DKIM module.

The current methods take different approaches to implement DKIM and DomainKeys. The DomainKeys patch creates a single program, qmail-dk that is called before qmail-queue. This program signs or verifies all incoming messages (that may later become outbound) based on the existence of the DKSIGN and DKVERIFY variables. The DKIM wrapper scripts wrap qmail-remote to sign messages and wrap qmail-queue (or qmail-dk) to verify incoming messages. This can be easier understood by looking at the qmail big picture.

I tend to agree with separate programs for signing outbound messages and verifying inbound messages as this allows signing all outbound messages, even those (such as NDRs) that never pass through qmail-queue. I also prefer patching qmail as it tends to be a little easier and requires less configuration after qmail is installed.

In this post I will show you how to patch qmail to support DKIM as well as DomainKeys. My qmail DKIM/DomainKeys patch uses neither Russel Nelson’s DomainKeys patch nor Kyle Wheeler’s DKIM/DomainKey wrappers, but borrows ideas from both. My patch uses the libdomainkeys and libdkim libraries to do the actual signing and verifying. Rather than creating two new programs, I patch qmail-smtpd (for verifying) and qmail-remote (for signing) directly.

I’ll do my best to provide step by step instructions for patching and installing for you non-Gentoo users, but in my next post I’ll share my ebuild which does it all for you.


1. Install libdomainkeys

The libdomainkeys library is used to sign and verify DomainKeys signatures.

$ wget http://downloads.sourceforge.net/domainkeys/libdomainkeys-0.69.tar.gz
$ tar -xzf libdomainkeys-0.69.tar.gz
$ cd libdomainkeys-0.69
$ make
(If you get errors during make, edit the Makefile and add -lresolv to the end of the LIBS line)
$ sudo install -m 644 libdomainkeys.a /usr/local/lib
$ sudo install -m 644 domainkeys.h dktrace.h /usr/local/include
$ sudo install -m 755 dknewkey /usr/local/bin
$ cd ..


2. Install libdkim

The libdkim library is used to sign and verify DKIM signatures. You’ll need g++ to compile this on your system. The library claims to be portable, but I needed to patch it to get it to compile on my Gentoo box. I’ve also included a (slightly modified) patch from Mihai Secasiu that makes working with libdkimtest much easier.

$ wget http://downloads.sourceforge.net/libdkim/libdkim-1.0.19.zip
$ wget http://www.bltweb.net/qmail/libdkim-1.0.19-linux.patch
$ wget http://www.bltweb.net/qmail/libdkim-1.0.19-extra-options.patch
$ unzip libdkim-1.0.19.zip
$ cd libdkim/src
$ patch -p2 < ../../libdkim-1.0.19-linux.patch
$ patch -p2 < ../../libdkim-1.0.19-extra-options.patch
$ make
$ sudo make install
$ cd ../..


3. Patch and install qmail

I’m currently using John Simpson’s qmail Combined Patch Set for my qmail installation. The instructions below highlight how to apply my DKIM/DomainKeys patch on top of John’s combined patch. I’d highly recommend checking out John’s combined patch as it is about as close as you can get to an actively maintained qmail.

I’m not attempting to describe or document John’s patch in anyway in this post, as John runs an excellent site about qmail (qmail.jms1.net) that contains far more information than is contained here. Do not attempt to proceed without reading through John’s documentation as well as the rest of this post.

$ wget http://cr.yp.to/software/qmail-1.03.tar.gz
$ wget http://qmail.jms1.net/patches/qmail-1.03-jms1.7.08.patch
$ wget http://www.bltweb.net/qmail/qmail-1.03-jms1.7.08-dkim-r1.patch
$ tar -xzf qmail-1.03.tar.gz
$ mv qmail-1.03 qmail-1.03-jms1.7.08
$ cd qmail-1.03-jms1.7.08
$ patch < ../qmail-1.03-jms1.7.08.patch
$ patch -p1 < ../qmail-1.03-jms1.7.08-dkim-r1.patch
$ sed -ie '1s/$/ -DDKIM/' conf-cc
$ make
$ make man
$ sudo make setup check
$ cd ..


4. Configure DKIM/DomainKeys signing

Signing is done by qmail-remote and is controlled by the dksign control file. Signatures are created using a private key on your system, and verified by a public key stored in the DNS for the email domain.

Generate keys

Before you can sign an email, you must create at least one public/private key pair. You should create key pairs for every domain you wish to sign. To create keys for example.com:

# mkdir -p /etc/domainkeys/example.com
# cd /etc/domainkeys/example.com
# dknewkey default 1024 > default.pub
# chown -R root:root /etc/domainkeys
# chmod 640 /etc/domainkeys/example.com/default
# chown root:qmail /etc/domainkeys/example.com/default

It is very important that the default file be readable only by root and the group which qmailr (the qmail-remote user) belongs to. This is the private key used for signing messages and, if compromised, would allow others to sign messages as your domain.

Now add a TXT entry to the DNS for default._domainkey.example.com containing the quoted part in the /etc/domainkeys/example.com/default.pub. NOTE: You normally want to include the quotes!

Configure control files

Create a file /var/qmail/control/dksign containing one line:

/etc/domainkeys/%/default

The % will be replaced with the domain name in the From: header (or the Sender: header if it exists). If no file exists for the given domain, parent domains will be tried. For example if the message is from foo@bar.example.com, /etc/domainkeys/bar.example.com/default will be tested first. If the file does not exist, /etc/domainkeys/example.com/default will be tested. If no key can be found, the message will not be signed. If a key exists, but cannot be read or contains invalid data, the message will not be sent and will remain in the queue until the problem is fixed.

If you do not create the /var/qmail/control/dksign file, no messages will be signed.

Test outbound signing

Now that DKIM/DomainKeys signing is configured, you can test it by sending an email to sa-test (at) sendmail dot net. This reflector will reply (within seconds) to the envelope sender with a status of the DomainKeys and DKIM signatures.

If you experience problems, consult the qmail-remote man page or post a comment below and I’ll try to help.


5. Configure DKIM/DomainKeys verification

Verification is performed by qmail-smtpd and is controlled by the DKVERIFY environment variable. Messages are only verified if DKVERIFY is set and RELAYCLIENT is not set. You may control which IP addresses are verified using the tcpserver access file (sometimes stored in /etc/tcprules.d/tcp.qmail-smtp).

When verifying a message, the contents of DKVERIFY are checked against the status of the DomainKeys and DKIM results. Each test result is represented by a letter. DKVERIFY should contain a series of letters for DomainKeys results, a comma, and then a series of letters for the DKIM results. If the letter is uppercase, the message will be rejected (hard error). If the letter is lowercase, the message will be deferred (soft error). The DKVERIFY variable can be set but empty, in which case messages will be verified and an Authentication-Results: header will be added but all messages will be accepted regardless of status.

The letters for DomainKeys results are:

Code Status Description
A OK The message contained a signature which correctly matched the contents of the message.
B BADSIG The message contained a signature which DID NOT correctly match the contents of the message. The signature may be forged, or the content may have been changed after the original server applied the signature.
C NOSIG The message did not contain a DomainKey-Signature header, or contained one which was missing a required field, or had a signature header without a “From:” header.
D NOKEY The public key needed to verify the signature does not exist (i.e. the authoritative DNS server for the domain says that the TXT record which should contain the key does not exist.)
E BADKEY The public key which was found in DNS is not usable.
F CANTVRFY The public key needed to verify the signature cannot be found, because the DNS server which should have the key is not responding, or returned a temporary error condition. The domainkeys specification says that the server SHOULD treat this as a soft error, telling the client to try their delivery again at some point in the future.
G SYNTAX The message is not in the proper format. This could be an improperly formatted email address, a duplicate “From:” header in the message, or any number of things which “confuse” the program.
H NORESOURCE Out of memory. The domainkeys specification says that the server SHOULD treat this as a soft error, telling the client to try their delivery again at some point in the future.
I ARGS Arguments are not usable
J REVOKED The key which was used to generate the signature has been revoked.
K INTERNAL There was an internal error in the libdomainkeys library

The letters for the DKIM results are:

Code Status Description
A OK The message contained a signature which correctly matched the contents of the message.
B FAIL The message failed verification
C BAD_SYNTAX The DKIM-Signature header could not be parsed or had bad tags/values
D SIG BAD RSA verify failed
E SIG BAD (testing) RSA verify failed but testing
F SIG EXPIRED Signature is expired (x= is old)
G SELECTOR INVALID Selector doesn’t parse or contains invalid values
H SELECTOR MISMATCH Selector granularity doesn’t match
I SELECTOR REVOKED The selector was revoked (p= is empty)
J DOMAIN TOO LONG The domain name is too long to request
K DNS TEMP FAIL Temporary DNS error requesting public key
L DNS PERM FAIL Permanent DNS error requestion public key
M PUBLIC KEY INVALID Public key isn’t valid or can’t be parsed
N NO SIG The message contains no DKIM signatures
O NO VALID SIG The message contains no valid signatures
P BAD BODY HASH The message body doesn’t verify
Q ALGORITHM MISMATCH The selector (h=) doesn’t match signature (a=)
R STAT INCOMPAT Incompatible v=

I recommend a DKVERIFY value of DEGIJKfh,CGHIJMQRkl. This will only reject improperly formatted messages. Messages that don’t verify will still be allowed. I would advise against rejecting messages that don’t verify as there are still some problems with DomainKeys and DKIM (such as mailing lists). Rather than rejecting bad signatures, incorporate the Authentication-Results header into your broader spam prevention strategy.

The Authentication-Results header

All messages received by qmail-smtpd when DKVERIFY is set will add an Authentication-Results header to the incoming message. This header conforms to the IETF internet draft. Here’s an example from one of my emails:

Authentication-Results: bltweb.net; domainkeys=pass (ok); dkim=pass (ok)


6. Examples

Here are some examples to help you configure your box. Anything that normally should be private is made up.

Keys

For my bltweb.net domain name, here’s what my keys look like (these are not the actual keys installed on my system, those are private):

$ ls -l /etc/domainkeys/bltweb.net
total 8.0K
-rw-r----- 1 root qmail 887 Mar 4 18:49 default
-rw-r--r-- 1 root root  254 Mar 4 18:49 default.pub

$ cat /etc/domainkeys/bltweb.net/default.pub
default._domainkey IN TXT “k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDbFnVeFZdlud6/xvLoMt2/g9qrQzZjg6mopp4IYgPwNxRfQTsvYJo4dxP/aIt5UcL1YWtEnOm6/VL+wzj33WvVGL8GWdJDcUWGpCOysWuKasH/sXCaxoZSFMNM02K5pOgzaIVinWZNLIv+yaDSnBC3zb35HoQOnU4KLySECWPRuQIDAQAB”

$ sudo cat /etc/domainkeys/bltweb.net/default
—–BEGIN RSA PRIVATE KEY—–
MIICXAIBAAKBgQDbFnVeFZdlud6/xvLoMt2/g9qrQzZjg6mopp4IYgPwNxRfQTsv
YJo4dxP/aIt5UcL1YWtEnOm6/VL+wzj33WvVGL8GWdJDcUWGpCOysWuKasH/sXCa
xoZSFMNM02K5pOgzaIVinWZNLIv+yaDSnBC3zb35HoQOnU4KLySECWPRuQIDAQAB
AoGAXuZniI2JuwK8Pg4LghEmhKK0waKnmIubnfYuVis+0XrKVEiJPoh1xSevfd7n
K3IDJQ9By8K8a8b3gGtH7fX3ktWWFNz++DpewvWzFksC++7rhZoarBC1puWxVNYI
M4xdqEtKXHIzaj3nRHM76RBD5htqa2hZkIDqfK7vDVZUkEECQQD0C5pmMGaBjO1K
bC0hs8dMogxsrnwooIiHg1FO0WhOXGxKYuQGxXjR/fNz8gUyeicCPB3/piKaucGT
OY1X0b9FAkEA5dHhTQTnkMD0pLow6yXTehy8NWzmIl9/EeIQu9HoXVpIGePy4Mrr
ydJzaisQ+RJ8dO5C+1PeR89IRYdeGS/l5QJBAKHRG8SMbTuTdTe2uMozCYA/pttd
asgJgd3Q7dXENlRXJhrArY/r2ivrJkUIAfgxVLI/qGh+AU30w2zaaWUEl70CQEe7
wv8vULg2AiaIl0xOejvbTEPAwfRoqlkCnwaA9m5tB6RNKjpQHFjaf3vcBWg5BO/a
jr2z5+WyJXTOU+i4sqECQC/lZY/0/cgEyyD0UL+oqYrVmlIm5Sc9Pnsu1fIRsfgC
SnHS8/eTTUxNERGIYso4+wVFHR82oR8hucVYa8iY7CM=
—–END RSA PRIVATE KEY—–
Signing Configuration

To sign emails for all domains for which I have a key in /etc/domainkeys, I set the control/dksign configuration file:

$ ls -l /var/qmail/control/dksign
-rw-r--r-- 1 root root 31 Mar 17 14:02 /var/qmail/control/dksign

$ cat /var/qmail/control/dksign
/etc/domainkeys/%/default
Verify Configuration

Here’s an example of my /etc/tcprules.d/tcp.qmail-smtp file. Make sure you regenerate the cdb file after editing your tcp.qmail-smtp file!

# Connections from localhost are allowed to relay
127.0.0.1:allow,RELAYCLIENT="",RBLSMTPD=""

# Everyone else can’t relay unless they auth
# All signed mail is allowed, even if it’s bad, but still prepend the
# Authentication-Results header
:allow,DKVERIFY="",AUTH_UNSET_DKVERIFY=""

# Or if I want to use the recommend DKIM settings, comment out the line
# above and use
# :allow,DKVERIFY="DEGIJKfh,CGHIJMQRkl",AUTH_UNSET_DKVERIFY=""


7. Finished

That’s it. You should now have a qmail installation capable of signing and verifying messages. More information is contained in the qmail-smtpd and qmail-remote man pages.

If you have any comments or find any bugs, please feel free to post a comment below.

Server Admin , , , ,

  1. March 19th, 2009 at 02:43 | #1

    Nice post. One added benefit of using these patches instead of wrapper scripts is that the signing and verification are much faster and consume less resources.

  2. March 19th, 2009 at 08:49 | #2

    One minor correction: my wrapper scripts *DO* handle both DomainKeys and DKIM signature generation and verification.

  3. March 19th, 2009 at 10:55 | #3

    @Kyle Wheeler
    Sorry Kyle, I remembered your scripts wrong. I’ve updated my post to reflect that your scripts do both DKIM and DomainKeys.

  4. March 19th, 2009 at 14:07 | #4

    nice write-up… or to quote coach zee, “good jorb.”

    once i get some time to try them on my own server, i plan to change my web site to refer people here.

  5. Me
    April 30th, 2009 at 03:44 | #5

    7.07 and 7.08 unable to compile them:
    ./compile qmail-smtpd.c
    qmail-smtpd.c: In function ‘blastdk’:
    qmail-smtpd.c:1289: error: too few arguments to function ‘DKIMVerifyResults’
    qmail-smtpd.c: In function ‘main’:
    qmail-smtpd.c:1940: warning: assignment makes pointer from integer without a cast
    qmail-smtpd.c:1941: warning: comparison between pointer and integer
    qmail-smtpd.c:1881: warning: return type of ‘main’ is not ‘int’
    make: *** [qmail-smtpd.o] Error 1

  6. Me
    April 30th, 2009 at 03:52 | #6

    ups, my mistake. Work fine, i just have two different versions of the dkim.h file. Sry again.

  7. Me again
    May 2nd, 2009 at 06:04 | #7

    Follow patch cause qmail-smtpd to exit with status 11 when is used with simscan, and if is used without simscan does not work does not add line Authentication-Results. Here is few parts of logs.

    with simscan and options from run script
    DKVERIFY=DEGIJKfh,CGHIJMQRkl
    QMAILQUEUE=”$VQ/bin/simscan”
    NOP0FCHECK=1
    SIMSCAN_DEBUG=2

    result is:

    @4000000049fc28310d9b834c tcpserver: end 3856 status 11
    @4000000049fc28310d9b8f04 tcpserver: status: 0/30
    @4000000049fc28310d9e3a9c simscan: no envelope information, deferred exit
    @4000000049fc28310da03284 simscan: exit error code: 54
    @4000000049fc28310da2229c 3856 > [EOF]

    without simscan and option in tcp.smtp.cdb
    127.0.0.1:allow,RBLSMTPD=””,RELAYCLIENT=””
    =:allow
    :allow,RBLSMTPD=”-Blocked – Reverse DNS queries for your IP fail. You cannot send me mail.”,DKVERIFY=”DEGIJKfh,CGHIJMQRkl”

    result is: mail is passed but The Authentication-Results header is not added and message probably is not verify.

    # ls -la /etc/domainkeys/domain.com/default
    -rw-r—– 1 root qmail 887 2009-05-01 00:23 /etc/domainkeys/stzbg.com/default

  8. May 2nd, 2009 at 11:45 | #8

    @Me again
    Hmm… Status 11 usually indicates a seg fault.

    Just to cover the basics, without simscan, can you check:

    1) After step 3 in my post, check that the conf-cc file in the qmail-1.03-jms1.7.08 directory has -DDKIM somewhere on the first line.

    2) Are you testing this from an IP address other than 127.0.0.1? In the example tcp.smtp.cdb file you provided, the Authentication-Results header will only be added to mail received from hosts other than 127.0.0.1.

    3) You are not setting RELAYCLIENT and DKVERIFY at the same time. My patch won’t do DKIM verification (or add the Authentication-Results header) when RELAYCLIENT is set.

    I don’t currently run simscan, but I’ll try to configure it to make sure my patch doesn’t cause problems (it shouldn’t). In the meantime let me know if you are able to get DKVERIFY to work without simscan.

  9. Me
    May 6th, 2009 at 02:32 | #9

    1) root@backup:~# cat /usr/local/src/qmail-1.03-jms1.7.08/conf-cc
    cc -O2 -DTLS -DEXTERNAL_TODO -I/usr/local/ssl/include -I/usr/kerberos/include -DDKIM

    This will be used to compile .c files.

    2) and 3) Yep i tested with both cases even with:
    127.0.0.1:allow,RBLSMTPD=””,RELAYCLIENT=””,DKVERIFY=”DEGIJKfh,CGHIJMQRkl”
    =:allow,RELAYCLIENT=””,DKVERIFY=”DEGIJKfh,CGHIJMQRkl”
    :allow,RBLSMTPD=”-Blocked – Reverse DNS queries for your IP fail. You cannot send me mail.”,RELAYCLIENT=””,DKVERIFY=”DEGIJKfh,CGHIJMQRkl”

    and no any effect (i mean line is not added Authentication-Results.)

    And it’s will be good if you add also some examples in your article.

  10. May 6th, 2009 at 09:58 | #10

    @Me
    The Authentication-Results header is never added (and DKIM/Domainkeys verification is not performed) if the RELAYCLIENT variable is set. The idea behind this is that if you are relaying mail to another host, you probably don’t want to do DKIM verification. The places where you do want to do DKIM verification is when anonymously receiving mail from the internet, a situation where you certainly do not want to relay!

    In your latest example, you’ve set RELAYCLIENT for all hosts and thus DKVERIFY is being ignored. Try temporarily removing RELAYCLIENT and see if it works.

    I also added an examples section.

  11. Mauro
    May 11th, 2009 at 08:29 | #11

    Hi,
    I have a strange problem:
    DKIM works correctly but DomainKey verification failed:
    Authentication System: DomainKeys Identified Mail
    Result: DKIM signature confirmed GOOD
    Description: Signature verified, message arrived intact
    Reporting host: sendmail.net
    More information: http://mipassoc.org/dkim/
    Sendmail milter: https://sourceforge.net/projects/dkim-milter/

    Authentication System: Domain Keys
    Result: DK signature confirmed BAD
    Description: Signature verification failed, message may have been
    tampered with or corrupted
    Reporting host: sendmail.net
    More information: http://antispam.yahoo.com/domainkeys
    Sendmail milter: https://sourceforge.net/projects/domainkeys-milter/

    Any idea?

    Thanks
    Regards

  12. May 11th, 2009 at 10:24 | #12

    @Mauro
    It looks like the sa-test@sendmail reflector is marking some email as failing DomainKeys. It is giving me the same results for mail sent via Thunderbird. This may be because of the multiple Received headers, or something else. I’m still trying to figure that out.

    However: The mail you sent me verifies as having a correct DomainKeys signature. I did some limited testing and sending the same email to the sa-test reflector and a Yahoo account results in the sa-test reflector saying DomainKeys is bad, and Yahoo saying it is good. I hate to say the problem is with the reflector, as the reflector is suppose to be 100% correct, but right now it seems isolated to the sendmail reflector. I will try to do some more research and see what is causing the BAD statuses.

    If I send mail to the sa-test reflector from a command line, it returns GOOD.

  13. Mauro
    May 12th, 2009 at 02:03 | #13

    @Brandon
    Hi Brandon,
    thank you very much.
    I tried also with gmail and it works correctly.

    Thanks
    Regards

  14. per
    May 17th, 2009 at 02:12 | #14

    what charachter are you using after the ‘=’ in your ‘examples’?

    :allow,DKVERIFY=””,AUTH_UNSET_DKVERIFY=””

    tnx,
    per.

  15. May 17th, 2009 at 14:14 | #15

    @per
    It’s just a regular double-quote, " WordPress (the blogging software I use) changes it to some other character automatically unless I remember to use &quot;. I’ve fixed it in the post above.

  16. per
    May 20th, 2009 at 03:02 | #16

    /etc/tcp/smtp
    127.0.0.:allow,RELAYCLIENT=””,QMAILQUEUE=”/var/qmail/bin/simscan”,NOP0FCHECK=”1″
    192.168.1.:allow,RELAYCLIENT=””,QMAILQUEUE=”/var/qmail/bin/simscan”,NOP0FCHECK=”1″
    :allow,DKVERIFY=”DEGIJKfh,CGHIJMQRkl”,AUTH_UNSET_DKVERIFY=””

    but i’ve got the …

    tcpserver: end 6654 status 11
    tcpserver: status: 0/30

    i’m using ‘jms’ qmail-smtpd run-file:
    http://qmail.jms1.net/scripts/service-qmail-smtpd-run :: are there anything particular should be taking note off i.e. ‘make domainkeys command (if needed)’?

  17. May 20th, 2009 at 11:46 | #17

    @per
    The status 11 is being caused by a bug in my DKIM patch. I’ve fixed the bug and posted an updated patch at http://www.bltweb.net/qmail/qmail-1.03-jms1.7.08-dkim-r1.patch. (I’ve also updated this post to reflect the location of the new patch). Please try using this new DKIM patch.

    Also, just to be clear, my patch is different from the patch used in John’s service-qmail-smtpd-run file. You should not uncomment any of the Domainkeys stuff in John’s run script. The default run script on John’s website works fine.

  18. per
    May 20th, 2009 at 16:46 | #18

    thanks brandon, the new patch(r1) work’s great!

    \per.

  19. xnt
    May 24th, 2009 at 11:56 | #19

    @Brandon
    The Authentication-Results header doesn’t apear in my received mails. I modify configuration of tcp.smtp, delete de RELAYCLIENT on all lines, put your example configuration but doesn’t work.
    The qmail-remote sign the mails who send my server, but qmail-smtpd doesn’t verify the mail DK & DKIM. In my logs doesn’t appear eny error.
    What can I do? (Same situation like @Me – but I don’t receive the “status 11″)

  20. May 24th, 2009 at 18:46 | #20

    @xnt
    Did you compile the new tcp.smtp file (run make in the same directory)? Do you have DKVERIFY=""? How are you testing receiving mail? Are you sending yourself something via a mail client? If so, make sure you are not authenticating when testing.

    If possible, post your tcp.smtp file.

  21. xnt
    May 25th, 2009 at 00:40 | #21

    @Brandon

    1. I have compiled the tcp.smtp with tcprules command /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp
    127.0.0.1:allow,RELAYCLIENT=””,RBLSMTPD=””
    :allow,DKVERIFY=””,AUTH_UNSET_DKVERIFY=””

  22. xnt
    May 25th, 2009 at 00:51 | #22

    @Brandon
    I send mails from yahoo and other mail servers from webmail for testing.
    May be the permission my problem? Can you paste your qmail-smtpd run-file?

  23. May 25th, 2009 at 01:27 | #23

    @xnt
    I have tested John’s run file with no modifications and it works fine.

    I’m not sure why verification is not working. For verification to work:
    1) You must have compiled with the -DDKIM switch in conf-cc file (my step 3)
    2) qmail-smtpd must receive mail from anonymous remote mail servers (aka running on port 25)
    3) The DKVERIFY environment variable must be set (it can be empty but it must be set)
    4) The RELAYCLIENT environment variable must not be set.

    I am not sure where to go from here. What is the full command listed when you run ps u -C tcpserver? For example, mine is:

    /usr/bin/tcpserver -p -v -R -x /etc/tcprules.d/tcp.qmail-smtp.cdb -c 30 -u 201 -g 200 0 smtp /var/qmail/bin/qmail-smtpd keystone.bltweb.net /usr/bin/checkpassword-pam -s qmail /bin/true
    
  24. xnt
    May 25th, 2009 at 01:49 | #24

    @Brandon
    1) The -DDKIM was set at compilation
    2) I send mail from yahoo and others
    3) DKVERIFY is set
    4) RELAYCLIENT is not set
    qmail-smtpd run script

    exec /usr/local/bin/envuidgid qmaild /usr/local/bin/tcpserver -RHPv -llocalhost -x /etc/tcp.smtp.cdb 0 smtp /var/qmail/spamdyke/spamdyke -f /var/qmail/spamdyke/spamdyke.conf /var/qmail/bin/qmail-smtpd mydomain.com /bin/checkpassword /bin/true

  25. xnt
    May 25th, 2009 at 14:38 | #25

    @Brandon
    Do you have another ideea? I tried everything and doesn’t work.
    How can I debug what qmail-smtp does?

  26. May 25th, 2009 at 21:40 | #26

    I would remove spamdyke temporarily to see if that has something to do with it. I have not tested with spamdyke. If I have time this week I’ll install it and see if I experience the same behavior as you.

    If you are familiar with SMTP and GDB you can try attaching GDB to qmail-smtpd. You’d need to recompile with GDB support (add -ggdb to conf-cc and conf-ld). You could then have a SMTP session over stdin/stdout by running qmail-smtpd. DKIM verification happens in qmail-smtpd.c in the blastdk function, around line 1294 in the qmail-smtpd.c file.

  27. xnt
    May 26th, 2009 at 04:05 | #27

    @Brandon
    Thanks for help man. The spamdyke is cause of problem. I disable the spamdyke and all works! Please install spamdyke and notify me if you have the same situation. I will search how spamdyke interfere with this patch, hope to find something.

  28. xnt
    May 26th, 2009 at 04:10 | #28

    @Brandon
    I have another question. Your mail to yahoo enter in bulk or in inbox?
    I have instaled dk & dkim, i have spf record to my dns-server, i’m not listed on any rbl, but my mails enter in bulk. I have 4 MX (2 have reverse and 2 not) Is the reverse dns essential to yahoo? How can resolve this problem?

  29. xnt
    May 26th, 2009 at 10:43 | #29

    @Brandon
    I review my spamdyke configuration and I find that spamdyke relay control was activated. I disable relay control and all work great.
    I wait for your response about yahoo, or from another user who see my question.

  30. June 19th, 2009 at 20:13 | #30

    Hi,

    Even if i’m quite new to qmail world I have some problems with DKIM patch
    So::

    libdkim 1.0.19 with patches is installed

    cd qmail-1.03
    patch < ../qmail-1.03-jms1.7.08.patch
    patch -p1 < ../qmail-1.03-jms1.7.08-dkim-r1.patch
    sed -ie '1s/$/ -DDKIM/' conf-cc
    make
    make man
    make setup check

    content of /var/qmail/dksign
    /etc/domainkeys/%/default

    ls -la /etc/domainkeys/medianetork.ro

    drwxr-x— 2 root nofiles 4096 2009-06-20 02:02 .
    drwxr-x— 4 root nofiles 4096 2009-01-14 00:46 ..
    -rw-r–r– 1 root nofiles 887 2009-06-20 02:02 default
    -rw-r–r– 1 root root 254 2009-06-20 02:02 default.pub

    so, when i send a test message to: sa-test@sendmail.net
    i get

    Authentication System: DomainKeys Identified Mail
    Result: (no result present)
    Reporting host:
    More information: http://mipassoc.org/dkim/
    Sendmail milter: https://sourceforge.net/projects/dkim-milter/

    Authentication System: Domain Keys
    Result: DK signature confirmed BAD
    Description: Signature verification failed, message may have been tampered with or corrupted
    Reporting host: sendmail.net
    More information: http://antispam.yahoo.com/domainkeys
    Sendmail milter: https://sourceforge.net/projects/domainkeys-milter/

    Authentication System: Sender ID
    Result: SID data confirmed GOOD
    Description: Sending host is authorized for sending domain
    Reporting host: sendmail.net
    More information: http://www.microsoft.com/senderid
    Sendmail milter: https://sourceforge.net/projects/sid-milter/

    Authentication System: Sender Permitted From (SPF)
    Result: SPF data confirmed GOOD
    Description: Sending host is authorized for sending domain
    Reporting host: sendmail.net
    More information: http://spf.pobox.com/

    So… where do i get wrong ???

  31. June 21st, 2009 at 18:11 | #31

    @Florin
    Not having a DKIM signature at all usually indicates you are running John’s old patch and not my patch. In my patch it is not possible to sign with DomainKeys exclusively.

    Check for an old qmail-dk program on your system and delete it. Make sure QMAILQUEUE does not point to qmail-dk.

  32. wee
    July 4th, 2009 at 11:44 | #32

    Hello Brandon,

    I’m facing a similar issue as Florin. The Problem is that when I send an emty test message that contains a “new line” to sa-test@sendmail.net I get “DKIM signature confirmed BAD”.

    Eg :

    root@mailbox:~# mail -s test sa-test@sendmail.net

    .
    EOT —–> Returns “DKIM signature confirmed BAD”

    root@mailbox:~# mail -s test sa-test@sendmail.net
    .
    EOT —–> Returns “DKIM signature confirmed GOOD”

    root@mailbox:~# mail -s test sa-test@sendmail.net
    test
    .
    EOT —–> Returns “DKIM signature confirmed GOOD”

    So I made some tests to other domains with messages containing only “new line”. On gmail.com the dkim signature result is “pass”.

    On the other hand on yahoo.com I get “domainkeys=pass (ok); from=mydomain.com; dkim=permerror (bad sig)”

    I have other postfix e-mail servers in administration where I use :

    dkim-milter ( http://sourceforge.net/projects/dkim-milter/ )

    dk-milter ( http://sourceforge.net/projects/dk-milter/ )

    sid-milter ( http://sourceforge.net/projects/sid-milter/ )

    which I think it’s exactly what sa-test@sendmail.net uses for dkim/dk/sid verification and signing.

    So I sent a “new line” message to one of my postfix servers and I got the following :

    Authentication-Results: mail.postfixmachine.org; sender-id=pass header.from=root@mailbox.org; spf=pass smtp.mfrom=root@mailbox.org
    Authentication-Results: mail.postfixmachine.org; domainkeys=pass header.from=root@mailbox.org
    Authentication-Results: mail.postfixmachine.org; dkim=fail (verification failed)

    I also made tests from the postfixmachine. I have sent “new line” messages to sa-test@sendmail.com , gmail.com , yahoo.com and the results where “pass” on every domain.

    I don’t think it has any importance, but the mail client I used to send the test messages is “Heirloom mailx 12.3 7/15/07″

  33. July 5th, 2009 at 22:33 | #33

    @wee
    Interesting, I hadn’t seen DKIM fail like this before, but I was able to reproduce this behaviour on my computer with the sa-test reflector.

    My DKIM patch signs messages using a relaxed header and body canonicalization. Section 3.4.4 of the DKIM spec specifies that empty lines at the end of a message should be ignored when signing and verifying messages.

    In the case of a message containing only empty lines, the libdkim library my patch uses signs/verifies the message as if there was no body at all. The library that the dkim-milter uses seems to sign/verify the message as if the body contains a single CRLF. A question about this was actually recently posted to the dkim-milter mailing list.

    From what I read of the DKIM spec, I think the libdkim library my patch uses is correct and the library the dkim-milter uses is incorrect. Have any thoughts on this?

    If you have DKIM verification working on your qmail server, try sending a message from YAHOO webmail containing nothing but two empty lines. You’ll see qmail indicates a bad signature. This is because Yahoo signed the message as if it contained a single CRLF in the body, where my patch verified the message as if the body was empty.

    Perhaps I should host a DKIM/DomainKeys reflector rather than suggest using the sa-test reflector. While this wouldn’t solve the problem, it may make the initial setup of my patch a little easier.

  34. wee
    July 8th, 2009 at 12:43 | #34

    Hello Brandon,

    I have sent several mails from yahoo.com and gmail.com ( with one or two empty lines ), with simscan/clamav/spamassasin on/off and I always got the result “pass” :

    Authentication-Results: localhost; domainkeys=pass (ok); dkim=pass (ok)

    I made the tests using both :

    :~# strings /etc/tcp.smtp.cdb
    +DKVERIFY=DEGIJKfh,CGHIJMQRkl

    and

    :~# strings /etc/tcp.smtp.cdb
    +DKVERIFY=

    As I read the 3.4 Canonicalization section I noticed :

    “To satisfy all requirements, two canonicalization algorithms are defined for each of the header and the body: a “simple” algorithm that tolerates almost no modification and a “relaxed” algorithm that tolerates common modifications such as whitespace replacement and header field line rewrapping.

    A signer MAY specify either algorithm for header or body when signing an email. If no canonicalization algorithm is specified by the signer, the “simple” algorithm defaults for both header and body. Verifiers MUST implement both canonicalization algorithms.”

    I’m not a programmer so I don’t know how exactly you implemented the patch, but could it be possible that the body canonical signing alghoritm doesn’t get specified so yahoo.com defaults to “simple” instead of “relaxed” ?

    Or maybe yahoo.com / dkim-milter simply ignores the body canonical signing alghoritm intentionaly even though is specified ?

    Maybe they do this because of the security vulnerabilitis the “relaxed” alghoritm suffers ? :

    3.4.4 The “relaxed” Body Canonicalization Algorithm :

    INFORMATIVE NOTE: It should be noted that the relaxed body canonicalization algorithm may enable certain types of extremely crude “ASCII Art” attacks where a message may be conveyed by adjusting the spacing between words. If this is a concern, the “simple” body canonicalization algorithm should be used instead.

  35. July 8th, 2009 at 14:06 | #35

    @wee
    My patch signs mail with relaxed canonicalization for both the header and the body. I did this mainly because that is what I saw Yahoo and others doing. I hope to one day extend my patch to allow you to control things like this via a configuration file.

    To view the canonicalization for a DKIM signed email, look for the c=xxx/yyy attribute in the DKIM-Signature header. The part before the slash (xxx) is the header canonicalization, the part after the slash (yyy) is the body canonicalization.

    It’s interesting that messages you sent from the Yahoo webmail client with nothing but two blank lines are passing DKIM verification. I see:
    Authentication-Results: keystone.bltweb.net; domainkeys=pass (ok); dkim=fail (bad sig, testing)
    on mine. Maybe there are some differences in Yahoo’s implementation based on geographic region.

    Ignoring my patch for a while, if I send an email from the Yahoo webmail client (using a yahoo.com email address) to a Gmail email address with exactly two blank lines (and nothing else) in the body, Gmail adds the following header to the message:

    Authentication-Results: mx.google.com; spf=pass (google.com: domain of nospam@yahoo.com designates 98.137.26.170 as permitted sender) smtp.mail=nospam@yahoo.com; dkim=neutral (body hash did not verify) header.i=@yahoo.com

    It’s from these results that I think there is a bug in Yahoo / dkim-milter’s implementation. I do not think Yahoo ignores the canonical setting, as I’m pretty sure I tested both relaxed and simple with Yahoo servers when I was writing my patch.

  36. wee
    July 8th, 2009 at 15:50 | #36

    Hello Brandon,

    Weird, if I send a test mail from Yahoo to Gmail with two empty lines (and nothing else, hit enter button twice and click send) I get :

    Authentication-Results: mx.google.com; spf=pass (google.com: domain of myaccount@yahoo.com designates 68.142.237.93 as permitted sender) smtp.mail=myaccount@yahoo.com; dkim=pass (test mode) header.i=@yahoo.com

    Any ideeas what test mode means ?

    If I send a two lines message from my qmail / postfix boxes to gmail.com I get dkim=pass without “(test mode)”

  37. Brandon
    July 8th, 2009 at 16:10 | #37

    @wee
    “Test mode” just means that the t=y is set in the DKIM DNS entry. For Yahoo:

    $ dig txt s1024._domainkey.yahoo.com
    ; <<>> DiG 9.4.3-P2 <<>> txt s1024._domainkey.yahoo.com
    ;; global options: printcmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10733
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

    ;; QUESTION SECTION:
    ;s1024._domainkey.yahoo.com. IN TXT

    ;; ANSWER SECTION:
    s1024._domainkey.yahoo.com. 62162 IN TXT “k=rsa\; t=y\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDrEee0Ri4Juz+QfiWYui/E9UGSXau/2P8LjnTD8V4Unn+2FAZVGE3kL23bzeoULYv4PeleB3gfm” “JiDJOKU3Ns5L4KJAUUHjFwDebt0NP+sBK0VKeTATL2Yr/S3bT/xhy+1xtj4RkdV7fVxTn56Lb4udUnwuxK4V5b5PdOKj/+XcwIDAQAB\; n=A 1024 bit key\;”

    ;; Query time: 30 msec
    ;; SERVER: 192.168.10.13#53(192.168.10.13)
    ;; WHEN: Wed Jul 8 16:05:01 2009
    ;; MSG SIZE rcvd: 307

    I just sent you a test message from my Yahoo account via mail.yahoo.com. If you get it, you might check how DKIM verified it. Does Yahoo still add advertisements to the bottom of emails? I have a Yahoo Plus account which doesn’t, but it’s possible an advertisement is being added to your messages, thus causing more than two blank lines, and thus a valid signature?

  38. wee
    July 9th, 2009 at 03:40 | #38

    @Brandon

    Hello Brandon,

    I got two blank lines and “dkim=neutral (body hash did not verify) header.i=@yahoo.com”

    I have sent you a reply with the full headers

  39. July 31st, 2009 at 10:02 | #39

    Hi Brandon,
    You have no idea how helpful this tutorial has been for me. No were on the Internet was I able to find a proper tutorial on how to do both DKIM and Domainkeys. I work in an Internet Service Provider company and I had to find a way to sign all my mails so that it won’t go to yahoo’s junk box. I was able to do Domainkeys but got stuck on applying DKIM until I saw your tutorial. Man you are a life saver. I was able to configure it with in minutes. Just one question left, do you know how I will be able to get “250-AUTH LOGIN” when I “ehlo localhost”? SMTP AUTH is a must for me. I had to setup “magicmail-0.8.4-2″ an alternate qmail-smtp software (i think) just so that I can do SMTP AUTH. How can I enable it with out using any out side software?

  40. July 31st, 2009 at 10:15 | #40

    @Gazi Shamim
    If my post worked for you, then you must be using John Simpson’s combined patch. In that case SMTP AUTH is already included in your Qmail install with no need for magicmail.

    See John’s patch details page. Also check out his tutorial on Setting up an SMTP service and helpful information on issues with SSL/TLS and AUTH.

    Essentially you need to provide a checkpassword program with access to your user database (for example checkpassword-pam to authenticate off your system’s PAM modules) as the second argument to the qmail-smtpd binary. This is covered on John’s pages, but you must do a little reading.

    One more note… My DKIM patch only does DKIM verification in qmail-smtpd. DKIM signing is done in qmail-remote. So, technically, if you don’t need DKIM verification (a lot of people don’t), you could continue with your current magicmail replacement for qmail-smtpd and still sign outbound messages with qmail-remote.

  41. Valery
    January 5th, 2010 at 09:28 | #41

    Hi,

    First thanks for sharing your experience with dkim, that is a really complicate think to configure.

    I ve some probleme during the make, I’ve edited the LIBS line like this:
    LIBS=-L. -ldomainkeys -lcrypto -lresolv

    but I still have this message when a do make.

    gcc -DBIND_8_COMPAT -O2 -o dktest dktest.o -L. -ldomainkeys -lcrypto -lresolv `cat dns.lib` `cat socket.lib`
    ./libdomainkeys.a(domainkeys.o): In function `dk_free’:
    domainkeys.o(.text+0×2830): undefined reference to `EVP_MD_CTX_cleanup’
    ./libdomainkeys.a(domainkeys.o): In function `dk_shutdown’:
    domainkeys.o(.text+0xef): undefined reference to `CRYPTO_cleanup_all_ex_data’
    collect2: ld returned 1 exit status
    make: *** [dktest] Erreur 1

    Somebody have an idea?

  42. January 5th, 2010 at 22:07 | #42

    @Valery
    What linux distribution are you using? What version of OpenSSL do you have. If possible. Try upgrading OpenSSL and try the compile again.

  43. January 13th, 2010 at 08:57 | #43

    Hi,
    I get the same error message !
    I’m using the Redhat 7.2 distribution with OpenSSL 0.9.6m.
    My hoster recommends not to install OpenSSL 0.9.7X : http://forum.ovh.com/archive/index.php/t-480.html

    What should I do ?

    • January 13th, 2010 at 09:39 | #44

      I believe libdomainkeys requires at least OpenSSL 0.9.7. I’m currently running 0.9.8l on my system with no problems. If you are unable to to install at least 0.9.7 you may see if someone has a binary package of libdomainkeys for your distribution.

  44. microbix
    February 26th, 2010 at 12:34 | #45

    how can i sign messages for local domains. (/var/qmail/control/locals) ?
    my /etc/tcp/smtp is:
    127.:allow,RELAYCLIENT=””
    :allow,DKVERIFY=”DEGIJKfh,CGHIJMQRkl”,AUTH_UNSET_DKVERIFY=””

    in rest many big tank you

  45. February 26th, 2010 at 12:40 | #46

    @microbix
    My post describes signing messages via qmail-remote and thus, cannot sign messages for local domains.

  46. echomeme
    March 1st, 2010 at 11:02 | #47

    hi,
    I’m on Centos4 and i try to install you solution.
    But (sorry..), i’ve got this error when i try to make the make install of libdkim :

    dkimsign.cpp: In constructor `CDKIMSign::CDKIMSign()’:
    dkimsign.cpp:46: error: `EVP_sha256′ was not declared in this scope

    So, i tried this solution :
    http://patchlog.com/security/qmail-and-dkim/#comment-6199
    ut i got these errors :

    ../libcrypto.a(sha256.o)(.text+0x5af): In function `sha256_block_host_order’:
    : undefined reference to `sha256_block’
    ../libcrypto.a(sha256.o)(.text+0x5c7): In function `sha256_block_data_order’:
    : undefined reference to `sha256_block’

  47. March 1st, 2010 at 11:10 | #48

    @echomeme
    Wish I could be more help, but the solution you posted would be my best guess. I run OpenSSL 0.9.8l on my server.

  48. echomeme
    March 1st, 2010 at 17:25 | #49

    i tried with the last openssl (0.9.8m), it’s the same error.
    dkimsign.cpp: In constructor `CDKIMSign::CDKIMSign()’:
    dkimsign.cpp:46: error: `EVP_sha256′ was not declared in this scope

    And the solution can’t be apply, the file is not the same.
    I thing there’s a another thing to do, but i don’t know, i’m not enought good in cpp.
    I tried to sign my outbound mail since wednesday last week and there’s always a mistake somewhere… Argh…

  49. echomeme
    March 3rd, 2010 at 06:02 | #50

    Hi Brandon,

    Sorry to bored you, i finally install libdkim (lib found here : http://duncanthrax.net/exim-experimental/libdkim-1.0.16-tk.tar.gz with some adaptation for sha256) and the wrapper (found here : http://patchlog.com/security/qmail-and-dkim/) sign well my mail.
    But your method is better.
    I try to install qmail with your patch but ([crazy_mode]AAAHHHH[/crazy_mode]) it give me this error :

    `cat socket.lib` -lssl -lcrypto env.a -ldkim -ldomainkeys
    /usr/bin/ld: cannot find -ldkim
    collect2: ld returned 1 exit status
    make: *** [qmail-remote] Error 1

    I think it’s a little thing but i don’t find a solution.

  50. March 28th, 2010 at 06:18 | #51

    Brother, I would like to thank you for the brilliant code I was so lazy myself to implement it and I was refusing to use the c++ resources founded out there.
    I also would like to ask you if there is a particular environment to sign dkim I managed to make dk signs but I don’t know why dkim is not signing… I’m not using jm1′s patch but yet I’ve imported and merged with not a single flawless line. I will re-read it but I’m pretty sure I didn’t commit any mistakes
    Thanks

Comment pages
1 2 3
  1. July 4th, 2011 at 09:48 | #1
  2. February 17th, 2012 at 03:09 | #2
  3. April 30th, 2013 at 04:13 | #3
  4. March 8th, 2014 at 05:30 | #4