DomainKeys filter for Postfix

dkfilter is an SMTP-proxy designed for Postfix. It implements DomainKeys message signing and verification. It comprises two separate filters, an "outbound" filter for signing outgoing email, and an "inbound" filter for verifying signatures of incoming email. The filters can operate as either Before-Queue or After-Queue Postfix content filters.

At this point, dkfilter is being superceded by a sister project I have called DKIMproxy. DKIMproxy implements DomainKeys and DKIM message signing and verifying. (DKIM is kind of an "upgrade" to DomainKeys that is being standardized by the IETF. It may one day replace DomainKeys.)

Note: I am still supporting Dkfilter. However, at some point in the future I hope to have DKIMproxy ready as a replacement/upgrade to Dkfilter.

News

2007-06-27 - No Software Updates; New Forum

Sorry there hasn't been any news on this project for a while. All of my DomainKeys work has been on Dkim-Proxy instead of Dkfilter.

Meanwhile, Mike Heijmans at techtribe.com just let me know today about a new DomainKeys forum that dkfilter users might be interested in. It's at www.domainkeysforum.org.

2006-10-19 - Config File patch refreshed

The Config File patch has been updated so that it applies cleanly against dkfilter version 0.11. Thanks to Jason Purdy.

2006-09-21 - dkfilter 0.11 now available

Version 0.11 includes a rewritten sample init script that does not depend on the startproc and killproc commands found on SuSE.

Requirements

Dkfilter is written in Perl. It requires the following Perl modules:

Dkfilter is based on smtpprox and Mail::DomainKeys. My thanks go out to Bennett Todd for providing smtpprox and Anthony D. Urso for providing Mail::DomainKeys.

Dkfilter is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation.

Download dkfilter

Dkfilter is currently beta-quality software. It has not received widespread testing, and may mangle, discard, bounce, or duplicate your mail. That said, if you are comfortable with Postfix and willing to give Dkfilter a try, please do.

Note to upgraders: Version 0.10 has a new dependency: Net::Server. You can install it using CPAN. See the NEWS file for details on other changes.

Download the current version: Version 0.11.

See what's new in this release.

You may also be interested in one or more of the following user-contributed patches:

Signature patch - by Jamie L. Penman-Smithson - changes the order of tags in the generated signature and uses Text::Wrap to prettify it. - updated by Guillermo Antonio Amaral Bastidas

Config File patch (for multiple keys) (for dkfilter 0.11, requires AppConfig::File) - by Xavier Perseguers - allows signing of multiple domains with each domain having its own key file, as specified in a configuration file.

SQL Database patch (for dkfilter 0.11, requires DBI) - by Sven Klose - the list of domains signed by dkfilter.out is now read from a database, so it is not necessary to restart the server when the list changes

Updated SQL Database patch (for dkfilter 0.11, requires DBI) - by Sven Klose - same as above, with some improvements- instead of getting a full list of domains from the database, it now queries just for the domain in the current message

Installing dkfilter

If you follow the instructions below, you will have the inbound (signature-verifying) filter installed as a Before-Queue filter to verify inbound mail received on port 25, and the outbound (signing) filter installed as an After-Queue filter to sign outgoing mail received on port 587.

Note: Please read and understand the Postfix documentation on content filters before attempting to install dkfilter.

The following steps are recommended for installing dkfilter:

  1. Determine where you want to install dkfilter's program files, e.g. /usr/local/dkfilter.
  2. "cd" to the directory containing dkfilter's source code and type ./configure --prefix= followed by the location in which you want to install the filter. E.g.
    ./configure --prefix=/usr/local/dkfilter
    
  3. Run make install to install the program files to the desired directory. If you used /usr/local/dkfilter as the prefix, the filter scripts will be installed in /usr/local/dkfilter/bin and the Perl module files will be in /usr/local/dkfilter/lib.
  4. Create a Unix user/group dedicated to running dkfilter. E.g. dkfilter.
  5. Create a startup/shutdown script for the filter. A sample script (sample-dkfilter-init-script.sh) is provided... make sure to check, and modify if necessary, the user, group, and directory found in the script. Also, you may need to adjust command-line arguments for starting the filter(s). Then you can copy it to /etc/init.d/dkfilter and use it like any other init script.

Setting up the inbound filter

The inbound filter understands the following arguments:

--reject-fail
if specified, messages that fail verification will be rejected. Note: this applies to "hard" fails only. Soft fails, like when the sending domain is simply testing domain keys, or if they don't have a "sign-all" policy published, will still be accepted.
--reject-error
if specified, and an error occurs while verifying a signature, a temporary rejection will be generated, and the sending system will have to try again later. Otherwise, the message will go through without verification, unaltered.
--hostname=HOSTNAME
specifies the hostname used in the Authentication-Results header that gets added to a verified message

To manually start the inbound filter:

dkfilter.in 127.0.0.1:10025 127.0.0.1:10026
This starts the filter listening on port 10025 and transmitting to port 10026.

The following example shows how to configure a Before-Queue Postfix filter for dkfilter.in. Incoming SMTP traffic (on port 25) is proxied to port 10025 and forwarded connections are accepted on port 10026.

/etc/postfix/master.cf:

#
# Before-filter SMTP server. Receive mail from the network and
# pass it to the content filter on localhost port 10025.
#
smtp      inet  n       -       n       -       -       smtpd
    -o smtpd_proxy_filter=127.0.0.1:10025
    -o smtpd_client_connection_count_limit=10
#
# After-filter SMTP server. Receive mail from the content filter on
# localhost port 10026.
#
127.0.0.1:10026 inet n  -       n       -        -      smtpd
    -o smtpd_authorized_xforward_hosts=127.0.0.0/8
    -o smtpd_client_restrictions=
    -o smtpd_helo_restrictions=
    -o smtpd_sender_restrictions=
    -o smtpd_recipient_restrictions=permit_mynetworks,reject
    -o smtpd_data_restrictions=
    -o mynetworks=127.0.0.0/8
    -o receive_override_options=no_unknown_recipient_checks

Execute postfix reload for Postfix to respond to changes in /etc/postfix/master.cf.

Setting up the outbound filter

The outbound filter needs access to the private key used for signing messages. In addition, in needs to know the name of the key selector being used, and what domain it should sign messages for. This information is specified with command-line arguments to dkfilter.out.

But first, let's generate a private/public key pair and publish the public key in DNS.

  1. Generate a private/public key pair using OpenSSL:
    openssl genrsa -out private.key 1024
    openssl rsa -in private.key -pubout -out public.key
    
    This creates the files private.key and public.key in the current directory, containing the private key and public key. Make sure private.key is not world-readable, but still readable by the dkfilter user.
  2. Pick a selector name... e.g. selector1
  3. Put the public-key data in DNS, in your domain, using the selector name you picked. Take the contents of the public.key file and remove the PEM header and footer, and concatenate the lines of the file into one big line. Then create a TXT entry, like this:
    selector1._domainkey IN TXT "k=rsa; p=MHwwDQYJK ... OprwIDAQAB; t=y"
    where selector1 is the name of the selector chosen in the last step and the p= parameter contains the public-key as one long string of characters.

Now, configure command-line arguments for dkfilter.out startup:

--reject-error
if specified, and an error occurs while generating a signature, a temporary rejection will be generated, and the sending system will have to try again later. Otherwise, the message will go through without being signing.
--keyfile=KEYFILE
this is required; specifies the file containing the private key
--selector=SELECTOR
this is required; specifies the name of the key selector
--domain=DOMAIN
this is required; specifies what domain(s) emails are signed for. If you want to sign for multiple domains, specify the domains separated by commas (see example below)
--method=METHOD
METHOD is simple or nofws; selects canonicalization method for signing. If not specified, the default is simple.
--headers
specifying this will create signatures with an h tag, which lists all the header names found in the signed message.

e.g.

dkfilter.out --keyfile=/usr/local/dkfilter/private.key --selector=selector1 \
        --domain=example.org,example.com --method=nofws \
        127.0.0.1:10027 127.0.0.1:10028

Finally, configure Postfix to filter outgoing, authorized messages only through the dkfilter.out service on port 10027. In the following example, messages sent via SMTP on port 587 (the submission port) will go through an After-Queue content filter that signs messages with DomainKeys.

/etc/postfix/master.cf:

#
# modify the default submission service to specify a content filter
# and restrict it to local clients and SASL authenticated clients only
#
submission  inet  n     -       n       -       -       smtpd
    -o smtpd_etrn_restrictions=reject
    -o smtpd_sasl_auth_enable=yes
    -o content_filter=dksign:[127.0.0.1]:10027
    -o receive_override_options=no_address_mappings
    -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject

#
# specify the location of the DomainKeys signing filter
#
dksign    unix  -       -       n       -       10      smtp
    -o smtp_send_xforward_command=yes
    -o smtp_discard_ehlo_keywords=8bitmime

#
# service for accepting messages FROM the DomainKeys signing filter
#
127.0.0.1:10028 inet  n  -      n       -       10      smtpd
    -o content_filter=
    -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
    -o smtpd_helo_restrictions=
    -o smtpd_client_restrictions=
    -o smtpd_sender_restrictions=
    -o smtpd_recipient_restrictions=permit_mynetworks,reject
    -o mynetworks=127.0.0.0/8
    -o smtpd_authorized_xforward_hosts=127.0.0.0/8

Execute postfix reload for Postfix to respond to changes in /etc/postfix/master.cf.

Known Issues

Please check the Frequently Asked Questions page if you have a problem. It is possible there is already a known solution to your problem. Otherwise, send me an email: jlong@messiah.edu.

Here I will try to document unresolved issues with dkfilter.

If you notice additional problems, let me know so I can add them to this list.

Interoperability Testing

The following email address is configured to auto-respond with Domain Key verification results. It uses the dkfilter implementation as found on this web page.

test@dktest.jason.long.name

Additional auto-responders are listed on the DomainKeys Implementors Site. These auto-responders use different implementations of the DomainKeys spec, so it's a good idea to try them out as well. Unfortunately, I have found several of them do not seem to properly verify signatures using the h= tag. See testers-status.

Support

Sorry, there is no forum or mailing list specific to Dkfilter. You can post questions in one of the following forums, but please mention in the subject you are using Jason Long's "dkfilter" software.

Feel free to post comments, suggestions, and patches, if you have any. I will monitor the forums when I can.

You can also email me directly (jlong@messiah.edu), but be warned I sometimes take a while to respond to email. Someday I might setup a mailing list as well, for this project.

Last updated: 2007-11-16