Date de publication du RFC : Août 2021
Auteur(s) du RFC : V. Dukhovni (Two Sigma), S. Huque (Salesforce), W. Toorop (NLnet Labs), P. Wouters (Aiven), M. Shore (Fastly)
Expérimental
Première rédaction de cet article le 12 août 2021
Lorsqu'on authentifie un serveur TLS (par exemple un serveur
DoT) avec DANE, le client TLS
doit utiliser un résolveur DNS
validant et tenir compte de son résultat
(données validées ou pas), ce qui n'est pas toujours facile, ni même
possible dans certains environnements. Ce RFC propose une solution pour cela : une
extension à TLS, dnssec_chain
, qui permet au
serveur TLS d'envoyer l'ensemble des enregistrements DNS pertinents
au client, le dispensant ainsi de solliciter un résolveur
validant. Toute la cuisine de vérification peut ainsi se faire sans
autre canal que TLS.
TLS
(normalisé dans les RFC 5246 et RFC 8446) fournit un canal de communication
sécurisé, si on a authentifié le serveur situé en face. La plupart
du temps, on authentifie via un certificat
PKIX (RFC 5280). Dans certains
cas, ce n'est pas facile d'utiliser PKIX. Par exemple, pour
DoT (RFC 7858), le
résolveur DoT n'est typiquement connu que par une adresse IP, alors que le
certificat ne contient en général qu'un nom
(oui, le RFC 8738 existe, mais n'est pas
toujours activé par les autorités de
certification). Les serveurs DoT sont souvent
authentifiables par DANE (RFC 6698 et
RFC 7671). Par exemple, mon résolveur DoT
public, dot.bortzmeyer.fr
, est authentifiable
avec DANE (regardez les données TLSA de
_853._tcp.dot.bortzmeyer.fr
). Mais DANE dépend
de la disponibilité d'un résolveur DNS
validant. Diverses raisons font que le
client TLS peut avoir du mal à utiliser un résolveur validant, et à
récupérer l'état de la validation (toutes les API de résolution de
noms ne donnent pas accès à cet état). L'article « Discovery
method for a DNSSEC validating stub resolver »
donne des informations sur ces difficultés. Bref, devoir récupérer
ces enregistrements DANE de manière sécurisée peut être un
problème. Et puis utiliser le DNS pour récupérer des données
permettant d'authentifier un résolveur DNS pose un
problème d'œuf et de poule.
D'où l'idée centrale de ce RFC : le client TLS demande au serveur de lui envoyer ces enregistrements. Le client n'a plus « que » à les valider à partir d'une clé de confiance DNSSEC (typiquement celle de la racine, commune à tout le monde). Le serveur peut aussi, s'il n'utilise pas DANE, renvoyer la preuve de non-existence de ces enregistrements, le client saura alors, de manière certaine, qu'il peut se rabattre sur un autre mécanisme d'authentification. L'extension TLS de notre RFC peut servir à authentifier un certificat complet, ou bien une clé brute (RFC 7250). Dans ce dernier cas, cette extension protège en outre contre les attaques dites « Unknown Key-Share ».
Notez le statut de ce RFC : cette spécification est pour l'instant expérimentale, elle n'a pas vraiment réuni de consensus à l'IETF, mais elle fait partie des solutions proposées pour sécuriser DoT, dans le RFC 8310 (section 8.2.2).
Bon, maintenant, l'extension elle-même (section 2). C'est une
extension TLS (ces extensions sont spécifiées dans la section 4.2 du
RFC 8446), elle est nommée
dnssec_chain
et enregistrée
dans le registre IANA, avec le code 59. Son champ de données
(extension_data
) vaut, dans le
ClientHello
, le port de
connexion et, dans le ServerHello
, un ensemble
d'enregistrements DNS au format binaire du DNS (pour TLS 1.2 ; en
1.3, cet ensemble est attaché au certificat du serveur). Dans le
langage de description des données TLS, cela donne, du client vers
le serveur :
struct { uint16 PortNumber; } DnssecChainExtension;
Et du serveur vers le client :
struct { uint16 ExtSupportLifetime; opaque AuthenticationChain<1..2^16-1> } DnssecChainExtension;
(Le ExtSupportLifetime
indique que le serveur
s'engage à continuer à gérer cette extension pendant au moins ce
temps - en heures. Si ce n'est plus le cas avant l'expiration du
délai, cela peut indiquer une usurpation par un faux serveur.)
Cette extension est donc une forme, assez spéciale, de « DNS sur
TLS ». Le client ne doit pas oublier d'envoyer un SNI (RFC 6066), pour que le serveur sache quel nom va
être authentifié et donc quels enregistrements DNS renvoyer. Quant
au serveur, s'il ne gère pas cette extension, il répond au client
avec un ServerHello
n'ayant pas l'extension
dnssec_chain
. Même chose si le serveur accepte
l'extension mais, pour une raison ou pour une autre, n'a pas pu
rassembler tous les enregistrements DNS.
Et pourquoi le client doit-il indiquer le port auquel il voulait se connecter ? Le serveur le connait, non ? Mais ce n'est pas forcément le cas, soit parce qu'il y a eu traduction de port quelque part sur le chemin, soit parce que le client a été redirigé, par exemple via le type d'enregistrement SVCB (RFC 9460). Le port indiqué par le client doit être le port original, avant toute traduction ou redirection.
Revenons à la « chaine », l'ensemble d'enregistrements DNS qui va
permettre la validation DANE. Le format est le format binaire
habituel du DNS, décrit dans le RFC 1035,
section 3.2.1. L'utilisation de ce format, quoiqu'il soit inhabituel
dans le monde TLS, permet, entre autres avantages, l'utilisation des
bibliothèques logicielles DNS existantes. Le RFC recommande
d'inclure dans l'ensemble d'enregistrements une chaine complète, y
compris la racine et incluant donc les clés DNSSEC de celle-ci
(enregistrements DNSKEY), même si le client les connait probablement
déjà. Cela donne par exemple la chaine suivante, pour le serveur
www.example.com
écoutant sur le port 443. Notez
qu'on inclut les signatures (RRSIG) :
_443._tcp.www.example.com
TLSA_443._tcp.www.example.com
TLSA)example.com
. DNSKEYexample.com
DNSKEY)example.com
DSexample.com
DS)com
DNSKEYcom
DNSKEY)com
DScom
DS).
DNSKEY.
DNSKEY)
(L'exemple suppose que
_443._tcp.www.example.com
et
example.com
sont dans la même zone.) Voilà,
avec tous ces enregistrements, le client peut, sans faire appel à un
résolveur DNS validant, vérifier (s'il a confiance dans la clé de la
racine) l'authenticité de l'enregistrement DANE (type TLSA) et donc
le certificat du serveur. De la même façon, si on n'a pas
d'enregistrement TLSA, le serveur peut envoyer les preuves de
non-existence (enregistrements NSEC ou NSEC3). Bon, évidemment, dans
ce cas, c'est moins utile, autant ne pas gérer l'extension
dnssec_chain
… Face à ce déni, le client TLS
n'aurait plus qu'à se rabattre sur une autre méthode
d'authentification.
Le serveur TLS construit la chaine des enregistrements comme il veut, mais pour l'aider, la section 3 du RFC fournit une procédure possible, à partir d'interrogations du résolveur de ce serveur. Une autre possibilité, plus simple pour le serveur, serait d'utiliser les requêtes chainées du RFC 7901 (mais qui n'ont pas l'air très souvent déployées aujourd'hui).
Comme tous les enregistrements DNS, ceux inclus dans l'extension
TLS dnssec_chain
ont une durée de vie. Et les signatures DNSSEC ont
une période de validité (en général plus longue que la durée de
vie). Le serveur TLS qui construit l'ensemble d'enregistrements qu'il
va renvoyer peut donc mémoriser cet ensemble, dans la limite du
TTL et de l'expiration
des signatures DNSSEC. Le client TLS peut lui aussi mémoriser ces
informations, dans les mêmes conditions.
On a vu plus haut que les données de l'extension TLS incluaient
un ExtSupportLifetime
qui indiquait combien de
temps le client pouvait s'attendre à ce que le serveur TLS continue
à gérer cette extension. Car le client peut épingler
(pinning) cette information. Cela permet de
détecter certaines attaques (« ce serveur gérait l'extension
dnssec_chain
et ce n'est maintenant plus le
cas ; je soupçonne un détournement vers un serveur pirate »). Cet
engagement du serveur est analogue au HSTS de HTTPS (RFC 6797) ; dans les deux cas, le serveur s'engage à rester
« sécurisé » pendant un temps minimum (mais pas infini, car on doit
toujours pouvoir changer de politique). À noter que « gérer
l'extension dnssec_chain
» n'est pas la même
chose que « avoir un enregistrement TLSA », on peut accepter
l'extension mais ne pas avoir de données à envoyer (il faudra alors
envoyer la preuve de non-existence mentionnée plus haut). Bien sûr,
le client TLS est libre de sa politique. Il peut aussi décider
d'exiger systématiquement l'acceptation de l'extension TLS
dnssec_chain
(ce qui, aujourd'hui, n'est
réaliste que si on ne parle qu'à un petit nombre de serveurs).
Si un serveur gérait l'extension
dnssec_chain
mais souhaite arrêter, il doit
bien calculer son coup : d'abord réduire
ExtSupportLifetime
à zéro puis attendre que
la durée annoncée dans le précédent
ExtSupportLifetime
soit écoulée, afin que tous
les clients aient arrêté de l'épingler comme serveur à
dnssec_chain
. Il peut alors proprement stopper
l'extension (cf. section 10 du RFC).
Un petit problème se pose si on fait héberger le serveur TLS chez
un tiers. Par exemple, imaginons que le titulaire du domaine
boulanger.example
ait un serveur chez la
société JVL (Je Vous Loge) et que
server.boulanger.example
soit un alias
(enregistrement de type CNAME) vers
clients.jvl.example
. Le client TLS va envoyer
server.boulanger.example
comme SNI. Il ne sera
pas pratique du tout pour JVL de coordonner la chaine
d'enregistrements DNS et le certificat. Il est donc conseillé que
l'enregistrement TLSA du client soit lui aussi un alias vers un
enregistrement TLSA de l'hébergeur. Cela pourrait donner (sans les
signatures, pour simplifier la liste) :
server.boulanger.example
CNAME (vers
clients.jvl.example
)_443._tcp.server.boulanger.example
CNAME
(vers _dane443.node1.jvl.example
)clients.jvl.example
AAAA_dane443.node1.jvl.example
TLSA
Les deux premiers enregistrements sont gérés par l'hébergé, les deux
derniers par l'hébergeur. (La section 9 du RFC explique pourquoi
l'enregistrement TLSA de l'hébergeur n'est pas en
_443._tcp
…)
Comme dit plus haut, le client TLS est maitre de sa politique : il peut exiger l'extension TLS, il peut l'accepter si elle existe, il peut l'ignorer. Si l'authentification par DANE échoue mais que celle par PKIX réussit, ou le contraire, c'est au client TLS de décider, en fonction de sa politique, ce qu'il fait.
Est-ce que le serveur TLS qui gère cette extension doit envoyer la chaine complète de certificats ? S'il veut pouvoir également être identifié avec PKIX, oui. Si non, s'il se contente de DANE et plus précisément de DANE-EE ou DANE-TA (ces deux termes sont définis dans le RFC 7218), il peut envoyer uniquement le certificat du serveur (pour DANE-EE).
Question mise en œuvre, l'excellente bibliothèque ldns a (je n'ai pas testé…) tout ce qu'il faut pour générer et tester ces chaines d'enregistrements DNS. Si vous voulez développer du code pour gérer cette extension, l'annexe A du RFC contient des vecteurs de test qui vous seront probablement bien utiles.
Version PDF de cette page (mais vous pouvez aussi imprimer depuis votre navigateur, il y a une feuille de style prévue pour cela)
Source XML de cette page (cette page est distribuée sous les termes de la licence GFDL)