Cela fait plusieurs fois que j'évoque DANE TLSA sur ce shaarli. L'idée est de stocker dans le DNS, signé cryptographiquement avec DNSSEC afin de garantir l'intégrité et l'authenticité des informations, les certificats x509 que nous utilisons dans nos transactions TLS afin de fermer les failles béantes du modèle de sécurité x509. Et de pouvoir se passer des centres de concentration du pouvoir que constituent les autorités de certification (AC) qui sont des sociétés commerciales qui vendent exclusivement du vent.
Pour approfondir la théorie :
Notons que DANE ne s'occupe pas seulement de TLS mais est beaucoup plus vaste. Exemple : le stockage des clés OpenPGP dans le DNS est normalisé, voir http://www.bortzmeyer.org/7929.html .
Je considère la théorie acquise et je n'y reviendrai pas. L'objectif est de tester DANE TLSA dans des conditions réelles sur mes serveurs persos. J'avais déjà tenté en 2014 mais j'étais restait bloqué sur la lib ldns qui ne prenait pas en charge les enregistrements DNS de type TLSA.
En effet, lors d'un futur renouvellement d'un certificat associé à un enregistrement TLSA, il faudra générer le certificat, générer son enregistrement TLSA, publier ce dernier dans votre zone DNS, attendre puis seulement ensuite mettre le certificat en production sur vos serveurs (web, mail, etc.).
ÉDIT DU 14/01/2017 À 17H45 : En fait, ce n'est pas aussi simple, comme nous le verrons de manière elliptique dans la section « Conception » ci-dessous :
FIN DE L'ÉDIT.
Il faut attendre combien de temps ? Cela dépend du TTL de l'enregistrement. Dans mon cas, je configure un TTL de 3600 secondes (1h) dans mes zones persos principalement parce que certaines sont hébergées à domicile, ce qui impose quelques contraintes, voir http://shaarli.guiguishow.info/?wgU1VQ.
Si vous n'attendez pas ce délai, il se peut qu'un client ait récupéré votre ancien enregistrement TLSA. Il n'arrivera pas à valider le nouveau certificat avec l'ancien TLSA. À l'heure actuelle, ce n'est pas bloquant puisque on est dans une validation "à la cool" compte-tenu du faible usage de DANE mais autant prendre le pli des bonnes pratiques qui seront nécessaires dans le futur, si toutefois DANE en fait bien partie, et avec lesquelles la connexion sécurisée échouera purement et simplement.
Avant de foncer tête baissée, réfléchissons à ce que nous voulons et allons faire.
Sur un de mes serveurs, j'utilise un certificat autosigné. Ce sera donc un usage = 3, que l'on nomme aussi DANE-EE / Domain-issued certificate. Il s'agit d'une contrainte sur le certificat : le client TLS doit obtenir le même de la part du serveur TLS pour que l'échange continue. On se passe de toute l'infrastructure et de toute la validation x509 habituelle.
Sur mes autres serveurs, comme celui qui héberge ce shaarli et mon blog, j'utilise une AC perso. Ce sera donc un usage = 2, que l'on nomme aussi DANE-TA / Trust anchor assertion. Il s'agit d'une contrainte sur l'AC : le client TLS acceptera uniquement tout certificat portant mon nom de domaine et signé par cette AC. On se passe de toute l'infrastructure x509 habituelle, on demande au client TLS d'ignorer toutes les AC pré-définies dans son magasin de certificat.
Pour le selector : il faut être vigilant pour les cas d'usage 0 et 2. L'annexe A.1.2 du RFC 6698 explique les cas où l'on peut obtenir des fails : des attributs ont été ajoutés au certificat d'AC, l'algorithme de signature change, le client TLS trouve un certificat d'AC actualisé dans son magasin ou dans son cache ou dans un attribut x509 « Authority Information Access », le certificat est cross-signé par plusieurs AC et le client TLS choisi l'autre CA, Let's Encrypt où le certificat (mais pas la paire de clés !) est re-généré tous les 3 mois, etc. Dans ces cas-là, une comparaison sur l'intégralité du certificat échouera. Dans mon cas, l'AC est mienne, elle ne change pas, elle n'est pas cross-signée, bref, je n'identifie aucun problème. Donc je stockerai le contenu entier de mes certificats dans le DNS donc selector = 0.
Pour le matching type, c'est plus facile : on ne va pas stocker tout le certificat dans le DNS et SHA-256 est suffisant de nos jours donc matching type = 1.
Lorsque je crée mes zones DNS, j'y enregistre d'abord mes machines, sous leur vrai nom genre viki.guiguishow.info. Ensuite, pour chaque machine, j'accroche les services assurés par cette machine. Soit avec les enregistrements MX et SRV quand c'est possible, soit avec des CNAME. Exemples : « @ MX viki », « shaarli CNAME viki ».
Tous mes sites web, mes virtualhosts, utilisent le même certificat x509.
La question est donc : est-ce que je dois créer des TLSA pour shaarli.guiguishow.info ou pour viki.guiguishow.info compte-tenu que le premier est un alias pointant sur le deuxième ? Est-ce que je dois avoir un enregistrement « _443._tcp.shaarli.guiguishow.info. IN TLSA [...] » ou bien un enregistrement « _443._tcp.viki.guiguishow.info. IN TLSA [...] » ?
L'annexe A.2.1.1 du RFC 6698 nous informe que les deux sont possibles (et même en même temps !) mais les implémentations demanderont « _443._tcp.shaarli.guiguishow.info. ». Ce nom doit répondre, même s'il est un alias vers « _443._tcp.viki.guiguishow.info. ». ÉDIT DU 14/01/2017 À 17H45 : pour les protocoles à indirection DNS (comme SMTP ou XMPP) les RFC 7672 et 7673 sont formels : le TLSA doit porter sur le nom du serveur, ici viki.guiguishow.info, pour faciliter l'hébergement. FIN DE L'ÉDIT.
J'ai choisi de créer un seul enregistrement TLSA par machine et autant de CNAME qu'il y a de virtualhosts. Je trouve ça lisible, je trouve que ça correspond bien à mon déploiement actuel de "un certificat x509 par machine" et ça facilitera les changements de certificats.
Oui parce que créer des enregistrements à la main avec OpenSSL, c'pas vraiment convivial.
Un logiciel plus convivial est hash-slinger. Il permet de générer des enregistrements SSHFP (voir http://shaarli.guiguishow.info/?QWcOtQ ) avec la commande sshfp
, des enregistrements DANE OpenPGP (voir http://www.bortzmeyer.org/7929.html) avec la commande openpgpkey
et des enregistrements DANE TLSA avec la commande tlsa
. Il est même packagé dans Debian. \o/
Ce logiciel attend un root.key, c'est-à-dire un fichier contenant la clé publique de la racine DNS pour l'utiliser avec la libunbound afin d'effectuer de la validation DNSSEC locale. Dans mon cas, j'ai un serveur récursif-cache local Unbound installé sur ma machine de travail donc j'ai un fichier /var/lib/unbound/root.key. Si ce n'est pas votre cas, installez unbound-anchor
et exécutez la commande sudo unbound-anchor -a /etc/unbound/root.key
.
Mais, sous Jessie, l'outil tlsa s'attend à trouver la clé dans /etc/unbound/root.key. Il faut patcher /usr/bin/tlsa (c'est un script python) en changeant les valeurs des variables ROOTKEY
et DLVKEY
. Ce problème a été corrigé dans les dernières versions. On peut même trouver une version corrigée dans jessie-backports.
tlsa --create --usage 3 --selector 0 --mtype 1 <hostname>
tlsa --create --usage 2 --selector 0 --mtype 1 <hostname>
Attention : il faut que le serveur (web, dans ce cas précis mais c'est valable pour tout serveur TLS) envoie le certificat de l'AC en plus de son certificat serveur. C'est la règle avec TLS + x509 (on doit fournir une chaîne complète jusqu'à un certificat que l'on suppose présent chez notre interlocuteur, une AC privée n'est pas supposée présente) mais on trouve des serveurs mal configurés. Pour vérifier ce point, vous pouvez utiliser https://www.ssllabs.com/ssltest/ : si vous avez un message « This server's certificate chain is incomplete. Grade capped to B. », ce n'est pas bon signe.
Je rappelle que pour chaîner des certificats, on fait comme cela :
cat moncertificat.crt > cert+ca.chain
cat certificatAC.crt >> cert+ca.chain
C'est le fichier .chain qu'il faut indiquer dans la configuration de votre serveur (SSLCertificateFile
pour apache httpd, smtpd_tls_cert_file
pour postfix, etc.).
tlsa va vous proposer chaque certificat présent dans la chaîne transmise par le serveur TLS, à vous d'accepter le bon. Exemple :
Got a certificate with the following Subject:
/C=FR/ST=Some-State/O=GuiGui's Show/CN=viki.guiguishow.info/emailAddress=[censure_no_spam]
Use this as certificate to match? [y/N] n
Got a certificate with the following Subject:
/C=FR/ST=Some-State/O=GuiGui's Show/CN=Autorite de certification GGS/emailAddress=[censure_no_spam]
Use this as certificate to match? [y/N] y
Il reste à ajouter l'enregistrement DNS créé par hash-slinger à notre zone DNS et à re-signer la zone.
ÉDIT DU 21/11/2016 À 11H50 : oui, demander à tlsa de récupérer le certificat en causant à votre serveur TLS implique que vous soyez sûr qu'il n'y a pas un attaquant actif entre vous et votre serveur auquel cas le certificat que vous mettrez dans le DNS sera celui de l'attaquant. Dans mon cas, j'utilise un VPN entre ma machine de travail qui exécute tlsa et mes serveurs. Vous pouvez également utiliser l'option « --certificate /chemin/vers/certificat » de tlsa pour lui donner localement le certificat à traiter. FIN DE L'ÉDIT.
Pour vérifier que tout est OK :
tlsa --verify <hostname>
SUCCESS (usage 3): The certificate offered by the server matches the TLSA record
SUCCESS (usage 3): The certificate offered by the server matches the TLSA record
Il y a deux lignes car tlsa vérifie en IPv4 et en IPv6.
Pour Firefox, il y a l'extension DNSSEC/TLSA Validator écrite par les gens de nic.cz, des gens de confiance.
Si votre configuration est OK, cette extension doit vous indiquer que tous vos sites web sont désormais OK. Attention : cette extension fait elle-même la résolution DNS (histoire d'être sûre de valider les signatures DNSSEC en local) donc elle conserve son propre cache. ;) Il faut redémarrer Firefox pour vider ce cache.
Tout protocole réseau qui utilise TLS peut être protégé par DANE TLSA : SMTP, IMAP, XMPP, etc.
Exemple avec SMTP :
hash-slinger ne prend pas en charge STARTTLS. Il faut procéder différemment :
openssl s_client -showcerts -connect <machine>:25 -starttls smtp </dev/null 2>/dev/null | openssl x509 -outform PEM > mycertfile.pem
tlsa --create --usage 3 --selector 0 --mtype 1 --certificate mycertfile.pem <nom_machine>
ÉDIT DU 14/01/2017 À 17H45 : conformément au RFC 7672, <hostname>
doit être le nom du serveur, celui qui est dans le RDATA (partie droite) de l'enregistrement MX, pas sur le nom de domaine pour lequel on insère un MX. FIN DE L'ÉDIT.
La commande openssl vient de là : https://superuser.com/questions/97201/how-to-save-a-remote-server-ssl-certificate-locally-as-a-file .
ÉDIT DU 21/11/2016 À 11H50 : oui, demander à openssl de récupérer le certificat en causant à votre serveur TLS implique que vous soyez sûr qu'il n'y a pas un attaquant actif entre vous et votre serveur auquel cas le certificat que vous mettrez dans le DNS sera celui de l'attaquant. Dans mon cas, j'utilise un VPN entre ma machine de travail qui exécute openssl s_client et mes serveurs. Sinon, vous pouvez directement filer le fichier contenant votre certificat à tlsa. ;) FIN DE L'ÉDIT.
Pour l'instant, mon logiciel de mail, Thunderbird, ne prend pas en charge DANE. :(
Pour l'instant, mon client Jabber, Gajim, ne prend pas en charge DANE. :(
Pour l'instant, mon serveur Jabber, ejabberd, ne prend pas en charge DANE pour la communication entre serveurs Jabber. :(
Mon serveur mails, Postfix, prend en charge DANE pour la communication entre serveurs mails. \o/ Uniquement les usages 2 et 3, ceux où on n'effectue pas la validation PKIX classique.
Pour que votre serveur mails Postfix valide le certificat qu'il obtient auprès d'un serveur SMTP distant en utilisant DANE mais qu'il continue l'envoi du mail s'il n'y a pas d'enregistrements DNS de type TLSA, il faut activer les options suivantes dans main.cf :
smtp_dns_support_level=dnssec
smtp_tls_security_level=dane
ÉDIT DU 30/04/2020 À 13 H 35 : attention : les versions de TLS et les suites de chiffrement autorisées se définissent alors dans smtp_tls_mandatory_protocols
et smtp_tls_mandatory_ciphers
! La documentation expose bien ce point : « For purposes of protocol and cipher selection, the "dane" security level is treated like a "mandatory" TLS security level ». FIN DE L'ÉDIT DU 30/04/2020.
Quand vous écrirez à un domaine qui utilise DANE, et si vous utilisez la directive de configuration smtp_tls_loglevel = 1
, Postfix indiquera dans les logs quand il validera une transaction TLS grâce à DANE :
Verified TLS connection established to [censure]:25: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
Pour les domaines qui n'utilisent pas DANE, vous verrez le classique message :
Untrusted TLS connection established to [censure]:25: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
Ici, DANE TLSA offre un avantage supplémentaire : en SMTP, POP, IMAP, XMPP, on préfère utiliser STARTTLS, c'est-à-dire que l'on n'ouvre pas 2 ports différents (un pour la version claire et un pour communiquer de manière chiffrée, comme c'est le cas avec http (port 80) et https (port 443) mais que l'on utilise un seul port dans lequel on se laisse une opportunité de démarrer une conversation chiffrée. Sauf que l'initiation de cette communication chiffrée se fait avec un message « STARTTLS »… qu'un attaquant actif peut supprimer ou altérer. Ainsi, l'échange aura lieu en clair. STARTTLS protège uniquement contre un attaquant passif, un attaquant qui est uniquement en capacité d'écouter sur le réseau.
Évidemment, on peut configurer les logiciels (clients et serveurs) pour forcer l'utilisation de TLS sauf que le mail est ancien et que tout le monde a l'habitude de faire n'importe quoi. Conclusion : forcer le chiffrement, c'est ne plus pouvoir envoyer de mails sauf à ses potos crypto-anarchistes. Sur Jabber, plus récent, on a moins cette inertie (mais le problème est quand même là) donc un serveur qui force le chiffrement n'est pas isolé.
Là où DANE intervient, c'est que si Postfix récupère un enregistrement TLSA utilisable lorsqu'il envoie un mail, il voudra forcément un échange chiffré avec le serveur de mail correspondant. Un attaquant actif ne peut plus faire échouer l'initialisation d'une communication chiffrée.
Dans la section « CNAME », nous avons vu que j'ai un enregistrement TLSA par couple port (443) + machine et que tous mes noms de sites web pointent dessus.
Mais là, nous avons besoin d'enregistrements TLSA pour le port 25. Et un jour peut-être pour les ports IMAP, POP, Jabber, etc. On ne va quand même pas avoir autant d'enregistrements TLSA dans nos zones : ça rend moins lisible le fichier et à chaque changement de certificat, il faudrait changer X enregistrements.
Sachant que, sur certains domaines que j'administre et dont je ne suis pas le seul utilisateur, j'ai des enregistrements CNAME pour aider à la configuration du logiciel mail tel que imap CNAME <machine>
, smtp CNAME <machine>
, etc. Je ne vais quand même pas avoir un TLSA pour chaque nom.
Évidemment, je vais utiliser des CNAME.
La question est : est-ce que je fais pointer tous les autres noms "TLSA" sur _443._tcp.<machine>
ou est-ce que je crée un enregistrement TLSA générique de la forme <machine> TLSA <RDATA>
sur lequel pointeront tous les autres ?
Je trouve la deuxième manière de faire plus lisible : lors d'un renouvellement de certificat x509, je cherche un enregistrement précis avec une sémantique précise et je change sa valeur. De plus, cela évite de faire penser que HTTPS est le protocole de référence pour tous les autres, ce qui n'a aucun sens.
En revanche, cette manière de faire peut conduire à des chaînes de CNAME. Si elles ne sont pas interdites dans la norme, elles sont déconseillées. Exemple de chaîne ? _443._tcp.shaarli.guiguishow.info. qui ponterait sur _443._tcp.viki.guiguishow.info. comme nous l'avons vu dans la section « CNAME » qui, lui-même, pointerait sur l'enregistrement générique viki.guiguishow.info. TLSA [...]. Un autre exemple ? _25._tcp.smtp.guiguishow.info. qui pointerait sur _25._tcp.viki.guiguishow.info. qui pointerait sur l'enregistrement générique.
En conclusion, j'ai :
ÉDIT DU 14/01/2017 À 17H45 : ajout d'informations suite à la relecture de Stéphane Bortzmeyer. Merci. :) FIN DE L'ÉDIT.