Configurazione di DKIM per qmail

12 febbraio 2024 by Roberto Puzzanghera 4 commenti

Questa pagina riguarda la patch DKIM inclusa nella mia patch combinata (maggiori informazioni qui). Questo argomento è avanzato ed è consigliabile tornare qui alla fine del tutto.

DKIM fornisce un metodo per validare l'identità di un nome a dominio associato a un messaggio con una autenticazione crittografata. La tecnica di validazione è basata sulla crittografia di una chiave pubblica: Il server che invia l'email aggiunge il nome a dominio al messaggio e vi affigge una firma digitale. Questa chiave è posta nell'intestazione DKIM-Signature: del messaggio. Colui che riceve il messaggio può controllare la validità della chiave pubblica leggendo un record TXT del DNS del dominio associato al messaggio.

Sei invitato a dare un'occhiata alle pagine man a partire da qmail-dkim(8) e spawn-filter(8).

Changelog

  • Feb 12, 2024
    - v. 1.48: fixed minor bug using filterargs for local deliveries (commit)
  • Feb 6, 2024
    -DKIM patch upgraded to v. 1.47
    * fixed a bug which was preventing filterargs' wildcards to work properly on sender domain
  • Jan 11, 2024
    - version 1.46
    * dk-filter.sh has been dropped. If signing at qmail-remote level, before upgrading, you have to review the configuration as explained below.
    * The variables USE_FROM, USE_SENDER and DKIMDOMAIN have been dropped
    * when signing at qmail-remote level qmail-dkim now has to be called directly by spawn-filter in the rc file. man spawn-filter for more info
    * In case of bounces the signature will be automatically based on the from: field. This will solve issues of DMARC reject by google in case of sieve/vacation bounces.
    * In case of ordinary bounces (mailbox not found, for instance) the bounce domain will be taken from control/bouncehost and, if doesn't exist, from control/me
  • Jan 4, 2024
    - patch upgraded to v. 1.44
    * fixed an issue with filterargs where spawn-filter is trying to execute remote:env xxxxx.... dk-filter. This issue happens when FILTERARGS environment variable is not defined in the qmail-send rc script.
    * dkim.c fix: https://notes.sagredo.eu/en/qmail-notes-185/configuring-dkim-for-qmail-92.html#comment3668 
    * adjustments fo dk-filter and dknewkey man pages
  • Nov 20, 2023
    * The patch now by default excludes X-Arc-Authentication-Results
    * dkim can additionally use the environment variable EXCLUDE_DKIMSIGN to include colon separated list of headers to be excluded from signing (just like qmail-dkim). If -X option is used with dk-filter, it overrides the value of EXCLUDE_DKIMSIGN.
  • Feb 19, 2023 (v. 1.37 upgrade)
    - ed25519 support​ (RFC 8463)
    - multiple signatures/selectors via the enhanced control/dkimkeys or DKIMSIGNDKIMSIGNEXTRADKIMSIGNOPTIONS  DKIMSIGNOPTIONSEXTRA variables
    - domainkey script replaced by dknewkey in order to create ed25519 keys and rsa keys with 1024/2048/4096 bit
    - dropped yahoo's domainkeys support (no longer need the libdomainkeys.a library)
    - man pages revised and enhanced
    - domainkeys directory moved to /var/qmail/control/domainkeys
    - the documentation in this page has been revised. You can find how to sign with the rsa key together with the ed25519 key below.

Ringraziamenti

Vorrei rivolgere un ringraziamento speciale a Manvendra Bhangui, l'autore della DKIM patch, per avermi assistito con grande cortesia durante tutta la configurazione.


I will show how to configure qmail-remote to sign your outgoing messages and qmail-smtpd to verify your incoming messages. Eventually, as an alternative, you can decide to set qmail-smtpd to do both things; this configuration is presented towards the bottom of this page.

In any case you have to create the domainkey signature.

Creazione della firma domainkey per le email in uscita

Le firme vengono create usando una chiave privata presente in un file protetto, e verificate da una chiave pubblica salvata in un record TXT nel DNS per il domino associato all'email.

Prima di poter firmare la posta, è necessario creare almeno una coppia di chiavi pubblica/privata. Si può decidere di creare una coppia di chiavi che valga per tutti i domini presenti nel mail server, oppure di usare una coppia di chiavi per ognuno dei domini.

A partire dalla versione 1.37 non useremo più lo script domainkey per creare le domainkey. Lo script dknewkey incluso nella patch dkim fa il suo dovere, gestendo sia le chiavi rsa (con bit qualunque) che quelle ed25519 keys.

Creare dunque la cartella dove saranno salvate tutte le domainkeys e assegnare i privilegi di scrittura all'utente qmailr:qmail se si è deciso di firmare a livello qmail-remote, vpopmail:vchkpw se si è deciso di firmare a livello qmail-smtpd.

mkdir /var/qmail/control/domainkeys
chown -R qmailr:qmail /var/qmail/control/domainkeys

dknewkey usage

Usage: dknewkey [options] keyfile 
options 
      [-p | --print]          : print DKIM public keys 
      [-r | --remove]         : remove DKIM keys 
      [-d | --domain domain]  : domain name 
      [-b | --bits   size]    : DKIM private key size 
      [-t | --type   type]    : Key type (RSA or ED25519) 
      [-e | --enforce]        : Key is not in testing 
      [-f]                    : force DKIM private key creation

Lo script può essere usato per creare una chiave o anche per stampare a video le chiavi appartenti a un dato dominio usando l'opzione -p.

keyfile è il nome del "descriptor" della coppia di chiavi che stiamo andando a generare. Il descriptor è un nome unico che lega insieme la chiave privata e la chiave pubblica. Se non si è sicuri di che nome scegliere per il descriptor, lasciare default come per l'esepio riportato sotto. Se si vuole usare un descriptor diverso, oppure se si deve firmare con la nuova chiave di tipo ed25519, leggere sotto.

Quando si crea una chiave per un dominio domain.tld essa verrà salvata nella cartella /var/qmail/control/domainkeys/domain.tld. La cartella dovrà appartenere all'utente qmailr (l'utente sotto cui viene eseguito qmail-remote), se si opta per firmare i messaggi in uscita a livello qmail-remote, oppure a vpopmail, che è l'utente sotto cui gira qmail-smtpd, se si opta per firmare i messaggi a livello qmail-smtpd. In quest'ultimo caso è necessario modificare leggermente lo script dknewkey affichè attribuisca i privilegi di lettura all'utente vpopmail.

# dknewkey -d domain.tld -t rsa -b 2048 default 
Generating rsa DKIM private key keysize=2048, file /var/qmail/control/domainkeys/domain.tld/default 
Generating rsa DKIM public  key for default.domainkey.domain.tld, file /var/qmail/control/domainkeys/domain.tld/default.pub, keysize=2048 
DKIM Private key for domain.tld file /var/qmail/control/domainkeys/domain.tld/default 
-----BEGIN RSA PRIVATE KEY----- 
MIIEpAIBAAKCAQEArscx1X+i6VEViYZpf9C6Bnd6ME15AxQ5U1T3O7Ts1BS8Z3tZ 
Bdda68Lg+wlc5B+FQaozqeoiQsOWReyD8JDwZ5WTxom4/Ey1XJX7jADUZ0oad/F4 
xxxxxxxxxxx very long xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
14SQHokCgYAkIUAHxYjuRkvzatWdEhI1buuBDWl2ZwpHnQSWxUKqeQdwygGAS78s 
ZMbHhuoW2Xt/Jjbwx7t1faA0TsJkER+P0WP61AbwTKA32SVkhc9yhPizdN7WZDjW 
scC2+bToOgxQK/6+1sfHrqXSEPFscwx/dYTlHyUtbLaYnFMJfSw4Cg== 
-----END RSA PRIVATE KEY----- 
-rw-r----- 1 root qmail 1679 Feb 19 13:12 /var/qmail/control/domainkeys/domain.tld/default 
------------------------------------------------------ 
DKIM TXT record for domain.tld with selector=default file /var/qmail/control/domainkeys/domain.tld/default.pub 
default._domainkey.domain.tld. IN TXT ("v=DKIM1; k=rsa; t=y; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArscx1X+i6VEViYZpf9C6Bnd6ME15AxQ5U1T3O7Ts1BS8Z3tZBdda68Lg+wlc5B+FQaozqeoiQsOWReyD8JDwZ5WTxom4/Ey1XJX7jADUZ0oad/F4a7OT96JaiCKAKX8otBXTwWdQZxk0J7lFxiBpZYA38YB+B3BYdig04MZiDvFe5lCeBpOHPCICZfjY"
       "G/rO9K9LRoMwXG3Raz7lY2XLhhnHrNxjXjUKmvSXySeedkZl/TbJbjO4vQ8+bIrTjvReEF4YXBqAIWQ4XIFy04S1SdhOFIp1kIXR7x8kKpc1vrjUsMg6Pth76FttlLGk0J2g5UYXPxrGVP1YyRHTiNTYPQIDAQAB") 
-rw-r--r-- 1 root qmail 461 Feb 19 13:12 /var/qmail/control/domainkeys/domain.tld/default.pub 
------------------------------------------------------

Questo è il record TXT da inserire nel proprio server DNS.

Se si decide di usare la stessa chiave per tutti i propri domini si deve usare dknewkey senza specificare il dominio come nell'esempio che segue. La chiave verrà allora salvata in /var/qmail/control/domainkeys. L'hostname del server "domain.tld" sarà usato per costruire l'esempio di chiave e si dovrà sostituirlo nel proprio DNS con il dominio reale.

# dknewkey -t rsa -b 1024 default
Generating rsa DKIM private key keysize=1024, file /var/qmail/control/domainkeys/default
Generating rsa DKIM public  key for default.domainkey.domain.tld, file /var/qmail/control/domainkeys/default.pub, keysize=1024
DKIM Private key for sagredo.eu file /var/qmail/control/domainkeys/default
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDHZT/CSiZXwbPIzCmZOWrBV4PR4XV/lPOL3f1GJjRVH5NMZwrr
hTxZ3R6JJN91dIlRbcDGQyEdpQDzjHVZgWfm45fGcVTBpF2JcdCycIXtXxX5N3GM
IUgxtrOI8ZyceMvDnu+wpuI/qhQS/zHi90+Ueth9t7S1cL1QX6ESoNu2awIDAQAB
AoGANAqwDnSt9z+ePe1TeiNrQpUl2ZSfxzHIMxw4a6OzCviXyFwolHoM22OEAcV2
8T/+Sxt7MgP5U7RqQCbLxhWpWTrLvUcSQAy6DJbjLUaf0bdvpIGxa+q7zlB5PAzi
uUWGL9s6HFJzp65heNIoDRTBgmQE9l4nXd3ua1JLSUhMCGECQQDrIX0/xeX8Tuvf
m9BWe7JuYTZ0hmSfwjUoNI5AzbtGCsLNor+lqJ8Q6depseXLwHsrt37SGznd7wcx
eNBCjEYbAkEA2RfNUdUnQISmkR4WQzYIICTnnltVTP7atqSB0gHHKwJqYl7F7FFB
3E1Hr9LxrcmhVKVtbABr0wmIs7F2YgCV8QJBALKWeBwlAn61rt/i58WYJDlEKuks
XmcdSeSkrls4J4KWj8lCUM/RGCfvhLdGAGTWaHcW4wNQXI5di5gezAePpXsCQHG3
NxSre7EfCwUu5mh0cBMuYakgnHEFell7mIkB52sPC9zVWgWslrwoOunNrEzlNj3Z
nZSaL+DOuK2vwpwZRHECQQCtgpPrGGnzO6cAuZi5NmBemii4+RYkNTUaXX2DlSpu
JxPpOSA3nf6OsmMatGdT857I3PNzIq/l8P0vSk3lHWlK
-----END RSA PRIVATE KEY-----
-rw-r----- 1 root qmail 887 Mar  8 19:05 /var/qmail/control/domainkeys/default
------------------------------------------------------
DKIM TXT record for domain.tld with selector=default file /var/qmail/control/domainkeys/default.pub
default._domainkey.domain.tld. IN TXT ("v=DKIM1; k=rsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHZT/CSiZXwbPIzCmZOWrBV4PR4XV/lPOL3f1GJjRVH5NMZwrrhTxZ3R6JJN91dIlRbcDGQyEdpQDzjHVZgWfm45fGcVTBpF2JcdCycIXtXxX5N3GMIUgxtrOI8ZyceMvDnu+wpuI/qhQS/zHi90+Ueth9t7S1cL1QX6ESoNu2awIDAQAB")
-rw-r--r-- 1 root qmail 282 Mar  8 19:05 /var/qmail/control/domainkeys/default.pub
------------------------------------------------------​

Ricordarsi di cancellare il tag t=y (modalità testing attiva) una volta terminata la fase di test.

Nel caso si abbiano problemi a inserire un record così lungo nel proprio DNS, a causa del fatto che il proprio pannello di controllo non gestisce bene i record su due righe, creare una chiave a 1024 bit, che è compresa in una sola riga, ed evitare di usare l'opzione DKIMSIGNOPTIONS="-z 2" più sotto.

Configurazione di qmail-remote per la firma e di qmail-smtpd per la verifica dei messaggi

Riferimenti:

rc script

Ecco come modificare il proprio script /var/qmail/rc affichè qmail-remote firmi in uscita i messaggi.

#!/bin/sh 

QMAILDIR=/var/qmail 

# Comment out DKIM_ON=1 to disable dkim sign at qmail-remote level 
# You have to define your variables in control/filterargs (DKIM page for more info)
# echo "*:remote:/var/qmail/bin/qmail-dkim:DKIMQUEUE=/bin/cat,DKIMSIGN=/var/qmail/control/domainkeys/%/default,DKIMSIGNOPTIONS=-z 2" > /var/qmail/control/filterargs
DKIM_ON=1 

if [ -r $QMAILDIR/control/filterargs ] &&[ -n "$DKIM_ON" ]; then 
  # DKIM sign at qmail-remote level
  exec env - PATH="$QMAILDIR/bin:$PATH" \ 
  QMAILREMOTE=$QMAILDIR/bin/spawn-filter \ 
  qmail-start "`cat $QMAILDIR/control/defaultdelivery`" 
else 
  # Use this if you are signing at qmail-smtpd level or you don't want to sign at all 
  exec env - PATH="$QMAILDIR/bin:$PATH" \ 
  qmail-start "`cat $QMAILDIR/control/defaultdelivery`" 
fi

Creiamo il file control/filterargs, che serve istruire spawn-filter su quale programma lanciare e con quali parametri:

echo "*:remote:/var/qmail/bin/qmail-dkim:DKIMQUEUE=/bin/cat,DKIMSIGN=/var/qmail/control/domainkeys/%/default,DKIMSIGNOPTIONS=-z 2" > /var/qmail/control/filterargs

La variabile QMAILREMOTE fa sì che qmail chiami spawn-filter prima che il messaggio sia collocato in coda, il quale a sua volta eseguirà un filtro a scelta dichiarato attraverso la variabile FILTERARGS, nel nostro caso qmail-dkim. Per un controllo più preciso a livello di singoli domini si può usare il control file filterargs (man spawn-filter). Inoltre si può usare QMAILLOCAL per firmare anche le email spedite agli utenti del vostro server stesso.

qmail-dkim utilizzerà come come locazione della domainkey il file /var/qmail/control/domainkeys/%/default. Il simbolo '%' verrà automaticamente sostituito con il dominio del mittente. Naturalmente si potrà decidere di firmare tutti domini con un singola firma collocata in /var/qmail/control/domainkeys/default

Per personalizzazioni sul selector da usare oppure sulla locazione della chiave si veda il man spawn-filter per un uso avanzato del file control/filterargs oppre di control/domainkeys.

qmail-smtpd/run script

Inserire le seguenti variabili di ambiente nel proprio run file /var/qmail/supervise/qmail-smtpd/run:

export QMAILQUEUE=/var/qmail/bin/qmail-dkim
export DKIMVERIFY="FGHKLMNOQRTVWp"
# This is to allow msg without "subject" in the h= list
# export UNSIGNED_SUBJECT=1
# This is to avoid verification of outgoing messages
export RELAYCLIENT_NODKIMVERIFY=1

Dichiarando UNSIGNED_SUBJECT si possono ammettere le email di alcuni providers che non firmano il subject (maggiori informazioni qui). Ciò però consentirebbe a uno spammer di modificare il subject senza invalidare per questo la firma, quindi usare questa opzione a proprio rischio (io l'ho dovuta abilitare per non rigettare i messaggi provenienti da libero.it).

Dichiarando RELAYCLIENT_NODKIMVERIFY si evita che qmail-dkim verifichi i propri messaggi in uscita.

Per scegliere al meglio le opzioni per la verifica dei messaggi leggere la pagina man di qmail-dkim.

Test

Test della firma

Faremo il test come qmailr, l'utente che esegue qmail-remote e che ha i privilegi di lettura della chiave.

E' necessario impostare la variabile di ambiente DKIMSIGN o DKIMKEY. Quindi settare DKIMQUEUE=/bin/cat di modo che il risultato sia mostrato a video.

DOMAIN=domain.tld 
RSA2048_SELECTOR=default 

( 
echo "From: postmaster@${DOMAIN}" 
echo "To: postmaster@${DOMAIN}" 
echo "Subject: Test" 
echo "Date: $(date -R)" 
echo 
echo "Test message" 
) > /tmp/mail.txt 

sudo -u qmailr env - \ 
  QMAILREMOTE=/var/qmail/bin/spawn-filter \ 
  CONTROLDIR=/tmp/control \ 
  DKIMSIGN=/var/qmail/control/domainkeys/%/${RSA2048_SELECTOR} \ 
  DKIMSIGNOPTIONS="-z 2" \ 
  DKIMQUEUE=/bin/cat \ 
  /var/qmail/bin/qmail-dkim < ${MSG}

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; 
       d=domain.tld; s=default; h=From:To:Subject:Date; bh=PkbvdhgKiEAA 
       hc+GiwM2ZnxMu+StJ76lWGj3Y9phfFA=; b=W1M3ZoTi+qcb/WwfJK7RIbf3ad0N 
       dBFTEBBDCqcWWnWVptuuILY4uTqq5bAfVEZZGb2O+6f1wuLvwXGbmM2jWvKwXQjJ 
       sFx7EkM+sJ5OtkwIHa/Lu3B91enXHF0bdXwSxkLcqU92UftFzIxArce4XBNBZ9gK 
       QujGix2TkuCOzwGwv3fytt4gizA6yFg+7lbih3m5pAi+MH77yWywpHEA1Ffl1pqh 
       JHbX5eM+THXovWFyOCY2tcijFSjMV53SUnckDHZd3sEZHbrM2iv7SUni2Wb/9Yvz 
       /4vGqRqJ0ZAzVqqfdL1kN+SBRV117ZyzNcS2jl+0sMnuDADy/hRD54n46A== 
From: postmaster@domain.tld
To: postmaster@domain.tld
Subject: Test 
Date: Sun, 19 Feb 2023 18:01:34 +0100 

Test message

In questo esempio CONTROLDIR=/tmp/control assicura che nulla di quanto definito in control/dkimkeys interferisca con questo test (le variabili vengono passate a mano).

Mandare un messaggio a sè stessi a guardare la firma DKIM nell'header:

DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed;
    d=yourdomain.xy; s=private; x=1298156019; h=to:from:subject;
    bh=tVrwKZaEzYO4qmI9mPfR04ZvZik=; b=r2VH/6rQdY6xcPjyg55ULnf7U+DEs
    +apecicwvygIZVvQwxU4NqiqAQGTF3Qkft2eBDu42TBzX4nV7FTs8wzn40iGkfhB
    mMZhQdcyOseg7DyOFKUK5D8Ji3ueF/xgYFUnffrxPdZUMpGN9+dA9fY0wkonp5ML
    dDSaNje9mmd34I=

Test della verifica

Assumerò qui che vpopmail sia l'utente che esegue qmail-smtpd.

DOMAIN=domain.tld

( 
echo "From: postmaster@${DOMAIN}" 
echo "To: postmaster@${DOMAIN}" 
echo "Subject: Test" 
echo "Date: $(date -R)" 
echo 
echo "Test message" 
) > /tmp/mail.txt 

sudo -u vpopmail env - \ 
DKIMQUEUE=/bin/cat \ 
/var/qmail/bin/qmail-dkim < /tmp/mail.txt

DKIM-Status: no signatures 
From: postmaster@domain.tld 
To: postmaster@domain.tld 
Subject: Test 
Date: Sun, 19 Feb 2023 19:58:22 +0100 

Test message

Mandare un messaggio a sè stessi ad esempio da un account gmail.com (che ha la firma DKIM) e controllare l'header. Il messaggio è stato verificato se si ha questa linea nell'header:

DKIM-Status: good

Ecco come testare la firma di un messaggio che è stato preventivamente salvato su disco come email.txt (non creare il file come cut&paste per evitare spazi bianchi accidentali che compremetterebbero la validazione del body, salvare su disco alla maniera normale):

> /var/qmail/bin/dkim -vS < /path/to/email.txt
DKIM-Status: good 

Testare il record DNS

Infine, inviare una mail a check-auth@verifier.port25.com con "test" come oggetto. Vi risponderanno con un messaggio che conterrà i risultati del test e così saprete se la configurazione del vostro  DNS è corretta.

E' anche possibile controllare se il proprio record dns è scritto in modo corretto attraverso questa pagina https://mxtoolbox.com/dkim.aspx.

Come far sì che qmail-dkim e simscan vivano insieme felici

[Se simscan non è ancora stato installato si può saltare questo passaggio. qmail non funzionerà con le direttive seguenti senza simscan]

Come certamente saprai, anche simscan ha bisogno di chiamare qmail-queue e deve essere anche lui incluso nella variabile di ambiente QMAILQUEUE, proprio come qmail-dkim. Lo stesso dovrebbe succedere con altri scanner per l'email..

Si può risolvere il problema assegnando qmail-dkim a QMAILQUEUE e simscan alla variabile DKIMQUEUE. In questo caso qmail-dkim chiamerà simscan quando avrà finito il suo lavoro.

Per far ciò è necessario modificare come seguee lo script di avvio di qmail-smtpd /var/qmail/supervise/qmail-smtpd/run (ed eventualmente anche /var/qmail/supervise/qmail-submission/run)

export QMAILQUEUE=/var/qmail/bin/qmail-dkim
export DKIMQUEUE=/var/qmail/bin/simscan

Configuring qmail-smtpd for signing outgoing messages

Si salti questo paragrafo se si è deciso di apportare la firma attraverso qmail-remote.

qmail-smtpd run script

Innanzitutto è bene sapere che il file control/me è il dominio che verrà usato per la firma dei messaggi di sistema senza mittente (null sender "<>"). Questi messaggi di sistema sono dei "rimbalzi" inviati dal nostro server che devono essere firmati pena il loro rigetto proprio a seguito della mancanza della firma (filtro DKIM e DMARC). Questo dominio deve essere contenuto nella variabile DKIMDOMAIN.

Inserire le seguenti variabili d'ambiente nel proprio /var/qmail/supervise/qmail-smtpd/run script:

export QMAILQUEUE=/var/qmail/bin/qmail-dkim
export DKIMKEY=/usr/local/etc/domainkeys/%/default
export DKIMDOMAIN=`cat /var/qmail/control/me`

# declaring NODK disables domainkey
# declaring NODKIM disables DKIM
export NODK=1

qmail-dkim firmerà i messaggi se la variabile RELAYCLIENT è stata impostata (guardare il file tcp.smtp) ed eseguirà la verifica in tutti i messaggi degli IP per cui quali RELAYCLIENT non è stata impostata.

DKIMKEY è la posizione della chiave. Il simbolo '%' verrà automaticamente sostituito con  is con il dominio del mittente. Naturalmente si può decidere di firmare tutti i domini con una singola chiave collocata in /usr/local/etc/domainkeys/default.

Testing

In questo test qmail-dkim assume che la chiave sia memorizzata nella cartella /var/qmail/control/domainkeys, quindi se le proprie chiavi sono memorizzate altrove sarà necessario creare un link simbolico.

DOMAIN=domain.tld

( 
echo "From: postmaster@${DOMAIN}" 
echo "To: postmaster@${DOMAIN}" 
echo "Subject: Test" 
echo "Date: $(date -R)" 
echo 
echo "Test message" 
) > /tmp/mail.txt

sudo -u vpopmail env - \
   DKIMQUEUE=/bin/cat \
   DKIMKEY=/var/qmail/control/domainkeys/%/default
   RELAYCLIENT=""
   /var/qmail/bin/qmail-dkim < /tmp/mail.txt

DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed;
        d=domain.tld; s=default; x=1298483339; h=To:From:Subject;
        bh=6rJdFs2WVS8T72i61KhaAvC6O6s=; b=ffnXBB98Gg6iZFEIL6alk8c5davso
        ozyrunXM3C8qaejIrJOwYhnlWQwSdrV599WErmJcDYyMjFjVgLzRQ9OTeYHjEnHT
        X/aiIkvjcxRuOaTK7PcwrcJGdtF0c6LWoK9RgiPctCw7DMcHGmUcSyXWc6ayzHgX
        A7nopQYuHzTuIU=
From: postmaster@domain.tld 
To: postmaster@domain.tld 
Subject: Test 
Date: Sun, 19 Feb 2023 19:58:22 +0100

Test message

Scegliere tra DKIMSIGN e DKIMKEY

  • man qmail-dkim(8) for more info
Questa è la logica che c'è sotto così come mi stata spiegata dall'autore della patch dkim:
  1. If RELAYCLIENT is defined and both DKIMSIGN and DKIMVERIFY are not defined then qmail-dkim looks for DKIMKEY for the private key to sign. If DKIMKEY is not defined, then control/domainkeys/%/default is used

  2. If RELAYCLIENT is not defined, then qmail-dkim uses DKIMSIGN for the key

  3. If RELAYCLIENT is not defined and both DKIMSIGN and DKIMVERIFY is defined, then qmail-dkim ignores DKIMVERIFY
  4. If the key has % in the filename, then it is replaced with the domain name from the From/Sender header. After substituting %, if the private key is not found, the qmail-dkim removes the % and again checks for the key. e.g. strace shows this

    access("control/domainkeys/mydomain.org/default", F_OK) = -1 ENOENT (No such file or directory)
    open("control/domainkeys/default", O_RDONLY|O_NONBLOCK) = 5
  5. If the key has % in the filename and the private key does not exists, then qmail-dkim exits without signing and without any failure. Hence messages will pass through. The reason for this behaviour is i have many clients who run multiple domains on a server and they need DKIM only for few domains.

  6. If the key does not have % sign and the private key does not exist, then qmail-dkim exits with 32 resulting in permanent failure  

    "Private key file does not exist (#5.3.5)"
  7. If none of the variables RELAYCLIENT, DKIMSIGN, DKIMVERIFY are defined, qmail-dkim does verification

Apportare firme multiple. Personalizzare il selector.

  • man dkim per maggiori informazioni

A partire dalla versione 1.37 della patch dkim abbiamo il supporto a ed25519, un nuovo algoritmo di firma crittografica per DKIM aggiunto con la RFC 8463. Al momento nessuno firma e tanto meno verifica la firma con questo algoritmo. Pertanto la raccomandazione di questa RFC è di apportare due firme: una per rsa e una per ed25519.

Assumendo che abbiamo già la nostra vecchia firma rsa, ecco come generare la firma ed25519 con dknewkey:

# dknewkey -d domain.tld -t ED25519 ed25519 
Generating ed25519 DKIM private key keysize=2048, file /var/qmail/control/domainkeys/domain.tld/ed25519 
Generating ed25519 DKIM public  key for ed25519.domainkey.domain.tld, file /var/qmail/control/domainkeys/domain.tld/ed25519.pub 
DKIM Private key for domain.tld file /var/qmail/control/domainkeys/domain.tld/ed25519 
-----BEGIN PRIVATE KEY----- 
MC4CAQAwBQYDK2VwBCIEIBdgashw5uHx2zxoDCRyIUvPp7Le0d0ljtKiwFreQo58 
-----END PRIVATE KEY----- 
-rw-r----- 1 root qmail 119 Feb 19 13:52 /var/qmail/control/domainkeys/domain.tld/ed25519 
------------------------------------------------------ 
DKIM TXT record for domain.tld with selector=ed25519 file /var/qmail/control/domainkeys/domain.tld/ed25519.pub 
ed25519._domainkey.domain.tld. IN TXT ("v=DKIM1; k=ed25519; t=y; p=l+ZydrxSK4GvFEQvVTKaFxY3+LUh4cCxktsLy8Y2Gl8=") 
-rw-r--r-- 1 root qmail 114 Feb 19 13:52 /var/qmail/control/domainkeys/domain.tld/ed25519.pub 
------------------------------------------------------

In questo esempio "ed25519" è il nome del selector per la chiave ed25519.

Ora vediamo come gestire chiave multiple e come personalizzare il selector con le funzionalità avanzate del file control/dkimkeys disponibili con la nuova patch dkim-1.37.

Il formato del file /var/qmail/control/dkimkeys contempla l'uso di wildcards e di espressioni regolari, e può essere usato per personalizzare il nome del selector e/o per definire chiavi multiple per un dato dominio.

L'esempio qui sotto è relativo a domini come example.*. Viene dichiarata una chiave rsa e una chiave ed25519.

example.*:/var/qmail/control/domainkeys/%/rsa2048,DKIMSIGNOPTIONS=-z 2,DKIMSIGNEXTRA=/var/qmail/control/domainkeys/%/ed25519,DKIMSIGNOPTIONSEXTRA=-z 4

Le variabili DKIMSIGN e DKIMSIGNOPTIONS appartengono alla prima chiave, che ha il selector rsa2048. DKIMSIGNOPTIONS=-z 2 specifica che l'hash di questa chiave è rsa-sha256 (rsa a 2048 bit).

DKIMSIGNEXTRA e DKIMSIGNOPTIONSEXTRA si riferiscono invece alla seconda chiave dichiarata, chge ha selector ed25519. DKIMSIGNOPTIONSEXTRA=-z 4 indica che essa avrà hash  ed25519.

NOTA: usare la sintassi DKIMSIGNOPTIONSEXTRA=-z 4 e non DKIMSIGNOPTIONSEXTRA="-z 4" in questo file.

Il formato del file dkimkeys è:

domain.tld:dkim_private_key_file_path[:OPTION1=1,OPTION2=2,OPTION3=3 ...]

Nota: domain può essere una espressione regolare alla portata di egrep, per esempio sagr*.* comprenderà domini come sagredo.eu, sagredo.com. ecc.

Si possono avere linee multiple nel file control file /var/qmail/control/dkimkeys. Se ci sono match multipli, verrà utilizzato il primo.

Come sempre, il nome del file della chiave privata sarà usato come selector, quindi sarà necessario creare un link simbolico tra il selector e la chiave privata.

Quando DKIMSIGN o DKIMKEY hanno il carattere '%', esso sarà rimpiazzato da domain.tld. Se dopo la sostituzione la chiave privata non viene trovata, il carattere '%' sarà rimosso.

Per esempio se DKIMSIGN=/var/qmail/control/domainkeys/%/private e il file /var/qmail/control/domainkeys/sagredo.eu/private non viene trovato, dk-filter userà  /var/qmail/control/domainkeys/private come file per la chiave privata.

Test

Per testare la doppia firma è sufficiente ripetere il test menzionato più sopra aggiungendo le variabili DKIMSIGNEXTRA e DKIMSIGNOPTIONSEXTRA per la firma ed25519.

DOMAIN=domain.tld
RSA2048_SELECTOR=default 
ED25519_SELECTOR=ed25519 

( 
echo "From: postmaster@${DOMAIN}" 
echo "To: postmaster@${DOMAIN}" 
echo "Subject: Test" 
echo "Date: $(date -R)" 
echo 
echo "Test message" 
) > /tmp/mail.txt 

sudo -u qmailr env - \ 
  QMAILREMOTE=/var/qmail/bin/spawn-filter \ 
  CONTROLDIR=/tmp/control \ 
  DKIMQUEUE=/bin/cat \
  DKIMSIGN=/var/qmail/control/domainkeys/%/${RSA2048_SELECTOR} \ 
  DKIMSIGNOPTIONS="-z 2" \ 
  DKIMSIGNEXTRA=/var/qmail/control/domainkeys/%/${ED25519_SELECTOR} \ 
  DKIMSIGNOPTIONSEXTRA="-z 4" \ 
  /var/qmail/bin/qmail-dkim < /tmp/mail.txt

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; 
       d=domain.tld; s=default; h=From:To:Subject:Date; bh=PkbvdhgKiEAA 
       hc+GiwM2ZnxMu+StJ76lWGj3Y9phfFA=; b=W1M3ZoTi+qcb/WwfJK7RIbf3ad0N 
       dBFTEBBDCqcWWnWVptuuILY4uTqq5bAfVEZZGb2O+6f1wuLvwXGbmM2jWvKwXQjJ 
       sFx7EkM+sJ5OtkwIHa/Lu3B91enXHF0bdXwSxkLcqU92UftFzIxArce4XBNBZ9gK 
       QujGix2TkuCOzwGwv3fytt4gizA6yFg+7lbih3m5pAi+MH77yWywpHEA1Ffl1pqh 
       JHbX5eM+THXovWFyOCY2tcijFSjMV53SUnckDHZd3sEZHbrM2iv7SUni2Wb/9Yvz 
       /4vGqRqJ0ZAzVqqfdL1kN+SBRV117ZyzNcS2jl+0sMnuDADy/hRD54n46A== 
DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; 
       d=domain.tld; s=ed25519; h=From:To:Subject:Date; bh=PkbvdhgKiEAA 
       hc+GiwM2ZnxMu+StJ76lWGj3Y9phfFA=; b=JzENCy7Xmtp/BW+xRPdHJuao+gTu 
       q182WxDSu+YDAyBEbEJw3fFDWcDEWuKFETV0f3HMdtn6G4Gt+0+w4WrkDA== 
From: postmaster@domain.tld
To: postmaster@domain.tld
Subject: Test 
Date: Sun, 19 Feb 2023 18:01:34 +0100 

Test message

CONTROLDIR=/tmp/control assicura che il programma non legga nulla di quanto contenuto nella cartella qmail/control directory, dkimkeys per esempio. Per testare control/dkimkeys, ripetere lo stesso test rimuovendo CONTROLDIR, DKIMSIGN e DKIMSIGNOPTIONS.

Commenti

domainkeys valore di t

Ciao  Roberto,
per un server in produzione devo cambiare il valore "t" da "y" nei TXT records a "n" oppure lo posso lasciare come lo genera lo script? Forse mi conviene modifcare lo script dato che faccio copia e incolla! :-)

Bellissima guida.

Grazie.Adele

Rispondi |

domainkeys valore di t

Ciao Adele, potresti anche togliere del tutto il campo t=y

Rispondi |

Cambio da rsa-sha1 a rsa-sha256 per dkim

Ottima guida, volevo chiedre come poter cambiare la versione dell'hash di firma per dkim da rsa-sha1 a rsa-sha256 in quanto piu' sicura

Rispondi |

Credo che dovresti editare lo

Credo che dovresti editare lo script  e settare appositamente openssl, vedi il man. Fammi sapere....

Rispondi |