DKIM
Server - Postfix

 

DKIM

Domainkeys uses a system to verify the DNS domain of the email sender and therefore confirm email integrity. This is an older type of verification. DKIM is more advanced and uses a public key to sign email so that the recipient can verify the sender. The recipient must be able to access the public key using DNS. Yahoo and Gmail both use this technology.

This is an example on connecting Postfix to dkimproxy.out for signing outbound messages. Messages that trigger the filter get sent to port 10027 where dkimproxy.out is listening. Dkimproxy.out processes the message and forwards the connection back to Postfix on port 10028. In order to set these ports up you must modify master.cf, make a backup of the original first.

 

master.cf

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 DKIM signing proxy

# Note: we allow "4" simultaneous deliveries here; high-volume sites may

# want a number higher than 4.

# Note: the smtp_discard_ehlo_keywords option requires Postfix 2.2 or

# better. Leave it off if your version does not support it.

#

dksign unix - - n - 4 smtp

-o smtp_send_xforward_command=yes

-o smtp_discard_ehlo_keywords=8bitmime,starttls

 

#

# service for accepting messages FROM the DKIM signing proxy

#

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

 

Add this line under the pickup line. Make sure to leave space before the “-o”

pickup fifo n - n 60 1 pickup

# Added for DKIM

-o content_filter=dksign:[127.0.0.1]:10027

 

Install Pre-requisites and Build dkimproxy

yum install -y make

yum install -y perl-Digest-SHA perl-Mail-Address perl-MIME-Base64-Perl perl-Net-DNS perl-Net-Server perl-Crypt-OpenSSL-RSA perl-Error


cd /usr/local/src

wget http://sourceforge.net/projects/dkimproxy/files/dkimproxy/1.4.1/dkimproxy-1.4.1.tar.gz

tar zxvf dkimproxy-1.4.1.tar.gz

cd dkimproxy-1.4.1


./configure --prefix=/usr/local/dkimproxy

make install

 

cp sample-dkim-init-script.sh /etc/init.d/dkimproxy

chmod 755 /etc/init.d/dkimproxy

 

groupadd -g 1003 dkim

useradd -u 1003 -s /bin/false -d /dev/null -g dkim dkim

 

Generate a private/public key pair using OpenSSL


mkdir -p /etc/postfix/ssl/domainkeys

cd /etc/postfix/ssl/domainkeys

openssl genrsa -out private.key 1024

openssl rsa -in private.key -pubout -out public.key


Now you will have two keys, a public and private.


chown dkim:dkim *.key

chmod 440 private.key

 

Create a DNS entry for Each Domain

 

Use a selector name like selector1.

 

selector1._domainkey IN TXT "k=rsa; t=s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8lNPJjExafzP+ouytzqpx8ixcbHgTFiHcuCZx41UoZBuh9+w///91i/E+7xG3iJoNKbAeZLPG96g090AqnkAFxEdJjLq0BcjH0JumYmzBhDFVbeF9uS+rZCxPFLt6T/llfMZv0LSYb+69CspQ5+gl4U+hmoVmGw5X63H8aFfVgQIDAQAB"


Be sure that the p= contains the public key minus the:


-----BEGIN PUBLIC KEY-----

-----END PUBLIC KEY-----


The first thing you will need to do is copy the example config for outgoing mail to a dkimproxy_out.conf.

cp /usr/local/dkimproxy/etc/dkimproxy_out.conf.example /usr/local/dkimproxy/etc/dkimproxy_out.conf

 

Now edit /usr/local/dkimproxy/etc/dkimproxy_out.conf. Be sure that you have the complete path to your private key and the name of the key is exactly what you entered. The other point to be careful with is the selector. Here the standard selector1 is used, this must match what you enter in the DNS server text file.

 

# specify what address/port DKIMproxy should listen on

listen 127.0.0.1:10027

# specify what address/port DKIMproxy forwards mail to

relay 127.0.0.1:10028

# specify what domains DKIMproxy can sign for (comma-separated, no spaces)

domain example.com

# specify what signatures to add

signature dkim(c=relaxed)

signature domainkeys(c=nofws)

# specify location of the private key

keyfile /etc/postfix/ssl/domainkeys/private.key

# specify the selector (i.e. the name of the key record put in DNS)

selector selector1

# control how many processes DKIMproxy uses

# - more information on these options (and others) can be found by

# running `perldoc Net::Server::PreFork'.

#min_servers 5

#min_spare_servers 2

 

Create a file which tells dkimproxy which domains have keys. Each domain must be listed separately on a line followed by the domainkeys encryption and the dkim encryption methods.

vi /etc/postfix/ssl/domainkeys/domainkeyfile


example.com domainkeys(a=rsa-sha1,c=nofws), dkim(a=rsa-sha256,c=relaxed)

 

Prepare to start your dkimproxy by restarting postifix first.

service postfix restart

service dkimproxy start


./dkimproxy.out --user=dkim --group=dkim --keyfile=/etc/postfix/etc/ssl/domainkeys/private.key --selector=selector1 --sender_map=/etc/postfix/ssl/domainkeys/domainkeyfile --daemonize –pidfile=/var/run/dkim.pid 127.0.0.1:10027 127.0.0.1:10028


Test Email

Here is a link to a site where you can send an email to an address you create and it will provide output to verify your implementation of dkimproxy.

http://www.brandonchecketts.com/emailtest.php

 

Errors

May 22 12:48:53 mail dkimproxy.out[16603]: signing error: Can't call method "use_no_padding" on an undefined value at /usr/lib/perl5/vendor_perl/5.8.8/Mail/DKIM/PrivateKey.pm line 179, <FILE> line 2.

 

Cannot find or use private key.

Restart Postfix and see error messages.

 

May 29 09:19:15 mail postfix/postfix-script: warning: not owned by root: /etc/postfix/ssl

May 29 09:19:15 mail postfix/postfix-script: warning: not owned by root: /etc/postfix/ssl/domainkeys

May 29 09:19:15 mail postfix/postfix-script: warning: not owned by root: /etc/postfix/ssl/domainkeys/private.key

May 29 09:19:15 mail postfix/postfix-script: warning: not owned by root: /etc/postfix/ssl/domainkeys/domainkeyfile

May 29 09:19:15 mail postfix/postfix-script: warning: not owned by root: /etc/postfix/ssl/domainkeys/public.key


You should see that the process for dkim is running.

 

ps aux | grep dkim

dkim 16074 0.0 0.2 18428 11260 ? Ss 06:45 0:00 /usr/bin/perl -I/usr/local/dkimproxy/lib /usr/local/dkimproxy/bin/dkimproxy.out --user=dkim --group=dkim --daemonize --pidfile=/usr/local/dkimproxy/var/run/dkimproxy_out.pid –conf_file=/usr/local/dkimproxy/etc/dkimproxy_out.conf


Example Accepted by Google

 

Received-SPF: pass (google.com: domain of This e-mail address is being protected from spambots. You need JavaScript enabled to view it designates 18.106.216.78 as permitted sender) client-ip=18.106.216.78;

Authentication-Results: mx.google.com; spf=pass (google.com: domain of This e-mail address is being protected from spambots. You need JavaScript enabled to view it designates 18.106.216.78 as permitted sender) smtp.mail= This e-mail address is being protected from spambots. You need JavaScript enabled to view it ; dkim=pass header.i=@example.com

Received: from mail.example.com (localhost [127.0.0.1])

by mail.example.com (Postfix) with ESMTP id E76E2D0D0D

for < This e-mail address is being protected from spambots. You need JavaScript enabled to view it >; Sun, 22 May 2011 13:35:25 +0000 (UTC)

DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=example.com;

h=date:from:to:subject:message-id:mime-version:content-type; s=

selector1; bh=/edzoYuyn17WXm8KeqcX/R+khdQ=; b=TV1j4gFI+yG3tIJxN1

OpW6WjO9x50T1MLkgVy8uSijfeDLJe1sp6A9RS2LmGRIQYMi7ox0RWpb9Xq3DsRT

gvH88Lwcj3Ulek0Tjsj0Lwf5VwKqSLo/AdIYTJLlLU1VH22GyserpfdFb0jH37OK

4XZ2WSda60cofUB+fvLZTdCH4=

DomainKey-Signature: a=rsa-sha1; c=nofws; d=example.com; h=

date:from:to:subject:message-id:mime-version:content-type; q=

dns; s=selector1; b=Bv/sGggTpDLSXhrrARRSTiarXoJYXBYd1SWWzNA8AfFc

PyF4HyaGtnUsFo5rdRtv7kNL+0kuJk6btWSdm2OjCandGSyyUXWZsE/qQpD/dZRH

a1BukDA6QaUMw9D/TBiS54aPNxGCWWP3Se31uH0L9gUcAD/9o7FekrrNa8VrKh4=