Postfix: forzare il dialogo cifrato fra due MTA

ECCETTO RESIDENTIÈ possibile forzare il dialogo cifrato TLS tra due server di posta elettronica (MTA).

Di seguito viene spiegato come farlo con Postfix 2.10.2, l’ultima disponibile, compilata sul server in cui gira con il supporto TLS attivato. È naturalmente possibile ottenere lo stesso risultato anche con altri MTA o con versioni precedenti di Postfix (sconsiglio di scendere sotto la 2.6.0 ed è meglio evitare il range  2.9.0 – 2.9.5 (incluse) perché hanno un baco nel calcolo del fingerprint della chiave pubblica.

È fondamentale una certa padronanza con Postfix, che viene data per scontata dalla procedura descritta di seguito.

Lo scopo è forzare l’MTA ad utilizzare una connessione via TLS quando dialoga con un altro MTA noto. Per fare ciò non è necessario un certificato rilasciato da una CA nota, ma va benissimo anche un certificato autogenerato. Lo scopo di questa configurazione è proprio quello di non utilizzare necessariamente la PKI.

Se si dispone di un certificato rilasciato da una CA, configurare Postfix come descritto in questo articolo. Se si vuole generare una coppia di chiavi si possono utilizzare gli script che si trovano in giro come ad esempio questo:

KEY=mail.acme.com.key
UKEY=mail.acme.com.key.unencrypted
CSR=mail.acme.com.csr
CRT=mail.acme.com.crt
openssl genrsa -des3 -rand /dev/urandom -out $KEY 1024
chmod 600 $KEY
openssl req -new -key $KEY -out $CSR -rand /dev/urandom
openssl x509 -req -days 3650 -in $CSR -signkey $KEY -out $CRT
openssl rsa -in $KEY -out $UKEY
mv $UKEY $KEY

In un modo o nell’altro abbiamo un paio di chiavi e abbiamo detto a Postfix di utilizzarle. Bisogna abilitare smtps nel file master.cf aggiungendo (o scommentando) queste righe

smtps     inet  n       -       n       -       -       smtpd
  -o smtpd_tls_wrappermode=yes

La prima opzione dice sostanzialmente di usare il TLS sulla porta 25 anziché su una porta dedicata e deve essere specificata qui come suggerito dalla documentazione. A seconda della configurazione dell’MTA potrebbe essere necessario indicare altri parametri.

Bisogna tenere presente che nella configurazione di Postfix tutto quello che inizia con smtp_ è riferito alle connessioni in cui Postfix agisce da client SMTP (invia la mail) mentre tutto quello che inizia con smtpd_ è riferito al comportamento di Postfix come server SMTP (riceve la mail). Nel file main.cf è bene tenere separati i gruppi smtp_ e smtpd_ relativi alle connessioni TLS per evitare di far confusione.

Se l’autenticazione del server a cui ci si collega non viene fatta tramite PKI deve essere fatta tramite una chiave nota, che in questo caso è il fingerprint del certificato del server SMTP: la validazione è eseguita dal client SMTP quando si collega al server: lo scopo di tutto questo setup è di spedire la mail al server giusto e di farlo in maniera sicura. La documentazione viene ancora una volta in aiuto e spiega i due modi per ottenere il fingerprint del server SMTP: o lo si estrae con una command line abbastanza complessa oppure si abilita smtp_tls_loglevel = 2 e lo si legge dal log. La seconda opzione è sicuramente la migliore e fornisce il risultato più attendibile.

Prendiamo quindi due MTA con l’ultima versione di Postfix, configuriamo le chiavi, modifichiamo master.cf come indicato sopra e aggiungiamo questo a main.cf (dopo aver verificato che non sia in conflitto con altre opzioni):

smtp_tls_security_level = may
smtp_tls_note_starttls_offer = yes
smtp_tls_fingerprint_digest = sha1
smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
smtp_tls_loglevel = 2
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtp_tls_session_cache_timeout = 3600s

smtpd_tls_security_level = may
smtpd_tls_received_header = yes
smtpd_tls_loglevel = 2
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom

Per maggiore sicurezza si può aggiungere anche soft_bounce = yes per evitare che vada perso qualche messaggio legittimo, ricordandosi poi di toglierlo o di impostarlo a no alla fine dei test. Se il server è headless oppure è una macchina virtuale, sarebbe opportuno installare haveged per aumentare l’entropia del generatore di numeri casuali e, quindi, la sicurezza delle comunicazioni.

Resta solamente da popolare la tabella tls_policy dove andremo a dire il comportamento da tenere per ogni destinatario. Di seguito vengono fatti solamente alcuni esempi generici, per conoscere tutte le opzioni disponibili è bene rifarsi alla documentazione.

tls_policy contiene delle coppie di valori in cui il primo valore è il dominio del destinatario (attenzione: il dominio, non il FQDN del MTA di destinazione) e il secondo è il comportamento con eventuali coppie nome=valore aggiuntive che sovrascrivono alcuni parametri generali di main.cf. Dal momento che è definito come hash: bisogna ricordarsi che dopo ogni modifica al file bisogna eseguire il comando postmap tls_policy

Vediamo un esempio.

nessunasicurezza.com  none
relayinsicuro.com     may
crittato.com          fingerprint 
   match=12:34:56:78:00:0C:AF:FE:00:BE:EF:00:BA:DD:EC:AF

In questo caso quando Postfix invia una mail ai destinatari @nessunasicurezza.com disabilita il TLS del tutto. Quando invia una mail a @relayinsicuro.com abilita il cosiddetto opportunistic TLS: se la sessione TLS va a buon fine, Postfix procede in modo sicuro, altrimenti riprova ad inviare la mail senza TLS; questo è il tipico caso di nome a dominio con un MX di backup di un provider che non supporta TLS. Postfix in questo caso non prevede la possibilità di indicare un comportamento specifico per ogni mail server di uno stesso nome a dominio. In un certo senso, un comportamento diverso per diversi MX dello stesso dominio avrebbe poco senso perché comunque la sicurezza totale sarebbe quella della connessione meno sicura.

Il terzo destinatario, @crittato.com, è quello che ci interessa. Quando Postfix invia una mail a @crittato.com verifica che il server di destinazione non solo supporti TLS ma abbia una chiave il cui fingerprint è quello indicato (se ne può specificare anche più d’uno). Se il server di destinazione non presenta una chiave con quel fingerprint, la mail non viene inoltrata.

Come detto, il fingerprint da inserire dopo match= è facilmente individuabile nel log di Postfix se si imposta smtp_tls_loglevel = 2. Dopo aver attivato la configurazione indicata sopra proviamo ad inviare una mail a @crittato.com, che fallirà perché è stato messo un fingerprint a caso (oppure si può specificare temporaneamente may). Il log della transazione SMTP ad un certo punto presenta una riga simile a questa:

postfix/smtp[1234]: mail.crittato.com[1.2.3.4]:25: subject_CN=mail.crittato.com, fingerprint=01:90:4E:F1:93:49:71:70:12:37:EA:08:4D:E4:D8:2C:56:26:67:20, pkey_fingerprint=12:34:56:78:00:0C:AF:FE:00:BE:EF:00:BA:DD:EC:AF

La sequenza esadecimale che segue pkey_fingerprint= è quella da mettere dopo match= nel file tls_policy ricordando sempre di eseguire postmap tls_policy dopo la modifica al file.

Una volta terminati i test, si può abbassare il livello di log di smtp_tls_loglevel e disabilitare il soft_bounce.

L’implementazione di TLS in un MTA non è una passeggiata, ma non è nemmeno una difficoltà insormontabile; è necessario tempo per leggere la documentazione e fare le prove necessarie, senza prendere scorciatoie, che sono tra le insidie di una buona sicurezza. Dal momento che il supporto di TLS è abbastanza eterogeneo, è bene tenere bene d’occhio i log dell’MTA nei primi tempi dopo l’attivazione per evitare rimbalzi indesiderati. Bisogna anche considerare il fatto che, abilitando TLS, si abilita una libreria composta da migliaia di righe di codice che non è garantita come infallibile.

Autore: Luigi Rosa

Consulente IT, sviluppatore, SysAdmin, cazzaro, e, ovviamente, geek.

Un pensiero riguardo “Postfix: forzare il dialogo cifrato fra due MTA”

Spazio per un commento