Full-service Internet Marketing & Web Development
Recent Posts

Sponsors
![]() |
How to implement DomainKeys from scratchMichel 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:
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:
_domainkey.domain.com:
selector._domainkey.domain.com:
You can test that these records are working fine by using `dig`:
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:
You can refer to the RFC to see the definition of every flag in the signature.
Here is an example mail:
The "DomainKey-Signature:" header for this email would be:
The following BASH script does everything you need:
dk-sign.sh:
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 - sa-test@sendmail.net
* DomainKeys Test #2 - http://www.mailradar.com/domainkeys/
* DomainKeys Test #3 - http://69.56.15.194/
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)
# (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
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
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: from@domain.com
To: sa-test@sendmail.net
Subject: Message subject
Date: Wed Aug 6 16:42:28 GMT 2008
Message-ID: <20080806164228.42037@domain.com>
Message body
To: sa-test@sendmail.net
Subject: Message subject
Date: Wed Aug 6 16:42:28 GMT 2008
Message-ID: <20080806164228.42037@domain.com>
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
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="from@domain.com"
to="sa-test@sendmail.net"
subject="Message subject"
msg="Message body"
# Other settings
[ "$1" != "" ] && to="$1"
file="mail.txt"
date=`date`
id="<`date +%Y%m%d%H%M%S`.$$@$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)
# (bof)
# Parameters
selector="selector"
domain="domain.com"
from="from@domain.com"
to="sa-test@sendmail.net"
subject="Message subject"
msg="Message body"
# Other settings
[ "$1" != "" ] && to="$1"
file="mail.txt"
date=`date`
id="<`date +%Y%m%d%H%M%S`.$$@$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 - sa-test@sendmail.net
* DomainKeys Test #2 - http://www.mailradar.com/domainkeys/
* DomainKeys Test #3 - http://69.56.15.194/
![]() |
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
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
|
|
Subscribe Now to receive new posts via Email as soon as they come out.
Comments
Post your comments




