Signing Commercial Email with DKIM and ZXTM

Many businesses today rely on email to communicate with their customers. It’s a useful tool to keep them up-to-date with current news, events, and offers. So it’s more than a little frustrating when a proportion of those messages end up being flagged as spam and never seen by the intended recipient

Many systems have been developed over the past few years, to allow legitimate companies to distinguish their commercial email from that of your average Viagra pedlar, or Nigerian business opportunity. One of those methods is DKIM (DomainKeys Identified Mail). DKIM is the result of collaboration between a number of well known industry players, and is currently in use by Google, Yahoo!, Ebay, and PayPal, to name but a few.

This article describes how to use ZXTM to control outgoing and incoming email (SMTP) traffic and manage DKIM signatures. ZXTM can add a DKIM signature to all outgoing mail to certify that it originated from your organization, and can verify any DKIM signatures in incoming mail for SPAM prevention purposes.

More about DKIM

The DKIM.org website says: “DomainKeys Identified Mail (DKIM) lets an organization take responsibility for a message while it is in transit. The organization is a handler of the message, either as its originator or as an intermediary. Their reputation is the basis for evaluating whether to trust the message for delivery. Technically DKIM provides a method for validating a domain name identity that is associated with a message through cryptographic authentication.” DKIM doesn’t act as a spam filter, but rather it allows organisations to verify the source of the message. Which in turn makes it easy to identify an email as legitimate.

Signing Mail

When an email is signed, the Signor adds an email header which indicates that they are prepared to take responsibility for the content of the message. The header contains a cryptographic signature of the data, which can then be verified by the receiving mail system (the Verifier). ZXTM can be used to Sign your outgoing mail, by routing the messages through the ZXTM. This could be done by creating a Virtual Server to load balance across a set of a SMTP smarthosts. Or you could use DNAT to redirect outgoing SMTP traffic through a ZXTM Virtual Server running in forward-proxy mode.

DKIM Signing Process

1. The mail server initiates an outgoing SMTP connection through the ZXTM, the mail is redirected through the ZXTM service and a DKIM Signatures is added
2. The mail is sent either to a Smart Host or directly onto the recipients mail server
3. The recipients mail server accepts the message for delivery
4. Optionally, the recipients mail server verifies the signature against the DNS DKIM record.

Verifying Mail

When an email is found to have a DKIM Signature, the Verifier process will create and compare a hash of the mail body against the body hash in the Signature, and then verify the Signature data against the public key for the signing domain. The public key is retrieved via the DNS system, using data found within the DKIM signature.

ZXTM can be used to process incoming SMTP connections, and check all messages for DKIM signatures. When a signature is found, the header will be verified by our Java Extension, and a new header can be added to indicate the result of the verification attempt. Your spam checking systems may then use the outcome of ZXTMs verification as part of their own spam scoring calculations.

DKIM Verifying Process

1. Third party mail server has mail to deliver to your organistation. Message is sent through internet via SMTP.
2. ZXTM acts as ADC for incoming SMTP traffic. ZXTM checks message for DKIM Signature.
3. If DKIM is present, then ZXTM looks up the DKIM record of the Signer via DNS, and verifies the Signature. A header is added to mail indicating the outcome of the verification process.
4. Message is delivered to mail server.

Java DKIM Library

Most of the work in Signing and Verifying the DKIM signatures will be performed by the open source JavaDKIM Library. The Java Extensions provided in this article make use of JavaDKIM version 1.0.1.

Using ZXTM to Sign Outgoing Mail

1. Routing Traffic into our Virtual Server

If you have smarthost(s) which deliver your mail, then you can place ZXTM between your mail server and the smarthost. All you need to do is configure a pool containing your smarthosts, and then configure your mail server to use ZXTM as its smarthost. Alternatively, if your mail server sends mail directly, then you can use ZXTM as a transparent SMTP proxy. On Linux, the following iptables command can be used to Destination NAT all traffic on port 25 into your ZXTM virtual server running on the Traffic IP specified.

Iptablest natA POSTROUTINGp tcpdport 25j DNATto <Traffic IP>:25

For more information on how this works, review the Transparent Proxy article.

You now need to create a TrafficScript rule to perform the ForwardProxy. The TrafficScript function request.getDestIP() will be used to retrieve the original destination of this connection to be used as the node end-point.

$dest = request.getDestIP();
Pool.select(“SMTP Pool”, $dest, 25);

2. Signing the Email

Once requests are routing through our Virtual Server, we need another TrafficScript rule to process the messages. For this purpose we will extend Julians SMTP Synchronisation rule.

# SMTP Synchronizer Condensed- ZXTM Request Rule
# State is tracked in the connection.data variable "STATE", which is
# set to one of the following two constants. The constants themselves
# are the regular expressions supplied as arguments to
# request.endsWith() to define the end of a request in each state.
$STATE_HEADERS = "\r\n";
$STATE_BODY = "\r\n\\.\r\n";
# Initialise STATE if this is the first request on a new connection
if (! connection.data.get("STATE")) {
connection.data.set("STATE", $STATE_HEADERS);
}
$request = request.endsWith(connection.data.get("STATE"));
#### STATE SWITCHING
# We read the whole body in one go, so if we've got to here, and the
# state is STATE_BODY, then switch back to reading headers.
if (connection.data.get("STATE") == $STATE_BODY) {
connection.data.set("STATE", $STATE_HEADERS);
# We have read the body. Remove the ending <CRLF>.<CRLF>
$request = String.replace( $request, "\r\n.\r\n", "" );
# Fix any new line . escapes added by SMTP
$request = String.replaceAll( $request, "\r\n.", "\r\n" );
# Run the message through DkimSigner
connection.data.set("message", $request);
java.run("com.zeus.mail.DkimSigner");
$request = connection.data.get("message");
# Re-escape any . escape sequences
$request = String.replaceAll( $request, "\r\n.", "\r\n.." );
# Add the ending <CRLF>.<CRLF>
$request = $request . "\r\n.\r\n";
} else if (string.regexmatch($request, "^DATA\r\n")) {
# Whereas if we were reading headers, and see DATA, we should
# prepare ourselves for the body
connection.data.set("STATE", $STATE_BODY);
}
request.set($request);

The rule removes the ending <CRLF>.<CRLF> from the SMTP conversation, plus any dot “.” escapes which may have been added by the SMTP transfer. The message is now its original 7-bit format and can be passed to our DkimSigner Java Extension. The Java Extension will read the mail from ZXTMs connection data, create the Signature and then update the connection data with a signed copy of the message. The signed copy is then ready to be sent onto the waiting SMTP server. All of the requirements of Julians original SMTP Synchronisation script must be adhered to here, including setting this rule to run every time within the Virtual Server configuration.

DkimSigner Java Extension

The Java Extension takes several initialisation parameters. It needs to know the signing domain (Domain), the signing identity (Identity), the Algorithm to use in the Signature (Algorithm), the canonicalization method (Canonicalizer), the DKIM selector (Selector), and Key information.

DkimSigner Initialisation Parameters

Using ZXTM to Verify Incoming Mail

You may run an SMTP Virtual Server in order to pass all incoming messages. The service can load balance the messages across one or more mail servers, checking for, and verifying DKIM or DomainKey signatures found in each message. As with the DkimSigner, the DkimVerifier will again make use of Julian SMTP Synchronization script. The email body processing code is now....

<--SNIP-->
# We have read the body.
if ( ( String.containsI( $request, "DKIM-Signature:" ) ) ||
( String.containsI($request, "Domainkey-Signature:" ) ) ) {
# Header to append to message to indicate Verification status.
$VH = "ZXTM-DKIM-Info";
# Remove the ending <CRLF>.<CRLF>
$verStr = String.replace( $request, "\r\n.\r\n", "" );
# Fix any new line . escapes added by SMTP
$verStr = String.replaceAll( $verStr, "\r\n.", "\r\n" );
# Run the message through DkimVerifier
connection.data.set("message", $verStr);
java.run("com.zeus.mail.DkimVerifier");
$verStr = connection.data.get("message");
# Append our verification header
$request = String.replace($request, "\r\n\r\n", "\r\n" . $VH . ": " . $verStr . "\r\n\r\n");
<--SNIP-->

The DkimVerifier expects to find the mail stored in ZXTM connection data, but instead of returning the message back to TrafficScript, it returns the result of the Verification attempt. Our TrafficScript will then insert a new header into the message, called ZXTM-DKIM-Info which will hold this result.

DkimVerifier Java Extension

The Verifier Extension needs far fewer configuration parameters than the Signer did. It simple needs the name of a recursive name server it can use, and a cache time. Our Verifier will cache DKIM records found in DNS in order to improve performance.

DkimVerifier Initialisation Parameters

Download the Binaries and Source code

Before you can Sign or Verify any email messages, you will need to upload the Java extensions and JavaDKIM library to your ZXTM cluster. The DkimExtensions.jar file contains the DkimVerifier and the DkimSigner Java Extensions. The Java-DKIM-1.0.1.jar contains the JavaDKIM library. You should upload the library, before the Java Extensions.

DkimExtensions.jar Download
DkimExtensions Source Download
JavaDKIM 1.0.1 Jar Download
JavaDKIM 1.0.1 Source Download

Enjoy!

Mark Boddington [Zeus Systems Engineering] 08 July 2009 Bookmark with del.icio.us Post this article to Digg Post this article to reddit Post this article to Facebook Tweet this article  
Leave a comment ...
Your email address will not be displayed.
Your URL will be displayed.
This public messageboard is not a forum for technical support. To report technical support problems, please contact our dedicated Support team using the instructions at the bottom of this page.
Options:
 
(Line breaks become <br />)
(Set cookies for name, email & url)

Recently...

Other Resources