Server Name Indication (SNI) è una estensione del protocollo TLS che consente a un server di presentare differenti certificati a seconda dell'hostname richiesto dal client durante il saluto TLS.
In un ambiente email moderno, molti domini condividono uno stesso indirizzo IP per i servizi SMTP, IMAP, POP3 e submission. Senza SNI, un amministratore di un server email può presentare un solo certificato per ogni socket disponibile, cosa che obbliga l'aministratore ad affidarsi a certificati multi-dominio (SAN) o a certificati con wildcard. Questo approccio aumenta i problemi operativi tra gli utenti finali novelli, che spesso non sono in grado di usare la configurazione automatica del client per configurare correttamente le loro mailbox.
L'abilitazione di SNI nei serivizi mail consente al server di presentare il certificato appropriato basato sull'hostname richiesto dal client, contenuto nel suo indirizzo email.
La funzionalità SNI per la mia distribuzione qmail è stata aggiunta da Andreas Gerstlauer (commit qui e qui), che vorrei ringraziare.
Creazione dei certificati
- Il mio script hook per
dehydrated
Supponiamo di voler creare certificati differenti per domain1.tld e per domain2.tld. Usiamo dehydrated per creare i due certificati. Modificare /etc/dehydrated/domains.txt in questo modo:
domain1.tld imap.domain1.tld pop3.domain1.tld smtp.domain1.tld domain2.tld imap.domain2.tld pop3.domain2.tld smtp.domain2.tld
Come sappiamo, non appena si lancia il comando dehydrated -c, uno specifico certificato viene costruito per ciascuna rige in domains.txt. Il nome di ciascun certificato corrisponde al primo dominio della riga, mentre gli altri domini di quella riga sono nomi alternativi (SAN) per lo stesso certificato. E' necessario mettere lì tutti domini che le procedure automatiche dei client di posta cercheranno di immaginare metre si configura la mailbox. Per esempio, se si sta configurando roberto@sagredo.eu, la procedura automatizzata probabilmente controllerà l'esistenza di smtp.sagredo.eu per il server SMTP e imap.sagredo.eu per l'IMAP.
In qmail, quando il client supporta SNI, i certificati SSL di domini specifici devono essere impostati nel seguente modo:
QMAILDIR/control/servercerts/<FQDN>/servercert.pem
Ho modificato lo script hook.sh per dehydrated al fine di salvare il primo certificato (prima riga in domains.txt) in
QMAILDIR/control/servercert.pem
e tutti gli altri certificati, a partire dalla riga due, in
QMAILDIR/control/servercerts/<FQDN>/servercert.pem
QMAILDIR/control/servercert.pem è usato come default, nel caso non possa essere trovato nel server un certificato appropriato per l'hostname richiesto.
Nel nostro esempio è necessario preparare i seguenti certificati:
QMAILDIR/control/servercert/servercert.pem QMAILDIR/control/servercerts/domain2.tld/servercert.pem
Riguardo a dovecot, è necessario dichiarare i certificati addizionali per SNI nel modo seguente:
local_name domain2.tld {
ssl_server_cert_file = /etc/dehydrated/certs/domain2.tld/fullchain.pem
ssl_server_key_file = /etc/dehydrated/certs/domain2.tld/privkey.pem
}
local_name *.domain2.tld {
ssl_server_cert_file = /etc/dehydrated/certs/test.sagredo.eu/fullchain.pem
ssl_server_key_file = /etc/dehydrated/certs/test.sagredo.eu/privkey.pem
}
Queste impostazioni per dovecot vengono aggiunte in automatico dallo script hook.sh.
Test dei certificati
Per testare SNI con openssl è necessario passare l'opzione -servername.
openssl s_client -starttls smtp -connect serverIP:587 -servername domain2.tld 2>/dev/null | grep subject=CN
In pratica, ci stiamo connettendo all'IP del mail server e richiedendo un certificato per il dominio domain2.tld. Se il server non fornisce un certificato per domain2.tld, allora verrà servito quello di default, che è /var/qmail/control/servercert.pem.
Alla fine del certificato abbiamo il Common Name (CN):
subject=CN = domain2.tld
che il FQDN per il quale il certificato è stato rilasciato. Se si ottiene domain2.tld o smtp.domain2.tld o ogni altro dominio avente domain2.tld come dominio di secondo livello, allora SNI sta funzionando bene e il client è in grado di indicare il certificato associato al dominio dal quale si sta connettendo.
Stesso esempio per i protocolli IMAP e POP3:
# openssl s_client -connect serverIP:995 -servername domain2.tld 2>/dev/null | grep subject=CN subject=CN = domain2.tld # openssl s_client -connect serverIP:993 -servername domain2.tld 2>/dev/null | grep subject=CN subject=CN = domain2.tld
Il SAN (Subject Alternative Name) del certificato è la lista dei domini che sono protetti da quel certifcato:
# openssl x509 -in /var/qmail/control/servercert.pem -noout -text | grep -A1 "Subject Alternative Name" X509v3 Subject Alternative Name: DNS:domain1.tld, DNS:smtp.domain1.tld, DNS:imap.domain1.tld, DNS:pop3.domain1.tld,
Si può ottenere il SAN quando ci si connette da remoto nel modo seguente:
openssl s_client -starttls smtp -connect domain1.tld:587 2>/dev/null | openssl x509 -noout -text | grep -A1 "Subject Alternative Name"

