Call us Toll-Free:
1-800-218-1525
Email us

 Sponsors

How to implement DomainKeys from scratch

Michel Nadeau, 08-06-2008
Today we configured a domain for sending DomainKeys-signed emails and wrote a BASH script to send DomainKeys-valid emails. This post explains in details how we achieved it. Normally DomainKeys is implemented in the mail server itself -as a filter- but we needed a standalone solution.

NOTE: this post assumes that you are using a Linux machine and that you are 'root'.

NOTE: all the code posted here is found in the attachment.

DomainKeys in a nutshell

"DomainKeys" creates a domain-level authentication framework for email by using public key technology and the DNS to prove the provenance and contents of an email.

Basically:
* A private/public SSL key is generated;
* DNS TXT records are created with the public key;
* The sent emails are signed using the private key;
* The received emails are verified using the public key.

NOTE: the implementation of DomainKeys requires total control over the domain DNS because you have to create TXT records.

Step 1 - Generating the private/public SSL key

To generate your private/public SSL key, you can use the following BASH script:

genkeys.sh:
#!/bin/sh
# (bof)

# Settings
s="selector"
d="domain.com"

# Cleanup
rm -rf $s.private
rm -rf $s.public
rm -rf $s._domainkey.$d

# Private key
openssl genrsa -out $s.private 768

# Public key
openssl rsa -in $s.private -out $s.public -pubout -outform PEM

# DNS TXT record
echo "k=rsa; p=$(cat $s.public | grep -v "^----" | tr -d "\n");" >$s._domainkey.$d

# (eof)

You have to adjust the "s" (selector) and "d" (domain) variables. The selector can be whatever you want -from "mx" to "apple" to "newyork"- we will use it later to define the DNS TXT record and in the DomainKeys signature.

Now you have 3 files:
* selector.private
* selector.public
* selector._domainkey.domain.com

Obviously, you want to keep the selector.private file in a safe place and do not distribute it.

Step 2 - Creating the DNS TXT records

Now that we have our private/public SSL key, we are ready to create the DNS TXT records.

DomainKeys needs 2 TXT records:
* _domainkey.domain.com - Contains the DomainKeys policy
* selector._domainkey.domain.com - Contains the public key

In our tests, we also had to create the 'domain.com' (no prefix) TXT record, else `dig` wouldn't see the 2 other records. We used a TTL of 60 for quick propagation of the records updates.

For the policy record we used "o=~". You can read more about policies in the RFC. For the public key record, the content is kindly generated by the previous BASH file (genkeys.sh). Just open the selector._domainkey.domain.com file and copy/paste the content. Your TXT records' values should look like this:

domain.com:
whatever

_domainkey.domain.com:
o=~

selector._domainkey.domain.com:
k=rsa; p=MHwwD...QqwIDAQAB;

You can test that these records are working fine by using `dig`:

dig TXT domain.com
dig TXT _domainkey.domain.com
dig TXT selector._domainkey.domain.com

Step 3 - Sending a DomainKeys-signed email

The process of signing a mail using DomainKeys is simple:
* You need the FINAL mail message with headers and body;
* You convert it to DOS format (CRLF line terminations). This is VERY important: if you skip this step your signature will fail all the tests;
* You generate a SSL hash of the whole thing (headers and body);
* You convert the result to Base64;
* You add the "DomainKey-Signature:" and the beginning of the mail.

The format of the "DomainKey-Signature:" header is:

DomainKey-Signature: a=rsa-sha1; q=dns; c=simple;
s=selector; d=domain.com; h=From:To:...;
b=Base64_key

You can refer to the RFC to see the definition of every flag in the signature.

Here is an example mail:

From: [email protected]
To: [email protected]
Subject: Message subject
Date: Wed Aug 6 16:42:28 GMT 2008
Message-ID: <[email protected]>

Message body

The "DomainKey-Signature:" header for this email would be:

DomainKey-Signature: a=rsa-sha1; q=dns; c=simple;
s=selector; d=domain.com; h=From:To:Subject:Date:Message-ID;
b=nweNWqqx...ws0uGm9EGlI

The following BASH script does everything you need:

dk-sign.sh:
#!/bin/sh
# (bof)

# Parameters
selector="selector"
domain="domain.com"
from="[email protected]"
to="[email protected]"
subject="Message subject"
msg="Message body"

# Other settings
[ "$1" != "" ] && to="$1"
file="mail.txt"
date=`date`
id="<`date +%Y%m%d%H%M%S`[email protected]$domain>"

# Temp files
tmp1="tmp.$$.1"
tmp2="tmp.$$.2"

# Replace macros in $file
cat $file | sed s/__TO__/"$to"/g | \
sed s/__FROM__/"$from"/g | \
sed s/__SUBJECT__/"$subject"/g | \
sed s/__MSG__/"$msg"/g | \
sed s/__DATE__/"$date"/g | \
sed s/__ID__/"$id"/g >$tmp1

# Make sure the file is in DOS format
./_bin/todos < $tmp1 > $tmp2

# Generate and add the signature
echo "DomainKey-Signature: a=rsa-sha1; q=dns; c=simple;" >$tmp1
echo " s=$selector; d=$domain; h=From:To:Subject:Date:Message-ID;" >>$tmp1
cat $tmp2 | \
openssl dgst -sign _ssl/dktest.private -sha1 | \
perl -MMIME::Base64 -0777 -ne 'print encode_base64($_)' | \
sed -e '1s/^/b=/' -e 's/^/ /' >>$tmp1
cat < $tmp2 >>$tmp1

echo ""
echo "DK-SIGN"
echo ""
echo "--"
cat $tmp1
echo "--"
echo ""

# Send the mail
./_bin/sendEmail -f $from -t $to -o message-file=$tmp1 -o message-format=raw

echo ""

# Cleanup
rm $tmp1 $tmp2

# (eof)

With this script, you should be able to send valid DomainKeys-signed mails to a DomainKeys test service (see resources).

Step 4 - Using the attachment

In attachment you find dk-sign.zip, which contains:

DK-SIGN/
DK-SIGN/_bin/
DK-SIGN/_bin/sendEmail
DK-SIGN/_bin/todos
DK-SIGN/_ssl/
DK-SIGN/_ssl/_keys_go_here
DK-SIGN/_tools/
DK-SIGN/_tools/dnstest.sh
DK-SIGN/_tools/dnstest_fn.sh
DK-SIGN/_tools/genkeys.sh
DK-SIGN/dk-sign.sh
DK-SIGN/mail.txt

Steps:
1. Adjust and run 'genkeys.sh' and move the 3 generated files to _ssl/
2. Adjust and run 'dk-sign.sh'

You may want to modify 'mail.txt' if the default template isn't fitting your needs.

Resources
* DomainKeys RFC - http://www.ietf.org/rfc/rfc4871.txt
* Wikipedia article - http://en.wikipedia.org/wiki/DomainKeys
* Official Web site - http://domainkeys.sourceforge.net/
* DomainKeys Test #1 - [email protected]
* DomainKeys Test #2 - http://www.mailradar.com/domainkeys/
* DomainKeys Test #3 - http://69.56.15.194/
Attached Files
File Type: zip dk-sign.zip (23.0 KB, 3193 views)

vinh, 01-19-2009
thanks for your info.

Tim, 02-18-2009
Thanks i found this article very helpful. But the link to the attachment is broken. Can someone please fix or email it to me? thx.

raka, 04-17-2009
hi help pls..

when i run dk-sign i have message error like this

Apr 17 17:51:16 mail sendEmail[8712]: ERROR => Received: 554 qmail-dk: Cannot sign message due to invalid message syntax. (#5.3.0)

please help me ..

thanks
Enjoyed this post?

Subscribe Now to receive new posts via Email as soon as they come out.

 Comments
Post your comments












Note: No link spamming! If your message contains link/s, it will NOT be published on the site before manually approved by one of our moderators.



About Us  |  Contact us  |  Privacy Policy  |  Terms & Conditions