Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

Mon livre « Cyberstructure »

Ève

Ce blog n'a d'autre prétention que de me permettre de mettre à la disposition de tous des petits textes que j'écris. On y parle surtout d'informatique mais d'autres sujets apparaissent parfois.


RFC 9115: An Automatic Certificate Management Environment (ACME) Profile for Generating Delegated Certificates

Date de publication du RFC : Septembre 2021
Auteur(s) du RFC : Y. Sheffer (Intuit), D. López, A. Pastor Perales (Telefonica I+D), T. Fossati (ARM)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF acme
Première rédaction de cet article le 21 septembre 2021


Ce nouveau RFC décrit un profil du protocole ACME d'obtention de certificat, profil qui permet de déléguer la demande à un tiers. C'est surtout utile pour le cas où vous sous-traitez l'hébergement de votre site Web (par exemple sur un CDN) : le sous-traitant peut alors demander un certificat, avec sa clé privée à lui, pour un nom de domaine que vous contrôlez et prouver qu'il héberge bien le serveur pour ce nom. Serveurs et clients TLS n'ont pas besoin d'être modifiés (seuls les serveurs et clients ACME le seront), et, bien entendu, le titulaire du nom de domaine garde un complet contrôle et peut, par exemple, révoquer les certificats obtenus par ses sous-traitants.

Ce profil utilise lui-même le profil STAR (Short-Term, Automatically Renewed) décrit dans le RFC 8739 donc faites bien attention à avoir lu le RFC 8739 avant. Le cas typique d'utilisation de ce mécanisme de délégation est le CDN. Un webmestre (l'IdO pour Identifier Owner car il est titulaire du nom de domaine, mettons foobar.example) a un site Web et sous-traite tout ou partie du service à un CDN, appelé ici NDC pour Name Delegation Consumer (et la ressemblance entre les sigles CDN et NDC est volontaire). Le CDN devra pouvoir répondre aux requêtes HTTPS pour www.foobar.example et donc présenter un certificat au nom www.foobar.example. Avec ACME, l'IdO peut obtenir un tel certifiat mais il ne souhaite probablement pas transmettre la clé privée correspondante au NDC. La solution de notre RFC est d'utiliser une extension à ACME, permettant la délégation du nom. Le NDC pourra alors obtenir un certificat STAR (de courte durée de vie, donc) pour www.foobar.example. Pas besoin de partager une clé privée, ni de transmettre des secrets de longue durée de vie (les délégations sont révocables, et les certificats STAR ne durent pas longtemps, le NDC devra renouveller souvent et ça cessera en cas de révocation). C'est l'utilisation typique de la délégation mais d'autres sont possibles (par exemple avec des certificats ordinaires, non-STAR). Le RFC note que la solution de délégation ne modifie qu'ACME, et pas TLS, et qu'elle marche donc avec les clients et serveurs TLS actuels (contrairement à d'autres propositions qui sont étudiées).

Pour que la délégation fonctionne, l'IdO doit avoir un serveur ACME, auquel le NDC devra se connecter, et s'être mis d'accord avec le NDC sur les paramètres à utiliser. C'est donc une étape relativement nouvelle, l'utilisateur d'ACME typique n'ayant qu'un client ACME, seule l'AC a un serveur. Mais c'est quand même plus simple que de monter une AC. Le serveur ACME chez l'IdO ne signera pas de certificats, il relaiera simplement la requête. Quand le NDC aura besoin d'un certificat, il enverra une demande à l'IdO, qui la vérifiera et, devenant client ACME, l'IdO enverra une demande à l'AC. Si ça marche, l'IdO prévient le NDC, et celui-ci récupérera le certificat chez l'AC (par unauthenticated GET, RFC 8739, section 3.4).

Le protocole ACME gagne un nouveau type d'objet, les délégations, qui indiquent ce qu'on permet au NDC. Comme les autres objets ACME, elles sont représentées en JSON et voici un exemple :

{
     "csr-template": {
       "keyTypes": [
         {
           "PublicKeyType": "id-ecPublicKey",
           "namedCurve": "secp256r1",
           "SignatureType": "ecdsa-with-SHA256"
         }
       ],
       "subject": {
         "country": "FR",
         "stateOrProvince": "**",
         "locality": "**"
       },
       "extensions": {
         "subjectAltName": {
           "DNS": [
             "www.foobar.example"
           ]
         },
         "keyUsage": [
           "digitalSignature"
         ],
         "extendedKeyUsage": [
           "serverAuth"
         ]
         }
     }
}
  

(Les champs des extensions comme keyUsage sont dans un nouveau registre IANA ; on peut ajouter des champs, selon la politique « spécification nécessaire ».) Ici, le NDC est autorisé à demander des certificats ECDSA pour le nom www.foobar.example. Quand le NDC enverra sa requête de certificat à l'IdO, il devra inclure cet objet « délégation », que l'IdO pourra comparer avec ce qu'il a configuré pour ce NDC. Voici un exemple partiel, envoyé lors d'un POST HTTPS au serveur ACME de l'IdO :

   {
     "protected": base64url({
       "alg": "ES256",
       "kid": "https://acme.ido.example/acme/acct/evOfKhNU60wg",
       "nonce": "Alc00Ap6Rt7GMkEl3L1JX5",
       "url": "https://acme.ido.example/acme/new-order"
     }),
     "payload": base64url({
       "identifiers": [
         {
           "type": "dns",
           "value": "www.foobar.example"
         }
       ],
       "delegation":
         "https://acme.ido.example/acme/delegation/gm0wfLYHBen"
     }),
     "signature":    ...
  

(Le nouveau champ delegation a été placé dans le registre IANA.) Le NDC enverra ensuite le CSR, et l'IdO relaiera la requête vers le serveur ACME de l'AC (moins l'indication de délégation, qui ne regarde pas l'AC).

Quand on utilise un CDN, il est fréquent qu'on doive configurer un alias dans le DNS pour pointer vers un nom indiqué par l'opérateur du CDN. Voici par exemple celui de l'Élysée :

% dig CNAME www.elysee.fr 
...
;; ANSWER SECTION:
www.elysee.fr.		3600 IN	CNAME 3cifmt6.x.incapdns.net.
...

L'extension au protocole ACME spécifiée dans notre RFC permet au NDC d'indiquer cet alias dans sa requête, l'IdO peut alors l'inclure dans sa zone DNS.

Tous les serveurs ACME ne seront pas forcément capables de gérer des délégations, il faudra donc l'indiquer dans les capacités du serveur, avec le champ delegation-enabled (mis dans le registre IANA).

Comme indiqué plus haut, l'IdO peut arrêter la délégation quand il veut, par exemple parce qu'il change de CDN. Cet arrêt se fait par une interruption explicite de la demande STAR (RFC 8739, section 3.1.2). Si les certificats ne sont pas des STAR, le mécanisme à utiliser est la révocation normale des certificats.

Après cet examen du protocole, la section 3 de notre RFC décrit le comportement de l'AC. Il n'y a pas grand'chose à faire pour l'AC (le protocole est entre le NDC et l'IdO) à part à être capable d'accepter des récupérations non authentifiées de certificats (car le NDC n'a pas de compte à l'AC).

On a parlé plus haut du CSR. Il doit se conformer à un certain gabarit, décidé par l'IdO. Ce gabarit est évidemment au format JSON, comme le reste d'ACME. La syntaxe exacte est décrite avec le langage CDDL (RFC 8610) et figure dans l'annexe A ou bien, si vous préférez, avec le langage JSON Schema, utilisé dans l'annexe B. Voici l'exemple de gabarit du RFC :

  {
     "keyTypes": [
       {
         "PublicKeyType": "rsaEncryption",
         "PublicKeyLength": 2048,
         "SignatureType": "sha256WithRSAEncryption"
       },
       {
         "PublicKeyType": "id-ecPublicKey",
         "namedCurve": "secp256r1",
         "SignatureType": "ecdsa-with-SHA256"
       }
     ],
     "subject": {
       "country": "CA",
       "stateOrProvince": "**",
       "locality": "**"
     },
     "extensions": {
       "subjectAltName": {
         "DNS": [
           "abc.ido.example"
         ]
       },
       "keyUsage": [
         "digitalSignature"
       ],
       "extendedKeyUsage": [
         "serverAuth",
         "clientAuth"
       ]
     }
   }

Dans cet exemple, l'IdO impose au NDC un certificat RSA ou ECDSA et rend impérative (c'est le sens des deux astérisques) l'indication de la province et de la ville. L'IdO doit évidemment vérifier que le CSRT reçu se conforme bien à ce gabarit.

Le RFC présente (en section 5) quelques autres cas d'utilisation de cette délégation. Par exemple, un IdO peut déléguer à plusieurs CDN, afin d'éviter que la panne d'un CDN n'arrête tout. Avec la délégation, ça se fait tout seul, chacun des CDN est authentifié, et demande séparément son certificat.

Autre cas rigolo, celui où le CDN délègue une partie du service à un CDN plus petit. Le modèle de délégation ACME peut s'y adapter (le petit CDN demande un certificat au gros, qui relaie à l'IdO…), si les différentes parties sont d'accord.

Enfin, la section 7 du RFC revient sur les propriétés de sécurité de ces délégations. En gros, il faut avoir confiance en celui à qui on délègue car, pendant la durée de la délégation, il pourra faire ce qu'il veut avec le nom qu'on lui a délégué, y compris demander d'autres certificats en utilisant sa délégation du nom de domaine. Il existe quelques mesures techniques que l'IdO peut déployer pour empêcher le NDC de faire trop de bêtises. C'est le cas par exemple des enregistrements DNS CAA (RFC 8659) qui peuvent limiter le nombre d'AC autorisées (voir aussi le RFC 8657).

Je ne connais pas encore d'opérateur de CDN qui mette en œuvre cette solution.


Téléchargez le RFC 9115


L'article seul

RFC 9098: Operational Implications of IPv6 Packets with Extension Headers

Date de publication du RFC : Septembre 2021
Auteur(s) du RFC : F. Gont (SI6 Networks), N. Hilliard (INEX), G. Doering (SpaceNet AG), W. Kumari (Google), G. Huston (APNIC), W. Liu (Huawei Technologies)
Pour information
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 20 septembre 2021


IPv6 souffre de réseaux mal gérés qui se permettent de jeter les paquets ayant des caractéristiques normales, mais qui déplaisent à certains équipements réseau. C'est par exemple le cas des paquets utilisant les en-têtes d'extension. Pourquoi les paquets utilisant ces en-têtes sont-ils souvent jetés ?

Ces en-têtes d'extension (qui n'ont pas d'équivalent en IPv4) sont normalisés dans le RFC 8200, section 4. Ils servent à la fois à des fonctions de base d'IPv6 (comme la fragmentation) et à étendre le protocole si nécessaire. Mais, en pratique, on observe trop souvent que les paquets IPv6 utilisant ces en-têtes d'extension ne passent pas sur certains réseaux. Ce RFC vise à étudier pourquoi, et à expliquer les conséquences. Comme toujours quand on explique un phénomène (la délinquance, par exemple), des gens vont comprendre de travers et croire qu'on justifie le phénomène en question (« expliquer, c’est déjà vouloir un peu excuser », avait stupidement dit un ancien premier ministre français, à propos du terrorisme djihadiste). Le cas est d'autant plus fréquent qu'en français, « comprendre » est ambigu, car il peut désigner l'explication (qui est utile aussi bien aux partisans qu'aux adversaires d'un phénomène) que la justification. Bref, ce RFC explique pourquoi des paquets innocents sont détruits, il ne dit pas qu'il faut continuer à le faire !

La section 4 du RFC explique la différence entre l'en-tête d'un paquet IPv6 et celui d'un paquet de l'ancienne version. Dans les deux versions, le problème est de placer des options dans les en-têtes. Le gros changement est l'utilisation par IPv6 d'un en-tête de taille fixe (40 octets), suivi d'une liste chainée d'en-têtes d'extension permettant d'encoder ces options. Au contraire, IPv4 avait un en-tête de taille variable (entre 20 et 60 octets), avec un champ indiquant sa longueur, champ qu'il fallait lire avant d'accéder à l'en-tête. Le mécanisme d'IPv4 n'était ni pratique, ni rapide, mais celui d'IPv6 n'est pas plus satisfaisant : il faut lire toute la liste chainée (dont la longueur est quelconque et non limitée) si on veut accéder aux informations au-dessus de la couche 3. Ce n'est pas un problème pour les routeurs, à qui la couche 3 suffit (à part le cas de l'en-tête Hop-by-hop options), mais c'est ennuyeux pour les autres boitiers situés sur le chemin, comme les pare-feux. Les évolutions récentes d'IPv6 ont aidé, comme l'obligation que tous les en-têtes d'extension soient dans le premier fragment, si le datagramme est fragmenté (RFC 7112), ou comme l'imposition d'un format commun aux futurs en-têtes d'extension (dans le RFC 6564), mais l'analyse de la liste des en-têtes d'extension reste un travail pénible pour les machines.

Le problème est identifié depuis longtemps. Il est analysé dans l'Internet-Draft draft-taylor-v6ops-fragdrop, dans draft-wkumari-long-headers, dans draft-kampanakis-6man-ipv6-eh-parsing, dans draft-ietf-opsec-ipv6-eh-filtering mais aussi dans des RFC, le RFC 7113 et le RFC 8900. Cela a mené à plusieurs changements dans la norme, je vous renvoie aux RFC 5722, RFC 7045, RFC 8021, etc. Plusieurs changements ont été intégrés dans la dernière révision du RFC principal de la norme, le RFC 8200. Ainsi, celui-ci dispense désormais les routeurs de chercher un éventuel en-tête d'extension Hop-by-hop options.

Parallèlement à ces analyses du protocole, diverses études ont porté sur le phénomène des paquets jetés s'ils contenaient des en-têtes d'extension. Cela a été documenté dans « Discovering Path MTU black holes on the Internet using RIPE Atlas », dans « IPv6 Extension Headers in the Real World v2.0 », également dans « Dealing with IPv6 fragmentation in the DNS » et « Measurement of IPv6 Extension Header Support » ainsi que dans le RFC 7872.

Comment est-ce que les équipements intermédiaires du réseau fonctionnent, et pourquoi est-ce que les en-têtes d'extension IPv6 peuvent parfois les défriser ? La section 6 du RFC rappelle l'architecture de ces machines. Un routeur de cœur de réseau est très différent de l'ordinateur de base, avec son processeur généraliste et sa mémoire de grande taille, ce qui le rend lent, mais souple. Au contraire, la transmission des paquets par le routeur est en général faite par du matériel spécialisé, ASIC ou NPU. (Vous pouvez consulter des explications dans l'exposé fait à l'IETF « Modern Router Architecture for Protocol Designers » et dans l'article « Modern router architecture and IPv6 ».) Avant de transmettre un paquet reçu sur l'interface de sortie, le routeur doit trouver quelle interface utiliser. Une méthode courante est de prendre les N premiers octets du paquet et de les traiter dans une TCAM ou une RLDRAM, où se fera la détermination du saut suivant (et donc de l'interface de sortie). Le choix du nombre N est crucial : plus il est petit, plus le routeur pourra traiter de paquets, mais moins il aura d'information sur le paquet. (En pratique, on observe des N allant de 192 à 384 octets.) Du fait qu'un routeur se limite normalement à la couche Réseau, et que l'en-tête IPv6 a une taille fixe, envoyer simplement les 40 octets de cet en-tête devrait suffire. Mais lisez plus loin : certains routeurs ou autres équipements intermédiaires sont configurés pour regarder au-delà, et voudraient des informations de la couche Transport, plus dure à atteindre.

Une solution, pour les routeurs qui ne lisent qu'un nombre limité d'octets avant de prendre une décision, est de lire les en-têtes d'extension un par un, et de réinjecter le reste du paquet dans le dispositif de traitement. Ça se nomme la recirculation, c'est plus lent, mais ça marche quelle que soit la longueur de la chaîne des en-têtes d'extension.

Comme le routeur comprend toujours un processeur généraliste (ne serait-ce que pour faire tourner les fonctions de contrôle comme SSH et les protocoles de routage), une autre solution serait d'envoyer à ce processeur les paquets « compliqués » (mais lire le RFC 6192 d'abord). L'énorme différence de performance entre le processeur généraliste et les circuits spécialisés fait que ce ne serait pas une solution réaliste sauf pour un trafic très modéré. (Le RFC note que certains routeurs ont trois dispositifs de traitement des paquets, et pas seulement deux comme présenté plus haut : outre le processeur généraliste, qui ne leur sert qu'aux fonctions de contrôle, et des circuits matériels spécialisés, ils ont un dispositif logiciel de transmission des paquets. Plus souple que les circuits spécialisés, il n'est pas forcément plus rapide que le processeur généraliste mais, au moins, il n'interfère pas avec les fonctions de contrôle.)

Bon, on l'a déjà dit, mais cela vaut la peine de le répéter : à part le cas (agaçant) de l'en-tête Hop-by-hop options, un routeur, équipement de couche 3 n'a normalement aucun besoin d'aller regarder tous les en-têtes d'extension (qui sont presque tous pour la machine terminale de destination uniquement). Encore moins de faire du DPI et d'aller chercher des informations dans les couches 4 à 7. Mais la section 7 du RFC explique pourquoi certains routeurs le font quand même (il s'agit d'une description de leurs pratiques, pas une approbation ; beaucoup des raisons données sont mauvaises).

D'abord, la répartition de charge et l'ECMP. Si un routeur peut faire passer un paquet via deux interfaces différentes, laquelle choisir ? Alterner (un coup à gauche, un coup à droite) augmenterait la probabilité d'une arrivée des paquets dans le désordre. On préfère la prédictabilité : tous les paquets d'un même flot doivent suivre le même chemin. Comment déterminer le « flot », notion parfois un peu floue ? En restant dans les couches basses, on peut utiliser uniquement les adresses IP de source et de destination mais elles ne sont pas assez discriminantes. En IPv6, on peut en théorie utiliser l'étiquette de flot (normalisé dans le RFC 6437, ainsi que les RFC 6438 et RFC 7098 pour son utilisation) mais elle n'est pas toujours présente, en partie (encore !) par la faute de middleboxes qui, ignorant ce concept d'étiquette de flot, jetaient les paquets qui en avaient une. (Voir les articles de I. Cunha, «  IPv4 vs IPv6 load balancing in Internet routes » et J. Jaeggli, «  IPv6 flow label: misuse in hashing ».) En pratique, les systèmes qui ont besoin d'identifier les flots utilisent plutôt une heuristique : le tuple à cinq élements {protocole de transport, adresse IP source, adresse IP destination, port source, port destination}. Ce n'est pas parfait mais, en pratique, cela marche à peu près. On voit que cela nécessite d'accéder à de l'information de la couche Transport, les ports. (Cette heuristique a d'autres limites : par exemple elle ne marche pas si une partie de la couche Transport est chiffrée, comme c'est le cas avec QUIC.)

Autre cas où un boitier intermédiaire ressent le besoin d'accéder aux informations des couches supérieures, les ACL. La plupart des pare-feux permettent d'utiliser comme critère de filtrage les numéros de ports, ce qui va nécessiter d'analyser la chaine des en-têtes d'extension IPv6 pour parvenir à la couche Transport. Entre les pare-feux mal faits qui cherchent les informations de la couche Transport immédiatement après l'en-tête fixe (car le programmeur a tout simplement sauté la partie du RFC qui parlait des en-têtes d'extension) et les difficultés posées par le fait, qu'avant le RFC 6564, les en-têtes d'extension inconnus étaient impossibles à analyser, on voit qu'arriver à la couche Transport n'est pas si facile que ça (le RFC dit qu'il est plus compliqué d'analyser IPv6 qu'IPv4, ce qui est très contestable ; mais ce n'est en effet pas plus facile). Cela peut avoir des conséquences en terme de sécurité, par exemple si un méchant ajoute des en-têtes d'extension dans l'espoir que ses paquets ne soient pas correctement identifiés (cf. RFC 7113).

Autre exemple, le réassemblage des paquets fragmentés nécessite un état (mémoriser les fragments en cours de réassemblage), ce qui peut être fatal à la mémoire du pare-feu, notamment en cas d'attaque. Pour les coûts de ce filtrage, voir l'article d'E. Zack « Firewall Security Assessment and Benchmarking IPv6 Firewall Load Tests ». Cette difficulté peut encourager les pare-feux à jeter les paquets ayant des en-têtes d'extension, surtout si un administrateur réseaux ignorant dit bien fort « ces en-têtes d'extension ne servent à rien de toute façon » (RFC 7872).

Un problème proche est celui de la protection contre les attaques par déni de service. Filtrer avec les adresses IP peut être fait rès efficacement (cf. RFC 5635) mais ne marche pas, par exemple si l'adresse IP source est usurpée. Une des méthodes utilisées alors est de repérer un motif récurrent dans les paquets envoyés par l'attaquant, et de filtrer sur ce motif (vous pouvez lire ici un exemple avec le DNS). Là encore, des informations au-delà de la couche Réseau sont nécessaires. Toujours en sécurité, les NIDS ont aussi besoin de plus d'informations que ce que fournit la couche Réseau.

Et, bien sûr, comme toute complexité, les en-têtes d'extension augmentent les risques de sécurité, d'autant plus qu'il y a un cercle vicieux : comme ils sont peu utilisés, le code qui les traite est peu testé, donc il y a des bogues, donc ils sont peu utilisés, etc.

Donc, un certain nombre de machines intermédiaires, qui assurent des fonctions allant au-delà de ce que fait un « simple » routeur, ont des problèmes avec les en-têtes d'extension IPv6 et choisissent souvent la solution de facilité, qui est de les jeter systématiquement.


Téléchargez le RFC 9098


L'article seul

Utiliser les « middleboxes » de censure pour des attaques par déni de service

Première rédaction de cet article le 17 septembre 2021


Une méthode courante pour réaliser une attaque par déni de service sur l'Internet est de trouver un réflecteur, une machine qui, sollicitée par l'attaquant, va envoyer des paquets vers la victime. Les bons (du point de vue de l'attaquant…) réflecteurs font en outre de l'amplification, émettant davantage de paquets et/ou d'octets qu'envoyés par l'attaquant. Un article à la conférence Usenix d'août 2021 expose un nouveau type de réflecteurs : les innombrables middleboxes placées pour censurer des communications sont tellement mal conçues qu'elles font d'excellents (du point de vue de l'attaquant…) réflecteurs.

Détaillons cet article, « Weaponizing Middleboxes for TCP Reflected Amplification ». Le but d'un attaquant est de trouver de nombreux réflecteurs (plus ils sont nombreux, plus l'attaque sera efficace) mais aussi de maximiser l'amplification (on parle de BAF - Bandwidth Amplification Factor - pour le gain en octets et de PAF - Packet Amplification Factor - pour le gain en paquets). On a ainsi vu des attaques exploitant l'amplification de protocoles utilisant UDP, comme par exemple le DNS ou bien NTP. Une des bases de l'attaque par réflexion étant de mentir sur son adresse IP, a priori, ces attaques ne sont pas possibles avec TCP, qui protège contre cette usurpation (RFC 5961). Mais, en fait, on sait déjà que des attaques par réflexion avec TCP sont possibles, et qu'elles ont parfois un bon BAF. C'est ce que développent les auteurs de l'article.

Comme réflecteurs, ils utilisent des middleboxes, ces engins installés en intermédiaires sur un grand nombre de chemins sur l'Internet, qui examinent le trafic et agissent, souvent n'importe comment. Une utilisation courante des middleboxes est la censure, soit étatique (au niveau d'un pays), soit au niveau d'un réseau local. Par exemple, la middlebox va examiner le trafic HTTP et, si l'adresse IP de destination est sur sa liste de blocage, empêcher la communication. Une des façons de le faire est de prétendre être le vrai serveur et de renvoyer une page indiquant que la connexion est bloquée : uae-web-blocked.jpg

Arrivé là, vous commencez à voir comment cela peut être exploité pour une attaque : l'attaquant envoie un paquet TCP d'ouverture de connexion (paquet SYN) vers une adresse IP censurée, en usurpant l'adresse IP de la victime, et le message de censure, avec l'image, sera envoyée à la victime, fournissant un BAF sérieux.

Mais, là, vous allez me dire que ça ne marchera pas, TCP ne fonctionne pas comme cela : la middlebox n'arrivera pas à établir une session TCP complète puisque la victime ne répondra pas aux accusés de réception, ou bien enverra un paquet de fin de session (paquet RST). Mais c'est là que l'article devient intéresssant : les auteurs ont découvert que de nombreuses middleboxes ne font pas du TCP correct : elles envoient le message de censure (une page Web complète, avec images), sans attendre qu'une session TCP soit établie.

Ce n'est pas uniquement de l'incompétence de la part des auteurs des logiciels qui tournent dans la middlebox. C'est aussi parce que, notamment dans le cas de la censure étatique, la middlebox ne voit pas forcément passer tous les paquets, le trafic Internet étant souvent asymétrique (si on a plusieurs liaisons avec l'extérieur). Et puis il faut aller vite et avoir le moins possible d'état à mémoriser. La middlebox ne se donne donc pas la peine de vérifier que la session TCP a été établie, elle crache ses données tout de suite, assomant la victime pour le compte de l'attaquant. L'amplification maximale observée (en octets, le BAF) a été de plus de 7 000… Et certains cas pathologiques permettaient de faire encore mieux.

Comment ont été trouvées les middleboxes utilisables ? Comme l'attaque ne marche que si la middlebox ne fait pas du TCP correct, les conditions exactes du déclenchement de la réflexion ne sont pas faciles à déterminer. Les auteurs ont donc envoyé une variété de paquets TCP (avec ou sans PSH, ACK, etc) et utilisé le système d'apprentissage Geneva pour découvrir la solution la plus efficace. (Au passage, le meilleur déclencheur de la censure semble être www.youporn.com, largement bloqué un peu partout.) En balayant tout l'Internet avec ZMap, ils ont pu identifier un grand nombre de réflecteurs. Ils ne les ont évidemment pas utilisé pour une vraie attaque, mais des méchants auraient pu le faire, montrant ainsi le danger que présente ces boitiers bogués et largement répandus (ils sont très populaires auprès des décideurs), alors qu'ils fournissent une armée de réflecteurs prêts à l'emploi.

Certains réflecteurs arrivent même à des facteurs d'amplification incroyables, voire infinis (une fois un paquet envoyé par l'attaquant, le tir de barrage du réflecteur ne cesse jamais). Les auteurs expliquent cela par des boucles de routage, faisant passer le paquet déclencheur plusieurs fois par la middlebox (et parfois sans diminuer le TTL), ainsi que par des réactions aux réactions de la victime (qui envoie des paquets RST).

Des bons réflecteurs d'attaque ont été identifiés à des nombreux endroits, comme l'université Brigham Young ou la municipalité de Jacksonville. Identifier les produits utilisés a été plus difficile mais on pu repérer le Dell SonicWALL NSA 220 ou un équipement Fortinet. D'un point de vue géopolitique, on notera que les réflecteurs sont situés un peu partout, avec évidemment davantage de présence dans les dictatures. Par contre, la Chine est assez peu représentée, leur système de censure étant (hélas) plus intelligement bâti.


L'article seul

Version 14 d'Unicode

Première rédaction de cet article le 16 septembre 2021


Le mardi 14 septembre est sortie la version 14 d'Unicode (retardée pour cause de Covid-19). Une description officielle des principaux changements est disponible mais voici ceux qui m'ont intéressé particulièrement. (Il n'y a pas de changement radical.)

Pour explorer plus facilement la grande base Unicode, j'utilise un programme qui la convertit en SQL et permet ensuite de faire des analyses variées. Faisons quelques requêtes SQL :

ucd=> SELECT count(*) AS Total FROM Characters;
 total  
--------
 144762

Combien de caractères sont arrivés avec la version 14 ?

ucd=> SELECT version,count(version) FROM Characters GROUP BY version ORDER BY version::float;
...
 11.0    |   684
 12.0    |   554
 12.1    |     1
 13.0    |  5930
 14.0    |   838

838 nouveaux caractères, c'est une version calme (la version 13 apportait bien davantage de caractères). Quels sont ces nouveaux caractères ?

ucd=> SELECT To_U(codepoint) AS Code_point, name FROM Characters WHERE version='14.0' ORDER BY Codepoint;
 code_point |                                    name                                    
-----------+----------------------------------------------------------------------------
...
 U+870      | ARABIC LETTER ALEF WITH ATTACHED FATHA
 U+871      | ARABIC LETTER ALEF WITH ATTACHED TOP RIGHT FATHA
 U+872      | ARABIC LETTER ALEF WITH RIGHT MIDDLE STROKE
 U+873      | ARABIC LETTER ALEF WITH LEFT MIDDLE STROKE
 U+874      | ARABIC LETTER ALEF WITH ATTACHED KASRA
...
 U+12F90   | CYPRO-MINOAN SIGN CM001
 U+12F91   | CYPRO-MINOAN SIGN CM002
 U+12F92   | CYPRO-MINOAN SIGN CM004
 U+12F93   | CYPRO-MINOAN SIGN CM005
 ...
 U+1CF00    | ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT
 U+1CF01    | ZNAMENNY COMBINING MARK NIZKO S KRYZHEM ON LEFT
 U+1CF02    | ZNAMENNY COMBINING MARK TSATA ON LEFT
...
 U+1E290   | TOTO LETTER PA
 U+1E291   | TOTO LETTER BA
 U+1E292   | TOTO LETTER TA
 U+1E293   | TOTO LETTER DA
...
 U+1FAAC    | HAMSA
 U+1FAB7    | LOTUS
 U+1FAB8    | CORAL
 U+1FAB9    | EMPTY NEST
 U+1FABA    | NEST WITH EGGS
 ...

Cette version amène en effet plusieurs écritures nouvelles comme le toto, le chypro-minoen (toujours pas déchiffré, ce qui explique que ses caractères aient un numéro et pas un nom), le vieil ouïghour (écriture pour laquelle ont été fabriquées les plus anciens caractères mobiles connus), le vithkuqi, ou le tangsa. On trouve également beaucoup de nouveaux caractères de l'alphabet arabe pour écrire des langues non-arabes.

Plus anecdotique, on trouve également la notation musicale Znamenny.

Si vous avez les bonnes polices de caractères, vous allez pouvoir voir quelques exemples (sinon, le lien mène vers Uniview). Un nouveau symbole apparait, le Som (), pour la monnaie officielle du Kirghizistan. Et on a l'habituelle succession de nouveaux émojis, plus ou moins utiles. Les recruteurs aimeront l'index pointé 🫵, les royalistes seront contents de la tête couronnée 🫅, les nostalgiques d'Usenet auront le troll 🧌, les fanas de Dune frémiront en voyant l'eau qu'on verse 🫗, les geeks s'angoisseront de la batterie vide 🪫 et les partisans de la surveillance de la population noteront qu'on a un émoji « carte d'identité » 🪪. Les personnes transgenres remarqueront l'homme enceint (🫃, ainsi que la personne enceinte 🫄, la femme enceinte 🤰 était arrivée en Unicode version 9).

Tiens, d'ailleurs, combien de caractères Unicode sont des symboles (il n'y a pas que les emojis parmi eux, mais Unicode n'a pas de catégorie « emoji ») :

 ucd=> SELECT count(*) FROM Characters  WHERE category IN ('Sm', 'Sc', 'Sk', 'So');
 count 
-------
  7741

Ou, en plus détaillé, et avec les noms longs des catégories :

ucd=> SELECT description,count(category) FROM Characters,Categories WHERE Categories.name = Characters.category AND category IN ('Sm', 'Sc', 'Sk', 'So') GROUP BY category, description;
   description   | count 
-----------------+-------
 Modifier_Symbol |   125
 Other_Symbol    |  6605
 Math_Symbol     |   948
 Currency_Symbol |    63

L'article seul

RFC 9107: BGP Optimal Route Reflection (BGP ORR)

Date de publication du RFC : Août 2021
Auteur(s) du RFC : R. Raszuk (NTT Network Innovations), B. Decraene (Orange), C. Cassar, E. Aman, K. Wang (Juniper Networks)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF idr
Première rédaction de cet article le 13 septembre 2021


Les grands AS ont tellement de routeurs BGP qu'ils ne peuvent pas connecter chaque routeur à tous les autres. On utilise alors souvent des réflecteurs de route, un petit nombre de machines parlant BGP auxquelles tout le monde se connecte, et qui redistribuent les routes externes apprises. Mais une machine BGP ne redistribue que les routes qu'elle utiliserait elle-même. Or, le réflecteur risque de faire un choix en fonction de sa position dans le réseau, qui n'est pas la même que celle du routeur « client ». Les routeurs risquent donc d'apprendre du réflecteur des routes sous-optimales (la route optimale étant typiquement celle qui amène à la sortie le plus vite possible, en application de la méthode de la patate chaude). Ce RFC définit une extension de BGP qui va permettre de sélectionner des routes spécifiques à un client, ou à un groupe de clients.

Un petit rappel : un réflecteur de routes (route reflector) fonctionne sur iBGP (Internal BGP), à l'intérieur d'un AS, alors que les serveurs de routes (route server) font de l'eBGP (External BGP), par exemple sur un point d'échange. Ces réflecteurs sont décrits dans le RFC 4456. Ils ne sont pas la seule méthode pour distribuer l'information sur les routes externes à l'intérieur d'un grand AS, mais c'est quand même la solution la plus fréquente.

Le RFC 4456 notait déjà que, vu les coûts attribués aux liens internes à l'AS, le réflecteur ne choisirait pas forcément les mêmes routes que si on avait utilisé un maillage complet. Le routage « de la patate chaude » (qui consiste à essayer de faire sortir le paquet de son réseau le plus vite possible, pour que ce soit un autre qui l'achemine) risque donc de ne pas aussi bien marcher : le point de sortie lorsqu'on utilise le réflecteur sera peut-être plus éloigné que si on avait le maillage complet, surtout si le réflecteur est situé en dehors du chemin habituel des paquets et n'a donc pas la même vision que les routeurs « normaux ». Or, c'est un cas fréquent. Le réflecteur choisira alors des routes qui sont optimales pour lui, mais qui ne le sont pas pour ces routeurs « normaux ».

La solution ? Permettre à l'administrateur réseaux de définir une localisation virtuelle pour le réflecteur, à partir de laquelle il fera ses calculs et choisira ses routes, au lieu d'utiliser sa localisation physique. Cette localisation virtuelle sera une adresse IP. Le réflecteur peut avoir plusieurs de ces localisations virtuelles, adaptées à des publics différents. Bref, le texte du RFC 4271 qui concerne la sélection de la meilleure route (section 9.1.2.2 du RFC 4271) est modifié pour remplacer « en fonction du saut suivant » par « en fonction de l'adresse IP configurée dans le réflecteur ».

Pour que cela marche, il faut que le réflecteur ait une vue complète du réseau, pour pouvoir calculer des coûts à partir de n'importe quel point du réseau. C'est possible avec les IGP à état des liens comme OSPF, ou bien avec BGP-LS (RFC 7752).

Et si le réflecteur a plusieurs clients ayant des desiderata différents, par exemple parce qu'ils sont situés à des endroits différents ? Dans ce cas, il doit faire tourner plusieurs processus de décision, chacun configuré avec une localisation vituelle différente.

Les principales marques de routeurs mettent déjà en œuvre ce RFC, comme on peut le voir sur la liste des implémentations. Du côté des logiciels qui ne sont pas forcément installés sur des routeurs, il semble que BIRD ne sache pas encore faire comme décrit dans ce RFC.


Téléchargez le RFC 9107


L'article seul

RFC 9109: Network Time Protocol Version 4: Port Randomization

Date de publication du RFC : Août 2021
Auteur(s) du RFC : F. Gont, G. Gont (SI6 Networks), M. Lichvar (Red Hat)
Chemin des normes
Première rédaction de cet article le 13 septembre 2021


Le protocole NTP utilisait traditionnellement un port bien connu, 123, comme source et comme destination. Cela facilite certaines attaques en aveugle, lorsque l'attaquant ne peut pas regarder le trafic, mais sait au moins quels ports seront utilisés. Pour compliquer ces attaques, ce RFC demande que NTP utilise des numéros de ports aléatoires autant que possible.

NTP est un très vieux protocole (sa norme actuelle est le RFC 5905 mais sa première version date de 1985, dans le RFC 958). Dans son histoire, il a eu sa dose des failles de sécurité. Certaines des attaques ne nécessitaient pas d'être le chemin entre deux machines qui communiquent car elles pouvaient se faire en aveugle. Pour une telle attaque, il faut deviner un certain nombre de choses sur la communication, afin que les paquets de l'attaquant soient acceptés. Typiquement, il faut connaitre les adresses IP source et destination, ainsi que les ports source et destination et le key ID de NTP (RFC 5905, section 9.1). NTP a plusieurs modes de fonctionnement (RFC 5905, sections 2 et 3). Certains nécessitent d'accepter des paquets non sollicités et, dans ce cas, il faut bien écouter sur un port bien connu, en l'occurrence 123. Mais ce n'est pas nécessaire dans tous les cas et notre RFC demande donc qu'on n'utilise le port bien connu que si c'est nécessaire, au lieu de le faire systématiquement comme c'était le cas au début de NTP et comme cela se fait encore trop souvent (« Usage Analysis of the NIST Internet Time Service »). C'est une application à NTP d'un principe général sur l'Internet, documenté dans le RFC 6056 : n'utilisez pas de numéros de port statiques ou prévisibles. Si on suit ce conseil, un attaquant en aveugle aura une information de plus à deviner, ce qui gênera sa tâche. Le fait d'utiliser un port source fixe a valu à NTP un CVE, CVE-2019-11331.

La section 3 du RFC résume les considérations à prendre en compte. L'idée de choisir aléatoirement le port source pour faire face aux attaques en aveugle est présente dans bien d'autres RFC comme le RFC 5927 ou le RFC 4953. Elle est recommandée par le RFC 6056. Un inconvénient possible (mais mineur) est que la sélection du chemin en cas d'ECMP peut dépendre du port source (calcul d'un condensat sur le tuple à cinq élements {protocole, adresse IP source, adresse IP destination, port source, port destination}, avant d'utiliser ce condendat pour choisir le chemin) et donc cela peut affecter les temps de réponse, troublant ainsi NTP, qui compte sur une certaine stabilité du RTT. D'autre part, le port source aléatoire peut gêner certaines stratégies de filtrage par les pare-feux : on ne peut plus reconnaitre un client NTP à son port source. Par contre, un avantage du port source aléatoire est que certains routeurs NAT sont suffisamment bogués pour ne pas traduire le port source s'il fait partie des ports « système » (inférieurs à 1 024), empêchant ainsi les clients NTP situés derrière ces routeurs de fonctionner. Le port source aléatoire résout le problème.

Assez de considérations, passons à la norme. Le RFC 5905, section 9.1, est modifié pour remplacer la supposition qui était faite d'un port source fixe par la recommandation d'un port source aléatoire.

Cela ne pose pas de problème particulier de mise en œuvre. Par exemple, sur un système POSIX, ne pas faire de bind() sur la prise suffira à ce que les paquets associés soient émis avec un port source aléatoirement sélectionné par le système d'exploitation.

À propos de mise en œuvre, où en sont les logiciels actuels ? OpenNTPD n'a jamais utilisé le port source 123 et est donc déjà compatible avec la nouvelle règle. Même chose pour Chrony. Par contre, à ma connaissance, ntpd ne suit pas encore la nouvelle règle.


Téléchargez le RFC 9109


L'article seul

RFC 9103: DNS Zone Transfer over TLS

Date de publication du RFC : Août 2021
Auteur(s) du RFC : W. Toorop (NLnet Labs), S. Dickinson (Sinodun IT), S. Sahib (Brave Software), P. Aras, A. Mankin (Salesforce)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dprive
Première rédaction de cet article le 12 septembre 2021


Traditionnellement, le transfert d'une zone DNS depuis le serveur maitre vers ses esclaves se fait en clair. Si l'authentification et l'intégrité sont protégées, par exemple par TSIG, le transfert en clair ne fournit pas de confidentialité. Or on n'a pas forcément envie qu'un tiers puisse lire l'entièreté de la zone. Ce RFC normalise un transfert de zones sur TLS, XoT (zone transfer over TLS). Il en profite pour faire quelques ajustement dans l'utilisation de TCP pour les transferts de zone.

Le RFC fait quarante-deux pages mais le principe est très simple. Au lieu de faire le transfert de zones (aussi nommé AXFR, RFC 5936) directement sur TCP, on le fait sur du TLS, comme le fait DoT (RFC 7858). Le reste du RFC est consacré à des détails pratiques, mais le concept tient en une seule phrase.

Le DNS sur TLS est normalisé depuis cinq ans, mais il ne couvre officiellement que la communication entre la machine terminale et le résolveur. Bien que des essais aient été faits pour communiquer en TLS avec des serveurs faisant autorité, rien n'est encore normalisé. Mais, au fait, est-ce que les transferts de zone ont vraiment besoin de confidentialité ? Le RFC 9076 ne traite pas le problème, le renvoyant aux RFC 5936 (la norme du transfert de zones, qui parle de la possibilité de restreindre ce transfert à des machines autorisées) et au RFC 5155 (qui parle des risques d'énumération de tous les noms d'une zone). Certes, le DNS étant public, tout le monde peut interroger les serveurs faisant autorité, et connaitre ainsi les données associées à un nom de domaine, mais il faut pour cela connaitre les noms. Si les petites zones n'ont rien de secret (elles ne contiennent que l'apex et www), si certaines zones sont publiques (la racine, par exemple), pour les autres zones, leur responsable ne souhaite pas forcément qu'on ait accès à tous les noms. Certains peuvent être le nom d'une personne (le-pc-de-henri.zone.example), et donc être des données personnelles, à protéger (le RFC note bien sûr que c'est une mauvaise pratique, mais elle existe), certains noms peuvent renseigner sur les activités et les projets d'une entreprise. Bref, il peut être tout à fait raisonnable de ne pas vouloir transmettre la zone en clair.

À noter qu'une surveillance du réseau pendant un transfert de zones fait en clair n'est pas la seule façon de trouver tous les noms. Une autre technique est l'énumération, utilisant par exemple les enregistrement NSEC de DNSSEC. Les enregistrement NSEC3 du RFC 5155 ont été conçus pour limiter ce risque (mais pas le supprimer ; le projet NSEC5 va essayer de résoudre le problème mais c'est loin d'être garanti).

Comment sécurise-t-on les transferts de zone aujourd'hui ? Les TSIG du RFC 8945 protègent l'intégrité mais pas la confidentialité. Vous pouvez trouver des détails pratiques sur la sécurisation des transferts de zone, combinant TSIG et ACL, dans un document du NIST en anglais et un document de l'ANSSI en français. On peut aussi en théorie utiliser IPsec entre maitre et esclaves mais cela semble irréaliste. D'où l'idée de base de ce nouveau RFC : mettre le transfert de zones sur TLS. Après tout, on utilise déjà TLS pour sécuriser la communication entre le client final et le résolveur : le protocole DoT, normalisé dans le RFC 7858.

Notre RFC introduit quelques nouveaux acronymes rigolos :

  • XFR : couvre à la fois AXFR (RFC 5936) et IXFR (transferts incrémentaux, RFC 1995). Donc, XFR-over-TLS, c'est un transfert de zones, complet ou incrémental, sur TLS.
  • XoT : acronyme pour XFR-over-TLS.
  • AXoT : AXFR sur TLS.
  • IXoT : IXFR sur TLS.

Pour la terminologie liée à la vie privée, voir le RFC 6973.

La section 3 du RFC spécifie le modèle de menace : on veut protéger le transfert de zones contre l'espionnage par un tiers, mais on n'essaie pas de cacher l'existence de la zone, ou le fait que telle machine soit serveur faisant autorité pour la zone. En effet, ces informations peuvent être obtenues facilement en interrogeant le DNS ou, dans le cas d'un maitre caché, en regardant le trafic réseau, sans même en décrypter le contenu.

Les principes de conception de XoT ? Fournir de la confidentialité et de l'authentification grâce à TLS, mais aussi en profiter pour améliorer les performances. Un certain nombre de programmes DNS ne peuvent pas, par exemple, utiliser la même connexion TCP pour plusieurs transferts de zone (même si le RFC 5936 le recommande). Il est difficile de résoudre ce problème sans casser les programmes existants et pas encore mis à jour. Par contre, XoT étant nouveau, il peut spécifier dès le début certains comportements qui améliorent les performances, comme l'utilisation d'une seule connexion pour plusieurs transferts.

Petit rappel de comment fonctionne le transfert de zones (RFC 5936, si vous voulez tous les détails). D'abord, le fonctionnement le plus courant : le serveur maitre (ou primaire) envoie un NOTIFY (RFC 1996) à ses esclaves (ou secondaires). Ceux-ci envoient une requête de type SOA au maitre puis, si le numéro de série récupéré est supérieur au leur, ils lancent l'AXFR sur TCP. Il y a des variations possibles : si le maitre n'envoie pas de NOTIFY ou bien s'ils sont perdus, les esclaves testent quand même de temps en temps le SOA (paramètre Refresh du SOA). Autre variante possible : les esclaves peuvent utiliser IXFR (RFC 1995) au lieu de AXFR pour ne transférer que la partie de la zone qui a changé. Et ils peuvent avoir à se rabattre en AXFR si le maitre ne gérait pas IXFR. Et les messages IXFR peuvent être sur UDP ou sur TCP (en pratique, BIND, NSD et bien d'autres font toujours l'IXFR sur TCP). Bref, il y a plusieurs cas. Les messages NOTIFY et SOA ne sont pas considérés comme sensibles du point de vue de la confidentialité et XoT ne les protège pas.

Maintenant, avec XoT, comment ça se passera (section 6 du RFC) ? Une fois le transfert de zones décidé (via SOA, souvent précédé du NOTIFY), le client (qui est donc le serveur secondaire) doit établir une connexion TLS (1.3 minimum), en utilisant ALPN, avec le nom dot (on notera que c'est donc le même ALPN pour XoT et pour DoT, l'annexe A du RFC explique ce choix). Le port est par défaut le classique 853 de DoT. Le client authentifie le serveur via les techniques du RFC 8310. Le serveur vérifie le client, soit avec des mécanismes TLS (plus sûrs mais plus compliqués à mettre en œuvre), soit avec les classiques ACL. Le client TLS (le serveur DNS esclave) fait ensuite de l'IXFR ou du AXFR classique sur ce canal TLS. Le serveur doit être capable d'utiliser les codes d'erreur étendus du RFC 8914.

Voilà, c'est tout. Maintenant, quelques détails pratiques. D'abord, rappelez-vous qu'il n'existe pas à l'heure actuelle de norme pour du DoT entre résolveur et serveur faisant autorité. Mais il y a des expériences en cours. Ici, par exemple, je fais du DoT avec un serveur faisant autorité pour facebook.com :

% kdig +tls @a.ns.facebook.com.  SOA facebook.com   
;; TLS session (TLS1.3)-(ECDHE-X25519)-(RSA-PSS-RSAE-SHA256)-(AES-256-GCM)
...
;; ANSWER SECTION:
facebook.com.       	3600	IN	SOA	a.ns.facebook.com. dns.facebook.com. 1631273358 14400 1800 604800 300

;; Received 86 B
;; Time 2021-09-10 13:35:44 CEST
;; From 2a03:2880:f0fc:c:face:b00c:0:35@853(TCP) in 199.0 ms

Mais on pourrait imaginer des serveurs faisant autorité qui ne fournissent pas ce service, pas encore normalisé, mais qui veulent faire du XoT. Est-ce possible de réserver TLS aux transferts de zone, mais sans l'utiliser pour les requêtes « normales » ? Oui, et dans ce cas le serveur doit répondre REFUSED à ces requêtes normales, avec le code d'erreur étendu 21 (Not supported). Ceci dit, il est difficile de dire comment réagiront les clients ; ils risquent d'ignorer le code d'erreur étendu et de recommencer bêtement (ou au contraire d'arrêter complètement d'utiliser le serveur).

Le but de XoT est de protéger le contenu de la zone contre les regards indiscrets. Mais comme vous le savez, TLS ne dissimule pas la taille des données qui passent entre ses mains et l'observation de cette taille peut donner des informations à un observateur, par exemple la taille des mises à jour en IXFR indique l'activité d'une zone. Le RFC suggère donc de remplir les données. Cela peut nécessiter d'envoyer des réponses vides, ce qui était interdit par les précédents RFC mais est maintenant autorisé.

Et les différentes formes de parallélisme des requêtes que permet le DNS sur TCP (et donc DoT) ? Elles sont décrites dans le RFC 7766. Si elles sont nécessaires pour exploiter le DNS de manière satisfaisante, elles ne sont pas forcément utiles pour XoT et notre RFC explique qu'on n'est pas forcé, par exemple, de permettre le pipelining (envoi d'une nouvelle requête quand la réponse à la précédente n'est pas encore arrivée) quand on fait du XoT. Par contre, comme avec tous les cas où on utilise du DNS sur TCP, il est recommandé de garder les connexions ouvertes un certain temps, par exemple en suivant le RFC 7828.

J'ai parlé plus haut de l'authentification dans une session XoT. La section 9 du RFC revient en détail sur cette question. Quels sont les mécanismes existants pour authentifier un transfert de zones ? Ils diffèrent par les services qu'ils rendent :

  • Authentification de la source des données DNS.
  • Authentification du correspondant (qui n'est pas forcément la source des données).
  • Confidentialité.

Les mécanismes possibles sont :

  • TSIG (RFC 8945) ; utiisant des clés partagées (ce qui n'est pas pratique), il permet d'authentifier la source des données.
  • SIG(0) (RFC 2931) ; utilisant de la cryptographie asymétrique, il permet d'authentifier la source des données. Ceci dit, il n'est quasiment jamais mis en œuvre dans les programmes DNS.
  • TLS en mode « opportuniste » (sans authentification) ; il ne garantit rien, sauf peut-être contre un observateur passif.
  • TLS en mode strict (obligation d'authentification du serveur par le client, RFC 8310) ; cela permet l'authentification du correspondant, et la confidentialité (mais ne garantit pas que le correspondant est la vraie source des données).
  • TLS mutuel ; le client s'authentifie également.
  • ACL fondées sur l'adresse IP ; très répandu, ce mécanisme permet au serveur d'« authentifier » le client. Une faiblesse pour le cas de XoT : le serveur doit accepter l'établissement de la session TLS avant de savoir s'il s'agit de XoT ou de DNS ordinaire sur TLS.
  • ZONEMD (RFC 8976) ; ce n'est pas vraiment une technique d'authentification mais elle peut être utile, en combinaison avec XoT.

Quelles sont les mises en œuvres actuelles de XoT ? Une liste existe. Actuellement, il n'y a guère que NSD qui permet le XoT mais le travail est en cours pour d'autres. Voyons comment faire du XoT avec NSD. On télécharge la dernière version (XoT est apparu en 4.3.7), on la compile (pas besoin d'options particulières) et on la configure, par exemple ainsi :

server:
       port: 7053
       ...
       tls-service-key: "server.key"
       tls-service-pem: "server.pem"
       # No TLS service if the port is not explicit in an interface definition
       ip-address: 127.0.0.1@7153
       tls-port: 7153

zone:
        name: "fx"
        zonefile: "fx"
	# NSD 4.3.7 (september 2021) : not yet a way to restrict XoT
        provide-xfr: 127.0.0.1 NOKEY 
  

Ainsi configuré, NSD va écouter sur le port 7153 en TLS. Notons qu'il n'y a pas de moyen de configurer finement : il accepte forcément XoT et les requêtes « normales ». De même, on ne peut pas obliger un client DNS à n'utiliser que XoT. Testons avec kdig, un client DNS qui accepte TLS, d'abord une requête normale :

    
% kdig +tls @localhost -p 7153 SOA fx 
;; TLS session (TLS1.3)-(ECDHE-SECP256R1)-(RSA-PSS-RSAE-SHA256)-(AES-256-GCM)
;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 11413
...
;; ANSWER SECTION:
fx.                 	600	IN	SOA	ns1.fx. root.fx. 2021091201 604800 86400 2419200 86400
...
;; Time 2021-09-12 11:06:39 CEST
;; From 127.0.0.1@7153(TCP) in 0.2 ms

  

Parfait, tout marche. Et le transfert de zones ?


% kdig +tls @localhost -p 7153 AXFR fx
;; AXFR for fx.
fx.                 	600	IN	SOA	ns1.fx. root.fx. 2021091201 604800 86400 2419200 86400
...
;; Received 262 B (1 messages, 9 records)
;; Time 2021-09-12 11:07:25 CEST
;; From 127.0.0.1@7153(TCP) in 2.3 ms

  

Excellent, nous faisons du XoT. Wireshark nous le confirme :

% tshark -d tcp.port==7153,tls -i lo port 7153
...
4 0.001200185    127.0.0.1 → 127.0.0.1    TLSv1 439 Client Hello
...
6 0.006305031    127.0.0.1 → 127.0.0.1    TLSv1.3 1372 Server Hello, Change Cipher Spec, Application Data, Application Data, Application Data, Application Data
...
10 0.007385823    127.0.0.1 → 127.0.0.1    TLSv1.3 140 Application Data
  

Dans ce cas, on utilisait NSD comme serveur primaire, recevant les clients XoT. Il peut aussi fonctionner comme serveur secondaire et il est alors client XoT. Je n'ai pas testé mais John Shaft l'a fait et en gros la configuration ressemble à :

tls-auth:
   name: un-nom-pour-identifier-ce-bloc
   auth-domain-name: nom-du-serveur-principal
zone:
   ...
   request-xfr: AXFR 2001:db8::1 NOKEY un-nom-pour-identifier-ce-bloc
  

Téléchargez le RFC 9103


L'article seul

RFC 9108: YANG Types for DNS Classes and Resource Record Types

Date de publication du RFC : Septembre 2021
Auteur(s) du RFC : L. Lhotka (CZ.NIC), P. Spacek (ISC)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 9 septembre 2021


YANG est le langage standard à l'IETF pour décrire des modèles de données, afin de, par exemple, gérer automatiquement des ressources. Ce RFC décrit le module YANG iana-dns-class-rr-type, qui rassemble les définitions des types d'enregistrements DNS.

YANG est normalisé dans le RFC 7950, et d'innombrables RFC décrivent des modules YANG pour de nombreux protocoles. YANG est utilisé par des protocoles de gestion à distance de ressources, comme RESTCONF (RFC 8040) ou NETCONF (RFC 6241). Mais ce RFC est le premier qui va utiliser YANG pour le DNS. L'un des objectifs (à long terme pour l'instant) est d'utiliser RESTCONF ou un équivalent pour gérer des serveurs DNS, résolveurs ou serveurs faisant autorité. (C'est un très vieux projet que cette gestion automatisée et normalisée des serveurs DNS.) Un mécanisme standard de gestion des serveurs nécessite un modèle de données commun, et c'est là que YANG est utile. Notre RFC est encore loin d'un modèle complet, il ne définit que le socle, le type des données que le DNS manipule. C'est la version YANG de deux registres IANA, celui des types d'enregistrements DNS et celui des classes (même si ce dernier concept est bien abandonné aujourd'hui).

Le registre IANA pour le DNS contient treize sous-registres. Le RFC n'en passe que deux en YANG, les classes et les types d'enregistrement. Les autres devront attendre un autre RFC. Les types d'enregistrement sont modélisés ainsi :

typedef rr-type-name {
    type enumeration {
      enum A {
        value 1;
        description
          "a host address";
        reference
          "RFC 1035";
      }
      enum NS {
        value 2;
        description
          "an authoritative name server";
...
  

Et les classes (mais, rappelez-vous, seule la classe IN compte aujourd'hui) :

typedef dns-class-name {
    type enumeration {
      enum IN {
        value 1;
        description
          "Internet (IN)";
        reference
          "RFC 1035";
      }
      enum CH {
        value 3;
        description
          "Chaos (CH)";
        reference
          "D. Moon, 'Chaosnet', A.I. Memo 628, Massachusetts Institute of
Technology Artificial Intelligence Laboratory, June 1981.";
}
...
  

Le module YANG complet se retrouve dans le registre IANA (créé par le RFC 6020).

Le module YANG devra suivre l'actuel registre IANA, qui utilise un autre format. Pour faciliter la synchronisation, le RFC contient une feuille de style XSLT pour convertir l'actuel format, qui est la référence, vers le format YANG. La feuille de style est dans l'annexe A du RFC mais vous avez une copie ici. Voici comment produire et vérifier le module YANG :

% wget https://www.iana.org/assignments/dns-parameters/dns-parameters.xml

% xsltproc iana-dns-class-rr-type.xsl dns-parameters.xml > iana-dns-class-rr-type.yang

% pyang iana-dns-class-rr-type.yang
  

Le moteur XSLT xsltproc fait partie de la libxslt. Le vérificateur YANG Pyang est distribué via GitHub mais on peut aussi l'installer avec pip (pip install pyang).


Téléchargez le RFC 9108


L'article seul

RFC 9106: Argon2 Memory-Hard Function for Password Hashing and Proof-of-Work Applications

Date de publication du RFC : Septembre 2021
Auteur(s) du RFC : A. Biryukov, D. Dinu (University of Luxembourg), D. Khovratovich (ABDK Consulting), S. Josefsson (SJD AB)
Pour information
Réalisé dans le cadre du groupe de recherche IRTF cfrg
Première rédaction de cet article le 8 septembre 2021


En général, en informatique, on essaie de diminuer la consommation de mémoire et de processeur des programmes, afin de les rendre plus efficaces. Mais il y a aussi des cas où on va tenter de réduire délibérement l'efficacité d'un programme. C'est le cas des fonctions de condensation qui sont utilisées en sécurité : on ne veut pas faciliter la tâche de l'attaquant. Ainsi, Argon2, spécifié dans ce RFC est volontairement très consommatrice de mémoire et d'accès à cette mémoire. Elle peut être utilisée pour condenser des mots de passe, ou pour des sytèmes à preuve de travail.

L'article original décrivant Argon2 est « Argon2: the memory-hard function for password hashing and other applications » et vous pouvez également lire « Argon2: New Generation of Memory-Hard Functions for Password Hashing and Other Applications ». Notre RFC reprend la description officielle, mais en s'orientant davantage vers les programmeurs et programmeuses qui devront mettre en œuvre cette fonction. Argon2 est conçu pour être memory-hard, c'est-à-dire faire souvent appel à la mémoire de la machine. Cela permet notamment aux ordinateurs classiques de tenir tête aux systèmes à base d'ASIC. (Par exemple, nombreuses sont les chaînes de blocs utilisant des preuves de travail. La fonction utilisée par Bitcoin, SHA-256, conçue pour être simple et rapide, n'est pas memory-hard et le résultat est qu'il y a belle lurette qu'un ordinateur, même rapide, n'a plus aucune chance dans le minage de Bitcoin. Seules les machines spécialisées peuvent rester en course, ce qui contribue à centraliser le minage dans peu de fermes de minage.) Argon2 est donc dur pour la mémoire, comme décrit dans l'article « High Parallel Complexity Graphs and Memory-Hard Functions ». À noter qu'Argon2 est très spécifique à l'architecture x86.

Argon2 se décline en trois variantes, Argon2id (celle qui est recommandée par le RFC), Argon2d et Argon2i. Argon2d a des accès mémoire qui dépendent des données, ce qui fait qu'il ne doit pas être employé si un attaquant peut examiner ces accès mémoire (attaque par canal auxiliaire). Il convient donc pour du minage de cryptomonnaie mais pas pour une carte à puce, que l'attaquant potentiel peut observer en fonctionnement. Argon2i n'a pas ce défaut mais est plus lent, ce qui ne gêne pas pour la condensation de mots de passe mais serait un problème pour le minage. Argon2id, la variante recommandée, combine les deux et est donc à la fois rapide et résistante aux attaques par canal auxiliaire. (Cf. « Tradeoff Cryptanalysis of Memory-Hard Functions », pour les compromis à faire en concevant ces fonctions dures pour la mémoire.) Si vous hésitez, prenez donc Argon2id. La section 4 du RFC décrit plus en détail les paramètres des variantes, et les choix recommandés.

Argon repose sur une fonction de condensation existante (qui n'est pas forcément dure pour la mémoire) et le RFC suggère Blake (RFC 7693).

La section 3 du RFC décrit l'algorithme mais je n'essaierai pas de vous le résumer, voyez le RFC.

La section 5 contient des vecteurs de test si vous voulez programmer Argon2 et vérifier les résultats de votre programme.

La section 7 du RFC revient en détail sur certaines questions de sécurité, notamment l'analyse de la résistance d'Argon2, par exemple aux attaques par force brute.


Téléchargez le RFC 9106


L'article seul

RFC 9096: Requirements for Customer Edge Routers to Mitigate IPv6 Renumbering Events

Date de publication du RFC : Août 2021
Auteur(s) du RFC : F. Gont (SI6 Networks), J. Zorz (6connect), R. Patterson (Sky UK), B. Volz (Cisco)
Réalisé dans le cadre du groupe de travail IETF v6ops
Première rédaction de cet article le 7 septembre 2021


Quand un FAI modifie la configuration de son réseau IPv6, les routeurs chez les clients finaux, les CPE, ne retransmettent pas toujours rapidement ce changement, ce qui mène parfois à des problèmes de connectivité. Ce RFC décrit ce que doivent faire ces CPE pour minimiser les conséquence négatives d'une rénumérotation d'un réseau.

Le problème est documenté dans le RFC 8978 : par exemple, lorsqu'un routeur chez M. Toutlemonde (une « box ») redémarre et « oublie » sa configuration réseau précédente, si elle a changé chez le FAI entretemps, les machines du réseau local de M. Toutlemonde risquent de continuer à utiliser pendant un certain une ancienne configuration, désormais invalide. Comment éviter cela ?

Notre RFC se penche surtout sur le cas où le routeur de M. Toutlemonde a appris son préfixe IPv6 depuis le FAI via la délégation de préfixe DHCP du RFC 8415, et qu'il retransmet l'information sur ce préfixe dans le réseau local avec le SLAAC du RFC 4862 (via les RA, Router Advertisements, RFC 4861) ou bien DHCP. Les machines terminales sur le réseau local peuvent aussi agir (ce sera dans un futur RFC) mais l'actuel RFC ne concerne que les routeurs. Il consiste en une série d'exigences auxquelles doivent se prêter les routeurs, exigences qui s'ajoutent à celles déjà présentes dans le RFC 7084 ou bien qui modifient des exigences de ce RFC 7084.

Beaucoup de ces exigences nécessitent un mécanisme de stockage d'informations sur le routeur, stockage qui doit survivre aux redémarrages, ce qui ne sera pas évident pour tous les routeurs. Ainsi, le RFC demande que, du côté WAN, le routeur utilise toujours le même identificateur (IAID, Identity Association IDentifier, RFC 8415, section 4.2) en DHCP (pour essayer de garder le même préfixe). Certains routeurs choisissent apparemment l'IAID au hasard à chaque démarrage, ce qui leur obtient un nouveau préfixe. Il vaut mieux le garder, mais cela nécessite qu'il puisse être stocké et mémorisé même en cas de redémarrage. Comme tous les routeurs n'ont pas de mécanisme de stockage stable, les exigences du RFC sont exprimées (dans le langage du RFC 2119) par un SHOULD et pas un MUST.

Autre exigence, qui relève du bon sens, le routeur ne doit pas, lorsqu'il utilise un préfixe du côté LAN (le réseau local), utiliser une durée de vie plus longue (options Preferred Lifetime et Valid Lifetime du message d'information sur le préfixe envoyé par le routeur, RFC 4861, section 4.6.2) que celle qu'il a lui-même appris en DHCP côté WAN. On ne doit pas promettre ce qu'on ne peut pas tenir, la durée du bail DHCP s'impose au routeur et aux annonces qu'il fait sur le réseau local.

Enfin, le routeur ne doit pas, au redémarrage, envoyer systématiquement un abandon du préfixe appris en DHCP (message DHCP RELEASE). Certains routeurs font apparemment cela, ce qui risque de déclencher une renumérotation brutale (RFC 8978).

Lorsque le préfixe change, le routeur devrait aussi signaler cela sur le réseau local. Là encore, cela impose une mémoire, un stockage stable. Il doit se souvenir de ce qu'il a reçu, et annoncé, précédemment, pour pouvoir annoncer sur le réseau local que ces anciens préfixes ne doivent plus être utilisés (cela se fait en annonçant ces préfixes, mais avec une durée de vie nulle). Dans un monde idéal, le routeur sera prévenu des changements de préfixe parce que le FAI réduira la durée de vie de ses baux DHCP, permettant un remplacement ordonné d'un préfixe par un autre. Dans la réalité, on a parfois des renumérotations brutales, sans préavis (RFC 8978). Le routeur doit donc également gérer ces cas.


Téléchargez le RFC 9096


L'article seul

RFC 9099: Operational Security Considerations for IPv6 Networks

Date de publication du RFC : Août 2021
Auteur(s) du RFC : E. Vyncke (Cisco), K. Chittimaneni (Square), M. Kaeo (Double Shot Security), E. Rey (ERNW)
Pour information
Réalisé dans le cadre du groupe de travail IETF opsec
Première rédaction de cet article le 7 septembre 2021


Tous les gens qui gèrent des réseaux IPv4 savent comment les sécuriser (normalement…). Et pour IPv6 ? Si ce n'est pas un protocole radicalement différent, il a quand même quelques particularités de sécurité. Ce RFC donne des conseils pratiques et concrets sur la sécurisation de réseaux IPv6. (Je le répète, mais c'est juste une nouvelle version d'IP : l'essentiel du travail de sécurisation est le même en v4 et en v6.)

Les différences entre IPv4 et IPv6 sont subtiles (mais, en sécurité, la subtilité compte, des petits détails peuvent avoir de grandes conséquences). Ceci dit, le RFC a tendance à les exagérer. Par exemple, il explique que la résolution d'adresses de couche 3 en adresses de couche 2 ne se fait plus avec ARP (RFC 826) mais avec NDP (RFC 4861). C'est vrai, mais les deux protocoles fonctionnent de manière très proche et ont à peu près les mêmes propriétés de sécurité (en l'occurrence, aucune sécurité). Plus sérieusement, le remplacement d'un champ d'options de taille variable dans IPv4 par les en-têtes d'extension d'IPv6 a certainement des conséquences pour la sécurité. Le RFC cite aussi le cas du NAPT (Network Address and Port Translation, RFC 2663). Souvent appelée à tort NAT (car elle ne traduit pas que l'adresse mais également le port), cette technique est très utilisée en IPv4. En IPv6, on ne fait pas de traduction ou bien on fait du vrai NAT, plus précisement du NPT (Network Prefix Translation, RFC 6296) puisqu'on change le préfixe de l'adresse. La phrase souvent entendue « en IPv6, il n'y a pas de NAT » est doublement fausse : c'est en IPv4 qu'on n'utilise pas le NAT, mais le NAPT, et on peut faire de la traduction d'adresses en IPv6 si on veut. NAT, NAPT ou NPT ne sont évidemment pas des techniques de sécurité mais elles peuvent avoir des conséquences pour la sécurité. Par exemple, toute traduction d'adresse va complexifier le réseau, ce qui introduit des risques. Autre facteur nouveau lié à IPv6 : la plupart des réseaux vont devoir faire de l'IPv4 et de l'IPv6 et les différentes techniques de coexistence de ces deux versions peuvent avoir leur propre impact sur la sécurité (RFC 4942).

La section 2 du RFC est le gros morceau du RFC ; c'est une longue liste de points à garder en tête quand on s'occupe de la sécurité d'un réseau IPv6. Je ne vais pas tous les citer, mais en mentionner quelques-uns qui donnent une bonne idée du travail du ou de la responsable de la sécurité.

D'abord, l'adressage. Aux débuts d'IPv6, l'idée était que les spécificités d'IPv6 comme le SLAAC allaient rendre la renumérotation des réseaux tellement triviale qu'on pourrait changer les adresses souvent. En pratique, ce n'est pas tellement le cas (RFC 7010) et il faut donc prêter attention à la conception de son adressage : on aura du mal à en changer. Heureusement, c'est beaucoup plus facile qu'en IPv4 : l'abondance d'adresses dispense des astuces utilisées en IPv4 pour essayer d'économiser chaque adresse. Par exemple, on peut donner à tous ses sous-réseaux la même longueur de préfixe, quelle que soit leur taille, ce qui simplifie bien les choses (le RFC 6177 est une lecture instructive). Comme en IPv4, les adresses peuvent être liées au fournisseur d'accès (PA, Provider Allocated) ou bien obtenues indépendamment de ce fournisseur (PI, Provider Independent). Le RFC 7381 discute ce cas. Cela peut avoir des conséquences de sécurité. Par exemple, les adresses PA sont en dernier ressort gérées par l'opérateur à qui il faudra peut-être demander certaines actions. Et ces adresses PA peuvent pousser à utiliser la traduction d'adresses, qui augmente la complexité. (D'un autre côté, les adresses PI sont plus difficiles à obtenir, surtout pour une petite organisation.) Ah, et puis, pour les machines terminales, le RFC 7934 rappelle à juste titre qu'il faut autoriser ces machines à avoir plusieurs adresses (il n'y a pas de pénurie en IPv6). Une des raisons pour lesquelles une machine peut avoir besoin de plusieurs adresses est la protection de la vie privée (RFC 8981).

Les gens habitués à IPv4 demandent souvent quel est l'équivalent du RFC 1918 en IPv6. D'abord, de telles adresses privées ne sont pas nécessaires en IPv6, où on ne manque pas d'adresses. Mais si on veut, on peut utiliser les ULA (Unique Local Addresses) du RFC 4193. Par rapport aux adresses privées du RFC 1918, elles ont le gros avantage d'être uniques, et donc d'éviter toute collision, par exemple quand deux organisations fusionnent leurs réseaux locaux. Le RFC 4864 décrit comment ces ULA peuvent être utilisés pour la sécurité.

Au moment de concevoir l'adressage, un choix important est celui de donner ou non des adresses IP stables aux machines. (Ces adresses stables peuvent leur être transmises par une configuration statique, ou bien en DHCP.) Les adresses stables facilitent la gestion du réseau mais peuvent faciliter le balayage effectué par un attaquant pendant une reconnaissance préalable. Contrairement à ce qu'on lit parfois encore, ce balayage est tout à fait possible en IPv6, malgré la taille de l'espace d'adressage, même s'il est plus difficile qu'en IPv4. Le RFC 7707 explique les techniques de balayage IPv6 possibles. Même chose dans l'article « Mapping the Great Void ». Bref, on ne peut pas compter sur la STO et donc, adresses stables ou pas, les machines connectées à l'Internet peuvent être détectées, et doivent donc être défendues.

Cela n'empêche pas de protéger la vie privée des utilisateurs en utilisant des adresses temporaires pour contacter l'extérieur. L'ancien système de configuration des adresses par SLAAC était mauvais pour la vie privée puisqu'il utilisait comme partie locale de l'adresse (l'IID, Interface IDentifier) l'adresse MAC, ce qui permettait d'identifier une machine même après qu'elle ait changé de réseau. Ce système est abandonné depuis longtemps (RFC 8064) au profit d'adresses aléatoires (RFC 8981). Ceci dit, ces adresses aléatoires posent un autre problème : comme elles changent fréquemment, elles ne permettent pas à l'administrateur réseau de suivre les activités d'une machine (c'est bien leur but), et on ne peut plus utiliser de mécanismes comme les ACL. Une solution possible est d'utiliser des adresses qui sont stables pour un réseau donné mais qui ne permettent pas de suivre une machine quand elle change de réseau, les adresses du RFC 7217. C'est dans beaucoup de cas le meilleur compromis. (Le RFC 7721 contient des détails sur les questions de sécurité liées aux adresses IP.)

On peut aussi couper SLAAC (cela peut se faire à distance avec des annonces RA portant le bit M) et n'utiliser que DHCP mais toutes les machines terminales n'ont pas un client DHCP.

En parlant de DHCP, lui aussi pose des problèmes de vie privée (décrits dans le RFC 7824) et si on veut être discret, il est recommandé d'utiliser le profil restreint défini dans le RFC 7844.

Après les adresses, la question des en-têtes d'extension, un concept nouveau d'IPv6. En IPv4, les options sont placées dans l'en-tête, qui a une longueur variable, ce qui complique et ralentit son analyse. En IPv6, l'en-tête a une longueur fixe (40 octets) mais il peut être suivi d'un nombre quelconque d'en-têtes d'extension (RFC 8200, section 4). Si on veut accéder à l'information de couche 4, par exemple pour trouver le port TCP, il faut suivre toute la chaîne d'en-têtes. Ce système était conçu pour être plus facile et plus rapide à analyser que celui d'IPv4, mais à l'usage, ce n'est pas le cas (le RFC estime même que le système d'IPv6 est pire). En partie pour cette raison, certains nœuds intermédiaires jettent tous les paquets IPv6 contenant des en-têtes d'extension (RFC 7872). D'autres croient que la couche Transport suit immédiatement l'en-tête, sans tenir compte de la possibilité qu'il y ait un en-tête d'extension, ce qui fausse leur analyse. L'en-tête d'extension Hop-by-hop options était particulièrement problématique, car devant être traité par tous les routeurs (le RFC 8200 a adouci cette règle).

Pour faciliter la tâche des pare-feux, plusieurs règles ont été ajoutées aux en-têtes d'extension depuis les débuts d'IPv6 : par exemple le premier fragment d'un datagramme doit contenir la totalité des en-têtes d'extension.

À l'interface d'IPv6 et de la couche 2, on trouve quelques problèmes supplémentaires. D'abord, concernant la résolution d'adresses IP en adresses MAC, pour laquelle IPv6 utilise le protocole NDP (Neighbor Discovery Protocol, RFC 4861). NDP partage avec ARP un problème fondamental : n'importe quelle machine du réseau local peut répondre ce qu'elle veut. Par exemple, si une machine demande « qui est 2001:db8:1::23:42:61 ? », toutes les machines locales peuvent techniquement répondre « c'est moi » et donner leur adresse MAC. Ce problème et quelques autres analogues sont documentés dans les RFC 3756 et RFC 6583. DHCP pose le même genre de problèmes, toute machine peut se prétendre serveur DHCP et répondre aux requêtes DHCP à la place du serveur légitime. Pour se prémunir contre les attaques faites par des machines envoyant de faux RA, on peut aussi isoler les machines, par exemple en donnant un /64 à chacune, ou bien en configurant commutateurs ou points d'accès Wifi pour bloquer les communications de machine terminale à machine terminale (celles qui qui ne sont pas destinées au routeur). Le RFC recommande le RA guard du RFC 6105.

Et sur les mobiles ? Un lien 3GPP est un lien point-à-point, l'ordiphone qui est à un bout ne peut donc pas parler aux autres ordiphones, même utilisant la même base. On ne peut parler qu'au routeur (GGSN - GPRS Gateway Support Node, ou bien PGW - Packet GateWay). Pour la même raison, il n'y a pas de résolution des adresses IP et donc pas de risque liés à cette résolution. Ce mécanisme empêche un grand nombre des attaques liées à NDP. Si vous voulez en apprendre plus à ce sujet, il faut lire le RFC 6459.

Le multicast peut être dangereux sur un réseau local, puisqu'il permet d'écrire à des machines qui n'ont rien demandé. Certains réseaux WiFi bloquent le multicast. En IPv6, cela empêche des actions néfastes comme de pinguer ff01::1 (l'adresse multicast qui désigne toutes les machines du réseau local), mais cela bloque aussi des protocoles légitimes comme mDNS (RFC 6762).

Compte-tenu de la vulnérabilité du réseau local, et des risques associés, il a souvent été proposé de sécuriser l'accès à celui-ci et IPv6 dispose d'un protocole pour cela, SEND, normalisé dans le RFC 3971, combiné avec les CGA du RFC 3972. Très difficile à configurer, SEND n'a connu aucun succès, à part dans quelques environnements ultra-sécurisés. On ne peut clairement pas compter dessus.

Voyons maintenant la sécurité du plan de contrôle : les routeurs et le routage (RFC 6192). Les problèmes de sécurité sont quasiment les mêmes en IPv4 et en IPv6, la principale différence étant le mécanisme d'authentification pour OSPF. Un routeur moderne typique sépare nettement le plan de contrôle (là où on fait tourner les protocoles comme OSPF, mais aussi les protocoles de gestion comme SSH qui sert à configurer le routeur) et le plan de transmission, là où se fait la transmission effective des paquets. Le second doit être très rapide, car il fonctionne en temps réel. Il utilise en général du matériel spécialisé, alors que le plan de contrôle est la plupart du temps mis en œuvre avec un processeur généraliste, et un système d'exploitation plus classique. Pas toujours très rapide, il peut être submergé par un envoi massif de paquets. Le plan de contrôle ne gère que les paquets, relativement peu nombreux, qui viennent du routeur ou bien qui y arrivent, le plan de transmission gérant les innombrables paquets que le routeur transmet, sans les garder pour lui. Chaque paquet entrant est reçu sur l'interface d'entrée, le routeur consulte une table qui lui dit quel est le routeur suivant pour ce préfixe IP, puis il envoie ce paquet sur l'interface de sortie. Et le tout très vite.

Notre RFC conseille donc de protéger le plan de contrôle en bloquant le plus tôt possible les paquets anormaux, comme des paquets OSPF qui ne viendraient pas d'une adresse locale au lien, ou les paquets BGP qui ne viennent pas d'un voisin connu. (Mais, bien sûr, il faut laisser passer l'ICMP, essentiel au déboguage et à bien d'autres fonctions.) Pour les protocoles de gestion, il est prudent de jeter les paquets qui ne viennent pas du réseau d'administration. (Tout ceci est commun à IPv4 et IPv6.)

Protéger le plan de contrôle, c'est bien, mais il faut aussi protéger le protocole de routage. Pour BGP, c'est pareil qu'en IPv4 (lisez le RFC 7454). Mais OSPF est une autre histoire. La norme OSPFv3 (RFC 4552) comptait à l'origine exclusivement sur IPsec, dont on espérait qu'il serait largement mis en œuvre et déployé. Cela n'a pas été le cas (le RFC 8504 a d'ailleurs supprimé cette obligation d'IPsec dans IPv6, obligation qui était purement théorique). Le RFC 7166 a pris acte de l'échec d'IPsec en créant un mécanisme d'authentification pour OSPFv3. Notre RFC recommande évidemment de l'utiliser.

Sinon, les pratiques classiques de sécurité du routage tiennent toujours. Ne pas accepter les routes « bogons » (conseil qui n'est plus valable en IPv4, où tout l'espace d'adressage a été alloué), celles pour des adresses réservées (RFC 8190), etc.

Pas de sécurité sans surveillance (c'est beau comme du Ciotti, ça) et journalisation. En IPv6 comme en IPv4, des techniques comme IPFIX (RFC 7011), SNMP (RFC 4293), etc sont indispensables. Comme en IPv4, on demande à son pare-feu, son serveur RADIUS (RFC 2866) et à d'autres équipements de journaliser les évènements intéressants. À juste titre, et même si ça va chagriner les partisans de la surveillance massive, le RFC rappelle que, bien que tout cela soit très utile pour la sécurité, c'est dangereux pour la vie privée, et que c'est souvent, et heureusement, encadré par des lois comme le RGPD. Administrateur réseaux, ne journalise pas tout, pense à tes responsabilités morales et légales !

Bon, mais cela, c'est commun à IPv4 et IPv6. Qu'est-ce qui est spécifique à IPv6 ? Il y a le format textuel canonique des adresses, normalisé dans le RFC 5952, qui permet de chercher une adresse sans ambiguité. Et la mémoire des correspondances adresses IP adresses MAC dans les routeurs ? Elle est très utile à enregistrer, elle existe aussi en IPv4, mais en IPv6 elle est plus dynamique, surtout si on utilise les adresses favorables à la vie privée du RFC 8981. Le RFC recommande de la récupérer sur le routeur au moins une fois toutes les 30 secondes. Et le journal du serveur DHCP ? Attention, en IPv6, du fait de l'existence de trois mécanismes d'allocation d'adresses (DHCP, SLAAC et statique) au lieu de deux en IPv4, le journal du serveur DHCP ne suffit pas. Et puis il ne contiendra pas l'adresse MAC mais un identificateur choisi par le client, qui peut ne rien vous dire. (Ceci dit, avec les machines qui changent leur adresse MAC, DHCPv4 a un problème du même genre.) En résumé, associer une adresse IP à une machine risque d'être plus difficile qu'en IPv4.

Une autre spécificité d'IPv6 est l'existence de nombreuses technologies de transition entre les deux protocoles, technologies qui apportent leurs propres problèmes de sécurité (RFC 4942). Normalement, elles n'auraient dû être que temporaires, le temps que tout le monde soit passé à IPv6 mais, comme vous le savez, la lenteur du déploiement fait qu'on va devoir les supporter longtemps, les réseaux purement IPv6 et qui ne communiquent qu'avec d'autres réseaux IPv6 étant une petite minorité. La technique de coexistence la plus fréquente est la double pile, où chaque machine a à la fois IPv4 et IPv6. C'est la plus simple et la plus propre, le trafic de chaque version du protocole IP étant natif (pas de tunnel). Avec la double pile, l'arrivée d'IPv6 n'affecte pas du tout IPv4. D'un autre côté, il faut donc gérer deux versions du protocole. (Anecdote personnelle : quand j'ai commencé dans le métier, IP était très loin de la domination mondiale, et il était normal, sur un réseau local, de devoir gérer cinq ou six protocoles très différents. Prétendre que ce serait une tâche insurmontable de gérer deux versions du même protocole, c'est considérer les administrateurs réseaux comme très paresseux ou très incompétents.) L'important est que les politiques soient cohérentes, afin d'éviter, par exemple, que le port 443 soit autorisé en IPv4 mais bloqué en IPv6, ou le contraire. (C'est parfois assez difficile à réaliser sans une stricte discipline : beaucoup de pare-feux n'ont pas de mécanisme simple pour indiquer une politique indépendante de la version du protocole IP.)

Notez que certains réseaux peuvent être « double-pile » sans que l'administrateur réseaux l'ait choisi, ou en soit conscient, si certaines machines ont IPv6 activé par défaut (ce qui est fréquent et justifié). Des attaques peuvent donc être menées via l'adresse locale au lien même si aucun routeur du réseau ne route IPv6.

Mais les plus gros problèmes de sécurité liés aux techniques de coexistence/transition viennent des tunnels. Le RFC 6169 détaille les conséquences des tunnels pour la sécurité. Sauf s'ils sont protégés par IPsec ou une technique équivalente, les tunnels permettent bien des choses qui facilitent le contournement des mesures de sécurité. Pendant longtemps, l'interconnexion entre réseaux IPv6 isolés se faisait via des tunnels, et cela a contribué aux légendes comme quoi IPv6 posait des problèmes de sécurité. Aujourd'hui, ces tunnels sont moins nécessaires (sauf si un réseau IPv6 n'est connecté que par des opérateurs archaïques qui n'ont qu'IPv4).

Les tunnels les plus dangereux (mais aussi les plus pratiques) sont les tunnels automatiques, montés sans configuration explicite. Le RFC suggère donc de les filtrer sur le pare-feu du réseau, en bloquant le protocole IP 41 (ISATAPRFC 5214, 6to4RFC 3056, mais aussi 6rdRFC 5969 - qui, lui, ne rentre pas vraiment dans la catégorie « automatique »), le protocole IP 47 (ce qui bloque GRE, qui n'est pas non plus un protocole « automatique ») et le port UDP 3544, pour neutraliser TeredoRFC 4380. D'ailleurs, le RFC rappelle plus loin que les tunnels statiques (RFC 2529), utilisant par exemple GRE (RFC 2784), sont plus sûrs (mais IPsec ou équivalent reste recommandé). 6to4 et Teredo sont de toute façon très déconseillés aujourd'hui (RFC 7526 et RFC 3964).

Et les mécanismes de traduction d'adresses ? On peut en effet traduire des adresses IPv4 en IPv4 (le traditionnel NAT, qui est plutôt du NAPT en pratique, puisqu'il traduit aussi le port), ce qui est parfois présenté à tort comme une fonction de sécurité, mais on peut aussi traduire de l'IPv4 en IPv6 ou bien de l'IPv6 en IPv6. Le partage d'adresses que permettent certains usages de la traduction (par exemple le CGNAT) ouvre des problèmes de sécurité bien connus. Les techniques de traduction d'IPv4 en IPv6 comme NAT64RFC 6146 ou 464XLATRFC 6877 apportent également quelques problèmes, décrits dans leurs RFC.

J'ai parlé plus haut du fait que les systèmes d'exploitation modernes ont IPv6 et l'activent par défaut. Cela implique de sécuriser les machines contre les accès non voulus faits avec IPv6. Du classique, rien de spécifique à IPv6 à part le fait que certains administrateurs système risqueraient de sécuriser les accès via IPv4 (avec un pare-feu intégré au système d'exploitation, par exemple) en oubliant de le faire également en IPv6.

Tous les conseils donnés jusqu'à présent dans cette section 2 du RFC étaient communs à tous les réseaux IPv6. Les sections suivantes s'attaquent à des types de réseau spécifiques à certaines catégories d'utilisateurs. D'abord (section 3), les « entreprises » (en fait, toutes les organisations - RFC 7381, pas uniquement les entreprises capitalistes privées, comme le terme étatsunien enterprise pourrait le faire penser). Le RFC contient quelques conseils de sécurité, proches de ce qui se fait en IPv4, du genre « bloquer les services qu'on n'utilise pas ». (Et il y a aussi le conseil plus évident : bloquer les paquets entrants qui ont une adresses IP source interne et les paquets sortants qui ont une adresse IP source externe.)

Et pour les divers opérateurs (section 4 du RFC) ? C'est plus délicat car ils ne peuvent pas, contrairement aux organisations, bloquer ce qu'ils ne veulent pas (sauf à violer la neutralité, ce qui est mal). Le RFC donne des conseils de sécurisation BGP (identiques à ceux d'IPv4) et RTBH (RFC 5635). Il contient également une section sur l'« interception légale » (le terme politiquement correct pour les écoutes et la surveillance). Légalement, les exigences (et les problèmes qu'elles posent) sont les mêmes en IPv4 et en IPv6. En IPv4, le partage d'adresses, pratique très répandue, complique sérieusement la tâche des opérateurs quand ils reçoivent un ordre d'identifier le titulaire de telle ou telle adresse IP (RFC 6269). En IPv6, en théorie, la situation est meilleure pour la surveillance, une adresse IP n'étant pas partagée. Par contre, l'utilisateur peut souvent faire varier son adresse au sein d'un préfixe /64.

Quand au réseau de l'utilisateur final, il fait l'objet de la section 5. Il n'y a pas actuellement de RFC définitif sur la délicate question de la sécurité de la maison de M. Michu. Notamment, les RFC 6092 et RFC 7084 ne prennent pas position sur la question très sensible de savoir si les routeurs/pare-feux d'entrée de ce réseau devraient bloquer par défaut les connexions entrantes. La sécurité plaiderait en ce sens mais ça casserait le principe de bout en bout.

Voilà, nous avons terminé cette revue du long RFC. Je résumerai mon opinion personnelle en disant : pour la plupart des questions de sécurité, les ressemblances entre IPv4 et IPv6 l'emportent sur les différences. La sécurité n'est donc pas une bonne raison de retarder la migration si nécessaire vers IPv6. J'ai développé cette idée dans divers exposés et articles.


Téléchargez le RFC 9099


L'article seul

RFC 9051: Internet Message Access Protocol (IMAP) - Version 4rev2

Date de publication du RFC : Août 2021
Auteur(s) du RFC : A. Melnikov (Isode), B. Leiba (Futurewei Technologies)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF extra
Première rédaction de cet article le 3 septembre 2021


IMAP, protocole d'accès distant à des boites aux lettres n'est pas juste un protocole, c'est tout un écosystème, décrit dans de nombreux RFC. Celui-ci est le socle de la version actuelle d'IMAP, la « 4rev2 ». Elle remplace la précédente version, « 4rev1 » (normalisée dans le RFC 3501). Le principal changement est sans doute une internationalisation plus poussée pour les noms de boites aux lettres et les en-têtes des messages.

Les protocoles traditionnels du courrier électronique, notamment SMTP ne permettaient que d'acheminer le courrier jusqu'à destination. Pour le lire, la solution la plus courante aujourd'hui est en mode client/serveur, avec IMAP, qui fait l'objet de notre RFC. IMAP ne permet pas d'envoyer du courrier, pour cela, il faut utiliser le RFC 6409. IMAP fonctionne sur un modèle où les messages ont plutôt vocation à rester sur le serveur, et où les clients peuvent, non seulement les récupérer mais aussi les classer, les détruire, les marquer comme lus, etc. IMAP permet de tout faire à distance.

Pour apprendre IMAP, il vaut mieux ne pas commencer par le RFC, qui est très riche. (La lecture du RFC 2683 est recommandée aux implémenteurs.) Pourtant, le principe de base est simple. IMAP est client/serveur. Le client se connecte en TCP au serveur, sur le port 143, et envoie des commandes sous forme de texte, comme avec SMTP. Il s'authentifie avec la commande LOGIN, choisit une boite aux lettres avec la commande SELECT, récupère un message avec la commande FETCH. IMAP peut aussi utiliser du TLS implicite, sur le port 993. Voici un exemple de session. Notons tout de suite, c'est un point très important du protocole IMAP, que chaque commande est précédée d'une étiquette (tag, voir les sections 2.2.1 et 5.5 du RFC) arbitraire qui change à chaque commande et qui permet d'associer une réponse à une commande, IMAP permettant d'envoyer plusieurs commandes sans attendre de réponse. Les réponses portent l'étiquette correspondante, ou bien un astérisque s'il s'agit d'un message du serveur non sollicité. Ici, le serveur utilise le logiciel Archiveopteryx :

% telnet imap.example.org imap     
Trying 192.0.2.23...
Connected to imap.example.org.
Escape character is '^]'.
* OK [CAPABILITY IMAP4rev1 AUTH=CRAM-MD5 AUTH=DIGEST-MD5 AUTH=PLAIN COMPRESS=DEFLATE ID LITERAL+ STARTTLS] imap.example.org Archiveopteryx IMAP Server
com1 LOGIN stephane vraimentsecret
com1 OK [CAPABILITY IMAP4rev1 ACL ANNOTATE BINARY CATENATE CHILDREN COMPRESS=DEFLATE CONDSTORE ESEARCH ID IDLE LITERAL+ NAMESPACE RIGHTS=ekntx STARTTLS UIDPLUS UNSELECT URLAUTH] done
com2 SELECT INBOX
* 189 EXISTS
* 12 RECENT
* OK [UIDNEXT 1594] next uid
* OK [UIDVALIDITY 1] uid validity
* FLAGS (\Deleted \Answered \Flagged \Draft \Seen)
* OK [PERMANENTFLAGS (\Deleted \Answered \Flagged \Draft \Seen \*)] permanent flags
com2 OK [READ-WRITE] done

Le serveur préfixe ses réponses par OK si tout va bien, NO s'il ne pas réussi à faire ce qu'on lui demande et BAD si la demande était erronnée (commande inconnue, par exemple). Ici, avec l'étiquette A2 et un Dovecot :

A2 CAVAPAS
A2 BAD Error in IMAP command CAVAPAS: Unknown command (0.001 + 0.000 secs).
  

Si le serveur n'est accessible qu'en TLS implicite (TLS démarrant automatiquement au début, sans STARTTLS), on peut utiliser un client TLS en ligne de commande, comme celui de GnuTLS :

% gnutls-cli -p 993 imap.maison.example
- Certificate[0] info:
- subject `CN=imap.maison.example', issuer `CN=CAcert Class 3 Root,OU=http://www.CAcert.org,O=CAcert Inc.', serial 0x02e9bf, RSA key 2048 bits, signed using RSA-SHA512, activated `2020-12-14 14:47:42 UTC', expires `2022-12-14 14:47:42 UTC', pin-sha256="X21ApSVQ/Qcb5Q8kgL/YqlH2XuEco/Rs2X2EgkvDEdI="
 ...
- Status: The certificate is trusted. 
- Description: (TLS1.3)-(ECDHE-SECP256R1)-(RSA-PSS-RSAE-SHA256)-(AES-256-GCM)

[À partir d'ici, on fait de l'IMAP]

* OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE LITERAL+ AUTH=PLAIN] Dovecot (Debian) ready.
A1 LOGIN stephane vraimenttropsecret
A1 OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE SNIPPET=FUZZY PREVIEW=FUZZY STATUS=SIZE SAVEDATE LITERAL+ NOTIFY SPECIAL-USE] Logged in
A2 SELECT INBOX
...
* 0 EXISTS
* 0 RECENT
A2 OK [READ-WRITE] Select completed (0.002 + 0.000 + 0.001 secs).
...
A14 FETCH 1 (BODY.PEEK[HEADER.FIELDS (SUBJECT)])
* 1 FETCH (BODY[HEADER.FIELDS (SUBJECT)] {17}
Subject: Test

)
A14 OK Fetch completed (0.007 + 0.000 + 0.006 secs).
  

Les commandes IMAP, comme FETCH dans l'exemple ci-dessus, sont décrites dans la section 6 du RFC. Pour tester son serveur IMAP, on peut aussi utiliser fetchmail et lui demander d'afficher toute la session avec -v -v :


 % fetchmail -v -v -u MYLOGIN imap.1and1.fr 
Enter password for MYLOGIN@imap.1and1.fr: 
fetchmail: 6.3.6 querying imap.1and1.fr (protocol auto) at Tue Apr 15 12:00:27 2008: poll started
fetchmail: 6.3.6 querying imap.1and1.fr (protocol IMAP) at Tue Apr 15 12:00:27 2008: poll started
Trying to connect to 212.227.15.141/143...connected.
fetchmail: IMAP< * OK IMAP server ready H mimap3 65564
fetchmail: IMAP> A0001 CAPABILITY
fetchmail: IMAP< * CAPABILITY IMAP4rev1 LITERAL+ ID STARTTLS CHILDREN QUOTA IDLE NAMESPACE UIDPLUS UNSELECT SORT AUTH=LOGIN AUTH=PLAIN
fetchmail: IMAP< A0001 OK CAPABILITY finished.
fetchmail: Protocol identified as IMAP4 rev 1
fetchmail: IMAP> A0002 STARTTLS
fetchmail: IMAP< A0002 OK Begin TLS negotiation.
fetchmail: Issuer Organization: Thawte Consulting cc
fetchmail: Issuer CommonName: Thawte Premium Server CA
fetchmail: Server CommonName: imap.1and1.fr
fetchmail: imap.1and1.fr key fingerprint: 93:13:99:6A:3F:23:73:C3:00:37:4A:39:EE:22:93:AB
fetchmail: IMAP> A0003 CAPABILITY
fetchmail: IMAP< * CAPABILITY IMAP4rev1 LITERAL+ ID CHILDREN QUOTA IDLE NAMESPACE UIDPLUS UNSELECT SORT AUTH=LOGIN AUTH=PLAIN
fetchmail: IMAP< A0003 OK CAPABILITY finished.
fetchmail: Protocol identified as IMAP4 rev 1
fetchmail: imap.1and1.fr: upgrade to TLS succeeded.
fetchmail: IMAP> A0004 LOGIN "m39041005-1" *
fetchmail: IMAP< A0004 OK LOGIN finished.
fetchmail: selecting or re-polling default folder
fetchmail: IMAP> A0005 SELECT "INBOX"

En IMAP, un message peut être identifié par un UID (Unique Identifier) ou par un numéro. Le numéro n'est pas global, il n'a de sens que pour une boite donnée, et il peut changer, par exemple si on détruit des messages. L'UID, lui, est stable, au moins pour une session (et de préférence pour toutes). Les messages ont également des attributs (flags). Ceux qui commencent par une barre oblique inverse comme \Seen (indique que le message a été lu), \Answered (on y a répondu), etc, sont obligatoires, et il existe également des attributs optionnels commençant par un dollar comme $Junk (spam). Les fonctions de recherche d'IMAP pourront utiliser ces attributs comme critères de recherche. Les attributs optionnels (keywords) sont listés dans un registre IANA, et on peut en ajouter (le RFC 5788 explique comment).

IMAP a des fonctions plus riches, notamment la possibilité de chercher dans les messages (section 6.4.4 du RFC), ici, on extrait les messages de mai 2007, puis on récupère le sujet du premier message, par son numéro :

com10 SEARCH since 1-May-2007 before 31-May-2007
* SEARCH 12
com10 OK done
com11 FETCH 1 (BODY.PEEK[HEADER.FIELDS (SUBJECT)])
* 1 FETCH (BODY[HEADER.FIELDS (Subject)] {17}
Subject: Rapport sur les fonctions de vue dans Archiveopteryx

)
com11 OK done
  

IMAP 4rev2 est complètement internationalisé et, par exemple, peut gérer des en-têtes en UTF-8, comme décrits dans le RFC 6532, ce qui est une des améliorations par rapport à 4rev1.

Vous noterez dans les réponses CAPABILITY montrées plus haut, que le serveur indique la ou les versions d'IMAP qu'il sait gérer. Il peut donc annoncer 4rev1 et 4rev2, s'il est prêt à gérer les deux. Le client devra utiliser la commande ENABLE pour choisir. S'il choisit 4rev2, le serveur pourra utiliser les nouveautés de 4rev2, notamment dans le domaine de l'internationalisation (noms de boites en UTF-8, alors que 4rev1 savait tout juste utiliser un bricolage basé sur UTF-7).

IMAP 4rev2 est compatible avec 4rev1 (un logiciel de la précédente norme peut interagir avec un logiciel de la nouvelle). Il peut même interagir avec l'IMAP 2 du RFC 1776 (IMAP 3 n'a jamais été publié), cf. RFC 2061.

L'annexe E résume les principaux changements depuis le RFC 3501, qui normalisait IMAP 4rev1 :

  • Messages plus grands (taille stockée sur 63 bits et plus seulement 32). Un serveur qui accepte les messages de plus de quatre gigoctets devra donc les masquer aux clients 4rev1 (ou bien trouver une autre stratégie).
  • UTF-8 pour les noms de boites et les sujets des messages.
  • Incorporation de nombreuses extensions précédemment séparées, trop nombreuses pour que je les cite toutes. Il y a par exemple le BINARY du RFC 3516 ou le LIST-EXTENDED du RFC 5258.
  • Beaucoup de clarifications du texte.
  • Abandon de certaines choses, aussi, comme le code de réponse UNSEEN de la commande SELECT.
  • Application des progrès de la cryptanalyse, donc remplacement de MD5 par SHA-256.
  • Suppression de la convention du préfixe « X- », en application du RFC 6648.

La réalisation d'un client ou d'un serveur IMAP soulève plein de problèmes pratiques, que la section 5 de notre RFC traite. Par exemple, les noms des boites aux lettres peuvent être en Unicode, plus précisément le sous-ensemble d'Unicode du RFC 5198 (cela n'était pas possible en 4rev1). Un logiciel doit donc s'attendre à rencontrer de tels noms.

IMAP est mis en œuvre dans de nombreux serveurs comme Dovecot, Courier, ou Archiveopteryx, déjà cité (mais qui semble abandonné). Mais, comme vous l'avez vu dans les exemples de session IMAP cités plus haut, la version de notre RFC, « 4rev2 » n'a pas encore forcément atteint tous les logiciels.

Côté client, on trouve du IMAP dans beaucoup de logiciels, des webmails, des MUA classiques comme mutt, des MUA en ligne de commande comme fetchmail, très pratique pour récupérer son courrier. (Si vous écrivez un logiciel IMAP à partir de zéro, ce RFC recommande la lecture préalable du RFC 2683.)

Il existe également des bibliothèques toutes faites pour programmer son client IMAP à son goût comme imaplib pour Python. Voici un exemple d'un court programme Python qui se connecte à un serveur IMAP, sélectionne tous les messages et les récupère. On note que la bibliothèque a choisi de rester très proche du vocabulaire du RFC :

import imaplib

# Unlike what the documentation says, "host" has no proper default.
connection = imaplib.IMAP4_SSL(host='localhost')                                                                                            
connection.login("stephane", "thisissecret")
connection.select() # Select the default mailbox
typee, data = connection.search(None, "ALL")
for num in data[0].split():
    # Fetches the whole message
    # "RFC822" est le terme traditionnel mais le format des messages
    # est désormais dans le RFC 5322.
    typ, data = connection.fetch(num, '(RFC822)')
    print('Message %s\n%s\n' % (num, data[0][1]))
connection.close()
connection.logout()

Téléchargez le RFC 9051


L'article seul

Le registre Afrinic attaqué

Première rédaction de cet article le 31 août 2021


Le registre d'adresses IP Afrinic est actuellement l'objet d'une attaque juridique dans un conflit qui l'oppose à un revendeur d'adresses IP. L'affaire est complexe et vous ne trouverez pas ici d'opinions fermes sur « qui a raison » mais je voudrais expliquer de quoi il retourne et surtout signaler un problème grave : la justice a gelé les comptes bancaires d'Afrinic, menaçant à terme l'Internet africain. Il ne s'agit donc pas d'une affaire purement privée entre deux organisations en conflit.

D'abord, qu'est-ce qu'un RIR, un registre d'adresses IP ? C'est l'organisme qui attribue les adresses IP, afin d'en garantir l'unicité. Les informations sur ces allocations sont ensuite publiquement accessibles via whois ou RDAP. Il y a cinq RIR dans le monde, Afrinic couvrant le continent africain. Contrairement aux noms de domaine, dont la gestion suscite toujours passions et controverses (l'une des facettes de la « gouvernance de l'Internet »), celle des adresses IP soulève nettement moins d'intérêt. C'est en partie dû au fait qu'on se moque d'avoir telle ou telle adresse IP (à quelques exceptions près comme certains résolveurs DNS publics avec leurs adresses facilement mémorisables comme 1.1.1.1). Et puis les adresses IP, c'est purement virtuel, le registre peut en « fabriquer » autant qu'il veut, non ? Il ne devrait pas y avoir de problème de pénurie, n'est-ce pas ?

Mais cela n'est vrai que pour l'actuelle version du protocole IP, la version 6. Avec l'ancienne version, IPv4, toujours utilisée à certains endroits, les adresses ne sont codées que sur 32 bits, ce qui ne permet qu'environ quatre milliards d'adresses (un peu moins en pratique, certaines adresses étant réservées pour des usages spécifiques). Si ce chiffre semble important, il est très insuffisant par rapport aux besoins de l'Internet mondial. Il y a donc bel et bien pénurie d'adresses IPv4 et, comme le disait ma grand-mère, « quand le foin manque dans l'écurie, les chevaux se battent ». Les tensions sur le stock d'adresses IPv4 imposent donc que les RIR aient une politique d'allocation de ces adresses, les réservant à ceux qui en ont besoin. On se doute bien que l'élaboration de telles politiques ne se fasse pas sans douleur, et les cinq RIR ont d'ailleurs des politiques différentes. En outre, et pour son malheur, Afrinic a eu pendant longtemps un stock d'adresses IPv4 important, ce qui a aggravé les tentations. (Le pillage des ressources de l'Afrique n'est pas une invention nouvelle.)

Et c'est la source du conflit actuel entre Afrinic et la société Cloud Innovation (chinoise, mais enregistrée dans un paradis fiscal africain). Cette société obtient des adresses IPv4 par différents moyens, et les loue ensuite à ses clients, notamment en Chine. Ce n'est pas forcément illégal, l'achat, la vente et la location d'adresses IP peuvent être acceptées par le système légal, et par les politiques des RIR (les détails sont complexes, je vous les épargne). On peut trouver ce business répugnant mais il existe et n'est pas interdit. Ceci dit, les organisations qui obtiennent des adresses IP sont censées respecter les règles d'allocation du RIR auquel elles se sont adressées. Ici, Afrinic reproche à Cloud Innovation d'avoir obtenu de nombreuses adresses IP en violation des règles, et menace cette société de reprendre les adresses, argumentant notamment sur le fait qu'elles ne sont pas utilisées en Afrique. Comme la question est complexe (j'ai déjà du mal à retenir les règles du RIR de ma région), je ne vais pas trancher en désignant un bon et un méchant.

Le vrai problème se situe ensuite : Cloud Innovation a obtenu de la justice qu'elle interdise à Afrinic de reprendre les adresses en question mais surtout à obtenu le gel des comptes bancaires d'Afrinic, ce qui menace le fonctionnement même du registre et, à terme, de l'Internet en Afrique.

Mais quelle justice au fait ? Afrinic est enregistré à Maurice et c'est donc la justice de ce pays qui est compétente. Je ne formulerai pas d'opinion sur la qualité de la justice mauricienne, je ne la connais pas, mais je trouve quand même que le blocage des comptes, empêchant l'une des parties au procès de fonctionner et même de payer ses juristes, est anormale, notamment compte-tenu de ses conséquences pour l'Internet. D'ailleurs, pourquoi Maurice ? C'est parce que, bien que chaque RIR serve un continent entier, l'organisation doit bien être enregistrée quelque part. Elle ne peut pas planer au-dessus des lois nationales. Pour avoir un statut international, il faudrait un traité intergouvernemental (comme pour l'Union africaine) et, outre la difficulté à négocier un tel traité, cela aurait d'autres conséquences de gouvernance, notamment sur le rôle des gouvernements. Il fallait donc un pays particulier et Maurice semblait un choix raisonnable. (Les Européens noteront que c'est pour la même raison que leur RIR est à Amsterdam et que l'Internet européen dépend donc de la justice néerlandaise.)

À court terme, l'Internet continue à fonctionner en Afrique : les RIR ne sont pas impliqués dans l'activité quotidienne, les paquets ne passent pas par eux, les opérateurs Internet font fonctionner les réseaux que le RIR fonctionne ou pas. Mais à moyen terme, le « gel » d'Afrinic pourrait paralyser beaucoup d'activités indispensables, notamment la tenue du registre des adresses IP. D'où l'urgence d'une solution.

Des personnes plus pressées ont suggéré d'attaquer l'attaquant et, par exemple, de ne plus router les préfixes IP de Cloud Innovation. La question est évidemment très délicate, car si je comprends l'exaspération de certains, des actions unilatérales de ce genre ne sont pas non plus un procédé satisfaisant pour résoudre les conflits. Il vaudrait mieux que la justice mauricienne débloque les comptes d'Afrinic, en attendant un jugement au fond.

(Un autre point dont j'aurais préféré ne pas parler ; le problème expliqué dans cet article a une origine extérieure à Afrinic. Il n'est pas lié à un autre problème, qui avait été abondemment discuté en 2019-2020, d'un employé d'Afrinic vendant discrètement des adresses IP, problème qui fait également l'objet d'actions en justice. Voir entre autres ma conférence à Coriin 2020.)

Et revenons à IPv6. Son déploiement est actuellement insuffisant, en raison de la lenteur anormale mise par beaucoup d'acteurs à effectuer la migration. Il y a des raisons à cela mais il faut noter que ces décisions de trainer la patte, en fonction des intérêts de ces acteurs, ont des conséquences globales, celles d'accentuer la pression sur les rares adresses IPv4, menant à ce genre de crises.

Quelles lectures pour finir :


L'article seul

RFC 9079: Source-Specific Routing in Babel

Date de publication du RFC : Août 2021
Auteur(s) du RFC : M. Boutier, J. Chroboczek (IRIF, University of Paris)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF babel
Première rédaction de cet article le 29 août 2021


Traditionnellement, le routage dans l'Internet se fait sur la base de l'adresse IP de destination. Mais on peut aussi envisager un routage où l'adresse IP source est prise en compte. Ce nouveau RFC étend le protocole de routage Babel en lui ajoutant cette possibilité.

Babel, normalisé dans le RFC 8966 est un protocole de routage à vecteur de distance. Il est prévu par défaut pour du routage IP traditionnel, où le protocole de routage construit une table de transmission qui associe aux préfixes IP de destination le routeur suivant (next hop). Un paquet arrive dans un routeur ? Le routeur regarde dans sa table le préfixe le plus spécifique qui correspond à l'adresse IP de destination (utilisant pour cela une structure de données comme, par exemple, le Patricia trie) et, lorsqu'il le trouve, la table contient les coordonnées du routeur suivant. Par exemple, si une entrée de la table dit que 2001:db8:1:fada::/64 a pour routeur suivant fe80::f816:3eff:fef2:47db%eth0, un paquet destiné à 2001:db8:1:fada::bad:1234 sera transmis à ce fe80::f816:3eff:fef2:47db, sur l'interface réseau eth0. Cette transmission classique a de nombreux avantages : elle est simple et rapide, et marche dans la plupart des cas.

Mais ce mécanisme a des limites. On peut vouloir prendre en compte d'autres critères que l'adresse de destination pour la transmission d'un paquet. Un exemple où un tel critère serait utile est le multihoming. Soit un réseau IP qui est connecté à plusieurs opérateurs, afin d'assurer son indépendance et pour faire face à un éventuel problème (technique ou commercial) chez l'un des opérateurs. La méthode officielle pour cela est d'acquérir des adresses indépendantes du fournisseur et de faire router ces adresses par les opérateurs auxquels on est connectés (par exemple en leur parlant en BGP). Mais avoir de ces adresses PI (Provider-Independent) est souvent difficile. Quand on est passionnée, on y arrive mais ce n'est pas vraiment accessible à tout le monde. On se retrouve donc en général avec des adresses dépendant du fournisseur. C'est par exemple le cas de loin le plus courant pour le particulier, la petite association ou la PME. Dans ce cas, le multihoming est compliqué. Mettons que les deux fournisseurs d'accès se nomment A et B et que chacun nous fournisse un préfixe d'adresses IP. Si une machine interne a deux adresses IP, chacune tirée d'un des préfixes, et qu'elle envoie vers l'extérieur un paquet ayant comme adresse source une adresse de B, que se passe-t-il ? Si le paquet est envoyé via le fournisseur B, tout va bien. Mais s'il est envoyé via le fournisseur A, il sera probablement jeté par le premier routeur de A, puisque son adresse IP source ne sera pas une adresse du fournisseur (RFC 3704 et RFC 8704). Pour éviter cela, il faudrait pouvoir router selon l'adresse IP source, envoyant les paquets d'adresse source A vers le fournisseur A et ceux ayant une adresse source B vers B. En gros, soit l'information de routage influe sur le choix de l'adresse source, soit c'est le choix de l'adresse source qui influe sur le routage. On ne peut pas faire les deux, ou alors on risque une boucle de rétroaction. Ce RFC choisit la deuxième solution.

La première solution serait que la machine émettrice choisisse l'adresse IP source selon que les adresses de destination soient routées vers A ou vers B. Le RFC 3484 explique comment le faire en séquentiel et le RFC 8305 le fait en parallèle (algorithme dit des « globes oculaires heureux »). Mais les systèmes actuels ne savent typiquement pas le faire et, de toute façon, cela ne réglerait pas le cas où le routage change pendant la vie d'une connexion TCP. TCP, contrairement à QUIC ou SCTP, ne supporte pas qu'une adresse IP change en cours de route, sauf à utiliser les extensions du RFC 8684. Une dernière solution serait de laisser les applications gérer cela (cf. RFC 8445) mais on ne peut pas compter que toutes les applications le fassent. Bref, le routage tenant compte de la source reste souvent la meilleure solution.

À part le cas du multihoming, d'autres usages peuvent tirer profit d'un routage selon la source. Ce routage peut simplifier la configuration des tunnels. Il peut aussi être utile dans le cas de l'anycast. Lorsqu'on utilise du routage classique, fondé uniquement sur la destination, il est difficile de prédire quels clients du groupe anycast seront servis par quelle instance du groupe. Cela rend la répartition de charge compliquée (il faut jouer avec les paramètres des annonces BGP, par exemple) et cela pose des problèmes aux protocoles avec état, comme TCP, où un même client doit rester sur la même instance du groupe anycast. (Des utilisations de l'anycast pour des services sans état, comme le DNS sur UDP, n'ont pas ce problème.) Au contraire, avec du routage fait selon la source, chaque instance anycast peut annoncer sa route avec le ou les préfixes IP qu'on veut que cette instance serve.

D'ailleurs, si vous voulez en savoir plus sur le routage selon la source (ou SADR Source-Address Dependent Routing, également appelé SSR pour Source-Specific Routing), vous pouvez lire l'article détaillé des auteurs du RFC, « Source-Specific Routing ». On peut aussi noter que ce routage dépendant de la source n'est pas la même chose qu'un routage décidé par la source (source routing), qui indiquerait une liste de routeurs par où passer. Ici, chaque routeur reste maitre du saut suivant (sur le routage décidé par la source, voir RFC 8354, et un exemple dans le RFC 6554).

Bon, le routage tenant compte de la source est intéressant, OK. Mais, avant de s'y lancer, il faut faire attention à un petit problème, la spécificité des routes. Lorsqu'on route uniquement selon la destination, et que plusieurs routes sont possibles, la règle classique d'IP est celle de la spécificité. La route avec le préfixe le plus spécifique (le plus long) gagne. Mais que se passe t-il si on ajoute l'adresse source comme critère ? Imaginons qu'on ait deux routes, une pour la destination 2001:db8:0:1::/64 et s'appliquant à toutes les sources et une autre route pour toutes les destinations (route par défaut), ne s'appliquant qu'à la source 2001:db8:0:2::/64. On va noter ces deux routes sous forme d'un tuple (destination, source) donc, ici, (2001:db8:0:1::/64, ::/0) et (::/0, 2001:db8:0:2::/64). Pour un paquet venant de 2001:db8:0:2::1 et allant en 2001:db8:0:1::1, quelle est la route la plus spécifique ? Si on considère la spécificité de la destination d'abord, la route choisie sera la (2001:db8:0:1::/64, ::/0). Mais si on regarde la spécificité de la source en premier, ce sera l'autre route, la (::/0, 2001:db8:0:2::/64) qui sera adoptée. Doit-on laisser chaque machine libre de faire du destination d'abord ou du source d'abord ? Non, car tous les routeurs du domaine doivent suivre la même règle, autrement des boucles pourraient se former, un paquet faisant du ping-pong éternel entre un routeur « destination d'abord » et un routeur « source d'abord ». Babel impose donc une règle : pour déterminer la spécificité d'une route, on regarde la destination d'abord. Le choix n'est pas arbitraire, il correspond à des topologies réseau typique, avec des réseaux locaux pour lesquelles on a une route spécifique, et une route par défaut pour tout le reste.

Un autre point important est celui du système de transmission des paquets. Il faut en effet rappeler que le terme « routage » est souvent utilisé pour désigner deux choses très différentes. La première est le routage à proprement parler (routing en anglais), c'est-à-dire la construction des tables de transmission, soit statiquement, soit avec des protocoles de routage comme Babel. La seconde est la transmission effective des paquets qui passent par le routeur (forwarding en anglais). Si on prend un routeur qui tourne sur Unix avec le logiciel babeld, ce dernier assure bien le routage au sens strict (construire les tables de routage grâce aux messages échangés avec les autres routeurs) mais c'est le noyau Unix qui s'occupe de la transmission. Donc, si on veut ajouter des fonctions de routage tenant compte de la source, il ne suffit pas de le faire dans le programme qui fait du Babel, il faut aussi s'assurer que le système de transmission en est capable, et avec la bonne sémantique (notamment l'utilisation de la destination d'abord pour trouver la route la plus spécifique). Si Babel, avec les extensions de ce RFC, tourne sur un système qui ne permet pas cela, il faut se résigner à ignorer les annonces spécifiques à une source. (Pour des systèmes comme Linux, qui permet le routage selon la source mais avec une mauvaise sémantique, puisqu'il utilise la source d'abord pour trouver la route la plus spécifique, la section V-B de l'article des auteurs cité plus haut fournit un algorithme permettant de créer des tables de transmission correctes.)

Le passage du routage classique au routage tenant compte de la source nécessite de modifier les structures de données du protocole de routage, ici Babel (section 3 du RFC). Les différentes structures de données utilisées par une mise en œuvre de Babel doivent être modifiées pour ajouter le préfixe de la source, et plusieurs des TLV dans les messages que s'échangent les routeurs Babel doivent être étendus avec un sous-TLV (RFC 8966, section 4.4) qui contient un préfixe source. La section 5 du RFC détaille les modifications nécessaires du protocole Babel. Les trois types de TLV qui indiquent un préfixe de destination, Updates, Route Requests et Seqno, doivent désormais transporter en plus un sous-TLV indiquant le préfixe source, marqué comme obligatoire (RFC 8966, section 4.4), de façon à ce qu'une version de Babel ne connaissant pas le routage selon la source n'accepte pas des annonces incomplètes. Si une annonce ne dépend pas de l'adresse IP source, il ne faut pas envoyer un sous-TLV avec le préfixe ::/0 mais au contraire ne pas mettre de sous-TLV (les autres versions de Babel accepteront alors l'annonce).

Ainsi, des versions de Babel gérant les extensions de notre RFC 9079 et d'autres qui ne les gèrent pas (fidèles au RFC 8966) pourront coexister sur le même réseau, sans que des boucles de routage ne se forment. En revanche, comme la notion de sous-TLV obligatoire n'est apparue qu'avec le RFC 8966, les vieilles versions de Babel, qui suivent l'ancien RFC 6126, ne doivent pas être sur le même réseau que les routeurs à routage dépendant de la source.

Le nouveau sous-TLV Source Prefix a le type 128 et sa valeur comporte un préfixe d'adresses IP, encodé en {longueur, préfixe}.

Notez que si les routeurs qui font du routage selon la source n'annoncent que des routes ayant le sous-TLV indiquant un préfixe source, les routeurs qui ne gèrent pas ce routage selon la source, et qui ignorent donc cette annonce, souffriront de famine : il n'y aura pas de routes vers certaines destinations, conduisant le routeur à jeter les paquets. Il peut donc être prudent, par exemple, d'avoir une route par défaut sans condition liée à la source, pour ces routeurs qui ignorent cette extension.

Question sécurité, il faut signaler (section 9 du RFC), que cette extension au routage apporte davantage de souplesse, et que cela peut nécessiter une révision des règles de sécurité, si celles-ci supposaient que tous les paquets vers une destination donnée suivaient le même chemin. Ainsi, le filtrage des routes (RFC 8966, annexe C) pourra être inutile si des routes spécifiques à une source sont présentes. Autre supposition qui peut être désormais fausse : une route spécifique à une machine de destination (host route, c'est-à-dire un préfixe /128) n'est plus forcément obligatoire, une autre route pour certaines sources peut prendre le dessus.

Au moins deux mises en œuvre de cette extension existent, dans babeld depuis la version 1.6 (en IPv6 seulement), et dans BIRD depuis la 2.0.2.

Merci à Juliusz Chroboczek pour sa relecture, et pour ses bonnes remarques sur le choix entre le routage selon la source et les autres solutions.


Téléchargez le RFC 9079


L'article seul

RFC 9043: FFV1 Video Coding Format Version 0, 1, and 3

Date de publication du RFC : Août 2021
Auteur(s) du RFC : M. Niedermayer, D. Rice, J. Martinez
Pour information
Réalisé dans le cadre du groupe de travail IETF cellar
Première rédaction de cet article le 24 août 2021


Ce RFC décrit FFV1, un encodage de flux vidéo sans pertes, et sans piège connu, par exemple de brevet.

Certains encodages vidéo font perdre de l'information, c'est-à-dire que, après décompression, on ne retrouve pas tout le flux original. Ces encodages avec pertes tirent profit des limites de l'œil humain (on n'encode pas ce qui ne se voit pas) mais peut poser des problèmes dans certains cas. Par exemple, si on veut stocker une vidéo sur le long terme, il est certainement préférable qu'elle soit aussi « authentique » que possible, et donc encodée sans pertes. Les organisations qui font de l'archivage sur le long terme (comme l'INA) ont tout intérêt à privilégier un format sans pertes et libre, qui sera encore utilisable dans 50 ans, plutôt que de choisir les derniers gadgets à la mode. Si on souhaite faire analyser cette vidéo par autre chose qu'un œil humain, par exemple un programme qui souhaite avoir la totalité des informations, là encore, le « sans perte » est nécessaire. FFV1 est sans perte, pour le plus grand bénéfice de l'archivage et de la science. C'est le premier codec sans perte documenté par l'IETF.

FFV1 ne date pas d'aujourd'hui, et le RFC traite d'un coup trois versions de FFV1 (section 4.2.1) :

Le nom FFV1 veut dire « FF Video 1 » et FF est une référence à FFmpeg, le programme de référence (qui a largement précédé la spécification officielle) dont le nom venait de Fast Forward (avance rapide).

Je ne vais pas vous décrire les algorithmes de FFV1, ça dépasse largement mes compétences. Comme le note le RFC, il faut d'abord connaitre le codage par intervalle, et le modèle YCbCr. Je vous renvoie donc à l'article en français d'un des auteurs et bien sûr au RFC lui-même. FFV1 utilise souvent des techniques un peu anciennes, pour éviter les problèmes de brevet.

Le RFC utilise du pseudo-code pour décrire l'encodage FFV1. Ce pseudo-code particulier est assez proche de C. Vous verrez donc du pseudo-code du genre :

    
for (i = 0; i < quant_table_set_count; i++) {      
  states_coded                                     
  if (states_coded) {                              
      for (j = 0; j < context_count[ i ]; j++) {   
          for (k = 0; k < CONTEXT_SIZE; k++) {     
              initial_state_delta[ i ][ j ][ k ]   
          }                                        
      }                                            
  }
}

  

Le type de média video/FFV1 a été enregistré à l'IANA pour les flux encodés en FFV1.

FFV1 décrit un encodage d'un flux vidéo, pas un format de conteneur. Le flux en question doit donc être inclus dans un conteneur, par exemple aux formats AVI, NUT ou Matroska (section 4.3.3 pour les détails de l'inclusion dans chaque format).

Comme pour tout codec utilisé sur le grand méchant Internet, un programme qui lit du FFV1 doit être paranoïaque et ne doit pas supposer que le flux vidéo est forcément correct. Même si le contenu du fichier est délibérement malveillant, le décodeur ne doit pas allouer de la mémoire à l'infini ou boucler sans fin (ou, pire encore, exécuter du code arbitraire par exemple parce qu'il y aura eu un débordement de pile ; FFV1 lui-même ne contient pas de code exécutable). Le RFC (section 6) donne l'exemple d'un calcul de taille d'une image où on multiplie la largeur par la hauteur, sans plus de précautions. Si cela provoque un dépassement d'entier, des tas de choses vilaines peuvent arriver. Un exemple de précaution : FFmpeg a été soumis à des flux FFV1 corrects et à des données aléatoires, tout en étant examiné par Valgrind et le vérificateur de Clang et aucun accès mémoire anormal n'a été détecté.

Question mises en œuvre, FFV1 est suffisamment ancien pour que de nombreux programmes sachent le décoder. L'implémentation de référence est FFmpeg (qui sait aussi encoder en FFV1). Il y a également un décodeur en Go, développé en même temps que la spécification et il y a aussi MediaConch dont le développement a permis de détecter des incohérences entre le projet de spécification et certains programmes. La spécification elle-même a été développée sur GitHub si vous voulez suivre son histoire, et son futur (une version 4 est prévue).

Comme exemple d'une vidéo encodée en FFV1, j'ai pris les 20 premières secondes de mon exposé au FOSDEM 2021. Le fichier (pour 20 secondes de vidéo !) fait 60 mégaoctets : la compression sans perte est évidemment moins efficace que si on accepte les pertes. Le fichier a été produit par FFmpeg (ffmpeg -i retro_gemini.webm -vcodec ffv1 -level 3 -to 00:00:20 retro_gemini.mkv, notez que, si FFV1 lui-même est sans perte, si vous encodez en FFV1 à partir d'un fichier déjà comprimé avec perte, vous ne recupérez évidemment pas ce qui a été perdu). mediainfo vous montre son contenu :

% mediainfo retro_gemini.mkv 
General
...
Format                                   : Matroska
Movie name                               : Gemini, a modern protocol that looks retro
...
DATE                                     : 2021-02-07
EVENT                                    : FOSDEM 2021
SPEAKERS                                 : Stéphane Bortzmeyer

Video
ID                                       : 1
Format                                   : FFV1
Format version                           : Version 3.4
Codec ID                                 : V_MS/VFW/FOURCC / FFV1
Duration                                 : 20 s 0 ms
Bit rate mode                            : Variable
Bit rate                                 : 25.7 Mb/s
Width                                    : 1 280 pixels
Height                                   : 720 pixels
Frame rate mode                          : Constant
Frame rate                               : 25.000 FPS
Color space                              : YUV
Compression mode                         : Lossless
...
  

Ou bien avec ffprobe :

% fprobe -show_format -show_streams retro_gemini.mkv
...
  Input #0, matroska,webm, from 'retro_gemini.mkv':
  Metadata:
    title           : Gemini, a modern protocol that looks retro
    DATE            : 2021-02-07
...
[STREAM]
index=0
codec_name=ffv1
codec_long_name=FFmpeg video codec #1
codec_type=video
codec_time_base=1/25
codec_tag_string=FFV1
width=1280
height=720
...
  

Merci à Jérôme Martinez pour sa relecture attentive.


Téléchargez le RFC 9043


L'article seul

RFC 9102: TLS DNSSEC Chain Extension

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. 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
  • RRSIG(_443._tcp.www.example.com TLSA)
  • example.com. DNSKEY
  • RRSIG(example.com DNSKEY)
  • example.com DS
  • RRSIG(example.com DS)
  • com DNSKEY
  • RRSIG(com DNSKEY)
  • com DS
  • RRSIG(com DS)
  • . DNSKEY
  • RRSIG(. 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.


Téléchargez le RFC 9102


L'article seul

RFC 9078: Reaction: Indicating Summary Reaction to a Message

Date de publication du RFC : Août 2021
Auteur(s) du RFC : D. Crocker (Brandenburg InternetWorking), R. Signes (Fastmail), N. Freed (Oracle)
Expérimental
Première rédaction de cet article le 5 août 2021


Vous trouvez que le courrier électronique, c'est vieux et ringard, et que les réseaux sociaux avec leurs possibilités de réaction (« J'aime ! », « Je partage ! », « Je rigole ! »), c'est mieux ? Et bien, vous n'êtes pas le seul ou la seule. Ce nouveau RFC normalise un mécanisme pour mettre des réactions courtes et impulsives dans le courrier électronique.

L'idée de base est que, si ce RFC plait et est mis en œuvre par les auteurs de MUA, on verra près du message qu'on lit un menu avec des émojis, et on cliquera dessus, et l'émetteur du message verra sur son propre MUA le message qu'il a envoyé accompagné de ces réactions. (Le RFC ne normalise pas une apparence particulière à ces réactions, cf. section 5.2 pour des idées qui ne sont que des suggestions.)

Bien sûr, on peut déjà répondre à un message avec des émojis dans le corps de la réponse. Mais l'idée est de structurer cette réaction pour permettre une utilisation plus proche de celle des réseaux sociaux, au lieu que la réaction soit affichée comme un message comme les autres. Liée au message originel, cette structuration permettra, par exemple, au MUA de l'émetteur originel de voir le nombre de Likes de son message… (Quant à savoir si c'est utile, c'est une autre histoire…)

Techniquement, cela fonctionnera avec la combinaison des en-têtes Content-Disposition: et In-Reply-To:. Voici un exemple montrant le format d'une réaction (négative…) à un message (le 12345@example.com) :

    
To: author@example.com
From: recipient@example.org
Date: Today, 29 February 2021 00:00:10 -800
Message-id: 56789@example.org
In-Reply-To: 12345@example.com
Subject: Re: Meeting
Mime-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Disposition: Reaction

👎

  

(Si vous n'avez pas les bons émojis sur votre système, le caractère en question était le pouce vers le bas.) Recevant cette réponse, le MUA de l'auteur (author@example.com) peut rechercher le message 12345@example.com et afficher que recipient@example.org n'est pas enthousiaste.

Le paramètre Reaction pour l'en-tête Content-Disposition: (RFC 2183) a été ajouté au registre IANA.

Le texte dans la partie MIME qui a l'en-tête Content-Disposition: Reaction est une ligne d'émojis. On peut utiliser les séquences d'émojis. Tous les émojis sont utilisables mais le RFC en liste cinq qui sont particulièrement importants car considérés comme la base, le minimum que devrait reconnaitre tout MUA :

Notez que le concept de séquence d'émojis n'est pas simple. Ce concept permet d'éviter de normaliser des quantités astronomiques d'émojis, en autorisation la combinaison d'émojis. Il est utilisé entre autres pour les drapeaux nationaux, ainsi le drapeau libanais sera 🇱🇧 (U+1F1F1 qui indique le L du code pays ISO 3166 et U+1F1E7 qui indique le B). Le RFC rappelle qu'écrire du code dans son application pour gérer ces séquences n'est pas raisonnable et qu'il vaut mieux utiliser une bibliothèque Unicode existante.

Les sections 4 et 5 du RFC donnent quelques idées aux auteurs de MUA sur la gestion de ces réactions. Normalement, l'IETF normalise des protocoles, pas des interfaces utilisateur. Mais cela n'interdit pas de parler un peu d'UX dans le RFC, comme indiqué plus haut. En outre, l'interface utilisateur vers le courrier est typiquement assez différente de celle des réseaux sociaux où ce concept de réaction existe. Ainsi, le RFC ne tranche pas sur la question de savoir s'il faut envoyer la réaction uniquement à l'auteur original du message, ou bien à tous les destinataires. Ou bien s'il faut envoyer un message contenant juste la partie Réaction ou si on peut la combiner avec un autre contenu. Et que faire si, depuis la même adresse, on reçoit plusieurs réactions, éventuellement contradictoires ? Ne garder que la dernière (attention, le courrier électronique ne conserve pas l'ordre d'envoi) ? Les additionner ?

Toujours en UX, le RFC note que la réception d'une image dépend beaucoup du récepteur. (Et, contrairement à ce que laisse entendre le RFC, ce n'est pas juste une question de « culture », des personnes de la même « culture » peuvent comprendre différemment la même image.) Il faut donc faire attention aux réactions, qui peuvent être mal comprises. (Ceci dit, c'est exactement pareil avec le texte seul.) Et, comme toujours sur l'Internet, cette possibilité pourra ouvrir de nouveaux problèmes de sécurité (utilisation pour l'hameçonnage ?).


Téléchargez le RFC 9078


L'article seul

RFC 9095: Extensible Provisioning Protocol (EPP) Domain Name Mapping Extension for Strict Bundling Registration

Date de publication du RFC : Juillet 2021
Auteur(s) du RFC : J. Yao, L. Zhou, H. Li (CNNIC), N. Kong (Consultant), W. Tan (Cloud Registry), J. Xie
Pour information
Première rédaction de cet article le 30 juillet 2021


Le bundling est le rassemblement de plusieurs noms de domaine dans un seul lot (bundle) qui va être traité comme un nom unique pour des opérations comme l'enregistrement du nom ou son transfert à un autre titulaire. Il est surtout pratiqué par les registres qui ont beaucoup de noms en écriture chinoise. Ce RFC décrit une extension au protocole d'avitaillement EPP pour pouvoir traiter ces lots.

Le problème n'existe pas qu'en chinois mais ce sont surtout les sinophones qui se sont manifestés à ce sujet, en raison de la possibilité d'écrire le même mot en écriture traditionnelle ou en écriture simplifiée (on parle de variantes : l'ensemble des variantes forme le lot). Pour prendre un exemple non-chinois, PIR avait décidé qu'un nom dans .ngo et dans .ong devaient être dans le même lot. Un registre qui décide que ces deux termes sont équivalents et doivent être gérés ensemble (par exemple, appartenir au même titulaire) les regroupent dans un lot (bundle, ou parfois package). C'est la politique suggérée dans les RFC 3743 et RFC 4290, et le RFC 6927 décrit les pratiques existantes. Par exemple, certains registres peuvent n'autoriser qu'une variante par lot, et bloquer les autres (empêcher leur enregistrement), tandis que d'autres enregistreront tous les noms ensemble. Sans compter bien sûr les registres qui n'ont pas de système de lot du tout. Notre nouveau RFC 9095 ne prend pas position sur ce sujet délicat, il décrit juste un moyen technique de manipuler ces lots avec EPP (RFC 5731).

Les variantes dans un même lot n'ont pas forcément tout en commun. Un registre peut par exemple décider que l'enregistrement des variantes doit être fait par le même titulaire mais qu'un nom du lot peut ensuite être transféré à un autre titulaire. Notre RFC se limite au cas strict où les membres du lot ont presque tous leurs attributs (titulaires, contacts, date d'expiration, peut-être serveurs de noms et, pourquoi pas, clés DNSSEC) en commun.

La lecture du RFC nécessite un peu de terminologie spécifique, décrite dans sa section 2. Par exemple, le RDN (Registered Domain Name) est celui qui a été demandé par le titulaire lors de l'enregistrement, et le BDN (Bundled Domain Name) est un nom qui a été inclus dans le lot, en fonction des règles du registre. Par exemple, si un registre décidait que tout nom avec des traits d'union était équivalent au même nom sans traits d'union, et qu'un titulaire enregistre tarte-poireaux.example (le RDN), alors tartepoireaux.example et tarte-poi-reaux.example seraient des BDN, membres du même lot que le RDN. Dans le modèle de notre RFC, les métadonnées comme la date d'expiration ou comme l'état du domaine sont attachées au RDN, les BDN du lot partageant ces métadonnées.

Notons aussi que le RFC n'envisage que le cas de lots assez petits (par exemple le nom en écriture chinoise traditionnelle et celui en écriture chinoise simplifiée). L'exemple que je donnais avec le trait d'union ne rentre pas tellement dans le cadre de ce RFC car le nombre de BDN est alors beaucoup plus élevé et serait difficile à gérer. (Amusez-vous à calculer combien de variantes de tartepoireaux.example existeraient si un décidait que le trait d'union n'est pas significatif.)

Dans l'extension EPP décrite dans ce RFC, le RDN est représenté (section 5 du RFC) en Unicode (le « U-label ») ou bien en ASCII (le « A-label », la forme « punycodée »). L'élement XML est <b-dn:rdn> (où b-dn est un préfixe possible pour l'espace de noms XML de notre RFC, urn:ietf:params:xml:ns:epp:b-dn). Si le RDN est représenté en ASCII, un attribut XML uLabel permet d'indiquer la version Unicode du nom. Cela donnerait, par exemple, <b-dn:rdn uLabel="实例.example">xn--fsq270a.example</b-dn:rdn>.

Enfin, la section 6 décrit les commandes et réponses EPP pour notre extension. La commande <check> n'est pas modifiée dans sa syntaxe mais le RFC impose que, si un nom qui fait partie d'un lot est envoyé dans la question, la réponse doit contenir le RDN et le BDN. Pour un RDN en sinogrammes, on aurait ainsi la version en écriture traditionnelle et en écriture simplifiée (ici, le nom est disponible à l'enregistrement) :


<response>
  <result code="1000">
    <msg>Command completed successfully</msg>
  </result>
  <resData>
    <domain:chkData
      xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
        <domain:cd>
         <domain:name avail="1">
          xn--fsq270a.example</domain:name>
        </domain:cd>
        <domain:cd>
          <domain:name avail="1">
            xn--fsqz41a.example
          </domain:name>
          <domain:reason>This associated domain name is
            a produced name based on bundle name policy.
          </domain:reason>
        </domain:cd>
    </domain:chkData>
...

  

La commande <info> n'est pas non plus modifiée mais sa réponse l'est, par l'ajout d'un élément <bundle> qui décrit le lot :


<response>
  <result code="1000">
    <msg>Command completed successfully</msg>
  </result>
  <resData>
    <domain:infData
      xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
      <domain:name>xn--fsq270a.example</domain:name>
      <domain:roid>58812678-domain</domain:roid>
      <domain:status s="ok"/>
...
    </domain:infData>
  </resData>
  <extension>
    <b-dn:infData
      xmlns:b-dn="urn:ietf:params:xml:ns:epp:b-dn">
      <b-dn:bundle>
        <b-dn:rdn uLabel="实例.example">
          xn--fsq270a.example
        </b-dn:rdn>
        <b-dn:bdn uLabel="實例.example">
          xn--fsqz41a.example
        </b-dn:bdn>
      </b-dn:bundle>
    </b-dn:infData>
  </extension>

  

Quand on crée un domaine qui fait partie d'un lot, la commande <create> doit inclure une extension indiquant que le client EPP connait la gestion de lots, et la réponse à <create> lui donnera le BDN. D'une manière analogue, la commande <delete> détruira tout le lot et l'indiquera dans la réponse. La commande <update> fonctionne sur le même principe : elle modifie le RDN et indique dans sa réponse le BDN affecté. La syntaxe complète de cette extension EPP figure dans la section 7 du RFC, sous forme d'un schéma W3C. Par ailleurs, cette extension est enregistrée dans le registre des extensions EPP (celui créé par le RFC 7451).

Un petit mot sur la sécurité, car de nombreux adversaires de l'internationalisation, notamment anglophones, ont critiqué les noms de domaine en Unicode, les accusant de tous les maux : les auteurs du RFC notent que des noms en chinois sont enregistrés depuis plus de quinze ans, et qu'aucun problème particulier n'a été signalé.

Questions mises en œuvre de ce RFC, les registres chinois (comme .cn ou .tw) suivent les principes de ce RFC (l'enregistrement d'un lot) depuis longtemps. CNNIC déploie cette extension EPP. En dehors de la sinophonie, PIR utilise les lots pour .ngo et .ong. Et cette extension EPP est mise en œuvre dans Net::DRI.

Et, comme souvent, il y a un brevet de Verisign sur la technique décrite dans ce RFC. Je ne l'ai pas lu mais il y a des chances qu'il soit sans mérite, comme beaucoup de brevets logiciels.


Téléchargez le RFC 9095


L'article seul

RFC 9077: NSEC and NSEC3: TTLs and Aggressive Use

Date de publication du RFC : Juillet 2021
Auteur(s) du RFC : P. van Dijk (PowerDNS)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 25 juillet 2021


Ce nouveau RFC corrige une légère bavure. Lorsqu'on utilise la mémorisation énergique du RFC 8198 pour synthétiser des réponses DNS en utilisant les informations DNSSEC, les normes existantes permettaient une mémorisation pendant une durée bien trop longue. Cette erreur (peu grave en pratique) est désormais corrigée.

Rappelons que le principe du RFC 8198 est d'autoriser un résolveur DNS à synthétiser des informations qu'il n'a normalement pas dans sa mémoire, notamment à partir des enregistrements NSEC de DNSSEC (RFC 4034, section 4). Si un résolveur interroge la racine du DNS :

    
%     dig @a.root-servers.net A foobar
...
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 37332
...
foo.			86400 IN NSEC food. NS DS RRSIG NSEC

  

La réponse est négative (NXDOMAIN) et un enregistrement NSEC annonce au client DNS qu'il n'y a pas de nom dans la racine entre .foo et .food. Si le résolveur mémorise cette information et qu'on lui demande par la suite un nom en .foocat, il n'aura pas besoin de contacter la racine, il sait, en raison de l'enregistrement NSEC que ce nom ne peut pas exister.

Bon, mais combien de temps le résolveur peut-il mémoriser cette non-existence ? Le RFC 2308 disait qu'une réponse négative (NXDOMAIN) pouvait être mémorisée pendant une durée indiquée par le minimum du champ Minimum de l'enregistrement SOA et du TTL de ce même enregistrement SOA. Mais le RFC 4034, normalisant DNSSEC, disait que l'enregistrement NSEC devait avoir un TTL égal au champ Minimum du SOA. Dans l'exemple de la racine du DNS, à l'heure actuelle, cela ne change rien, ces durées sont toutes égales. Mais elles pourraient être différentes. Si un enregistrement SOA a un Minimum à une journée mais un TTL d'une heure, le RFC 2308 impose une heure de mémorisation au maximum, le RFC 4034 permettait une journée… Ça pourrait même être exploité pour une attaque en faisant des requêtes qui retournent des enregistrements NSEC, afin de nier l'existence d'un nom pendant plus longtemps que prévu. [Bon, dans le monde réel, je trouve que c'est un problème assez marginal mais ce n'est pas une raison pour ne pas le corriger.]

Le RFC 8198 avait déjà tenté de corriger le problème mais sans y réussir. Notre nouveau RFC impose désormais clairement que, contrairement à ce que dit le RFC 4034 (et deux ou trois autres RFC sur DNSSEC), la durée maximale de mémorisation est bien le minimum du champ Minimum de l'enregistrement SOA et du TTL de ce même enregistrement SOA.

Si les logiciels que vous utilisez pour signer les zones ne peuvent pas être corrigées immédiatement, le RFC demande que vous changiez le contenu de la zone pour mettre la même valeur au champ Minimum de l'enregistrement SOA et au TTL de ce même enregistrement SOA.

En pratique, les signeurs suivants ont déjà été corrigés :


Téléchargez le RFC 9077


L'article seul

RFC 9076: DNS Privacy Considerations

Date de publication du RFC : Juillet 2021
Auteur(s) du RFC : T. Wicinski
Pour information
Réalisé dans le cadre du groupe de travail IETF dprive
Première rédaction de cet article le 24 juillet 2021


La surveillance généralisée sur l'Internet est un gros problème pour la vie privée. L'IETF s'active donc à améliorer la protection de la vie privée contre cette surveillance (RFC 7258). Un protocole qui avait souvent été négligé dans ce travail est le DNS. Ce RFC décrit les problèmes de vie privée liés au DNS. Il remplace le RFC 7626, avec deux changements important, l'intégration des techniques de protection développées et déployées depuis l'ancien RFC et, malheureusement, beaucoup de propagande anti-chiffrement imposée par les acteurs traditionnels des résolveurs DNS qui ne veulent pas se priver de leurs possibilités de contrôle et de surveillance.

Ce RFC est en fait à la croisée de deux activités. L'une d'elles consiste à documenter les problèmes de vie privée, souvent ignorés jusqu'à présent dans les RFC. Cette activité est symbolisée par le RFC 6973, dont la section 8 contient une excellente analyse de ces problèmes, pour un service particulier (la présence en ligne). L'idée est que, même si on ne peut pas résoudre complètement le problème, on peut au moins le documenter, pour que les utilisateurs soient conscients des risques. Et la seconde activité qui a donné naissance à ce RFC est le projet d'améliorer effectivement la protection de la vie privée des utilisateurs du DNS, en marchant sur deux jambes : minimiser les données envoyées et les rendre plus résistantes à l'écoute, via le chiffrement. L'objectif de diminution des données a débouché sur la QNAME minimization spécifiée dans le RFC 7816 et le chiffrement a donné DoT (RFC 7858) et DoH (RFC 8484).

Donc, pourquoi un RFC sur les questions de vie privée dans le DNS ? Ce dernier est un très ancien protocole, dont l'une des particularités est d'être mal spécifié : aux deux RFC originaux, les RFC 1034 et RFC 1035, il faut ajouter dix ou vingt autres RFC dont la lecture est nécessaire pour tout comprendre du DNS. Et aucun travail de consolidation n'a jamais été fait, contrairement à ce qui a eu lieu pour XMPP, HTTP ou SMTP. Or, le DNS est crucial, car quasiment toutes les transactions Internet mettent en jeu au moins une requête DNS (ne me dites pas des bêtises du genre « moi, je télécharge avec BitTorrent, je n'utilise pas le DNS » : comment allez-vous sur thepiratebay.am ?) Mais, alors que les questions de vie privée liées à HTTP ont fait l'objet d'innombrables articles et études, celles liées au DNS ont été largement ignorées pendant longtemps (voir la bibliographie du RFC pour un état de l'art). Pourtant, on peut découvrir bien des choses sur votre activité Internet uniquement en regardant le trafic DNS.

Une des raisons du manque d'intérêt pour le thème « DNS et vie privée » est le peu de compétences concernant le DNS : le protocole est souvent ignoré ou mal compris. C'est pourquoi le RFC doit commencer par un rappel (section 1) du fonctionnement du DNS.

Je ne vais pas reprendre tout le RFC ici. Juste quelques rappels des points essentiels du DNS : il existe deux sortes de serveurs DNS, qui n'ont pratiquement aucun rapport. Il y a les serveurs faisant autorité et les résolveurs. Les premiers sont ceux qui connaissent de première main l'information pour une zone DNS donnée (comme fr ou wikipedia.org). Ils sont gérés par le titulaire de la zone ou bien sous-traités à un hébergeur DNS. Les seconds, les résolveurs, ne connaissent rien (à part l'adresse IP des serveurs de la racine). Ils interrogent donc les serveurs faisant autorité, en partant de la racine. Les résolveurs sont gérés par le FAI ou le service informatique qui s'occupe du réseau local de l'organisation. Ils peuvent aussi être individuels, ou bien au contraire être de gros serveurs publics comme Google Public DNS, gros fournisseur de la NSA. Pour prendre un exemple concret (et en simplifiant un peu), si M. Michu veut visiter le site Web http://thepiratebay.am/, son navigateur va utiliser les services du système d'exploitation sous-jacent pour demander l'adresse IP de thepiratebay.am. Le système d'exploitation va envoyer une requête DNS au résolveur (sur Unix, les adresses IP des résolveurs sont dans /etc/resolv.conf). Celui-ci va demander aux serveurs de la racine s'ils connaissent thepiratebay.am, il se fera rediriger vers les serveurs faisant autorité pour am, puis vers ceux faisant autorité pour thepiratebay.am. Le résolveur aura alors une réponse qu'il pourra transmettre au navigateur de M. Michu.

Principal point où j'ai simplifié : le DNS s'appuie beaucoup sur la mise en cache des données, c'est-à-dire sur leur mémorisation pour gagner du temps la fois suivante. Ainsi, si le même M. Michu, cinq minutes après, veut aller en http://armenpress.am/, son résolveur ne demandera rien aux serveurs de la racine : il sait déjà quels sont les serveurs faisant autorité pour am.

Le trafic DNS est un trafic IP ordinaire, typiquement porté par UDP. Mais il peut aussi fonctionner sur TCP et bientôt sur QUIC. Il peut être écouté, et comme il n'est pas toujours chiffré, un indiscret peut tout suivre. Voici un exemple pris avec tcpdump sur un serveur racine (pas la racine officielle, mais, techniquement, cela ne change rien) :

15:29:24.409283 IP6 2001:67c:1348:8002::7:107.10127 > \
    2001:4b98:dc2:45:216:3eff:fe4b:8c5b.53: 32715+ [1au] \
    AAAA? www.armenpress.am. (46)

On y voit que le client 2001:67c:1348:8002::7:107 a demandé l'adresse IPv6 de www.armenpress.am.

Pour compléter le tableau, on peut aussi noter que les logiciels génèrent un grand nombre de requêtes DNS, bien supérieur à ce que voit l'utilisateur. Ainsi, lors de la visite d'une page Web, le résolveur va envoyer la requête primaire (le nom du site visité, comme thepiratebay.am), des requêtes secondaires dues aux objets contenus dans la page Web (JavaScript, CSS, divers traqueurs et autres outils de cyberflicage ou de cyberpub) et même des requêtes tertiaires, lorsque le fonctionnement du DNS lui-même nécessitera des requêtes. Par exemple, si abc.xyz est hébergé sur des serveurs dans google.com, une visite de http://abc.xyz/ nécessitera de résoudre les noms comme ns1.google.com, donc de faire des requêtes DNS vers les serveurs de google.com.

Bien sûr, pour un espion qui veut analyser tout cela, le trafic DNS représente beaucoup de données, souvent incomplètes en raison de la mise en cache, et dont l'interprétation peut être difficile (comme dans l'exemple ci-dessus). Mais les organisations qui pratiquent l'espionnage massif, comme la NSA, s'y connaissent en matière de big data et savent trouver les aiguilles dans les bottes de foin.

Les sections 3 à 7 du RFC détaille les risques pour la vie privée dans les différents composants du DNS. Notez que la confidentialité du contenu du DNS n'est pas prise en compte (elle l'est dans les RFC 5936 et RFC 5155). Il est important de noter qu'il y a une énorme différence entre la confidentialité du contenu et la confidentialité des requêtes. L'adresse IP de www.charliehebdo.fr n'est pas un secret : les données DNS sont publiques, dès qu'on connait le nom de domaine, et tout le monde peut faire une requête DNS pour la connaitre. Mais le fait que vous fassiez une requête pour ce nom ne devrait pas être public. Vous n'avez pas forcément envie que tout le monde le sache. (On peut quand même nuancer un peu le côté « public » des données DNS : on peut avoir des noms de domaine purement internes à une organisation. Mais ces noms « fuitent » souvent, par la marche sur la zone décrite dans le RFC 4470, ou via des systèmes de « passive DNS).

Pour comprendre les risques, il faut aussi revenir un peu au protocole DNS. Les deux informations les plus sensibles dans une requête DNS sont l'adresse IP source et le nom de domaine demandé (qname, pour Query Name, cf. RFC 1034, section 3.7.1). L'adresse IP source est celle de votre machine, lorsque vous parlez au résolveur, et celle du résolveur lorsqu'il parle aux serveurs faisant autorité. Elle peut indiquer d'où vient la demande. Lorsque on utilise un gros résolveur, celui-ci vous masque vis-à-vis des serveurs faisant autorité (par contre, ce gros résolveur va avoir davantage d'informations). Ceci dit, l'utilisation d'ECS (RFC 7871) peut trahir votre adresse IP, ou au moins votre préfixe. (Cf. cette analyse d'ECS. D'autre part, certains opérateurs se permettent d'insérer des informations comme l'adresse MAC dans des options EDNS de la requête.)

Quant au qname, il peut être très révélateur : il indique les sites Web que vous visitez, voire, dans certains cas, les logiciels utilisés. Au moins un client BitTorrent fait des requêtes DNS pour _bittorrent-tracker._tcp.domain.example, indiquant ainsi à beaucoup de monde que vous utilisez un protocole qui ne plait pas aux ayant-droits. Et si vous utilisez le RFC 4255, pas mal de serveurs verront à quelles machines vous vous connectez en SSH...

Donc où un méchant qui veut écouter votre trafic DNS peut-il se placer ? D'abord, évidemment, il suffit qu'il écoute le trafic réseau. On l'a dit, le trafic DNS aujourd'hui est souvent en clair donc tout sniffer peut le décoder. Même si vous utilisez HTTPS pour vous connecter à un site Web, le trafic DNS, lui, ne sera pas chiffré. (Les experts pointus de TLS noteront qu'il existe d'autres faiblesses de confidentialité, comme le SNI du RFC 6066, qui n'est pas encore protégé, cf. RFC 8744.) À noter une particularité du DNS : le trafic DNS peut passer par un autre endroit que le trafic applicatif. Alice peut naïvement croire que, lorsqu'elle se connecte au serveur de Bob, seul un attaquant situé physiquement entre sa machine et celle de Bob représente une menace. Alors que son trafic DNS peut être propagé très loin, et accessible à d'autres acteurs. Si vous utilisez, par exemple, le résolveur DNS public de FDN, toute la portion de l'Internet entre vous et FDN peut facilement lire votre trafic DNS.

Donc, l'éventuel espion peut être près du câble, à écouter. Mais il peut être aussi dans les serveurs. Bercé par la musique du cloud, on oublie souvent cet aspect de la sécurité : les serveurs DNS voient passer le trafic et peuvent le copier. Pour reprendre les termes du RFC 6973, ces serveurs sont des assistants : ils ne sont pas directement entre Alice et Bob mais ils peuvent néanmoins apprendre des choses à propos de leur conversation. Et l'observation est très instructive. Elle est utilisée à de justes fins dans des systèmes comme DNSDB (section 6 du RFC) mais il n'est pas difficile d'imaginer des usages moins sympathiques comme dans le cas du programme NSA MORECOWBELL.

Les résolveurs voient tout le trafic puisqu'il y a peu de mise en cache en amont de ces serveurs. Il faut donc réfléchir à deux fois avant de choisir d'utiliser tel ou tel résolveur ! Il est déplorable qu'à chaque problème DNS (ou supposé tel), des ignorants bondissent sur les réseaux sociaux pour dire « zyva, mets 8.8.8.8 [Google Public DNS] comme serveur DNS et ça ira plus vite » sans penser à toutes les données qu'ils envoient à la NSA ainsi.

Les serveurs faisant autorité voient passer moins de trafic (à cause des caches des résolveurs) mais, contrairement aux résolveurs, ils n'ont pas été choisis délibérement par l'utilisateur. Celui-ci peut ne pas être conscient que ses requêtes DNS seront envoyées à plusieurs acteurs du monde du DNS, à commencer par la racine. Le problème est d'autant plus sérieux que, comme le montre une étude, la concentration dans l'hébergement DNS est élevée : dix gros hébergeurs hébergent le tiers des domaines des 100 000 sites Web les plus fréquentés (listés par Alexa).

Au passage, le lecteur attentif aura noté qu'un résolveur personnel (sur sa machine ou dans son réseau local) a l'avantage de ne pas envoyer vos requêtes à un résolveur peut-être indiscret mais l'inconvénient de vous démasquer vis-à-vis des serveurs faisant autorité, puisque ceux-ci voient alors votre adresse IP. Une bonne solution (qui serait également la plus économe des ressources de l'Internet) serait d'avoir son résolveur local et de faire suivre les requêtes non résolues au résolveur du FAI. Du point de vue de la vie privée, ce serait sans doute la meilleure solution mais cela ne résout hélas pas un autre problème, celui des DNS menteurs, contre lesquels la seule protection est d'utiliser uniquement un résolveur de confiance. On peut résoudre ce problème en ayant son propre résolveur mais qui fait suivre à un résolveur public de confiance. Notez que la taille compte : plus un résolveur est petit, moins il protège puisque ses requêtes sortantes ne seront dues qu'à un petit nombre d'utilisateurs.

Enfin, il y a aussi les serveurs DNS « pirates » (installés, par exemple, via un serveur DHCP lui-même pirate) qui détournent le trafic DNS, par exemple à des fins de surveillance. Voir par exemple l'exposé de Karrenberg à JCSA 2012 disponible en ligne (transparents 27 et 28, Unknown et Other qui montrent l'existence de clones pirates du serveur racine K.root-servers.net).

Pour mes lecteurs en France férus de droit, une question intéressante : le trafic DNS est-il une « donnée personnelle » au sens de la loi Informatique & Libertés ? Je vous laisse plancher sur la question, qui a été peu étudiée.

Les changements depuis le RFC 7626 sont résumés dans l'annexe A. Outre des retours d'expérience basés sur le déploiement de solutions minimisant et/ou chiffrant les données, ils consistent essentiellement en remarques négatives sur le chiffrement, défendant le mécanisme traditionnel de résolution DNS. Il n'y avait d'ailleurs pas forcément d'urgence à sortir un nouveau RFC. Comme le demandait Alissa Cooper, l'auteure du RFC 6973, « Why not wait to see how QUIC, DOH, ADD, ODNS, etc. shake out in the next few years and take this up then? ». C'est en raison de ces changements négatifs que je ne suis pas cité comme auteur du RFC (contraitement à son prédécesseur). Sara Dickinson, qui avait géré l'essentiel du travail pour les débuts de ce nouveau RFC, s'est également retirée, en raison de la dureté des polémiques qui ont déchiré l'IETF sur ce document.

Depuis la sortie du RFC 7626, il y a eu un certain nombre de déploiement de techniques améliorant la protection de la vie privée dans le cas du DNS, notamment la minimisation des données (RFC 7816) et le chiffrement (DoT, RFC 7858, DoH, RFC 8484, et le futur DoQ). Cela permet des retours d'expérience. Par exemple, sur l'ampleur du déploiement de la minimisation, ou sur les performances du chiffrement (voir « An End-to-End, Large-Scale Measurement of DNS-over-Encryption »). Il y a eu également des discussions politiques à propos de ces techniques et de leur déploiement, souvent malhonnêtes ou confuses (et ce RFC en contient plusieurs) comme l'accusation de « centralisation », qui sert surtout à protéger l'état actuel, où l'opérateur de votre réseau d'accès à l'Internet peut à la fois vous surveiller et contrôler ce que vous voyez, via sa gestion de la résolution DNS. Mais il est vrai que rien n'est simple en matière de sécurité et que DoH (mais pas DoT) est trop bavard, puisqu'il hérite des défauts de HTTP, en envoyant trop d'informations au serveur.

Le RFC essaie de décourager les utilisateurs d'utiliser le chiffrement (dans l'esprit du RFC 8404) en notant que ce n'est pas une technologie parfaite (par exemple, l'observation des métadonnées peut donner des indications ou, autre exemple, une mauvaise authentification du résolveur peut vous faire envoyer vos requêtes à un méchant). C'est vrai mais c'est le cas de toutes les solutions de sécurité et on ne trouve pas de tels avertissements dans d'autres RFC qui parlent de chiffrement. L'insistance des opérateurs pour placer ces messages anti-chiffrement dans ce RFC montre bien, justement, l'importance de se protéger contre la curiosité des opérateurs.

Le RFC remarque également qu'il n'existe pas actuellement de moyen de découvrir automatiquement le résolveur DoT ou DoH. Mais c'est normal : un résolveur DoT ou DoH annoncé par le réseau d'accès, par exemple via DHCP, n'aurait guère d'intérêt, il aurait les mêmes défauts (et les mêmes qualités) que le résolveur traditionnel. DoT et DoH n'ont de sens qu'avec un résolveur configuré statiquement. Le RFC cite des déploiements de résolveurs DNS avec chiffrement faits par plusieurs FAI (aucun en France, notons-le). Cela montre une grosse incompréhension du problème : on ne chiffre pas pour le plaisir de chiffrer, mais parce que cela permet d'aller de manière sécurisée vers un autre résolveur. Chiffrer la communication avec le résolveur habituel ne fait pas de mal mais on ne gagne pas grand'chose puisque ce résolveur a les mêmes capacités de surveillance et de modification des réponses qu'avant. Notons que le RFC, inspiré par la propagande des telcos, raconte que le risque de surveillance est minimisé par le chiffrement du lien radio dans les réseaux 4G et après. Cela oublie le fait que la surveillance peut justement venir de l'opérateur.

Plus compliqué est le problème de l'endroit où se fait cette configuration. Traditionnellement, la configuration du résolveur à utiliser était faite globalement par le système d'exploitation. Ce n'est pas du tout une règle du protocole DNS (les RFC normalisant le DNS ne contrôlent que ce qui circule sur le câble, pas les choix locaux de chaque machine) et il serait donc absurde d'invoquer un soi-disant principe comme quoi le DNS serait forcément géré au niveau du système. Certains déploiements de DoH (celui de Firefox, par exemple), mettent le réglage dans l'application (en l'occurrence le navigateur Web). La question est discutable et discutée mais, de toute façon, elle ne relève pas de l'IETF (qui normalise ce qui passe sur le réseau) et il est anormal que le RFC en parle.

Le temps passé depuis le RFC 7626 a également permis la mise en service d'un plus grand nombre de résolveurs publics, comme Quad9 ou comme celui de Cloudflare. Mais il n'y a pas que les grosses boîtes états-uniennes qui gèrent des résolveurs DNS publics. Ainsi, je gère moi-même un modeste résolveur public. Le très intéressant RFC 8932 explique le rôle des politiques de vie privée dans ces résolveurs publics et comment en écrire une bonne. Bien sûr, comme toujours en sécurité, la lutte de l'épée contre la cuirasse est éternelle et des nouvelles actions contre la vie privée et la liberté de choix apparaissent, par exemple des réseaux qui bloquent l'accès à DoT (en bloquant son port 853) ou aux résolveurs DoH connus (DoH a été développé en partie pour être justement plus difficile à bloquer).


Téléchargez le RFC 9076


L'article seul

RFC 9075: Report from the IAB COVID-19 Network Impacts Workshop 2020

Date de publication du RFC : Juillet 2021
Auteur(s) du RFC : J. Arkko (Ericsson), S. Farrell (Trinity College Dublin), M. Kühlewind (Ericsson), C. Perkins (University of Glasgow)
Pour information
Première rédaction de cet article le 23 juillet 2021


La pandémie de Covid-19 en 2020 a affecté de nombreux aspects de notre vie. Concernant plus spécifiquement l'Internet, elle a accru l'utilisation d'outils de communication informatiques. Quels ont été les effets de ces changements sur l'Internet ? Un atelier de l'IAB fait le point sur ces effets et en tire des leçons. Je vous le dis tout de suite : contrairement à certains discours sensationnalistes, l'Internet n'a pas subi de conséquences sérieuses.

De janvier à mars 2020, de nombreux pays ont imposé un confinement plus ou moins strict. Des activités comme le travail ou l'éducation devaient se faire à distance, en utilisant les outils numériques. Certains politiciens ont tenu des discours dramatisants, prétendant que, si on ne renonçait pas à regarder ses vidéos favorites, l'Internet allait s'écrouler. Même si aucun professionnel des réseaux n'a repris ce discours, cela ne veut pas dire qu'il ne s'est rien passé. L'IAB a donc organisé en novembre 2020 un atelier (évidemment tenu en ligne car il n'y avait pas le choix) pour étudier les effets de ces confinements sur l'Internet, comprendre ce qui est arrivé et peut-être formuler des recommandations.

Donc, pendant le confinement et l'augmentation du télétravail qui en a résulté, le trafic Internet a changé. Il n'a pas toujours augmenté (les travailleurs utilisaient également Internet quand ils étaient au bureau, et les gens regardaient déjà Netflix avant la pandémie) mais il s'est déplacé : trafic de type différent, à des heures différentes, etc. Et, dans la plupart des pays, c'est arrivé assez soudainement, laissant peu de temps pour l'adaptation. La sécurité a été également très affectée, les mesures de sécurité conçues sur la base d'un lieu physique n'ayant plus de sens. Tout à coup, il a fallu autoriser beaucoup d'accès distants, avec tous les risques que cela impliquait. L'atelier lui-même a été différent des précédents ateliers de l'IAB, qui étaient fondés sur une participation physique pendant deux jours continus. Cette fois, l'atelier s'est fait en trois sessions à distance, avec respiration et réflexion entre les sessions.

Qu'ont observé les acteurs de l'Internet ? À l'atelier, certains FAI ou gérants de points d'échange Internet ont signalé des accroissements de 20 % du trafic. C'est à la fois beaucoup et peu. C'est beaucoup car c'est survenu soudainement, sans être étalé sur une période permettant le déploiement de nouvelles ressources, et c'est peu, car la croissance de l'utilisation des réseaux est un phénomène permanent : il faut toujours augmenter la capacité (20 % représente une augmentation annuelle typique, mais qui fut concentrée en quelques semaines). On voit ici le trafic sur le point d'échange Internet de Francfort (la source est ici). S'il y a bien une brusque montée début 2020 avec le démarrage du confinement, il faut noter qu'elle s'inscrit dans une augmentation du trafic Internet sur le long terme : decix-covid-2020.png

Cette montée du trafic lors du confinement est également relativisée sur les statistiques de trafic au point d'échange parisien (la source est ici) : franceix-covid-2020.png

De même, l'article « Measurement of congestion on ISP interconnection links » mesure des moments de congestion limités aux États-Unis en mars. Cette croissance était très inégalement répartie selon les services. Vous ne serez pas surpris d'apprendre que certains opérateurs de services de vidéo-conférence ont vu leur activité tripler, voire décupler. Une intéressante conclusion est que, contrairement à ce que certains discours sensationnalistes comme ceux de Thierry Breton prétendaient, l'Internet n'a pas connu de problème généralisé. Comme toujours dans ce réseau mondial, les problèmes sont restés localisés, ralentissements à certains endroits, baisse automatique de la qualité des vidéos à d'autres, mais pas de problème systémique. Ce bon résultat n'a pas été obtenu uniquement par la capacité du réseau existant à encaisser la montée en charge. Il y a eu également de nombreuses actions prises par les différents acteurs du réseau, qui ne sont pas restés les bras croisés face au risque. Bref, vu du point de vue scientifique, c'était une expérience intéressante, qui montre que l'Internet peut résister à des crises, ce qui permet de penser que les problèmes futurs ne seront pas forcément fatals.

[L'atelier portait bien sur l'Internet, sur l'infrastructure, pas sur les services hébergés. Il est important de faire la distinction car certains services (comme ceux de l'Éducation Nationale en France) ont été incapables de résister à la charge et se sont vite écroulés. Mais ce n'était pas une défaillance de l'Internet, et renoncer à regarder des vidéos n'aurait pas protégé le CNED contre ces problèmes. Notons qu'il n'y avait pas de fatalité à ces problèmes des services : Wikipédia et Pornhub, deux services très différents dans leur utilisation et leur gestion, ont continué à fonctionner correctement.]

Voyons maintenant les détails, dans la section 3 du RFC. On commence avec la sous-section 3.1, les mesures. Que s'est-il passé ? Comme on pouvait s'y attendre, le trafic résidentiel a augmenté (en raison du travail à la maison), tandis que celui des réseaux mobiles chutait (on se déplaçait moins). Le trafic vers les opérateurs de services de vidéo-conférence (comme Zoom) a augmenté, ainsi que celui des services de distraction (VoD) pendant la journée. Mais il y a eu surtout un gros déplacement des pics d'activité. En semaine, l'activité Internet était très liée au rythme de la journée, avec des trafics très différents dans la journée et le soir. Pendant les confinements, on a vu au contraire une activité plus étalée dans le temps chez les FAI résidentiels, et une activité de la semaine qui ressemble à celle des week-ends. Là encore, pas de conséquences graves, bien que certains FAI aient signalé des ralentissements notamment en mars 2020. Bref, l'Internet sait bien résister aux sautes de trafic qui, il est vrai, font partie de son quotidien depuis sa création.

Parmi les articles soumis pour l'atelier, je vous recommande, sur la question des mesures, le très détaillé « A view of Internet Traffic Shifts at ISP and IXPs during the COVID-19 Pandemic ». Les auteurs ont observé le trafic chez plusieurs opérateurs et points d'échange (le seul nommé est le réseau académique de Madrid). Par exemple, en utilisant diverses heuristiques (le port seul ne suffit plus, tout le monde étant sur 443), les auteurs ont des chiffres concernant diverses applications (vidéo-conférence, vidéo à la demande, jeux en ligne, etc). Moins détaillé, il y a le « IAB COVID-19 Workshop: Interconnection Changes in the United States » (à l'origine publié dans un Internet-Draft, draft-feamster-livingood-iab-covid19-workshop).

Un exemple de changement du trafic est donné par le Politecnico de Turin qui a vu son trafic sortant multiplié par 2,5, en raison de la diffusion de ses 600 cours en ligne par jour, alors que le trafic entrant était divisé par 10. Dans les universités, le trafic entrant est typiquement bien plus gros que le sortant (les étudiants et enseignants sont sur le campus et accèdent à des ressources distantes) mais cela a changé pendant le confinement, les ressources externes étant accédées depuis la maison. (Une entreprise aurait pu voir des effets différents, si les employés accèdent à ces ressources externes via le VPN de l'entreprise.) Le REN REDIMadrid a vu également de gros changements dans son trafic. Effet imprévu, les communications avec les AS d'Amérique latine a augmenté, probablement parce que les étudiants hispanophones américains profitaient des possibilités de cours à distance pour suivre les activités des universités de l'ex-métropole.

Comme dit plus haut, les réseaux mobiles, 4G et autres, ont vu leur activité baisser. L'article « A Characterization of the COVID-19 Pandemic Impact on a Mobile Network Operator Traffic » note une mobilité divisée par deux en Grande-Bretagne et un trafic diminué d'un quart. (Certaines personnes ne sont plus mobiles mais utilisent la 4G à la maison, et il y a bien d'autres phénomènes qui rendent compliquée l'analyse.) L'observation des signaux envoyés par les téléphones (le réseau mobile sait où vous êtes…) a également permis de mesurer l'ampleur de la fuite hors des grandes villes (10 % des Londoniens).

Et dans la connexion des FAI avec les services sur le cloud ? Les liens d'interconnexion entre FAI et fournisseurs de services ont-ils tenu ? Pas de congestion persistante mais des moments de tension, par exemple aux États-Unis vers les petits FAI, qui n'avaient pas toujours une interconnexion suffisante pour encaisser tout le trafic accru. Comme toujours sur l'Internet, malgré le caractère mondial de la pandémie, il y a peu d'observations valables partout et tout le temps, vu la variété des capacités des liaisons. Malgré l'observation générale « globalement, ça a tenu », il y a toujours des endroits où ça rame à certains moments.

En effet, le bon fonctionnement de l'Internet mondial ne signifiait pas que tous les MM. Toutlemonde de la Terre avaient une bonne qualité de connexion. L'article « The Impact of COVID-19 on Last-mile Latency » (plus de détails sur le blog de l'auteur) rend compte de mesures faites avec les sondes RIPE Atlas, qui trouvent une congestion plus fréquente sur le « premier kilomètre » (le lien entre la maison de M. Toutlemonde et le premier POP de son FAI) pendant le confinement. Cela dépend évidemment beaucoup du FAI et du pays, le Japon ayant été particulièrement touché. La situation s'est toutefois améliorée au fur et à mesure, notamment en raison des déploiements de capacité supplémentaire par les opérateurs (et, au Japon, des investissements qui étaient prévus pour les Jeux Olympiques). L'Internet se retrouve donc plus robuste qu'avant. Le RFC cite même Nietzsche « Ce qui ne me tue pas me rend plus fort ».

On l'a dit, le trafic n'a pas seulement changé quantitativement mais aussi qualitativement. La vidéo-conférence a, fort logiquement, crû. Le trafic très asymétrique de certains FAI grand public (beaucoup plus de trafic entrant vers les consommateurs que de trafic sortant) s'est un peu égalisé, en raison des flux vidéos sortants. NCTA et Comcast signalent plus de 30 % de hausse de ce trafic sortant, Vodafone 100 %. Un rapport d'Ericsson sur les utilisateurs signale :

  • Une augmentation de l'utilisation de l'Internet par 9 utilisateurs sur 10 (le dixième était peut-être déjà connecté tout le temps ?) et des usages nouveaux par 1 utilisateur sur 5 (des gens comme moi qui se mettent à la vidéo-conférence alors qu'ils détestaient cela avant).
  • Peu de plaintes concernant les performances.
  • Évidemment un changement dans les applications utilisées, les applications de vidéo-conférence voient leur usage s'accroitre, celles liées à la location d'hôtels ou de restaurants (ou, note le RFC, celles permettant la recherche d'une place de parking) le voient diminuer.

Ces changements sont-ils permanents ? Resteront-ils dans le « monde d'après » ? Le RFC estime que le télétravail s'est désormais installé et restera ; on peut donc prévoir que l'utilisation intensive d'outils de réunion à distance persistera (cf. le rapport « Work-At-Home After Covid-19—Our Forecast »).

Après ces observations, la section 3 du RFC continue avec des considérations sur les problèmes opérationnels constatés. D'abord, un point de fracture numérique. Aux États-Unis, et probablement dans bien d'autres pays, le débit entrant chez les utilisateurs est corrélé au niveau de vie. Mais on a constaté pendant la pandémie une réduction de l'écart entre riches et pauvres (l'étude ne portait pas sur des foyers individuels mais sur des zones géographiques identifiées par leur code postal, un bon indicateur de niveau de vie, au moins aux USA). Cette réduction de l'écart n'était pas forcément liée à un changement de comportement des utilisateurs mais l'était peut-être au fait que certains FAI comme Comcast ont étendu la capacité liée à des abonnements bon marché, par souci de RSE pendant la crise. L'écart entre riches et pauvres était donc peut-être dû à une différence dans les abonnements souscrits, pas à une différence d'utilisation de l'Internet.

Les applications vedettes des confinements ont évidemment été les outils de réunion en ligne, gros services privateurs et capteurs de données personnelles comme Microsoft Teams ou Zoom, ou bien services reposant sur des logiciels libres comme BigBlueButton (dont le RFC, qui reflète un point de vue surtout étatsunien, ne parle pas). D'autres outils de distribution de vidéo, comme YouTube ont vu également leur trafic augmenter soudainement. Certains acteurs, comme justement YouTube, ont délibérement réduit la qualité des vidéos pour diminuer la charge sur le réseau, mais il n'est pas évident que cela ait eu un effet majeur. Autre catégorie d'applications qui a vu son utilisation augmenter, les jeux en ligne. Souvent très consommateurs de ressources, ils ont la particularité de demander à la fois une forte capacité (en raisons des contenus multimédias riches à télécharger) et une faible latence (quand on tire sur le zombie, il doit tomber tout de suite). La mise à jour d'un jeu très populaire a un effet très net sur le réseau des FAI ! Mais il faut noter que ce n'est pas un phénomène spécifique au confinement. Les opérateurs ont déjà dû faire face à des évènements soudains, comme une nouvelle version d'un logiciel très utilisé ou comme une nouvelle mode, par exemple une application qui connait un succès rapide, ce qui est assez fréquent sur l'Internet. Outre ces « effets Slashdot », il y a aussi les attaques par déni de service, qui nécessitent de suravitailler (mettre davantage de capacité que strictement nécessaire). Les opérateurs ont donc déjà de l'expérience dans ce domaine mais, note le RFC, cette expérience n'est pas toujours partagée.

Une discussion lors de l'atelier a porté sur la possibilité de gérer ce genre de problèmes par des mesures discriminatoires, de type qualité de service (un terme propagandiste, il faut le noter : si on discrimine, certains auront une meilleure qualité et d'autres une moins bonne). Marquer le trafic « pas essentiel » (qui décidera de ce qui n'est pas essentiel ?) avec DSCP pour le faire passer par les chemins les plus lents aurait-il aidé ? Compte-tenu du caractère très brûlant de ce débat, il n'est pas étonnant qu'aucun consensus n'est émergé de l'atelier. Le RFC se réjouit qu'au moins les engueulades ont été moins graves que d'habitude.

Une bonne partie de cet atelier était consacré à l'étude de faits : qu'ont vu les opérateurs ? Or, ils n'ont pas vu la même chose. Cela reflète les différences de situation mais aussi les différences dans les outils d'observation. La métrologie n'est pas une chose facile ! Par exemple, les applications de vidéo-conférence ou de distribution de vidéo à la demande ont des mécanismes de correction d'erreur et de gestion de la pénurie très élaborés. L'application s'adapte en permanence aux caractéristiques du réseau, par exemple en ajustant son taux de compression. C'est très bien pour l'utilisateur, cela permet de lui dissimuler une grande partie des problèmes, mais cela complique l'observation. Et quand il y a un problème, il est difficile à analyser. L'autre jour, sans que cela ait de rapport avec un confinement, je regardais une vidéo sur Netflix et la qualité de l'image était vraiment médiocre, gâchant le plaisir. Mais où était le problème ? Mon PC était trop lent ? Le Wifi était pourri ? Le réseau de Free surchargé ? L'interconnexion entre Free et Netflix était-elle encombrée ? Les serveurs de Netflix ramaient-ils ? C'est très difficile à dire, et cela dépend de beaucoup de choses (par exemple, deux utilisateurs de Netflix ne tombent pas forcément sur le même serveur chez Netflix et peuvent donc avoir des vécus différents). Et puis, globalement, on manque de capacités d'observation sur l'Internet. Le client ne voit pas ce qui se passe sur le serveur, le serveur ne sait pas grand'chose sur le client, et peut-être qu'aucun des deux n'a pas visibilité sur l'interconnexion. Chacun connait bien son réseau, mais personne ne connait l'Internet dans son ensemble. Le RFC note que, paradoxalement, la Covid-19 a amélioré les choses, en augmentant le niveau de coopération entre les acteurs de l'Internet.

Et la sécurité ? Elle a aussi été discutée à l'atelier car le passage brusque de tant de gens au télétravail a changé le paysage de la sécurité. On ne pouvait plus compter sur le pare-feu corporate et sur les machines du bureau soigneusement verrouillées par la DSI. Au lieu de cela, tout le monde utilisait des VPN pas toujours bien maitrisés (cf. l'article « IAB COVID-19 Network Impacts »). Et la pandémie a été l'occasion de nombreuses escroqueries (décrites dans le même article). À propos de sécurité, le RFC en profite pour vanter les résolveurs DNS menteurs et critiquer DoH (qui n'est pour rien dans ces escroqueries).

En conclusion, le RFC note que le bon fonctionnement de l'Internet pendant la pandémie n'était pas dû uniquement à ses qualités intrinsèques, mais aussi à l'action de nombreux acteurs. Comme d'autres professions, les techniciens et techniciennes de l'Internet étaient une des lignes de défense face à l'épidémie et cette ligne était très motivée, et a tenu. Ces techniciennes et techniciens méritent donc de chaudes félicitations. Mais on peut quand même améliorer les choses :

  • En continuant à étudier le fonctionnement de l'Internet. Le caractère critique de l'Internet pour tant d'activités humaines justifie qu'on continue à analyser ses caractéristiques et ses faiblesses.
  • Le partage d'informations et la communication sont essentiels et doivent être accrus.
  • La lutte contre la fracture numérique doit se poursuivre, puisqu'en période de confinement, être coupé du réseau, ou y accéder dans de mauvaises conditions (accès lent, matériel inadapté, manque de littératie numérique), aggrave encore l'isolement.

Et le RFC se conclut par un bilan de cet atelier qui, contrairement aux ateliers précédents de l'IAB, a été fait entièrement en ligne. Les participants ont été plutôt contents, notamment du fait que le travail à distance a permis de changer le format : au lieu de deux jours complets de discussions, l'atelier a pu se tenir en alternant des moments de discussion et du travail chez soi, pour approfondir et critiquer les discussions. Toutefois, le RFC note que cela a bien marché car la quasi-totalité des présents se connaissaient bien, étant des participants de longue date à l'IETF. Il n'est pas du tout évident que cela aurait aussi bien marché avec des gens nouveaux, le présentiel étant crucial pour créer des liens informels.

L'ensemble des articles écrits par les participants à l'atelier (pour participer, il fallait avoir écrit un texte) est disponible en ligne (en bas de la page).


Téléchargez le RFC 9075


L'article seul

Les problèmes gris dans les réseaux informatiques

Première rédaction de cet article le 21 juillet 2021


Une passionnante discussion sur la liste NANOG vient de porter sur les « problèmes gris ». Qu'est-ce qu'un problème gris en matière de réseaux informatiques ?

Les réseaux ne sont pas fiables, toute personne qui a déjà vu un message « Connection time out » peut en témoigner. De l'erreur de configuration chez un opérateur à l'attaque d'une pelleteuse sur une fibre, en passant par une bogue dans les routeurs, les causes de panne ne manquent pas. Ces pannes sont typiquement binaires : soit toutes les communications passent, soit aucune ne passe. À défaut d'être faciles à prévenir, ou même à réparer, ces pannes sont triviales à détecter : la supervision couine et les utilisateurs râlent. Mais il y a aussi des pannes « grises ». C'est quand ça déconne mais pas de manière binaire : la grande majorité du trafic passe (et on peut donc ne s'apercevoir de rien) mais le problème gris frappe une petite minorité des paquets, selon des critères qui ne sont pas évidents à première vue. Par exemple, le réseau laisse passer tous les paquets, sauf ceux qui ont telle combinaison d'options. Ou bien il laisse passer 99,99 % des paquets mais jette les autres (en dehors du cas de congestion, où il est normal de jeter les paquets). Dans la discussion sur NANOG, un ingénieur citait un cas qu'il avait rencontré où une line card défaillante jetait tous les paquets IPv6 où le 65e bit de l'adresse de destination était à 1 (ce qui est apparemment assez rare). Le terme a été utilisé dans d'autres contextes que le réseau (par exemple cette étude de Microsoft).

La discussion sur la liste NANOG avait été lancée dans le contexte d'une étude de l'École polytechnique de Zurich, étude qui commençait par un sondage auprès des opérateurs pour leur demander s'ils géraient les problèmes gris et comment.

D'abord, une constatation peu originale mais qu'il est important de rappeler. Même en dehors de la congestion, aucun réseau ne transporte 100 % des paquets. Il y a toujours des problèmes, les réseaux étant des objets physiques, soumis aux lois de la physique et aux perturbations diverses (comme les rayons cosmiques). Aucune machine n'est idéale, l'électronique n'est pas virtuelle et est donc imparfaite, la mémoire d'un routeur ne garde pas forcément intact ce qu'on lui a confié. Et, non, FCS et ECC ne détectent pas tous les problèmes. Comme le notait un observateur : « De ma longue expérience, j'en ai tiré une analyse (très pertinente) : en informatique il y a entre 1 % et 2 % de magie. C'est faux, mais ça soulage parfois de se dire qu'on est peut être la cible d'un sortilège vaudou ou sous la coupe d'une bonne fée. » Si un opérateur prétendait sincèrement ne pas avoir de problèmes gris, cela indiquerait une absence de recherche plutôt qu'une absence de problème. Fermer les yeux permet de dormir mieux :-)

Les problèmes gris sont très difficiles à détecter. Supposons que, comme tout bon ingénieur, vous avez un système de supervision automatique qui fonctionne, mettons, en envoyant des messages ICMP de type Echo et en attendant une réponse. Si vous envoyez trois paquets par test, et que le réseau jette 1 % des paquets (un chiffre très élevé) au hasard, vous n'avez qu'une chance sur un demi-million de détecter le problème. Bien sûr, on ne se contente pas de ce genre de tests. On regarde par exemple les compteurs attachés aux interfaces des routeurs et on regarde si les compteurs d'erreur grimpent. Mais si c'est l'électronique des routeurs qui est défaillante, les compteurs ne seront pas fiables.

Les problèmes gris sont parfois déterministes (comme dans l'exemple du bit 65 plus haut) mais pas toujours et, s'ils ne sont pas reproductibles, le problème est encore pire. Même s'ils sont déterministes, l'algorithme n'est pas forcément évident. Si les paquets sont aiguillés à l'intérieur d'un équipement selon des critères complexes, et qu'un seul des circuits est défaillant, vous ne trouverez pas forcément tout de suite pourquoi, des fois, ça passe et, des fois, ça ne passe pas.

Est-ce grave pour l'opérateur ? Dans la discussion sur NANOG, un participant a dit franchement que les problèmes gris étaient fréquents mais tellement difficiles à traiter (par exemple parce qu'ils impliquent souvent de longues et difficiles négociations avec les vendeurs de matériel) qu'il valait mieux les ignorer, sauf si un client râlait. Mais, justement, le client ne râle pas toujours si le problème est rare, et difficile à pointer du doigt avec précision. Et puis les systèmes modernes comportent tellement de couches superposées que le client a le plus grand mal à trouver l'origine d'un problème. Ainsi, dans le cas d'un problème spécifique à IPv6, comme celui cité plus haut, le fait que le navigateur Web typique se rabatte automatiquement et rapidement en IPv4 n'aide pas au diagnostic (même si c'est certainement mieux pour le bonheur de l'utilisateur).

Pour donner une idée de la subtilité des problèmes gris, un participant à NANOG citait un cas d'un commutateur qui perdait 0,00012 % des paquets, un nombre difficile à repérer au milieu des erreurs de mesure. Le problème avait été détecté lors du remplacement des anciens tests (genre les trois messages ICMP cités plus haut) par des tests plus violents.

Bref, quand vous (enfin, votre navigateur Web) avez récupéré cet article, peut-être un problème gris a-t-il perturbé cette récupération. Peut-être n'a-t-il même pas été détecté et le texte que vous lisez n'est pas le bon…


L'article seul

RFC 9065: Considerations around Transport Header Confidentiality, Network Operations, and the Evolution of Internet Transport Protocols

Date de publication du RFC : Juillet 2021
Auteur(s) du RFC : G. Fairhurst (University of Aberdeen), C. Perkins (University of Glasgow)
Pour information
Réalisé dans le cadre du groupe de travail IETF tsvwg
Première rédaction de cet article le 20 juillet 2021


La couche Transport n'est pas celle qui suscite le plus de passions dans l'Internet. Mais la récente normalisation du protocole QUIC a mis cette couche en avant et l'usage du chiffrement par QUIC a relancé le débat : quelles sont les conséquences d'un chiffrement de plus en plus poussé de la couche Transport ?

Traditionnellement, la couche Transport ne faisait pas de chiffrement (cf. RFC 8095 et RFC 8922). On chiffrait en-dessous (IPsec) ou au-dessus (TLS, SSH). IPsec ayant été peu déployé, l'essentiel du chiffrement aujourd'hui sur l'Internet est fait par TLS. Toute la mécanique TCP est donc visible aux routeurs sur le réseau. Ils peuvent ainsi mesurer le RTT, découvrir début et fin d'une connexion, et interférer avec celle-ci, par exemple en envoyant des paquets RST (ReSeT) pour mettre fin à la session. Cela permet de violer la vie privée (RFC 6973), par exemple en identifiant une personne à partir de son activité en ligne. Et cette visibilité de la couche Transport pousse à l'ossification : de nombreux intermédiaires examinent TCP et, si des options inhabituelles sont utilisées, bloquent les paquets. Pour éviter cela, QUIC chiffre une grande partie de la couche 4, pour éviter les interférences par les intermédiaires et pour défendre le principe de bout en bout et la neutralité du réseau. Comme souvent en sécurité, cette bonne mesure de protection a aussi des inconvénients, que ce RFC examine. Notons tout de suite que ce qui est un inconvénient pour les uns ne l'est pas forcément pour les autres : pour un FAI, ne pas pouvoir couper les connexions TCP de BitTorrent avec RST est un inconvénient mais, pour l'utilisateur, c'est un avantage, cela le protège contre certaines attaques par déni de service.

On ne peut pas sérieusement aujourd'hui utiliser des communications non-chiffrées (RFC 7258). Personne n'ose dire publiquement le contraire. Par contre, on entend souvent un discours « je suis pour le chiffrement, mais » et, comme toujours avec ce genre de phrase, c'est ce qui est après le « mais » qui compte. Ce RFC essaie de documenter les avantages et les inconvénients du chiffrement de la couche Transport, mais, en pratique, est plus détaillé sur les inconvénients, ce qui était déjà le cas du RFC 8404.

La section 2 du RFC explique quel usage peut être fait des informations de la couche Transport par les équipements intermédiaires. En théorie, dans un modèle en couches idéal, il n'y en aurait aucun : la couche Transport est de bout en bout, les routeurs et autres équipements intermédiaires ne regardent rien au-dessus de la couche Réseau. Mais en pratique, ce n'est pas le cas, comme l'explique cette section. (Question pour mes lecteurices au passage : vous semble-t-il légitime de parler de DPI quand un routeur regarde le contenu de la couche Transport, dont il n'a en théorie pas besoin, ou bien doit-on réserver ce terme aux cas où il regarde dans la couche Application ?)

Première utilisation de la couche Transport par des intermédiaires : identifier des flots de données (une suite d'octets qui « vont ensemble »). Pourquoi en a-t-on besoin ? Il y a plusieurs raisons possibles, par exemple pour la répartition de charge, où on veut envoyer tous les paquets d'un flot donné au même serveur. Cela se fait souvent en prenant un tuple d'informations dans le paquet (tuple qui peut inclure une partie de la couche Transport, comme les ports source et destination) et en le condensant pour avoir un identificateur du flot. Si la couche Transport est partiellement ou totalement chiffrée, on ne pourra pas distinguer deux flots différents entre deux machines. En IPv6, l'étiquette de flot (RFC 6437) est une solution possible (RFC 6438, RFC 7098), mais je n'ai pas l'impression qu'elle soit très utilisée.

Maintenant, passons à la question de l'identification d'un flot. Était-ce un transfert de fichiers, de la vidéo, une session interactive ? Il faut déduire cette identification à partir des informations de la couche Transport (voir le RFC 8558). Mais pourquoi identifier ces flots alors que l'opérateur doit tous les traiter pareil, en application du principe de neutralité ? Cela peut être dans l'intérêt de l'utilisateur (mais le RFC ne donne pas d'exemple…) ou bien contre lui, par exemple à des fins de surveillance, ou bien pour discriminer certains usages (comme le réclament régulièrement certains politiciens et certains opérateurs), voire pour les bloquer complètement. Autrefois, on pouvait souvent identifier un service uniquement avec le numéro de port (43 pour whois, 25 pour le courrier, etc, cf. RFC 7605) mais cela n'a jamais marché parfaitement, plusieurs services pouvant utiliser le même port et un même service pouvant utiliser divers ports. De toute façon, cette identification par le numéro de port est maintenant finie, en partie justement en raison de cette discrimination selon les usages, qui pousse tout le monde à tout faire passer sur le port 443. Certains services ont un moyen simple d'être identifié, par exemple par un nombre magique, volontairement placé dans les données pour permettre l'identification, ou bien simple conséquence d'une donnée fixe à un endroit connu (RFC 3261, RFC 8837, RFC 7983…). Lors de la normalisation de QUIC, un débat avait eu lieu sur la pertinence d'un nombre magique permettant d'identifier du QUIC, idée finalement abandonnée.

Si les équipements intermédiaires indiscrets n'arrivent pas à déterminer le service utilisé, le flot va être considéré comme inconnu et le RFC reconnait que certains opérateurs, en violation de la neutralité de l'Internet, ralentissent ces flots inconnus.

L'étape suivante pour ceux qui veulent identifier à quoi servent les données qu'ils voient passer est d'utiliser des heuristiques. Ainsi, une visio-conférence à deux fera sans doute passer à peu près autant d'octets dans chaque sens, alors que regarder de la vidéo à la demande créera un trafic très asymétrique. Des petits paquets UDP régulièrement espacés permettent de soupçonner du trafic audio, même si on n'a pas pu lire l'information SDP (RFC 4566). Des heuristiques plus subtiles peuvent permettre d'en savoir plus. Donc, il faut se rappeler que le chiffrement ne dissimule pas tout, il reste une vue qui peut être plus ou moins précise (le RFC 8546 décrit en détail cette notion de vue depuis le réseau).

Autre motivation pour analyser la couche Transport, l'amélioration des performances. Inutile de dire que le FAI typique ne va pas se pencher sur les problèmes de performance d'un abonné individuel (si ça rame avec Netflix, appeler le support de son FAI ne déclenche pas de recherches sérieuses). Mais cela peut être fait pour des analyse globales. Là encore, les conséquences peuvent être dans l'intérêt de l'utilisateur, ou bien contre lui. Le RFC note que les mesures de performance peuvent amener à une discrimination de certains services (« QoS », qualité de service, c'est-à-dire dégradation de certains services). Que peut-on mesurer ainsi, qui a un impact sur les performances ? Il y a la perte de paquets, qu'on peut déduire, en TCP, des retransmissions. Dans l'Internet, il y a de nombreuses causes de pertes de paquets, du parasite sur un lien radio à l'abandon délibéré par un routeur surchargé (RFC 7567) en passant par des choix politiques de défavoriser certains paquets (RFC 2475). L'étude de ces pertes peut permettre dans certains cas de remonter aux causes.

On peut aussi mesurer le débit. Bon, c'est facile, sans la couche Transport, uniquement en regardant le nombre d'octets qui passent par les interfaces réseaux. Mais l'accès aux données de la couche Transport permet de séparer le débit total du débit utile (goodput, en anglais, pour le différencier du débit brut, le throughput, cf. section 2.5 du RFC 7928, et le RFC 5166). Pour connaitre ce débit utile, il faut pouvoir reconnaitre les retransmissions (si un paquet est émis trois fois avant enfin d'atteindre le destinataire, il ne contribue qu'une fois au débit utile). Une retransmission peut se voir en observant les numéros de séquence en TCP (ou dans d'autres protocoles comme RTP).

La couche Transport peut aussi nous dire quelle est la latence. Cette information est cruciale pour évaluer la qualité des sessions interactives, par exemple. Et elle influe beaucoup sur les calculs du protocole de couche 4. (Voir l'article « Internet Latency: A Survey of Techniques and their Merits ».) Comment mesure-t-on la latence ? Le plus simple est de regarder les accusés de réception TCP et d'en déduire le RTT. Cela impose d'avoir accès aux numéros de séquence. Dans TCP, ils sont en clair, mais QUIC les chiffre (d'où l'ajout du spin bit).

D'autres métriques sont accessibles à un observateur qui regarde la couche Transport. C'est le cas de la gigue, qui se déduit des observations de la latence, ou du réordonnancement des paquets (un paquet qui part après un autre, mais arrive avant). L'interprétation de toutes ces mesures dépend évidemment du type de lien. Un lien radio (RFC 8462) a un comportement différent d'un lien filaire (par exemple, une perte de paquets n'est pas forcément due à la congestion, elle peut venir de parasites).

Le RFC note que la couche Réseau, que les équipements intermédiaires ont tout à fait le droit de lire, c'est son rôle, porte parfois des informations qui peuvent être utiles. En IPv4, ce sont les options dans l'en-tête (malheureusement souvent jetées par des pare-feux trop fascistes, cf. RFC 7126), en IPv6, les options sont après l'en-tête de réseau, et une option, Hop-by-hop option est explicitement prévue pour être examinée par tous les routeurs intermédiaires.

Outre les statistiques, l'analyse des données de la couche Transport peut aussi servir pour les opérations (voir aussi le RFC 8517), pour localiser un problème, pour planifier l'avitaillement de nouvelles ressources réseau, pour vérifier qu'il n'y a pas de tricheurs qui essaient de grapiller une part plus importante de la capacité, au risque d'aggraver la congestion (RFC 2914). En effet, le bon fonctionnement de l'Internet dépend de chaque machine terminale. En cas de perte de paquets, signal probable de congestion, les machines terminales sont censées réémettre les paquets avec prudence, puisque les ressources réseau sont partagées. Mais une machine égoïste pourrait avoir plus que sa part de la capacité. Il peut donc être utile de surveiller ce qui se passe, afin d'attraper d'éventuels tricheurs, par exemple une mise en œuvre de TCP qui ne suivrait pas les règles habituelles. (Si on utilise UDP, l'application doit faire cela elle-même, cf. RFC 8085. Ainsi, pour RTP, comme pour TCP, un observateur extérieur peut savoir si les machines se comportent normalement ou bien essaient de tricher.)

Autre utilisation de l'observation de la couche Transport pour l'opérationnel, la sécurité, par exemple la lutte contre les attaques par déni de service, l'IDS et autres fonctions. Le RFC note que cela peut se faire en coopération avec les machines terminales, si c'est fait dans l'intérêt de l'utilisateur. Puisqu'on parle de machines terminales, puisque le chiffrement d'une partie de la couche Transport est susceptible d'affecter toutes les activités citées plus haut, le RFC rappelle la solution évidente : demander la coopération des machines terminales. Il y a en effet deux cas : soit les activités d'observation de la couche Transport sont dans l'intérêt des utilisateurs, et faites avec leur consentement, et dans ce cas la machine de l'utilisateur peut certainement coopérer, soit ces activités se font contre l'utilisateur (discrimination contre une application qu'il utilise, par exemple), et dans ce cas le chiffrement est une réponse logique à cette attaque. Bien sûr, c'est la théorie ; en pratique, certaines applications ne fournissent guère d'informations et de moyens de déboguage. Les protocoles de transport qui chiffrent une bonne partie de leur fonctionnement peuvent aussi aider, en exposant délibérement des informations. C'est par exemple ce que fait QUIC avec son spin bit déjà cité, ou avec ses invariants documentés dans le RFC 8999.

Autre cas où le chiffrement de la couche Transport peut interférer avec certains usages, les réseaux d'objets contraints, disposant de peu de ressources (faible processeur, batterie qu'il ne faut pas vider trop vite, etc). Il arrive dans ce cas d'utiliser des relais qui interceptent la communication, bricolent dans la couche Transport puis retransmettent les données. Un exemple d'un tel bricolage est la compression des en-têtes, courante sur les liens à très faible capacité (cf. RFC 2507, RFC 2508, le ROHC du RFC 5795, RFC 6846, le SCHC du RFC 8724, etc). Le chiffrement rend évidemment cela difficile, les relais n'ayant plus accès à l'information. C'est par exemple pour cela que le RTP sécurisé du RFC 3711 authentifie l'en-tête mais ne le chiffre pas. (Je suis un peu sceptique sur cet argument : d'une part, les objets contraints ne vont pas forcément utiliser des protocoles de transport chiffrés, qui peuvent être coûteux, d'autre part un sous-produit du chiffrement est souvent la compression, ce qui rend inutile le travail des relais.)

Un dernier cas cité par le RFC où l'observation du fonctionnement de la couche Transport par les machines intermédiaires est utile est celui de la vérification de SLA. Si un contrat ou un texte légal prévoit certaines caractéristiques pour le réseau, l'observation de la couche 4 (retransmission, RTT…) est un moyen d'observer sans avoir besoin d'impliquer les machines terminales. (Personnellement, je pense justement que ces vérifications devraient plutôt se faire depuis les machines terminales, par exemple avec les sondes RIPE Atlas, les SamKnows, etc.)

La section 3 du RFC décrit un autre secteur qui est intéressé par l'accès aux données de transport, la recherche. Par exemple, concevoir de nouveaux protocoles doit s'appuyer sur des mesures faites sur les protocoles existants, pour comprendre leurs forces et leurs faiblesses. C'est possible avec un protocole comme TCP, où l'observation passive permet, via notamment les numéros de séquence, de découvrir le RTT et le taux de perte de paquets. (Passive : sans injecter de paquets dans le réseau. Voir le RFC 7799.) Mais ces mêmes informations peuvent aussi servir contre l'utilisateur. Même s'il n'y a pas d'intention néfaste (par exemple de discrimination contre certains usages), toute information qui est exposée peut conduire à l'ossification, l'impossibilité de changer le protocole dans le futur. Une des motivations des protocoles chiffrés comme QUIC est en effet d'éviter l'ossification : une middlebox ne pourra pas prendre de décisions sur la base d'informations qu'elle n'a pas. QUIC affiche des données au réseau seulement s'il le veut (c'est le cas du spin bit). D'où également le choix délibéré de graisser, c'est-à-dire de faire varier certaines informations pour éviter que des programmeurs de middleboxes incompétents et/ou paresseux n'en déduisent que cette information ne change jamais (le graissage est décrit dans le RFC 8701).

La bonne solution pour récolter des données sans sacrifier la vie privée est, comme dit plus haut, de faire participer les extrémités, les machines terminales, ce qu'on nomme en anglais le endpoint-based logging. Actuellement, malheureusement, les mécanismes de déboguage ou de récolte d'information sur ces machines terminales sont trop réduits, mais des efforts sont en cours. Par exemple, pour QUIC, c'est la normalisation du format « qlog » d'enregistrement des informations vues par la couche Transport (Internet-Draft draft-ietf-quic-qlog-main-schem) ou bien le format Quic-Trace. Mais le RFC note que la participation des machines terminales ne suffit pas toujours, notamment si on veut déterminer , dans le réseau, se produit un problème.

Après qu'on ait vu les utilisations qui sont faites de l'analyse de la couche Trnsport par les équipements intermédiaires, la section 4 du RFC revient ensuite sur les motivations du chiffrement de cette couche. Pourquoi ne pas se contenter de ce que font TLS et SSH, qui chiffrent uniquement la couche Application ? L'une des premières raisons est d'empêcher l'ossification, ce phénomène qui fait qu'on ne peut plus faire évoluer la couche Transport car de stupides équipements intermédiaires, programmés avec les pieds par des ignorants qui ne lisent pas les RFC, rejettent les paquets légaux mais qui ne correspondent pas à ce que ces équipements attendaient. Ainsi, si un protocole de transport permet l'utilisation d'un octet dans l'en-tête, mais que cet octet est à zéro la plupart du temps, on risque de voir des middleboxes qui jettent les paquets où certains bits de ce champ sont à un car « ce n'est pas normal ». Tout ce qui est observable risque de devenir ossifié, ne pouvant plus être modifié par la suite. Chiffrer permet de garantir que les équipements intermédiaires ne vont pas regarder ce qui ne les regarde pas. Le RFC donne plusieurs exemples édifiants des incroyables comportements de ces logiciels écrits par des gens qui ne comprenaient qu'une partie d'un protocole :

  • Pendant le développement de TLS 1.3 (qui mènera au RFC 8446), il a fallu concevoir 1.3 de manière à ce qu'il ressemble à 1.2, car certaines middleboxes rejettaient du TLS légal, mais différent de ce qu'elles attendaient.
  • MPTCP (RFC 8684) a également dû être modifié pour tenir compte de boitiers intermédiaires qui observaient le fonctionnement de la fenêtre TCP et se permettaient de couper les connexions qui leur semblaient anormales.
  • D'une manière générale, tout protocole qui permet des options est confronté à des middleboxes qui interfèrent dès qu'on utilise des options nouvelles. C'est le cas par exemple de TCP Fast Open (RFC 7413).
  • Encore pire, si c'est possible, on a vu des équipements intermédiaires qui changeaient les numéros de séquence TCP, ce qui cassait les accusés de réception SACK (RFC 2018).

Il n'est donc pas étonnant que les concepteurs de protocole cherchent désormais à chiffrer au maximum, pour éviter ces interférences. Le RFC 8546 rappelle ainsi que c'est la vue depuis le réseau (wire image), c'est-à-dire ce que les équipements intermédiaires peuvent observer, pas la spécification écrite du protocole, qui détermine, dans le monde réel, ce qu'un intermédiaire peut observer et modifier. Il faut donc réduire cette vue au strict minimum ; tout ce qui n'est pas chiffré risque fortement d'être ossifié, figé. Et le RFC 8558 affirme lui qu'on ne doit montrer au réseau que ce qui doit être utilisé par le réseau, le reste, qui ne le regarde pas, doit être dissimulé.

Une autre motivation du chiffrement de la couche Transport est évidemment de mieux protéger la vie privée (RFC 6973). L'ampleur de la surveillance massive (RFC 7624) est telle qu'il est crucial de gêner cette surveillance le plus possible. Le RFC note qu'il n'y a pas que la surveillance passive, il y a aussi l'ajout de données dans le trafic, pour faciliter la surveillance. Du fait de cet « enrichissement », il peut être utile, quand un champ doit être observable (l'adresse IP de destination est un bon exemple), d'utiliser quand même la cryptographie pour empêcher ses modifications, via un mécanisme d'authentification. C'est ce que fait TCP-AO (RFC 5925, mais qui semble peu déployé), et bien sûr le service AH d'IPsec (RFC 4302).

Comme on le voit, il y a une tension, voire une lutte, entre les opérateurs réseau et les utilisateurs. On pourrait se dire que c'est dommage, qu'il vaudrait mieux que tout le monde travaille ensemble. Cela a été discuté à l'IETF, avec des expressions comme « un traité de paix entre machines terminales et boitiers intermédiaires ». Pour l'instant, cela n'a pas débouché sur des résultats concrets, en partie parce qu'il n'existe pas d'organisations représentatives qui pourraient négocier, signer et faire respecter un tel traité de paix. On en reste donc aux mesures unilatérales. Les machines terminales doivent chiffrer de plus en plus pour maintenir le principe de bout en bout. Comme dans tout conflit, il y a des dégâts collatéraux (le RFC 8922 en décrit certains). Le problème n'étant pas technique mais politique, il est probable qu'il va encore durer. La tendance va donc rester à chiffrer de plus en plus de choses.

À noter qu'une autre méthode que le chiffrement existe pour taper sur les doigts des boitiers intermédiaires pénibles, qui se mêlent de ce qui ne les regarde pas, et s'en mêlent mal : c'est le graissage. Son principe est d'utiliser délibérément toutes les options possibles du protocole, pour habituer les middleboxes à voir ces variations. Le RFC 8701 en donne un exemple, pour le cas de TLS.

Déterminer ce qu'il faut chiffrer, ce qu'il faut authentifier, et ce qu'il vaut mieux laisser sans protection, autorisant l'observation et les modifications, n'est pas une tâche facile. Autrefois, tout était exposé parce qu'on avait moins de problèmes avec les boitiers intermédiaires et que les solutions, comme le chiffrement, semblaient trop lourdes. Aujourd'hui qu'on a des solutions réalistes, on doit donc choisir ce qu'on montre ou pas. Le choix est donc désormais explicite (cf. RFC 8558).

Au passage, une façon possible d'exposer des informations qui peuvent être utiles aux engins intermédiaires est via un en-tête d'extension. Par exemple en IPv6, l'en-tête Hop-by-hop (RFC 8200, section 4.3) est justement fait pour cela (voir un exemple dans le RFC 8250, quoiqu'avec un autre type d'en-tête). Toutefois, cet en-tête Hop-by-hop est clairement un échec : beaucoup de routeurs jettent les paquets qui le portent (RFC 7872), ou bien les traitent plus lentement que les paquets sans cette information. C'est encore pire si cet en-tête porte des nouvelles options, inconnues de certaines middleboxes, et c'est pour cela que le RFC 8200 déconseille (dans sa section 4.8) la création de nouvelles options Hop-by-hop.

Mais, bon, le plus important est de décider quoi montrer, pas juste comment. Le RFC rappelle qu'il serait sympa d'exposer explicitement des informations comme le RTT ou le taux de pertes vu par les machines terminales, plutôt que de laisser les machines intermédiaires le calculer (ce qu'elles ne peuvent de toute façon plus faire en cas de chiffrement). Cela permettrait de découpler l'information de haut niveau des détails du format d'un protocole de transport. Pourquoi une machine terminale ferait-elle cela, au risque d'exposer des informations qu'on peut considérer comme privées ? Le RFC cite la possibilité d'obtenir un meilleur service, sans trop préciser s'il s'agit de laisser les opérateurs offrir un traitement préférentiel aux paquets portant cette information, ou bien si c'est dans l'espoir que l'information exposée serve à l'opérateur pour améliorer son réseau. (Comme le note le RFC 8558, il y a aussi le risque que la machine terminale mente au réseau. Au moins, avec le chiffrement, les choses sont claires : « je refuse de donner cette information » est honnête.)

Dernière note, cet ajout d'informations utiles pour l'OAM peut être faite par la machine terminale mais aussi (section 6 du RFC) par certains équipements intermédiaires.

En conclusion ? La section 7 du RFC reprend et résume les points importants :

  • Le chiffrement et l'authentification dans la couche de Transport sont une bonne chose. Personne n'ose dire ouvertement qu'il faudrait rester à des protocoles de transport non sécurisés. C'est un point sur lequel le document a beaucoup évolué. Dans les versions antérieures, comme le notait Christian Huitema, « Much of the draft reads like a lamentation of the horrible consequences of encrypting transport headers », reflétant unilatéralement le point de vue des opérateurs réseau, et des vendeurs de middleboxes. Une relecture par Christopher Wood au début du projet avait déjà pointé ce problème, notant que le document était très anti-chiffrement. Cette question a, fort logiquement, été le principal point de discussion à l'IETF.
  • Le RFC, officiellement, ne tranche pas sur la pertinence et l'éthique des pratiques qu'il décrit, il explique juste ce qui se fait. (Le même argument, que je trouve un peu hypocrite, avait été utilisé pour le très contestable RFC 8404.)
  • Comme souvent en sécurité, il n'y a pas de solution idéale, il faudra trouver un compromis, par exemple entre la vie privée et l'OAM. Le RFC cite le spin bit de QUIC, qui avait été très chaudement discuté, comme un exemple de compromis, en tout cas par le sérieux de l'analyse de ses coûts et de ses bénéfices.
  • Le RFC reconnait que tout ce qui est exposé au réseau s'ossifiera et deviendra une spécification de fait, qu'on ne pourra plus changer. Qu'un protocole choisisse d'exposer beaucoup ou au contraire très peu, il doit de toute façon faire ce choix explicitement.
  • Même le chiffrement de la couche Transport ne cache pas tout, et les couches inférieures exposent toujours des métadonnées. Un surveillant déterminé n'est donc pas désarmé. (Même si des organisations comme Interpol prétendent que le chiffrement rend la police « aveugle ».)
  • Les opérationnels se sont habitués depuis longtemps à disposer de certaines informations, que le chiffrement de la couche Transport peut rendre inutilisables. Il faudra donc changer certaines pratiques et certains outils, par exemple avec davantage de coopération des machines terminales (sinon, les opérations seront affectées).
  • Le RFC rappelle aussi qu'il existe différents types de réseaux, et qui n'ont pas forcément les mêmes contraintes et les mêmes buts. Entre le réseau d'une entreprise qui veut contrôler tout ce que font les employés et le réseau d'un FAI qui doit respecter (en théorie…) le principe de neutralité, il n'est pas du tout sûr qu'on puisse trouver des solutions qui plaisent à tout le monde. (A priori, l'IETF travaille et normalise pour l'Internet ouvert, pas forcément pour chaque réseau connecté à l'Internet avec ses règles spécifiques.)
  • L'Internet est un réseau partagé et son bon fonctionnement dépend donc du respect de certaines règles par tous. Par exemple, un protocole de transport doit penser aux autres, en ne noyant pas le réseau sous les paquets de retransmission. Si un fournisseur de logiciels était tenté de développer un protocole de transport égoïste, qui tente d'obtenir plus que sa part de la capacité du réseau, la tricherie pourrait se détecter en observant le fonctionnement de ce protocole. Le chiffrement de la couche Transport rend évidemment la vérification plus complexe.
  • Le bon fonctionnement de l'Internet sur le long terme dépend également d'une activité de recherche et développement, qui s'appuie sur des mesures, que le chiffrement de la couche Transport peut gêner. (C'est bien, de se préoccuper des chercheurs.)

Téléchargez le RFC 9065


L'article seul

RFC 8984: JSCalendar: A JSON Representation of Calendar Data

Date de publication du RFC : Juillet 2021
Auteur(s) du RFC : N. Jenkins, R. Stepanek (Fastmail)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF calext
Première rédaction de cet article le 20 juillet 2021


Beaucoup d'applications gèrent des agendas, avec des réunions à ne pas oublier, des évènements récurrents, des rendez-vous précis. Le format traditionnel d'échange de ces applications est iCalendar, normalisé dans le RFC 5545 (ou, dans sa déclinaison en JSON, jCal, dans le RFC 7265). Ce RFC propose une syntaxe JSON mais, surtout, un modèle de données très différent, JSCalendar. Le but est de remplacer iCalendar.

Les principes de base ? Simplicité (au moins dans les cas simples, car les calendriers sont des bêtes compliquées…), uniformité (autant que possible, une seule façon de représenter un évènement), tout en essayant de permettre des conversions depuis iCalendar (RFC 5545 et RFC 7986), donc en ayant un modèle de données compatible. JSCalendar, comme son nom l'indique, utilise JSON, plus exactement le sous-ensemble i-JSON, normalisé dans le RFC 7493.

Bon, mais pourquoi ne pas avoir gardé iCalendar ? Parce qu'il est trop complexe avec plusieurs formats de date, parce que ses règles de récurrence sont ambigües et difficiles à comprendre, parce que sa syntaxe est mal définie. jCal n'a pas ce dernier problème mais il garde tous les autres. On voit même des logiciels utiliser leur propre représentation en JSON des données iCalendar au lieu d'utiliser jCal. Bref, JSCalendar préfère repartir, sinon de zéro, du moins d'assez loin.

Voici un exemple très simple et très minimal de représentation d'un évènement en JSCalendar :

{
     "@type": "Event",
     "uid": "a8df6573-0474-496d-8496-033ad45d7fea",
     "updated": "2020-01-02T18:23:04Z",
     "title": "Some event",
     "start": "2020-01-15T13:00:00",
     "timeZone": "America/New_York",
     "duration": "PT1H"
}
  

Comme avec iCalendar, les données JSCalendar peuvent être échangées par courrier ou avec n'importe quel autre protocole de son choix comme JMAP ou WebDAV.

Avant d'attaquer ce format JSCalendar, rappelez-vous qu'il utilise JSON et que la terminologie est celle de JSON. Ainsi, on nomme « objet » ce qui, selon le langage utilisé, serait un dictionnaire ou un tableau associatif. Ensuite, outre les types de base de JSON, JSCalendar a des types supplémentaires (section 1), notamment :

  • Id, un identificateur, pour que les objets aient un nom simple et unique (c'est une chaîne de caractères JSON). On peut par exemple utiliser un UUID (RFC 4122). Dans l'exemple ci-dessus, le membre uid de l'objet est un Id.
  • UTCDateTime, une date-et-heure (un instant dans le temps) au format du RFC 3339 dans une chaîne de caractères JSON, est obligatoirement en UTC. Un tel type est intéressant pour les évènements internationaux comme une vidéoconférence. Dans l'exemple ci-dessus, le membre updated est de ce type.
  • LocalDateTime, une date-et-heure selon le fuseau horaire local. Un tel type est utile pour les évènements locaux, comme un pique-nique. Dans l'exemple ci-dessus, qui concerne une réunion en présentiel, start est de ce type. On a besoin des deux types, à la fois parce que les évènements en distanciel et en présentiel n'ont pas les mêmes besoins, et aussi parce que le décalage entre les deux peut varier. Les calendriers, c'est compliqué et le RFC cite l'exemple de la LocalDateTime 2020-10-04T02:30:00 qui n'existe pas à Melbourne car le passage à l'heure d'été fait qu'on saute de 2h à 3h, mais qui peut apparaitre dans les calculs (start + une durée) ou bien si les règles de l'heure d'été changent.
  • Duration est une durée, exprimée comme en iCalendar (PT1H pour « une heure » dans l'exemple ci-dessus, ce serait P1Y pour une année). Gag : une journée (P1D) ne fait pas forcément 24 heures, par exemple si on passe à l'heure d'été pendant cette journée.
  • SignedDuration, une durée qui peut être négative.
  • TimeZoneId, un identifiant pour un fuseau horaire, pris dans la base de l'IANA, par exemple Europe/Paris.
  • PatchObject est un pointeur JSON (ces pointeurs sont normalisés dans le RFC 6901) qui permet de désigner un objet à modifier.
  • Relation est un objet, et plus un simple type scalaire comme les précédents. Il permet d'indiquer une relation entre deux objets, notamment vers un objet parent ou enfant..
  • Link est également une relation et donc un objet, mais vers le monde extérieur. Il a des propriétés comme href (dont la valeur est, comme vous vous en doutez, un URI) ou cid qui identifie le contenu vers lequel on pointe, dans la syntaxe du RFC 2392.

Les types de JSCalendar figurent dans un registre IANA, qu'on peut remplir avec la procédure « Examen par un expert » du RFC 8126.

Bien, maintenant que nous avons tous nos types, construisons des objets. Il y en a de trois types (section 2) :

  • Event (l'exemple ci-dessus, regardez sa propriété @type) est un évènement ponctuel, par exemple une réunion professionnelle ou une manifestation de rue. Il a une date-et-heure de départ, et une durée.
  • Task est une tâche à accomplir, elle peut avoir une date-et-heure limite et peut avoir une durée estimée.
  • Group est un groupe d'évènements JSCalendar.

JSCalendar n'a pas de règles de canonicalisation (normalisation) générales, car cela dépend trop de considérations sémantiques que le format ne peut pas connaitre. Par exemple, JSON permet des tableaux, et JSCalendar utilise cette possibilité mais, quand on veut décider si deux tableaux sont équivalents, doit-on tenir compte de l'ordre des éléments ([1, 2] == [2, 1]) ? Cela dépend de l'application et JSCalendar ne fixe donc pas de règles pour ce cas. (Un cas rigolo et encore pire est celui des valeurs qui sont des URI puisque la canonicalisation des URI dépend du plan - scheme.)

Quelles sont les propriétés typiques des objets JSCalendar (section 4) ? On trouve notamment, communs aux trois types d'objets (évènement, tâche et groupe) :

  • @type, le type d'objet (Event dans l'exemple ci-dessus, un des trois types possibles).
  • uid (a8df6573-0474-496d-8496-033ad45d7fea dans l'exemple), l'identificateur de l'objet (il est recommandé que ce soit un des UUID du RFC 4122).
  • prodID, un identificateur du logiciel utilisé, un peu comme le User-Agent: de HTTP. Le RFC suggère d'utiliser un FPI.
  • updated, une date-et-heure de type UTCDateTime.
  • title et description, des chaînes de caractères utiles.
  • locations (notez le S) qui désigne les lieux physiques de l'évènement. C'est compliqué. Chaque lieu est un objet de type Location qui a comme propriétés possibles un type (tiré du registre des types de lieux créé par le RFC 4589), et une localisation sous forme de latitude et longitude (RFC 5870).
  • Tous les évènements ne sont pas dans le monde physique, certains se produisent en ligne, d'où le virtualLocations, qui indique des informations comme l'URI (via la propriété du même nom). Ainsi, une conférence en ligne organisée par l'assocation Parinux via BigBlueButton aura comme virtualLocations {"@type": "VirtualLocation", "uri": "https://bbb.parinux.org/b/ca--xgc-4r3-n8z", …}.
  • color permet de suggérer au logiciel une couleur à utiliser pour l'affichage, qui est une valeur RGB en hexadécimal ou bien un nom de couleur CSS.

Et je suis loin d'avoir cité toutes les propriétés possibles, sans compter celles spécifiques à un type d'objet.

Pour le cas de locations, le RFC fournit un exemple de vol international (quand il était encore possible de prendre l'avion) :

   {
     "...": "",
     "title": "Flight XY51 to Tokyo",
     "start": "2020-04-01T09:00:00",
     "timeZone": "Europe/Berlin",
     "duration": "PT10H30M",
     "locations": {
       "418d0b9b-b656-4b3c-909f-5b149ca779c9": {
         "@type": "Location",
         "rel": "start",
         "name": "Frankfurt Airport (FRA)"
       },
       "c2c7ac67-dc13-411e-a7d4-0780fb61fb08": {
         "@type": "Location",
         "rel": "end",
         "name": "Narita International Airport (NRT)",
         "timeZone": "Asia/Tokyo"
       }
     }
   }
  

Notez les UUID pour identifier les lieux, et le changement de fuseau horaire entre le départ et l'arrivée. Si l'évènement a lieu à la fois en présentiel et en distanciel (ici, le concert est dans un lieu physique identifié par ses coordonnées géographiques, mais aussi diffusé en ligne), cela peut donner :

{
  "...": "",
  "title": "Live from Music Bowl: The Band",
  "description": "Go see the biggest music event ever!",
  "locale": "en",
  "start": "2020-07-04T17:00:00",
  "timeZone": "America/New_York",
  "duration": "PT3H",
  "locations": {
    "c0503d30-8c50-4372-87b5-7657e8e0fedd": {
      "@type": "Location",
      "name": "The Music Bowl",
      "description": "Music Bowl, Central Park, New York",
      "coordinates": "geo:40.7829,-73.9654"
    }
  },
  "virtualLocations": {
    "1": {
      "@type": "VirtualLocation",
      "name": "Free live Stream from Music Bowl",
      "uri": "https://stream.example.com/the_band_2020"
    }
    },
    ...
  

Les fournisseurs de logiciel peuvent ajouter des propriétés définies par eux. Dans ce cas, le RFC recommande fortement qu'ils les nomment en les faisant précéder d'un nom de domaine identifiant le fournisseur. Si celui-ci a example.com et veut une propriété toto, il la nommera example.com:toto. C'est évidemment une solution temporaire, les fournisseurs ont tout intérêt à enregistrer ces propriétés pour qu'elles puissent servir à tout le monde. Le mécanisme d'enregistrement de nouvelles propriétés est « Examen par un expert » (RFC 8126) et les propriétés sont dans un registre IANA.

Passons maintenant à un aspect compliqué mais indispensable des calendriers : les règles de récurrence, comme « Réunion de service tous les premiers lundis du mois à 10 h, sauf jour férié ». Il est important de maintenir ces évènements récurrents sous forme de règles, et de ne pas de les instancier immédiatement, car l'application des règles peut donner des résultats différents dans le futur. JSCalendar permet une propriété recurrenceRules qui décrit ces règles de récurrence et évidemment une excludedRecurrenceRules car s'il n'y a pas d'exceptions, ce n'est pas drôle. Exprimer les règles n'est pas facile. L'idée est de spécifier la récurrence sous forme d'une série de règles, chacune indiquant une fréquence (annuelle, mensuelle, etc), à chaque fois à partir de la propriété start, le calendrier utilisé (qui doit être un des calendriers disponibles dans CLDR), la marche à suivre quand une règle produit une date invalide dans ce calendrier (annuler l'évènement, le mettre avant, le mettre après), et plein d'autres propriétés optionnelles comme le jour du mois (« réunion tous les 6 du mois »), de la semaine (« tous les mercredis »), etc. Il faut ensuite plusieurs pages au RFC pour expliquer la façon subtile dont les règles sont appliquées, et se combinent. Les exceptions de la excludedRecurrenceRules fonctionnent de la même façon, et sont ensuite soustraites des dates-et-heures sélectionnées par les règles.

Le RFC fournit cet exemple de récurrence : le premier avril arrive tous les ans (et dure une journée, notez le duration) :

    {
     "...": "",
     "title": "April Fool's Day",
     "showWithoutTime": true,
     "start": "1900-04-01T00:00:00",
     "duration": "P1D",
     "recurrenceRules": [{
       "@type": "RecurrenceRule",
       "frequency": "yearly"
     }]
   }
  

Alors qu'ici, on fait du yoga une demi-heure chaque jour à 7 h du matin :

   {
     "...": "",
     "title": "Yoga",
     "start": "2020-01-01T07:00:00",
     "duration": "PT30M",
     "recurrenceRules": [{
       "@type": "RecurrenceRule",
       "frequency": "daily"
     }]
   }
  

Bon, ensuite, quelques détails pour aider le logiciel à classer et présenter les évènements. Un évènement peut avoir des propriétés comme priority (s'il y a deux réunions en même temps, laquelle choisir ?), freeBusyStatus (est-ce que cet évènement fait que je doive être considéré comme occupé ou est-il compatible avec autre chose ?), privacy (cet évènement peut-il être affiché publiquement ?), participationStatus (je viendrai, je ne viendrai pas, je ne sais pas encore…), et plein d'autres encore.

Il y a aussi des propriétés concernant d'autres sujets, par exemple l'adaptation locale. Ainsi, la propriété localizations indique la ou les langues à utiliser (leur valeur est une étiquette de langue du RFC 5646).

Toutes les propriétés vues jusqu'à présent étaient possibles pour tous les types d'objets JSCalendar (évènement, tâche et groupe). D'autres propriétés sont spécifiques à un ou deux types :

  • Les évènements (Event) peuvent avoir entre autres un start (un LocalDateTime qui indique le début de l'évènement) et un duration (la durée de l'évènement).
  • Les tâches (Task) peuvent avoir un start mais aussi un due qui indique la date où elles doivent être terminées, et un percentComplete (pour les chefs de projet…).
  • Les groupes (Group) ont, par exemple, entries, qui indique les objets qui sont membres du groupe.

Les fichiers à ce format JSCalendar sont servis sur l'Internet avec le type application/jscalendar+json.

Pour terminer, voyons un peu la sécurité de JSCalendar (section 7). Évidemment, toutes les informations stockées dans un calendrier sont sensibles : rares sont les personnes qui accepteraient de voir la totalité de leur agenda être publiée ! Celui-ci permet en effet de connaitre le graphe social (les gens qu'on connait), les lieux où passe la personne, ses habitudes et horaires, bref, que des choses personnelles. Toute application qui manipule des données JSCalendar doit donc soigneusement veiller à la confidentialité de ces données, et doit les protéger.

Le risque d'accès en lecture n'est pas le seul, la modification non autorisée de l'agenda serait également un problème, elle pourrait permettre, par exemple, de faire déplacer une personne en un lieu donné. D'autres conséquences d'une modification pourraient toucher la facturation (location d'une salle pendant une certaine durée) ou d'autres questions de sécurité (activer ou désactiver une alarme à certains moments). L'application qui manie du JSCalendar doit donc également empêcher ces changements non autorisés.

Notez que ces problèmes de sécurité ne concernent pas le format à proprement parler, mais les applications qui utilisent ce format. Rien dans JSCalendar, dans ce RFC, ne le rend particulièrement vulnérable ou au contraire protégé, tout est dans l'application.

Les règles de récurrence sont complexes et, comme tout programme, elles peuvent entrainer des conséquences imprévues, avec consommation de ressources informatiques associées. Un exemple aussi simple que la session de yoga quotidienne citée plus haut pourrait générer une infinité d'évènements, si elle était mise en œuvre par une répétition systématique, jusqu'à la fin des temps. Les programmes doivent donc faire attention lorsqu'ils évaluent les règles de récurrence.

L'un des buts d'un format standard d'évènements est évidemment l'échange de données. Il est donc normal et attendu qu'une application de gestion d'agenda reçoive des objets JSCalendar de l'extérieur, notamment via l'Internet. On voit souvent du iCalendar en pièce jointe d'un courrier, par exemple. Il ne faut pas faire une confiance aveugle à ces données venues d'on ne sait où, et ne pas tout intégrer dans le calendrier du propriétaire. L'authentification du courrier (par exemple avec DKIM, RFC 6376) aide un peu, mais n'est pas suffisante.

Les fuseaux horaires sont une source de confusion sans fin. Un utilisateur qui n'est pas attentif, lorsqu'on lui dit qu'un évènement a lieu à 10h30 (UTC-5) peut croire que c'est 10h30 de son fuseau horaire à lui. (Et encore, ici, j'ai indiqué le fuseau horaire de manière lisible, contrairement à ce que font la plupart des Étatsuniens, qui utilisent leurs sigles à eux comme PST, ou ce que font les Français qui n'indiquent pas le fuseau horaire, persuadés qu'ils sont que le monde entier est à l'heure de Paris.) Cette confusion peut être exploitée par des méchants qui utiliseraient les fuseaux horaires de manière délibérement peu claire pour tromper quelqu'un sur l'heure d'un évènement. (Dans la série Mad Men, les hommes qui ne supportent pas l'arrivée d'une femme dans le groupe lui donnent des informations trompeuses sur les heures de réunion, pour qu'elle manque ces évènements.)

Où trouve-t-on du JSCalendar à l'heure actuelle ? Mobilizon ne l'a pas encore (l'action « Ajouter à mon agenda » exporte du iCalendar). Fastmail annonce qu'ils gèrent JSCalendar (mais apparemment seulement dans les échanges JMAP, pas avec l'import/export normal). Cyrus l'a aussi (si vous avez des détails, ça m'intéresse). Pour le cas des récurrences, vous avez une intéressante mise en œuvre en Python. Attention, il y a aussi plein de logiciels qui s'appellent « jscalendar » (notamment des widgets JavaScript pour afficher un calendrier dans un formulaire Web) mais qui n'ont aucun rapport avec ce RFC.


Téléchargez le RFC 8984


L'article seul

RFC 9063: Host Identity Protocol Architecture

Date de publication du RFC : Juillet 2021
Auteur(s) du RFC : R. Moskowitz (HTT Consulting), M. Komu (Ericsson)
Pour information
Réalisé dans le cadre du groupe de travail IETF hip
Première rédaction de cet article le 15 juillet 2021


Ce RFC propose d'aborder l'architecture de l'Internet en utilisant un nouveau type d'identificateur, le Host Identifier (HI), pour beaucoup d'usages qui sont actuellement ceux des adresses IP. Il remplace le RFC 4423, qui était la description originale du protocole HIP, mais il n'y a pas de changements fondamentaux. HIP était un projet très ambitieux mais, malgré ses qualités, la disponibilité de plusieurs mises en œuvre, et des années d'expérimentation, il n'a pas percé.

Une adresse IP sert actuellement à deux choses : désigner une machine (l'adresse IP sert par exemple à distinguer plusieurs connexions en cours) et indiquer comment la joindre (routabilité). Dans le premier rôle, il est souhaitable que l'adresse soit relativement permanente, y compris en cas de changement de FAI ou de mobilité (actuellement, si une machine se déplace et change d'adresse IP, les connexions TCP en cours sont cassées). Dans le second cas, on souhaite au contraire une adresse qui soit le plus « physique » possible, le plus dépendante de la topologie. Ces deux demandes sont contradictoires.

HIP résout le problème en séparant les deux fonctions. Avec HIP, l'adresse IP ne serait plus qu'un identifiant « technique », ne servant qu'à joindre la machine, largement invisible à l'utilisateur et aux applications (un peu comme une adresse MAC aujourd'hui). Chaque machine aurait un HI (Host Identifier) unique. Contrairement aux adresses IP, il n'y a qu'un HI par machine multi-homée mais on peut avoir plusieurs HI pour une machine si cela correspond à des usages différents, par exemple une identité publique, et une « anonyme ».

Pour pouvoir être vérifié, le nouvel identificateur, le HI sera (dans la plupart des cas) une clé publique cryptographique, qui sera peut-être allouée hiérarchiquement par PKI ou plutôt de manière répartie par tirage au sort (comme le sont les clés SSH ou PGP aujourd'hui, ce qui serait préférable, question vie privée). Ces identificateurs fondés sur la cryptographie permettent l'authentification réciproque des machines (contrairement à IP, où il est trivial de mentir sur son adresse), et d'utiliser ensuite IPsec (RFC 7402) pour chiffrer la communication (HIP n'impose pas IPsec, plusieurs encapsulations des données sont possibles, et négociées dynamiquement, mais, en pratique, la plupart des usages prévus reposent sur IPsec).

L'authentification permet d'être sûr du HI de la machine avec qui on parle et, si le HI était connu préalablement à partir d'une source de confiance, d'être sûr qu'on parle bien à l'interlocuteur souhaité. (Si on ne connait pas le HI à l'avance, on dit que HIP est en mode « opportuniste ».)

Cette séparation de l'identificateur et du localisateur est un sujet de recherche commun et d'autres propositions que HIP existent, comme LISP (RFC 6830) ou ILNP (RFC 6740). Dans tous les cas, les couches supérieures (comme TCP) ne verront que l'identificateur, permettant au localisateur de changer sans casser les sessions de transport en cours. (Un mécanisme ressemblant est le Back to My Mac du RFC 6281.) L'annexe A.1 de notre RFC rappelle les avantages de cette approche. Et l'annexe A.2, lecture très recommandée, note également ses défauts, l'indirection supplémentaire ajoutée n'est pas gratuite, et entraine des nouveaux problèmes. Notamment, il faut créer un système de correspondance - mapping - entre les deux, système qui complexifie le projet. Il y a aussi la latence supplémentaire due au protocole d'échange initial, qui est plus riche. Comparez cette honnêteté avec les propositions plus ou moins pipeau de « refaire l'Internet en partant de zéro », qui ne listent jamais les limites et les problèmes de leurs solutions miracle.

Ce HI (Host Identifier) pourra être stocké dans des annuaires publics, comme le DNS (RFC 8005), ou une DHT (RFC 6537), pour permettre le rendez-vous (RFC 8004) entre les machines.

Notez que ce n'est pas directement le Host Identifier, qui peut être très long, qui sera utilisé dans les paquets IP, mais un condensat, le HIT (Host Identity Tag).

HIP intègre les leçons de l'expérience avec IP, notamment de l'importance d'authentifier la machine avec qui on parle. C'est ce qui est fait dans l'échange initial qui permet à un initiateur et un répondeur de se mettre à communiquer. Notamment, il y a obligation de résoudre un puzzle cryptographique, pour rendre plus difficile certaines attaques par déni de service. Voir à ce sujet « DOS-Resistant Authentication with Client Puzzles » de Tuomas Aura, Pekka Nikander et Jussipekka Leiwo, « Deamplification of DoS Attacks via Puzzles » de Jacob Beal et Tim Shepard ou encore « Examining the DOS Resistance of HIP » de Tritilanunt, Suratose, Boyd, Colin A., Foo, Ernest, et Nieto, Juan Gonzalez.

La sécurité est un aspect important de HIP. Les points à garder en tête sont :

  • Protection contre certaines attaques par déni de service via le puzzle cryptographique à résoudre.
  • Protection contre les attaques de l'homme du milieu si le HI a été obtenu par un mécanisme sûr. Cela ne marche évidemment pas en mode opportuniste, où l'initiateur ne connait pas le HI de son correspondant, et le découvre une fois la connexion faite.
  • Le mode opportuniste peut être renforcé, question sécurité, par le TOFU (RFC 7435).
  • Tout mécanisme de séparation de l'identificateur et du localisateur ouvre de nouveaux problèmes : que se passe-t-il si le correspondant ment sur son localisateur ? Est-ce que cela permet des attaques par réflexion ? C'est pour éviter cela que les systèmes à séparation de l'identificateur et du localisateur prévoient, comme HIP, un test de l'existence d'une voie de retour (Cf. RFC 4225).
  • Enfin, on peut évidemment mettre des ACL sur des HI mais leur structure « plate » fait qu'il n'y a pas d'agrégation possible de ces ACL (il faut une ACL par machine avec qui on correspond).

Au sujet du TOFU, le RFC cite «  Leap-of-faith security is enough for IP mobility » de Miika Kari Tapio Komu et Janne Lindqvist, « Security Analysis of Leap-of-Faith Protocols » de Viet Pham et Tuomas Aura et « Enterprise Network Packet Filtering for Mobile Cryptographic Identities » de Janne Lindqvist, Essi Vehmersalo, Miika Komu et Jukka Manner.

Notre RFC ne décrit qu'une architecture générale, il est complété par les RFC 7401, qui décrit le protocole, RFC 7402, RFC 8003, RFC 8004, RFC 8005, RFC 8046 et RFC 5207. Si des implémentations expérimentales existent déjà et que des serveurs publics utilisent HIP, aucun déploiement significatif n'a eu lieu (cf. l'article « Adoption barriers of network layer protocols: The case of host identity protocol de T. Leva, M. Komu, A. Keranen et S. Luukkainen). Comme le disait un des relecteurs du RFC, « There's a lot of valuable protocol design and deployment experience packed into this architecture and the associated protocol RFCs. At the same time, actual adoption and deployment of HIP so far appears to have been scarce. I don't find this surprising. The existing Internet network/transport/application protocol stack has already become sufficiently complicated that considerable expertise is required to manage it in all but the simplest of cases. Teams of skilled engineers routinely spend hours or days troubleshooting operational problems that crop up within or between the existing layers, and the collection of extensions, workarounds, identifiers, knobs, and failure cases continues to grow. Adding a major new layer--and a fairly complicated one at that--right in the middle of the existing stack seems likely to explode the already heavily-strained operational complexity budget of production deployments. ». L'annexe A.3 décrit les questions pratiques liées au déploiement. Elle rappelle le compte-rendu d'expérience chez Boeing de Richard Paine dans son livre « Beyond HIP: The End to Hacking As We Know It ». Elle tord le cou à certaines légendes répandues (que HIP ne fonctionne pas à travers les routeurs NAT, ou bien qu'il faut le mettre en œuvre uniquement dans le noyau.)

Ah, question implémentations (RFC 6538), on a au moins HIP for Linux et OpenHIP qui ont été adaptés aux dernières versions de HIP, et des protocoles associés.

Les changements depuis le RFC 4423 sont résumés en section 14. Il n'y en a pas beaucoup, à part l'intégration de l'expérience, acquise dans les treize dernières années (et résumée dans le RFC 6538) et des améliorations du texte. La nouvelle annexe A rassemble plein d'informations concrètes, notamment que les questions pratiques de déploiement de HIP, et sa lecture est très recommandée à tous ceux et toutes celles qui s'intéressent à la conception de protocoles. La question de l'agilité cryptographique (RFC 7696) a également été détaillée.


Téléchargez le RFC 9063


L'article seul

Récupérer la date d'expiration d'un domaine en RDAP

Première rédaction de cet article le 4 juillet 2021
Dernière mise à jour le 7 juillet 2021


C'est dimanche, il ne fait pas beau, pas question de pique-nique, on va donc faire un peu de JSON. Un des problèmes les plus courants avec les noms de domaine est l'expiration accidentelle du nom. « Nous avons oublié de le renouveler » et paf plus rien ne marche. Pourtant, la date à laquelle le domaine expire est publiquement annoncée, via des protocoles comme whois ou RDAP. Comment utiliser RDAP pour récupérer cette date dans un programme, par exemple un programme d'alerte qui préviendra si l'expiration approche ?

Un peu de contexte d'abord ; un certain nombre (mais pas tous) de registres de noms de domaine exigent un renouvellement périodique du nom, avec paiement et parfois acceptation de nouvelles conditions. L'oubli de ce renouvellement est un gag très fréquent. On ne paie pas, et, à la date d'expiration, le domaine disparait ou bien est mis en attente, plus publié dans le DNS, ce qui fait que tous les services associés cessent de fonctionner. Dans le premier cas, le pire, le domaine a été supprimé, et un autre peut l'enregistrer rapidement. Il est donc crucial de ne pas laisser le domaine expirer. Un des outils indispensables quand on gère un domaine important est donc une supervision automatique de l'approche de l'expiration. L'information est diffusée par le registre, via plusieurs protocoles. Le traditionnel whois, normalisé dans le RFC 3912 a plusieurs inconvénients notamment le fait que le format de sortie n'est pas normalisé. Il est donc difficile d'écrire un programme qui analyse l'information retournée (il existe quand même des solutions comme, en Perl, Net::DRI). Au contraire, le plus moderne RDAP a un format de sortie normalisé (dans le RFC 9083). Utilisons-le, en prenant comme exemple le domaine de ce blog, bortzmeyer.org.

RDAP utilise HTTPS et produit du JSON (RFC 8259). D'autre part, pour interroger le bon serveur RDAP (celui du registre), il faut connaitre son nom, ce qui se trouve dans un registre IANA qui associe le TLD à son serveur RDAP. On apprend ainsi que les informations concernant .org sont à demander à https://rdap.publicinterestregistry.net/rdap/org/. Utilisant le RFC 9082 pour former une requête RDAP correcte, on va utiliser curl pour poser la question sur bortzmeyer.org :

% curl -s https://rdap.publicinterestregistry.net/rdap/org/domain/bortzmeyer.org
  

On récupère un gros JSON compliqué, que je ne vous montre pas ici. On veut juste la date d'expiration du domaine. On va se servir pour cela de l'excellent outil jq :

% curl -s https://rdap.publicinterestregistry.net/rdap/org/domain/bortzmeyer.org | \
       jq '.events | map(select(.eventAction == "expiration"))[0] | .eventDate' 
"2021-08-29T09:32:04.304Z"
  

OK, j'ai triché, ça m'a pris plus de quelques secondes pour écrire le programme jq qui extrait cette information, et j'ai dû vérifier dans le RFC 9083. Expliquons donc.

Partons du haut de l'objet JSON retourné. Il contient un membre nommé events (RFC 9083, section 4.5) qui indique les évènements passés ou futurs pertinents, comme la création du domaine ou comme sa future expiration. On doit donc commencer par demander au programme jq de filtrer sur ce membre, d'où le .events au début. Ensuite, on veut ne garder, parmi les évènements, que l'expiration. On applique donc (map) un test (.eventAction == "expiration") à chaque élement du tableau events et on ne garde (select) que celui qui nous intéresse. Oui, « celui » et pas « ceux » car il n'y a normalement qu'un évènement d'expiration, donc on ne garde que le premier élement ([0]) du tableau produit. Ce premier élément, comme tous ceux qui composent le tableau events est un évènement (RFC 9083, section 4.5), un objet qui a ici deux membres, eventAction, son type (celui sur lequel on filtre, avec .eventAction == "expiration" et eventDate, l'information qu'on recherche. On termine donc par un filtre du seul eventDate, date qui est au format du RFC 3339. Et voilà. On peut ensuite traiter cette date comme on veut. Par exemple, le programme GNU date peut vous traduire cette date en secondes écoulées depuis l'epoch :

% date --date=$(curl -s https://rdap.publicinterestregistry.net/rdap/org/domain/bortzmeyer.org | \
                jq -r '.events | map(select(.eventAction== "expiration"))[0] | .eventDate') \
    +%s 
1630229524
  

Abandonnons maintenant curl et jq pour un programme écrit en Python. On utilise la bibliothèque Requests pour faire du HTTPS et les bibliothèques standard incluses dans Python pour faire du JSON, du calcul sur les dates, etc. Récupérer le JSON est simple :

response = requests.get("%s/%s" % (SERVER, domain))
if response.status_code != 200:
    raise Exception("Invalid RDAP return code: %s" % response.status_code)
  

Le transformer en un dictionnaire Python également :

rdap = json.loads(response.content)
  

On va ensuite y chercher la date d'expiration, qu'on transforme en une belle date-et-heure Python sur laquelle il sera facile de faire des calculs :

for event in rdap["events"]:
    if event["eventAction"] == "expiration":
        expiration = datetime.datetime.strptime(event["eventDate"], RFC3339)
        now = datetime.datetime.utcnow()
        rest = expiration-now
  

Et on peut ensuite mettre les traitements qu'on veut, ici prévenir si l'expiration approche :


if rest < CRITICAL:
            print("CRITICAL: domain %s expires in %s, HURRY UP!!!" % (domain, rest))
            sys.exit(2)
elif rest < WARNING:
            print("WARNING: domain %s expires in %s, renew now" % (domain, rest))
            sys.exit(1)
else:
            print("OK: domain %s expires in %s" % (domain, rest))
            sys.exit(0)

  

Le code complet est disponible (il faut aussi ce module). Notez qu'il n'est pas tellement robuste, il faudrait prévoir davantage de traitement d'erreur. Python fait toutefois en sorte que la plupart des erreurs soient détectées automatiquement (par exemple s'il n'existe pas de membre events dans le résultat) donc, au moins, vous n'aurez pas de résultats erronés. Et puis, par rapport au programme curl+jq plus haut, un grand avantage de ce programme Python est qu'il utilise le registre IANA des serveurs (décrit dans le RFC 7484) et qu'il trouve donc tout seul le serveur RDAP :

% ./expiration-rdap.py bortzmeyer.org                   
OK: domain bortzmeyer.org expires in 55 days, 18:54:01.281920

% ./expiration-rdap.py quimper.bzh
WARNING: domain quimper.bzh expires in 6 days, 18:17:25.919080, renew now
  

Une version plus élaborée de ce programme Python, utilisable depuis des logiciels de supervision automatique comme Nagios, Icinga ou Zabbix est disponible.

Notez qu'un tel outil n'est qu'un élément parmi tout ce qu'il faut faire pour bien gérer l'éventuelle expiration de votre domaine. Il faut aussi mettre les dates de renouvellement dans votre agenda, il est recommandé d'activer l'auto-renouvellement ou, mieux, chez les registres qui le permettent, de louer pour plusieurs années. Je vous recommande également la lecture du « Guide du Titulaire Afnic » ou des « Bonnes pratiques pour l'acquisition et l'exploitation de noms de domaine de l'ANSSI ».


L'article seul

RFC 9039: Uniform Resource Names for Device Identifiers

Date de publication du RFC : Juin 2021
Auteur(s) du RFC : J. Arkko (Ericsson), C. Jennings (Cisco), Z. Shelby (ARM)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF core
Première rédaction de cet article le 1 juillet 2021


Voici un nouvel espace de noms pour des URN, dev, afin de stocker des identificateurs pour des équipements matériels, par exemple pour les inventaires.

Les URN, un sous-ensemble des URI, et des cousins des URL, sont normalisés dans le RFC 8141. On peut placer des URN partout où on peut mettre des URI, par exemple comme noms dans SenML (RFC 8428). Pour des objets contraints, les URN risquent d'être un peu longs par rapport à, par exemple, une adresse IPv4, mais ils sont plus souples. Un URN commence par le plan urn:, suivie d'un espace de noms. Ces espaces sont stockés dans un registre IANA. Ce nouveau RFC crée un nouvel espace de noms, dev. On pourra donc désormais avec des URN comme urn:dev:os:32473-123456 (qui identifie la machine 123456 de l'organisation 32473). Ces identificateurs de machines pourront être utilisés toutes les fois où on a besoin de désigner une machine, dans les données du RFC 8428, dans des inventaires, etc.

Passons au concret maintenant, avec la section 3 du RFC, qui donne la définition formelle de l'espace de noms dev. Ces URN sont évidemment conformes à la norme des URN, le RFC 8141. Comme tous les URN, ceux sous urn:dev: ne sont pas prévus pour être résolus automatiquement. Contrairement aux URL, ils ne fournissent pas de moyen d'accès à une ressource. Bien sûr, si on les met dans une base de données, d'inventaire de ses machines, par exemple, on pourra retrouver l'information, mais ce RFC ne spécifie aucun mécanisme de résolution standard (section 3.6 du RFC).

Après le urn:dev:, ces URN prennent un composant supplémentaire, qui identifie le type d'identificateur dont dérive l'URN. Cela peut être :

  • mac, où l'identificateur est une adresse MAC, enregistrée selon les procédures IEEE, au format EUI-64. C'est par exemple urn:dev:mac:acde48234567019f (pour l'adresse MAC ac:de:48:23:45:67:01:9f). Si vous faites varier l'adresse MAC, par exemple pour protéger votre vie privée, l'URN n'est plus un identifiant stable.
  • ow, qui s'appuie sur 1-Wire, un système privateur.
  • org, avec des identificateurs spécifiques à une organisation, identifiée par son PEN (les PEN sont normalisés dans le RFC 2578). Les PEN sont enregistrés à l'IANA. Prenons comme exemple celui d'une entreprise dont j'étais un co-fondateur, 9319. Si cette entreprise utilise des noms pour ses machines, la machine marx aurait comme URN urn:dev:org:9319-marx.
  • os, comme les org mais plutôt prévus pour des numéros de série. Si cette entreprise numérote toutes ses machines en partant de 1, un URN serait urn:dev:os:9319-1. (Notez que des versions précédentes des URN dev utilisaient os pour les identificateurs LwM2M.) Ainsi, le RIPE-NCC qui a le PEN 15854 pourrait nommer ses sondes Atlas d'après leur numéro unique et donc la sonde 6593 pourrait être désignée par urn:dev:os:15854-6593. Notez qu'on pourrait avoir ici une intéressante discussion sur l'intérêt respectif des URN (urn:dev:os:15854-6593) et des URL (https://atlas.ripe.net/probes/6593/).
  • ops, qui ressemble à l'os, mais avec un identificateur de produit entre le PEN et le numéro de série, par exemple urn:dev:ops:9319-coffeemachine-2 pour la deuxième machine à café de l'organisation. (Comme os, il avait été utilisé pour l'Open Mobile Alliance.)
  • Un autre type, qui sera défini dans le futur (cf. section 7 du RFC). En attendant, on peut utiliser example pour des exemples, comme urn:dev:example:1234.

Enfin, une machine identifiée par un de ces URN peut avoir une partie particulière de la machine désignée par une chaine de caractères après un tiret bas. Ainsi, urn:dev:os:9319-1_alimentation serait l'alimentation de la machine urn:dev:os:9319-1.

Notez que l'équivalence de deux URN est sensible à la casse donc attention, par exemple, à la façon dont vous écrivez les adresses MAC. Le RFC recommande de tout mettre en minuscules.

Idéalement, on veut bien sûr qu'un URN dev identifie une machine et une seule. Mais, en pratique, cela peut dépendre du type d'identificateurs utilisé. Ainsi, les adresses MAC ne sont pas forcément uniques, entre autres parce que certains fabricants ont déjà réutilisé des adresses.

Petit avertissement sur la vie privée : les identificateurs décrits dans ce RFC sont prévus pour être très stables sur le long terme (évidemment, puisque leur but est de garder trace d'une machine) et leur utilisation imprudente (par exemple si on envoie un de ces URN avec les données d'un utilisateur anonyme) peut permettre une surveillance accrue (sections 3.4 et 6.1 du RFC). Le RFC 7721 détaille les risques de ces identificateurs à longue durée de vie.

Le RFC note (section 1) qu'il existe d'autres catégories d'identificateurs qui, selon le cas, pourraient concurrencer nos URN de l'espace de noms dev. C'est le cas par exemple des condensats du RFC 6920, des IMEI du RFC 7254, des MEID du RFC 8464 et bien sûr des UUID du RFC 4122. Tous peuvent se représenter sous forme d'URI, et parfois d'URN. Ils ont leurs avantages et leurs inconvénients, le choix est vaste.

Pour les gens qui utiisent le SGBD PostgreSQL, notez qu'il n'a pas de type de données « URI » donc, si on veut stocker les URN de notre RFC dans PostgreSQL, il faut utiliser le type TEXT, ou bien installer une extension comme pguri. Selon ce qu'on veut faire de ces URN, on peut aussi prendre une solution plus simple qui ne nécessite pas d'installer d'extension, ici pour une organisation qui met toutes ces machines en urn:dev:os:9319-… :

CREATE DOMAIN urndev AS text CHECK (VALUE ~ '^urn:dev:os:9319-[0-9]+(_[a-z0-9]+)?$');
COMMENT ON DOMAIN urndev IS 'URN DEV (RFC 9039) for our devices';
CREATE TABLE Devices (id SERIAL, urn urndev UNIQUE NOT NULL, comments TEXT);
INSERT INTO Devices (urn, comments) VALUES ('urn:dev:os:9319-2', 'No comment');
INSERT INTO Devices (urn) VALUES ('urn:dev:os:9319-1_alimentation');
INSERT INTO Devices (urn, comments) VALUES ('urn:dev:os:9319-666', 'Beast');
  

Téléchargez le RFC 9039


L'article seul

Une « monnaie numérique de banque centrale », c'est quoi ?

Première rédaction de cet article le 27 juin 2021


Dès qu'il s'agit de monnaie, on lit n'importe quoi dans les médias, et on entend n'importe quoi aux tribunes des colloques. Songeons par exemple à tous les gens qui ont péroré sur le Bitcoin ou sur les cryptomonnaies sans rien y connaitre. De même quand on parle de « monnaie numérique de banque centrale », la confusion règne. Notons donc un excellent article d'analyse écrit pour la banque centrale suisse (mais qui n'exprime pas la politique officielle de cette institution) expliquant à quoi pourrait ressembler une MNBC (monnaie numérique de banque centrale) et proposant une solution spécifique.

Lorsqu'on parle de « monnaie électronique » (ou numérique), la confusion règne. Parfois, le terme désigne toute monnaie qui n'est pas en pièces ou en billets (à ce compte, toutes les monnaies sont électroniques depuis longtemps). Parfois, on ne le dit que pour les cryptomonnaies ou que pour celles qui tournent sur une chaine de blocs. Ici, on va utiliser le terme pour une monnaie qui a certaines propriétés de l'argent liquide (notamment une certaine protection de la vie privée) tout en étant entièrement numérique. Ainsi, la carte Visa n'entre pas dans cette définition, car elle n'offre aucune vie privée.

L'article dont je parlais au début est « Comment émettre une monnaie numérique de banque centrale ». Oui, l'avantage des études faites pour un organisme officiel suisse, c'est qu'il y a une traduction de qualité en français. Ses auteurs sont David Chaum (celui de DigiCash), Christian Grothoff (celui de GNUnet) et Thomas Moser, des gens qui connaissent leur sujet, donc.

Pour résumer leur article (mais je vous en recommande la lecture complète), leur cahier des charges est celui d'une monnaie émise et gérée par une banque centrale (un cahier des charges, donc, très différent de celui du Bitcoin, qui vise à se passer de banque centrale), garantissant un minimum d'anonymat pour ceux qui paient avec cette monnaie (« la préservation d’une propriété clé de la monnaie physique: la confidentialité des transactions »), mais pas pour ceux qui la reçoivent. Les revenus des commerçants ne sont donc pas dissimulés, ce qui permet de lutter contre la fraude fiscale. La définition même de monnaie ne fait pas consensus mais les auteurs se focalisent sur un rôle, le moyen d'échange (il y en a d'autres rôles à la monnaie, par exemple unité de mesure ou stockage de valeur). De plus, les auteurs veulent appliquer les principes de KYC (connaissance du client), d'AML (lutte contre le blanchiment) et de CFT (lutte contre le financement du terrorisme), oui, il y en a, des sigles, dans le secteur bancaire. On voit que les objectifs mis en avant sont distincts de ceux de Bitcoin et, a fortiori, de Zcash puisque que, comme le note l'article, « La détection de fraude requiert cependant une capacité d’identification du payeur et le traçage des clients, ce qui est incompatible avec le respect de la confidentialité de la transaction. ». Le fait d'avoir un cahier des charges clair est un des intérêts de cette étude. Par exemple, d'innombrables articles ont été écrits sur des projets comme Diem ou le « yuan électronique » alors que leur cahier des charges reste vague. Le problème est d'autant plus grave qu'il y a souvent de la mauvaise foi dans certains discours. Ainsi, les projets de numérisation ont souvent pour but réel d'en finir avec l'argent liquide pour avoir une traçabilité complète des transactions et une surveillance permanente des acheteurs.

Comment les auteurs de l'article voient-ils leur système de MNBC (monnaie numérique de banque centrale) ? Étant donné qu'il n'y a qu'un émetteur, nul besoin d'une chaine de blocs. (La quasi-totalité des projets de « chaine de blocs privée » ou de « chaine de blocs à permission » n'ont aucun sens : comme le dit l'article « La DLT est une architecture intéressante lorsqu’il n’existe pas d’acteur central ou si les parties prenantes ne souhaitent pas s’accorder sur un acteur central de confiance. Ce qui n’est cependant pratiquement jamais le cas pour une monnaie numérique de détail émise par une banque centrale. [...] Recourir à un registre distribué [réparti, plutôt] ne fait qu’augmenter les coûts de transaction; cela n’apporte aucun avantage dans une mise en place par une banque centrale »). Leur système repose à la place sur GNU Taler (développé par un des auteurs) et les signatures en aveugle de Chaum. La sécurité du système dépend donc de ces techniques logicielles. (D'autres propositions font appel à des systèmes physiques spécifiques, mais « les fonctions physiques non clonables ne peuvent pas s’échanger sur Internet (éliminant de fait l’usage principal de la MNBC » et « les tentatives précédentes de verrous matériels pour empêcher la copie ont été compromises de façon répétée », voir les DRM.) Comme la monnaie numérique de banque centrale envisagée dans cet article a beaucoup de propriétés communes avec l'argent physique (le liquide), elle a également une sécurité proche : possession fait loi, ce qui veut dire que, si l'appareil sur lequel vous gardez vos pièces est détruit, vous perdez votre argent. Cette solution, comme l'argent liquide, n'est raisonnable que pour des sommes relativement faibles. Si l'acheteur n'est pas identifiable, le vendeur l'est car il ne peut pas réutiliser directement les « pièces », il doit les remettre à la banque. C'est nécessaire au mécanisme de protection contre la double dépense. Autre nécessité, la banque centrale doit être connectée en permanence, ce qui impose des exigences nouvelles pour les banques centrales (« La détection de doubles dépenses en ligne élimine ce risque mais rend donc les transactions impossibles si la connexion Internet de la banque centrale est indisponible. ») Je ne vous détaille pas les protocoles cryptographiques ici, je n'ai pas le niveau, lisez l'article. Notez qu'ils sont assez complexes, ce qui peut être un obstacle à l'adoption : la plupart des utilisateurs ne peuvent pas comprendre cette solution, ils devront faire confiance à la minorité qui a compris et vérifié. (Ceci dit, dès aujourd'hui, peu de gens comprennent le système monétaire.)

Quelles sont les chances qu'une banque centrale, avec ses messieurs sérieux en costume-cravate, reprenne cette idée et se lance dans un projet de monnaie numérique protégeant la vie privée ? Personnellement, je dirais qu'elles sont à peu près nulles. Les auteurs notent à juste titre que « une MNBC de détail devrait être basée sur un logiciel libre ou ouvert. Imposer une solution propriétaire qui entraînerait une dépendance à un fournisseur spécifique pourrait vraisemblablement constituer dès le départ un obstacle à son adoption. » Mais cette condition suffirait à faire rejeter le projet par toute banque centrale (déjà, le mot « libre »…). Tous ces dirigeants politiques et financiers passent du temps à critiquer le Bitcoin « qui permet la fraude fiscale et le financement du terrorisme » mais ils ne font aucun effort pour développer des alternatives. Le projet décrit dans cet article est sympathique mais n'a aucune chance. Il essaie de plaire aux banques centrales mais celles-ci n'en voudront jamais, attachées qu'elles sont à des solutions fermées, privatrices, et facilitant la surveillance.


L'article seul

RFC 9057: Email Author Header Field

Date de publication du RFC : Juin 2021
Auteur(s) du RFC : D. Crocker (Brandenburg InternetWorking)
Expérimental
Première rédaction de cet article le 23 juin 2021


Qui est l'auteur d'un message reçu par courrier électronique ? La réponse semblait autrefois simple, c'est forcément la personne ou l'organisation indiquée dans le champ From:. Sauf que des changements récents (et pas forcément bien inspirés) dans le traitement des messages ont amené à ce que le From: soit parfois modifié, par exemple par certaines listes de diffusion. Il ne reflète donc plus le vrai auteur. D'où ce RFC qui crée un nouvel en-tête, Author:, qui identifie le vrai émetteur.

La norme pertinente est le RFC 5322, qui définit des en-têtes comme From: (auteur d'un message) ou Sender: (personne ou entité qui n'a pas écrit le message mais réalise l'envoi, par exemple parce que l'auteur n'avait pas le temps, ou bien parce que le message a été relayé par un intermédiaire). Les amateurs d'archéologie noteront que le courrier électronique est très ancien, plus ancien que l'Internet, cette ancienneté étant la preuve de son efficacité et de sa robustesse. Le premier RFC avec la notion formelle d'auteur d'un message était le RFC 733.

Une particularité du courrier électronique est que le message ne va pas toujours directement de la machine de l'auteure à celle du lecteur (cf. le RFC 5598, sur l'architecture du courrier). Il y a souvent des intermédiaires (mediators) comme les gestionnaires de listes de diffusion, qui prennent un message et le redistribuent aux abonnées. En raison du problème du spam, plusieurs mécanismes de protection ont été développés, qui peuvent poser des problèmes pour ces intermédiaires. SPF (RFC 7208), contrairement à une légende tenace, n'affecte pas les listes de diffusion. (C'est en raison de la distinction entre enveloppe et en-tête d'un message. Si vous entendez quelqu'un pontifier sur SPF et la messagerie, et qu'il ne connait pas la différence entre l'émetteur indiqué dans l'enveloppe et celui marqué dans l'en-tête, vous pouvez être sûre que cette personne est ignorante.) En revanche, DKIM (RFC 6376), surtout combiné avec DMARC (RFC 7489), peut poser des problèmes dans certains cas (le RFC 6377 les détaille). Pour gérer ces problèmes, certaines listes de diffusion choisissent de carrément changer le From: du message et d'y mettre, par exemple (ici tiré de l'utile liste outages, informant des pannes Internet) :


From: Erik Sundberg via Outages <outages@outages.org>

  

Alors que le message avait en fait été écrit par « Erik Sundberg <ESundberg@nitelusa.com> ». C'est une mauvaise idée, mais elle est commune. Dans ce cas, la liste s'est « approprié » le message et on a perdu le vrai auteur, privant ainsi la lectrice d'une information utile (dans le cas de la liste Outages, il a toutefois été préservé dans le champ Reply-To:). [Personnellement, il me semble que l'idéal serait de ne pas modifier le message, préservant ainsi les signatures DKIM, et donc les vérifications DMARC. Dans les cas où le message est modifié, DMARC s'obstine à vérifier le From: et pas le Sender:, ce qui serait pourtant bien plus logique.]

Maintenant, la solution (section 3 du RFC) : un nouvel en-tête, Author:, dont la syntaxe est la même que celle de From:. Par exemple :


Author: Dave Crocker <dcrocker@bbiw.net>

  

Cet en-tête peut être mis au départ, par le MUA, ou bien ajouté par un intermédiaire qui massacre le champ From: mais veut garder une trace de sa valeur originale en la recopiant dans le champ Author:. Cela n'est possible que s'il n'y a pas déjà un champ Author:. S'il existe, il est strictement interdit de le modifier ou de le supprimer.

À la lecture, par le MUA de réception, le RFC conseille d'utiliser le champ Author:, s'il est présent, plutôt que le From:, pour afficher ou trier sur le nom de l'expéditrice.

Comme dans le cas du champ From:, un malhonnête peut évidemment mettre n'importe quoi dans le champ Author: et il faut donc faire attention à ne pas lui accorder une confiance aveugle.

Author: a été ajouté au registre des en-têtes.

On notera qu'une tentative précédente de préservation de l'en-tête From: original avait été faite dans le RFC 5703, qui créait un Original-From: mais uniquement pour les intermédiaires, pas pour les MUA.


Téléchargez le RFC 9057


L'article seul

Traiter des options EDNS nouvelles dans un programme

Première rédaction de cet article le 18 juin 2021


Le protocole DNS permet d'attacher des métadonnées aux questions ou aux réponses par le biais de l'extension EDNS, normalisée dans le RFC 6891. Un certain nombre d'options sont déjà normalisées et peuvent être manipulées depuis un programme, via une bibliothèque DNS. Mais s'il s'agit d'une option EDNS nouvelle, pas encore traitée par la bibliothèque ?

On va voir cela avec l'option « RRSERIAL » actuellement en cours de discussion à l'IETF, dans le draft draft-ietf-dnsop-rrserial. Son but est de récupérer le numéro de série de la zone correspondant à une réponse. Elle est très simple, la valeur associée étant vide dans la question, et uniquement un entier sur 32 bits dans la réponse. Un serveur expérimental existe utilisant cette option, 200.1.122.30.

Déjà, on peut tester sans programmer avec dig, et son option +ednsopt. Les options EDNS ont un code, enregistré à l'IANA. RRSERIAL n'en a pas encore, donc le serveur de test utilise le code temporaire 65024 :

% dig +ednsopt=65024 @200.1.122.30 dateserial.example.com
...
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
; OPT=65024: 78 49 7a 79 ("xIzy")
  

Ça marche, on a obtenu une réponse. dig ne sait pas la formater proprement (« xIzy » est la représentation de 78 49 7a 79 interprété comme de l'ASCII, alors qu'il s'agit d'un entier, le nombre 2018081401), mais c'est déjà ça. (Le draft précise que l'option RRSERIAL a une valeur nulle dans la requête, seule sa présence compte. S'il avait fallu donner une valeur, dig permet de le faire avec +ednsopt=CODE:VALEUR.) Donc, le serveur fonctionne bien. Maintenant, on voudrait faire mieux et donc utiliser un client DNS adapté (d'autant plus qu'il y a des cas à traiter comme la réponse NXDOMAIN, où le numéro de série de la zone est dans un enregistrement SOA, pas dans l'option EDNS). On va donc programmer.

Commençons en Python avec la bibliothèque dnspython. On peut fabriquer l'option dans la requête avec la classe GenericOption :

opts = [dns.edns.GenericOption(dns.edns.RRSERIAL, b'')]
...
message = dns.message.make_query(qname, qtype, options=opts)
  

(Le b'' indique une valeur binaire vide.) Pour lire l'option dans la réponse :

    
for opt in response.options:
   if opt.otype == dns.edns.RRSERIAL:
      print("Serial of the answer is %s" % struct.unpack(">I", opt.data)[0])

  

On a donc juste à convertir la valeur binaire en chaine (le >I signifie un entier gros-boutien). Le code Python complet est en test-rrserial.py.

Pour Go, on va utiliser la bibliothèque godns. Créer l'option et l'ajouter à la requête DNS (m dans le code) se fait ainsi :

m.Question = make([]dns.Question, 1)
// Tout pseudo-enregistrement EDNS a pour nom "." (la racine)
o.Hdr.Name = "."
o.Hdr.Rrtype = dns.TypeOPT
o.SetUDPSize(4096)
// Option EDNS générique
e := new(dns.EDNS0_LOCAL)
e.Code = otype
// Requête vide
e.Data = []byte{}
o.Option = append(o.Option, e)
// Extra est la section Additionnelle
m.Extra = append(m.Extra, o)
  

Et pour lire le résultat :

opt := msg.IsEdns0()
for _, v := range opt.Option {
    // Merci à Tom Thorogood pour le rappel qu'il faut forcer le type
    // et donc avoir une nouvelle variable v (le ':=').
    switch v := v.(type) {
        case *dns.EDNS0_LOCAL:
            if v.Option() == otype {
                serial := binary.BigEndian.Uint32(v.Data)
                fmt.Printf("EDNS rrserial found, \"%d\"\n", serial)
            ...
  

Le code Go complet est en test-rrserial.go.


L'article seul

RFC 9082: Registration Data Access Protocol (RDAP) Query Format

Date de publication du RFC : Juin 2021
Auteur(s) du RFC : S. Hollenbeck (Verisign Labs), A. Newton (AWS)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF regext
Première rédaction de cet article le 16 juin 2021


Le protocole d'information RDAP, qui vise à remplacer whois, est décrit dans un ensemble de RFC. Celui présenté ici normalise la façon de former les requêtes RDAP. Celles-ci ont la forme d'une URL, puisque RDAP repose sur l'architecture REST. Ce RFC remplace l'ancienne norme sur les requêtes RDAP, qui était dans le RFC 7482, mais il n'y a pas de changement significatif.

RDAP peut être utilisé pour beaucoup de sortes d'entités différentes mais ce RFC ne couvre que ce qui correspond aux usages actuels de whois, les préfixes d'adresses IP, les AS, les noms de domaine, etc. Bien sûr, un serveur RDAP donné ne gère pas forcément tous ces types d'entités, et il doit renvoyer le code HTTP 501 (Not implemented) s'il ne sait pas gérer une demande donnée. Ce RFC ne spécifie que l'URL de la requête, le format de la réponse est variable (JSON, XML...) et le seul actuellement normalisé, au-dessus de JSON, est décrit dans le RFC 9083. Quant au protocole de transport, le seul actuellement normalisé pour RDAP (dans le RFC 7480) est HTTP. D'autre part, ces RFC RDAP ne décrivent que le protocole entre le client RDAP et le serveur, pas « l'arrière-cuisine », c'est-à-dire l'avitaillement (création, modification et suppression) des entités enregistrées. RDAP est en lecture seule et ne modifie pas le contenu des bases de données qu'il interroge.

Passons aux choses concrètes. Une requête RDAP est un URL (RFC 3986). Celui-ci est obtenu en ajoutant un chemin spécifique à une base. La base (par exemple https://rdap.example.net/) va être obtenue par des mécanismes divers, comme celui du RFC 7484, qui spécifie un registre que vous pouvez trouver en ligne. On met ensuite un chemin qui dépend du type d'entité sur laquelle on veut se renseigner, et qui indique l'identificateur de l'entité. Par exemple, avec la base ci-dessus, et une recherche du nom de domaine internautique.fr, on construirait un URL complet https://rdap.example.net/domain/internautique.fr. Il y a cinq types d'entités possibles :

  • ip : les préfixes IP (notez qu'on peut chercher un préfixe en donnant juste une des adresses IP couvertes par ce préfixe),
  • autnum : les numéros de systèmes autonomes,
  • domain : un nom de domaine (notez que cela peut être un domaine dans in-addr.arpa ou ipv6.arpa),
  • nameserver : un serveur de noms,
  • entity : une entité quelconque, comme un bureau d'enregistrement, ou un contact identifié par un handle.

La requête est effectuée avec la méthode HTTP GET (les méthodes permettant de modifier le contenu du registre n'ont pas de sens ici, les modifications dans le registre sont plutôt faites avec EPP). Pour juste savoir si un objet existe, on peut aussi utiliser la méthode HEAD. Si on n'obtient pas de code 404, c'est que l'objet existe.

Pour ip, le chemin dans l'URL est /ip/XXXXXX peut être une adresse IPv4 ou IPv6 sous forme texte. Il peut aussi y avoir une longueur de préfixe à la fin donc /ip/2001:db8:1:a::/64 est un chemin valable. Ainsi, sur le service RDAP du RIPE-NCC, https://rdap.db.ripe.net/ip/2001:4b98:dc0:41:: est un URL possible. Testons-le avec curl (le format de sortie, en JSON, est décrit dans le RFC 9083, vous aurez peut-être besoin de passer le résultat à travers jq pour l'afficher joliment) :

% curl https://rdap.db.ripe.net/ip/2001:4b98:dc0:41:: 
{
  "handle" : "2001:4b98:dc0::/48",
  "startAddress" : "2001:4b98:dc0::/128",
  "endAddress" : "2001:4b98:dc0:ffff:ffff:ffff:ffff:ffff/128",
  "ipVersion" : "v6",
  "name" : "GANDI-HOSTING-DC0",
  "type" : "ASSIGNED",
  "country" : "FR",
  "rdapConformance" : [ "rdap_level_0" ],
  "entities" : [ {
    "handle" : "GAD42-RIPE",
    "vcardArray" : [ "vcard", [ [ "version", { }, "text", "4.0" ], [ "fn", { }, "text", "Gandi Abuse Department" ], [ "kind", { }, "text", "group" ], [ "adr", {
      "label" : "63-65 Boulevard Massena\n75013 Paris\nFrance"
...

J'ai utilisé curl mais, notamment pour formater plus joliment la sortie de RDAP, les vrais utilisateurs se serviront plutôt d'un client RDAP dédié comme RDAPBrowser sur Android, ou nicinfo. Voici une vue de RDAPbrowser: rdapbrowser.png

Pour autnum, on met le numéro de l'AS après /autnum/ (au format « asplain » du RFC 5396). Toujours dans l'exemple RIPE-NCC, https://rdap.db.ripe.net/autnum/208069 permet de chercher de l'information sur l'AS 208069 :

% curl https://rdap.db.ripe.net/autnum/208069
{
  "handle" : "AS208069",
  "name" : "ATAXYA",
  "type" : "DIRECT ALLOCATION",
  "entities" : [ {
    "handle" : "mc40833-RIPE",
    "roles" : [ "administrative", "technical" ],
    "objectClassName" : "entity"
  }, {
...

Pour les noms de domaines, on met le nom après /domain/. Ainsi, sur le serveur RDAP d'Afilias, https://rdap.afilias.net/rdap/info/domain/rmll.info nous donnera de l'information sur le domaine rmll.info. On peut mettre un nom en Unicode donc https://rdap.example.net/domain/potamochère.fr est valable, mais il devra être encodé comme l'explique la section 6.1, plus loin (en gros, UTF-8 en NFC). Si on ne veut pas lire cette information sur l'encodage, on peut aussi utiliser la forme Punycode, donc chercher avec https://rdap.example.net/domain/xn--potamochre-66a.fr. Un exemple réel, en Russie :

% curl https://api.rdap.nic.рус/domain/валфекс.рус
...
         {
      "eventAction": "registration",
      "eventDate": "2018-12-26T07:53:41.776927Z"
    },
    ...
                "adr",
            {
              "type": "Registrar Contact"
            },
            "text",
            [
              "",
              "",
              "125476, g. Moskva, ul. Vasilya Petushkova, dom 3, str. 1",
              "",
              "",
              "",
              "RU"
            ]
          ]
...
  

(Attention, le certificat ne sera accepté par curl que si curl a été compilé avec l'option « IDN ».)

On peut aussi se servir de RDAP pour les noms de domaines qui servent à traduire une adresse IP en nom :

% curl https://rdap.db.ripe.net/domain/1.8.a.4.1.0.0.0.0.d.1.4.1.0.0.2.ip6.arpa
{
  "handle" : "0.d.1.4.1.0.0.2.ip6.arpa",
  "ldhName" : "0.d.1.4.1.0.0.2.ip6.arpa",
  "nameServers" : [ {
    "ldhName" : "dns15.ovh.net"
  }, {
    "ldhName" : "ns15.ovh.net"
  } ],
  "rdapConformance" : [ "rdap_level_0" ],
  "entities" : [ {
    "handle" : "OK217-RIPE",
    "roles" : [ "administrative" ]
  }, {
    "handle" : "OTC2-RIPE",
    "roles" : [ "zone", "technical" ]
  }, {
    "handle" : "OVH-MNT",
    "roles" : [ "registrant" ]
  } ],
  "remarks" : [ {
    "description" : [ "OVH IPv6 reverse delegation" ]
  } ],
...

Pour un serveur de noms, on met son nom après /nameserver donc, chez Afilias :

% curl https://rdap.afilias.net/rdap/info/nameserver/rmll1.rmll.info
{
...
   "ipAddresses": {
      "v4": [
         "80.67.169.65"
      ]
   }, 
   "lang": "en", 
   "ldhName": "rmll1.rmll.info", 
...

Pour entity, on indique juste un identificateur. Voici un exemple :

% curl  http://rdg.afilias.info/rdap/entity/81
{
   "handle": "81", 
   "lang": "en", 
...
   "roles": [
      "registrar"
   ], 
   "vcardArray": [
      "vcard", 
      [
         [
            "version", 
            {}, 
            "text", 
            "4.0"
         ], 
         [
            "fn", 
            {}, 
            "text", 
            "Gandi SAS"
         ], 
         [
            "adr", 
            {}, 
            "text", 
            [
               "", 
               "", 
               "63-65 boulevard Massena", 
               "Paris", 
               "", 
               "F-75013", 
               "FR"
            ]
...
  

Certains registres, qui stockent d'autres types d'objets, pourront ajouter leurs propres requêtes, en prenant soin d'enregistrer les préfixes de ces requêtes dans le registre IANA. Par exemple, le logiciel de gestion de registres FRED permet d'interroger le registre sur les clés DNSSEC avec les requêtes /fred_keyset (la syntaxe des requêtes locales est identificateur du préfixe + tiret bas + type cherché).

Dernière possibilité, un chemin spécial indique qu'on veut récupérer de l'aide sur ce serveur RDAP particulier. En envoyant help (par exemple https://rdap.example.net/help), on obtient un document décrivant les capacités de ce serveur, ses conditions d'utilisation, sa politique vis-à-vis de la vie privée, ses possibilités d'authentification (via les mécanismes de HTTP), l'adresse où contacter les responsables, etc. C'est l'équivalent de la fonction d'aide qu'offrent certains serveurs whois, ici celui de l'AFNIC :

% whois -h whois.nic.fr  -- -h
...
%% Option   Function
%% -------  -------------------------------------
%% -r       turn off recursive lookups
%% -n       AFNIC output format
%% -o       old fashioned output format (Default)
%% -7       force 7bits ASCII output format
%% -v       verbose mode for templates and help options
%%          (may be use for reverse query)
%% -T type  return only objects of specified type
%% -P       don't return individual objects in case of contact search
%% -h       informations about server features
%% -l lang  choice of a language for informations (you can specify US|EN|UK for
%%          english or FR for french)
%%
...

Pour RDAP, voyez par exemple https://rdap.nic.bzh/help (qui renvoie de l'HTML), ou, plus austères et se limitant à un renvoi à une page Web, http://rdap.apnic.net/help ou https://rdap.nic.cz/help.

Toutes les recherches jusque-là ont été des recherches exactes (pas complètement pour les adresses IP, où on pouvait chercher un réseau par une seule des adresses contenues dans le réseau). Mais on peut aussi faire des recherches plus ouvertes, sur une partie de l'identificateur. Cela se fait en ajoutant une requête (la partie après le point d'interrogation) dans l'URL et en ajoutant un astérisque (cf. section 4.1). Ainsi, https://rdap.example.net/domains?name=foo* cherchera tous les domaines dont le nom commence par la chaîne de caractères foo. (Vous avez noté que c'est /domains, au pluriel, et non plus /domain ?) Voici un exemple d'utilisation :

% curl  https://rdap.afilias.net/rdap/info/domains\?name=rm\*
...
  "errorCode": 422,
  "title": "Error in processing the request",
  "description": [
    "WildCard search is not supported on sub-zone or tld"
  ]
...

Eh oui, les requêtes ouvertes comme celle-ci posent à la fois des problèmes techniques (la charge du serveur) et politico-juridiques (la capacité à extraire de grandes quantités de la base de données). Elles sont donc typiquement utilisables seulement après une authentification.

On peut aussi chercher un domaine d'après ses serveurs de noms, par exemple https://rdap.example.net/domains?nsLdhName=ns1.example.com chercherait tous les domaines délégués au serveur DNS ns1.example.com. Une telle fonction peut être jugée très indiscrète et le serveur RDAP est toujours libre de répondre ou pas mais, ici, cela marche, on trouve bien le domaine qui a ce serveur de noms :

% curl  https://rdap.afilias.net/rdap/info/domains\?nsLdhName=ns0.abul.org 
...
"domainSearchResults": [
    {
      "objectClassName": "domain",
      "handle": "D10775367-LRMS",
      "ldhName": "rmll.info",
...
  

Deux autres types permettent ces recherches ouvertes, /nameservers (comme dans https://rdap.example.net/nameservers?ip=2001:db8:42::1:53, mais notez qu'on peut aussi chercher un serveur par son nom) et /entities (comme dans https://rdap.example.net/entities?fn=Jean%20Dupon*) :

% curl  http://rdg.afilias.info/rdap/entities\?fn=go\*     
{
   "entitySearchResults": [
      {
         "fn": "Go China Domains, Inc.", 
...
         "fn": "Gotnames.ca Inc.", 
...

Notez que ce type de recherche peut représenter un sérieux danger pour la vie privée (comme noté dans le RFC, par exemple en section 4.2) puisqu'elle permet, par exemple de trouver tous les titulaires prénommés Jean. Elle est donc parfois uniquement accessible à des clients authentifiés, et de confiance.

La section 4 détaille le traitement des requêtes. N'oubliez pas qu'on travaille ici sur HTTP et que, par défaut, les codes de retour RDAP suivent la sémantique HTTP (404 pour un objet non trouvé, par exemple). Il y a aussi quelques cas où le code à retourner est moins évident. Ainsi, si un serveur ne veut pas faire une recherche ouverte, il va répondre 422 (Unprocessable Entity).

Vous avez noté plus haut, mais la section 6 le rappelle aux distraits, que le nom de domaine peut être exprimé en Unicode ou en ASCII. Donc, https://rdap.example.net/domain/potamochère.fr et https://rdap.example.net/domain/xn--potamochre-66a.fr sont deux requêtes acceptables.

Enfin, la section 8 rappelle quelques règles de sécurité comme :

  • Les requêtes ouvertes peuvent mener à une forte consommation de ressources sur le serveur. Le serveur qui ne vaut pas se faire DoSer doit donc faire attention avant de les accepter.
  • Les requêtes RDAP, et surtout les requêtes ouvertes, peuvent soulever des questions liées à la vie privée. Les serveurs RDAP doivent donc réfléchir avant de renvoyer de l'information. Rappelez-vous que RDAP, contrairement à whois, peut avoir un mécanisme d'authentification, donc peut envoyer des réponses différentes selon le client.
  • Et, corollaire du précédent point, les gérants de serveurs RDAP doivent définir une politique d'autorisation : qu'est-ce que je renvoie, et à qui ?

Les changements depuis le RFC 7482 sont peu nombreux et sont surtout de clarification.


Téléchargez le RFC 9082


L'article seul

RFC 9083: JSON Responses for the Registration Data Access Protocol (RDAP)

Date de publication du RFC : Juin 2021
Auteur(s) du RFC : S. Hollenbeck (Verisign Labs), A. Newton (AWS)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF regext
Première rédaction de cet article le 16 juin 2021


Dans l'ensemble des normes sur le protocole RDAP, ce RFC est destiné à décrire le format de sortie, celui des réponses envoyées par le serveur d'information RDAP. Ce format est basé sur JSON et, pour utiliser RDAP en remplacement de whois, il faudra donc se munir de quelques outils pour traiter le JSON. Ce RFC remplace le RFC 7483 mais il y a très peu de changements.

JSON est normalisé dans le RFC 8259 et représente aujourd'hui le format de choix pour les données structurées c'est-à-dire analysables par un programme. (L'annexe E de notre RFC explique en détail le pourquoi du choix de JSON.) Une des caractéristiques importantes de whois est en effet que son format de sortie n'a aucune structure, c'est du texte libre, ce qui est pénible pour les programmeurs qui essaient de le traiter (mais, d'un autre côté, cela ralentit certains usages déplorables, comme la récolte d'adresses de courrier à des fins de spam, jouant ainsi un rôle de semantic firewall). L'utilisation typique de RDAP est en HTTP (RFC 7480) avec les requêtes exprimées dans la syntaxe des URL du RFC 9082. Voici tout de suite un exemple réel, avec la réponse JSON :

% curl https://rdap.afilias.net/rdap/info/domain/kornog-computing.info
...
{
   "entities": [
...
         "objectClassName": "entity", 
         "roles": [
            "technical", 
            "billing", 
            "administrative"
         ], 
         "vcardArray": [
            "vcard", 
            [
               [
                  "version", 
                  {}, 
                  "text", 
                  "4.0"
               ], 
               [
                  "fn", 
                  {}, 
                  "text", 
                  "KORNOG computing"
               ], 
               [
		    "adr",
		    {
		      "cc": "FR"
		    },
		    "text",
		    {}
	      ]
...
   "events": [
      {
         "eventAction": "registration", 
         "eventDate": "2007-08-14T17:02:33Z"
      }, 
      {
         "eventAction": "last changed", 
         "eventDate": "2014-08-14T01:54:07Z"
      }, 
      {
         "eventAction": "expiration", 
         "eventDate": "2015-08-14T17:02:33Z"
      }
   ], 
   "handle": "D19378523-LRMS", 
   "lang": "en", 
   "ldhName": "kornog-computing.info", 
...
   "nameservers": [
      {
         "ldhName": "ns1.kornog-computing.net", 
         "objectClassName": "nameserver", 
         "remarks": [
            {
               "description": [
                  "Summary data only. For complete data, send a specific query for the object."
               ], 
               "title": "Incomplete Data", 
               "type": "object truncated due to unexplainable reasons"
            }
         ]
      }, 
      {
         "ldhName": "ns2.kornog-computing.net", 
         "objectClassName": "nameserver", 
         "remarks": [
            {
               "description": [
                  "Summary data only. For complete data, send a specific query for the object."
               ], 
               "title": "Incomplete Data", 
               "type": "object truncated due to unexplainable reasons"
            }
         ]
      }
   ], 
   "notices": [
      {
         "description": [
            "Access to AFILIAS WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the Afilias registry database. The data in this record is provided by Afilias Limited for informational purposes only, and Afilias does not guarantee its accuracy. [...]"
         ], 
         "title": "TERMS OF USE"
      }
   ], 
   "objectClassName": "domain", 
...
   "rdapConformance": [
      "rdap_level_0"
   ], 
   "secureDNS": {
      "zoneSigned": false
   }, 
   "status": [
      "clientDeleteProhibited -- http://www.icann.org/epp#clientDeleteProhibited", 
      "clientTransferProhibited -- http://www.icann.org/epp#clientTransferProhibited"
   ]
}

La section 1.2 présente le modèle de données de RDAP. Dans les réponses, on trouve des types simples (comme des chaînes de caractères), des tableaux JSON, et des objets JSON qui décrivent les trucs sur lesquels on veut de l'information (noms de domaine, adresses IP, etc). Ces objets peuvent comporter des tableaux ou d'autres objets et, lorsqu'une réponse renvoie plusieurs objets (cas des recherches ouvertes, cf. RFC 9082, section 3.2), peuvent eux-même être regroupés en tableaux. Il existe plusieurs classes de ces objets. D'abord, les classes communes aux registres de noms de domaine et aux RIR (registres d'adresses IP) :

  • Domaines (oui, même pour les RIR, pensez à in-addr.arpa et ip6.arpa),
  • Serveurs de noms,
  • Entités diverses, comme les handles, les identificateurs des contacts, genre GR283-FRNIC.

Deux classes sont spécifiques aux RIR :

On verra peut-être apparaître d'autres classes avec le temps, si l'usage de RDAP se répand.

La section 2 de notre RFC décrit comment JSON est utilisé. Le type MIME renvoyé est application/rdap+json. La section 2 commence par un rappel que le client RDAP doit ignorer les membres inconnus dans les objets JSON, afin de préserver la future extensibilité. (Cette règle ne s'applique pas au jCard - cf. RFC 7095 - embarqué.) Si un serveur veut ajouter des membres qui lui sont spécifiques, il est recommandé qu'il préfixe leur nom avec un identificateur court suivi d'un tiret bas. Ainsi, cet objet RDAP standard :

{
     "handle" : "ABC123",
     "remarks" :
     [
       {
         "description" :
         [
           "She sells sea shells down by the sea shore.",
           "Originally written by Terry Sullivan."
         ]
       }
     ]
   }

S'il est servi par le « registre de la Lune » (registre imaginaire qui fournit les exemples de ce RFC), celui-ci, lorsqu'il voudra ajouter des membres, les précédera de lunarNIC_ :

{
     "handle" : "ABC123",
     "lunarNic_beforeOneSmallStep" : "TRUE THAT!",
     "remarks" :
     [
       {
         "description" :
         [
           "She sells sea shells down by the sea shore.",
           "Originally written by Terry Sullivan."
         ]
       }
     ],
     "lunarNic_harshMistressNotes" :
     [
       "In space,",
       "nobody can hear you scream."
     ]
   }

(Je vous laisse décoder les références geeks dans l'exemple.)

La section 3 s'occupe des types de données de base. On utilise du JSON normal, tel que spécifié dans le RFC 8259, avec ses chaînes de caractères, ses booléens, son null... Un handle (l'identifiant unique - par registre - d'un contact, parfois nommé NIC handle ou registry ID) est une chaîne. Les adresses IP se représentent également par une chaîne de caractères (ne pas oublier le RFC 5952 pour IPv6). Les pays sont identifiés par le code à deux lettres de ISO 3166. Les noms de domaines peuvent être sous une forme ASCII ou bien en Unicode. Les dates et heures suivent le RFC 3339, et les URI le RFC 3986.

Les informations plus complexes (comme les détails sur un contact) utilisent jCard, normalisé dans le RFC 7095.

Que trouve-t-on dans les objets JSON renvoyés par un serveur RDAP ? Une indication de la version de la norme :

"rdapConformance" :
   [
     "rdap_level_0"
   ]

(Éventuellement avec d'autres identificateurs pour les extensions locales.) Et des liens vers des ressources situées ailleurs, suivant le cadre du RFC 8288 :

         "links": [
            {
               "href": "http://rdg.afilias.info/rdap/entity/ovh53ec16bekre5", 
               "rel": "self", 
               "type": "application/rdap+json", 
               "value": "http://rdg.afilias.info/rdap/entity/ovh53ec16bekre5"
            }

On peut aussi avoir du texte libre, comme dans l'exemple plus haut avec le membre remarks. Ce membre sert aux textes décrivant la classe, alors que notices est utilisé pour le service RDAP. Un exemple :

   "notices": [
      {
         "description": [
            "Access to AFILIAS WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the Afilias registry database. The data in this record is provided by Afilias Limited for informational purposes only, and Afilias does not guarantee its accuracy. [...]"
         ], 
         "title": "TERMS OF USE"
      }
   ], 

Contrairement à whois, RDAP permet l'internationalisation sous tous ses aspects. Par exemple, on peut indiquer la langue des textes avec une étiquette de langue (RFC 5646) :

   "lang": "en", 

Enfin, la classe (le type) de l'objet renvoyé par RDAP est indiquée par un membre objectClassName :

   "objectClassName": "domain", 

Ces classes, justement. La section 5 les décrit. Il y a d'abord la classe Entity qui correspond aux requêtes /entity du RFC 9082. Elle sert à décrire les personnes et les organisations. Parmi les membres importants pour les objets de cette classe, handle qui est un identificateur de l'instance de la classe, et roles qui indique la relation de cette instance avec l'objet qui la contient (par exemple "roles": ["technical"] indiquera que cette Entity est le contact technique de l'objet). L'information de contact sur une Entity se fait avec le format vCard du RFC 7095, dans un membre vcardArray. Voici un exemple avec le titulaire du domaine uba.ar :

% curl https://rdap.nic.ar/entity/30546666561
...
  "objectClassName": "entity",
  "vcardArray": [
    "vcard",
    [
      [
        "version",
        {},
        "text",
        "4.0"
      ],
      [
        "fn",
        {},
        "text",
        "UNIVERSIDAD DE BUENOS AIRES"
      ]
    ]
  ],
...

(jCard permet de mentionner plein d'autres choses qui ne sont a priori pas utiles pour RDAP, comme la date de naissance ou le genre.)

La classe Nameserver correspond aux requêtes /nameserver du RFC 9082. Notez qu'un registre peut gérer les serveurs de noms de deux façons : ils peuvent être vus comme des objets autonomes, enregistrés tels quel dans le registre (par exemple via le RFC 5732), ayant des attributs par exemple des contacts, et interrogeables directement par whois ou RDAP (c'est le modèle de .com, on dit alors que les serveurs de noms sont des « objets de première classe »). Ou bien ils peuvent être simplement des attributs des domaines, accessibles via le domaine. Le principal attribut d'un objet Nameserver est son adresse IP, pour pouvoir générer des colles dans le DNS (enregistrement DNS d'une adresse IP, pour le cas où le serveur de noms est lui-même dans la zone qu'il sert). Voici un exemple avec un des serveurs de noms de la zone afilias-nst.info :

% curl https://rdap.afilias.net/rdap/info/nameserver/b0.dig.afilias-nst.info 
...
  "ipAddresses": {
    "v4": [
      "65.22.7.1"
    ],
    "v6": [
      "2a01:8840:7::1"
    ]
  },
...

Notez que l'adresse IP est un tableau, un serveur pouvant avoir plusieurs adresses.

La classe Domain correspond aux requêtes /domain du RFC 9082. Un objet de cette classe a des membres indiquant les serveurs de noms, si la zone est signée avec DNSSEC ou pas, l'enregistrement DS si elle est signée, le statut (actif ou non, bloqué ou non), les contacts, etc. Voici un exemple :

% curl http://rdg.afilias.info/rdap/domain/afilias-nst.info  
...
   "nameservers": [
      {
         "ldhName": "a0.dig.afilias-nst.info", 
...
  "secureDNS": {
    "delegationSigned": false
  },
  ...
  "status": [
    "client transfer prohibited",
    "server delete prohibited",
    "server transfer prohibited",
    "server update prohibited"
  ],
...

La classe IP network rassemble les objets qu'on trouve dans les réponses aux requêtes /ip du RFC 9082. Un objet de cette classe ne désigne en général pas une seule adresse IP mais un préfixe, dont on indique la première (startAddress) et la dernière adresse (endAddress). Personnellement, je trouve cela très laid et j'aurai préféré qu'on utilise une notation préfixe/longueur. Voici un exemple :

% curl https://rdap.db.ripe.net/ip/131.111.150.25    
...
{
  "handle" : "131.111.0.0 - 131.111.255.255",
  "startAddress" : "131.111.0.0/32",
  "endAddress" : "131.111.255.255/32",
  "ipVersion" : "v4",
  "name" : "CAM-AC-UK",
  "type" : "LEGACY",
  "country" : "GB",
...

La dernière classe normalisée à ce stade est autnum (les AS), en réponse aux requêtes /autnum du RFC 9082. Elle indique notamment les contacts de l'AS. Pour l'instant, il n'y a pas de format pour indiquer la politique de routage (RFC 4012). Un exemple d'un objet de cette classe :

% curl  https://rdap.db.ripe.net/autnum/20766 
{
  "handle" : "AS20766",
  "name" : "GITOYEN-MAIN-AS",
  "type" : "DIRECT ALLOCATION",
...
    "handle" : "GI1036-RIPE",
    "vcardArray" : [ "vcard", [ [ "version", { }, "text", "4.0" ], [ "fn", { }, "text", "NOC Gitoyen" ], [ "kind", { }, "text", "group" ], [ "adr", {
      "label" : "Gitoyen\n21 ter rue Voltaire\n75011 Paris\nFrance"
    }, "text", null ], [ "email", { }, "text", "noc@gitoyen.net" ] ] ],
...

Comme, dans la vie, il y a parfois des problèmes, une section de notre RFC, la section 6, est dédiée aux formats des erreurs que peuvent indiquer les serveurs RDAP. Le code de retour HTTP fournit déjà des indications (404 = cet objet n'existe pas ici, 403 = vous n'avez pas le droit de le savoir, etc) mais on peut aussi ajouter un objet JSON pour en indiquer davantage, objet ayant un membre errorCode (qui reprend le code HTTP), un membre title et un membre description. Voici un exemple sur le serveur RDAP de l'ARIN :

% curl -v http://rdap.arin.net/registry/autnum/99999
< HTTP/1.0 404 Not Found
< Mon, 10 May 2021 09:07:52 GMT
< Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips
...
{
...
  "errorCode" : 404,
  "title" : "AUTNUM NOT FOUND",
  "description" : [ "The autnum you are seeking as '99999' is/are not here." ]

Plus positive, la possibilité de demander de l'aide à un serveur RDAP, en se renseignant sur ses capacités, avec la requête /help. Son résultat est décrit dans la section 7 mais tous les serveurs RDAP actuels n'utilisent pas cette possibilité. En voici un où ça marche, à l'ARIN :

%  curl -s https://rdap.arin.net/registry/help 
{
  "rdapConformance" : [ "rdap_level_0" ],
  "notices" : [ {
    "title" : "Terms of Service",
    "description" : [ "By using the ARIN RDAP/Whois service, you are agreeing to the RDAP/Whois Terms of Use" ],
    "links" : [ {
      "value" : "https://rdap.arin.net/registry/help",
      "rel" : "about",
      "type" : "text/html",
      "href" : "https://www.arin.net/resources/registry/whois/tou/"
    } ]
  }, {
    "title" : "Whois Inaccuracy Reporting",
    "description" : [ "If you see inaccuracies in the results, please visit: " ],
    "links" : [ {
      "value" : "https://rdap.arin.net/registry/help",
      "rel" : "about",
      "type" : "text/html",
      "href" : "https://www.arin.net/resources/registry/whois/inaccuracy_reporting/"
    } ]
  }, {
    "title" : "Copyright Notice",
    "description" : [ "Copyright 1997-2021, American Registry for Internet Numbers, Ltd." ]
  } ]
}

Et les résultats des recherches ouvertes (section 3.2 du RFC 9082), qui peuvent renvoyer plusieurs objets ? Ce sont des tableaux JSON, dans des membres dont le nom se termine par Results. Par exemple, en cherchant les noms de domaines commençant par ra (ce test a été fait sur un serveur expérimental qui ne marche plus depuis) :

% curl http://rdg.afilias.info/rdap/domains\?name=ra\*|more           
   "domainSearchResults": [
      {
         "ldhName": "RAINSTRAGE.INFO", 
         ...
         "objectClassName": "domain", 
         "remarks": [
            {
               "description": [
                  "Summary data only. For complete data, send a specific query for the object."
               ], 
               "title": "Incomplete Data", 
               "type": "object truncated due to unexplainable reasons"
            }
...
         "ldhName": "RADONREMOVAL.INFO", 
...
         "ldhName": "RANCONDI.INFO", 
...

Les vrais serveurs RDAP en production ne répondent pas forcément à ces requêtes trop coûteuses et qui peuvent trop facilement être utilisées pour le renseignement économique :

%  curl https://rdap.afilias.net/rdap/info/domains\?name=ra\*
...
"errorCode": 422,
  "title": "Error in processing the request",
  "description": [
    "WildCard search is not supported on sub-zone or tld"
  ]
  

Vous avez peut-être noté dans le tout premier exemple le membre events (section 4.5 du RFC). Ces événements comme created ou last-changed donnent accès à l'histoire d'un objet enregistré. Ici, nous apprenons que le domaine kornog-computing.info a été enregistré en 2007.

Certaines valeurs qui apparaissent dans les résultats sont des chaînes de caractères fixes, stockées dans un nouveau registre IANA. Elles sont conçues pour être utilisées dans les notices, remarks, status, roles et quelques autres. Parmi les remarques, on trouvera le cas où une réponse a été tronquée (section 9 du RFC), comme dans l'exemple ci-dessus avec la mention Incomplete Data. Parmi les statuts, on trouvera, par exemple validated (pour un objet vérifié, par exemple un nom de domaine dont on a vérifié les coordonnées du titulaire), locked (pour un objet verrouillé), obscured (qui n'est pas un statut dans le base du données du registre mais simplement la mention du fait que le serveur RDAP a délibérement modifié certaines informations qu'il affiche, par exemple pour protéger la vie privée), etc. Pour les rôles, on trouvera registrant (titulaire), technical (contact technique), etc.

Pour ceux qu'intéressent les questions d'internationalisation, la section 12 contient d'utiles mentions. L'encodage des données JSON doit être de l'UTF-8. Et, comme indiqué plus haut, les IDN peuvent être sous la forme Punycode ou bien directement en UTF-8.

Et la vie privée, un problème permanent avec whois, où il faut toujours choisir entre la distribution de données utiles pour contacter quelqu'un et les risques pour sa vie privée ? La section 13 revient sur cette question. Un point important : RDAP est un protocole, pas une politique. Il ne définit pas quelles règles suivre (c'est de la responsabilité des divers registres) mais il fournit les outils pour mettre en œuvre ces règles. Notamment, RDAP permet de marquer des parties de la réponse comme étant connues du registre, mais n'ayant délibérement pas été envoyées (avec les codes private et removed) ou bien comme ayant été volontairement rendues peu ou pas lisibles (code obscured).

Vous avez vu dans les exemples précédents que les réponses d'un serveur RDAP sont souvent longues et, a priori, moins lisibles que celles d'un serveur whois. Il faudra souvent les traiter avec un logiciel qui comprend le JSON. Un exemple très simple et que j'apprécie est jq. Il peut servir à présenter le résultat de manière plus jolie :

% curl -s https://rdap.centralnic.com/pw/domain/centralnic.pw  | jq .
...
{
  "objectClassName": "domain",
  "handle": "D956082-CNIC",
  "ldhName": "centralnic.pw",
  "nameservers": [
    {
      "objectClassName": "nameserver",
      "ldhName": "ns0.centralnic-dns.com",
...

(Essayez ce même serveur RDAP sans jq !)

Mais on peut aussi se servir de jq pour extraire un champ particulier, ici le pays :

% curl -s  https://rdap.db.ripe.net/ip/131.111.150.25 | jq ".country"
"GB"

% curl -s  https://rdap.db.ripe.net/ip/192.134.1.1 | jq ".country"
"FR"

Il y a évidemment d'autres logiciels que jq sur ce créneau, comme JSONpath, jpath ou, pour les programmeurs Python, python -m json.tool.

Un dernier mot, sur le choix de JSON pour le format de sortie, alors que le protocole standard d'avitaillement des objets dans les bases Internet, EPP (RFC 5730) est en XML. L'annexe E de notre RFC, qui discute ce choix, donne comme principaux arguments que JSON est désormais plus répandu que XML (cf. l'article « The Stealthy Ascendancy of JSON ») et que c'est surtout vrai chez les utilisateurs (EPP étant utilisé par une population de professionnels bien plus réduite).

Quels changements depuis le RFC 7483 ? La plupart sont mineurs et sont de l'ordre de la clarification. D'autres sont des corrections d'erreurs, par exemple une coquille qui avait mis registrant là où il aurait fallu dire registrar (la proximité des mots en anglais entraine souvent des erreurs, même chez les professionnels). Il y a une certaine tendance au durcissement des règles, des éléments qui étaient optionnels dans le RFC 7483 sont devenus obligatoires comme, par exemple, rdapConformance (dont le statut optionnel avait causé des problèmes).

Et question logiciels qui mettent en œuvre RDAP ? Beaucoup de logiciels de gestion de registre le font aujourd'hui, notamment ceux sous contrat avec l'ICANN, puisqu'ils n'ont pas le choix. Mais les logiciels ne sont pas forcément publiquement disponibles. Parmi ceux qui le sont, il y a RedDog, Fred, celui de l'APNIC


Téléchargez le RFC 9083


L'article seul

QUIC et le suivi des utilisateurs par le serveur

Première rédaction de cet article le 12 juin 2021


Suite à mes articles sur le protocole QUIC, on a parfois attiré mon attention sur un problème potentiel de vie privée : certes, QUIC protège bien contre la surveillance exercée par un acteur extérieur à la communication, grâce à son chiffrement systématique. Mais qu'en est-il de la surveillance exercée par le serveur sur lequel on se connecte ? Penchons-nous sur la complexité de la conception des protocoles Internet, quand on est soucieux de vie privée.

Au contraire du cas de la surveillance par un tiers, très longuement traité dans les RFC sur QUIC (voir par exemple le RFC 9000, section 9.5), le cas du suivi d'un utilisateur par le serveur auquel il se connecte est absent. Et ce alors que les grosses entreprises capitalistes qui forment un partie très visible du Web d'aujourd'hui sont connues pour pratiquer la surveillance de masse. Mais qu'en est-il exactement ?

Voyons d'abord le principe de l'éventuel problème de suivi d'un utilisateur par le serveur. Les connexions QUIC peuvent être longues, peut-être plusieurs heures, voire jours, et elles survivent même aux changements d'adresses IP, QUIC permettant la migration d'une adresse à une autre. Le serveur peut donc facilement déterminer que la demande de /truc.html à 9 h est faite par le même utilisateur que la demande de /machin.html à 16 h, puisque c'est la même connexion QUIC. Indiscutablement, ce problème de suivi de l'utilisateur existe. Mais est-ce spécifique à QUIC et est-ce un vrai problème en pratique ?

D'abord, le problème est ancien. Si le vieil HTTP original n'envoyait qu'une requête par connexion, cette limitation a disparu il y a longtemps. Ainsi, HTTP/2 (RFC 7540) privilégiait déjà les connexions de longue durée, posant les mêmes problèmes. Toutefois, QUIC, avec sa capacité de survivre aux changements d'adresse IP, étend encore la durée de ces connexions, ce qui peut être vu comme aggravant le problème. (Des techniques assez rares, comme multipath TCP, RFC 8684, fonctionnaient également à travers les changements d'adresses IP.)

Mais surtout, dans l'utilisation typique du Web aujourd'hui, il existe bien d'autres méthodes de suivi de l'utilisateur par le serveur. Il y a évidemment les cookies du RFC 6265. Même si on n'est pas connecté à un service comme YouTube, des cookies sont placés. Et ces cookies, contrairement à la connexion de longue durée de QUIC, permettent un suivi inter-serveurs, via Google Analytics et les boutons de partage des GAFA que tant de webmestres mettent sur leurs pages sans réfléchir. Et il n'y a pas que les cookies, le fingerprinting du navigateur peut également permettre d'identifier un visiteur unique, par toutes les informations que le très bavard HTTP transmet, comme le montre bien le test de l'EFF. Bref, à l'heure actuelle, le serveur indiscret qui veut pister ses utilisateurs a bien des moyens plus puissants à sa disposition.

En revanche, si on utilise un système tout orienté vie privée, tel le Tor Browser, qui débraye beaucoup de services du Web trop indiscrets, et fait tout passer par Tor, alors, la durée des connexions QUIC pourrait devenir le maillon faible de la vie privée.

Pour Tor, le problème est à l'heure actuelle purement théorique puisque Tor ne transmet que TCP et que QUIC utilise UDP. Mais il pourrait se poser dans le futur, le projet Tor a d'ailleurs déjà réfléchi à cela dans le contexte de HTTP/2 (qui s'appelait SPDY à ses débuts).

Un client QUIC soucieux de ne pas être suivi à la trace peut donc, une fois qu'il a géré les problèmes bien plus énormes que posent les cookies et le fingerprinting, envisager des solutions comme de ne pas laisser les connexions QUIC durer trop longtemps et surtout ne pas utiliser la migration (qui permet de maintenir la connexion lorsque l'adresse IP change). Cela peut se faire en raccrochant délibérement la connexion, ou simplement en ne prévoyant pas de réserve de connection IDs (RFC 9000, section 5.1.1). Ceci dit, c'est plus facile à dire qu'à faire car une application n'est pas forcément informée rapidement d'un changement d'adresse IP de la machine. Et, évidemment, cela aura un impact négatif sur les performances totales.

La longue durée des connexions QUIC n'est pas le seul mécanisme par lequel un serveur pourrait suivre à la trace un client. QUIC permet à un client de mémoriser des informations qui lui permettront de se reconnecter au serveur plus vite (ce qu'on nomme le « 0-RTT »). Ces informations (qui fonctionnent exactement comme un cookie HTTP) permettent évidemment également au serveur de reconnaitre un client passé. Cette possibilité et ses conséquences parfois néfastes sont détaillées dans le RFC 9001, sections 4.5 et 9.1. Notez que cela existe également avec juste TLS (ce qu'on nomme le session resumption, RFC 8446, section 2.2) et avec le TCP Fast Open (RFC 7413), avec les mêmes conséquences sur la possibilité de suivi d'un client par le serveur. Le client QUIC qui voudrait protéger sa vie privée doit donc faire attention, quand il démarre une nouvelle connexion, à ne pas utiliser ces possibilités, qui le trahiraient (mais qui diminuent la latence ; toujours le compromis).

Comme souvent en sécurité, on est donc face à un compromis. Si on ne pensait qu'à la vie privée, on utiliserait Tor tout le temps… Les navigateurs Web, par exemple, optimisent clairement pour la vitesse, pas pour la vie privée.


L'article seul

L'Internet était-il en panne aujourd'hui ?

Première rédaction de cet article le 8 juin 2021


Aujourd'hui, entre 1015 et 1110 UTC, le CDN Fastly était en panne, provoquant des dysfonctionnements divers sur quelques sites Web connus. Je ne sais pas ce qui s'est passé, donc je ne vais pas vous l'expliquer mais je voudrais revenir sur la façon dont cet incident a été présenté dans les médias.

Car les titres sensationnalistes n'ont pas manqué, annonçant une panne massive du Web, voire de tout l'Internet ou au moins d'une grande partie. Des gens ont ricané en reprenant la légende comme quoi l'Internet avait été conçu pour résister à une attaque nucléaire ou déploré que l'Internet soit trop centralisé, ce qu'il n'est justement pas. La tonalité générale dans les médias était qu'il s'agissait d'une panne majeure de ce réseau informatique dont tant de choses dépendent. La réalité est très différente : l'Internet a très bien tenu, l'écrasante majorité des sites Web marchaient, quelques gros sites Web commerciaux avaient une drôle d'allure. Voici par exemple celui du Monde : fastly-outage-lemonde.png

L'Internet est le réseau informatique sous-jacent à toutes nos activités en ligne. Si des pannes partielles et localisées l'affectent souvent, il n'a jamais connu de panne généralisée, ou visible à l'échelle mondiale. Pendant l'incident avec Fastly, le courrier électronique passait comme d'habitude, les nœuds Bitcoin se tenaient au courant des transactions financières, les téléchargements BitTorrent se poursuivaient, les informaticiens se connectaient en SSH, les gens continuaient à bavarder sur Signal ou Matrix, et les utilisateurs de Gemini regardaient du contenu en ligne.

Et le Web ? Si l'Internet est l'infrastructure sous-jacente, le Web est l'application la plus connue, et même la seule connue de la plupart des gens qui ont le monopole de l'accès aux médias officiels. En tout cas, le Web marchait comme d'habitude. Des millions de sites Web (comme celui que vous visitez en ce moment) n'ont eu aucun problème. Une infime minorité, ceux qui avaient du contenu sur le CDN Fastly était, soit inaccessible, soit affichait une apparence curieuse car, si le code HTML était bien chargé par le navigateur, les feuilles de style ou le JavaScript ne suivaient pas. C'est pour cela que la page d'accueil de GitHub était bizarre : fastly-outage-github.png

D'accord, ces gros sites Web commerciaux étaient souvent des sites visibles et connus. Mais même comme cela, Fastly n'est pas le seul fournisseur de CDN et beaucoup d'autres sites continuaient à fonctionner. Il faut arrêter cette présentation erronée comme quoi une poignée de sites Web connus sont « l'Internet » comme cela a souvent été dit.

Des gens ont reproché à ces sites de n'avoir pas de redondance, de dépendre entièrement d'un seul CDN. Mais c'est un détail. Le point important est que les pannes arrivent. On ne peut pas les empêcher toutes. Ce qu'il faut, c'est éviter qu'elles aient des conséquences trop étendues. Il ne faut pas se poser la question de la robustesse de GitHub, il faut au contraire faire en sorte que toute l'activité de programmation mondiale ne cesse pas quand GitHub est en panne. Il faut des milliers de GitLab ou de Gitea, un système réellement décentralisé, où il n'y aura aucun site qui concentrera toute une activité.

Le lendemain, Fastly a publié une explication (sommaire) sur la panne. Notons qu'en attendant cette explication, les médias n'ont pas hésité à avancer des théories fumeuses comme France Inter qui a mis en cause « les serveurs DNS » alors qu'il n'y avait jamais eu aucune indication en ce sens.

Pour se détendre, Natouille avait lancé sur le fédivers (tiens, encore un système décentralisé et qui n'a donc pas eu de problème global) le mot-croisillon « #ExpliqueLaPanneInternet ». Vous pouvez consulter les très amusantes « explications » de la panne sur n'importe quelle instance du fédivers.


L'article seul

Fiche de lecture : Cosmogonies

Auteur(s) du livre : Julien d'Huy
Éditeur : La Découverte
978-2-348-05966-7
Publié en 2020
Première rédaction de cet article le 3 juin 2021


Il y a longtemps que les folkloristes et les ethnologues ont remarqué des ressemblances troublantes entre des contes et des mythes chez des peuples très lointains. De nombreuses explications ont été proposées. L'auteur, dans ce gros livre très technique, détaille une de ces explications : les mythes ont une origine commune, remontant parfois à des milliers d'années. Il explique ensuite comment étayer cette explication avec des méthodes proches de celles de la phylogénie.

Un exemple frappant est donné par le récit que vous connaissez peut-être grâce à l'Odyssée. Le cyclope Polyphème garde des troupeaux d'animaux. Ulysse et ses compagnons sont capturés par lui et dévorés un à un. Ulysse réussit à aveugler le cyclope en lui brûlant son œil puis s'échappe de la grotte où il était prisonnier en se cachant sous un mouton. Des récits très proches se trouvent chez des peuples qui n'ont aucun lien avec les Grecs de l'Antiquité, notamment chez des Amérindiens, complètement séparés des Européens bien avant Homère. On peut penser à une coïncidence mais de telles ressemblances sont quand même bien fréquentes. On peut aussi se dire que l'unicité physique de l'espèce humaine se traduit par une mentalité identique, et donc une unité des mythes. Mais si les ressemblances sont fréquentes, il y a aussi des différences. Par exemple, lorsqu'on fait des catalogues de mythes, l'Afrique est souvent à part. Si on a un peu bu, on peut aussi imaginer que des extra-terrestres ou bien un être surnaturel ont raconté les mêmes mythes à tous les humains. L'auteur part d'une autre hypothèse : les mythes actuels sont le résultat de l'évolution de mythes très anciens, qui ont divergé à partir d'une souche commune.

La théorie elle-même est ancienne. Mais comment l'étayer ? On peut remarquer que, pour les différentes versions d'un même mythe, des sous-groupes semblent se dessiner. par exemple, dans le mythe de Polyphème, les variantes américaines sont proches les unes des autres, et assez distinctes des variantes eurasiatiques (par exemple, en Amérique, le cyclope est remplacé par un corbeau). Cela évoque fortement un arbre évolutif.

À partir de là, l'auteur utilise une méthode proche de la phylogénie. Les mythes sont découpés en éléments, un peu comme les gènes qu'on utilise en biologie, et on utilise les outils de la phylogénie pour établir des arbres phylogénétiques, dont on étudie ensuite la vraisemblance. Par exemple, les grands mouvements migratoires se retrouvent bien dans cette analyse, avec des mythes amérindiens qui forment un groupe distinct, mais néanmoins souvent rattaché à des mythes qu'on trouve en Asie. De même, les variations génétiques de l'espèce humaine se retrouvent souvent dans les arbres des mythes, non pas évidemment parce que tel ou tel gène dicterait les mythes qu'on raconte, mais parce que les humains font souvent de l'endogamie et que gènes et mythes se transmettent ensemble, au sein des mêmes groupes humains. La place particulière de l'Afrique s'expliquerait par l'ancienneté : Homo sapiens est sorti d'Afrique il y a longtemps et les mythes qu'il avait à ce moment ont tellement évolué qu'on ne les reconnait plus aujourd'hui. Bien, sûr, je schématise beaucoup. Comme souvent en sciences humaines, la situation est plus compliquée que cela, et vous devrez lire le livre pour en apprécier les nuances. D'autant plus que les sujets ethnologiques sont toujours politiquement sensibles, par exemple lorsque l'auteur explique le mythe assez commun du matriarcat originel par un mythe commun, pas par une réalité historique (les mythes ne disent pas la vérité, ils racontent une histoire…).

Un autre exemple de mythe courant est celui de la femme-oiseau. En gros, un homme (un mâle) surprend, souvent au bain, une femme-animal (souvent un oiseau), et cache sa part animale (son manteau de plumes, par exemple). Il peut ainsi la garder près de lui, jusqu'au jour où elle remet la main sur son plumage et peut ainsi se sauver. Là encore, on peut isoler ses élements (les « gènes »), les abstraire (femme-animal au lieu de femme-oiseau car, dans certaines variantes, l'animal est une chèvre ou un éléphant) et les mettre dans le logiciel de phylogénie qui va alors sortir un arbre. Comme toujours, en phylogénie, beaucoup dépend de certaines hypothèses (les paramètres donnés au logiciel) et il est donc important de regarder ensuite les résultats de la reconstruction phylogénétique à la lumière de la génétique, de la connaissance qu'on a des migrations humaines, et des découvertes archéologiques. Dans certains cas, on peut même retrouver la racine de l'arbre, c'est-à-dire le mythe originel.

Le livre n'est pas toujours facile à lire, à pas mal d'endroits, c'est davantage une exposition de résultats de recherche récents qu'un ouvrage de vulgarisation. Avoir fait de la bio-informatique et notamment de la phylogénie, et/ou des statistiques peut aider. Mais les mythes eux-mêmes sont fascinants puisque chacun est un moyen de plonger dans l'esprit de peuples lointains ou même disparus.

(J'ai reçu un message détaillant des critiques sévères à propos de ce livre. Je précise donc que je ne suis moi-même ni folkloriste, ni ethnologue, et que je ne faisais que rendre compte de ce que j'avais compris du livre lu. De toute façon, en sciences humaines, il est rare qu'il existe des consensus, même sur les choses les plus basiques. Je n'ai donc pas modifié mon article.)


L'article seul

RFC 8903: Use cases for DDoS Open Threat Signaling

Date de publication du RFC : Mai 2021
Auteur(s) du RFC : R. Dobbins (Arbor Networks), D. Migault (Ericsson), R. Moskowitz (HTT Consulting), N. Teague (Iron Mountain Data Centers), L. Xia (Huawei), K. Nishizuka (NTT Communications)
Pour information
Réalisé dans le cadre du groupe de travail IETF dots
Première rédaction de cet article le 31 mai 2021


Le travail autour de DOTS (DDoS Open Threat Signaling) vise à permettre la communication, pendant une attaque par déni de service, entre la victime et une organisation qui peut aider à atténuer l'attaque. Ce nouveau RFC décrit quelques scénarios d'utilisation de DOTS. Autrement, DOTS est normalisé dans les RFC 8811 et ses copains.

Si vous voulez un rappel du paysage des attaque par déni de service, et du rôle de DOTS (DDoS Open Threat Signaling) là-dedans, je vous recommande mon article sur le RFC 8612. Notre RFC 8903 ne fait que raconter les scénarios typiques qui motivent le projet DOTS.

Par exemple, pour commencer, un cas simple où le fournisseur d'accès Internet d'une organisation est également capable de fournir des solutions d'atténuation d'une attaque. Ce fournisseur (ITP dans le RFC, pour Internet Transit Provider) est sur le chemin de tous les paquets IP qui vont vers l'organisation victime, y compris ceux de l'attaque. Et il a déjà une relation contractuelle avec l'utilisateur. Ce fournisseur est donc bien placé, techniquement et juridiquement, pour atténuer une éventuelle attaque. Il peut déclencher le système d'atténuation, soit à la demande de son client qui subit une attaque, soit au contraire contre son client si celui-ci semble une source (peut-être involontaire) d'attaque. (Le RFC appelle le système d'atténuation DMS pour DDoS Mitigation Service ; certains opérateurs ont des noms plus amusants pour le DMS comme OVH qui parle d'« aspirateur ».)

Dans le cas d'une demande du client, victime d'une attaque et qui souhaite l'atténuer, le scénario typique sera qu'une machine chez le client (un pare-feu perfectionné, par exemple), établira une session DOTS avec le serveur DOTS inclus dans le DMS du fournisseur d'accès. Lorsqu'une attaque est détectée (cela peut être automatique, avec un seuil pré-défini, ou bien manuel), la machine du client demandera l'atténuation. Pendant l'atténuation, le client pourra obtenir des informations de la part du DMS du fournisseur. Si l'attaque se termine, le client pourra décider de demander l'arrêt de l'atténuation. Notez que la communication entre le client DOTS (chez la victime) et le serveur DOTS (chez le fournisseur d'accès) peut se faire sur le réseau « normal » (celui qui est attaqué) ou via un lien spécial, par exemple en 4G, ce qui sera plus cher et plus compliqué mais aura l'avantage de fonctionner même si l'attaque sature le lien normal.

Ce scénario simple peut aussi couvrir le cas du réseau domestique. On peut imaginer une box disposant de fonctions de détection d'attaques (peut-être en communiquant avec d'autres, comme le fait la Turris Omnia) et d'un client DOTS, pouvant activer automatiquement l'atténuation en contactant le serveur DOTS du FAI.

Le second cas envisagé est celui où le fournisseur d'accès n'a pas de service d'atténuation mais où le client (mettons qu'il s'agisse d'un hébergeur Web), craignant une attaque, a souscrit un contrat avec un atténuateur spécialisé (de nombreuses organisations ont aujourd'hui ce genre de services, y compris sans but lucratif). Dans ce cas, il faudra « détourner » le trafic vers cet atténuateur, avec des trucs DNS ou BGP, qui sont sans doute hors de portée de la petite ou moyenne organisation. L'accord avec l'atténuateur doit prévoir la technique à utiliser en cas d'attaque. Si c'est le DNS, la victime va changer ses enregistrements DNS pour pointer vers les adresses IP de l'atténuateur (attention au TTL). Si c'est BGP, ce sera à l'atténuateur de commencer à annoncer le préfixe du client (attention aux règles de sécurité BGP, pensez IRR et ROA), et au client d'arrêter son annonce. Le reste se passe comme dans le scénario précédent.


Téléchargez le RFC 8903


L'article seul

RFC 9038: Extensible Provisioning Protocol (EPP) Unhandled Namespaces

Date de publication du RFC : Mai 2021
Auteur(s) du RFC : J. Gould (VeriSign), M. Casanova (SWITCH)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF regext
Première rédaction de cet article le 30 mai 2021


Le protocole EPP, qui sert notamment lors de la communication entre un registre (par exemple de noms de domaine) et son client, est extensible : on peut rajouter de nouveaux types d'objets et de nouvelles informations. Normalement, le serveur EPP n'envoie au client ces nouveautés que si le client a annoncé, lors de la connexion, qu'il savait les gérer. Et s'il ne l'a pas fait, que faire de ces données, ces unhandled namespaces ? Ce nouveau RFC propose de les envoyer quand même, mais dans un élément XML prévu pour des informations supplémentaires, et qui ne devrait donc rien casser chez le client.

Le but est de rester compatible avec l'EPP standard, tel que normalisé dans le RFC 5730. Prenons l'exemple de l'extension pour DNSSEC du RFC 5910. Comme toutes les extensions EPP, elle utilise les espaces de noms XML. Cette extension particulière est identifiée par l'espace de noms urn:ietf:params:xml:ns:secDNS-1.1. À l'établissement de la connexion, le serveur annonce les extensions connues :

    
<greeting 
    <svcMenu>
       ...
         <svcExtension>
            <extURI>urn:ietf:params:xml:ns:secDNS-1.1</ns0:extURI>

  

Et le client annonce ce qu'il sait gérer :


<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
 <command>
   <login>
...
    <svcs>
      <svcExtension><extURI>urn:ietf:params:xml:ns:secDNS-1.1</extURI></svcExtension>
...

  

(<svcExtension> est décrit dans le RFC 5730, sections 2.4 et 2.9.1.1). Ici, le serveur a annoncé l'extension DNSSEC et le client l'a acceptée. Tout le monde va donc pouvoir envoyer et recevoir des messages spécifiques à cette extension, comme l'ajout d'une clé :


   <extension>
      <update xmlns="urn:ietf:params:xml:ns:secDNS-1.1"> 
         <add xmlns="urn:ietf:params:xml:ns:secDNS-1.1">
            <dsData xmlns="urn:ietf:params:xml:ns:secDNS-1.1">
               ...
              <digest xmlns="urn:ietf:params:xml:ns:secDNS-1.1">076CF6DA3692EFE72434EA1322177A7F07023400E4D1A1F617B1885CF328C8AA</digest>
    ...

  

Mais, si le client ne gère pas une extension (et ne l'a donc pas indiquée dans son <login>), que peut faire le serveur s'il a quand même besoin d'envoyer des messages spécifiques à cette extension inconnue du client, ce unhandled namespace ? C'est particulièrement important pour la messagerie EPP (commande <poll>) puisque le serveur peut, par exemple, mettre un message dans la boite sans connaitre les capacités du client, mais cela peut affecter également d'autres activités.

La solution de notre RFC est d'utiliser un élément EPP déjà normalisé (RFC 5730, secton 2.6), <extValue>, qui permet d'ajouter des informations que le client ne pourra pas analyser automatiquement, comme par exemple un message d'erreur lorsque le serveur n'a pas pu exécuter l'opération demandée. Notre RFC étend cet <extValue> au cas des espaces de noms non gérés. Le sous-élément <value> contiendra l'élément XML appartenant à l'espace de noms que le client ne sait pas gérer, et le sous-élément <reason> aura comme contenu un message d'information dont la forme recommandée est NAMESPACE-URI not in login servicesNAMESPACE-URI est le unhandled namespace. Par exemple, le RFC cite un cas où le registre ne gère pas l'extension DNSSEC du RFC 5910 et répond :


<response>
   ...
      <extValue>
        <value>
           <secDNS:infData
               xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1">
             <secDNS:dsData>
                   ...
                   <secDNS:digest>49FD46E6C4B45C55D4AC</secDNS:digest>
             </secDNS:dsData>
           </secDNS:infData>
        </value>
        <reason>
           urn:ietf:params:xml:ns:secDNS-1.1 not in login services
        </reason>
      </extValue>

  

(Le RFC a aussi un autre exemple, avec l'extension de rédemption du RFC 3915.)

Ce RFC ne change pas le protocole EPP : il ne fait que décrire une pratique, compatible avec les clients actuels, pour leur donner le plus d'informations possible. Toutefois, pour informer tout le monde, cette pratique fait l'objet elle-même d'une extension, urn:ietf:params:xml:ns:epp:unhandled-namespaces-1.0, que le serveur va inclure dans son <greeting> et que le client mettra dans sa liste d'extensions acceptées. (Cet espace de nom a été mis dans le registre IANA créé par le RFC 3688. L'extension a été ajoutée au registre des extensions EPP introduit par le RFC 7451.) De toute façon, le client a tout intérêt à inclure dans sa liste toutes les extensions qu'il gère et à regarder s'il y a des <extValue> dans les réponses qu'il reçoit (même si la commande EPP a été un succès) ; cela peut donner des idées aux développeurs sur des extensions supplémentaires qu'il serait bon de gérer. Quant au serveur, il est bon que son administrateur regarde s'il y a eu des réponses pour des unhandled namespaces et prenne ensuite contact avec l'administrateur du client pour lui signaler ce manque.

Notez que ce RFC s'applique aux extensions portant sur les objets manipulés en EPP (par exemple les noms de domaine) et à celles portant sur les séquences de commandes et de réponses EPP, mais pas aux extensions portant sur le protocole lui-même (cf. RFC 3735).

Question mises en œuvre de ce RFC, le SDK de Verisign inclut le code nécessaire (dans le fichier gen/java/com/verisign/epp/codec/gen/EPPFullExtValuePollMessageFilter.java). D'autre part, le registre du .ch utilise ce concept d'espaces de noms inconnus pour indiquer au BE les changements d'un domaine provoqués par l'utilisation du CDS du RFC 7344, puisque ces changements ne sont pas passés par EPP.


Téléchargez le RFC 9038


L'article seul

RFC 9022: Domain Name Registration Data (DNRD) Objects Mapping

Date de publication du RFC : Mai 2021
Auteur(s) du RFC : G. Lozano (ICANN), J. Gould, C. Thippeswamy (VeriSign)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF regext
Première rédaction de cet article le 30 mai 2021


Le RFC 8909 normalisait un format générique pour les séquestres d'objets enregistrés dans un registre. Ce nouveau RFC 9022 précise ce format pour le cas spécifique des registres de noms de domaine (dont les objets enregistrés sont les noms de domaine, les contacts, les serveurs de noms, etc).

Rappelons que le but d'un séquestre est de permettre à un tiers de reprendre les opérations d'un registre (par exemple un registre de noms de domaine) en cas de défaillance complète de celui-ci. Pas juste une panne matérielle qui fait perdre des données, non, une défaillance grave, par exemple une faillite, qui fait que plus rien ne marche. Le registre doit donc envoyer régulièrement des données à l'opérateur de séquestre qui, au cas où la catastrophe survient, enverra ces données au nouveau registre, qui sera en mesure (en théorie…) de charger les données dans une nouvelle base et de reprendre les opérations. Sous quel format sont envoyées ces données ? Car il faut évidemment un format ouvert et documenté, pour que le nouveau registre ait pu développer un programme d'importation des données. C'est le but du RFC 8909 et de notre nouveau RFC 9022. Ils spécifient un format à base de XML (avec possibilité de CSV).

Par rapport au format générique du RFC 8909, notre RFC ajoute les objets spécifiques de l'industrie des noms de domaine (il est recommandé de réviser la terminologie du RFC 8499) :

  • Les noms de domaine, tels que manipulés en EPP selon le RFC 5731.
  • Les serveurs de noms (pour les registres où ils sont enregistrés comme objets séparés, ce qui n'est pas obligatoire), tels que gérés via EPP selon le RFC 5732.
  • Les contacts (le titulaire du nom de domaine, le contact technique avec qui on verra les problèmes DNS, etc), selon le modèle utilisé en EPP par le RFC 5733.
  • Les BE (Bureaux d'Enregistrement). Le cas est un peu différent car ils ne sont typiquement pas gérés via EPP puisque les sessions EPP sont justement établies par un BE, qui a donc dû être créé par un autre moyen.
  • Les noms spéciaux, qui sont des noms de domaine qui ne sont pas des noms de domaines habituels mais, par exemple, des gros mots dont l'enregistrement est interdit. En anglais, le sigle officiel est NNDN, qui veut récursivement dire NNDN's Not a Domain Name.
  • Les tables liées à IDN, pour les registres qui maintiennent des informations restreignant l'usage de ces noms de domaine en Unicode (cf. RFC 6927).
  • Certains paramètres de configuration des serveurs EPP du registre.
  • Des compteurs du nombre d'objets enregistrés.
  • Des objets qui sont importants pour le registre mais pas assez répandus pour avoir fait l'objet d'une normalisation.

Le format concret du séquestre se décline en deux « modèles », un en XML et un en CSV (RFC 4180), mais j'ai l'impression que le XML est nettement plus utilisé. Dans tous les cas :

  • Les dates sont au format du RFC 3339.
  • Les noms des pays sont les identificateurs à deux lettres de ISO 3166.
  • Les numéros de téléphone sont au format E.164.
  • Les adresses IP doivent suivre le format du RFC 5952. Pour IPv4, le RFC est vague, car il n'y a pas de format standard (vous ne verrez pas une seule adresse IP dans le RFC 791, que cite notre RFC…).

Pour CSV, chaque fichier CSV représente une table (les noms de domaine, les contacts, les serveurs de noms…) et chaque ligne du fichier un objet. Le modèle de données est décrit plus précisément en section 4.6. Voici un exemple d'une ligne extraite du fichier des noms de domaine, décrivant le domaine domain1.example, créé le 3 avril 2009, et dont le titulaire a pour identificateur (handle) registrantid :

domain1.example,Ddomain2-TEST,,,registrantid,registrarX,registrarX,clientY,2009-04-03T22:00:00.0Z,registrarX,clientY,2009-12-03T09:05:00.0Z,2025-04-03T22:00:00.0Z 
  

Les contacts seraient mis dans un autre fichier CSV, avec un fichier de jointure pour faire le lien entre domaines et contacts.

Et pour XML ? Il s'inspire beaucoup des éléments XML échangés avec EPP, par exemple pour la liste des états possibles pour un domaine. Voici un exemple (RDE = Registry Data Escrow, et l'espace de noms correspondant rdeDom est urn:ietf:params:xml:ns:rdeDomain-1.0) :


<rdeDom:domain>
      <rdeDom:name>jdoe.example</rdeDom:name>
      <rdeDom:roid>DOM03-EXAMPLE</rdeDom:roid>
      <rdeDom:status s="ok"/>
      <rdeDom:registrant>IZT01</rdeDom:registrant>
      <rdeDom:contact type="tech">IZT01</rdeDom:contact>
      <rdeDom:contact type="billing">IZT01</rdeDom:contact>
      <rdeDom:contact type="admin">IZT01</rdeDom:contact>
      <rdeDom:ns>
        <domain:hostObj>ns.jdoe.example</domain:hostObj>
      </rdeDom:ns>
      <rdeDom:clID>RAR03</rdeDom:clID>
      <rdeDom:crRr>RAR03</rdeDom:crRr>
      <rdeDom:crDate>2019-12-26T14:18:40.65647Z</rdeDom:crDate>
      <rdeDom:exDate>2020-12-26T14:18:40.509742Z</rdeDom:exDate>
</rdeDom:domain>

  

On voit que cela ressemble en effet beaucoup à ce qui avait été envoyé en EPP pour créer le domaine (cf. RFC 5731). Si vous voulez un exemple complet et réaliste, regardez les sections 14 et 15 du RFC.

Et voici un exemple de contact (RFC 5733) :

    
<rdeContact:contact>
      <rdeContact:id>IZT01</rdeContact:id>
      <rdeContact:status s="ok"/>
      <rdeContact:postalInfo type="loc">
        <contact:name>John Doe</contact:name>
        <contact:addr>
          <contact:street>12 Rue de la Paix</contact:street>
          <contact:city>Paris</contact:city>
          <contact:pc>75002</contact:pc>
          <contact:cc>FR</contact:cc>
        </contact:addr>
      </rdeContact:postalInfo>
      <rdeContact:voice>+33.0353011234</rdeContact:voice>
      <rdeContact:email>john.doe@foobar.example</rdeContact:email>
      <rdeContact:clID>RAR03</rdeContact:clID>
      <rdeContact:crRr>RAR03</rdeContact:crRr>
      <rdeContact:crDate>2019-12-26T13:47:05.580392Z</rdeContact:crDate>
      <rdeContact:disclose flag="0">
        <contact:name type="loc"/>
        <contact:addr type="loc"/>
        <contact:voice/>
        <contact:fax/>
        <contact:email/>
      </rdeContact:disclose>
</rdeContact:contact>

  

On notera l'élement <disclose> qui indique qu'on ne doit pas diffuser le nom, l'adresse ou d'autres éléments sur le contact (normal, il s'agit d'une personne physique, et la loi Informatique & Libertés s'applique, cf. section 14 du RFC). La jointure avec les domaines dont il est contact (comme le jdoe.example plus haut), se fait sur l'identificateur (élément <id>, dit aussi handle). L'information sur l'adresse a le type loc, ce qui veut dire qu'elle peut utiliser tout le jeu de caractères Unicode. Avec le type int, elle serait restreinte à l'ASCII (une très ancienne erreur fait que EPP appelle loc - local, ce qui est internationalisé et int - international ce qui est restreint aux lettres utilisées en anglais).

Et enfin, un objet représentant un serveur de noms (RFC 5732) :


<rdeHost:host>
      <rdeHost:name>ns1.foobar.example</rdeHost:name>
      <rdeHost:status s="ok"/>
      <rdeHost:addr ip="v6">2001:db8:cafe:fada::53</rdeHost:addr>
      <rdeHost:clID>RAR02</rdeHost:clID>
      <rdeHost:crRr>RAR02</rdeHost:crRr>
      <rdeHost:crDate>2020-05-13T12:37:41.788684Z</rdeHost:crDate>
</rdeHost:host>         

  

Ce format de séquestre permet aussi de représenter des objets qui n'ont pas d'équivalent en EPP, comme les bureaux d'enregistrement, qui ne peuvent pas être créés en EPP puisque la session EPP est liée au client du registre, donc au bureau d'enregistrement. Un exemple de BE (Bureau d'Enregistrement) :


<rdeRegistrar:registrar>
      <rdeRegistrar:id>RAR21</rdeRegistrar:id>
      <rdeRegistrar:name>Name Business</rdeRegistrar:name>
      <rdeRegistrar:status>ok</rdeRegistrar:status>
      <rdeRegistrar:postalInfo type="loc">
        <rdeRegistrar:addr>
          <rdeRegistrar:street>1 rue du Test</rdeRegistrar:street>
          <rdeRegistrar:city>Champignac</rdeRegistrar:city>
          <rdeRegistrar:cc>FR</rdeRegistrar:cc>
        </rdeRegistrar:addr>
      </rdeRegistrar:postalInfo>
      <rdeRegistrar:voice>+33.0639981234</rdeRegistrar:voice>
      <rdeRegistrar:fax>+33.0199001234</rdeRegistrar:fax>
      <rdeRegistrar:email>master-of-domains@namebusiness.example</rdeRegistrar:email>
</rdeRegistrar:registrar>    
 
  

On peut aussi mettre dans le séquestre des références vers ses tables IDN (que l'ICANN exige mais qui n'ont aucun intérêt). Plus intéressant, la possibilité de stocker dans le séquestre les listes de termes traités spécialement, par exemple interdits ou bien soumis à un examen manuel. Cela se nomme NNDN pour « NNDN's not domain name », oui, c'est récursif. Voici un exemple :


<rdeNNDN:NNDN>
     <rdeNNDN:uName>gros-mot.example</rdeNNDN:uName>
     <rdeNNDN:nameState>blocked</rdeNNDN:nameState>
     <rdeNNDN:crDate>2005-04-23T11:49:00.0Z</rdeNNDN:crDate>
   </rdeNNDN:NNDN>

  

Tous les registres n'ont pas les mêmes règles et le RFC décrit également les mécanismes qui permettent de spécifier dans le séquestre les contraintes d'intégrité spécifiques d'un registre. L'opérateur de séquestre, qui reçoit le fichier XML ou les fichiers CSV, est censé vérifier tout cela (autrement, il ne joue pas son rôle, s'il se contente de stocker aveuglément un fichier). La section 8 de notre RFC décrit plus en profondeur les vérifications recommandées, comme de vérifier que les contacts indiqués pour chaque domaine sont bien présents. Pour vérifier un séquestre, il faut importer beaucoup de schémas. Voici, la liste, sous forme d'une commande shell :

for schema in contact-1.0.xsd  host-1.0.xsd		rdeDomain-1.0.xsd     rdeIDN-1.0.xsd	    rgp-1.0.xsd domain-1.0.xsd	 rde-1.0.xsd		rdeEppParams-1.0.xsd  rdeNNDN-1.0.xsd	    secDNS-1.1.xsd epp-1.0.xsd	 rdeContact-1.0.xsd	rdeHeader-1.0.xsd     rdePolicy-1.0.xsd   eppcom-1.0.xsd	 rdeDnrdCommon-1.0.xsd	rdeHost-1.0.xsd       rdeRegistrar-1.0.xsd); do
   wget https://www.iana.org/assignments/xml-registry/schema/${schema}
done   
  

Ensuite, on importe (fichier escrow-wrapper.xsd) et on utilise xmllint sur l'exemple de séquestre de la section 14 du RFC (fichier escrow-example.xml) :

% xmllint --noout --schema wrapper.xsd escrow-example.xml                            
escrow-example.xml validates
  

Ouf, tout va bien, le registre nous a envoyé un séquestre correct.

Enfin, la syntaxe formelle de ce format figure dans la section 9 du RFC, dans le langage XML Schema.

Ce format est mis en œuvre par tous les TLD qui sont liés par un contrat avec l'ICANN. 1 200 TLD envoient ainsi un séquestre une fois par semaine à l'ICANN.

Le concept de séquestre pose de sérieux problèmes de sécurité car le ou les fichiers transmis sont typiquement à la fois confidentiels, et cruciaux pour assurer la continuité de service. Lors du transfert du fichier, le registre et l'opérateur de séquestre doivent donc vérifier tous les deux l'authenticité du partenaire, et la confidentialité de la transmission. D'autant plus qu'une bonne partie du fichier est composée de données personnelles.


Téléchargez le RFC 9022


L'article seul

Le spin bit de QUIC

Première rédaction de cet article le 28 mai 2021


Une bonne partie du travail à l'IETF sur le protocole QUIC avait tourné autour d'un seul bit de l'en-tête QUIC, le spin bit. Pourquoi ?

Ce bit intéressant apparait dans les paquets QUIC à en-tête court (cf. le RFC 9000), et a agité énormément d'électrons lors des discussions à l'IETF. Pour comprendre ces polémiques, il faut voir à quoi sert ce bit. Avec TCP, quelqu'un qui surveillait le réseau pouvait calculer un certain nombre de choses sur la connexion TCP, comme le RTT, par exemple, en observant le délai entre un octet et l'accusé de réception couvrant cet octet. Cela peut être utilisé pour régler le réseau de manière à améliorer les performances (mais ne rêvez pas : contrairement à ce qui a parfois été prétendu, aucun FAI ne va vous informer de la santé de vos connexions individuelles, ni vous aider à les optimiser). Mais c'est également un problème de vie privée (toute information que vous envoyez sur le réseau peut être utilisée à mauvais escient). L'une des idées fortes de QUIC est de réduire la vue présentée au réseau (RFC 8546) et donc de chiffrer au maximum ; avec QUIC, on ne peut plus trouver le RTT en examinant les paquets qui passent. Cela peut être un problème si on souhaite justement informer le réseau et les gens qui le gèrent. Le spin bit a donc pour but de donner un minimum d'informations explicitement (alors qu'avec TCP, on donne plein d'informations sans s'en rendre compte). Ce spin bit est public (il n'est pas dans la partie chiffrée du paquet) et est inversé par l'initiateur de la connexion à chaque aller-retour (section 17.4 du RFC). Cela permet donc d'estimer le RTT. Cette utilisation est par exemple mise en œuvre dans le programme spindump.

Ce spin bit est optionnel, puisqu'on a vu qu'il pouvait être mal utilisé. Le RFC précise qu'une mise en œuvre de QUIC doit permettre sa désactivation, globalement ou par connexion. Il ajoute que, même si le spin bit est activé, QUIC doit le débrayer pour au moins une connexion sur seize, choisie au hasard, pour que les gens qui veulent être discrets et donc coupent le spin bit ne soient pas trop séparables des autres. C'est un principe classique en protection de la vie privée : il ne faut pas se distinguer. Pendant une enquête de police, les gens qui ont éteint leur ordiphone peu avant les faits seront les premiers suspects…

Cet unique bit a suscité beaucoup de discussions pour sa petite taille. Si vous voulez en apprendre d'avantage, vous pouvez consulter l'Internet-Draft draft-andersdotter-rrm-for-rtt-in-quic (une technique compliquée mais qui contient une bonne explication du spin bit), ou bien le draft-martini-hrpc-quichr qui, globalement, était très enthousiaste en faveur de QUIC mais suggèrait la suppression du spin bit. Merci d'ailleurs à leurs auteurs, pour leurs explications qui m'ont beaucoup aidé. Il y a également l'article « Three Bits Suffice: Explicit Support for Passive Measurement of Internet Latency in QUIC and TCP » (la version finale du spin bit est différente mais l'article explique bien le principe).


L'article seul

Le protocole QUIC désormais normalisé

Première rédaction de cet article le 28 mai 2021


Le protocole de transport QUIC vient d'être normalisé, sous la forme de plusieurs RFC. QUIC, déjà largement déployé, peut changer pas mal de choses sur le fonctionnement de l'Internet, en remplaçant, au moins partiellement, TCP.

Je vais décrire les RFC en question plus longuement dans des articles spécifiques à chacun mais cet article est consacré à une vision de plus haut niveau : c'est quoi, QUIC, et à quoi ça sert ?

QUIC n'est pas un protocole d'application comme peuvent l'être HTTP ou SSH. Les utilisateurs ordinaires ne verront pas la différence, ils se serviront des mêmes applications, via les mêmes protocoles applicatifs. QUIC est un protocole de transport, donc un concurrent de TCP, dont il vise à résoudre certaines limites, notamment dans le contexte du Web. Quelles limites ? Pour comprendre, il faut revenir à ce à quoi sert la couche de transport (couche 4 du traditionnel modèle en couches). Placée entre les datagrammes d'IP, qui peuvent arriver ou pas, dans l'ordre ou pas, et les applications, qui comptent en général sur un flux d'octets ordonnés, où rien ne manque, la couche transport est chargée de surveiller l'arrivée des paquets, de signaler à l'émetteur qu'il en manque, qu'il puisse réémettre, et de mettre dans le bon ordre les données. Dit comme ça, cela semble simple, mais cela soulève beaucoup de problèmes intéressants. Par exemple, il ne faut pas envoyer toutes les données sans réfléchir : le réseau n'est peut-être pas capable de les traiter, et un envoi trop brutal pourrait mener à la congestion. De même, en cas de pertes de paquet, il faut certes ré-émettre, mais aussi diminuer le rythme d'envoi, la perte pouvant être le signal que le réseau est saturé. C'est à la couche transport de gérer cette congestion, en essayant de ne pas la déclencher, ou en tout cas de ne pas l'aggraver. En pratique, la couche transport est donc très complexe, comme le montre le nombre de RFC sur TCP. Si la norme de base reste le vieux RFC 793, de nombreux autres RFC sont également à prendre en compte (le RFC 7414 vous fournit une liste commentée, mais qui n'est plus à jour).

Maintenant que nous avons révisé les tâches de la couche transport, quelles sont ces limites de TCP dont je parlais, et qui justifient le développement de QUIC ? Notez d'abord qu'elles ont surtout été mentionnées dans le contexte du Web. Celui-ci pose en effet des problèmes particuliers, notamment le désir d'une faible latence (quand on clique, on veut une réponse tout de suite) et le fait que l'affichage d'une seule page nécessite le chargement de plusieurs ressources (images sans intérêt, vidéos agaçantes, code JavaScript pour faire bouger des trucs, CSS, etc). La combinaison de TCP et de TLS n'est pas satisfaisante question latence, puisqu'il faut d'abord établir la connexion TCP, avant de pouvoir commencer la négociation qui mènera à l'établissement de la session TLS (il existe des solutions partielles comme le TCP Fast Open du RFC 7413, mais qui n'est pas protégé par la cryptographie, ou la session resumption du RFC 8446, section 2.2). Ensuite, TCP souffre du manque de parallélisme : quand on veut récupérer plusieurs ressources, il faut soit ouvrir plusieurs connexions TCP, qui ne partageront alors plus d'information (RTT, taux de perte, etc) ou de calculs (cryptographie…), et consommeront potentiellement beaucoup de ports, soit multiplexer à l'intérieur d'une connexion TCP, ce que fait HTTP/2 (RFC 7540) mais, alors, on risque le head-of-line blocking, où la récupération d'une ressource bloque les suivantes, et le fait que la perte d'un seul paquet va faire ralentir tous les téléchargements. Cela ne veut pas dire que TCP est complètement dépassé : largement testé au feu depuis de nombreuses années, il déplace chaque jour d'innombrables octets, pour des connexions qui vont de la courte page HTML à des fichiers de plusieurs giga-octets.

Quels sont les concepts de base de QUIC ? QUIC gère des connexions entre machines, comme TCP. Par contre, contrairement à TCP, ces connexions portent ensuite des ruisseaux (streams) séparés, ayant leur propre contrôle de congestion, en plus du contrôle global à la connexion. Les ruisseaux peuvent être facilement et rapidement créés. Ce n'est pas par hasard que le concept ressemble à celui des ruisseaux de HTTP/2 (RFC 7540), dans les deux cas, le but était de s'adapter au désir des navigateurs Web de charger toutes les ressources d'une page en parallèle, sans pour autant « payer » l'établissement d'une connexion pour chaque ressource.

Avec QUIC, le chiffrement est obligatoire. Il n'y a pas de version de QUIC en clair. Non seulement les données applicatives sont chiffrées, comme avec TLS ou SSH mais une bonne partie de la couche transport l'est également. Pourquoi ?

  • En raison de la prévalence de la surveillance massive sur l'Internet (RFC 7258) ; moins on expose de données, moins il y a de risques.
  • Afin d'éviter que les middleboxes ne se croient capables d'analyser le fonctionnement de la couche transport, et ne se croient autorisées à y intervenir, ce qui mène à une ossification de l'Internet. Si tout est chiffré, on pourra faire évoluer le protocole sans craindre l'intervention de ces fichus intermédiaires.
  • Certains FAI ont déjà exploité le caractère visible de TCP (RFC 8546) pour des attaques, par exemple en envoyant des paquets RST (ReSeT) pour couper le trafic BitTorrent. TLS et SSH ne protègent pas contre ce genre d'attaques. (Mais QUIC ne protège pas complètement ; le problème est difficile car il faut bien permettre aux machines terminales de réclamer une coupure de la connexion.)
  • L'observation de la couche transport peut permettre d'identifier les services utilisés et d'en dé-prioritiser certains. Le chiffrement du transport peut donc aider à préserver la neutralité du réseau.

On peut prévoir que les habituels adversaires du chiffrement protesteront d'ailleurs contre QUIC, en l'accusant de gêner la visibilité (ce qui est bien le but). Voir par exemple le RFC 8404 et même le RFC 9065. On voit ainsi un fabricant de produits de sécurité qui conseille carrément de bloquer QUIC. Qu'est-ce que vont dire ces adversaires du chiffrement lorsqu'on aura des VPN sur QUIC, comme ce sur quoi travaille le bien nommé groupe MASQUE !

QUIC utilise le classique protocole TLS (RFC 8446) pour le chiffrement mais pas de la manière habituelle. Normalement, TLS fait la poignée de main initiale, l'échange des clés et le chiffrement des données. Avec QUIC, TLS ne fait que la poignée de main initiale et l'échange des clés. Une fois les clés obtenues, QUIC chiffrera tout seul comme un grand, en utilisant les clés fournies par TLS.

Puisqu'on a parlé des middleboxes : déployer un nouveau protocole de transport dans l'Internet d'aujourd'hui est très difficile, en raison du nombre d'équipements qui interfèrent avec le trafic (les routeurs NAT, par exemple). Conceptuellement, QUIC aurait pu tourner directement sur IP. Mais il aurait alors été bloqué dans beaucoup de réseaux. D'où le choix de ses concepteurs de le faire passer sur UDP. (Le protocole de transport SCTP avait eu ce problème et a dû se résigner à la même solution, cf. RFC 6951.) QUIC utilise UDP comme il utiliserait IP. On lit parfois que QUIC, ce serait « HTTP au-dessus d'UDP », mais c'est une grosse incompréhension. QUIC est une couche de transport complète, concurrente de TCP, dont le fonctionnement sur UDP n'est qu'un détail nécessaire au déploiement. QUIC n'a aucune des propriétés d'UDP. Par exemple, comme TCP, mais contrairement à UDP, QUIC teste la réversibilité du trafic, ce qui empêche l'usurpation d'adresses IP et toutes les attaques UDP qui reposent dessus.

QUIC est parfois présenté comme « tournant en mode utilisateur et pas dans le noyau (du système d'exploitation) ». En fait, ce n'est pas spécifique à QUIC. Tout protocole de transport peut être mis en œuvre en mode utilisateur ou noyau (et il existe des mises en œuvre de TCP qui fonctionnent en dehors du noyau). Mais il est exact qu'en pratique la plupart des mises en œuvre de QUIC ne sont pas dans le noyau du système, l'expérience prouvant que les mises à jour du système sont souvent trop lentes, par rapport au désir de faire évoluer en permanence la couche transport. Ceci dit, la norme ne l'impose pas et n'en parle même pas. (On peut ajouter aussi que, dans beaucoup de systèmes d'exploitation, il est plus facile à un programme utilisateur de tourner sur UDP que directement sur IP. Par exemple, sur Unix, tourner directement sur IP nécessite d'utiliser les prises brutes et donc d'être root.) Et puis, sur Windows, Google n'aime pas dépendre de Microsoft pour les performances de son navigateur.

Pour résumer les différences entre QUIC et TCP (rappelez-vous qu'ils assurent à peu près les mêmes fonctions) :

  • QUIC est systématiquement chiffré,
  • QUIC permet un vrai multiplexage ; la requête lente ne bloque pas la rapide, et la perte d'un paquet ne ralentit pas tous les ruisseaux multiplexés,
  • QUIC fusionne transport et chiffrement, ce qui permet notamment de diminuer la latence à l'établissement de la connexion,
  • QUIC permet la migration d'une connexion en cas de changement d'adresse IP (je n'en ai pas parlé ici, voir RFC 9000).

Les RFC normalisant QUIC sont :

  • RFC 9000 est la norme principale, décrivant le socle de base de QUIC,
  • RFC 9001 normalise l'utilisation de TLS avec QUIC,
  • RFC 9002 spécifie les mécanismes de récupération de QUIC, quand des paquets sont perdus et qu'il faut ré-émettre, sans pour autant écrouler le réseau,
  • RFC 8999 est consacré aux invariants de QUIC, aux points qui ne changeront pas dans les nouvelles versions de QUIC.

J'ai dit que QUIC, comme TCP, est un protocole de transport généraliste, et qu'on peut faire tourner plusieurs applications différentes dessus. En pratique, QUIC a été conçu essentiellement en pensant à HTTP mais dans le futur, d'autres protocoles pourront profiter de QUIC, notamment s'ils ont des problèmes qui ressemblent à ceux du Web (désir de faible latence, et de multiplexage).

Pour HTTP, la version de HTTP qui tourne sur QUIC se nomme HTTP/3 et sera normalisée plus tard. Comme HTTP/2 (RFC 7540), HTTP/3 a un encodage binaire mais il ne fait plus de multiplexage, celui-ci étant désormais assuré par QUIC. Pour d'autres protocoles, les curieux pourront s'intéresser à SMB (déjà géré par Wireshark), au DNS (draft-ietf-dprive-dnsoquic) ou SSH (draft-bider-ssh-quic). En moins sérieux, il y a même eu des discussions pour mettre IRC sur QUIC, mais ce n'est pas allé très loin.

QUIC a eu une histoire longue et compliquée. À l'origine, vers 2012, QUIC était un projet Google (documenté dans « QUIC: Multiplexed Transport Over UDP », article qui ne reflète pas le QUIC actuel). Si les motivations étaient les mêmes que celles du QUIC actuel, et que certains concepts étaient identiques, il y avait quand même deux importantes différences techniques : le QUIC de Google utilisait un protocole de cryptographie spécifique, au lieu de TLS, et il était beaucoup plus marqué pour son utilisation par HTTP uniquement. Et il y a aussi bien sûr une différence politique, QUIC était un protocole privé d'une entreprise particulière, il est maintenant une norme IETF. Le travail à l'IETF a commencé en 2016 à la réunion de Séoul. Les discussions à l'IETF ont été chaudes et prolongées, vu l'importance du projet. Après tout, il s'agit de remplacer, au moins partiellement, le principal protocole de transport de l'Internet. C'est ce qui explique qu'il se soit écoulé plus de quatre ans entre le premier projet IETF et ces RFC. Vous pouvez avoir une idée de ce travail en visitant le site Web du groupe de travail ou en admirant les milliers de tickets traités.

Questions mises en œuvre de QUIC (elles sont nombreuses), je vous renvoie à mon article sur le RFC 9000. Le déploiement de QUIC a commencé il y a longtemps puisque Google l'avait déjà mis dans Chrome et ses services. En 2017, Google annonçait que QUIC représentait déjà 7 % du trafic vers ses serveurs. Bon, c'était le QUIC de Google, on va voir ce que cela va donner pour celui de l'IETF, mais le point important est que le déploiement n'a pas attendu les RFC.

Quelques lectures sur QUIC :


L'article seul

Une courte session QUIC avec explications

Première rédaction de cet article le 28 mai 2021


On va voir ici quelques exemples QUIC, avec explications des paquets échangés. On saute directement dans les détails donc, si ce n'est pas déjà fait, je recommande de commencer par l'article d'introduction à QUIC.

Comme on ne peut pas facilement utiliser tcpdump ou Wireshark (mais lisez cet article jusqu'au bout, j'explique à la fin) pour analyser une communication QUIC (tout est systématiquement chiffré), on va se servir d'un client QUIC qui a la gentillesse d'afficher en détail ce qu'il fait, en l'occurrence picoquic. Pour le compiler :

# La bibliothèque picotls
git clone https://github.com/h2o/picotls.git
cd picotls
git submodule init
git submodule update
cmake .
make
cd ..

# picoquic
git clone https://github.com/private-octopus/picoquic.git
cd picoquic
cmake .
make
  

Puis on va utiliser le programme client picoquicdemo pour se connecter en HTTP/3 à un serveur public, mettons f5quic.com :

% ./picoquicdemo -l /tmp/quic.txt f5quic.com 4433 '0:index.html'
  

La ligne de commande ci-dessus lance picoquicdemo, enregistre les informations dans le fichier /tmp/quic.txt, se connecte à f5quic.com sur le port 4433 et récupère le fichier index.html (qui n'existe pas mais peu importe, une réponse 404 nous suffit).

Parmi les messages affichés, vous verrez :

No token file present. Will create one as <demo_token_store.bin>.
  

Ces jetons (tokens) sont définis dans le RFC 9000, section 8.1.1. Générés par le serveur, ils servent à s'assurer que le client reçoit bien les réponses, donc qu'il n'a pas usurpé son adresse IP. Ce test de retournabilité permet de se protéger contre les imposteurs. Comme c'est la première fois que nous lançons le client, il est normal qu'il n'ait pas encore de jeton.

Le fichier de résultat est téléchargeable ici, quic-demo-0.txt. Décortiquons-le :

efed1e171949e7a6: Sending ALPN list (8): h3-32, hq-32, h3-31, hq-31, h3-29, hq-29, h3-30, hq-30
  

La chaîne de caractères efed1e171949e7a6 est le Connection ID (RFC 9000, section 5.1). QUIC utilise ALPN (RFC 7301) pour indiquer l'application à lancer à l'autre bout. h3-32 est HTTP/3, draft version 32 (dans le futur RFC, l'ALPN sera h3).

efed1e171949e7a6: Sending transport parameter TLS extension (89 bytes):
  

Diverses extensions au protocole TLS comme Extension type: 9 (max_streams_uni), length 2, 4201 qui indique le nombre maximum de ruisseaux QUIC dans la connexion. Rappelez-vous que QUIC fusionne la traditionnelle couche transport et le chiffrement. Les paramètres de transport sont donc envoyés sous forme d'extensions TLS (RFC 9001, section 8.2). Ces paramètres figurent dans un registre IANA. Vous pouvez y vérifier que 9 est initial_max_streams_uni.

efed1e171949e7a6: Sending packet type: 2 (initial), S0, Q1, Version ff000020,
  

Les choses sérieuses démarrent. Le client envoie un paquet de type Initial marquant son désir d'ouvrir une connexion QUIC. Les types de paquets ne sont pas dans un registre IANA, leur liste limitative figure dans le RFC 9000, notamment dans la section 17.2. La version de QUIC désirée est ff000020, ce qui était la dernière version de développement. Aujourd'hui, ce serait Version 1. (La liste des versions, pour l'instant réduite, est dans un registre IANA.)

efed1e171949e7a6:     Crypto HS frame, offset 0, length 335: 0100014b030372b6...
efed1e171949e7a6:     padding, 867 bytes
  

Ce premier paquet contient une trame QUIC de type CRYPTO (RFC 9000, section 19.6), avec les paramètres cryptographiques, et du remplissage, pour atteindre la taille miminum imposée de 1 200 octets (RFC 9000, section 8.1)

efed1e171949e7a6: Sending 1252 bytes to 40.112.191.60:4433 at T=0.002156 (5bc54cac22aa1)
efed1e171949e7a6: Receiving 1200 bytes from 40.112.191.60:4433 at T=0.169086 (5bc54cac4b6b3)
  

Parfait, on a envoyé le paquet, et reçu une réponse. Petit rappel : l'information de base dans QUIC est transmise dans des trames, les trames voyagent dans un paquet, les paquets sont placés dans des datagrammes UDP. Il peut y avoir plusieurs paquets dans un datagramme et plusieurs trames dans un paquet. Déchiffrons maintenant la réponse :


efed1e171949e7a6: Receiving packet type: 2 (initial), S0, Q1, Version ff000020,
efed1e171949e7a6:     <b3efa80036784b1f>, <041eb19906b9ca99>, Seq: 0, pl: 149
...
efed1e171949e7a6:     ACK (nb=0), 0
efed1e171949e7a6:     Crypto HS frame, offset 0, length 123: 02000077030314b7...

  

Le serveur a répondu avec son propre paquet Initial (cf. RFC 9000, section 7, figure 4). Ensuite, il nous serre la main :

efed1e171949e7a6: Receiving packet type: 4 (handshake), S0, Q1, Version ff000020,
efed1e171949e7a6:     Crypto HS frame, offset 0, length 979: 0800006400620010...
efed1e171949e7a6: Received transport parameter TLS extension (82 bytes):
...

On est d'accord, on envoie nous aussi un Handshake :

efed1e171949e7a6: Sending packet type: 4 (handshake), S0, Q0, Version ff000020,
  

(Il y a en fait plusieurs paquets Handshake.)

efed1e171949e7a6: Receiving packet type: 6 (1rtt protected), S0, Q0,
...
efed1e171949e7a6: Sending packet type: 6 (1rtt protected), S1, Q0,
efed1e171949e7a6:     Prepared 1414 bytes
efed1e171949e7a6:     ping, 1 bytes
efed1e171949e7a6:     padding, 1413 bytes
  

Cette fois, la connexion est établie. On peut maintenant échanger des paquets de type 1-RTT, le type de paquet général, qui sert pour tout sauf au début de la connexion. ping et padding sont des types de trames (RFC 9000, section 19). Les différents types de trames sont dans un registre IANA. ping sert à déclencher l'envoi d'un accusé de réception, qui montrera que l'autre machine est bien vivante. padding fait du remplissage pour gêner l'analyse de trafic. Maintenant, c'est bon, le travail est fait, on peut raccrocher :


efed1e171949e7a6: Sending packet type: 6 (1rtt protected), S0, Q0,
efed1e171949e7a6:     <041eb19906b9ca99>, Seq: 4 (4), Phi: 0,
efed1e171949e7a6:     Prepared 8 bytes
efed1e171949e7a6:     ACK (nb=0), 0-4
efed1e171949e7a6:     application_close, Error 0x0000, Reason length 0

efed1e171949e7a6: Sending 34 bytes to 40.112.191.60:4433 at T=0.334640 (5bc54cac73d65)
efed1e171949e7a6: Receiving 37 bytes from 40.112.191.60:4433 at T=0.489651 (5bc54cac99ae8)
efed1e171949e7a6: Receiving packet type: 6 (1rtt protected), S0, Q1,
efed1e171949e7a6:     <b3efa80036784b1f>, Seq: 5 (5), Phi: 0,
efed1e171949e7a6:     Decrypted 11 bytes
efed1e171949e7a6:     application_close, Error 0x0000, Reason length 8
efed1e171949e7a6:         Reason: No error

  

Tout va bien, on a envoyé un paquet de type 1-RTT qui contient l'alerte TLS application_close, la connexion est fermée.

Ici, on n'avait demandé qu'un seul fichier (index.html). Mais l'usage normal du Web est de demander plusieurs ressources, puisque l'affichage d'une page nécessite en général de nombreuses ressources (CSS, JavaScript, images…). Avec QUIC, ces différentes demandes peuvent être faites sur des ruisseaux différents, pour un maximum de parallélisme :

% ./picoquicdemo -l /tmp/quic.txt f5quic.com 4433 '0:index.html;100:foobar.html'
...
Opening stream 0 to GET /index.html
Opening stream 100 to GET /foobar.html
...

Et dans le fichier contenant les détails (quic-demo-1.txt), on va trouver cette fois des messages concernant ce ruisseau n° 100 :

    
7f0a5c80d9f66dab: Sending packet type: 6 (1rtt protected), S0, Q1,
7f0a5c80d9f66dab:     Stream 100, offset 0, length 32, fin = 1: 011e0000d1d7510c...
...
7f0a5c80d9f66dab: Receiving packet type: 6 (1rtt protected), S0, Q0,
7f0a5c80d9f66dab:     Stream 100, offset 0, length 245, fin = 0: 013e0000db5f4d91...
...

  

On a vu que la première connexion n'avait pas de jeton. Stocker un jeton reçu du serveur permet de faire du « zéro-RTT », c'est-à-dire d'envoyer des données dès le premier paquet transmis. Si on recommence la même commande picoquicdemo, le programme va lire le jeton précédemment obtenu, et stocké dans le fichier demo_token_store.bin, et s'en servir :

The session was properly resumed!
Zero RTT data is accepted!

Vous pouvez voir le résultat dans le fichier complet (quic-demo-2.txt). Après le paquet de type Initial, au lieu d'un type Handshake, on attaque directement avec un paquet de type 0-RTT :

119d7339e68827df: Sending packet type: 5 (0rtt protected), S0, Q1, Version ff000020,
   

Et si on veut quand même utiliser l'excellent Wireshark, dont les versions les plus récentes savent décoder QUIC ? D'abord, sans truc particulier, on peut voir la partie non chiffrée des paquets QUIC. D'abord avec tshark, la version texte de Wireshark analysant un pcap pris en communiquant avec le serveur public de Microsoft (le pcap a été enregistré avec un tcpdump -w /tmp/quic-microsoft.pcap host msquic.net and udp and port 443 :

% tshark  -r  /tmp/quic-microsoft.pcap
1   0.000000 10.168.234.1 → 138.91.188.147 QUIC 1294 Initial, DCID=9b4dccfc42f8ab9c, SCID=cf4d6e8c2c7b43a2, PKN: 0, CRYPTO, PADDING
2   0.170410 138.91.188.147 → 10.168.234.1 QUIC 1294 Handshake, DCID=cf4d6e8c2c7b43a2, SCID=09fa3e7edeb3b621ae
3   0.170550 138.91.188.147 → 10.168.234.1 QUIC 1294 Handshake, DCID=cf4d6e8c2c7b43a2, SCID=09fa3e7edeb3b621ae
4   0.170558 138.91.188.147 → 10.168.234.1 QUIC 1108 Protected Payload (KP0), DCID=cf4d6e8c2c7b43a2
5   0.171689 10.168.234.1 → 138.91.188.147 QUIC 331 Protected Payload (KP0), DCID=09fa3e7edeb3b621ae
6   0.171765 10.168.234.1 → 138.91.188.147 QUIC 1514 Protected Payload (KP0), DCID=09fa3e7edeb3b621ae
  

On voit que les paquets d'établissement de la connexion, Initial et Handshake ne sont pas chiffrés (on n'a pas encore négocié les paramètres cryptographiques). On voit même que le paquet Initial contient deux trames, CRYPTO et PADDING (pour atteindre la taille minimale, imposée pour éviter les attaques avec amplification). tshark affiche les connections ID (DCID = destination et SCID = source). Une fois la cryptographie configurée, on ne voit plus grand'chose, la taille des paquets, et le connection ID de la destination (il s'agit de paquets à en-tête court, qui n'incluent pas le connection ID de la source). Même les paquets à la fin, qui terminent la connexion, ne sont pas décodables.

Voyons cette partie non chiffrée plus en détail avec l'option -V :

User Datagram Protocol, Src Port: 44873, Dst Port: 443
    Source Port: 44873
    Destination Port: 443
    Length: 1260
    UDP payload (1252 bytes)
QUIC IETF
    QUIC Connection information
        [Connection Number: 0]
    [Packet Length: 1252]
    1... .... = Header Form: Long Header (1)
    .1.. .... = Fixed Bit: True
    ..00 .... = Packet Type: Initial (0)
    .... 00.. = Reserved: 0
    .... ..11 = Packet Number Length: 4 bytes (3)
    Version: 1 (0x00000001)
    Destination Connection ID Length: 8
    Destination Connection ID: 9b4dccfc42f8ab9c
    Source Connection ID Length: 8
    Source Connection ID: cf4d6e8c2c7b43a2
    Token Length: 0
    Length: 1226
    Packet Number: 0
    Payload: 03c99cd0b086b40241f66768c1806ae00bcfa9f7db97593669e784fa326c83f89aac54d2…
    TLSv1.3 Record Layer: Handshake Protocol: Client Hello
        Frame Type: CRYPTO (0x0000000000000006)
        Offset: 0
        Length: 393
        Crypto Data
        Handshake Protocol: Client Hello
            Handshake Type: Client Hello (1)
            Length: 389
	    ...
            ALPN Next Protocol: h3
	    ...
	    Extension: quic_transport_parameters (len=85)
                Type: quic_transport_parameters (57)
		...
                Parameter: initial_max_data (len=4) 1048576
                    Type: initial_max_data (0x04)
                    Length: 4
                    Value: 80100000
                    initial_max_data: 1048576
		...
                Parameter: max_idle_timeout (len=4) 30000 ms
                    Type: max_idle_timeout (0x01)
                    Length: 4
                    Value: 80007530
                    max_idle_timeout: 30000
                 ...
  

Il s'agit du paquet Initial, à en-tête long (le premier bit), incluant un classique Client Hello TLS, qui comprend notamment une demande ALPN pour HTTP/3, et les paramètres de transport spécifique à QUIC. La réponse du serveur inclut deux paquets QUIC (n'oubliez pas qu'un datagramme UDP peut transporter plusieurs paquets QUIC, chacun pouvant transporter plusieurs trames, ce qui est le cas du premier paquet, qui inclut une trame ACK et une trame CRYPTO) :

User Datagram Protocol, Src Port: 443, Dst Port: 44873
    Source Port: 443
    Destination Port: 44873
    Length: 1260
    UDP payload (1252 bytes)
QUIC IETF
    QUIC Connection information
        [Connection Number: 0]
    [Packet Length: 179]
    1... .... = Header Form: Long Header (1)
    .1.. .... = Fixed Bit: True
    ..00 .... = Packet Type: Initial (0)
    .... 00.. = Reserved: 0
    .... ..11 = Packet Number Length: 4 bytes (3)
    Version: 1 (0x00000001)
    Destination Connection ID Length: 8
    Destination Connection ID: cf4d6e8c2c7b43a2
    Source Connection ID Length: 9
    Source Connection ID: 09fa3e7edeb3b621ae
    Token Length: 0
    Length: 152
    Packet Number: 0
    ACK
        Frame Type: ACK (0x0000000000000002)
        Largest Acknowledged: 0
        ACK Delay: 16
        ACK Range Count: 0
        First ACK Range: 0
    TLSv1.3 Record Layer: Handshake Protocol: Server Hello
        Frame Type: CRYPTO (0x0000000000000006)
        Offset: 0
        Length: 123
        Crypto Data
        Handshake Protocol: Server Hello
	...
QUIC IETF
    [Packet Length: 1073]
    1... .... = Header Form: Long Header (1)
    .1.. .... = Fixed Bit: True
    ..10 .... = Packet Type: Handshake (2)
    Version: 1 (0x00000001)
    Destination Connection ID Length: 8
    Destination Connection ID: cf4d6e8c2c7b43a2
    Source Connection ID Length: 9
    Source Connection ID: 09fa3e7edeb3b621ae
    Length: 1047
    [Expert Info (Warning/Decryption): Failed to create decryption context: Secrets are not available]
    ...
  

Le deuxième paquet, le Handshake est déjà chiffré.

Cette analyse peut aussi être faite avec l'interface graphique de Wireshark : wireshark-quic-1.png

Maintenant, si on veut aller plus loin et fouiller dans la partie chiffrée des paquets ? Il faut pour cela que l'application écrive les clés utilisées pendant la connexion dans un fichier, et qu'on dise à Wireshark d'utiliser ce fichier pour déchiffrer. Si l'application utilise une bibliothèque qui permet d'inscrire les clés de session dans un fichier, comme OpenSSL ou picotls, on peut la convaincre d'écrire ces clés en définissant la variable d'environnement SSLKEYLOGFILE. Par exemple :

% export  SSLKEYLOGFILE=/tmp/quic.key 

%  ./picoquicdemo  msquic.net  443  '0:index.html'

% cat /tmp/quic.key
SERVER_HANDSHAKE_TRAFFIC_SECRET 0469b5f648c6aece6b78338f4453f38d39a1527a5564458631a8d221c0d10ffa dc21c8a9927bc196a48e670c4920b26a4b9bdba8bfc5d610c055def0bda3f3cdc8062a90992b228e1f02b659ddc0bfec
CLIENT_HANDSHAKE_TRAFFIC_SECRET 0469b5f648c6aece6b78338f4453f38d39a1527a5564458631a8d221c0d10ffa 53b7105c924b3f5ae1e8cda70f0b5f20119a267ba462e027e645bf1b762f490f4ee2deef2cde93feace61cdd56c708a1
SERVER_TRAFFIC_SECRET_0 0469b5f648c6aece6b78338f4453f38d39a1527a5564458631a8d221c0d10ffa 683e037fb3e1d6451d1edce1d638fc4271859d32c164ee7c9c5b16e9761abfd97d2f91ea5c8141f4b8d7f2b9bdc36cc8
CLIENT_TRAFFIC_SECRET_0 0469b5f648c6aece6b78338f4453f38d39a1527a5564458631a8d221c0d10ffa 2ca521c138a9e7ad66817b583c9a3423d1d2d92a0a51a7290e08d3e4707cc6a407fc7f389dde74ba6faeba19033492b7
  

Il faut ensuite dire à Wireshark d'utiliser ces clés. Dans les menus Edit Preferences Protocols TLS, on indique le nom du fichier dans (Pre-)-Master-Secret log filename. (Ou bien on édite le fichier de préférences de Wireshark, par exemple ~/.config/wireshark/preferences pour mettre tls.keylog_file: /tmp/quic.key.)

Désormais, Wireshark sait déchiffrer :

% tshark  -r  /tmp/quic-microsoft.pcap | more 
1   0.000000 10.168.234.1 → 138.91.188.147 QUIC 1294 Initial, DCID=345d144296b90cff, SCID=f50587894e0cd26c, PKN: 0, CRYPTO, PADDING
2   0.166722 138.91.188.147 → 10.168.234.1 HTTP3 1294 Protected Payload (KP0), DCID=f50587894e0cd26c, PKN: 2, STREAM(3), SETTINGS, STREAM(7), STREAM(11), PADDING
3   0.167897 10.168.234.1 → 138.91.188.147 QUIC 332 Protected Payload (KP0), DCID=d9e7940a80b4975407, PKN: 0, ACK, NCI, NCI, NCI, PADDING
4   0.167987 10.168.234.1 → 138.91.188.147 QUIC 1514 Protected Payload (KP0), DCID=d9e7940a80b4975407, PKN: 1, PING, PADDING
5   0.168550 10.168.234.1 → 138.91.188.147 HTTP3 225 Protected Payload (KP0), DCID=d9e7940a80b4975407, PKN: 2, STREAM(2), SETTINGS, STREAM(6
), STREAM(10), STREAM(0), HEADERS, PADDING
6   0.332156 138.91.188.147 → 10.168.234.1 QUIC 1294 Protected Payload (KP0), DCID=f50587894e0cd26c, PKN: 3, ACK, DONE, NCI, NCI, PADDING
7   0.332361 138.91.188.147 → 10.168.234.1 QUIC 1482 Protected Payload (KP0), DCID=f50587894e0cd26c, PKN: 4, PING, PADDING
8   0.332372 138.91.188.147 → 10.168.234.1 HTTP3 1294 Protected Payload (KP0), DCID=f50587894e0cd26c, PKN: 5, ACK, STREAM(7), STREAM(0), HEADERS
9   0.332375 138.91.188.147 → 10.168.234.1 HTTP3 177 Protected Payload (KP0), DCID=f50587894e0cd26c, PKN: 6, STREAM(0), DATA
10   0.332841 10.168.234.1 → 138.91.188.147 QUIC 77 Protected Payload (KP0), DCID=d9e7940a80b4975407, PKN: 3, ACK, CC
11   0.487969 138.91.188.147 → 10.168.234.1 QUIC 80 Protected Payload (KP0), DCID=f50587894e0cd26c, PKN: 7, ACK, CC
  

On voit que la communication était utilisée pour HTTP/3 et on peut suivre les détails, comme les types de trame utilisés. Même chose avec l'option -V, on voit la totalité des paquets, ici un datagramme envoyé par le client :

User Datagram Protocol, Src Port: 56785, Dst Port: 443
    Source Port: 56785
    Destination Port: 443
    Length: 191
    UDP payload (183 bytes)
QUIC IETF
    QUIC Connection information
        [Connection Number: 0]
    [Packet Length: 183]
    QUIC Short Header DCID=d9e7940a80b4975407 PKN=2
        0... .... = Header Form: Short Header (0)
        .1.. .... = Fixed Bit: True
        ..1. .... = Spin Bit: True
        ...0 0... = Reserved: 0
        .... .0.. = Key Phase Bit: False
        .... ..00 = Packet Number Length: 1 bytes (0)
        Destination Connection ID: d9e7940a80b4975407
        Packet Number: 2
    STREAM id=2 fin=0 off=0 len=7 uni=1
        Frame Type: STREAM (0x000000000000000a)
            .... ...0 = Fin: False
            .... ..1. = Len(gth): True
            .... .0.. = Off(set): False
        Stream ID: 2
        Length: 7
    STREAM id=6 fin=0 off=0 len=1 uni=1
        Frame Type: STREAM (0x000000000000000a)
            .... ...0 = Fin: False
            .... ..1. = Len(gth): True
            .... .0.. = Off(set): False
        Stream ID: 6
        Length: 1
    STREAM id=10 fin=0 off=0 len=1 uni=1
        Frame Type: STREAM (0x000000000000000a)
            .... ...0 = Fin: False
            .... ..1. = Len(gth): True
            .... .0.. = Off(set): False
        Stream ID: 10
        Length: 1
    STREAM id=0 fin=1 off=0 len=31 uni=0
        Frame Type: STREAM (0x000000000000000b)
            .... ...1 = Fin: True
            .... ..1. = Len(gth): True
            .... .0.. = Off(set): False
        Stream ID: 0
        Length: 31
    PADDING Length: 104
        Frame Type: PADDING (0x0000000000000000)
        [Padding Length: 104]
...
Hypertext Transfer Protocol Version 3
    Type: HEADERS (0x0000000000000001)
    Length: 29
    Frame Payload: 0000d1d7510b2f696e6465782e68746d6c500a6d73717569632e6e6574
  

Le datagramme comprend un seul paquet, qui contient cinq trames, quatre de données (type STREAM) et une de remplissage (type PADDING). Dans les données se trouve une requête HTTP/3.

Graphiquement, on voit aussi davantage de détails : wireshark-quic-2.png

Si vous voulez regarder vous-même avec Wireshark, et que vous n'avez pas de client QUIC pour créer du trafic, les fichiers quic-microsoft.pcap et quic.key sont disponibles.


L'article seul

RFC 9001: Using TLS to Secure QUIC

Date de publication du RFC : Mai 2021
Auteur(s) du RFC : M. Thomson (Mozilla), S. Turner (sn3rd)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF quic
Première rédaction de cet article le 28 mai 2021


Le protocole de transport QUIC est toujours sécurisé par la cryptographie. Il n'y a pas de communication en clair avec QUIC. Cette sécurisation se fait actuellement par TLS mais QUIC utilise TLS d'une manière un peu spéciale, documentée dans ce RFC.

Fini d'hésiter entre une version avec TLS ou une version sans. Avec QUIC, c'est forcément chiffré et, pour l'instant, avec TLS (dans le futur, QUIC pourra utiliser d'autres protocoles, mais ce n'est pas encore défini). QUIC impose en prime au minimum TLS 1.3 (RFC 8446), qui permet notamment de diminuer la latence, la communication pouvant s'établir dans certains cas dès le premier paquet. Petit rappel de TLS, pour commencer : TLS permet d'établir un canal sûr, fournissant authentification du serveur et confidentialité de la communication, au-dessus d'un media non-sûr (l'Internet). TLS est normalement constitué de deux couches, la couche des enregistrements (record layer) et celle de contenu (content layer), qui inclut notamment le mécanisme de salutation initial. On établit une session avec le protocole de salutation (handshake protocol), puis la couche des enregistrements chiffre les données (application data) avec les clés issues de cette salutation. Les clés ont pu être créées par un échange Diffie-Helman, ou bien être pré-partagées (PSK, pour Pre-Shared Key), ce dernier cas permettant de démarrer la session immédiatement (« 0-RTT »).

QUIC utilise TLS d'une façon un peu spéciale. Certains messages TLS n'existent pas comme ChangeCipherSpec ou KeyUpdate (QUIC ayant ses propres mécanismes pour changer la cryptographie en route, cf. section 6), et, surtout, la couche des enregistrements disparait, QUIC faisant le chiffrement selon son format, mais avec les clés négociées par TLS.

La poignée de mains qui établit la session TLS peut donc se faire de deux façons :

  • « 1-RTT » où le client et le serveur peuvent envoyer des données après un aller-retour (RTT). Rappelez-vous que c'est ce temps d'aller-retour qui détermine la latence, donc la « vitesse » perçue par l'utilisateur, au moins pour les transferts de faible taille (comme le sont beaucoup de ressources HTML).
  • « 0-RTT », où le client peut envoyer des données dès le premier datagramme transmis. Cette façon de faire nécessite que client et serveur se soient parlés avant, et que le client ait stocké un jeton généré par le serveur (sept jours maximum, dit le RFC 8446), qui permettra au serveur de trouver tout de suite le matériel cryptographique nécessaire. Attention, le 0-RTT ne protège pas contre le rejeu, mais ce n'est pas grave pour des applications comme HTTP avec la méthode GET, qui est idempotente. Et le 0-RTT pose également problème avec la PFS (la confidentialité même en cas de compromission ultérieure des clés).

La section 3 du RFC fait un tour d'horizon général du protocole TLS tel qu'utilisé par QUIC. Comme vu plus haut, la couche des enregistrements (record layer) telle qu'utilisée avec TCP n'est plus présente, les messages TLS comme Handshake et Alert sont directement transportés sur QUIC (qui, contrairement à TCP, permet d'assurer confidentialité et intégrité). Avec TCP, la mise en couches était stricte, TLS étant entièrement au-dessus de TCP, avec QUIC, l'intégration est plus poussée, QUIC et TLS coopèrent, le premier chiffrant avec les clés fournies par le second, et QUIC transportant les messages de TLS. De même, quand on fait tourner un protocole applicatif sur QUIC, par exemple HTTP/3, celui-ci est directement placé sur QUIC, TLS s'effaçant complètement. Les applications vont donc confier leurs données à QUIC, pas à TLS. En simplifiant (beaucoup…), on pourrait dire que TLS ne sert qu'au début de la connexion. Pour citer Radia Perlman, « It is misleading to regard this as a specification of running QUIC over TLS. It is related to TLS in the same way that DTLS is related to TLS: it imports much of the syntax, but there are many differences and its security must be evaluated largely independently. My initial reaction to this spec was to wonder why it did not simply run QUIC over DTLS . I believe the answer is that careful integration improves the performance and is necessary for some of the address agility/transition design. ».

La section 4 explique plus en détail comment les messages TLS sont échangés via QUIC. Les messages cryptographiques sont transportés dans des trames de type CRYPTO. Par exemple, le ClientHello TLS sera dans une trame CRYPTO elle-même située dans un paquet QUIC de type Initial. Les Alert sont dans des trames CONNECTION_CLOSE dont le code d'erreur est l'alerte TLS. Ce sont les seuls messages que QUIC passera à TLS, il fait tout le reste lui-même.

On a vu que le principal travail de TLS est de fournir du matériel cryptographique à QUIC. Plus précisément, TLS fournit, après sa négociation avec son pair :

QUIC se servira de tout cela pour chiffrer.

QUIC impose une version minimale de TLS : la 1.3, normalisée dans le RFC 8446. Les versions ultérieures sont acceptées mais elles n'existent pas encore.

Ah et, comme toujours avec TLS, le client doit authentifier le serveur, typiquement via son certificat. Le serveur ne doit pas utiliser les possibilités TLS de ré-authentification ultérieure (message CertificateRequest) car le multiplexage utilisé par QUIC empêcherait de corréler cette demande d'authentification avec une requête précise du client.

Outre le « 0-RTT » de QUIC, qui permet au client d'envoyer des données applicatives dès le premier paquet, QUIC+TLS fournit un autre mécanisme pour gagner du temps à l'établissement de la connexion, la reprise de session (session resumption, RFC 8446, section 2.2). Si le client a enregistré les informations nécessaires depuis une précédente session avec ce serveur, il peut attaquer directement avec un NewSessionTicket dans une trame CRYPTO et abréger ainsi l'établissement de session TLS.

Les erreurs TLS, comme bad_certificate, unexpected_message ou unsupported_extension, sont définies dans le RFC 8446, section 6. Dans QUIC, elles sont transportées dans des trames de type CONNECTION_CLOSE, et mises dans le champ d'erreur (Error Code, RFC 9000, section 19.19). Notez que ces trames mènent forcément à la coupure de toute la session QUIC, et il n'y a donc pas moyen de transporter un simple avertissement TLS.

Bien, maintenant qu'on a vu le rôle de TLS, comment QUIC va-t-il utiliser les clés pour protéger les paquets ? La section 5 répond à cette question. QUIC va utiliser les clés fournies par TLS (je simplifie, car QUIC effectue quelques dérivations avant) comme clés de chiffrement intègre (RFC 5116). Il utilisera l'algorithme de chiffrement symétrique indiqué par TLS. Tous les paquets ne sont pas protégés (par exemple ceux de négociation de version, inutiles pour l'instant puisque QUIC n'a qu'une version, ne bénéficient pas de protection puisqu'il faudrait connaitre la version pour choisir les clés de protection). Le cas des paquets Initial est un peu plus subtil puisqu'ils sont chiffrés, mais avec une clé dérivée du connection ID, qui circule en clair. Donc, en pratique, seule leur intégrité est protégée, par leur confidentialité (cf. section 7 pour les conséquences).

J'ai dit que QUIC n'utilisait pas directement les clés fournies par TLS. Il applique en effet une fonction de dérivation, définie dans la section 7.1 du RFC 8446, elle-même définie à partir des fonctions du RFC 5869.

Il existe plein de pièges et de détails à prendre en compte quand on met en œuvre QUIC+TLS. Par exemple, en raison du réordonnancement des datagrammes dans le réseau, et des pertes de datagrammes, un paquet chiffré peut arriver avant le matériel cryptographique qui permettrait de le déchiffrer, ou bien avant que les affirmations du pair aient été validées. La section 5.7 du RFC explique comment gérer ce cas (en gros, jeter les paquets qui sont « en avance », ou bien les garder pour déchiffrement ultérieur mais ne surtout pas tenter de les traiter). Autre piège, QUIC ignore les paquets dont la vérification d'intégrité a échoué, alors que TLS ferme la connexion. Cela a pour conséquences qu'avec QUIC un attaquant peut essayer plusieurs fois. Il faut donc compter les échecs et couper la connexion quand un nombre maximal a été atteint (section 6.6). Bien sûr, pour éviter de faciliter une attaque par déni de service (où l'attaquant enverrait plein de mauvais paquets dans l'espoir de fermer la connexion), ces limites doivent être assez hautes (2^23 paquets pour AEAD_AES_128_GCM), voir « Limits on Authenticated Encryption Use in TLS » ou « Robust Channels: Handling Unreliable Networks in the Record Layers of QUIC and DTLS 1.3 », ainsi que l'annexe B du RFC.

Encore question détails subtils, la poignée de mains de TLS n'est pas tout à fait la même quand elle est utilisée par QUIC (section 8). Ainsi, ALPN doit être utilisé et avec succès, autrement on raccroche avec l'erreur no_application_protocol.

Le but de TLS est de fournir de la sécurité, notamment confidentialité et authentification, donc il est recommandé de bien lire la section 9, qui traite de la sécurité de l'ensemble du RFC. Ainsi, si on utilise les tickets de session de TLS (RFC 8446, section 4.6.1), comme ils sont transmis en clair, ils peuvent permettre à un observateur de relier deux sessions, même si les adresses IP sont différentes.

Le « 0-RTT » est formidable pour diminuer la latence, mais il diminue aussi la sécurité : il n'y a pas de protection contre le rejeu. Si QUIC lui-même n'est pas vulnérable au rejeu, l'application qui travaille au-dessus de QUIC peut l'être. Prenez un protocole applicatif qui aurait des services comme, en HTTP, « envoyez-moi une pizza » (sans doute avec la méthode POST), on voit bien que le rejeu serait problématique. Bref, les applications qui, contrairement au protocole QUIC, ne sont pas idempotentes, ont tout intérêt à désactiver le 0-RTT.

QUIC tournant sur UDP, qui ne protège pas contre l'usurpation d'adresse IP, il existe en théorie un risque d'attaque par réflexion, avec amplification. Par exemple, la réponse à un ClientHello peut être bien plus grande que le ClientHello lui-même. Pour limiter les risques, QUIC impose que le premier paquet du client ait une taille minimale (pour réduire le facteur d'amplification), en utilisant le remplissage, et que le serveur ne réponde pas avec plus de trois fois la quantité de données envoyée par le client, tant que l'adresse IP de celui-ci n'a pas été validée.

Plus sophistiquées sont les attaques par canal auxiliaire. Par exemple, si une mise en œuvre de QUIC jette trop vite les paquets invalides, un attaquant qui mesure les temps de réaction pourra en déduire des informations sur ce qui n'allait pas exactement dans son paquet. Il faut donc que toutes les opérations prennent un temps constant.

Et puis, bien sûr, comme tout protocole utilisant la cryptographie, QUIC+TLS a besoin d'un générateur de nombres aléatoires correct (cf. RFC 4086).

Question mise en œuvre, notez qu'on ne peut pas forcément utiliser une bibliothèque TLS quelconque. Il faut qu'elle permette de séparer signalisation et chiffrement et qu'elle permette d'utiliser QUIC comme transport. (Et il n'y a pas d'API standard pour cela.) C'est par exemple le cas de la bibliothèque picotls. Pour OpenSSL, il faut attendre (un patch existe) et cela bloque parfois l'intégration de certains logiciels.

Et question tests, à ma connaissance, on ne peut pas actuellement utiliser openssl s_client ou gnutls-cli avec un serveur QUIC. Même problème avec le fameux site de test TLS https://ssllabs.com/.

Pour terminer, voici l'analyse d'une communication QUIC+TLS, analyse faite avec Wireshark. D'abord, le premier paquet, de type QUIC Initial, qui contient le ClientHello dans une trame de type CRYPTO :

QUIC IETF
    1... .... = Header Form: Long Header (1)
    .1.. .... = Fixed Bit: True
    ..00 .... = Packet Type: Initial (0)
    .... 00.. = Reserved: 0
    .... ..11 = Packet Number Length: 4 bytes (3)
    Version: 1 (0x00000001)
    Destination Connection ID Length: 8
    Destination Connection ID: 345d144296b90cff
...
    Length: 1226
    Packet Number: 0
    TLSv1.3 Record Layer: Handshake Protocol: Client Hello
        Frame Type: CRYPTO (0x0000000000000006)
        Offset: 0
        Length: 384
        Crypto Data
        Handshake Protocol: Client Hello
            Handshake Type: Client Hello (1)
            Length: 380
            ...
            Extension: quic_transport_parameters (len=85)
                Type: quic_transport_parameters (57)
                Length: 85
                Parameter: initial_max_stream_data_bidi_local (len=4) 2097152
                    Type: initial_max_stream_data_bidi_local (0x05)
                    Length: 4
                    Value: 80200000
                    initial_max_stream_data_bidi_local: 2097152
             ...
  

Dans les extensions TLS, notez l'extension spécifique à QUIC, quic_transport_parameters. QUIC « abuse » de TLS en s'en servant pour emballer ses propres paramètres. (La liste de ces paramètres de transport figure dans un registre IANA.)

La réponse à ce paquet Initial contiendra le ServerHello TLS. La poignée de mains se terminera avec les paquets QUIC de type Handshake. TLS ne servira plus par la suite, QUIC chiffrera tout seul.


Téléchargez le RFC 9001


L'article seul

RFC 9002: QUIC Loss Detection and Congestion Control

Date de publication du RFC : Mai 2021
Auteur(s) du RFC : J. Iyengar (Fastly), I. Swett (Google)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF quic
Première rédaction de cet article le 28 mai 2021


Pour tout protocole de transport, détecter les pertes de paquets, et être capable d'émettre et de réémettre des paquets sans provoquer de congestion sont deux tâches essentielles. Ce RFC explique comment le protocole QUIC assure cette tâche.

Pour l'instant, TCP reste le principal protocole de transport sur l'Internet. Mais QUIC pourrait le dépasser. QUIC est normalisé dans une série de RFC et notre RFC 9002 se charge d'une tâche délicate et cruciale : expliquer comment détecter les pertes de paquets, et comment ne pas contribuer à la congestion. Voyons d'abord la conception générale (section 3 du RFC). Les messages QUIC sont mis dans des trames, une ou plusieurs trames sont regroupées dans un paquet (qui n'est pas un paquet IP) et un ou plusieurs paquets sont dans un datagramme UDP qu'on envoie à son correspondant. Les paquets ont un numéro (RFC 9000, section 12.3). Ces numéros ne sont pas des numéros des octets dans les données envoyées, notamment, un numéro de paquet ne se répète jamais dans une connexion. Alors qu'on peut envoyer les mêmes données plusieurs fois, s'il y a perte et réémission ; en cas de retransmission, les données sont renvoyées dans un nouveau paquet, avec un nouveau numéro, contrairement à TCP. Cela permet de savoir facilement si c'est une retransmission. (TCP, lui, essaie de déduire l'ordre de distribution du numéro de séquence, et ce n'est pas trivial.)

La plupart des paquets QUIC feront l'objet d'un accusé de réception mais attention. Il y a des trames dont le type exige un accusé de réception et d'autres non. Si un paquet ne contient que des trames n'exigeant pas d'accusé de réception, ce paquet ne sera confirmé par le récepteur qu'indirectement, lors de la réception d'un paquet ultérieur contenant au moins une trame exigeant un accusé de réception.

QUIC n'est pas TCP, cela vaut la peine de le rappeler. La très intéressante section 4 du RFC enfonce le clou en énumérant les différences entre les algorithmes de TCP et ceux de QUIC, pour assurer les mêmes fonctions. Ainsi, dans TCP, tous les octets sont numérotés selon un seul espace de numérotation (les numéros de séquence) alors que QUIC a plusieurs espaces, les paquets servant à établir la connexion ne partagent pas leurs numéros avec ceux des données. QUIC fonctionne ainsi car les premiers sont moins protégés par la cryptographie.

Pour TCP, le numéro de séquence indique à la fois l'ordre d'émission et l'ordre de l'octet dans le flux de données. Le problème de cette approche est que, en cas de retransmission, le numéro de séquence n'indique plus l'ordre d'émission, rendant difficile de distinguer une émission initiale et une retransmission (ce qui serait pourtant bien utile pour estimer le RTT). Au contraire, dans QUIC, le numéro de paquet n'identifie que l'ordre d'émission. La retransmission a donc forcément un numéro supérieur à l'émission initiale. Pour déterminer la place des octets dans le flux de données, afin de s'assurer que l'application reçoive les données dans l'ordre, QUIC utilise le champ Offset des trames de type STREAM, celles qui transmettent les données (RFC 9000, section 19.8). QUIC a ainsi moins d'ambiguités, par exemple quand il faut mesurer le taux de pertes.

QUIC, comme TCP, doit estimer le temps optimum pour décider qu'un paquet est perdu (RTO, pour Retransmission TimeOut). QUIC est plus proche de l'algorithme du RFC 8985 que du TCP classique. La section 5 du RFC détaille l'estimation du RTT.

La section 6 porte sur le problème délicat de la détection des pertes de paquets. La plupart des paquets QUIC doivent faire l'objet d'un accusé de réception. S'il n'est pas arrivé avant un temps limite, le paquet est décrété perdu, et il faudra demander une réémission (RFC 9000, section 13.3). Plus précisement, le paquet est considéré comme perdu s'il avait été envoyé avant un paquet qui a fait l'objet d'un accusé de réception et s'il s'est écoulé N paquets depuis ou bien un temps suffisamment long. (TCP fait face à exactement le même défi, et la lecture des RFC 5681, RFC 5827, RFC 6675 et RFC 8985 est recommandée.) La valeur recommandée pour N est 3, pour être proche de TCP. Mais attention si le réseau fait que les paquets arrivent souvent dans le désordre, cela pourrait mener à des paquets considérés à tort comme perdus. Le problème existait déjà pour TCP mais il est pire avec QUIC puisque des équipements intermédiaires sur le réseau qui remettaient les paquets dans l'ordre ne peuvent plus fonctionner avec QUIC, qui chiffre le plus de choses possibles pour éviter ces interventions souvent maladroites. Et le délai avant lequel on déclare qu'un paquet est perdu ? Il doit tenir compte du RTT qu'on doit donc mesurer.

Une fois la ou les pertes détectées, on réémet les paquets. Simple, non ? Sauf qu'il faut éviter que cette réémission n'aggrave les problèmes et ne mène à la congestion (le réseau, trop chargé, perd des paquets, les émetteurs réémettent, chargeant le réseau, donc on perd davantage de paquets, donc les émetteurs réémettent encore plus…). L'algorithme actuellement spécifié pour QUIC (section 7 du RFC) est proche du NewReno de TCP (normalisé dans le RFC 6582). Mais le choix d'un algorithme de contrôle de l'émetteur est unilatéral, et une mise en œuvre de QUIC peut toujours en choisir un autre, comme Cubic (RFC 8312). Évidemment, pas question d'être le gros porc qui s'attribue toute la capacité réseau pour lui seul, et cet algorithme doit de toute façon respecter les principes du RFC 8085 (en résumé : ne soyez pas égoïste, et pensez aux autres, laissez-leur de la capacité).

Pour aider à cette lutte contre la congestion, QUIC, comme TCP, peut utiliser ECN (RFC 3168 et RFC 8311).

Comme TCP, QUIC doit démarrer une nouvelle session doucement (RFC 6928) et non partir bille en tête avec une fenêtre de grande taille.

La réaction aux pertes de paquets peut avoir des conséquences sur la sécurité (section 8 du RFC). Par exemple, les « signaux » utilisés par QUIC pour décider qu'il y a eu une perte (l'absence d'un paquet, le RTT, ECN) ne sont pas protégés par la cryptographie, contrairement aux données transportées et à certaines métadonnées. Un attaquant actif peut fausser ces signaux et mener QUIC à réduire son débit. Il n'y a pas vraiment de protection contre cela. Autre risque de sécurité, alors que QUIC est normalement conçu pour priver un observateur de beaucoup d'informations qui, avec TCP étaient en clair, il n'atteint pas 100 % de succès dans ce domaine. Par exemple les paquets ne contenant que des accusés de réception (trames de type ACK) peuvent être identifiés par leur taille (ils sont tout petits), et l'observateur peut alors en déduire des informations sur les performances du chemin. Si on veut éviter cela, il faut utiliser le remplissage des accusés de réception.

Vous aimez lire des programmes ? L'annexe A du RFC contient du pseudo-code mettant en œuvre les mécanismes de récupération décrits dans le RFC.


Téléchargez le RFC 9002


L'article seul

RFC 8999: Version-Independent Properties of QUIC

Date de publication du RFC : Mai 2021
Auteur(s) du RFC : M. Thomson (Mozilla)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF quic
Première rédaction de cet article le 28 mai 2021


Ce RFC, qui fait partie de la première fournée sur QUIC, décrit les invariants du protocole QUIC, les choses qui ne changeront pas dans les futures versions de QUIC.

Comme tous les protocoles Internet, QUIC doit faire face à l'ossification, cette tendance à rendre les changements impossibles, en raison du nombre de composants du réseau qui refusent tout comportement qu'ils n'attendaient pas, même si c'était une évolution prévue ou en tout cas possible. Une des méthodes pour limiter cette ossification est la documentation d'invariants, des parties du protocole dont on promet qu'elles ne changeront pas dans les futures versions. Tout le reste peut bouger et les équipements comme les middleboxes peuvent donc s'appuyer sur ce RFC pour faire les choses proprement, en sachant ce qui durera longtemps, et ce qui est susceptible d'évoluer.

La section 15 du RFC 9000 explique le principe des versions de QUIC. QUIC est actuellement à la version 1. C'est la seule pour l'instant. Mais si une version 2 (puis 3, puis 4…) apparait un jour, il faudra négocier la version utilisée entre les deux parties (section 6 du RFC 9000). Ces nouvelles versions pourront améliorer le protocole, répondant à des phénomènes qui ne sont pas forcément prévisibles. Par exemple QUIC v1 utilise forcément TLS pour la sécurité (RFC 9001), mais les futures versions pourront peut-être utiliser un autre protocole cryptographique, plus sûr, ou plus rapide. L'expérience de nombreux protocoles IETF est qu'il est difficile de déployer une nouvelle version d'un protocole déjà en place, car il y a toujours des équipements dans le réseau qui faisaient des suppositions sur le protocole, qui ne sont plus vraies avec la nouvelle version (et, souvent même pas avec l'ancienne…) et qui pertuberont, voire couperont la communication. D'où cette idée de documenter les invariants, en indiquant donc clairement que tout ce qui n'est pas invariant… peut changer. Un exemple d'invariant est « A QUIC packet with a long header has the high bit of the first byte set to 1. All other bits in that byte are version specific. ». Actuellement (version 1), le deuxième bit vaut forcément 1 (RFC 9000, section 17.2), mais ce n'est pas un invariant : les autres versions feront peut-être différemmment.

Concevoir des invariants est tout un art. Trop d'invariants et QUIC ne peut plus évoluer. Pas assez d'invariants et ils ne servent plus à rien. Ainsi, il semble difficile de faire un répartiteur de charge qui marche avec toutes les futures versions de QUIC (pas assez d'invariants pour lui).

Et dans les paquets, qu'est-ce qui sera invariant ? (Petit rappel au passage, un datagramme UDP peut contenir plusieurs paquets QUIC.) Il y a deux sortes de paquets, les longs et les courts. (Plus rigoureusement, ceux à en-tête long et ceux à en-tête court.) On les distingue par le premier bit. Tous les autres bits du premier octet sont spécifiques d'une version particulière de QUIC, et ne sont donc pas invariants. Ce premier octet est suivi d'un numéro de version sur 32 bits (aujourd'hui, forcément 1, sauf en cas de négociation de version, non encore spécifiée), puis du connection ID de la destination (attention : longueur variable, dans les paquets longs, il est encodé sous forme longueur puis valeur, cela permettra d'avoir des identificateurs de connexion très longs dans le futur) puis, mais seulement pour les paquets longs, du connection ID de la source. Tout le reste du paquet dépend de la version de QUIC utilisée.

Notez que la longueur des paquets n'étant pas dans les invariants, on ne peut même pas trouver combien il y a de paquets QUIC dans un datagramme de manière indépendante de la version.

L'identificateur de connexion est une donnée opaque : la façon de le choisir pourra varier dans le futur.

Bien sûr, spécifier rigoureusement les invariants n'empêchera pas les middleboxes de tirer des fausses conclusions et, par exemple, de généraliser des comportements de la version 1 de QUIC à toutes les versions ultérieures (section 7 du RFC). L'annexe A donne une liste (sans doute incomplète) des suppositions qu'un observateur pourrait faire mais qui sont erronées. QUIC essaie de réduire ce qu'on peut observer, en chiffrant au maximum, afin de limiter ces suppositions erronées, mais il reste des choses visibles, qui ne sont pas forcément invariantes. Le RFC écrit ces suppositions de manière neutre, en notant qu'elles sont fausses. J'ai préféré rédiger en insistant sur leur fausseté. Donc, rappelez-vous que, notamment dans les futures versions de QUIC :

  • QUIC n'utilise pas forcément TLS,
  • les paquets longs peuvent apparaitre même après l'établissement de la connexion,
  • il n'y aura pas toujours de phase de connexion au début,
  • le dernier paquet avant une période de silence n'est pas forcément uniquement un accusé de réception,
  • les numéros de paquet ne croissent pas forcément de un à chaque paquet,
  • ce n'est pas toujours le client qui parle le premier,
  • les connection ID peuvent changer très vite,
  • le second bit du premier octet, parfois appelé à tort le « QUIC bit », n'est pas forcément à un, et il avait même été proposé de le faire varier (ce qu'on appelle le graissage, cf. RFC 8701),
  • et plusieurs autres points.

À noter que le numéro de version n'apparait que dans les paquets longs. Un programme qui observe des paquets QUIC de versions différentes ne peut donc analyser les paquets courts que s'il a mémorisé les numéros de versions correspondant à chaque connection ID de destination qu'il voit.

Autre point important : il n'y a pas d'invariant qui identifie un paquet QUIC. Pas de nombre magique ou de chose équivalente. Donc, aucun moyen d'être raisonnablement sûr que ce qui passe est du QUIC. C'est bien sûr volontaire, pour augmenter les chances que la neutralité soit respectée. Mais cela peut amener des middleboxes agressives à essayer de deviner si c'est bien du QUIC ou pas, en se trompant. (Le « QUIC bit » n'est évidemment pas une preuve suffisante, il peut s'agir d'un autre protocole où ce bit vaut 1.)


Téléchargez le RFC 8999


L'article seul

RFC 9000: QUIC: A UDP-Based Multiplexed and Secure Transport

Date de publication du RFC : Mai 2021
Auteur(s) du RFC : J. Iyengar (Fastly), M. Thomson (Mozilla)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF quic
Première rédaction de cet article le 28 mai 2021


Le protocole de transport QUIC vient d'être normalisé, dans une série de quatre RFC. J'ai écrit un résumé synthétique de QUIC, cet article porte sur le principal RFC du groupe, celui qui normalise le cœur de QUIC, le mécanisme de transport des données. QUIC, comme TCP, fournit aux protocoles applicatifs un service de transport des données fiable, et en prime avec authentification et confidentialité.

L'un des buts principaux de QUIC est de réduire la latence. La capacité des réseaux informatiques augmente sans cesse, et va continuer de la faire, alors que la latence sera bien plus difficile à réduire. Or, elle est déterminante dans la perception de « vitesse » de l'utilisateur. Quels sont les problèmes que pose actuellement l'utilisation de TCP, le principal protocole de transport de l'Internet ?

  • Head-of-line blocking, quand une ressource rapide est bloquée par une lente située avant elle dans la file, ou quand la perte d'un seul paquet TCP bloque toute la connexion en attendant que les données manquantes soient réémises. Si on multiplexe au-dessus de TCP, comme le fait HTTP/2 (RFC 7540), tous les ruisseaux d'une même connexion doivent attendre.
  • Latence due à l'ouverture de la session TLS, d'autant plus que TCP et TLS étant découplés, TLS doit attendre que TCP ait fini pour commencer sa négociation.

Le cahier des charges de QUIC était à peu près :

  • Déployable aujourd'hui, sans changement important de l'Internet. Compte-tenu du nombre de boitiers intermédiaires intrusifs (cf. RFC 7663), cela exclut le développement d'un nouveau protocole de transport reposant directement sur IP : il faut passer sur TCP ou UDP. Les solutions « révolutionnaires » ont donc été abandonnées immédiatement.
  • Faible latence, notamment pour le démarrage de la session.
  • Meilleure gestion de la mobilité (ne pas casser les sessions si on change de connectivité).
  • Assurer la protection de la vie privée au moins aussi bien qu'avec TCP+TLS (donc, tout chiffrer). Le chiffrement ne sert d'ailleurs pas qu'à gêner la surveillance : il a aussi pour but d'empêcher les modifications que se permettent bien des FAI.
  • Services aux applications à peu près semblables à ceux de TCP (distribution fiable et ordonnée des données).
  • Coexistence heureuse avec TCP, aucun des deux ne doit prendre toute la capacité au détriment de l'autre (cf. RFC 5348). QUIC, comme TCP, contrôle la quantité de données envoyées, pour ne pas écrouler le réseau.

Certains de ces objectifs auraient pu être atteints en modifiant TCP. Mais TCP étant typiquement mis en œuvre dans le noyau du système d'exploitation, tout changement de TCP met un temps trop long à se diffuser. En outre, si les changements à TCP sont importants, ils peuvent être bloqués par les boitiers intermédiaires, comme si c'était un nouveau protocole.

QUIC peut donc, plutôt qu'à TCP, être comparé à SCTP tournant sur DTLS (RFC 8261), et on peut donc se demander pourquoi ne pas avoir utilisé ce système. C'est parce que :

  • La latence pour établir une session est très élevée. SCTP et DTLS étant deux protocoles séparés, il faut d'abord se « connecter » avec DTLS, puis avec SCTP (RFC 8261, section 6.1).
  • Cette séparation de SCTP et DTLS fait d'ailleurs que d'autres tâches sont accomplies deux fois (alors que dans QUIC, chiffrement et transport sont intégrés, cf. RFC 9001).

Pour une comparaison plus détaillée de SCTP et QUIC, voir l'Internet-Draft draft-joseph-quic-comparison-quic-sctp. (SCTP peut aussi tourner sur UDP - RFC 6951 mais j'ai plutôt utilisé SCTP sur DTLS comme point de comparaison, pour avoir le chiffrement.) Notez que ces middleboxes intrusives sont particulièrement répandues dans les réseaux pour mobiles, type 4G (où elles sont parfois appelée TCP proxies), puisque c'est un monde où on viole bien plus facilement la neutralité du réseau.

Faire mieux que TCP n'est pas évident. Ce seul RFC fait 207 pages, et il y a d'autres RFC à lire. Déjà, commençons par un peu de terminologie :

  • Client et serveur ont le sens habituel, le client est l'initiateur de la connexion QUIC, le serveur est le répondeur,
  • Un paquet QUIC n'est pas forcément un datagramme IP ; plusieurs paquets peuvent se trouver dans un même datagramme envoyé sur UDP,
  • Certains paquets déclenchent l'émission d'un accusé de réception (ACK-eliciting packets) mais pas tous,
  • Dans un paquet, il y a plusieurs unités de données, les trames. Il existe plusieurs types de trames, par exemple PING sert uniquement à déclencher l'accusé de réception, alors que STREAM contient des données de l'application.
  • Une adresse est la combinaison d'une adresse IP, et d'un port. Elle sert à identifier une extrémité du chemin entre client et serveur mais pas à identifier une connexion.
  • L'identifiant de connexion (CID, connection ID) joue ce rôle. Il permet à QUIC de gérer les cas où un routeur NAT change le port source, ou bien celui où on change de type de connexion.
  • Un ruisseau (stream) est un canal de données à l'intérieur d'une connexion QUIC. QUIC multiplexe des ruisseaux. Par exemple, pour HTTP/3 (le RFC n'est pas encore publié), chaque ressource (image, feuille de style, etc) voyagera dans un ruisseau différent.

Maintenant, plongeons dans le RFC. Rappelez-vous qu'il est long ! Commençons par les ruisseaux (section 2 du RFC). Ils ressemblent aux ruisseaux de HTTP/2 (RFC 7540), ce qui est logique, QUIC ayant été conçu surtout en pensant à HTTP. Chaque ruisseau est un flux ordonné d'octets. Dans une même connexion QUIC, il y a plusieurs ruisseaux. Les octets d'un ruisseau sont reçus dans l'ordre où ils ont été envoyés (plus exactement, QUIC doit fournir ce service mais peut aussi fournir un service dans le désordre), ce qui n'est pas forcément le cas pour les octets d'une même connexion. (Dans le cas de HTTP, cela sert à éviter qu'une ressource lente à se charger ne bloque tout le monde.) Comme avec TCP, les données sont un flot continu, même si elles sont réparties dans plusieurs trames. La création d'un ruisseau est très rapide, il suffit d'envoyer une trame avec l'identifiant d'un ruisseau et hop, il est créé. Les ruisseaux peuvent durer très longtemps, ou au contraire tenir dans une seule trame.

J'ai parlé de l'identifiant d'un ruisseau. Ce numéro, ce stream ID est pair pour les ruisseaux créés par le client, impair s'ils sont créés par le serveur. Cela permet à client et serveur de créer des ruisseaux sans se marcher sur les pieds. Un autre bit dans l'identifiant indique si le ruisseau est bidirectionnel ou unidirectionnel.

Une application typique va donc créer un ou plusieurs ruisseaux, y envoyer des données, en recevoir, et fermer les ruisseaux, gentiment (trame STREAM avec le bit FIN) ou brutalement (trame RESET_STREAM). La machine à états complète des ruisseaux figure dans la section 3 du RFC.

Comme avec TCP, il ne s'agit pas d'envoyer des données au débit maximum, sans se soucier des conséquences. Il faut se contrôler, à la fois dans l'intérêt du réseau (éviter la congestion) et dans celui du récepteur, qui a peut-être du mal à traiter tout ce qu'on lui envoie. D'où, par exemple, la trame STOP_SENDING qui dit à l'émetteur de se calmer.

Plus fondamentalement, le système de contrôle de QUIC est décrit dans la section 4. Il fonctionne aussi bien par ruisseau qu'au niveau de toute la connexion. C'est le récepteur qui contrôle ce que l'émetteur peut envoyer, en disant « j'accepte au total N octets ». Il le fait à l'établissement de la connexion puis, lorsqu'il peut à nouveau traiter des données, via les trames MAX_DATA (pour l'ensemble de la connexion) et MAX_STREAM_DATA (valables, elles, pour un seul ruisseau). Normalement, les quantités d'octets que l'émetteur peut envoyer sont toujours croissantes. Par exemple, à l'établissement de la connexion, le récepteur annonce qu'il peut traiter 1 024 octets. Puis, une fois qu'il a des ressources disponibles, il signalera qu'il peut traiter 2 048 octets. Si l'émetteur ne lui avait transmis que 1 024, cette augmentation lui indiquera qu'il peut reprendre l'émission. Si l'émetteur envoie plus de données qu'autorisé, le récepteur ferme brutalement la connexion. À noter que les trames de type CRYPTO ne sont pas concernées car elles peuvent être nécessaires pour changer les paramètres cryptographiques (RFC 9001, section 4.1.3).

J'ai parlé des connexions QUIC mais pas encore dit comment elles étaient établies. La section 5 le détaille. Comme QUIC tourne sur UDP, un certain nombre de gens n'ont pas compris le rôle d'UDP et croient que QUIC est sans connexion. Mais c'est faux, QUIC impose l'établissement d'une connexion, c'est-à-dire d'un état partagé entre l'initiateur (celui qui sollicite une connexion) et le répondeur. La négociation initiale permettra entre autres de se mettre d'accord sur les paramètres cryptographiques, mais aussi sur le protocole applicatif utilisé (par exemple HTTP). QUIC permet d'envoyer des données dès le premier paquet (ce qu'on nomme le « 0-RTT ») mais rappelez-vous que, dans ce cas, vous n'êtes plus protégé contre les attaques par rejeu. Ce n'est pas grave pour un GET HTTP mais cela peut être gênant dans d'autres cas.

Une fonction essentielle aux connexions QUIC est le connection ID. Il s'agit d'un identificateur de la connexion, qui lui permettra notamment de survivre aux changements de connectivité (passage de 4G dehors en WiFi chez soi, par exemple) ou aux fantaisies des routeurs NAT qui peuvent subitement changer les ports utilisés. Quand un paquet QUIC arrive sur une machine, c'est ce connection ID qui sert à démultiplexer les paquets entrants, et à trouver les paramètres cryptographiques à utiliser pour le déchiffrer. Il n'y a pas qu'un connection ID mais tout un jeu, car, comme il circule en clair, il pourrait être utilisé pour suivre à la trace un utilisateur. Ainsi, quand une machine change d'adresse IP, la bonne pratique est de se mettre à utiliser un connection ID qui faisait partie du jeu de départ, mais n'a pas encore été utilisé, afin d'éviter qu'un surveillant ne fasse le rapprochement entre les deux adresses IP. Notez que le jeu de connection ID négocié au début peut ensuite être agrandi avec des trames NEW_CONNECTION_ID.

Dans quel cas un port peut-il changer ? QUIC utilise UDP, pour maximiser les chances de passer à travers les pare-feux et les routeurs NAT. Cela pose des problèmes si le boitier intermédiaire fait des choses bizarres. Par exemple, si un routeur NAT décide de mettre fin à une connexion TCP qui n'a rien envoyé depuis longtemps, il peut génerer un message RST (ReSeT) pour couper la connexion. Rien de tel en UDP, où le routeur NAT va donc simplement supprimer de sa table de correspondance (entre adresses publiques et privées) une entrée. Après cela, les paquets envoyés par la machine externe seront jetés sans notification, ceux envoyés par la machine interne créeront une nouvelle correspondance, avec un port source différent et peut-être même une adresse IP source différente. La machine externe risque donc de ne pas les reconnaitre comme des paquets appartenant à la même connexion QUIC. En raison des systèmes de traduction d'adresses, l'adresse IP source et le port source vus par le pair peuvent changer pendant une même « session ». Pour permettre de reconnaitre une session en cours, QUIC utilise donc le connection ID, un nombre de longueur variable généré au début de la connexion (un dans chaque direction) et présent dans les paquets. (Le connection ID source n'est pas présent dans tous les paquets.)

Vous avez vu qu'une connexion QUIC peut parfaitement changer d'adresse IP en cours de route. Cela aura certainement des conséquences pour tous les systèmes qui enregistrent les adresses IP comme identificateur d'un dialogue, du journal d'un serveur HTTP (qu'est-ce que Apache va mettre dans son access_log ?) aux surveillances de la HADOPI.

Pour limiter les risques qu'une correspondance dans un routeur faisant de la traduction d'adresses n'expire, QUIC dispose de plusieurs moyens de keepalive comme les trames de type PING.

Comment l'application qui utilise QUIC va-t-elle créer des connexions et les utiliser ? La norme QUIC, dans notre RFC, ne spécifie pas d'API. Elle expose juste les services que doit rendre QUIC aux applications, notamment :

  • Ouvrir une connexion (si on est initiateur),
  • Attendre des demandes de connexions (si on est répondeur),
  • Activer les données early data, c'est-à-dire envoyées dès le premier paquet (rappelez-vous que le rejeu est possible donc l'application doit s'assurer que cette première requête est idempotente),
  • Configurer certaines valeurs comme le nombre maximal de ruisseaux ou comme la quantité de données qu'on est prêt à recevoir,
  • Envoyer des trames PING, par exemple pour s'assurer que la connexion reste ouverte,
  • Fermer la connexion.

Le RFC ne le spécifie pas, mais il faudra évidemment que QUIC permette à l'application d'envoyer et de recevoir des données.

Il n'y a actuellement qu'une seule version de QUIC, la 1, normalisée dans notre RFC 9000 (cf. section 15). Dans le futur, d'autres versions apparaitront peut-être, et la section 6 du RFC explique comment se fera la future négociation de version (ce qui sera un point délicat car il faudra éviter les attaques par repli). Notez que toute version future devra se conformer aux invariants du RFC 8999, une garantie de ce qu'on trouvera toujours dans QUIC.

Un point important de QUIC est qu'il n'y a pas de mode « en clair ». QUIC est forcément protégé par la cryptographie. L'établissement de la connexion impose donc la négociation de paramètres cryptographiques (section 7). Ces paramètres sont mis dans une trame CRYPTO qui fait partie du premier paquet envoyé. QUIC version 1 utilise TLS (RFC 9001). Le serveur est toujours authentifié, le client peut l'être. C'est aussi dans cette négociation cryptographique qu'est choisie l'application, via ALPN (RFC 7301).

Dans le cas courant, quatre paquets sont échangés, Initial par chacun des participants, puis Handshake. Mais, si le 0-RTT est accepté, des données peuvent être envoyées par l'initiateur dès le premier paquet.

Puisqu'UDP, comme IP, ne protège pas contre l'usurpation d'adresse IP, QUIC doit valider les adresses IP utilisées, pour éviter, par exemple, les attaques par réflexion (section 8). Si un initiateur contacte un répondeur en disant « mon adresse IP est 2001:db8:dada::1 », il ne faut pas le croire sur parole, et lui envoyer plein de données sans vérification. QUIC doit valider l'adresse IP de son correspondant, et le revalider lorsqu'il change d'adresse IP. À l'établissement de la connexion, c'est la réception du paquet Handshake, proprement chiffré, qui montre que le correspondant a bien reçu notre paquet Initial et a donc bien l'adresse IP qu'il prétend avoir. En cas de changement d'adresse IP, la validation vient du fait que le correspondant utilise un des connection ID qui avait été échangés précédemment ou d'un test explicite de joignabilité avec les trames PATH_CHALLENGE et PATH_RESPONSE. Sur ces migrations, voir aussi la section 9.

Pour les futures connexions, on utilisera un jeton qui avait été transmis dans une trame NEW_TOKEN et qu'on a stocké localement. (C'est ce qui permet le 0-RTT.) Le RFC ne spécifie pas le format de ce jeton, seule la machine qui l'a créé et qui l'envoie à sa partenaire a besoin de le comprendre (comme pour un cookie). Le RFC conseille également de n'accepter les jetons qu'une fois (et donc de mémoriser leur usage) pour limiter le risques de rejeu.

Tant que la validation n'a pas été faite, une machine QUIC ne doit pas envoyer plus de trois fois la quantité de données reçue (pour éviter les attaques avec amplification). C'est pour cela que le paquet Initial est rempli de manière à atteindre une taille (1 200 octets, exige le RFC) qui garantit que l'autre machine pourra répondre, même si elle a beaucoup à dire.

Une fois qu'on est connectés, on peut s'échanger des données, qui feront l'objet d'accusés de réception de la part du voisin (trames de type ACK). Contrairement au TCP classique, les accusés de réception ne sont pas forcément contigus, comme dans l'extension SACK du RFC 2018. Si l'accusé de réception n'est pas reçu, l'émetteur réémet, comme avec TCP.

Bon, une fois qu'on a ouvert la connexion, et échangé des données, quand on n'a plus rien à dire, que fait-on ? On raccroche. La section 10 du RFC explique comment se terminent les connexions QUIC. Cela peut se produire suite à une inactivité prolongée, suite à une fermeture explicite normale, ou bien avec le cas particulier de la fermeture sans état. Chacun des partenaires peut évidemment estimer que, s'il ne s'est rien passé depuis longtemps, il peut partir. (Cette durée maximale d'attente peut être spécifiée dans les paramètres à l'établissement de la connexion.) Mais on peut aussi raccrocher explicitement à tout moment (par exemple parce que le partenaire n'a pas respecté le protocole QUIC), en envoyant une trame de type CONNECTION_CLOSE. Cela fermera la connexion et, bien sûr, tous ses ruisseaux.

Pour que la trame CONNECTION_CLOSE soit acceptée par l'autre machine, il faut que son émetteur connaisse les paramètres cryptographiques qui permettront de la chiffrer proprement. Mais il y a un cas ennuyeux, celui où une des deux machines a redémarré, tout oublié, et reçoit des paquets d'une ancienne connexion. Comment dire à l'autre machine d'arrêter d'en envoyer ? Avec TCP, on envoie un paquet RST (ReSeT) et c'est bon. Mais cette simplicité est dangereuse car elle permet également à un tiers de faire des attaques par déni de service en envoyant des « faux » paquets RST. Des censeurs ou des FAI voulant bloquer du trafic pair-à-pair ont déjà pratiqué ce genre d'attaque. La solution QUIC à ce double problème est la fermeture sans état (stateless reset). Cela repose sur l'envoi préalable d'un jeton (cela peut se faire via un paramètre lors de l'établissement de la connexion, ou via une trame NEW_CONNECTION_ID). Pour pouvoir utiliser ces jetons, il faudra donc les stocker, mais il ne sera pas nécessaire d'avoir les paramètres cryptographiques : on ne chiffre pas le paquet de fermeture sans état, il est juste authentifié (par le jeton). Si la perte de mémoire est totale (jeton stocké en mémoire non stable, et perdu), il ne reste plus que les délais de garde pour mettre fin à la connexion. Évidemment, le jeton ne peut être utilisé qu'une fois, puisqu'un surveillant a pu le copier. Notez que les détails de ce paquet de fermeture sans état sont soigneusement conçus pour que ce paquet soit indistinguable d'un paquet QUIC « normal ».

Dans un monde idéal, tout fonctionnera comme écrit dans le RFC. Mais, dans la réalité, des machines ne vont pas suivre le protocole et vont faire des choses anormales. La section 11 du RFC couvre la gestion d'erreurs dans QUIC. Le problème peut être dans la couche de transport, ou dans l'application (et, dans ce cas, il peut être limité à un seul ruisseau). Lorsque l'erreur est dans la couche transport et qu'elle semble irrattrapable, on ferme la connexion avec une trame CONNECTION_CLOSE. Si le problème ne touche qu'un seul ruisseau, on peut se contenter d'une trame RESET_STREAM, qui met fin juste à ce ruisseau.

On a parlé de paquets et de trames. La section 12 précise ces termes :

  • Les deux machines s'envoient des datagrammes UDP,
  • chaque datagramme contient un ou plusieurs paquets QUIC,
  • chaque paquet QUIC peut contenir une ou plusieurs trames. Chacune d'elle a un type, la liste étant dans un registre IANA.

Parmi les paquets, il y a les paquets longs et les paquets courts. Les paquets longs, qui contiennent tous les détails, sont Initial, Handshake, 0-RTT et Retry. Ce sont surtout ceux qui servent à établir la connexion. Les paquets courts sont le 1-RTT, qui ne peut être utilisé qu'après l'établissement complet de la connexion, y compris les paramètres cryptographiques. Bref, les paquets longs (plus exactement, à en-tête long) sont plus complets, les paquets courts (à en-tête court) plus efficaces.

Les paquets sont protégés par la cryptographie. (QUIC n'a pas de mode en clair.) Mais attention, elle ne protège pas la totalité du paquet. Ainsi, le connection ID est en clair puisque c'est lui qui sera utilisé à la destination pour trouver la bonne connexion et donc les bons paramètres cryptographiques pour déchiffrer. (Mais il est protégé en intégrité donc ne peut pas être modifié par un attaquant sans que ce soit détecté.) De même, les paquets Initial n'ont de protection que contre la modification, pas contre l'espionnage. En revanche, les paquets qui transportent les données (0-RTT et 1-RTT) sont complètement protégés. Les détails de ce qui est protégé et ce qui ne l'est pas figurent dans le RFC 9001.

La coalescence de plusieurs paquets au sein d'un seul datagramme UDP vise à augmenter les performances en diminuant le nombre de datagrammes à traiter. (J'en profite pour rappeler que la métrique importante pour un chemin sur le réseau n'est pas toujours le nombre d'octets par seconde qui peuvent passer par ce chemin. Parfois, c'est le nombre de datagrammes par seconde qui compte.) Par contre, si un datagramme qui comprend plusieurs paquets, qui eux-mêmes contiennent des trames de données de ruisseaux différents, est perdu, cela va évidemment affecter tous ces ruisseaux.

Les paquets ont un numéro, calculé différemment dans chaque direction, et partant de zéro. Ce numéro est chiffré. Les réémissions d'un paquet perdu utilisent un autre numéro que celui du paquet original, ce qui permet, contrairement à TCP, de distinguer émission et réémission.

Avec QUIC, les datagrammes ne sont jamais fragmentés (en IPv4), on met le bit DF à 1 pour éviter cela. QUIC peut utiliser la PLPMTUD (RFC 8899) pour trouver la MTU du chemin.

Le format exact des paquets est spécifié en section 17. Un paquet long (plus exactement, à en-tête long) se reconnait par son premier bit mis à 1. Il comprend un type (la liste est dans le RFC, elle n'est pas extensible, il n'y a pas de registre IANA), les deux connection ID et les données, dont la signification dépend du type. Les paquets de type Initial comportent entre autres dans ces données un jeton, qui pourra servir, par exemple pour les futurs connexions 0-RTT. Les paquets de type Handshake contiennent des trames de type CRYPTO, qui indiquent les paramètres cryptographiques. Quant aux paquets courts, leur premier bit est à 0, et ils contiennent moins d'information, par exemple, seul le connection ID de destination est présent, pas celui de la source.

Dans sa partie non chiffrée, le paquet a un bit qui a suscité bien des débats, le spin bit. Comme c'est un peu long à expliquer, ce bit a son propre article.

QUIC chiffre beaucoup plus de choses que TCP. Ainsi, pour les paquets à en-tête court, en dehors du connection ID et de quelques bits dont le spin bit, rien n'est exposé. Par exemple, les accusés de réception sont chiffrés et on ne peut donc pas les observer. Le but est bien de diminuer la vue offerte au réseau (RFC 8546), alors que TCP expose tout (les accusés de réception, les estampilles temporelles, etc). QUIC chiffre tellement qu'il n'existe aucun moyen fiable, en observant le trafic, de voir ce qui est du QUIC et ce qui n'en est pas. (Certaines personnes avaient réclamé, au nom de la nécessité de surveillance, que QUIC se signale explicitement .)

Les différents types de trames sont tous listés en section 19. Il y a notamment :

  • PADDING qui permet de remplir les paquets pour rendre plus difficile la surveillance,
  • PING qui permet de garder une connexion ouverte, ou de vérifier que la machine distante répond (il n'y a pas de PONG, c'est l'accusé de réception de la trame qui en tiendra lieu),
  • ACK, les accusés de réception, qui indiquent les intervalles de numéros de paquets reçus,
  • CRYPTO, les paramètres cryptographiques de la connexion,
  • STREAM, qui contiennent les données, et créent les ruisseaux ; envoyer une trame de type STREAM suffit, s'il n'est pas déjà créé, à créer le ruisseau correspondant (ils sont identifiés par un numéro contenu dans cette trame),
  • CONNECTION_CLOSE, pour mettre fin à la connexion.

Les types de trame figurent dans un registre IANA. On notera que l'encodage des trames n'est pas auto-descriptif : on ne peut comprendre une trame que si on connait son type. C'est plus rapide, mais moins souple et cela veut dire que, si on introduit de nouveaux types de trame, il faudra utiliser des paramètres au moment de l'ouverture de la connexion pour être sûr que l'autre machine comprenne ce type.

Bon, les codes d'erreur, désormais (section 20 du RFC). La liste complète est dans un registre IANA, je ne vais pas la reprendre ici. Notons quand même le code d'erreur NO_ERROR qui signifie qu'il n'y a pas eu de problème. Il est utilisé lorsqu'on ferme une connexion sans que pour autant quelque chose de mal se soit produit.

Si vous voulez une vision plus concrète de QUIC, vous pouvez regarder mon article d'analyse d'une connexion QUIC.

L'une des principales motivations de QUIC est la sécurité, et il est donc logique qu'il y ait une longue section 21 consacrée à l'analyse détaillée de la sécurité de QUIC. D'abord, quel est le modèle de menace ? C'est celui du RFC 3552. En deux mots : on ne fait pas confiance au réseau, tout intermédiaire entre deux machines qui communiquent peut être malveillant. Il y a trois sortes d'attaquants : les attaquants passifs (qui ne peuvent qu'écouter), les attaquants actifs situés sur le chemin (et qui peuvent donc écouter et écrire) et les attaquants actifs non situés sur le chemin, qui peuvent écrire mais en aveugle. Voyons maintenant les attaques possibles.

La poignée de mains initiale est protégée par TLS. La sécurité de QUIC dépend donc de celle de TLS.

Les attaques par réflexion, surtout dangereuses quand elles se combinent avec une amplification sont gênées, sinon complètement empêchées, par la validation des adresses IP. QUIC ne transmet pas plus de trois fois le volume de données à une adresse IP non validée. Ce point n'a pas forcément été compris par tous, et certains ont paniqué à la simple mention de l'utilisation d'UDP. C'est par exemple le cas de cet article, qui est surtout du FUD d'un vendeur.

Du fait du chiffrement, même un attaquant actif qui serait sur le chemin et pourrait donc observer les paquets, ne peut pas injecter de faux paquets ou, plus exactement, ne peut pas espérer qu'ils seront acceptés (puisque l'attaquant ne connait pas la clé de chiffrement). L'attaquant actif qui n'est pas sur le chemin, et doit donc opérer en aveugle, est évidemment encore plus impuissant. (Avec TCP, l'attaquant actif situé sur le chemin peut insérer des paquets qui seront acceptés. Des précautions décrites dans le RFC 5961 permettent à TCP de ne pas être trop vulnérable à l'attaquant aveugle.)

La possibilité de migration des connexions QUIC (changement de port et/ou d'adresse IP) apporte évidemment de nouveaux risques. La validation du chemin doit être refaite lors de ces changements, autrement, un méchant partenaire QUIC pourrait vous rediriger vers une machine innocente.

Bien sûr, les attaques par déni de service restent possibles. Ainsi, un attaquant actif sur le chemin qui a la possibilité de modifier les paquets peut tout simplement les corrompre de façon à ce qu'ils soient rejetés. Mais il y a aussi des attaques par déni de service plus subtiles. L'attaque dite Slowloris vise ainsi à épuiser une autre machine en ouvrant beaucoup de connexions qui ne seront pas utilisées. Un serveur utilisant QUIC doit donc se méfier et, par exemple, limiter le nombre de connexions par client. Le méchant client peut aussi ouvrir, non pas un grand nombre de connexions mais un grand nombre de ruisseaux. C'est d'autant plus facile que d'ouvrir le ruisseau de numéro N (ce qui ne nécessite qu'une seule trame de type STREAM) ouvre tous les ruisseaux jusqu'à N, dans la limite indiquée dans les paramètres de transport.

On a vu que dans certains cas, une machine QUIC n'a plus les paramètres qui lui permettent de fermer proprement une connexion (par exemple parce qu'elle a redémarré) et doit donc utiliser la fermeture sans état (stateless reset). Dans certains cas, un attaquant peut mettre la main sur un jeton qu'il utilisera ensuite pour fermer une connexion.

Le chiffrement, comme toute technique de sécurité, a ses limites. Ainsi, il n'empêche pas l'analyse de trafic (reconnaitre le fichier récupéré à sa taille, par exemple). D'où les trames de type PADDING pour gêner cette attaque.

QUIC a plusieurs registres à l'IANA. Si vous voulez ajouter des valeurs à ces registres, leur politique (cf. RFC 8126) est :

  • Pour les ajouts provisoires, ce sera « Examen par un expert », et le RFC donne l'instruction d'être assez libéral,
  • Pour les ajouts permanents, il faudra écrire une spécification (« Spécification nécessaire »). Là aussi, le RFC demande d'être assez libéral, les registres ne manquent pas de place. Par exemple, les paramètres de transport jouissent de 62 bits.
  • Pour les types de trame, si la majorité de l'espace prévu suit cette politique « Spécification nécessaire », une petite partie est reservée pour enregistrement via une politique plus stricte, « Action de normalisation ».

L'annexe A de notre RFC contient du pseudo-code pour quelques algorithmes utiles à la mise en œuvre de QUIC. Par exemple, QUIC, contrairement à la plupart des protocoles IETF, a plusieurs champs de taille variable. Les encoder et décoder efficacement nécessite des algorithmes astucieux, suggérés dans cette annexe.

Il existe d'ores et déjà de nombreuses mises en œuvre de QUIC, l'écriture de ce RFC ayant été faite en parallèle avec d'innombrables hackathons et tests d'interopérabilité. Je vous renvoie à la page du groupe de travail, qui indique également des serveurs QUIC publics. Elles sont dans des langages de programmation très différents, par exemple celle de Cloudflare, Quiche, est en Rust. À ma connaissance, toutes tournent en espace utilisateur mais ce n'est pas obligatoire, QUIC pourrait parfaitement être intégré dans le noyau du système d'exploitation. Une autre bonne source pour la liste des mises en œuvre de QUIC est le Wikipédia anglophone. Notez que le navigateur Web libre Firefox a désormais QUIC.

Quelques lectures pour aller plus loin :


Téléchargez le RFC 9000


L'article seul

RFC Origins of Domain Names

Première rédaction de cet article le 10 mai 2021


Qu'est-ce qu'un nom de domaine ? La question semble simple puisque les noms de domaine sont aujourd'hui partout, y compris sur les affiches publicitaires. Mais cette question apparemment simple soulève bien d'autres questions, que ce texte d'Edward Lewis étudie. Notamment, il est très difficile de trouver la définition originale de « nom de domaine ».

Par exemple, quelles sont les relations des noms de domaine avec le DNS ? Les noms de domaine ont-ils été inventés par le DNS, ou bien est-ce que le DNS a été créé pour fournir un nouveau protocole pour faire des résolutions de noms de domaine ? La question n'est pas purement philosophique, elle s'est posée ces dernières années à l'IETF lorsqu'il a fallu travailler sur des protocoles de résolution de noms autres que le DNS, et utiliser les noms de domaine dans de nouveaux contextes. Cela a été le cas, par exemple, du .onion du RFC 7686. Un nom comme sjnrk23rmcl4ie5atmz664v7o7k5nkk4jh7mm6lor2n4hxz2tos3eyid.onion (qui pointe vers le blog que vous êtes en train de consulter, si vous utilisez Tor) est-il un nom de domaine, bien qu'il n'utilise pas du tout le DNS ? Le débat est d'autant plus confus que, en raison de l'immense succès du DNS, même ses opposants et ceux qui prétendent offrir une solution alternative appellent souvent n'importe quel protocole de résolution de noms « DNS ».

D'autres RFC ont eu une genèse difficile car ils nécessitaient des définitions claires de certains termes et concepts, définitions qu'on ne trouvait pas dans les textes fondateurs. C'est ainsi que les RFC 4592 et RFC 5936 ont suscité beaucoup de débats terminologiques.

En outre, le problème n'est pas purement technique ; les noms de domaine sont des enjeux financiers et politiques importants, et les débats sont rudes au sujet de leur gouvernance (notez au passage que l'auteur du texte travaille à l'ICANN, mais son embauche est récente, et son document n'est pas du tout langue de bois). Ainsi, l'ICANN décide des politiques d'enregistrement dans les gTLD et, dans une certaine mesure, à la racine des noms de domaine, mais l'IETF a aussi son mécanisme d'enregistrement, spécifié dans le RFC 6761. La délimitation de leurs pouvoirs et rôles respectifs est formalisée dans le RFC 2860 et, comme tous les textes sacrés, chacun l'interprète d'une manière différente. Notamment, le terme « assignments of domain names for technical uses » (qui sont pour l'IETF) a suscité des trésors d'exégèse : qu'est-ce qu'une « utilisation technique » ?

Pour traiter cette difficile question, la démarche de ce texte est historique : plongeons-nous dans le passé, relisons les vieux RFC et voyons ce qu'ils nous racontent. Je vous révèle la vérité tout de suite : les RFC parlaient de noms de domaine avant que le DNS ne soit inventé. Mais, en même temps, le concept de nom de domaine a évolué. Le texte ne propose pas de solution, ou de « définition définitive », il décrit plutôt qu'il ne spécifie. À l'origine, il avait été écrit comme Internet-Draft, pour être publié sous forme de RFC mais ce projet n'a pas abouti.

Aujourd'hui, la norme de base du DNS est constituée des RFC 1034 et RFC 1035. Ces documents anciens, jamais mis à jour, sont complétés par un grand nombre de RFC plus récents, formant un cauchemar pour le programmeur qui veut écrire un serveur ou un client DNS. Et aucun des deux RFC de référence ne définit ce qu'est un nom de domaine… Ils citent des textes précédents (IEN-116, RFC 799, RFC 819, et RFC 830), sans donner de définition précise, même si les concepts essentiels (la nature hiérarchique des noms, le point comme séparateur des composants dans la représentation textuelle) sont mentionnés. Mais il est clair que le concept de nom de domaine existait avant le DNS : il était utilisé par SMTP. Le RFC 788 y fait déjà allusion, des années avant la création du DNS, même si c'est seulement avec le RFC 821 que SMTP utilisera officiellement ces noms, « Domains are a recently [en 1982] introduced concept in the ARPA Internet mail system ». Et avant le DNS, il y avait déjà des protocoles de nommage utilisant ces noms de domaines, par exemple dans les RFC 819 ou surtout le RFC 830. Donc, la question est tranchée : ce n'est pas le DNS qui définit les noms de domaine. Cela a pour conséquence, entre autre, qu'il est absurde de parler d'un « DNS sur la blockchain » ou d'un « DNS pair-à-pair », sous prétexte que tel ou tel protocole de nommage utilise des noms de domaine.

Bon, mais si ce n'est pas le DNS qui a créé le concept de nom de domaine, c'est qui ? Le courrier électronique, comme semble l'indiquer les RFC sur SMTP ? Comme indiqué ci-dessus, la première occurrence du terme apparait dans le RFC 788, en novembre 1981, mais sans définition (le concept était encore en discussion). La première définition apparait dans le RFC 799 mais c'est encore très confus, le nom de domaine n'est pas encore hiérarchique. (Traditionnellement, « domaine » est utilisé pour désigner une entité administrative unique, avec ses règles propres, et ce sens est encore utilisé dans des documents comme le RFC 5598. Les gens du routage utilisent le terme « système autonome » là où ceux du courrier se serviront plutôt de « domaine ». Les noms de domaine d'aujourd'hui viennent de là. Un exemple est donné par IEN 19.) Puis le RFC 805, en février 1982, saute le pas et introduit pour la première fois explicitement la notion de nom de domaine hiérarchique (le premier RFC sur le DNS ne sera publié qu'un an plus tard, et le DNS ne sera pas adopté instantanément, loin de là). Le RFC 819 précisera le concept, et créera en même temps celui de TLD, avec le premier domaine de tête, .arpa.

Le texte de Lewis note bien que cette histoire n'est que celle transcrite dans les RFC. La réalité n'est pas exactement ce qui a été écrit, les choses sont sans doute plus compliquées. Mais les points importants ne font pas de doute : les noms de domaine existaient avant le DNS, et ils ont été créés surtout pour une application spécifique, SMTP, pas pour servir de système d'identificateurs généralisé. Par exemple, le RFC sur FTP, RFC 959, bien que publié deux ans après les premiers RFC sur le DNS, ne mentionne pas une seule fois les noms de domaine.

Et le concept de résolution, central dans le DNS, d'où vient-il ? La première mention semble être dans le RFC 724, quasiment dans le sens actuel, celui de trouver une information (par exemple une adresse) à partir d'un nom. Selon les auteurs des premiers RFC, interrogés par Ed Lewis, le terme venait de la programmation (par exemple la résolution des noms en adresses lors de l'édition de liens).

Bien, maintenant qu'on a renoncé à trouver la source unique et originale du concept de nom de domaine, voyons les variantes. Car il existe plusieurs types de noms de domaine. Déjà, il y a ceux utilisés dans le DNS. Ce sont un sous-ensemble de tous les noms de domaine, avec des restrictions spécifiques, et des règles de correspondance particulières :

  • La taille maximale d'un nom est de 255 octets (j'ai bien dit octets et pas caractères), celle d'un composant de 63 caractères.
  • La correspondance est faite de manière insensible à la casse.

En revanche, la limitation aux caractères ASCII et l'interdiction des symboles comme + ou & est une légende : le DNS autorise tous les octets, comme le rappelle bien le RFC 2181 (section 11). Ces restrictions existent par contre dans d'autres variantes des noms de domaine. Notez bien que j'ai écrit que le protocole DNS autorise tous les octets. Les registres de noms de domaine, eux, peuvent imposer des restrictions supplémentaires, notamment parce que les gens qui réservent des noms de domaine le font souvent pour créer des noms de machine, présentés plus loin.

Le DNS introduit deux autres concepts importants : une séparation entre la représentation des noms aux humains, et leur encodage dans les paquets effectivement échangés. Sur le câble, les noms de domaine ne comportent pas de point, par exemple (RFC 1035, section 3.1). Et le second concept est la notion d'autorité, lié à une zone (un sous-arbre géré par les mêmes serveurs faisant autorité).

Autre sous-ensemble, les noms de machines (host names). Ce n'est pas la même chose qu'un nom de domaine. Ils sont soumis à une syntaxe plus restrictive, décrite dans le RFC 952, légèrement assouplie ensuite par le RFC 1123. Là, les caractères comme le * ou le _ sont vraiment interdits. Cette règle est souvent nommée LDH, pour Letters Digits Hyphen, puisque seuls les lettres (ASCII), les chiffres (arabes) et le tiret sont admis.

À propos des lettres ASCII, il faut aussi parler des noms en Unicode, puisque la planète n'est pas peuplée que de gens qui écrivent en ASCII. Ces noms internationalisés, les IDN, sont normalisés dans le RFC 5890. Pourquoi un RFC supplémentaires puisque le DNS admet tous les octets, même non-ASCII, dans un nom ? Parce que le DNS ne permet pas d'indiquer l'encodage, et qu'en prime ses règles d'insensibilité à la casse ne sont pas celles, bien plus complexes, d'Unicode. Enfin, certaines vieilles applications ou bibliothèques auraient pu mal réagir à la présence des caractères non-ASCII. D'où la séparation des noms en deux : les U-label, le nom normal, en Unicode, et le A-label, une représentation en pur ASCII, normalisée dans le RFC 3492, qui permettait de minimiser les risques de mauvaises surprises. Ainsi, lorsque potamochère.fr est le U-label,x xn--potamochre-66a.fr sera le A-label.

Le système IDN est donc une chose de plus dans l'univers déjà riche des noms de domaine. Pour approfondir, vous pouvez aussi lire le RFC 6055, qui traite du cas des noms en Unicode en dehors du DNS, et le RFC 4290, qui parle de règles que peuvent suivre les registres de noms de domaines.

Et, justement, un protocole proche du DNS, le Multicast DNS du RFC 6762, utilise des noms qui ne sont pas passés en punycode (la forme xn--…) mais utilisent un encodage plus traditionnel d'Unicode, UTF-8, tel que décrit dans le RFC 5198. (L'annexe F du RFC 6762 explique ce choix.)

Notez que le texte considère que les adresses IP sont une forme de nom de domaine, puisqu'on peut les utiliser, par exemple, dans les URL. (En théorie, on peut aussi dans les adresses de courrier électronique mais, en pratique, cela ne marche pas.)

Mettons maintenant notre hoodie et nos gants, pour ressembler au hacker dans les reportages de BFM TV, et descendons dans les profondeurs du darknet. Non, je plaisante, on va simplement regarder les noms des services Tor, en .onion. Ce blog, par exemple, est accessible avec Tor en sjnrk23rmcl4ie5atmz664v7o7k5nkk4jh7mm6lor2n4hxz2tos3eyid.onion. S'agit-il d'un nom de domaine ? Oui, certainement. Sa syntaxe est définie dans la documentation Tor, et est celle d'un nom de domaine. (Notez que le TLD .onion a été réservé par le RFC 7686.) Mais ce n'est pas du tout un nom DNS : ces noms ne sont jamais résolus par le DNS, mais par un protocole spécifique à Tor (cf. le protocole de rendez-vous), utilisant le fait que le nom est une clé cryptographique.

Et le fichier /etc/hosts ? Historiquement, il servait à stocker des noms de machine et leurs adresses IP. Il fonctionne encore aujourd'hui, et sur de nombreux systèmes d'exploitation. La syntaxe des noms qu'il contient n'est pas définie très rigoureusement. La section 6 du RFC 3493 parle de ce cas.

Bref, si on veut assurer l'interopérabilité, ce n'est pas facile. Il n'y a pas une définition unique des noms de domaine, mais plusieurs sous-ensembles plus ou moins bien définis. La tâche des interfaces utilisateur qui permettent d'indiquer des noms de domaine n'est pas facile ! Cela rend compliquée l'addition de nouveautés. Ainsi, les IDN n'avaient pas été normalisés sans mal. Le texte de Lewis cite un dernier exemple de cette difficulté à déterminer ce qui est acceptable : un nom d'un seul composant (comme dk) est-il valable ? C'est clairement un nom de domaine légal pour le DNS. Il peut avoir des adresses IP associées, comme dans l'exemple. Mais il ne marchera pas pour certaines applications, comme le courrier électronique.

Sinon, quelques autres articles sur le DNS sur ce blog :


L'article seul

Un rapport de la RAND sur l'utilisation des cryptomonnaies par les terroristes

Première rédaction de cet article le 8 mai 2021


« Les cryptomonnaies, comme le Bitcoin, financent le terrorisme » est un cliché classique lors des discussions sur ces cryptomonnaies. Dans quel mesure est-ce vrai ? L'argent, c'est le nerf de la guerre et, sans argent, une organisation ne va pas bien loin. Comment font les terroristes ? Sans avoir besoin de risquer votre vie en allant enquêter sur le financement de Daech, ce rapport de la RAND « Terrorist Use of Cryptocurrencies » est une analyse intéressante.

(Pour celles et ceux qui ne connaissent pas, la RAND n'est pas Framasoft ou la Quadrature du Net. Politiquement, c'est d'un tout autre bord, et il faut lire leurs analyses en se rappelant que leur but est défendre l'impérialisme étatsunien. Mais cela n'empêche pas que ces études contiennent souvent des informations utiles.)

Évidemment, connaitre le fonctionnement financier d'une organisation clandestine est difficile. Il n'y a pas d'informations publiques fiables, et on rencontre par contre beaucoup de discours sensationnalistes, fondés sur l'ignorance ou bien la mauvaise foi. Annoncer que les terroristes utilisent les cryptomonnaies précède en général des discours appelant à interdire ou en tout cas à restreindre sérieusement l'utilisation de ces cryptomonnaies. Comme on manque de faits précis (mais la bibliographie contient beaucoup d'éléments), ce rapport repose plutôt sur l'analyse : quels sont les propriétés utiles d'un mécanisme financier pour un groupe terroriste, et en quoi les cryptomonnaires ont, ou pas, ces propriétés ? Le rapport est détaillé, largement sourcé, et manifestement écrit par des gens qui connaissent bien le monde des cryptomonnaies, contrairement à la grande majorité des déclarations ou articles sur le Bitcoin. Une lecture que je vous recommande, donc.

Je vous divulgue tout de suite les conclusions : il n'y a pas d'utilisation significative des cryptomonnaies par les organisations terroristes, mais ça pourrait changer dans le futur. Voyons ces deux points.

(Point de terminologie au passage : je sais bien que « terrorisme » est un terme très polysémique, et d'un usage délicat. J'ai choisi la solution de facilité en reprenant ce terme tel que l'utilise le rapport. Notez que la RAND se focalise sur le terrorisme au Moyen-Orient, notamment Daech, même si les narcos latino-américains sont brièvement mentionnés.)

Une organisation terroriste a plusieurs activités financières ; par exemple, la levée de fonds auprès de donateurs, le financement d'attaques, le financement de l'infrastructure, les trafics illégaux pour remplir les caisses, etc. Certaines de ces activités sont proches de celles d'autres entreprises ou associations, d'autres sont plus spécifiques au terrorisme. Une organisation terroriste importante doit s'attendre à avoir des adversaires redoutables et doit donc bien réfléchir aux outils et aux méthodes employées, pour diminuer les risques. Sécuriser son portefeuille Bitcoin ne pose pas les mêmes problèmes quand on est un particulier visé uniquement par des attaques opportunistes et quand on est un groupe terroriste en guerre ouverte contre un État puissant. Les auteurs du rapport listent ensuite une série de propriétés des cryptomonnaies, essayant de voir si elles sont importantes ou pas pour les activités financières citées plus haut. Ainsi, l'utilisabilité d'une cryptomonnaie (disponibilité de logiciels sûrs et simples d'utilisation) est importante pour les dons des sympathisants, beaucoup de donateurs renonceront s'ils n'arrivent pas à envoyer de l'argent, mais elle est nettement moins cruciale pour les trafics illégaux, où seuls quelques professionnels entrainés manipuleront les fonds.

Le rapport analyse ensuite les cryptomonnaies par rapport à ces propriétés. Ainsi, Bitcoin est jugé pas facile à utiliser, pas très répandu dans les pays où opèrent les groupes terroristes considérés, et pas très anonyme. D'autres cryptomonnaies comme Monero ou Zcash sont bien meilleures question anonymat mais encore pires que le Bitcoin question facilité d'utilisation et diffusion. La tonalité générale du rapport est plutôt pessimiste sur les cryptomonnaies, considérant qu'une organisation terroriste rationnelle et compétente n'a guère de raisons de les utiliser. Des membres de Daech ont pu faire des essais, mais on est loin d'une utilisation significative.

Le rapport ne s'arrête pas à cette situation actuelle, et essaie d'analyser ce qui peut arriver dans le futur. C'est évidemment une partie plus faible du rapport, car prédire l'avenir est délicat. Les auteurs notent à plusieurs reprises que des changements dans les cryptomonnaies (apparition d'une nouvelle cryptomonnaie vraiment anonyme, simple à utiliser, répandue, etc) pourrait changer sérieusement la donne. Même chose si la répression sur les flux financiers ne laissait pas d'autres choix aux terroristes. Mais c'est purement théorique, on n'a pas d'indication en ce sens. Le rapport conclut qu'on ne sait pas trop mais qu'il faut rester vigilant.

Merci à Éric Freyssinet pour avoir attiré mon attention sur cet intéressant rapport, suite à un petit déjeuner du FIC.


L'article seul

La vulnérabilité DNS tsuNAME

Première rédaction de cet article le 6 mai 2021


L'Internet est plein de failles de sécurité donc, aujourd'hui, pas de surprise qu'une nouvelle faille soit publiée : tsuNAME est une faille DNS permettant des attaques par déni de service en exploitant un cycle dans les dépendances des noms de domaine.

Le principe est simple : l'attaquant doit contrôler deux noms de domaine, avec un parent qui est la victime visée. Mettons que le méchant veuille attaquer le TLD .example, il a deux noms, foo.example et bar.example, il crée un cycle en faisant en sorte que les serveurs de noms de foo.example soient tous dans bar.example et réciproquement. En syntaxe de fichier de zone :

foo IN NS ns.bar.example.
bar IN NS ns.foo.example.
  

(C'est une présentation simplifiée : un attaquant peut faire des cycles plus complexes.) Aucun nom en foo.example ou bar.example ne peut être résolu avec succès, en raison de ce cycle. Mais le but de l'attaquant n'est pas là : lorsqu'un résolveur veut résoudre www.foo.example, le serveur faisant autorité pour .example le renvoie à ns.bar.example. Pour résoudre ce nom, il interroge à nouveau le pauvre serveur faisant autorité pour .example, qui le renvoie à ns.foo.example et ainsi de suite. (Si vous aimez les vidéos, je vous renvoie à celle de l'Afnic sur le fonctionnement du DNS.) Et, pire, certains résolveurs ne se souviennent pas que la résolution a échoué et recommencent donc la fois suivante. Un attaquant qui a configuré le cycle (ou bien repéré un cycle existant) peut donc utiliser les résolveurs auxquels il a accès (directement, ou bien via un botnet qu'il contrôle) pour faire l'attaque à sa place.

Normalement, les résolveurs limitent le nombre de requêtes déclenchées par une requête originale. Ils le font surtout pour se protéger eux-mêmes, par exemple contre les attaques en récursion infinie. Mais la nouveauté de tsuNAME est de se servir d'un éventuel manque de limites pour attaquer les serveurs faisant autorité. En pratique, peu de résolveurs sont assez imprudents pour être vraiment intéressants pour l'attaquant. La principale exception était Google Public DNS, qui a ainsi involontairement participé à une attaque contre le .nz. (Il a été corrigé depuis.)

Une leçon pour les programmeurs de résolveurs DNS : ne vous laissez pas entrainer dans des cycles, pensez à jeter l'éponge rapidement, et à mémoriser cet échec pour la prochaine fois.


L'article seul

Fiche de lecture : L'homme préhistorique est aussi une femme

Auteur(s) du livre : Marylène Patou-Mathis
Éditeur : Allary
978-2370-733412
Publié en 2020
Première rédaction de cet article le 2 mai 2021


La représentation traditionnelle des humains de la préhistoire montre les hommes en train de chasser et les femmes en train de coudre, faire la cuisine ou s'occuper des enfants. Est-ce que cette représentation repose sur des données scientifiques sérieuses sur la répartition des tâches à la préhistoire ? Pas forcément, dit l'auteure.

Dans ce livre, Marylène Patou-Mathis examine ce que l'on sait de la répartition genrée des activités chez nos ancêtres. Je vous le dis tout de suite : il y a beaucoup de choses qu'on ne sait pas. On n'a pas de photos prises sur le vif des humains préhistoriques. On n'a que leurs squelettes, leurs outils et les produits de leur activité, par exemple les peintures pariétales ou les statuettes, produits qui ne sont pas faciles à interpréter. La représentation traditionnelle des rôles des deux genres reflétait davantage ce qui se faisait dans la société où vivait les auteurs de ces représentations que ce qui se faisait à la préhistoire. Souvent, on plaquait donc notre conception de la division du travail entre genres sur nos ancêtres. Ou bien on supposait qu'ils étaient forcément comme les peuples « primitifs », ou plutôt comme on voyait les peuples « primitifs » contemporains.

Bon, mais maintenant qu'on a progressé, est-ce que la science peut répondre à des questions comme « Les femmes chassaient-elles ? Autant que les hommes ? » Là, c'est plus délicat. L'auteure note que, pour la majorité des squelettes retrouvés, on n'est pas sûr de leur sexe. Et ce n'est pas mieux pour les dessins qu'on retrouve. Souvent, on suppose, justement en fonction de ce qu'on estime être la société du passé. Une tombe contient des armes ? On suppose que le défunt était un homme. (L'excellent chapitre 2 est une véritable « histoire de la misogynie chez les penseurs » et montre bien que les hommes, même scientifiques, étaient largement aveuglés par leurs préjugés sexistes.) Et, par un raisonnement circulaire, on en déduit que les hommes chassaient et faisaient la guerre. Lorsqu'on examine de plus près (comme dans le cas de la fameuse guerrière de Birka p. 169), on a parfois des surprises. Une fois qu'on a déterminé le sexe de la personne dont on retrouve le squelette, on peut étudier des choses comme les déformations liées à une activité physique répétée (le lancer de javelot semblait pratiqué par les hommes et par les femmes chez les Néandertal). Mais il est difficile, avec ce qu'on retrouve de nos ancêtres, de décrire avec précision comment les deux genres se répartissaient les tâches. L'ADN peut aider (cas de Birka), ou certaines caractéristiques du corps (la forme différente des mains entre les deux sexes montre que certaines images de mains sur les parois des grottes étaient faites par des femmes, p. 144) mais il n'y aura pas de certitude, d'autant plus que rien n'indique que toutes les sociétés préhistoriques étaient identiques.


L'article seul

RFC 9019: A Firmware Update Architecture for Internet of Things

Date de publication du RFC : Avril 2021
Auteur(s) du RFC : B. Moran, H. Tschofenig (Arm Limited), D. Brown (Linaro), M. Meriac (Consultant)
Pour information
Réalisé dans le cadre du groupe de travail IETF suit
Première rédaction de cet article le 1 mai 2021


On le sait, le « S » dans « IoT » veut dire « sécurité ». Cette plaisanterie traditionnelle rappelle une vérité importante sur les brosses à dents connectées, les télés connectées, les voitures connectées et les sextoys connectés : leur sécurité est catastrophique. Les vendeurs de ces objets ont vingt ou trente ans de retard en matière de sécurité et c'est tous les jours qu'un nouveau piratage spectaculaire d'un objet connecté est annoncé. Une partie des vulnérabilités pourrait être bouchée en mettant à jour plus fréquemment les objets connectés. Mais cela ne va pas sans mal. Ce RFC fait partie d'un projet qui vise à construire certaines briques qui seront utiles pour permettre cette mise à jour fréquente. Il définit l'architecture générale.

Une bonne analyse du problème est décrite dans le RFC 8240, qui faisait le compte-rendu d'un atelier de réflexion sur la question. L'atelier avait bien montré l'ampleur et la complexité du problème ! Notre nouveau RFC est issu du groupe de travail SUIT de l'IETF, créé suite à cet atelier. La mise à jour du logiciel des objets connectés compte beaucoup d'aspects, et l'IETF se focalise sur un format de manifeste (en CBOR) qui permettra de décrire les mises à jour. (Le format effectif sera dans un futur RFC.)

Le problème est compliqué : idéalement, on voudrait que les mises à jour logicielles de ces objets connectés se passent automatiquement, et sans casse. Ces objets sont nombreux, et beaucoup d'objets connectés sont installés dans des endroits peu accessibles ou, en tout cas, ne sont pas forcément bien suivis. Et ils n'ont souvent pas d'interface utilisateur du tout. Une solution réaliste doit donc être automatique (on sait que les injonctions aux humains « mettez à jour vos brosses à dents connectées » ne seront pas suivies). D'un autre côté, cette exigence d'automaticité va mal avec celle de consentement de l'utilisateur, d'autant plus que des mises à jour peuvent éliminer certaines fonctions de l'objet, ou en ajouter des peu souhaitables (cf. RFC 8240). En moins grave, elles peuvent aussi annuler des réglages ou modifications faits par les utilisateurs.

Le format de manifeste sur lequel travaille le groupe SUIT vise à authentifier l'image (le code), par exemple en la signant. Un autre point du cahier des charges, mais qui n'est qu'optionnel [et que je trouve peu réaliste dans la plupart des environnements] est d'assurer la confidentialité de l'image, afin d'empêcher la rétro-ingénierie du code. Ce format de manifeste vise avant tout les objets de classe 1 (selon la terminologie du RFC 7228). Il est prévu pour du logiciel mais peut être utilisé pour décrire d'autres ressources, comme des clés cryptographiques.

On l'a dit, le travail du groupe SUIT se concentre sur le format du manifeste. Mais une solution complète de mise à jour nécessite évidemment bien plus que cela, le protocole de transfert de fichiers pour récupérer l'image, un protocole pour découvrir qu'il existe des mises à jour (cf. le status tracker en section 2.3), un pour trouver le serveur pertinent (par exemple avec DNS-SD, RFC 6763). Le protocole LwM2M (Lightweight M2M) peut par exemple être utilisé.

Et puis ce n'est pas tout de trouver la mise à jour, la récupérer, la vérifier cryptographiquement. Une solution complète doit aussi fournir :

  • La garantie que la mise à jour ne va pas tout casser (si beaucoup d'utilisateurs débrayent les mises à jour automatiques, ce n'est pas par pure paranoïa), ce qui implique des mises à jour bien testées, et une stratégie de repli si la mise à jour échoue,
  • des mises à jour rapides, puisque les failles de sécurité sont exploitées dès le premier jour, alors que les mises à jour nécessitent souvent un long processus d'approbation, parfois pour de bonnes raisons (les tests dont je parlais au paragraphe précédent), parfois pour des mauvaises (processus bureaucratiques), et qu'elles doivent souvent passer en cascade par plusieurs acteurs (bibliothèque intégrée dans un système d'exploitation intégré dans un composant matériel intégré dans un objet, tous les quatre par des acteurs différents),
  • des mises à jour économes en énergie, l'objet pouvant être contraint dans ce domaine,
  • des mises à jour qui fonctionnent même après que les actionnaires de l'entreprise aient décidé de mettre leur argent ailleurs et aient abandonné les objets vendus (on peut toujours rêver).

Bon, maintenant, après cette liste au Père Noël, au travail. Un peu de vocabulaire pour commencer :

  • Image (ou firmware) : le code qui sera téléchargé sur l'objet et installé (je n'ai jamais compris pourquoi ça s'appelait « ROM » dans le monde Android). L'image peut être juste le système d'exploitation (ou une partie de celui-ci) ou bien un système de fichiers complet.
  • Manifeste : les métadonnées sur l'image, par exemple date, numéro de version, signature, etc.
  • Point de départ de la validation (trust anchor, RFC 5914 et RFC 6024) : la clé publique à partir de laquelle se feront les validations cryptographiques.
  • REE (Rich Execution Environment) : un environnement logiciel général, pas forcément très sécurisé. Par exemple, Alpine Linux est un REE.
  • TEE (Trusted Execution Environment) : un environnement logiciel sécurisé, typiquement plus petit que le REE et doté de moins de fonctions.

Le monde de ces objets connectés se traduit par une grande dispersion des parties prenantes. On y trouve par exemple :

  • Les auteurs de logiciel, qui sont souvent très loin du déploiement et de la maintenance des objets,
  • les fabricants de l'objet,
  • les opérateurs des objets qui ne sont pas les propriétaires de l'objet : la plupart du temps, pour piloter votre objet, celui que vous avez acheté, vous devez passer par cet opérateur, en général le fabricant, s'il n'a pas fait faillite ou abandonné ces objets,
  • les gestionnaires des clés (souvent le fabricant),
  • et le pauvre utilisateur tout en bas.

[Résultat, on a des chaînes d'approvisionnement longues, compliquées, opaques et vulnérables. Une grande partie des problèmes de sécurité des objets connectés vient de là, et pas de la technique. Par exemple, il est fréquent que les auteurs des logiciels utilisés se moquent de la sécurité et ne fournissent pas de mise à jour pour combler les failles dans les programmes.]

La section 3 du RFC présente l'architecture générale de la solution. Elle doit évidemment reposer sur IP (ce RFC étant écrit par l'IETF, un choix contraire aurait été étonnant), et, comme les images sont souvent de taille significative (des dizaines, des centaines de kilo-octets, au minimum), il faut utiliser en prime un protocole qui assurera la fiabilité du transfert et qui ne déclenchera pas de congestion, par exemple TCP, soit directement, soit par l'intermédiaire d'un protocole applicatif comme MQTT ou CoAP. En dessous d'IP, on pourra utiliser tout ce qu'on veut, USB, BLE, etc. Outre IP et TCP (pas évident pour un objet contraint, cf. RFC 9006), l'objet devra avoir le moyen de consulter le status tracker pour savoir s'il y a du nouveau, la capacité de stocker la nouvelle image avant de l'installer (si la mise à jour échoue, il faut pouvoir revenir en arrière, donc stocker l'ancienne image et la nouvelle), la capacité de déballer, voire de déchiffrer l'image et bien sûr, puisque c'est le cœur du projet SUIT, la capacité de lire et de comprendre le manifeste. Comme le manifeste comprend de la cryptographie (typiquement une signature), il faudra que l'objet ait du logiciel pour des opérations cryptographiques typiques, et un magasin de clés cryptographiques. Notez que la sécurité étant assurée via le manifeste, et non pas via le mécanisme de transport (sécurité des données et pas du canal), le moyen de récupération de l'image utilisé n'a pas de conséquences pour la sécurité. Ce sera notamment pratique pour le multicast.

Le manifeste peut être inclus dans l'image ou bien séparé. Dans le second cas, l'objet peut décider de charger l'image ou pas, en fonction du manifeste.

La mise à jour du code d'un objet contraint pose des défis particuliers. Ainsi, ces objets ne peuvent souvent pas utiliser de code indépendant de sa position. La nouvelle image ne peut donc pas être mise n'importe où. Cela veut dire que, lorsque le code est exécuté directement à partir du moyen de stockage (et donc pas chargé en mémoire), il faut échanger l'ancienne et la nouvelle image, ce qui complique un éventuel retour en arrière, en cas de problème.

Avec tout ça, je n'ai pas encore tellement parlé du manifeste lui-même. C'est parce que notre RFC ne décrit que l'architecture, donc les généralités. Le format du manifeste sera dans deux futurs RFC, un pour décrire le format exact (fondé sur CBOR, cf. RFC 8949) et un autre pour le modèle d'information (en gros, la liste des éléments qui peuvent être mis dans le manifeste).

La section 7 de notre RFC fait la synthèse des questions de sécurité liées à la mise à jour. Si une mise à jour fréquente du logiciel est cruciale pour la sécurité, en permettant de fermer rapidement des failles découvertes dans le logiciel de l'objet, la mise à jour peut elle-même présenter des risques. Après tout, mettre à jour son logiciel, c'est exécuter du code récupéré via l'Internet… L'architecture présentée dans ce RFC fournit une sécurité de bout en bout, par exemple en permettant de vérifier l'authenticité de l'image récupérée (et, bien sûr, son intégrité). Pas question d'exécuter un code non authentifié, ce qui est pourtant couramment le cas aujourd'hui avec les mises à jour de beaucoup d'équipements informatiques.

Cette même section en profite pour noter que la cryptographie nécessite de pouvoir changer les algorithmes utilisés. Le RFC cite même l'importance de la cryptographie post-quantique. (C'est un des tous premiers RFC publiés à en parler, après le RFC 8773.) D'un côté, ce genre de préoccupations est assez décalée : la réalité de l'insécurité des objets connectés est tellement abyssale qu'on aura bien des problèmes avant que les calculateurs quantiques ne deviennent une menace réelle. De l'autre, certains objets connectés peuvent rester en service pendant longtemps. Qui sait quelles seront les menaces dans dix ans ? (Un article comme « Quantum Annealing for Prime Factorization » estimait que, dans le pire des cas, les algorithmes pré-quantiques commenceraient à être cassés vers 2030, mais il est très difficile d'estimer la fiabilité de ces prédictions, cf. mon exposé à Pas Sage En Seine.)

J'insiste, mais je vous recommande de lire le RFC 8240 pour bien comprendre tous les aspects du problème. D'autre part, vous serez peut-être intéressés par l'évaluation faite du projet SUIT sous l'angle des droits humains. Cette évaluation suggérait (ce qui n'a pas été retenu) que le chiffrement des images soit obligatoire.


Téléchargez le RFC 9019


L'article seul

La curieuse annonce des adresses IPv4 de l'armée états-unienne

Première rédaction de cet article le 26 avril 2021


Le 20 janvier 2021, l'armée des États-Unis a soudainement annoncé sur l'Internet des millions d'adresses IP qui n'avaient jamais été actives sur l'Internet. Les causes exactes ne sont pas connues (il y a des explications officielles mais qui ne répondent pas à toutes les questions). Comment a-t-on vu cela et quelles conclusions (forcément assez spéculatives) peut-on en tirer ?

Au début, cela ressemblait à un détournement BGP classique, provoqué soit par une erreur humaine (cas de l'accident malaisien), soit par une volonté délibérée de détourner du trafic (cas de l'attaque contre MyEtherWallet). Le protocole BGP permet à un routeur Internet d'annoncer les préfixes d'adresses IP qu'il sait joindre. S'il se trompe ou qu'il ment, ses pairs vont parfois accepter l'annonce et l'utiliser, envoyant alors le trafic vers les détourneurs. Le 20 janvier 2021, ce fut la première réaction, « quelqu'un annonce les adresses IP de l'armée ». Comment le voit-on ? Rappelez-vous que l'Internet est très transparent. Tout routeur de la DFZ va voir les annonces et, même si vous n'avez pas accès à un tel routeur, plusieurs services vous fournissent les données. Servons-nous du classique RouteViews. Vous pouvez récupérer toutes les annonces du 20 janvier 2021 et les analyser (ici, on convertit les données qui étaient au format MRT du RFC 6396, avec l'outil bgpdump) :

% wget http://archive.routeviews.org/bgpdata/2021.01/UPDATES/updates.20210120.1645.bz2
% bunzip2 updates.20210120.1645.bz2
% bgpdump updates.20210120.1645 > updates.20210120.1645.txt
  

On a alors un fichier texte avec les annonces BGP, qu'on peut regarder avec l'éditeur ou l'afficheur de son choix. Voici la première annonce bizarre (l'heure est évidemment UTC) :

TIME: 01/20/21 16:57:35.081428
TYPE: BGP4MP_ET/MESSAGE/Update
FROM: 64.71.137.241 AS6939
TO: 128.223.51.102 AS6447
ORIGIN: IGP
ASPATH: 6939 8003
NEXT_HOP: 64.71.137.241
ANNOUNCE
   11.0.0.0/8
  

(La dernière annonce pour ce même préfixe, relayée par plusieurs routeurs avant d'atteindre RouteViews, a été vue à 17:04:19.316776, ce qui donne une idée de la rapidité de la propagation des routes dans l'Internet.)

En quoi est-ce que cette annonce était bizarre ? D'abord, le préfixe 11.0.0.0/8, un préfixe comportant beaucoup d'adresses (surtout depuis l'épuisement des adresses IPv4) n'avait jamais été annoncé publiquement sur l'Internet avant (comme on peut le voir sur RIPEstat) ou, plus exactement, jamais été annoncé en dehors de quelques détournements ponctuels. Mais qui, en 2021, a encore un préfixe /8 non annoncé ? whois nous montre que c'est le DoD :

% whois 11.0.0.0  
...
NetRange:       11.0.0.0 - 11.255.255.255
CIDR:           11.0.0.0/8
NetName:        DODIIS
NetType:        Direct Allocation
OriginAS:       
Organization:   DoD Network Information Center (DNIC)
RegDate:        1984-01-19
Updated:        2007-08-22
...
OrgName:        DoD Network Information Center
  

(Pour la petite histoire, ce préfixe a été alloué au DoD en 1985, dans le RFC 943 ; oui, à l'époque, les RFC servaient de registres d'adresses IP.)

Tout de suite, on pense à un détournement des adresses IP de l'armée états-unienne par des Chinois/Russes/Cubains/Iraniens. D'autant plus que la date est curieuse : 16:57:35.081428 UTC, c'est moins de trois minutes avant la fin officielle du mandat de Trump, fin de mandat qui avait été marquée par plusieurs troubles graves. Et puis l'AS qui a fait les annonces, l'AS 8003, n'était pas tellement connu avant, appartenant à une entreprise très discrète et sur laquelle les investigations n'ont pas révélé grand-chose, à part son association passée à des activités bizarres. (whois AS8003 pour avoir les informations sur cet AS.)

Dans les jours et les semaines suivants, d'autres préfixes autrefois inutilisés ont été annoncés, par exemple le 7.0.0.0/8.

Finalement, le Pentagone (via son service DDS) a révélé que l'annonce était normale : il ne s'agit pas d'un détournement mais d'une opération légitime. Mais quels sont ses buts ? Pourquoi l'armée qui n'annonçait pas ses adresses IP depuis si longtemps (ce qui ne veut pas dire qu'elles n'étaient pas utilisées en interne) a-t-elle tout à coup changé sa politique ? Inutile de préciser qu'on ne saura de toute façon pas tout. Mais on peut toujours spéculer :

  • Un tel volume d'adresses IP représente beaucoup d'argent en période de pénurie (le marché est entre 20 et 30 dollars par adresse),
  • ou bien l'armée est en train de monter un pot de miel géant, pour attraper plein de trafic malveillant,
  • certains administrateurs réseau ont été assez incompétents et imprudents pour utiliser ces préfixes d'adresses IP apparemment inutilisés pour numéroter leurs réseaux internes ; l'annoncer sur l'Internet permettrait de capter ce trafic interne (on dit que l'armée chinoise était dans ce cas),
  • ou encore le but est vraiment de s'en servir, par exemple pour y héberger des services.

La possibilité d'une vente de ces adresses, et donc peut-être d'un test pour s'assurer qu'elles ne posaient pas de problèmes techniques, a été souvent mentionnée, vu le « trésor » d'adresses IP de l'armée. Mais relativisons : au cours actuel (mais qui baisserait si le DoD vendait d'un coup toutes ces adresses), cela ferait certes plusieurs centaines de millions de dollars mais c'est une goutte d'eau par rapport aux budgets militaires de ce pays. Et puis le GAO (la « Cour des Comptes ») avait noté dans un rapport de 2020 les difficultés, notamment légales, à vendre ces adresses IP. Un rapport parlementaire estimait que la vente d'adresses IP par le DoD soulevait de nombreux problèmes et n'était pas forcément une solution viable.

Autre hypothèse, celle du pot de miel. C'est nettement plus vraisemblable : tout préfixe important annoncé sur l'Internet reçoit un « rayonnement de fond », l'Internet Background Radiation (IBR), et les nouveaux préfixes annoncés vont certainement attirer beaucoup de trafic, permettant des études qui intéressent certainement les services de cyberguerre.

Et, en parlant de cyberguerre, qu'en est-il de l'hypothèse d'un détournement délibéré du trafic des réseaux qui ont été assez stupides pour utiliser ces préfixes d'adresses IP ? Là, je ne vous étonnerai pas en vous disant que mes contacts au Pentagone sont muets et ne m'ont pas tenu informé :-)

Enfin, s'agissant de l'hébergement de services, ça reste possible mais l'annonce faite par une petite société inconnue et discrète ne plaide pas en ce sens. Notez que le très utile Shodan trouve déjà des machines connectées dans le préfixe 11.0.0.0/8. (Attention si vous essayez de les pirater : le propriétaire n'a pas le sens de l'humour.) Ma préférée (mais rappelez-vous qu'il peut s'agir d'un pot de miel) est un routeur Ubiquiti annonçant comme nom HACKED-ROUTER-HELP-SOS-HAD-DUPE-PASSWORD.

Quelques lectures en plus :


L'article seul

Fiche de lecture : Leur progrès et le nôtre

Auteur(s) du livre : François Ruffin
Éditeur : Seuil
978-2-02-147770-2
Publié en 2021
Première rédaction de cet article le 25 avril 2021


Le progrès technique est-il une bonne ou une mauvaise chose ? Avec tous les philosophes et militants politiques qui ont réfléchi à la question depuis je ne sais plus combien de siècles, on se doute bien qu'il n'y aura pas de réponse simple. Et puis, posé comme ça, c'est trop binaire. Dans ce court livre, François Ruffin estime que ça dépend, ça dépend de quel progrès, de qui le décide, de comment c'est déployé.

Nous voyons en ce moment beaucoup d'« injonctions au progrès », d'affirmations peu subtiles comme quoi le « progrès » (au sens du progrès technique) est à la fois forcément positif, inévitable et que de toute façon ceux et celles qui s'y opposent sont à coup sûr des amish attardés. Ce discours de la « startup nation », porté par exemple par Emmanuel Macron, est tellement idiot qu'il permet à Ruffin de se faire plaisir facilement, par exemple en dressant p. 20 la liste des cérémonies d'adoration des entreprises du numérique auxquelles a participé le président de la république, qui préfère se faire photographier en présence de patrons du numérique qu'avec des infirmières ou des éboueurs. L'auteur oublie d'ailleurs parfois son point de vue de classe par exemple en affirmant p. 23 que Macron aime s'entourer d'une « cour de geeks » comme s'il y avait le moindre rapport entre les patrons des grandes entreprises du numérique et le développeur de logiciel libre dans son garage. De même, taper sur Musk (p. 123) n'est pas difficile, tant le personnage prend soin d'être sa propre caricature.

Ruffin peut donc, vu le ridicule des propagandistes de « la Tech », facilement expliquer que tout progrès n'est pas bon à prendre. Le progrès technique n'est pas toujours un progrès social, et l'auteur liste de nombreux exemples où les techniques modernes, notamment autour du numérique, peuvent servir à opprimer, à surveiller, à contrôler et pas à augmenter le bonheur humain. D'où le titre, il y a ce qu'ils appellent le progrès, et ce que les lecteurs du livre considéreraient comme le vrai progrès (augmenter le salaire des enseignants plutôt que de chercher à tout prix à se faire voir serrant la main de Zuckerberg). Même sans parler de cas où le progrès technique a été un recul social (la surveillance généralisée est probablement le meilleur exemple), l'auteur cite aussi avec raison des cas où le progrès n'est pas linéaire et où ses effets peuvent s'épuiser. Un réfrigérateur dans la maison est un progrès, un deuxième n'apporte pas tellement d'avantages. (Comme le dit un des protagonistes de la série Mad Men à un débutant dans le monde de la publicité « notre rôle est de convaincre le consommateur d'acheter un objet alors qu'il en a déjà un qui sert à la même chose ».)

Cette partie où Ruffin explique que le progrès technique est un moyen, pas un but en soi, est la meilleure du livre. Il l'illustre de nombreux exemples. Après, les difficultés commencent : il ne faut pas avaler tout sous prétexte que ce serait « le progrès » mais comment décider ? L'auteur suggère quelques pistes, mais plutôt vagues. La démocratie, que le déploiement de telle ou telle technique, soit décidé par les citoyens, d'accord, mais les modalités pratiques ne vont pas aller sans mal. (C'est un des points que notait, à juste titre, le RFC 8890.) François Ruffin propose p. 139, une « Convention citoyenne permanente sur le numérique », l'idée me semble intéressante mais elle n'est pas développée, alors que cette suggestion fait surgir plein de questions. Une autre proposition, formulée par une personne interrogée par l'auteur (p. 140), serait que les ingénieurs décident « quelles applications autoriser », ce qui, cette fois, fait plutôt froid dans le dos.

Il faut dire qu'analyser les conséquences d'un progrès technique, surtout s'il n'a pas encore été déployé, est difficile. François Ruffin cite souvent la 5G, sujet à la mode. Heureusement, il ne reprend pas les délires complotistes entendus souvent (par exemple sur le « danger des ondes ») mais il traite le sujet de manière trop superficielle, par exemple en disant que la 5G n'a « pas d'utilité », ce qui est toujours une conclusion imprudente.

L'auteur dérape également un peu lorsqu'il brode p. 69 sur la légende comme quoi toutes les écoles de la Silicon Valley seraient sans ordinateurs car les cadres des entreprises du numérique voudraient mettre leurs enfants à l'abri de ce danger. Non seulement ce récit ne repose que sur quelques déclarations isolées de quelques personnages, mais il est amusant de constater que des gens qui critiquent, à juste titre, le manque de culture politique de pas mal d'acteurs du numérique, considèrent comme crédibles toutes les théories qu'ils peuvent émettre sur l'éducation. Pourquoi ne pas également les citer quand ils deviennent végétaliens ou bien se convertissent au bouddhisme, autres modes californiennes ?

Ce livre a le mérite de poser les bonnes questions : qui décide ? La 5G, l'Internet, l'infomatique, les ordiphones ne sont pas arrivés tout seuls. Des gens ont décidé, et ont mis les moyens nécessaires. Toute la question du progrès est de savoir qui va pouvoir prendre ces décisions, aujourd'hui confisquées par une minorité.


L'article seul

RFC 9011: Static Context Header Compression and Fragmentation (SCHC) over LoRaWAN

Date de publication du RFC : Avril 2021
Auteur(s) du RFC : O. Gimenez (Semtech), I. Petrov (Acklio)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF lpwan
Première rédaction de cet article le 23 avril 2021


Le RFC 8724 décrivait un mécanisme général de compression pour les réseaux LPWAN (réseaux contraints pour objets contraints). Ce nouveau RFC 9011 précise ce mécanisme pour le cas spécifique de LoRaWAN.

Ces « réseaux contraints pour objets contraints » sont décrits dans le RFC 8376. Ils ont des concepts communs mais aussi des différences, ce qui justifie la séparation de SCHC en un cadre générique (celui du RFC 8724) et des spécifications précises par réseau, comme ce que fait notre RFC pour LoRaWAN, la technique qui est utilisée dans divers réseaux déployés. Donc, rappelez-vous, LoRaWAN = la technologie, LoRa = un réseau déployé utilisant cette technologie (mais d'autres réseaux concurrents peuvent utiliser LoRaWAN). LoRaWAN est normalisé par l'alliance LoRa (cf. le texte de la norme) et les auteurs du RFC sont actifs dans cette alliance. Si vous voulez un exemple d'utilisation de LoRaWAN, je recommande cet article en français sur une Gateway LoRaWAN réalisée sur un Raspberry Pi.

La section 3 du RFC fait un rappel de SCHC : si vous n'avez pas le courage de lire le RFC 8724, apprenez que SCHC a deux parties, une de compression des en-têtes, et une de fragmentation, les liens des réseaux contraints ayant souvent une faible MTU. La section 4, elle, explique LoRaWAN (vous avez aussi le RFC 8376, notamment sa section 2.1). La terminologie de SCHC et celle de LoRaWAN ne coïncident pas parfaitement donc il faut se souvenir que Gateway dans LoRaWAN s'appelle plutôt RGW (Radio GateWay) dans SCHC, que le Network Server de LoRaWAN est le NGW (Network GateWay) de SCHC et que les utilisateurs de LoRaWAN doivent se souvenir que leur Application Server est nommé C/D (Compression/Décompression) ou F/R (Fragmentation/Réassemblage) chez SCHC. Les objets connectés par LoRaWAN sont très souvent contraints et LoRaWAN définit trois classes d'objets, de la classe A, la plus contrainte, à la C. Notamment, les objets de la classe A émettent sur le réseau mais n'ont pas de moment d'écoute dédié, ceux de la classe B écoutent parfois, et ceux de la classe C écoutent en permanence, ce qui consomme pas mal d'énergie. Autant dire que les objets de classe C sont en général alimentés en électricité en permanence.

La section 5 est le cœur du RFC, expliquant en détail comment on met en correspondance les concepts abstraits de SCHC avec les détails du protocole LoRaWAN. Ainsi, le RuleID de SCHC est mis sur huit bits, dans le port (Fport) LoRaWAN (norme LoRaWAN, version 1.04, section 4.3.2), juste avant la charge utile. L'annexe A du RFC donne des exemples d'encodage des paquets.

Merci à Laurent Toutain pour sa relecture.


Téléchargez le RFC 9011


L'article seul

Name:Wreck, vulnérabilité Internet du jour

Première rédaction de cet article le 14 avril 2021


Comme souvent, une vulnérabilité logicielle a reçu un nom commercial (« Name:Wreck », notez le deux-points) et a eu droit à des articles dans les médias. Plongeons-nous un peu dans cette vulnérabilité et ce qu'elle nous apprend.

Name:Wreck est décrite dans un rapport (en anglais) de la société Forescout dont je vous recommande la lecture, c'est bien expliqué et avec une dose relativement limitée de sensationnalisme et de marketing. Name:Wreck n'est pas, comme cela a parfois été dit, une « vulnérabilité DNS » ou une « faille DNS » mais une bogue dans des logiciels client DNS. La bogue exploite une fonction peu connue du DNS, la compression des données dans les réponses. Comme le même nom de domaine peut apparaitre plusieurs fois dans une réponse DNS, l'encodage des noms dans le paquet peut se faire en ne mettant qu'une fois le nom et, le reste du temps, en mettant un pointeur vers ce nom. J'ai simplifié, pour avoir tous les détails, il faut lire le RFC 1035, section 4.1.4. (Notez que le rapport mentionne d'autres vulnérabilités, qui n'ont pas grand'chose à voir avec les pointeurs de compression.)

Si vous êtes programmeuse ou programmeur, vous avez déjà senti le problème : que se passe-t-il, par exemple, si le pointeur pointe en dehors du paquet ? Eh bien vous avez gagné, ce genre de problèmes est fréquent, beaucoup de mises en œuvre du DNS analysent les paquets sans faire assez attention. La section 6 du rapport cité plus haut liste un certain nombre d'erreurs courantes dans l'analyse des paquets DNS. Ces erreurs sont encore plus graves si on programme en C, langage qui, par défaut, vous laissera écrire au-delà des bornes. J'ajoute que mon expérience personnelle d'analyse de paquets DNS réels montre que les paquets mal formés sont une réalité, soit par désir de malveillance, soit par erreur. Ainsi, comme le note la sous-section 6.5 du rapport, un client DNS qui ferait une boucle sur le nombre d'enregistrements dans une section DNS sans précautions découvrirait rapidement que les paquets annonçant des milliers d'enregistrements, mais de taille bien trop courte pour les contenir, existent en vrai dans l'Internet. La règle de base de l'analyse de paquets entrants « soyez paranoïaques » s'applique au DNS.

Donc, en envoyant un paquet soigneusement calculé, avec des pointeurs de compression incorrects, on peut déclencher une boucle sans fin chez le client, ou un plantage, ou, pire, une exécution de code. Notons que si tout programme, quel que soit le langage dans lequel il est écrit, peut être vulnérable aux deux premières conséquences, la possibilité qu'une bogue mène à une exécution de code est quand même assez spécifique à C. Cela pourrait être un argument pour prôner l'utilisation de langages supposés plus sûrs, comme Rust (après, comme je n'ai pas appris à programmer en Rust, je réserve mon opinion).

La vulnérabilité existe par exemple dans le client DNS du système d'exploitation Nucleus de Siemens, conçu pour les objets connectés (cf. l'avis de sécurité). Elle touche aussi le système d'exploitation FreeBSD (cf. l'avis). Un des mérites des auteurs de l'étude est en effet de ne pas s'être limités aux clients DNS classiques mais d'avoir regardé d'autres logiciels qui analysent des informations DNS. C'est le cas des clients DHCP, qui peuvent recevoir des informations DNS, comme la liste des domaines à ajouter aux noms cherchés (option 119 en DHCP v4). En l'occurrence, chez FreeBSD, c'est en effet le client dhclient qui était vulnérable. (Quoique certaines mesures de protection peuvent, si elles sont utilisées, limiter les conséquences de la faille.)

Bien, donc, la faille existe. Maintenant, soyons positifs, agissons. Quelles sont les actions possibles ? Évidemment, les auteurs des logiciels concernés ont patché. Mais cela ne concerne que le code d'origine, pas toutes ses utilisations, loin en aval. Ce n'est pas parce qu'un patch existe chez FreeBSD, ou même qu'une nouvelle version de ce système d'exploitation sort, que toutes les machines FreeBSD de la planète vont recevoir le nouveau code. En outre, FreeBSD est souvent utilisé indirectement, par des gens qui ne savent même pas que le joli boitier très cher qu'ils ont acheté (répartiteur de charge, pare-feu, etc) utilise en fait FreeBSD. Ces boitiers spécialisés utilisent souvent des versions très en retard des logiciels (libres ou privateurs) qu'ils intègrent. Des versions vulnérables continueront donc à être en production pendant longtemps.

Et c'est encore pire dans le monde merveilleux de l'« Internet des Objets ». Là, la règle est le n'importe quoi, des objets vendus sans aucune mise à jour, ou bien une mise à jour compliquée, et qui ne dure de toute façon pas éternellement. Là, on peut parier que les versions vulnérables dureront bien plus longtemps. Un bonne lecture à rappeler est le RFC 8240, le compte-rendu d'un atelier IAB sur cette question de la mise à jour des objets connectés. Au passage, ce problème a une composante technique (ce sur quoi travaille le groupe de travail IETF SUIT) et surtout une composante business. Rien n'oblige les vendeurs d'objets connectés à assurer une maintenance rapide et correcte de leurs logiciels sur le long terme.

Bon, alors que faire en attendant ? Le rapport suggère d'isoler et de segmenter, pour éviter que les objets vulnérables se trouvent directement exposés au grand méchant Internet. C'est par exemple l'argument de Paul Vixie quand il dit qu'il faut s'assurer que les objets en entreprise ne parlent pas directement à des serveurs DNS externes mais passent forcément par un résolveur interne (qui ne leur enverra que des paquets DNS correctement formés). Le problème est que cela suppose que l'entreprise ait un résolveur interne, correct, à jour, qui rende le service attendu… (Par exemple, beaucoup de ces résolveurs internes ne valident pas.) Autrement, pas mal d'objets (via une décision de leur programmeur, ou de leur utilisateur) vont essayer de court-circuiter le résolveur local.

Et à l'IETF, peut-on faire quelque chose ? Changer le protocole DNS pour supprimer la compression n'est clairement pas possible, mais on pourrait attirer l'attention des programmeuses et des programmeurs sur ces dangers. C'est ce que propose un Internet-Draft écrit par les auteurs du rapport Name:Wreck, draft-dashevskyi-dnsrr-antipatterns. Le rapport suggère également de modifier le RFC 5625, qui dit qu'un relais DNS peut jeter les paquets mal formés. Le rapport suggère de dire qu'il le doit. Le problème est que certains de ces relais analysent la totalité des paquets (et peuvent donc les « proprifier ») alors que d'autres passent juste des bits et ne savent donc pas quels sont les paquets incorrects.

On peut quand même en tirer une leçon pour la conception de systèmes informatiques critiques : la compression dans le DNS est compliquée, mal spécifiée, et dangereuse. Comme la fragmentation/réassemblage dans IP, elle a déjà mené à pas mal de failles. On peut donc rappeler que la complexité est l'ennemie de la sécurité et que, pour gagner quelques octets, les auteurs du DNS ont créé une fonction dangereuse. Pensez-y la prochaine fois que vous entendrez quelqu'un dire que rajouter « juste une petite fonction simple » dans une spécification ou un code ne peut pas poser de problème.


L'article seul

Fiche de lecture : Cavanna, paléontologue !

Auteur(s) du livre : Pascal Tassy
Éditeur : Éditions Matériologiques
978-2-37361-252-3
Publié en 2020
Première rédaction de cet article le 7 avril 2021


Si, comme beaucoup de personnes (comme moi, par exemple), vous ignoriez que Cavanna était féru de paléontologie, vous allez l'apprendre dans ce court livre où l'auteur nous raconte ses échanges scientifiques avec le fondateur de Charlie Hebdo.

Cavanna avait de nombreuses cordes à son arc. Mais ce récit de Pascal Tassy se focalise sur une seule corde : la passion du « rital » pour l'étude des espèces disparues. Cavanna était curieux de sciences et aimait discuter avec les scientifiques. Son arrivée à la soutenance de thèse de l'auteur (thèse sur les mastodontes) avait sérieusement déstabilisé le bientôt docteur. Ils ont finalement parlé d'adaptation, de sélection naturelle, de cladistique, d'écologie… pendant de nombreuses années.

Si Cavanna et Pascal Tassy étaient d'accord sur beaucoup de choses (par exemple pour se moquer des créationnistes), il leur restait des sujets de controverses. J'ai ainsi appris que Cavanna, contrairement à son ami, était plutôt favorable au transhumanisme et tenté par l'idée d'immatérialisme.

Il était même prévu entre les deux amis d'écrire ensemble un livre… qui ne s'est finalement pas fait. À défaut, vous aurez dans ce récit quelques idées sur ce qu'aurait pu être ce livre.

Autre compte-rendu de ce livre, dans Charlie Hebdo.


L'article seul

RFC 9018: Interoperable Domain Name System (DNS) Server Cookies

Date de publication du RFC : Avril 2021
Auteur(s) du RFC : O. Sury (Internet Systems Consortium), W. Toorop (NLnet Labs), D. Eastlake 3rd (Futurewei Technologies), M. Andrews (Internet Systems Consortium)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 6 avril 2021


Le RFC 7873 normalisait un mécanisme, les cookies, pour qu'un serveur DNS authentifie raisonnablement l'adresse IP du client (ce qui, normalement, n'est pas le cas en UDP). Comme seul le serveur avait besoin de reconnaitre ses cookies, le RFC 7873 n'imposait pas un algorithme particulier pour les générer. Cela posait problème dans certains cas et notre nouveau RFC propose donc un mécanisme standard pour fabriquer ces cookies.

L'un des scénarios d'utilisation de ces « cookies standards » est le cas d'un serveur anycast dont on voudrait que toutes les instances génèrent des cookies standardisés, pour qu'une instance puisse reconnaitre les cookies d'une autre. Le RFC 7873, section 6, disait bien que toutes les instances avaient intérêt à partir du même secret mais ce n'était pas plus détaillé que cela. La situation actuelle, où chaque serveur peut faire différemment, est décrite dans le RFC par un mot en anglais que je ne connaissais pas, gallimaufry. D'où l'idée de spécifier cet algorithme, pour simplifier la vie des programmeuses et programmeurs avec un algorithme de génération de cookie bien étudié et documenté ; plus besoin d'en inventer un. Et cela permet de créer un service anycast avec des logiciels d'auteurs différents. S'ils utilisent cet algorithme, ils seront compatibles. Il ne s'agit que d'une possibilité : les serveurs peuvent utiliser cet algorithme mais ne sont pas obligés, le RFC 7873 reste d'actualité.

Comment, donc, construire un cookie ? Commençons par celui du client (section 3). Rappel : le but est d'authentifier un minimum donc, par exemple, le client doit choisir un cookie différent par serveur (sinon, un serveur pourrait se faire passer pour un autre, d'autant plus que le cookie circule en clair), et, donc, il faut utiliser quelque chose de spécifique au serveur dans l'algorithme, par exemple son adresse IP. Par contre, pas besoin de le changer souvent, il peut parfaitement durer des mois, sauf évidemment si un élément entrant dans sa construction change, ou est compromis. Autrefois, il était suggéré d'utiliser l'adresse IP du client dans la construction du cookie client, mais cette suggestion a été retirée car le logiciel ne connait parfois son adresse IP que trop tard (ça dépend de l'API réseau utilisée et, par exemple, avec l'API sockets de si on a déjà fait un bind() et, de toute façon, si on est derrière un routeur NAT, connaitre l'adresse IP locale ne sert pas à grand'chose). Néanmoins, pour éviter qu'un cookie ne permette à un observateur de relier deux requêtes d'une même machine, le cookie doit changer quand l'adresse IP change, comme rappelé par la section 8.1. (C'est particulièrement important si on utilise des techniques de protection de la vie privée comme celle du RFC 8981.)

Voilà, c'est tout parce que ce qui est important dans notre RFC, c'est le cookie serveur (section 4), puisque c'est là qu'on voudrait un cookie identique pour toutes les instances du service. Les éléments utilisés pour le générer sont le cookie du client, l'adresse IP du serveur, quelques métadonnées et un secret (qu'il faudra donc partager au sein du service anycast). Le secret changera, par exemple une fois par mois. Une fois qu'on a tous ces éléments, on va ensuite condenser le tout, ici avec SipHash (cf. J. Aumasson, et D. J. Bernstein, « SipHash: A Fast Short- Input PRF »). (Parmi les critères de choix d'une fonction de condensation, il y a les performances, un serveur DNS actif pouvant avoir à faire ce calcul souvent, pour vérifier les cookies.) Le cookie comprendra un numéro de version, un champ réservé, une estampille temporelle et le condensat. L'algorithme de génération du condensat inclus dans le cookie est donc : Condensat = SipHash-2-4 ( Cookie client | Version | Réservé | Estampille | Client-IP, Secret ), avec :

  • Le signe | indique la concaténation.
  • Le champ Version vaut actuellement 1 (les futures versions seront dans un registre IANA).
  • Le champ Réservé ne comporte pour l'instant que des zéros.
  • L'estampille temporelle sert à éviter les attaques par rejeu et permet de donner une durée de validité aux cookies (le RFC recommande une heure, avec cinq minutes de battement pour tenir compte des horloges mal synchronisées).

On a vu qu'il fallait changer le secret connu du serveur de temps en temps (voire plus rapidement s'il est compromis). Pour que ça ne casse pas tout (un serveur ne reconnaissant pas les cookies qu'il avait lui-même émis avec l'ancien secret…), il faut une période de recouvrement où le serveur connait déjà le nouveau secret (et accepte les cookies ainsi générés, par exemple par les autres instances du service anycast), puis une période où le serveur génère les cookies avec le nouveau secret, mais continue à accepter les cookies anciens (par exemple gardés par des clients). La section 5 rappelle, comme on le fait pour les remplacements de clés DNSSEC, de tenir compte des TTL pour calculer les délais nécessaires.

Si vous voulez mettre en œuvre vous-même cet algorithme, notez que l'annexe A du RFC contient des vecteurs de test, permettant de vérifier si vous ne vous êtes pas trompé.

La section 2 de notre RFC décrit les changements depuis le RFC 7873. Les algorithmes données comme simples suggestions dans les annexes A.1 et B.1 sont trop faibles et ne doivent pas être utilisés. Celui de l'annexe B.2 ne pose pas de problèmes de sécurité mais celui de notre nouveau RFC est préféré.

Plusieurs mises en œuvre de ce nouvel algorithme ont été faites, et leur interopérabilité testée (notamment au cours du hackathon de la réunion IETF 104 à Prague). Au moins BIND, Knot et getdns ont déjà cet algorithme dans leurs versions publiées.


Téléchargez le RFC 9018


L'article seul

Faut-il forcément passer du temps à étudier les techniques qui semblent farfelues ?

Première rédaction de cet article le 29 mars 2021


J'ai vu récemment, mais ce n'était la première fois, une personne se prétendant « inventeur » affirmer que ceux qui riaient de ses prétentions fantaisistes n'avaient pas pris le temps d'examiner son travail et que leurs critiques n'étaient donc pas pertinentes. Le bon sens dit en effet qu'il ne faut pas critiquer sans connaitre, et que connaitre nécessite de passer un peu de temps sur l'objet de la critique. Est-ce que le bon sens a raison ?

Le cas précis auquel je fais allusion concernait la sécurité informatique et l'inventeur prétendait avoir trouvé une solution de sécurité universelle. J'ai rencontré ce cas plusieurs fois en informatique (les participants à l'IETF penseront bien sûr à « IPv10 »). Mais ce serait la même chose avec quelqu'un prétendant avoir trouvé un remède contre toutes les maladies, ou bien une personne affirmant avoir mis au point le mouvement perpétuel. (On trouve même ce syndrome de l'inventeur génial dans les sciences humaines, par exemple les gens annonçant avoir déchiffré le disque de Phaistos.) Dans tous ces cas, face aux première réactions négatives, l'inventeur génial se drape dans sa dignité et dit bien haut que ses opposants n'ont pas lu ses textes, n'ont pas étudié sa machine, et qu'on ne doit donc pas les croire puisqu'ils n'ont même pas fait l'effort minimal de chercher à comprendre.

Ce raisonnement semble s'appuyer sur un principe de base de la science et de la technique : comprendre une invention n'est pas facile, il faut y passer du temps, et, tant qu'on ne l'a pas fait, on doit rester prudent dans ses affirmations. Mais il faut poursuivre plus loin ce raisonnement : c'est justement parce qu'évaluer sérieusement une invention prend du temps qu'on ne peut pas le faire pour chaque type qui annonce à l'univers qu'il a inventé un truc extraordinaire. Toute personne connue dans son domaine voit passer de nombreuses annonces d'inventions géniales, et si elle consacrait à chacune le temps nécessaire pour être absolument sûre de sa vacuité, cette personne n'aurait pas le temps de faire du travail sérieux.

Est-ce injuste ? Peut-être. Mais c'est ainsi. Les journées n'ont que 24 heures et il faut bien dormir de temps en temps. Si vous êtes inventeur, ne croyez pas qu'un·e expert·e du domaine va consacrer gratuitement des heures ou des jours de son temps à analyser patiemment tout ce que vous racontez. Trépigner du pied en enjoignant les expert·es de se pencher sur vos élucubrations ne produira pas de succès.

Mais, alors, une invention disruptive, surprenante, remettant en cause des certitudes n'a aucune chance de percer ? On ne travaillera que sur des choses déjà connues, sans surprise ? Non, évidemment. Mais on sélectionnera. L'expert·e passera du temps sur les propositions dont ielle estime, à première vue, qu'elles offrent des chances sérieuses de ne pas être une perte d'efforts. Pour celles qui sont très surprenantes, inhabituelles, et qui remettent en cause des certitudes, l'expert·e va d'abord utiliser des « signaux d'alarme ». Ce sont des heuristiques (terme prétentieux pour dire qu'elles ne sont pas parfaites, mais quand même utiles). Si vous êtes inventeur génial et que vous voulez augmenter vos chances d'être écouté, ne déclenchez pas ces signaux d'alarme :

  • Prétentions délirantes (« Ce mode de communication […] est insaisissable, intraçable, anonyme et totalement sécurisé »). Rappelez-vous que les annonces extraordinaires nécessitent des preuves extraordinaires. Plus vous vous vantez, plus vous aurez du mal à convaincre.
  • Applicabilité excessive. Les vraies inventions marchent dans certains cas, résolvent certains problèmes, et pas d'autres. Affirmer que vous allez « stopper les cyberattaques, les demandes de rançons informatiques ou encore les usurpations d'identité » ou « il pourrait aussi s'avérer très utile pour l'armée, puisqu'il s'agit là d'un outil idéal pour transmettre des ordres, des plans » ne contribue pas à votre crédibilité. Au contraire, une preuve de sérieux est quand vous exposez clairement les limites de votre invention (toute technique a des limites).
  • Ignorance complète des bases du domaine dans lequel vous prétendez avoir inventé quelque chose. Cette heuristique est d'un usage délicat car, parfois (« parfois » au sens de « une fois sur un zillion »), quelqu'un d'extérieur au domaine fait une percée, en partie justement car ielle n'était pas du domaine et pouvait donc penser « en dehors de la boite ». Mais c'est beaucoup plus rare que le cas où l'inventeur est simplement ignorant des difficultés du domaine. Un exemple est, en cryptographie, quelqu'un qui ne saurait pas ce qu'est une attaque de l'homme du milieu, ou qui ne comprendrait pas la différence entre cryptographie symétrique et asymétrique (« votre correspondant, une fois le message reçu, passe de la même façon sa carte, qui a la même clé de chiffrement que la vôtre »).
  • Propos vagues. Annoncer des résultats mirobolants sans donner de détails précis va allumer un signal d'alarme. Prétendre que cette absence de détails est due à votre souci d'éviter que les Chinois vous copient n'arrange rien (voir le point suivant).
  • Paranoïa. Un inventeur qui commence par « je suis génial mais le système / les puissants / les GAFA / Framasoft / les polytechniciens / les énarques conspirent pour me faire taire » allume également le plus puissant des signaux d'alarme. (J'en profite pour signaler que se comparer à Galilée n'aide pas. 1) Galilée n'a pas été rejeté par les autres scientifiques mais par les religieux, qui sont toujours opposés à la science 2) pour un Galilée, combien d'escrocs ?)
  • Grands mots. Ajouter « blockchain », « quantique » ou « IA » n'ajoute pas de la crédibilité à votre discours, sauf si vous pouvez expliquer en détail ce que ces techniques apportent à votre œuvre.
  • La forme compte aussi. Bien sûr, un inventeur génial peut avoir une orthographe catastrophique. Mais un texte bacler PLEIN D'AFFIRMATIONS EN MAJUSCULES et de ponctation !!! eksèssive car votre invantion est GÉNIALE !!! ne va pas vous aider. Respirez et prenez le temps de relire. (Au passage, n'avoir comme documentation que des vidéos convient si vous êtes influenceur beauté, pas si vous prétendez être inventeur.)

Tous les inventeurs ne déclenchent pas la totalité de ces signaux d'alarme. Mais ils en allument en général plusieurs. Comme toutes les heuristiques, elles ne sont pas parfaites. On ne connait pas de mécanisme parfait pour déterminer si une invention est géniale ou débile. Et les expert·es, comme tout le monde, peuvent se tromper. Mais, en raison de la finitude de la journée de travail, on doit utilise ces heuristiques, sinon on ne produirait jamais rien.


L'article seul

RFC 9006: TCP Usage Guidance in the Internet of Things (IoT)

Date de publication du RFC : Mars 2021
Auteur(s) du RFC : C. Gomez (UPC), J. Crowcroft (University of Cambridge), M. Scharf (Hochschule Esslingen)
Pour information
Réalisé dans le cadre du groupe de travail IETF lwig
Première rédaction de cet article le 28 mars 2021


À côté de machines disposant de ressources matérielles suffisantes (électricité, processeur, etc), qui peuvent faire tourner des protocoles comme TCP sans ajustements particuliers, il existe des machines dites contraintes, et des réseaux de machines contraintes, notamment dans le cadre de l'Internet des Objets. Ces machines, pauvres en énergie ou en capacités de calcul, doivent, si elles veulent participer à des communications sur l'Internet, adapter leur usage de TCP. Ce RFC documente les façons de faire du TCP « léger ».

Ces CNN (Constrained-Node Networks, réseaux contenant beaucoup d'objets contraints) sont décrits dans le RFC 7228. On parle bien d'objets contraints, soit en processeur, soit en énergie. Un Raspberry Pi ou une télévision connectée ne sont pas des objets contraints, ils peuvent utiliser les systèmes habituels, avec un TCP normal, au contraire des objets contraints, qui nécessitent des technologies adaptées. Le RFC 8352 explique ainsi les problèmes liés à la consommation électrique de certains protocoles. Des protocoles spéciaux ont été développés pour ces objets contraints, comme 6LoWPAN (RFC 4944, RFC 6282 et RFC 6775) ou comme le RPL du RFC 6550 ou, au niveau applicatif, le CoAP du RFC 7252.

Côté transport, on sait que les principaux protocoles de transport actuels sur l'Internet sont UDP et TCP. TCP a été parfois critiqué comme inadapté à l'Internet des Objets. Ces critiques n'étaient pas forcément justifiées mais il est sûr que le fait que TCP ait des en-têtes plutôt longs, pas de multicast et qu'il impose d'accuser réception de toutes les données peut ne pas être optimal pour ces réseaux d'objets contraints. D'autres reproches pouvaient être traités, comme expliqué dans l'article «  TCP in the Internet of Things: from ostracism to prominence ». Notez que CoAP, à l'origine, tournait uniquement sur UDP mais que depuis il existe aussi sur TCP (RFC 8323). Les CNN (Constrained-Node Networks) utilisent parfois d'autres protocoles applicatifs tournant sur TCP comme HTTP/2 (RFC 7540) ou MQTT.

TCP est certes complexe si on veut utiliser toutes les optimisations qui ont été développées au fil du temps. Mais elles ne sont pas nécessaires pour l'interopérabilité. Un TCP minimum peut parfaitement communiquer avec des TCP optimisés, et notre RFC explique comment réduire l'empreinte de TCP, tout en restant évidemment parfaitement compatible avec les TCP existants. (Notez qu'il y avait déjà eu des travaux sur l'adaptation de TCP à certains environnements, voir par exemple le RFC 3481.)

Bon, maintenant, au travail. Quelles sont les propriétés des CNN (RFC 7228) qui posent problème avec TCP (section 2 du RFC) ? Ils manquent d'énergie et il ne peuvent donc pas émettre et recevoir en permanence (RFC 8352), ils manquent de processeur, ce qui limite la complexité des protocoles, et ils utilisent souvent des réseaux physiques qui ont beaucoup de pertes (voire qui corrompent souvent les paquets), pas vraiment les réseaux avec lesquels TCP est le plus à l'aise (RFC 3819).

La communication d'un objet contraint se fait parfois à l'intérieur du CNN, avec un autre objet contraint et parfois avec une machine « normale » sur l'Internet. Les types d'interaction peuvent aller de l'unidirectionnel (un capteur transmet une mesure qu'il a faite), à la requête/réponse en passant par des transferts de fichiers (mise à jour du logiciel de l'objet contraint, par exemple). Voyons maintenant comment TCP peut s'adapter (section 3 du RFC).

D'abord, la MTU. En IPv6, faire des paquets de plus de 1 280 octets, c'est prendre le risque de la fragmentation, qui n'est pas une bonne chose pour des objets contraints en mémoire (RFC 8900), qui n'ont en plus pas très envie de faire de la Path MTU discovery (RFC 8201). Donc, notre RFC conseille d'utiliser la MSS (Maximum Segment Size) de TCP pour limiter la taille des paquets. Attention, les CNN tournent parfois sur des réseaux physiques assez spéciaux, où la MTU est bien inférieure aux 1 280 octets dont IPv6 a besoin (RFC 8200, section 5). Par exemple, IEEE 802.15.4 a une MTU de 127 octets seulement. Dans ce cas, il faut prévoir une couche d'adaptation entre IPv6 et le réseau physique (ce que fait le RFC 4944 pour IEE 802.15.4, le RFC 7668 pour Bluetooth LE, le RFC 8105 pour DECT LE, etc). Heureusement, d'autres technologies de réseau physique utilisées dans le monde des CNN n'ont pas ces limites de MTU, c'est le cas par exemple de Master-Slave/Token-Passing (cf. RFC 8163), IEEE 802.11ah, etc.

Deuxième endroit où on peut optimiser, ECN (RFC 3168). ECN permet aux routeurs intermédiaires de marquer dans un paquet que la congestion est proche ; le destinataire peut alors prévenir l'émetteur de ralentir. Le RFC 8087 décrit les avantages de l'ECN. Permettant de détecter l'approche de la congestion avant qu'on ait perdu un seul paquet (et donc sans qu'on ait à dépenser des watts pour retransmettre), l'ECN est particulièrement intéressant pour les CNN. Le RFC 7567 donne des conseils pratiques pour son déploiement.

Un problème classique de TCP sur les liens radio est que TCP interprète une perte de paquet comme signal de congestion, le poussant à ralentir, alors que cette perte peut en fait être due à la corruption d'un paquet (suite à une perturbation radio-électrique, par exemple). Il serait donc intéressant de pouvoir signaler explicitement ce genre de perte (la question était déjà discutée dans le RFC 2757 mais aussi dans l'article « Explicit Transport Error Notification (ETEN) for Error-Prone Wireless and Satellite Networks »). Pour l'instant, il n'existe aucun mécanisme standard pour cela, ce qui est bien dommage.

Pour faire tourner TCP sur une machine contrainte, une technique parfois utilisée est de n'envoyer qu'un segment à la fois (et donc d'annoncer une fenêtre dont la taille est d'un MSS - Maximum Segment Size). Dans ce cas, pas besoin de mémoriser plus qu'un segment de données envoyé mais dont l'accusé de réception n'a pas encore été reçu. C'est très économique, mais ça se paie cher en performances puisqu'il faut attendre l'accusé de réception de chaque segment avant d'en envoyer un autre. La capacité effective du lien va chuter, d'autant plus que certaines optimisations de TCP comme le fast recovery dépendent d'une fenêtre plus grande qu'un seul segment. Au niveau applicatif, on voit la même technique avec CoAP, qui est par défaut purement requête/réponse.

Si on veut faire du TCP « un seul segment », le code peut être simplifié, ce qui permet de gagner encore en octets, mais notre RFC rappelle quand même que des options comme MSS (évidemment), NoOp et EndOfOptions restent nécessaires. En revanche, on peut réduire le code en ne gérant pas les autres options comme WindowScaling (RFC 7323), Timestamps (RFC 7323) ou SACK (RFC 2018). TCP a le droit d'ignorer ces options, qui, en « un seul segment » sont parfois inutiles (WindowScaling, SACK) et parfois moins importantes (Timestamps). En tout cas, si la machine a assez de mémoire, il est sûr que transmettre plusieurs segments avant d'avoir eu l'accusé de réception du premier, et utiliser des algorithmes comme le fast recovery améliore certainement les performances. Même chose pour les accusés de réception sélectifs, les SACK du RFC 2018.

La détermination du RTO (Retransmission TimeOut) est un des points cruciaux de TCP (RFC 6298). S'il est trop long, on attendra longtemps la retransmission, quand un paquet est perdu, s'il est trop court, on ré-émettra parfois pour rien, gâchant des ressources alors que le paquet était juste en retard. Bref, une mise en œuvre de TCP pour les CNN doit soigner ses algorithmes de choix du RTO (cf. RFC 8961).

Continuons avec des conseils sur TCP dans les réseaux d'objets contraints. Notre RFC rappelle que les accusés de réception retardés, utiles pour accuser réception d'une plus grande quantité de données et ainsi diminuer le nombre de ces accusés, peuvent améliorer les performances… ou pas. Cela dépend du type de trafic. Si, par exemple, le trafic est surtout dans une direction, avec des messages courts (ce sera typiquement le cas avec CoAP), retarder les accusés de réception n'est sans doute pas une bonne idée.

Les paramètres par défaut de TCP sont parfois inadaptés aux CNN. Ainsi, le RFC 5681 recommande une taille de fenêtre initiale d'environ quatre kilo-octets. Le RFC 6298 fait des recommandations qui peuvent aboutir à des tailles de fenêtre initiale encore plus grandes. C'est très bien pour un PC connecté via la fibre mais pas pour la plupart des objets contraints, qui demandent des paramètres adaptés. Bref, il ne faut pas lire le RFC 6298 trop littéralement, car il faut en général une taille de fenêtre initiale plus petite.

Il n'y a pas que TCP lui-même, il y a aussi les applications qui l'utilisent. C'est l'objet de la section 4 du RFC. En général, si un objet contraint communique avec un non-contraint, c'est le premier qui initie la connexion (cela lui permet de dormir, et donc d'économiser l'énergie, s'il n'a rien à dire). L'objet contraint a tout intérêt à minimiser le nombre de connexions TCP, pour économiser la mémoire. Certes, cela crée des problèmes de head-of-line blocking (une opération un peu lente bloque les opérations ultérieures qui passent sur la même connexion TCP) mais cela vaut souvent la peine.

Et combien de temps garder la connexion TCP ouverte ? Tant qu'on a des choses à dire, c'est évident, on continue. Mais lorsqu'on n'a plus rien à dire, l'application doit-elle fermer les connexions, qui consomment de la mémoire, sachant que rouvrir la connexion prendra du temps et des ressources (la triple poignée de mains…). C'est un peu le problème de l'automobiliste arrêté qui se demande s'il doit couper son moteur. S'il faut redémarrer tout de suite, il consommera davantage de carburant. D'un autre côté, s'il laisse son moteur tourner, ce sera également un gaspillage. Le problème est soluble si l'application sait exactement quand elle aura à nouveau besoin d'émettre, ou si l'automobiliste sait exactement combien de temps durera l'arrêt mais, en pratique, on ne le sait pas toujours. (Ceci dit, pour l'automobile, le système d'arrêt-démarrage automatique dispense désormais le conducteur du choix.)

Une autre raison pour laquelle il faut être prudent avec les connexions TCP inactives est le NAT. Si un routeur NAT estime que la connexion est finie, il va retirer de ses tables la correspondance entre l'adresse IP interne et l'externe et, lorsqu'on voudra recommencer à transmettre des paquets, ils seront perdus. Le RFC 5382 donne des durées minimales avant ce retrait (deux heures…) mais elles ne sont pas forcément respectées par les routeurs NAT. Ainsi, l'étude « An Experimental Study of Home Gateway Characteristics » trouve que la moitié des boitiers testés ne respectent pas la recommandation du RFC 5382, avec des délais parfois aussi courts que quelques minutes ! Une des façons d'empêcher ces coupures est d'utiliser le mécanisme keep-alive de TCP (RFC 1122, section 4.2.3.6), qui envoie régulièrement des paquets dont le seul but est d'empêcher le routeur NAT d'oublier la connexion. Une autre est d'avoir des « battements de cœur » réguliers dans les applications, comme le permet CoAP (RFC 8323). Et, si on coupe rapidement les connexions TCP inutilisées, avant qu'une stupide middlebox ne le fasse, comment reprendre rapidement ensuite, si le trafic repart ? TCP Fast open (RFC 7413) est une solution possible.

Enfin, la sécurité pose des problèmes particuliers dans les CNN, où les ressources de certaines machines peuvent être insuffisantes pour certaines solutions de sécurité. Ainsi, pour TCP, la solution d'authentification AO (RFC 5925) augmente la taille des paquets et nécessite des calculs supplémentaires.

Il existe un certain nombre de mises en œuvre de TCP qui visent les objets contraints mentionnés dans ce RFC. Une machine 32 bits alimentée en courant en permanence, comme un vieux Raspberry Pi, n'est pas concernée, elle fait tourner le TCP habituel de Linux. On parle ici de TCP pour objets vraiment contraints. C'est par exemple (annexe A du RFC) le cas de :

  • uIP, qui vise les microcontrôleurs à 8 et 16 bits. Elle est utilisée dans Contiki et sur la carte d'extension Ethernet (shield) pour Arduino. En 5 ko, elle réussit à faire IP (dont IPv6 dans les dernières versions) et TCP. Elle fait partie de celles qui utilisent le « un segment à la fois », ce qui évite les calculs de fenêtres (qui nécessitent des calculs sur 32 bits, qui seraient lents sur ces processeurs). Et c'est à l'application de se souvenir de ce qu'elle a envoyé, TCP ne le fait pas pour elle. L'utiliser est donc difficile pour le programmeur.
  • lwIP, qui vise le même genre de processeurs, mais dont l'empreinte mémoire est supérieure (entre 14 et 22 ko). Il faut dire qu'elle n'est pas limitée à envoyer un segment à la fois et que TCP mémorise les données envoyées, déchargeant l'application de ce travail. Et elle dispose de nombreuses optimisations comme SACK.
  • RIOT a sa propre mise en œuvre de TCP, nommée GNRC TCP. Elle vise aussi les engins de classe 1 (cf. RFC 7228 pour cette terminologie). Elle est de type « un segment à la fois » mais c'est TCP, et pas l'application, qui se charge de mémoriser les données envoyées (et qu'il faudra peut-être retransmettre). Par défaut, une application ne peut avoir qu'une seule connexion et il faut recompiler si on veut changer cela. Par contre, RIOT dispose d'une interface sockets, familière à beaucoup de programmeurs.
  • freeRTOS a aussi un TCP, pouvant envoyer plusieurs segments (mais une option à un seul segment est possible, pour économiser la mémoire). Il a même les accusés de réception retardés.
  • uC/OS peut également faire du TCP avec plusieurs segments en vol.

Un tableau comparatif en annexe A.7 résume les principales propriétés de ces différentes mises en œuvre de TCP sur objets contraints.


Téléchargez le RFC 9006


L'article seul

RFC 8997: Deprecation of TLS 1.1 for Email Submission and Access

Date de publication du RFC : Mars 2021
Auteur(s) du RFC : L. Velvindron (cyberstorm.mu), S. Farrell (Trinity College Dublin)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF uta
Première rédaction de cet article le 24 mars 2021


Dans le cadre général de l'abandon des versions 1.0 et 1.1 du protocole TLS (cf. RFC 8996), ce RFC déclare que ces vieilles versions ne doivent plus être utilisées pour le courrier (mettant ainsi à jour le RFC 8314).

Ce RFC 8314 spécifiait l'usage de TLS pour la soumission et la récupération de courrier. Sa section 4.1 imposait une version minimale de TLS, la 1.1. Cette 1.1 étant officiellement abandonnée pour obsolescence dans le RFC 8996, la version minimale est maintenant la 1.2. C'est tout, ce RFC est simple et court.


Téléchargez le RFC 8997


L'article seul

RFC 8996: Deprecating TLSv1.0 and TLSv1.1

Date de publication du RFC : Mars 2021
Auteur(s) du RFC : K. Moriarty (Dell EMC), S. Farrell (Trinity College Dublin)
Réalisé dans le cadre du groupe de travail IETF tls
Première rédaction de cet article le 24 mars 2021
Dernière mise à jour le 25 mars 2021


Ce RFC est très court, car il s'agit juste de formaliser une évidence : les versions 1.0 et 1.1 du protocole de cryptographie TLS ne devraient plus être utilisées, elles souffrent de diverses failles, notamment de sécurité. Les seules versions de TLS à utiliser sont la 1.2 (recommandée depuis 2008 !) et la 1.3 (publiée en 2018). Ainsi, une bibliothèque TLS pourra retirer tout le code correspondant à ces versions abandonnées, ce qui diminuera les risques (moins de code, moins de bogues).

Que reproche-t-on exactement à ces vieux protocoles (section 1 du RFC) ?

  • Ils utilisent des algorithmes de cryptographie dépassés et dangereux, par exemple TLS 1.0 impose de gérer Triple DES, et SHA-1 est utilisé à plusieurs endroits. Un des points les plus problématiques à propos des vieilles versions de TLS est en effet leur dépendance vis-à-vis de cet algorithme de condensation SHA-1. Celui-ci est connu comme vulnérable.
  • Ils ne permettent pas d'utiliser les algorithmes modernes, notamment le chiffrement intègre.
  • Indépendamment des défauts de ces vieux protocoles, le seul fait d'avoir quatre versions à gérer augmente les risques d'erreur, pouvant mener à des attaques par repli.
  • Des développeurs de bibliothèques TLS ont manifesté leur souhait de retirer les vieilles versions de TLS, ce qui implique leur abandon officiel par l'IETF.
  • Pour davantage