Mediante DKIM podemos firmar los correos que mandamos mediante un determinado dominio. Se usa el header DKIM-Signature. Vamos a ver como funciona y como configurar qmail para que firme los correos salientes:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=date:from:to:subject:message-id:in-reply-to:references:x-mailer :mime-version:content-type:content-transfer-encoding; bh=h94cOorFnF7zrqXewhm6jiXkvCwtLdWYcECXDq7i+w0=; b=vpq1zBvkGwfaVOCsHRCGrb9UulHTxD/G38gF0CZ3I/YRvOUqpk/kS1W1fc1xdT/T72 xo+cf1feYMPVKw0xeRU83OGHDIMzA2zYc7pqRB8yO/dVA7PsCg+r2QmI1hwVne4dqNQk d60abjGiZJG48ZzVHQUehODLMqJkoZI4VFqKo=
El que reciba el mail puede obtener la clave pública a partir del selector (valor s) en este caso gamma combinado con el dominio firmante (valor d). En el caso anterior sería:
# dig gamma._domainkey.gmail.com txt +short "k=rsa\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIhyR3oItOy22ZOaBrIVe9m/iME3RqOJeasANSpg2YTHTYV+Xtp4xwf5gTjCmHQEMOs0qYu0FYiNQPQogJ2t0Mfx9zNu06rfRBDjiIU9tpx2T+NGlWZ8qhbiLo5By8apJavLyqTLavyPSrvsx0B3YzC63T4Age2CDqZYA+OwSMWQIDAQAB"
A continuación se usan los headers que se indican con el valor h, se tratan según el algoritmo especificado en el valor c y se firma con un hash de los datos tratados.
Para el caso de relaxed podemos consultar la sección 3.4.2 del RFC4871 donde se indica que cómo se deberán tratar los headers para asegurarnos que se podrá verificar el firmado aunque MTAs intermedias modifiquen los headers.
Para empezar a firmar los mails salientes con qmail, primero deberemos instalar el modulo de perl Mail::DKIM
cpan> install Mail::DKIM
A continuación deberemos conservar el script que viene con el paquete llamado dkimsign.pl:
cp /root/.cpan/build/Mail-DKIM-0.39/scripts/dkimsign.pl /usr/local/bin/
Deberemos modificarlo para que acepte como parámetro nuestra clave privada:
cat <<EOF > /usr/local/src/dkimsign.patch --- dkimsign.pl.old 2012-01-30 22:06:50.959015108 +0100 +++ dkimsign.pl 2012-01-30 22:08:19.839015533 +0100 @@ -26,8 +26,10 @@ my $debug_canonicalization; my $binary; my $help; +my $key="rsa.private"; GetOptions( "type=s" => \$type, + "key=s" => \$key, "algorithm=s" => \$algorithm, "method=s" => \$method, "selector=s" => \$selector, @@ -61,7 +63,7 @@ Algorithm => $algorithm, Method => $method, Selector => $selector, - KeyFile => "private.key", + KeyFile => $key, Debug_Canonicalization => $debugfh, ); EOF patch /usr/local/bin/dkimsign.pl /usr/local/src/dkimsign.patch
Copiamos el qmail-remote original, ya que lo substituiremos por un script que firme los correos:
cp /var/qmail/bin/qmail-remote /var/qmail/bin/qmail-remote.orig
Podemos encontrar un script como el siguiente que permite tener varias claves privadas para firmar según el dominio del from:
#!/bin/bash host="$1" sender="$2" [ -z "$sender" ] && [ "$DEFAULTDOMAIN" ] && sender="@$DEFAULTDOMAIN" [ -z "$sender" ] && sender=@`hostname -f` DOMAIN="${sender##*@}" [ "$DKREMOTE" ] || DKREMOTE="/var/qmail/bin/qmail-remote.orig" [ "$DKSIGN" ] || DKSIGN="/etc/domainkeys/%/default" if [ "$DOMAIN" ] ; then while [ ! -r "${DKSIGN//\%/$DOMAIN}" ] ; do # try parent domains, per RFC 4871, section 3.8 DOMAIN=${DOMAIN#*.} DPARTS=( ${DOMAIN//./ } ) [ ${#DPARTS[*]} -eq 1 ] && DOMAIN="${sender##*@}" && break done fi DKSIGN="${DKSIGN//\%/$DOMAIN}" if [ -r "$DKSIGN" ] ; then tmp=`/bin/mktemp /tmp/dk.sign.XXXXXXXXXXXXXXXXXXX` tmp2=`/bin/mktemp /tmp/dk2.sign.XXXXXXXXXXXXXXXXXXX` /bin/cat - >"$tmp" # compute the DomainKey signature error=`(/usr/local/bin/dkimsign.pl --type=domainkeys --selector=default \ --key="$DKSIGN" --method=simple <"$tmp" | \ /usr/bin/tr -d '\r' >> "$tmp2") 2>&1` [ "$error" ] && echo "DomainKey error: $error" >&2 && exit -2 # compute the DKIM signature error=`(/usr/local/bin/dkimsign.pl --type=dkim --selector=default \ --key="$DKSIGN" --method=relaxed <"$tmp" | \ /usr/bin/tr -d '\r' >> "$tmp2") 2>&1` [ "$error" ] && echo "DKIM error: $error" >&2 && exit -2 # feed the signatures and the original message to the real qmail-remote /bin/cat "$tmp2" "$tmp" | "$DKREMOTE" "$@" retval=$? /bin/rm "$tmp" "$tmp2" exit $retval else echo "No DK signature added" >&2 exec "$DKREMOTE" "$@" fi
Pero para el caso de muchos dominios puede ser muy pesado tener que crear tantas claves por lo que podemos firmar usando un único dominio. Podemos simplificar el script para que use únicamente la clave privada que tenemos en /etc/domainkeys/default. Por otro lado, los ficheros temporales los podemos guardar en memoria mediante tmpfs:
tmpfs on /dev/shm type tmpfs (rw)
El script anterior, del que deberemos personalizar el dominio con el que queremos firmar, una vez simplificado quedaría:
#!/bin/bash DKSIGN="/etc/domainkeys/default" DKREMOTE="/var/qmail/bin/qmail-remote.orig" DKDOMAIN="systemadmin.es" tmp=`/bin/mktemp /dev/shm/dk.sign.XXXXXXXXXXXXXXXXXXX` tmp2=`/bin/mktemp /dev/shm/dk2.sign.XXXXXXXXXXXXXXXXXXX` /bin/cat - >"$tmp" /usr/local/bin/dkimsign.pl --type=dkim --selector=default \ --key="$DKSIGN" --method=relaxed --domain=$DKDOMAIN <"$tmp" | \ /usr/bin/tr -d '\r' >> "$tmp2" 2>&1 /bin/cat "$tmp2" "$tmp" | "$DKREMOTE" "$@" retval=$? /bin/rm "$tmp" "$tmp2" exit $retval
Lo podemos llamar qmail-remote.DKIM A continuación deberemos crear una clave privada:
mkdir -p /etc/domainkeys/systemadmin.es cd /etc/domainkeys/systemadmin.es openssl genrsa -out rsa.private 768 cp rsa.private default
Y generamos la clave pública:
openssl rsa -in rsa.private -out rsa.public -pubout -outform PEM rm rsa.private
Lo que nos quedará:
$ ll total 8 -rw-r--r-- 1 root root 688 Mar 17 19:05 default -rw-r--r-- 1 root root 223 Mar 17 19:05 rsa.public
A continuación podemos obtener lo que deberemos añadir al registro TXT:
$ grep -v ^- rsa.public | perl -e 'while(<>){chop;$l.=$_;}print "k=rsa; t=y; p=$l;\n";' k=rsa; t=y; p=MHwwAAAAKoZIhvcNAQEBBAADAwAwAAJhAJ6243dIC0CzzBI9nNY/12347selbvh0GI3phmOcEYAA4M+/nlM+lMXHHIo8rlKtgYA2E412345g40ms2zWeCWMtAAmgHL1QCgvQJ5STzF5wOVz6mtFb6AAKBb9AAvl3wIDAQAB;
Mediante el valor t indicamos si estamos en pruebas, cuando estemos seguros que funciona correctamente lo podemos quitar:
_domainkey.systemadnin.es. IN TXT "o=-;" default._domainkey.systemadmin.es. IN TXT "k=rsa; t=y; p=MHwwDQYJKoZIhvcNAQEBBQADawAwaAJhAOCKwsbO8avw2253VH6ACFqGfilvDfVboz4LX1TLM3oVV8sT51W7k8j8H2Mg3w3SgpKlYcAyJ8LO7cifRpYPUIJjhmeQtIXtGFm0aK7lvxC+sDzvJdWssbXAb3t6hveJ3QIDAQAB;"
Podemos habilitar el firmado creando un link simbólico del qmail-remote.DKIM al qmail-remote y reinicar qmail-send:
ln -sf /var/qmail/bin/qmail-remote.DKIM /var/qmail/bin/qmail-remote svc -t /service/qmail-send
Si mandamos un mail de prueba:
# telnet localhost 25 Trying 127.0.0.1... Connected to localhost.localdomain (127.0.0.1). Escape character is '^]'. 220 RTFM ESMTP helo test mail from: jordi@test.com 250 ok rcpt to: ejemplo@gmail.com 250 ok data 354 go ahead From: Jordi Prats <jprats@test.com> Subject: test dkim aaa . 250 ok 1328476380 qp 16660
Podemos ver la firma en los headers del mail:
DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=systemadmin.es; h=date :message-id:from:to:subject; s=default; bh=0PMpbQVFwgW9281z6qXAO N7t78U=; b=AGSC7IO9Uro/MKQcoEU4ZFsU4C8RY0O3Wox+wywnr2JblZc40NfCc Zgqj+sdTATtcJSvH9lVcLSxbD88qpYbQ1ausjszyzswpVudDi6muJefLP2v9A2qB Cc7K1F+ngvp
Si lo comprobamos con un SpamAssassin veremos los siguientes hits de reglas:
X-Spam-Status: No, score=-0.1 required=4.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_PASS,SPF_PASS autolearn=unavailable version=3.3.1
En el caso de gmail, si mandamos un mail firmado con DKIM nos añadirá via y el dominio firmante al lado del from, por ejemplo:
Tags: <a href="http://systemadmin.es/tag/qmail" title="qmail" rel="tag">qmail</a><br>
<h4>Relacionados</h4>
<ul>
<li><a href="http://systemadmin.es/2009/03/usando-qmail-para-entregar-correo-a-nuestro-relay" title="Usando qmail para entregar correo a nuestro relay (31/March/2009)">Usando qmail para entregar correo a nuestro relay</a></li>
<li><a href="http://systemadmin.es/2009/02/ucspi-tls-sslserver-general-protection-rip32bca95737-rsp7fff288e6988-error0" title="UCSPI-TLS sslserver: general protection rip:32bca95737 rsp:7fff288e6988 error:0 (20/February/2009)">UCSPI-TLS sslserver: general protection rip:32bca95737 rsp:7fff288e6988 error:0</a></li>
<li><a href="http://systemadmin.es/2009/02/spamcheck-para-newsletters-con-qmail-y-spamassassin" title="Spamcheck para newsletters con qmail y spamassassin (27/February/2009)">Spamcheck para newsletters con qmail y spamassassin</a></li>
<li><a href="http://systemadmin.es/2009/07/qmqtool-herramienta-para-ver-y-modificar-la-cola-de-qmail" title="qmqtool: Herramienta para ver y modificar la cola de qmail (14/July/2009)">qmqtool: Herramienta para ver y modificar la cola de qmail</a></li>
<li><a href="http://systemadmin.es/2009/01/qmailanalog-usrbinld-errno-tls-definition-in-lib64libcso6-section-tbss-mismatches-non-tls-reference-in-strerrastrerr_syso" title="qmailanalog: /usr/bin/ld: errno: TLS definition in /lib64/libc.so.6 section .tbss mismatches non-TLS reference in strerr.a(strerr_sys.o) (20/January/2009)">qmailanalog: /usr/bin/ld: errno: TLS definition in /lib64/libc.so.6 section .tbss mismatches non-TLS reference in strerr.a(strerr_sys.o)</a></li>
Via http://systemadmin.es/2012/02/dkim-domainkeys-identified-mail-qmail
