SSU2

Proposal 159
Fermé
Author eyedeekay, orignal, zlatinb, zzz
Created 2021-09-12
Last Updated 2025-03-05
Target Version 0.9.56

Statut

Plan de déploiement :

FeatureTesting (not default)Enabled by default
Local test code2022-02
Joint test code2022-03
Joint test in-net0.9.54 2022-05
Freeze basic protocol0.9.54 2022-05
Basic Session0.9.55 2022-080.9.56 2022-11
Address Validation (Retry)0.9.55 2022-080.9.56 2022-11
Fragmented RI in handshake0.9.55 2022-080.9.56 2022-11
New Token0.9.55 2022-080.9.57 2022-11
Freeze extended protocol0.9.55 2022-08
Relay0.9.55 2022-080.9.56 2022-11
Peer Test0.9.55 2022-080.9.56 2022-11
Enable for random 2%0.9.55 2022-08
Path Validation0.9.55+ dev0.9.56 2022-11
Connection Migration0.9.55+ dev0.9.56 2022-11
Immediate ACK flag0.9.55+ dev0.9.56 2022-11
Key Rotation0.9.57 2023-020.9.58 2023-05
Disable SSU 1 (i2pd)0.9.56 2022-11
Disable SSU 1 (Java I2P)0.9.58 2023-050.9.61 2023-12
La session de base inclut la phase de négociation (handshake) et la phase de données. Le protocole étendu inclut le relais et le test de pairs.

Aperçu

Cette proposition décrit un protocole d’accord de clés authentifié pour améliorer la résistance de SSU à diverses formes d’identification automatisée et d’attaques.

La proposition est organisée comme suit : les objectifs de sécurité sont présentés, suivis d’une discussion du protocole de base. Ensuite, une spécification complète de tous les messages du protocole est donnée. Enfin, les adresses de router et l’identification de version sont discutées.

Comme avec les autres transports I2P, SSU2 est défini pour le transport point-à-point (routeur-à-routeur) des messages I2NP. Ce n’est pas un canal de données à usage général. Comme SSU, il fournit également deux services supplémentaires : le relais pour la traversée NAT et les tests de pairs pour la détermination de l’accessibilité entrante. Il fournit également un troisième service, absent dans SSU, pour la migration de connexion lorsqu’un pair change d’IP ou de port.

Motivation

SSU est la seule couche de protocole restante qui nécessite ElGamal, qui est très lent. Le contrôle de flux pour SSU est complexe et ne fonctionne pas bien. Certaines parties de SSU sont vulnérables aux attaques d’usurpation d’adresse. La négociation initiale n’utilise pas Noise.

Objectifs de conception

  • Réduire l’utilisation du CPU en éliminant ElGamal. Utiliser X25519 pour le DH.

  • Maintenir les fonctions Peer Test et Relay, et augmenter leur sécurité.

  • Faciliter l’implémentation en permettant l’utilisation d’algorithmes de contrôle de flux standards.

  • Réduire la latence de configuration. Le temps de configuration médian est actuellement d’environ 135 ms pour NTCP2 et 187 ms pour SSU, même si NTCP2 a un aller-retour supplémentaire ; remplacer ElGamal dans SSU2 devrait la réduire, mais d’autres modifications peuvent également aider.

  • Maintenir ou augmenter le débit maximum par rapport à SSU 1, tel que mesuré sur une gamme de latences simulées et de pourcentages de perte de paquets sur un testnet.

  • Empêcher les attaques d’amplification de trafic et de mauvais routage provenant d’adresses sources usurpées via la « validation d’adresse ».

  • Faciliter l’identification des paquets, pour réduire la dépendance aux solutions de repli et aux heuristiques qui rendent le code excessivement complexe.

  • Formaliser et améliorer la migration de connexion lorsque l’IP ou le port du pair change. Ne pas migrer les connexions tant que la validation d’adresse n’est pas terminée, pour prévenir les attaques. Certaines implémentations SSU 1 utilisent des heuristiques coûteuses pour gérer les changements de port dus au rebinding NAT. Aucune implémentation SSU 1 connue ne peut gérer les changements d’IP du tout.

  • Support SSU 1 et 2 sur un seul port, détection automatique, et publié comme un seul “transport” (c’est-à-dire RouterAddress) dans la NetDB.

  • Publier le support pour la version 1 uniquement, 2 uniquement, ou 1+2 dans la NetDB dans un champ séparé, et utiliser par défaut la version 1 uniquement (ne pas lier le support de version à une version particulière de routeur)

  • S’assurer que toutes les implémentations (Java/i2pd/Go) peuvent ajouter le support de la version 2 (ou non) selon leurs propres calendriers

  • Ajouter un remplissage aléatoire à tous les messages, y compris les messages de négociation et de données. Tout le remplissage doit être couvert par le MAC, contrairement au remplissage de fin de paquet dans SSU 1. Fournir un mécanisme d’options pour que les deux côtés puissent demander un remplissage minimum et maximum et/ou une distribution de remplissage. Les spécificités de la distribution de remplissage dépendent de l’implémentation et peuvent ou non être spécifiées dans le protocole lui-même.

  • Masquer les en-têtes et le contenu des messages qui ne sont pas entièrement chiffrés de manière suffisante pour que les boîtiers DPI et les signatures antivirus ne puissent pas facilement les classifier. S’assurer également que les messages envoyés à un pair unique ou à un ensemble de pairs n’aient pas un motif de bits similaire.

  • Corriger la perte de bits dans DH due au format Java Ticket1112, et accélérer le DH en passant à X25519.

  • Passer à une vraie fonction de dérivation de clé (KDF) plutôt que d’utiliser le résultat DH tel quel

  • Ajouter la “résistance au sondage” (comme l’appelle Tor) ; cela inclut la résistance aux attaques par rejeu.

  • Maintenir un échange de clés authentifié bidirectionnel (2W-AKE). Le 1W-AKE n’est pas suffisant pour notre application.

  • S’appuyer sur la clé publique statique publiée dans le RouterInfo comme une autre partie de l’authentification.

  • Ajouter des options/version dans la négociation pour une extensibilité future.

  • Ne pas ajouter de manière significative au CPU requis pour l’établissement de connexion ; si possible, le réduire de manière significative.

  • Supprimer l’exigence de padding à un multiple de 16 octets imposée par le chiffrement AES dans SSU 1.

  • Utiliser ChaCha/Poly1305 standard pour le chiffrement et MAC, remplaçant le chiffrement AES et le MAC HMAC-MD5-128 non-standard utilisé dans SSU 1.

  • Utiliser des clés de chiffrement séparées pour l’envoi et la réception, au lieu des clés communes pour les deux directions utilisées dans SSU 1.

  • Utiliser une poignée de main à 3 messages et un seul aller-retour, comme dans NTCP2. Supprimer le délai d’attente des messages de données qui fait de SSU effectivement une poignée de main à deux allers-retours.

  • Améliorer considérablement l’efficacité des ACK et NACK, qui est horrible dans SSU 1. Réduire la bande passante requise pour les ACK et NACK, et augmenter la taille de paquet disponible pour les données. Encoder efficacement les NACK pour une rafale de messages manquants, ce qui est courant sur WiFi.

  • Réduire la complexité requise pour implémenter la fragmentation des messages I2NP. Contourner les mécanismes de fragmentation et l’encodage pour les messages I2NP complets.

  • Minimiser la surcharge protocolaire avant le rembourrage, en particulier pour les ACKs. Bien que le rembourrage soit ajouté, la surcharge avant le rembourrage reste une surcharge. Les nœuds à faible bande passante doivent pouvoir utiliser SSU2.

  • Maintenir les horodatages pour la détection de rejeu et de décalage.

  • Éviter tout problème lié à l’année 2038 dans les horodatages, doit fonctionner au moins jusqu’en 2106.

  • Augmenter la MTU minimum de 620 à 1280 pour l’efficacité, la facilité d’implémentation, et l’augmentation de la taille maximale des messages I2NP. La fragmentation et le réassemblage sont assez coûteux. En fournissant de l’espace pour des messages tunnel de 1028 octets, une grande majorité des messages I2NP ne nécessiteront pas de fragmentation.

  • Augmenter le MTU maximum de 1488 (1484 pour IPv6) à 1500 pour l’efficacité. Supprimer l’exigence que le MTU soit un multiple de 16.

  • Augmenter la taille maximale des messages I2NP d’environ 32K dans SSU 1 à environ 64 KB comme dans NTCP2.

  • Supprimer la signature des champs IP et port de la négociation initiale, de sorte que les routers qui ne connaissent pas leur IP externe et leur port pourront se connecter.

  • Conserver le mécanisme de découverte IP/port de SSU 1 dans la négociation, afin que les routeurs puissent apprendre leur IP externe et leur port.

  • Inclure des représentants des développeurs de routeurs Java, C++ et Go dans la conception.

Non-Goals

  • Résistance DPI à toute épreuve… il s’agirait de transports pluggables, Proposition 109.

  • Un transport basé sur TLS (ou ressemblant à HTTPS)… qui serait Proposition 104.

  • Résistance DPI basée sur le timing (le timing/délais inter-messages peuvent dépendre de l’implémentation ; les délais intra-message peuvent être introduits à n’importe quel point, y compris avant l’envoi du padding aléatoire, par exemple). Les délais artificiels (ce qu’obfs4 appelle IAT ou inter-arrival time) sont indépendants du protocole lui-même.

  • Déniabilité de participation à une session (il y a des signatures dedans).

Objectifs non visés qui peuvent être partiellement reconsidérés ou discutés :

  • Le degré de protection contre l’Inspection Approfondie de Paquets (Deep Packet Inspection - DPI)

  • Sécurité post-quantique (PQ)

  • Déni plausible

Security Goals

Nous considérons trois parties :

  • Alice, qui souhaite établir une nouvelle session.
  • Bob, avec qui Alice souhaite établir une session.
  • Mallory, l’« homme du milieu » entre Alice et Bob.

Au maximum deux participants peuvent mener des attaques actives.

Alice et Bob possèdent tous les deux une paire de clés statiques, qui est contenue dans leur RouterIdentity.

Le protocole proposé tente de permettre à Alice et Bob de s’accorder sur une clé secrète partagée (K) selon les exigences suivantes :

  1. Sécurité de la clé privée : ni Bob ni Mallory n’apprennent quoi que ce soit sur la clé privée statique d’Alice. Symétriquement, Alice n’apprend rien sur la clé privée statique de Bob.

  2. La clé de session K n’est connue que par Alice et Bob.

  3. Confidentialité persistante parfaite : la clé de session convenue reste secrète dans le futur, même lorsque les clés privées statiques d’Alice et/ou Bob sont révélées après que la clé ait été convenue.

  4. Authentification bidirectionnelle : Alice est certaine qu’elle a établi une session avec Bob, et vice versa.

  5. Protection contre la DPI en ligne : S’assurer qu’il n’est pas trivial de détecter qu’Alice et Bob sont engagés dans le protocole en utilisant uniquement des techniques d’inspection approfondie des paquets (DPI) simples. Voir ci-dessous.

  6. Déni limité : ni Alice ni Bob ne peuvent nier leur participation au protocole, mais si l’un d’eux divulgue la clé partagée, l’autre partie peut nier l’authenticité du contenu des données transmises.

Cette proposition tente de fournir les cinq exigences basées sur le protocole Station-To-Station (STS). Notez que ce protocole est également la base du protocole SSU.

Additional DPI Discussion

Nous supposons deux composants DPI :

Online DPI

DPI en ligne inspectant tous les flux en temps réel. Les connexions peuvent être bloquées ou autrement altérées. Les données de connexion ou les métadonnées peuvent être identifiées et stockées pour une analyse hors ligne. Le DPI en ligne n’a pas accès à la base de données réseau I2P. Le DPI en ligne n’a qu’une capacité de calcul limitée en temps réel, incluant le calcul de longueur, l’inspection de champs, et des calculs simples tels que XOR. Le DPI en ligne dispose de la capacité d’exécuter des fonctions cryptographiques rapides en temps réel telles que ChaCha20, AEAD, et le hachage, mais celles-ci seraient trop coûteuses à appliquer à la plupart ou à tous les flux. Toute application de ces opérations cryptographiques ne s’appliquerait qu’aux flux sur des combinaisons IP/Port préalablement identifiées par l’analyse hors ligne. Le DPI en ligne n’a pas la capacité d’exécuter des fonctions cryptographiques à haute charge telles que DH ou elligator2. Le DPI en ligne n’est pas conçu spécifiquement pour détecter I2P, bien qu’il puisse avoir des règles de classification limitées à cette fin.

L’objectif est d’empêcher l’identification du protocole par une DPI en ligne.

La notion de DPI en ligne ou « directe » inclut ici les capacités adverses suivantes :

  1. La capacité d’inspecter toutes les données envoyées ou reçues par la cible.

  2. La capacité d’effectuer des opérations sur les données observées, telles que l’application de chiffrements par blocs ou de fonctions de hachage.

  3. La capacité de stocker et comparer avec les messages précédemment envoyés.

  4. La capacité de modifier, retarder ou fragmenter les paquets.

Cependant, le DPI en ligne est supposé avoir les restrictions suivantes :

  1. L’impossibilité de mapper les adresses IP aux hachages de router. Bien que cela soit trivial avec un accès en temps réel à la base de données réseau, cela nécessiterait un système DPI spécifiquement conçu pour cibler I2P.

  2. L’impossibilité d’utiliser les informations de temporisation pour détecter le protocole.

  3. De manière générale, la boîte à outils DPI en ligne ne contient aucun outil intégré spécifiquement conçu pour la détection I2P. Cela inclut la création de “honeypots”, qui par exemple incluraient un remplissage non aléatoire dans leurs messages. Notez que cela n’exclut pas les systèmes d’apprentissage automatique ou les outils DPI hautement configurables tant qu’ils répondent aux autres exigences.

Pour contrer l’analyse de charge utile, il est assuré que tous les messages sont indiscernables de données aléatoires. Cela nécessite également que leur longueur soit aléatoire, ce qui est plus compliqué que d’ajouter simplement un remplissage aléatoire. En fait, dans l’Annexe A, les auteurs soutiennent qu’un schéma de remplissage naïf (c’est-à-dire uniforme) ne résout pas le problème. L’Annexe A propose donc d’inclure soit des délais aléatoires, soit de développer un schéma de remplissage alternatif qui peut fournir une protection raisonnable contre l’attaque proposée.

Pour se protéger contre la sixième entrée ci-dessus, les implémentations devraient inclure des délais aléatoires dans le protocole. De telles techniques ne sont pas couvertes par cette proposition, mais elles pourraient également résoudre les problèmes de longueur de padding. En résumé, la proposition fournit une bonne protection contre l’analyse de charge utile (lorsque les considérations de l’Annexe A sont prises en compte), mais seulement une protection limitée contre l’analyse de flux.

Offline DPI

DPI hors ligne inspectant les données stockées par le DPI en ligne pour une analyse ultérieure. Le DPI hors ligne peut être conçu spécifiquement pour détecter I2P. Le DPI hors ligne n’a pas d’accès en temps réel à la base de données réseau I2P. Le DPI hors ligne a accès à cette spécification et aux autres spécifications I2P. Le DPI hors ligne dispose de capacités de calcul illimitées, incluant toutes les fonctions cryptographiques définies dans cette spécification.

Le DPI hors ligne n’a pas la capacité de bloquer les connexions existantes. Le DPI hors ligne a la capacité d’effectuer en temps quasi-réel (dans les minutes suivant la configuration) l’envoi vers l’hôte/port des parties par injection de paquets. Le DPI hors ligne a la capacité d’effectuer en temps quasi-réel (dans les minutes suivant la configuration) la relecture de messages précédents (modifiés ou non) pour du “sondage” ou d’autres raisons.

Ce n’est pas un objectif d’empêcher l’identification du protocole par une DPI hors ligne. Tout décodage de données obfusquées dans les deux premiers messages, qui est implémenté par les routers I2P, peut également être implémenté par la DPI hors ligne.

L’objectif est de rejeter les tentatives de connexion utilisant la réutilisation de messages précédents.

Address Validation

Ce qui suit est copié de QUIC RFC 9000. Pour chaque section, réviser et éditer.

La validation d’adresse garantit qu’un point de terminaison ne peut pas être utilisé pour une attaque d’amplification de trafic. Dans une telle attaque, un paquet est envoyé à un serveur avec des informations d’adresse source falsifiées qui identifient une victime. Si un serveur génère des paquets plus nombreux ou plus volumineux en réponse à ce paquet, l’attaquant peut utiliser le serveur pour envoyer plus de données vers la victime qu’il ne pourrait en envoyer par lui-même.

La défense principale contre les attaques d’amplification consiste à vérifier qu’un pair est capable de recevoir des paquets à l’adresse de transport qu’il revendique. Par conséquent, après avoir reçu des paquets d’une adresse qui n’est pas encore validée, un endpoint DOIT limiter la quantité de données qu’il envoie à l’adresse non validée à trois fois la quantité de données reçues de cette adresse. Cette limite sur la taille des réponses est connue sous le nom de limite anti-amplification.

La validation d’adresse est effectuée à la fois lors de l’établissement de connexion (voir Section 8.1) et lors de la migration de connexion (voir Section 8.2).

Address Validation during Connection Establishment

L’établissement de connexion fournit implicitement la validation d’adresse pour les deux points de terminaison. En particulier, la réception d’un paquet protégé avec des clés Handshake confirme que le pair a traité avec succès un paquet Initial. Une fois qu’un point de terminaison a traité avec succès un paquet Handshake du pair, il peut considérer que l’adresse du pair a été validée.

De plus, un endpoint PEUT considérer l’adresse du pair comme validée si le pair utilise un ID de connexion choisi par l’endpoint et que l’ID de connexion contient au moins 64 bits d’entropie.

Pour le client, la valeur du champ Destination Connection ID dans son premier paquet Initial lui permet de valider l’adresse du serveur dans le cadre du traitement réussi de tout paquet. Les paquets Initial du serveur sont protégés avec des clés qui sont dérivées de cette valeur (voir Section 5.2 de QUIC-TLS). Alternativement, la valeur est renvoyée en écho par le serveur dans les paquets Version Negotiation (Section 6) ou incluse dans l’Integrity Tag des paquets Retry (Section 5.8 de QUIC-TLS).

Avant de valider l’adresse client, les serveurs NE DOIVENT PAS envoyer plus de trois fois le nombre d’octets qu’ils ont reçus. Ceci limite l’ampleur de toute attaque par amplification qui peut être montée en utilisant des adresses sources usurpées. Dans le but d’éviter l’amplification avant la validation d’adresse, les serveurs DOIVENT compter tous les octets de charge utile reçus dans les datagrammes qui sont uniquement attribués à une seule connexion. Ceci inclut les datagrammes qui contiennent des paquets qui sont traités avec succès et les datagrammes qui contiennent des paquets qui sont tous rejetés.

Les clients DOIVENT s’assurer que les datagrammes UDP contenant des paquets Initial ont des charges utiles UDP d’au moins 1200 octets, en ajoutant des trames PADDING si nécessaire. Un client qui envoie des datagrammes rembourrés permet au serveur d’envoyer plus de données avant de terminer la validation d’adresse.

La perte d’un paquet Initial ou Handshake du serveur peut provoquer un interblocage si le client n’envoie pas de paquets Initial ou Handshake supplémentaires. Un interblocage pourrait se produire lorsque le serveur atteint sa limite anti-amplification et que le client a reçu des accusés de réception pour toutes les données qu’il a envoyées. Dans ce cas, lorsque le client n’a aucune raison d’envoyer des paquets supplémentaires, le serveur sera incapable d’envoyer plus de données car il n’a pas validé l’adresse du client. Pour éviter cet interblocage, les clients DOIVENT envoyer un paquet lors d’un Probe Timeout (PTO) ; voir Section 6.2 de QUIC-RECOVERY. Spécifiquement, le client DOIT envoyer un paquet Initial dans un datagramme UDP qui contient au moins 1200 octets s’il ne possède pas de clés Handshake, et sinon envoyer un paquet Handshake.

Un serveur pourrait souhaiter valider l’adresse du client avant de commencer la négociation cryptographique. QUIC utilise un token dans le paquet Initial pour fournir une validation d’adresse avant de terminer la négociation. Ce token est livré au client pendant l’établissement de connexion avec un paquet Retry (voir Section 8.1.2) ou dans une connexion précédente en utilisant la frame NEW_TOKEN (voir Section 8.1.3).

En plus des limites d’envoi imposées avant la validation d’adresse, les serveurs sont également contraints dans ce qu’ils peuvent envoyer par les limites définies par le contrôleur de congestion. Les clients ne sont contraints que par le contrôleur de congestion.

Token Construction

Un token envoyé dans une trame NEW_TOKEN ou un paquet Retry DOIT être construit de manière à permettre au serveur d’identifier comment il a été fourni à un client. Ces tokens sont transportés dans le même champ mais nécessitent une gestion différente de la part des serveurs.

Address Validation Using Retry Packets

Dès réception du paquet Initial du client, le serveur peut demander une validation d’adresse en envoyant un paquet Retry (Section 17.2.5) contenant un jeton. Ce jeton DOIT être répété par le client dans tous les paquets Initial qu’il envoie pour cette connexion après avoir reçu le paquet Retry.

En réponse au traitement d’un paquet Initial contenant un token qui a été fourni dans un paquet Retry, un serveur ne peut pas envoyer un autre paquet Retry ; il peut seulement refuser la connexion ou permettre qu’elle se poursuive.

Tant qu’il n’est pas possible pour un attaquant de générer un token valide pour sa propre adresse (voir Section 8.1.4) et que le client est capable de retourner ce token, cela prouve au serveur qu’il a reçu le token.

Un serveur peut également utiliser un paquet Retry pour reporter les coûts d’état et de traitement de l’établissement de connexion. Exiger du serveur qu’il fournisse un ID de connexion différent, ainsi que le paramètre de transport original_destination_connection_id défini dans la Section 18.2, oblige le serveur à démontrer que lui, ou une entité avec laquelle il coopère, a reçu le paquet Initial original du client. Fournir un ID de connexion différent accorde également au serveur un certain contrôle sur la façon dont les paquets suivants sont routés. Ceci peut être utilisé pour diriger les connexions vers une instance de serveur différente.

Si un serveur reçoit un Initial client qui contient un token Retry invalide mais qui est par ailleurs valide, il sait que le client n’acceptera pas un autre token Retry. Le serveur peut ignorer un tel paquet et permettre au client d’atteindre le délai d’expiration pour détecter l’échec de la négociation, mais cela pourrait imposer une pénalité de latence significative au client. Au lieu de cela, le serveur DEVRAIT immédiatement fermer (Section 10.2) la connexion avec une erreur INVALID_TOKEN. Notez qu’un serveur n’a établi aucun état pour la connexion à ce moment-là et n’entre donc pas dans la période de fermeture.

Un flux montrant l’utilisation d’un paquet Retry est illustré dans la Figure 9.

Client                                                  Server

Initial[0]: CRYPTO[CH] ->

                                                <- Retry+Token

Initial+Token[1]: CRYPTO[CH] ->

                                 Initial[0]: CRYPTO[SH] ACK[1]
                       Handshake[0]: CRYPTO[EE, CERT, CV, FIN]
                                 <- 1-RTT[0]: STREAM[1, "..."]

                Figure 9: Example Handshake with Retry

Address Validation for Future Connections

Un serveur PEUT fournir aux clients un jeton de validation d’adresse pendant une connexion qui peut être utilisé sur une connexion ultérieure. La validation d’adresse est particulièrement importante avec 0-RTT car un serveur envoie potentiellement une quantité importante de données à un client en réponse aux données 0-RTT.

Le serveur utilise la trame NEW_TOKEN (Section 19.7) pour fournir au client un jeton de validation d’adresse qui peut être utilisé pour valider les connexions futures. Dans une connexion future, le client inclut ce jeton dans les paquets Initial pour fournir la validation d’adresse. Le client DOIT inclure le jeton dans tous les paquets Initial qu’il envoie, sauf si un Retry remplace le jeton par un plus récent. Le client NE DOIT PAS utiliser le jeton fourni dans un Retry pour les connexions futures. Les serveurs PEUVENT rejeter tout paquet Initial qui ne porte pas le jeton attendu.

Contrairement au jeton qui est créé pour un paquet Retry, qui est utilisé immédiatement, le jeton envoyé dans la trame NEW_TOKEN peut être utilisé après qu’une certaine période de temps soit écoulée. Ainsi, un jeton DEVRAIT avoir un temps d’expiration, qui pourrait être soit un temps d’expiration explicite soit un horodatage d’émission qui peut être utilisé pour calculer dynamiquement le temps d’expiration. Un serveur peut stocker le temps d’expiration ou l’inclure sous forme chiffrée dans le jeton.

Un jeton émis avec NEW_TOKEN NE DOIT PAS inclure d’informations qui permettraient à un observateur de lier les valeurs à la connexion sur laquelle il a été émis. Par exemple, il ne peut pas inclure l’ID de connexion précédent ou les informations d’adressage, à moins que les valeurs ne soient chiffrées. Un serveur DOIT s’assurer que chaque trame NEW_TOKEN qu’il envoie est unique pour tous les clients, à l’exception de celles envoyées pour réparer les pertes de trames NEW_TOKEN précédemment envoyées. Les informations qui permettent au serveur de distinguer entre les jetons de Retry et NEW_TOKEN PEUVENT être accessibles à des entités autres que le serveur.

Il est peu probable que le numéro de port client soit identique sur deux connexions différentes ; la validation du port a donc peu de chances de réussir.

Un token reçu dans une trame NEW_TOKEN est applicable à tout serveur pour lequel la connexion est considérée comme faisant autorité (par exemple, les noms de serveur inclus dans le certificat). Lors de la connexion à un serveur pour lequel le client conserve un token applicable et inutilisé, il DEVRAIT inclure ce token dans le champ Token de son paquet Initial. L’inclusion d’un token pourrait permettre au serveur de valider l’adresse du client sans aller-retour supplémentaire. Un client NE DOIT PAS inclure un token qui n’est pas applicable au serveur auquel il se connecte, sauf si le client a connaissance que le serveur qui a émis le token et le serveur auquel le client se connecte gèrent conjointement les tokens. Un client PEUT utiliser un token de toute connexion précédente à ce serveur.

Un token permet à un serveur de corréler l’activité entre la connexion où le token a été émis et toute connexion où il est utilisé. Les clients qui souhaitent rompre la continuité d’identité avec un serveur peuvent se débarrasser des tokens fournis en utilisant la frame NEW_TOKEN. En comparaison, un token obtenu dans un paquet Retry DOIT être utilisé immédiatement pendant la tentative de connexion et ne peut pas être utilisé lors de tentatives de connexion ultérieures.

Un client NE DEVRAIT PAS réutiliser un jeton d’une trame NEW_TOKEN pour différentes tentatives de connexion. La réutilisation d’un jeton permet aux connexions d’être liées par des entités sur le chemin réseau ; voir Section 9.5.

Les clients peuvent recevoir plusieurs tokens sur une seule connexion. En plus de prévenir la traçabilité, n’importe quel token peut être utilisé dans toute tentative de connexion. Les serveurs peuvent envoyer des tokens supplémentaires soit pour permettre la validation d’adresse pour plusieurs tentatives de connexion, soit pour remplacer des tokens plus anciens qui pourraient devenir invalides. Pour un client, cette ambiguïté signifie que l’envoi du token inutilisé le plus récent a le plus de chances d’être efficace. Bien que sauvegarder et utiliser des tokens plus anciens n’ait aucune conséquence négative, les clients peuvent considérer que les tokens plus anciens sont moins susceptibles d’être utiles au serveur pour la validation d’adresse.

Lorsqu’un serveur reçoit un paquet Initial avec un jeton de validation d’adresse, il DOIT tenter de valider le jeton, sauf s’il a déjà terminé la validation d’adresse. Si le jeton est invalide, alors le serveur DEVRAIT procéder comme si le client n’avait pas d’adresse validée, incluant potentiellement l’envoi d’un paquet Retry. Les jetons fournis avec les trames NEW_TOKEN et les paquets Retry peuvent être distingués par les serveurs (voir Section 8.1.1), et ces derniers peuvent être validés de manière plus stricte. Si la validation réussit, le serveur DEVRAIT alors permettre à la négociation de se poursuivre.

Remarque : La logique qui consiste à traiter le client comme non validé plutôt que d’abandonner le paquet est que le client pourrait avoir reçu le jeton lors d’une connexion précédente en utilisant la trame NEW_TOKEN, et si le serveur a perdu son état, il pourrait être incapable de valider complètement le jeton, entraînant un échec de connexion si le paquet est abandonné.

Dans une conception sans état, un serveur peut utiliser des jetons chiffrés et authentifiés pour transmettre des informations aux clients que le serveur peut ensuite récupérer et utiliser pour valider une adresse client. Les jetons ne sont pas intégrés dans la négociation cryptographique, et ils ne sont donc pas authentifiés. Par exemple, un client pourrait être capable de réutiliser un jeton. Pour éviter les attaques qui exploitent cette propriété, un serveur peut limiter son utilisation des jetons uniquement aux informations nécessaires pour valider les adresses client.

Les clients PEUVENT utiliser des jetons obtenus sur une connexion pour toute tentative de connexion utilisant la même version. Lors de la sélection d’un jeton à utiliser, les clients n’ont pas besoin de considérer d’autres propriétés de la connexion qui est tentée, incluant le choix des protocoles d’application possibles, les tickets de session, ou d’autres propriétés de connexion.

Address Validation Token Integrity

Un jeton de validation d’adresse DOIT être difficile à deviner. Inclure une valeur aléatoire avec au moins 128 bits d’entropie dans le jeton serait suffisant, mais cela dépend du serveur se souvenant de la valeur qu’il envoie aux clients.

Un schéma basé sur des jetons permet au serveur de décharger tout état associé à la validation vers le client. Pour que cette conception fonctionne, le jeton DOIT être couvert par une protection d’intégrité contre la modification ou la falsification par les clients. Sans protection d’intégrité, des clients malveillants pourraient générer ou deviner des valeurs pour des jetons qui seraient acceptés par le serveur. Seul le serveur nécessite un accès à la clé de protection d’intégrité pour les jetons.

Il n’y a pas besoin d’un format unique bien défini pour le jeton car le serveur qui génère le jeton le consomme également. Les jetons envoyés dans les paquets Retry DEVRAIENT inclure des informations qui permettent au serveur de vérifier que l’adresse IP source et le port dans les paquets clients restent constants.

Les jetons envoyés dans les trames NEW_TOKEN DOIVENT inclure des informations qui permettent au serveur de vérifier que l’adresse IP du client n’a pas changé depuis l’émission du jeton. Les serveurs peuvent utiliser les jetons des trames NEW_TOKEN pour décider de ne pas envoyer un paquet Retry, même si l’adresse du client a changé. Si l’adresse IP du client a changé, le serveur DOIT respecter la limite anti-amplification ; voir Section 8. Notez qu’en présence de NAT, cette exigence pourrait être insuffisante pour protéger les autres hôtes qui partagent le NAT contre les attaques par amplification.

Les attaquants pourraient rejouer les jetons pour utiliser les serveurs comme amplificateurs dans des attaques DDoS. Pour se protéger contre de telles attaques, les serveurs DOIVENT s’assurer que le rejeu de jetons soit empêché ou limité. Les serveurs DEVRAIENT s’assurer que les jetons envoyés dans les paquets Retry ne soient acceptés que pendant une courte période, car ils sont renvoyés immédiatement par les clients. Les jetons qui sont fournis dans les trames NEW_TOKEN (Section 19.7) doivent être valides plus longtemps mais NE DEVRAIENT PAS être acceptés plusieurs fois. Les serveurs sont encouragés à permettre que les jetons ne soient utilisés qu’une seule fois, si possible ; les jetons PEUVENT inclure des informations supplémentaires sur les clients pour restreindre davantage l’applicabilité ou la réutilisation.

DPI en ligne

La validation de chemin est utilisée par les deux pairs lors de la migration de connexion (voir Section 9) pour vérifier l’accessibilité après un changement d’adresse. Dans la validation de chemin, les points de terminaison testent l’accessibilité entre une adresse locale spécifique et une adresse de pair spécifique, où une adresse est le 2-tuple d’adresse IP et de port.

La validation de chemin teste que les paquets envoyés sur un chemin vers un pair sont reçus par ce pair. La validation de chemin est utilisée pour s’assurer que les paquets reçus d’un pair en migration ne portent pas une adresse source usurpée.

La validation de chemin ne valide pas qu’un pair peut envoyer dans la direction de retour. Les accusés de réception ne peuvent pas être utilisés pour la validation du chemin de retour car ils contiennent une entropie insuffisante et pourraient être usurpés. Les points de terminaison déterminent indépendamment l’accessibilité sur chaque direction d’un chemin, et par conséquent l’accessibilité de retour ne peut être établie que par le pair.

La validation de chemin peut être utilisée à tout moment par l’un ou l’autre des endpoints. Par exemple, un endpoint pourrait vérifier qu’un pair est toujours en possession de son adresse après une période d’inactivité.

La validation de chemin n’est pas conçue comme un mécanisme de traversée NAT. Bien que le mécanisme décrit ici puisse être efficace pour la création de liaisons NAT qui prennent en charge la traversée NAT, l’attente est qu’un point de terminaison soit capable de recevoir des paquets sans avoir d’abord envoyé un paquet sur ce chemin. Une traversée NAT efficace nécessite des mécanismes de synchronisation supplémentaires qui ne sont pas fournis ici.

Un endpoint PEUT inclure d’autres trames avec les trames PATH_CHALLENGE et PATH_RESPONSE utilisées pour la validation de chemin. En particulier, un endpoint peut inclure des trames PADDING avec une trame PATH_CHALLENGE pour la découverte de l’unité de transmission maximale de chemin (PMTUD) ; voir la Section 14.2.1. Un endpoint peut également inclure sa propre trame PATH_CHALLENGE lors de l’envoi d’une trame PATH_RESPONSE.

Un endpoint utilise un nouvel ID de connexion pour les sondes envoyées depuis une nouvelle adresse locale ; voir Section 9.5. Lors du sondage d’un nouveau chemin, un endpoint peut s’assurer que son pair dispose d’un ID de connexion inutilisé disponible pour les réponses. L’envoi des trames NEW_CONNECTION_ID et PATH_CHALLENGE dans le même paquet, si la active_connection_id_limit du pair le permet, garantit qu’un ID de connexion inutilisé sera disponible pour le pair lors de l’envoi d’une réponse.

Un endpoint peut choisir de sonder simultanément plusieurs chemins. Le nombre de chemins simultanés utilisés pour les sondes est limité par le nombre d’ID de connexion supplémentaires que son pair a fournis précédemment, car chaque nouvelle adresse locale utilisée pour une sonde nécessite un ID de connexion non utilisé auparavant.

DPI hors ligne

Pour initier la validation de chemin, un endpoint envoie une frame PATH_CHALLENGE contenant une charge utile imprévisible sur le chemin à valider.

Un endpoint PEUT envoyer plusieurs trames PATH_CHALLENGE pour se protéger contre la perte de paquets. Cependant, un endpoint NE DEVRAIT PAS envoyer plusieurs trames PATH_CHALLENGE dans un seul paquet.

Un endpoint NE DEVRAIT PAS sonder un nouveau chemin avec des paquets contenant une trame PATH_CHALLENGE plus fréquemment qu’il n’enverrait un paquet Initial. Cela garantit que la migration de connexion ne représente pas plus de charge sur un nouveau chemin que l’établissement d’une nouvelle connexion.

Le point de terminaison DOIT utiliser des données imprévisibles dans chaque trame PATH_CHALLENGE afin de pouvoir associer la réponse du pair avec le PATH_CHALLENGE correspondant.

Un endpoint DOIT étendre les datagrammes qui contiennent une trame PATH_CHALLENGE à au moins la plus petite taille maximale de datagramme autorisée de 1200 octets, sauf si la limite anti-amplification pour le chemin ne permet pas d’envoyer un datagramme de cette taille. L’envoi de datagrammes UDP de cette taille garantit que le chemin réseau de l’endpoint vers le pair peut être utilisé pour QUIC ; voir Section 14.

Lorsqu’un point de terminaison ne peut pas étendre la taille du datagramme à 1200 octets en raison de la limite anti-amplification, le MTU du chemin ne sera pas validé. Pour s’assurer que le MTU du chemin est suffisamment important, le point de terminaison DOIT effectuer une seconde validation de chemin en envoyant une trame PATH_CHALLENGE dans un datagramme d’au moins 1200 octets. Cette validation supplémentaire peut être effectuée après qu’une PATH_RESPONSE ait été reçue avec succès ou lorsque suffisamment d’octets ont été reçus sur le chemin pour que l’envoi du datagramme plus important ne résulte pas en un dépassement de la limite anti-amplification.

Contrairement à d’autres cas où les datagrammes sont étendus, les endpoints NE DOIVENT PAS rejeter les datagrammes qui semblent être trop petits lorsqu’ils contiennent PATH_CHALLENGE ou PATH_RESPONSE.

Path Validation Responses

À la réception d’une trame PATH_CHALLENGE, un point de terminaison DOIT répondre en renvoyant en écho les données contenues dans la trame PATH_CHALLENGE dans une trame PATH_RESPONSE. Un point de terminaison NE DOIT PAS retarder la transmission d’un paquet contenant une trame PATH_RESPONSE sauf si contraint par le contrôle de congestion.

Une frame PATH_RESPONSE DOIT être envoyée sur le chemin réseau où la frame PATH_CHALLENGE a été reçue. Cela garantit que la validation de chemin par un pair ne réussit que si le chemin est fonctionnel dans les deux directions. Cette exigence NE DOIT PAS être appliquée par le point de terminaison qui initie la validation de chemin, car cela permettrait une attaque sur la migration ; voir Section 9.3.3.

Un endpoint DOIT étendre les datagrammes qui contiennent une trame PATH_RESPONSE à au moins la plus petite taille maximale de datagramme autorisée de 1200 octets. Cela vérifie que le chemin est capable de transporter des datagrammes de cette taille dans les deux directions. Cependant, un endpoint NE DOIT PAS étendre le datagramme contenant le PATH_RESPONSE si les données résultantes dépassent la limite anti-amplification. Cela ne devrait se produire que si le PATH_CHALLENGE reçu n’a pas été envoyé dans un datagramme étendu.

Un endpoint NE DOIT PAS envoyer plus d’une trame PATH_RESPONSE en réponse à une trame PATH_CHALLENGE ; voir Section 13.3. Le pair est censé envoyer davantage de trames PATH_CHALLENGE si nécessaire pour provoquer des trames PATH_RESPONSE supplémentaires.

Validation d’adresse lors de l’établissement de connexion

La validation de chemin réussit lorsqu’une trame PATH_RESPONSE est reçue qui contient les données qui ont été envoyées dans une trame PATH_CHALLENGE précédente. Une trame PATH_RESPONSE reçue sur n’importe quel chemin réseau valide le chemin sur lequel le PATH_CHALLENGE a été envoyé.

Si un point de terminaison envoie une trame PATH_CHALLENGE dans un datagramme qui n’est pas étendu à au moins 1200 octets et si la réponse valide l’adresse du pair, le chemin est validé mais pas le MTU du chemin. En conséquence, le point de terminaison peut maintenant envoyer plus de trois fois la quantité de données qui ont été reçues. Cependant, le point de terminaison DOIT initier une autre validation de chemin avec un datagramme étendu pour vérifier que le chemin prend en charge le MTU requis.

La réception d’un accusé de réception pour un paquet contenant une trame PATH_CHALLENGE n’est pas une validation adéquate, car l’accusé de réception peut être falsifié par un pair malveillant.

Construction de Token

La validation de chemin échoue seulement lorsque le point de terminaison tentant de valider le chemin abandonne sa tentative de validation du chemin.

Les endpoints DEVRAIENT abandonner la validation de chemin basée sur un minuteur. Lors de la configuration de ce minuteur, les implémentations sont averties que le nouveau chemin pourrait avoir un temps d’aller-retour plus long que l’original. Une valeur de trois fois le plus grand entre le PTO actuel ou le PTO pour le nouveau chemin (en utilisant kInitialRtt, tel que défini dans QUIC-RECOVERY) est RECOMMANDÉE.

Ce délai d’expiration permet à plusieurs PTO d’expirer avant l’échec de la validation du chemin, de sorte que la perte d’une seule trame PATH_CHALLENGE ou PATH_RESPONSE n’entraîne pas l’échec de la validation du chemin.

Notez que le point de terminaison peut recevoir des paquets contenant d’autres trames sur le nouveau chemin, mais une trame PATH_RESPONSE avec les données appropriées est requise pour que la validation du chemin réussisse.

Lorsqu’un point de terminaison abandonne la validation de chemin, il détermine que le chemin est inutilisable. Cela n’implique pas nécessairement un échec de la connexion – les points de terminaison peuvent continuer à envoyer des paquets sur d’autres chemins selon les besoins. Si aucun chemin n’est disponible, un point de terminaison peut attendre qu’un nouveau chemin devienne disponible ou fermer la connexion. Un point de terminaison qui n’a pas de chemin réseau valide vers son pair PEUT signaler ceci en utilisant l’erreur de connexion NO_VIABLE_PATH, en notant que ceci n’est possible que si le chemin réseau existe mais ne supporte pas le MTU requis (Section 14).

Une validation de chemin peut être abandonnée pour d’autres raisons que l’échec. Principalement, cela se produit si une migration de connexion vers un nouveau chemin est initiée pendant qu’une validation de chemin sur l’ancien chemin est en cours.

Connection Migration

Ce qui suit est copié de QUIC RFC 9000. Pour chaque section, examinez et modifiez.

L’utilisation d’un ID de connexion permet aux connexions de survivre aux changements d’adresses de point de terminaison (adresse IP et port), tels que ceux causés par un point de terminaison migrant vers un nouveau réseau. Cette section décrit le processus par lequel un point de terminaison migre vers une nouvelle adresse.

La conception de QUIC repose sur le fait que les points de terminaison conservent une adresse stable pendant toute la durée de la négociation. Un point de terminaison NE DOIT PAS initier une migration de connexion avant que la négociation soit confirmée, comme défini dans la Section 4.1.2 de QUIC-TLS.

Si le pair a envoyé le paramètre de transport disable_active_migration, un endpoint NE DOIT également PAS envoyer de paquets (y compris les paquets de sondage ; voir Section 9.1) depuis une adresse locale différente vers l’adresse que le pair a utilisée pendant la négociation, sauf si l’endpoint a agi sur un paramètre de transport preferred_address du pair. Si le pair viole cette exigence, l’endpoint DOIT soit abandonner les paquets entrants sur ce chemin sans générer de Stateless Reset, soit procéder à la validation du chemin et permettre au pair de migrer. Générer un Stateless Reset ou fermer la connexion permettrait à des tiers sur le réseau de provoquer la fermeture de connexions en usurpant l’identité ou en manipulant autrement le trafic observé.

Tous les changements d’adresse de pair ne sont pas des migrations intentionnelles ou actives. Le pair pourrait subir une reliure NAT : un changement d’adresse dû à un middlebox, généralement un NAT, allouant un nouveau port sortant ou même une nouvelle adresse IP sortante pour un flux. Un endpoint DOIT effectuer une validation de chemin (Section 8.2) s’il détecte un changement d’adresse d’un pair, sauf s’il a préalablement validé cette adresse.

Lorsqu’un point de terminaison n’a aucun chemin validé sur lequel envoyer des paquets, il PEUT abandonner l’état de connexion. Un point de terminaison capable de migration de connexion PEUT attendre qu’un nouveau chemin devienne disponible avant d’abandonner l’état de connexion.

Ce document limite la migration des connexions vers de nouvelles adresses client, sauf tel que décrit dans la Section 9.6. Les clients sont responsables d’initier toutes les migrations. Les serveurs n’envoient pas de paquets non-exploratoires (voir Section 9.1) vers une adresse client jusqu’à ce qu’ils voient un paquet non-exploratoire de cette adresse. Si un client reçoit des paquets d’une adresse serveur inconnue, le client DOIT rejeter ces paquets.

Validation d’adresse utilisant les paquets de nouvelle tentative

Un endpoint PEUT sonder l’accessibilité d’un pair depuis une nouvelle adresse locale en utilisant la validation de chemin (Section 8.2) avant de migrer la connexion vers la nouvelle adresse locale. L’échec de la validation de chemin signifie simplement que le nouveau chemin n’est pas utilisable pour cette connexion. L’échec de validation d’un chemin n’entraîne pas la fin de la connexion sauf s’il n’y a pas de chemins alternatifs valides disponibles.

Les trames PATH_CHALLENGE, PATH_RESPONSE, NEW_CONNECTION_ID et PADDING sont des “trames de sondage”, et toutes les autres trames sont des “trames de non-sondage”. Un paquet contenant uniquement des trames de sondage est un “paquet de sondage”, et un paquet contenant toute autre trame est un “paquet de non-sondage”.

Validation d’adresse pour les connexions futures

Un endpoint peut migrer une connexion vers une nouvelle adresse locale en envoyant des paquets contenant des trames non-probing depuis cette adresse.

Chaque endpoint valide l’adresse de son pair lors de l’établissement de la connexion. Par conséquent, un endpoint en migration peut envoyer à son pair en sachant que le pair est prêt à recevoir à l’adresse actuelle du pair. Ainsi, un endpoint peut migrer vers une nouvelle adresse locale sans avoir d’abord à valider l’adresse du pair.

Pour établir la joignabilité sur le nouveau chemin, un point de terminaison initie la validation de chemin (Section 8.2) sur le nouveau chemin. Un point de terminaison PEUT différer la validation de chemin jusqu’après qu’un pair envoie la prochaine trame non-sonde vers sa nouvelle adresse.

Lors de la migration, le nouveau chemin pourrait ne pas prendre en charge le débit d’envoi actuel du point de terminaison. Par conséquent, le point de terminaison remet à zéro son contrôleur de congestion et son estimation RTT, comme décrit dans la Section 9.4.

Le nouveau chemin pourrait ne pas avoir la même capacité ECN. Par conséquent, le point de terminaison valide la capacité ECN comme décrit dans la Section 13.4.

Intégrité du jeton de validation d’adresse

Recevoir un paquet d’une nouvelle adresse de pair contenant une trame non-exploratoire indique que le pair a migré vers cette adresse.

Si le destinataire autorise la migration, il DOIT envoyer les paquets suivants à la nouvelle adresse de pair et DOIT initier la validation de chemin (Section 8.2) pour vérifier la propriété de l’adresse par le pair si la validation n’est pas déjà en cours. Si le destinataire n’a pas d’ID de connexion inutilisés provenant du pair, il ne pourra rien envoyer sur le nouveau chemin jusqu’à ce que le pair en fournisse un ; voir Section 9.5.

Un point de terminaison ne change l’adresse vers laquelle il envoie des paquets qu’en réponse au paquet non-sonde avec le numéro le plus élevé. Cela garantit qu’un point de terminaison n’envoie pas de paquets vers une ancienne adresse de pair dans le cas où il reçoit des paquets réordonnés.

Un point de terminaison PEUT envoyer des données à une adresse de pair non validée, mais il DOIT se protéger contre les attaques potentielles comme décrit dans les Sections 9.3.1 et 9.3.2. Un point de terminaison PEUT ignorer la validation d’une adresse de pair si cette adresse a été vue récemment. En particulier, si un point de terminaison retourne à un chemin précédemment validé après avoir détecté une forme de migration factice, ignorer la validation d’adresse et restaurer l’état de détection de perte et de congestion peut réduire l’impact sur les performances de l’attaque.

Après avoir modifié l’adresse à laquelle il envoie les paquets non-sonde, un endpoint peut abandonner toute validation de chemin pour d’autres adresses.

Recevoir un paquet d’une nouvelle adresse de pair pourrait être le résultat d’un rebinding NAT chez le pair.

Après avoir vérifié une nouvelle adresse client, le serveur DEVRAIT envoyer de nouveaux jetons de validation d’adresse (Section 8) au client.

Validation de Chemin

Il est possible qu’un pair usurpe son adresse source pour amener un point de terminaison à envoyer des quantités excessives de données vers un hôte non consentant. Si le point de terminaison envoie significativement plus de données que le pair usurpateur, la migration de connexion pourrait être utilisée pour amplifier le volume de données qu’un attaquant peut générer vers une victime.

Comme décrit dans la Section 9.3, un endpoint est requis pour valider la nouvelle adresse d’un pair afin de confirmer la possession de cette nouvelle adresse par le pair. Jusqu’à ce que l’adresse d’un pair soit considérée comme valide, un endpoint limite la quantité de données qu’il envoie à cette adresse ; voir Section 8. En l’absence de cette limite, un endpoint risque d’être utilisé pour une attaque par déni de service contre une victime qui ne se doute de rien.

Si un endpoint ignore la validation d’une adresse de pair comme décrit ci-dessus, il n’a pas besoin de limiter son taux d’envoi.

Initiation de la validation de chemin

Un attaquant sur le chemin pourrait provoquer une migration de connexion fallacieuse en copiant et transmettant un paquet avec une adresse usurpée de sorte qu’il arrive avant le paquet original. Le paquet avec l’adresse usurpée sera perçu comme provenant d’une connexion en migration, et le paquet original sera considéré comme un doublon et abandonné. Après une migration fallacieuse, la validation de l’adresse source échouera car l’entité à l’adresse source ne possède pas les clés cryptographiques nécessaires pour lire ou répondre à la trame PATH_CHALLENGE qui lui est envoyée, même si elle le souhaitait.

Pour protéger la connexion contre les échecs dus à une telle migration parasite, un endpoint DOIT revenir à l’utilisation de la dernière adresse de pair validée lorsque la validation d’une nouvelle adresse de pair échoue. De plus, la réception de paquets avec des numéros de paquet plus élevés depuis l’adresse de pair légitime déclenchera une autre migration de connexion. Cela entraînera l’abandon de la validation de l’adresse de la migration parasite, contenant ainsi les migrations initiées par l’attaquant injectant un seul paquet.

Si un endpoint n’a aucun état concernant la dernière adresse de pair validée, il DOIT fermer la connexion silencieusement en supprimant tout l’état de connexion. Cela entraîne une gestion générique des nouveaux paquets sur la connexion. Par exemple, un endpoint PEUT envoyer un Stateless Reset en réponse à tout paquet entrant supplémentaire.

Réponses de Validation de Chemin

Un attaquant hors chemin qui peut observer les paquets pourrait transmettre des copies de paquets authentiques vers les points de terminaison. Si le paquet copié arrive avant le paquet authentique, cela apparaîtra comme une re-liaison NAT. Tout paquet authentique sera rejeté comme un doublon. Si l’attaquant est capable de continuer à transmettre des paquets, il pourrait être en mesure de provoquer une migration vers un chemin via l’attaquant. Cela place l’attaquant sur le chemin, lui donnant la capacité d’observer ou de supprimer tous les paquets ultérieurs.

Ce type d’attaque repose sur l’utilisation par l’attaquant d’un chemin qui a approximativement les mêmes caractéristiques que le chemin direct entre les points de terminaison. L’attaque est plus fiable si relativement peu de paquets sont envoyés ou si la perte de paquets coïncide avec la tentative d’attaque.

Un paquet non-sondant reçu sur le chemin original qui augmente le numéro de paquet maximum reçu amènera le point de terminaison à revenir sur ce chemin. L’élicitation de paquets sur ce chemin augmente la probabilité que l’attaque échoue. Par conséquent, l’atténuation de cette attaque repose sur le déclenchement de l’échange de paquets.

En réponse à une migration apparente, les endpoints DOIVENT valider le chemin précédemment actif en utilisant une trame PATH_CHALLENGE. Ceci induit l’envoi de nouveaux paquets sur ce chemin. Si le chemin n’est plus viable, la tentative de validation expirera et échouera ; si le chemin est viable mais n’est plus souhaité, la validation réussira mais ne résultera que dans l’envoi de paquets de sondage sur le chemin.

Un endpoint qui reçoit un PATH_CHALLENGE sur un chemin actif DEVRAIT envoyer un paquet non-sondage en réponse. Si le paquet non-sondage arrive avant toute copie effectuée par un attaquant, cela entraîne la migration de la connexion vers le chemin d’origine. Toute migration ultérieure vers un autre chemin redémarre entièrement ce processus.

Cette défense est imparfaite, mais cela n’est pas considéré comme un problème grave. Si le chemin via l’attaque est de manière fiable plus rapide que le chemin original malgré plusieurs tentatives d’utiliser ce chemin original, il n’est pas possible de distinguer entre une attaque et une amélioration du routage.

Un endpoint pourrait également utiliser des heuristiques pour améliorer la détection de ce type d’attaque. Par exemple, le rebinding NAT est improbable si des paquets ont été reçus récemment sur l’ancien chemin ; de même, le rebinding est rare sur les chemins IPv6. Les endpoints peuvent également rechercher des paquets dupliqués. Inversement, un changement d’ID de connexion indique plus probablement une migration intentionnelle plutôt qu’une attaque.

Validation de chemin réussie

La capacité disponible sur le nouveau chemin pourrait ne pas être la même que celle de l’ancien chemin. Les paquets envoyés sur l’ancien chemin NE DOIVENT PAS contribuer au contrôle de congestion ou à l’estimation RTT pour le nouveau chemin.

Lors de la confirmation de la propriété par un pair de sa nouvelle adresse, un endpoint DOIT immédiatement réinitialiser le contrôleur de congestion et l’estimateur de temps d’aller-retour pour le nouveau chemin aux valeurs initiales (voir Annexes A.3 et B.3 de QUIC-RECOVERY) sauf si le seul changement dans l’adresse du pair est son numéro de port. Étant donné que les changements de port uniquement résultent généralement d’une nouvelle liaison NAT ou d’autres activités de middlebox, l’endpoint PEUT à la place conserver son état de contrôle de congestion et son estimation d’aller-retour dans ces cas plutôt que de revenir aux valeurs initiales. Dans les cas où l’état de contrôle de congestion conservé d’un ancien chemin est utilisé sur un nouveau chemin avec des caractéristiques substantiellement différentes, un expéditeur pourrait transmettre de manière trop agressive jusqu’à ce que le contrôleur de congestion et l’estimateur RTT se soient adaptés. En général, il est conseillé aux implémentations d’être prudentes lors de l’utilisation de valeurs précédentes sur un nouveau chemin.

Il pourrait y avoir un réordonnancement apparent au niveau du récepteur lorsqu’un point de terminaison envoie des données et des sondes depuis/vers plusieurs adresses pendant la période de migration, étant donné que les deux chemins résultants pourraient avoir des temps d’aller-retour différents. Un récepteur de paquets sur plusieurs chemins enverra toujours des trames ACK couvrant tous les paquets reçus.

Bien que plusieurs chemins puissent être utilisés pendant la migration de connexion, un seul contexte de contrôle de congestion et un seul contexte de récupération de perte (comme décrit dans QUIC-RECOVERY) pourraient être adéquats. Par exemple, un endpoint pourrait retarder le passage à un nouveau contexte de contrôle de congestion jusqu’à ce qu’il soit confirmé qu’un ancien chemin n’est plus nécessaire (comme le cas décrit dans la Section 9.3.3).

Un expéditeur peut faire des exceptions pour les paquets de sonde afin que leur détection de perte soit indépendante et ne provoque pas indûment la réduction du taux d’envoi par le contrôleur de congestion. Un point de terminaison peut définir un minuteur séparé lorsqu’un PATH_CHALLENGE est envoyé, qui est annulé si le PATH_RESPONSE correspondant est reçu. Si le minuteur se déclenche avant que le PATH_RESPONSE soit reçu, le point de terminaison peut envoyer un nouveau PATH_CHALLENGE et redémarrer le minuteur pour une période plus longue. Ce minuteur DEVRAIT être défini comme décrit dans la Section 6.2.1 de QUIC-RECOVERY et NE DOIT PAS être plus agressif.

Échec de la validation de chemin

L’utilisation d’un ID de connexion stable sur plusieurs chemins réseau permettrait à un observateur passif de corréler l’activité entre ces chemins. Un point de terminaison qui se déplace entre les réseaux pourrait ne pas souhaiter que son activité soit corrélée par une entité autre que son pair, donc différents ID de connexion sont utilisés lors de l’envoi depuis différentes adresses locales, comme discuté dans la Section 5.1. Pour que cela soit efficace, les points de terminaison doivent s’assurer que les ID de connexion qu’ils fournissent ne peuvent pas être liés par une autre entité.

À tout moment, les points de terminaison PEUVENT changer le Destination Connection ID qu’ils transmettent vers une valeur qui n’a pas été utilisée sur un autre chemin.

Un endpoint NE DOIT PAS réutiliser un ID de connexion lors de l’envoi depuis plus d’une adresse locale – par exemple, lors de l’initiation d’une migration de connexion comme décrit dans la Section 9.2 ou lors du sondage d’un nouveau chemin réseau comme décrit dans la Section 9.1.

De même, un endpoint NE DOIT PAS réutiliser un ID de connexion lors de l’envoi vers plus d’une adresse de destination. En raison de changements réseau échappant au contrôle de son pair, un endpoint pourrait recevoir des paquets provenant d’une nouvelle adresse source avec la même valeur de champ Destination Connection ID, auquel cas il PEUT continuer à utiliser l’ID de connexion actuel avec la nouvelle adresse distante tout en continuant d’envoyer depuis la même adresse locale.

Ces exigences concernant la réutilisation de l’ID de connexion s’appliquent uniquement à l’envoi de paquets, car des changements non intentionnels de chemin sans changement d’ID de connexion sont possibles. Par exemple, après une période d’inactivité réseau, une nouvelle liaison NAT pourrait causer l’envoi de paquets sur un nouveau chemin lorsque le client reprend l’envoi. Un point de terminaison répond à un tel événement comme décrit dans la Section 9.3.

L’utilisation d’identifiants de connexion différents pour les paquets envoyés dans les deux directions sur chaque nouveau chemin réseau élimine l’usage de l’identifiant de connexion pour lier les paquets de la même connexion à travers différents chemins réseau. La protection d’en-tête garantit que les numéros de paquets ne peuvent pas être utilisés pour corréler l’activité. Ceci n’empêche pas d’autres propriétés des paquets, telles que le timing et la taille, d’être utilisées pour corréler l’activité.

Un endpoint NE DEVRAIT PAS initier une migration avec un pair qui a demandé un ID de connexion de longueur nulle, car le trafic sur le nouveau chemin pourrait être trivialement lié au trafic sur l’ancien. Si le serveur est capable d’associer des paquets avec un ID de connexion de longueur nulle à la bonne connexion, cela signifie que le serveur utilise d’autres informations pour démultiplexer les paquets. Par exemple, un serveur pourrait fournir une adresse unique à chaque client – par exemple, en utilisant les services alternatifs HTTP ALTSVC. Les informations qui pourraient permettre un routage correct des paquets sur plusieurs chemins réseau permettront également aux activités sur ces chemins d’être liées par des entités autres que le pair.

Un client peut souhaiter réduire la traçabilité en basculant vers un nouvel ID de connexion, un port UDP source, ou une adresse IP (voir RFC8981) lors de l’envoi de trafic après une période d’inactivité. Changer l’adresse depuis laquelle il envoie les paquets en même temps peut amener le serveur à détecter une migration de connexion. Cela garantit que les mécanismes qui supportent la migration sont exercés même pour les clients qui ne subissent pas de re-liaison NAT ou de migrations authentiques. Changer d’adresse peut amener un pair à réinitialiser son état de contrôle de congestion (voir Section 9.4), donc les adresses NE DEVRAIENT être changées que rarement.

Un endpoint qui épuise les ID de connexion disponibles ne peut pas sonder de nouveaux chemins ou initier une migration, ni répondre aux sondes ou aux tentatives de migration de son pair. Pour garantir que la migration soit possible et que les paquets envoyés sur différents chemins ne puissent pas être corrélés, les endpoints DEVRAIENT fournir de nouveaux ID de connexion avant que les pairs migrent ; voir Section 5.1.1. Si un pair pourrait avoir épuisé les ID de connexion disponibles, un endpoint en migration pourrait inclure une frame NEW_CONNECTION_ID dans tous les paquets envoyés sur un nouveau chemin réseau.

Server’s Preferred Address

QUIC permet aux serveurs d’accepter des connexions sur une adresse IP et de tenter de transférer ces connexions vers une adresse plus privilégiée peu après la négociation initiale. Ceci est particulièrement utile lorsque les clients se connectent initialement à une adresse partagée par plusieurs serveurs mais préféreraient utiliser une adresse unicast pour assurer la stabilité de la connexion. Cette section décrit le protocole pour migrer une connexion vers une adresse de serveur privilégiée.

La migration d’une connexion vers une nouvelle adresse de serveur en cours de connexion n’est pas prise en charge par la version de QUIC spécifiée dans ce document. Si un client reçoit des paquets provenant d’une nouvelle adresse de serveur alors que le client n’a pas initié de migration vers cette adresse, le client DEVRAIT rejeter ces paquets.

Sondage d’un Nouveau Chemin

Un serveur communique une adresse préférée en incluant le paramètre de transport preferred_address dans la négociation TLS.

Les serveurs PEUVENT communiquer une adresse préférée de chaque famille d’adresses (IPv4 et IPv6) pour permettre aux clients de choisir celle qui convient le mieux à leur connexion réseau.

Une fois que la négociation est confirmée, le client DEVRAIT sélectionner l’une des deux adresses fournies par le serveur et initier la validation de chemin (voir Section 8.2). Un client construit les paquets en utilisant tout ID de connexion actif précédemment non utilisé, pris soit du paramètre de transport preferred_address soit d’une trame NEW_CONNECTION_ID.

Dès que la validation de chemin réussit, le client DEVRAIT commencer à envoyer tous les futurs paquets vers la nouvelle adresse du serveur en utilisant le nouvel ID de connexion et cesser d’utiliser l’ancienne adresse du serveur. Si la validation de chemin échoue, le client DOIT continuer à envoyer tous les futurs paquets vers l’adresse IP originale du serveur.

Initiation de la Migration de Connexion

Un client qui migre vers une adresse préférée DOIT valider l’adresse qu’il choisit avant de migrer ; voir Section 21.5.3.

Un serveur peut recevoir un paquet adressé à son adresse IP préférée à tout moment après avoir accepté une connexion. Si ce paquet contient une trame PATH_CHALLENGE, le serveur envoie un paquet contenant une trame PATH_RESPONSE conformément à la Section 8.2. Le serveur DOIT envoyer des paquets non-sondeurs depuis son adresse d’origine jusqu’à ce qu’il reçoive un paquet non-sondeur du client à son adresse préférée et jusqu’à ce que le serveur ait validé le nouveau chemin.

Le serveur DOIT sonder le chemin vers le client depuis son adresse préférée. Ceci aide à se prémunir contre une migration fallacieuse initiée par un attaquant.

Une fois que le serveur a terminé sa validation de chemin et a reçu un paquet non-sondeur avec un nouveau numéro de paquet le plus élevé sur son adresse préférée, le serveur commence à envoyer des paquets non-sondeurs au client exclusivement depuis son adresse IP préférée. Le serveur DEVRAIT abandonner les paquets plus récents pour cette connexion qui sont reçus sur l’ancienne adresse IP. Le serveur PEUT continuer à traiter les paquets retardés qui sont reçus sur l’ancienne adresse IP.

Les adresses qu’un serveur fournit dans le paramètre de transport preferred_address ne sont valides que pour la connexion dans laquelle elles sont fournies. Un client NE DOIT PAS les utiliser pour d’autres connexions, y compris les connexions qui sont reprises à partir de la connexion actuelle.

Répondre à la migration de connexion

Un client pourrait avoir besoin d’effectuer une migration de connexion avant d’avoir migré vers l’adresse préférée du serveur. Dans ce cas, le client DEVRAIT effectuer une validation de chemin vers l’adresse originale et l’adresse préférée du serveur depuis la nouvelle adresse du client de manière concurrente.

Si la validation du chemin de l’adresse préférée du serveur réussit, le client DOIT abandonner la validation de l’adresse originale et migrer vers l’utilisation de l’adresse préférée du serveur. Si la validation du chemin de l’adresse préférée du serveur échoue mais que la validation de l’adresse originale du serveur réussit, le client PEUT migrer vers sa nouvelle adresse et continuer à envoyer vers l’adresse originale du serveur.

Si les paquets reçus à l’adresse préférée du serveur ont une adresse source différente de celle observée depuis le client pendant la négociation, le serveur DOIT se protéger contre les attaques potentielles comme décrit dans les sections 9.3.1 et 9.3.2. En plus d’une migration simultanée intentionnelle, cela peut également se produire parce que le réseau d’accès du client a utilisé une liaison NAT différente pour l’adresse préférée du serveur.

Les serveurs DEVRAIENT initier la validation de chemin vers la nouvelle adresse du client lors de la réception d’un paquet de sonde provenant d’une adresse différente ; voir Section 8.

Un client qui migre vers une nouvelle adresse DEVRAIT utiliser une adresse préférée de la même famille d’adresses pour le serveur.

L’ID de connexion fourni dans le paramètre de transport preferred_address n’est pas spécifique aux adresses qui sont fournies. Cet ID de connexion est fourni pour s’assurer que le client dispose d’un ID de connexion disponible pour la migration, mais le client PEUT utiliser cet ID de connexion sur n’importe quel chemin.

Usurpation d’adresse de pair

QUIC recommande que les endpoints qui envoient des données en utilisant IPv6 DEVRAIENT appliquer un label de flux IPv6 en conformité avec RFC 6437, sauf si l’API locale ne permet pas de définir les labels de flux IPv6.

Malheureusement, l’API Java ne permet pas de définir les étiquettes de flux IPv6.

Objectifs exclus

Ce qui suit est copié de QUIC RFC 9000. Pour chaque section, examinez et modifiez.

L’objectif de QUIC est de fournir une connexion de transport sécurisée. La section 21.1 fournit un aperçu de ces propriétés ; les sections suivantes discutent des contraintes et des mises en garde concernant ces propriétés, y compris les descriptions d’attaques connues et de contre-mesures.

Usurpation d’adresse sur le chemin

Une analyse de sécurité complète de QUIC dépasse le cadre de ce document. Cette section fournit une description informelle des propriétés de sécurité souhaitées pour aider les implémenteurs et guider l’analyse du protocole.

QUIC assume le modèle de menaces décrit dans SEC-CONS et fournit des protections contre de nombreuses attaques qui découlent de ce modèle.

À cette fin, les attaques sont divisées en attaques passives et actives. Les attaquants passifs ont la capacité de lire les paquets du réseau, tandis que les attaquants actifs ont également la capacité d’écrire des paquets dans le réseau. Cependant, une attaque passive pourrait impliquer un attaquant ayant la capacité de provoquer un changement de routage ou toute autre modification dans le chemin emprunté par les paquets qui constituent une connexion.

Les attaquants sont également catégorisés comme étant soit des attaquants sur le chemin soit des attaquants hors chemin. Un attaquant sur le chemin peut lire, modifier ou supprimer tout paquet qu’il observe de sorte que le paquet n’atteigne plus sa destination, tandis qu’un attaquant hors chemin observe les paquets mais ne peut pas empêcher le paquet original d’atteindre sa destination prévue. Les deux types d’attaquants peuvent également transmettre des paquets arbitraires. Cette définition diffère de celle de la Section 3.5 de SEC-CONS en ce qu’un attaquant hors chemin est capable d’observer les paquets.

Les propriétés de la négociation initiale, des paquets protégés et de la migration de connexion sont considérées séparément.

Transfert de paquets hors chemin

La négociation QUIC intègre la négociation TLS 1.3 et hérite des propriétés cryptographiques décrites dans l’Annexe E.1 de TLS13. Beaucoup des propriétés de sécurité de QUIC dépendent de la négociation TLS fournissant ces propriétés. Toute attaque sur la négociation TLS pourrait affecter QUIC.

Toute attaque sur la négociation TLS qui compromet la confidentialité ou l’unicité des clés de session, ou l’authentification des pairs participants, affecte les autres garanties de sécurité fournies par QUIC qui dépendent de ces clés. Par exemple, la migration (Section 9) dépend de l’efficacité des protections de confidentialité, à la fois pour la négociation des clés utilisant la négociation TLS et pour la protection des paquets QUIC, afin d’éviter la corrélation entre les chemins réseau.

Une attaque sur l’intégrité de la négociation TLS pourrait permettre à un attaquant d’affecter la sélection du protocole d’application ou de la version QUIC.

En plus des propriétés fournies par TLS, la poignée de main QUIC offre une certaine défense contre les attaques DoS sur la poignée de main.

Détection de perte et contrôle de congestion

La validation d’adresse (Section 8) est utilisée pour vérifier qu’une entité qui revendique une adresse donnée est capable de recevoir des paquets à cette adresse. La validation d’adresse limite les cibles d’attaque par amplification aux adresses pour lesquelles un attaquant peut observer les paquets.

Avant la validation d’adresse, les points de terminaison sont limités dans ce qu’ils peuvent envoyer. Les points de terminaison ne peuvent pas envoyer de données vers une adresse non validée en excès de trois fois les données reçues de cette adresse.

Note : La limite anti-amplification ne s’applique que lorsqu’un point de terminaison répond à des paquets reçus d’une adresse non validée. La limite anti-amplification ne s’applique pas aux clients lors de l’établissement d’une nouvelle connexion ou lors de l’initiation d’une migration de connexion.

Implications de confidentialité de la migration de connexion

Le calcul du premier vol du serveur pour une négociation complète est potentiellement coûteux, nécessitant à la fois une signature et un calcul d’échange de clés. Afin de prévenir les attaques DoS computationnelles, le paquet Retry fournit un mécanisme d’échange de jetons peu coûteux qui permet aux serveurs de valider l’adresse IP d’un client avant d’effectuer des calculs coûteux au prix d’un seul aller-retour. Après une négociation réussie, les serveurs peuvent émettre de nouveaux jetons à un client, ce qui permettra l’établissement de nouvelles connexions sans encourir ce coût.

Adresse préférée du serveur

Un attaquant sur le chemin ou hors du chemin peut forcer l’échec d’une négociation en remplaçant ou en concurrençant les paquets Initial. Une fois que des paquets Initial valides ont été échangés, les paquets Handshake suivants sont protégés par les clés Handshake, et un attaquant sur le chemin ne peut pas forcer l’échec de la négociation autrement qu’en supprimant des paquets pour amener les points de terminaison à abandonner la tentative.

Un attaquant positionné sur le chemin peut également remplacer les adresses des paquets de part et d’autre et ainsi faire en sorte que le client ou le serveur ait une vision incorrecte des adresses distantes. Une telle attaque est indiscernable des fonctions exécutées par un NAT.

Communication d’une Adresse Préférée

L’ensemble de la négociation est protégé cryptographiquement, les paquets Initial étant chiffrés avec des clés spécifiques à la version et les paquets Handshake et suivants étant chiffrés avec des clés dérivées de l’échange de clés TLS. De plus, la négociation des paramètres est intégrée dans la transcription TLS et fournit ainsi les mêmes garanties d’intégrité que la négociation TLS ordinaire. Un attaquant peut observer les paramètres de transport du client (tant qu’il connaît le sel spécifique à la version) mais ne peut pas observer les paramètres de transport du serveur et ne peut pas influencer la négociation des paramètres.

Les identifiants de connexion ne sont pas chiffrés mais protégés en intégrité dans tous les paquets.

Cette version de QUIC n’incorpore pas de mécanisme de négociation de version ; les implémentations de versions incompatibles échoueront simplement à établir une connexion.

Migration vers une Adresse Préférée

La protection des paquets (Section 12.1) applique un chiffrement authentifié à tous les paquets excepté les paquets de négociation de version, bien que les paquets Initial et Retry aient une protection limitée en raison de l’utilisation de matériel de clé spécifique à la version ; voir QUIC-TLS pour plus de détails. Cette section considère les attaques passives et actives contre les paquets protégés.

Les attaquants sur le chemin et hors du chemin peuvent monter une attaque passive dans laquelle ils sauvegardent les paquets observés pour une attaque hors ligne contre la protection des paquets à un moment futur ; cela est vrai pour tout observateur de tout paquet sur tout réseau.

Un attaquant qui injecte des paquets sans être capable d’observer des paquets valides pour une connexion a peu de chances de réussir, car la protection des paquets garantit que les paquets valides ne sont générés que par les points de terminaison qui possèdent le matériel de clé établi pendant la poignée de main ; voir les sections 7 et 21.1.1. De même, tout attaquant actif qui observe des paquets et tente d’insérer de nouvelles données ou de modifier des données existantes dans ces paquets ne devrait pas être capable de générer des paquets considérés comme valides par le point de terminaison récepteur, autres que les paquets Initial.

Une attaque par usurpation, dans laquelle un attaquant actif réécrit les parties non protégées d’un paquet qu’il transmet ou injecte, comme l’adresse source ou de destination, n’est efficace que si l’attaquant peut transmettre des paquets vers le point de terminaison original. La protection des paquets garantit que les charges utiles des paquets ne peuvent être traitées que par les points de terminaison qui ont complété la négociation, et les paquets invalides sont ignorés par ces points de terminaison.

Un attaquant peut également modifier les limites entre les paquets et les datagrammes UDP, provoquant la fusion de plusieurs paquets en un seul datagramme ou la division de paquets fusionnés en plusieurs datagrammes. Mis à part les datagrammes contenant des paquets Initial, qui nécessitent un remplissage, la modification de l’arrangement des paquets dans les datagrammes n’a aucun effet fonctionnel sur une connexion, bien qu’elle puisse changer certaines caractéristiques de performance.

Interaction de la Migration Client et de l’Adresse Préférée

La migration de connexion (Section 9) fournit aux points de terminaison la capacité de transitionner entre adresses IP et ports sur plusieurs chemins, en utilisant un chemin à la fois pour la transmission et la réception de trames non-sondantes. La validation de chemin (Section 8.2) établit qu’un pair est à la fois disposé et capable de recevoir des paquets envoyés sur un chemin particulier. Cela aide à réduire les effets de l’usurpation d’adresse en limitant le nombre de paquets envoyés vers une adresse usurpée.

Cette section décrit les propriétés de sécurité prévues de la migration de connexion sous divers types d’attaques DoS.

Utilisation du Flow Label IPv6 et Migration

Un attaquant qui peut empêcher qu’un paquet qu’il observe n’atteigne plus sa destination prévue est considéré comme un attaquant sur le chemin. Lorsqu’un attaquant est présent entre un client et un serveur, les points de terminaison sont tenus d’envoyer des paquets à travers l’attaquant pour établir la connectivité sur un chemin donné.

Un attaquant sur le chemin de communication peut :

  • Inspecter les paquets

  • Modifier les en-têtes de paquets IP et UDP

  • Injecter de nouveaux paquets

  • Retarder les paquets

  • Réorganiser les paquets

  • Abandonner les paquets

  • Diviser and fusionner les datagrammes le long des limites de paquets

Un attaquant sur le chemin ne peut pas :

  • Modifier une partie authentifiée d’un paquet et amener le destinataire à accepter ce paquet

Un attaquant sur le chemin a la possibilité de modifier les paquets qu’il observe ; cependant, toute modification apportée à une portion authentifiée d’un paquet entraînera son rejet par le point de terminaison récepteur comme étant invalide, car les charges utiles des paquets sont à la fois authentifiées et chiffrées.

QUIC vise à limiter les capacités d’un attaquant sur le chemin comme suit :

  1. Un attaquant situé sur le chemin peut empêcher l’utilisation d’un chemin pour une connexion, provoquant l’échec de la connexion si elle ne peut pas utiliser un chemin différent qui ne contient pas l’attaquant. Ceci peut être accompli en supprimant tous les paquets, en les modifiant de sorte qu’ils échouent à se déchiffrer, ou par d’autres méthodes.

  2. Un attaquant sur le chemin peut empêcher la migration vers un nouveau chemin sur lequel l’attaquant se trouve également en faisant échouer la validation du chemin sur le nouveau chemin.

  3. Un attaquant présent sur le chemin ne peut pas empêcher un client de migrer vers un chemin sur lequel l’attaquant n’est pas présent.

  4. Un attaquant sur le chemin peut réduire le débit d’une connexion en retardant les paquets ou en les abandonnant.

  5. Un attaquant sur le chemin ne peut pas amener un endpoint à accepter un paquet dont il a modifié une partie authentifiée de ce paquet.

Off-Path Active Attacks

Un attaquant hors-chemin n’est pas directement sur le chemin entre un client et un serveur mais pourrait être capable d’obtenir des copies de certains ou de tous les paquets envoyés entre le client et le serveur. Il est également capable d’envoyer des copies de ces paquets vers l’un ou l’autre des points de terminaison.

Un attaquant hors chemin peut :

  • Inspecter les paquets

  • Injecter de nouveaux paquets

  • Réorganiser les paquets injectés

Un attaquant hors-chemin ne peut pas :

  • Modifier les paquets envoyés par les points de terminaison

  • Retarder les paquets

  • Abandonner les paquets

  • Réorganiser les paquets originaux

Un attaquant hors-chemin peut créer des copies modifiées de paquets qu’il a observés et injecter ces copies dans le réseau, potentiellement avec des adresses source et de destination usurpées.

Pour les besoins de cette discussion, il est supposé qu’un attaquant hors-chemin a la capacité d’injecter une copie modifiée d’un paquet dans le réseau qui atteindra le point de terminaison de destination avant l’arrivée du paquet original observé par l’attaquant. En d’autres termes, un attaquant a la capacité de “gagner” de manière consistante une course contre les paquets légitimes entre les points de terminaison, causant potentiellement l’ignorance du paquet original par le destinataire.

Il est également supposé qu’un attaquant dispose des ressources nécessaires pour affecter l’état NAT. En particulier, un attaquant peut amener un endpoint à perdre sa liaison NAT puis obtenir le même port pour l’utiliser avec son propre trafic.

QUIC vise à contraindre les capacités d’un attaquant hors-chemin comme suit :

  1. Un attaquant hors-chemin peut faire la course aux paquets et tenter de devenir un attaquant “limité” sur le chemin.

  2. Un attaquant hors chemin peut faire en sorte que la validation de chemin réussisse pour les paquets transférés avec l’adresse source listée comme l’attaquant hors chemin tant qu’il peut fournir une connectivité améliorée entre le client et le serveur.

  3. Un attaquant hors-chemin ne peut pas provoquer la fermeture d’une connexion une fois que la négociation (handshake) est terminée.

  4. Un attaquant hors-chemin ne peut pas faire échouer la migration vers un nouveau chemin s’il ne peut pas observer le nouveau chemin.

  5. Un attaquant hors-chemin peut devenir un attaquant sur-chemin limité pendant la migration vers un nouveau chemin pour lequel il est également un attaquant hors-chemin.

  6. Un attaquant hors chemin peut devenir un attaquant en chemin limité en affectant l’état NAT partagé de telle sorte qu’il envoie des paquets au serveur depuis la même adresse IP et le même port que le client a utilisés à l’origine.

Aperçu des propriétés de sécurité

Un attaquant sur le chemin limité est un attaquant hors chemin qui a offert un routage amélioré des paquets en dupliquant et transmettant les paquets originaux entre le serveur et le client, causant l’arrivée de ces paquets avant les copies originales de sorte que les paquets originaux sont rejetés par le point de terminaison de destination.

Un attaquant on-path limité diffère d’un attaquant on-path en ce qu’il n’est pas sur le chemin original entre les points de terminaison, et par conséquent les paquets originaux envoyés par un point de terminaison atteignent toujours leur destination. Cela signifie qu’un échec futur à router les paquets copiés vers la destination plus rapidement que leur chemin original n’empêchera pas les paquets originaux d’atteindre la destination.

Un attaquant limité sur le chemin peut :

  • Inspecter les paquets

  • Injecter de nouveaux paquets

  • Modifier les en-têtes de paquets non chiffrés

  • Réordonner les paquets

Un attaquant limité sur le chemin ne peut pas :

  • Retarder les paquets pour qu’ils arrivent plus tard que les paquets envoyés sur le chemin original

  • Abandonner les paquets

  • Modifier la partie authentifiée et chiffrée d’un paquet et faire accepter ce paquet par le destinataire

Un attaquant on-path limité ne peut retarder les paquets que jusqu’au point où les paquets originaux arrivent avant les paquets dupliqués, ce qui signifie qu’il ne peut pas offrir un routage avec une latence pire que le chemin original. Si un attaquant on-path limité supprime des paquets, la copie originale arrivera quand même au point de terminaison de destination.

QUIC vise à contraindre les capacités d’un attaquant hors-chemin limité comme suit :

  1. Un attaquant limité sur le chemin ne peut pas provoquer la fermeture d’une connexion une fois que la négociation initiale est terminée.

  2. Un attaquant on-path limité ne peut pas forcer la fermeture d’une connexion inactive si le client est le premier à reprendre l’activité.

  3. Un attaquant limité sur le chemin peut faire qu’une connexion inactive soit considérée comme perdue si le serveur est le premier à reprendre l’activité.

Notez que ces garanties sont les mêmes garanties fournies pour tout NAT, pour les mêmes raisons.

Handshake

En tant que transport chiffré et authentifié, QUIC fournit une gamme de protections contre le déni de service. Une fois que la négociation cryptographique est terminée, les points de terminaison QUIC rejettent la plupart des paquets qui ne sont pas authentifiés, limitant considérablement la capacité d’un attaquant à interférer avec les connexions existantes.

Une fois qu’une connexion est établie, les endpoints QUIC peuvent accepter certains paquets ICMP non authentifiés (voir Section 14.2.1), mais l’utilisation de ces paquets est extrêmement limitée. Le seul autre type de paquet qu’un endpoint peut accepter est une réinitialisation sans état (Section 10.3), qui repose sur le fait que le token reste secret jusqu’à ce qu’il soit utilisé.

Pendant la création d’une connexion, QUIC ne fournit une protection que contre les attaques provenant de l’extérieur du chemin réseau. Tous les paquets QUIC contiennent une preuve que le destinataire a vu un paquet précédent de son pair.

Les adresses ne peuvent pas changer pendant la négociation, donc les points de terminaison peuvent ignorer les paquets qui sont reçus sur un chemin réseau différent.

Les champs Source et Destination Connection ID constituent le principal moyen de protection contre une attaque hors-chemin pendant la négociation ; voir Section 8.1. Ceux-ci doivent correspondre à ceux définis par un pair. À l’exception des paquets Initial et Stateless Resets, un point de terminaison n’accepte que les paquets qui incluent un champ Destination Connection ID correspondant à une valeur que le point de terminaison a précédemment choisie. C’est la seule protection offerte pour les paquets Version Negotiation.

Le champ Destination Connection ID dans un paquet Initial est sélectionné par un client pour être imprévisible, ce qui sert un objectif supplémentaire. Les paquets qui transportent la négociation cryptographique sont protégés avec une clé qui est dérivée de cet ID de connexion et d’un salt spécifique à la version QUIC. Cela permet aux points de terminaison d’utiliser le même processus pour authentifier les paquets qu’ils reçoivent que celui qu’ils utilisent après la fin de la négociation cryptographique. Les paquets qui ne peuvent pas être authentifiés sont rejetés. Protéger les paquets de cette manière fournit une assurance forte que l’expéditeur du paquet a vu le paquet Initial et l’a compris.

Ces protections ne sont pas destinées à être efficaces contre un attaquant capable de recevoir des paquets QUIC avant que la connexion ne soit établie. Un tel attaquant peut potentiellement envoyer des paquets qui seront acceptés par les endpoints QUIC. Cette version de QUIC tente de détecter ce type d’attaque, mais elle s’attend à ce que les endpoints échouent à établir une connexion plutôt que de récupérer. Pour l’essentiel, le protocole de handshake cryptographique QUIC-TLS est responsable de la détection des altérations durant le handshake.

Les points de terminaison sont autorisés à utiliser d’autres méthodes pour détecter et tenter de récupérer des interférences avec le handshake. Les paquets invalides peuvent être identifiés et rejetés en utilisant d’autres méthodes, mais aucune méthode spécifique n’est imposée dans ce document.

Anti-Amplification

Un attaquant pourrait être en mesure de recevoir un jeton de validation d’adresse (Section 8) d’un serveur puis libérer l’adresse IP qu’il a utilisée pour acquérir ce jeton. Plus tard, l’attaquant peut initier une connexion 0-RTT avec un serveur en usurpant cette même adresse, qui pourrait maintenant adresser un point de terminaison différent (victime). L’attaquant peut ainsi potentiellement amener le serveur à envoyer une quantité de données équivalente à une fenêtre de congestion initiale vers la victime.

Les serveurs DEVRAIENT fournir des atténuations pour cette attaque en limitant l’utilisation et la durée de vie des jetons de validation d’adresse ; voir Section 8.1.3.

DoS côté serveur

Un endpoint qui accuse réception de paquets qu’il n’a pas reçus pourrait amener un contrôleur de congestion à permettre l’envoi à des débits supérieurs à ce que le réseau supporte. Un endpoint PEUT ignorer des numéros de paquets lors de l’envoi de paquets pour détecter ce comportement. Un endpoint peut alors immédiatement fermer la connexion avec une erreur de connexion de type PROTOCOL_VIOLATION ; voir Section 10.2.

Interruption de handshake sur le chemin

Une attaque de falsification de requête se produit lorsqu’un point de terminaison amène son pair à émettre une requête vers une victime, la requête étant contrôlée par le point de terminaison. Les attaques de falsification de requête visent à fournir à un attaquant l’accès aux capacités de son pair qui pourraient autrement être indisponibles pour l’attaquant. Pour un protocole de réseau, une attaque de falsification de requête est souvent utilisée pour exploiter toute autorisation implicite conférée au pair par la victime en raison de l’emplacement du pair dans le réseau.

Pour qu’une contrefaçon de requête soit efficace, un attaquant doit être capable d’influencer quels paquets le peer envoie et où ces paquets sont envoyés. Si un attaquant peut cibler un service vulnérable avec une charge utile contrôlée, ce service pourrait effectuer des actions qui sont attribuées au peer de l’attaquant mais sont décidées par l’attaquant.

Par exemple, les exploits de falsification de requête inter-sites CSRF sur le Web amènent un client à émettre des requêtes qui incluent des cookies d’autorisation COOKIE, permettant à un site d’accéder aux informations et actions qui sont destinées à être restreintes à un site différent.

Comme QUIC fonctionne sur UDP, la modalité d’attaque principale préoccupante est celle où un attaquant peut sélectionner l’adresse vers laquelle son pair envoie des datagrammes UDP et peut contrôler une partie du contenu non protégé de ces paquets. Comme une grande partie des données envoyées par les endpoints QUIC est protégée, cela inclut le contrôle du texte chiffré. Une attaque réussit si un attaquant peut amener un pair à envoyer un datagramme UDP vers un hôte qui effectuera une action basée sur le contenu du datagramme.

Cette section discute des façons dont QUIC pourrait être utilisé pour des attaques de falsification de requêtes.

Cette section décrit également des contre-mesures limitées qui peuvent être mises en œuvre par les points de terminaison QUIC. Ces atténuations peuvent être employées unilatéralement par une implémentation ou un déploiement QUIC, sans que les cibles potentielles d’attaques de falsification de requêtes aient besoin d’agir. Cependant, ces contre-mesures pourraient être insuffisantes si les services basés sur UDP n’autorisent pas correctement les requêtes.

Étant donné que l’attaque de migration décrite dans la Section 21.5.4 est assez puissante et ne dispose pas de contre-mesures adéquates, les implémentations de serveurs QUIC doivent supposer que les attaquants peuvent les amener à générer des charges utiles UDP arbitraires vers des destinations arbitraires. Les serveurs QUIC NE DEVRAIENT PAS être déployés dans des réseaux qui n’implémentent pas le filtrage d’entrée BCP38 et qui disposent également de points de terminaison UDP insuffisamment sécurisés.

Bien qu’il ne soit généralement pas possible de s’assurer que les clients ne soient pas co-localisés avec des points de terminaison vulnérables, cette version de QUIC ne permet pas aux serveurs de migrer, empêchant ainsi les attaques de migration usurpées sur les clients. Toute extension future qui permet la migration de serveur DOIT également définir des contre-mesures pour les attaques de falsification.

Négociation des paramètres

QUIC offre certaines opportunités à un attaquant d’influencer ou de contrôler où son pair envoie les datagrammes UDP :

  • établissement de connexion initial (Section 7), où un serveur est capable de choisir où un client envoie les datagrammes – par exemple, en remplissant les enregistrements DNS ;

  • adresses préférées (Section 9.6), où un serveur est capable de choisir où un client envoie les datagrammes ;

  • migrations de connexion usurpées (Section 9.3.1), où un client est capable d’utiliser l’usurpation d’adresse source pour sélectionner où un serveur envoie les datagrammes suivants ; et

  • paquets usurpés qui amènent un serveur à envoyer un paquet de Négociation de Version (Section 21.5.5).

Dans tous les cas, l’attaquant peut amener son pair à envoyer des datagrammes à une victime qui pourrait ne pas comprendre QUIC. C’est-à-dire que ces paquets sont envoyés par le pair avant la validation d’adresse ; voir Section 8.

En dehors de la partie chiffrée des paquets, QUIC offre à un endpoint plusieurs options pour contrôler le contenu des datagrammes UDP que son pair envoie. Le champ Destination Connection ID offre un contrôle direct sur les octets qui apparaissent tôt dans les paquets envoyés par le pair ; voir Section 5.1. Le champ Token dans les paquets Initial offre à un serveur un contrôle sur d’autres octets des paquets Initial ; voir Section 17.2.2.

Il n’y a aucune mesure dans cette version de QUIC pour empêcher le contrôle indirect sur les portions chiffrées des paquets. Il est nécessaire de supposer que les endpoints sont capables de contrôler le contenu des frames qu’un pair envoie, en particulier ces frames qui transmettent des données d’application, telles que les frames STREAM. Bien que cela dépende dans une certaine mesure des détails du protocole d’application, un certain contrôle est possible dans de nombreux contextes d’utilisation de protocole. Comme l’attaquant a accès aux clés de protection des paquets, il est probable qu’il soit capable de prédire comment un pair va chiffrer les paquets futurs. Un contrôle réussi sur le contenu du datagramme nécessite alors seulement que l’attaquant soit capable de prédire le numéro de paquet et le placement des frames dans les paquets avec un certain degré de fiabilité.

Cette section suppose que limiter le contrôle sur le contenu des datagrammes n’est pas réalisable. L’objectif des atténuations dans les sections suivantes est de limiter les façons dont les datagrammes qui sont envoyés avant la validation d’adresse peuvent être utilisés pour la falsification de requêtes.

Paquets Protégés

Un attaquant agissant en tant que serveur peut choisir l’adresse IP et le port sur lesquels il annonce sa disponibilité, donc les paquets Initial des clients sont supposés être disponibles pour une utilisation dans ce type d’attaque. La validation d’adresse implicite dans le handshake garantit que – pour une nouvelle connexion – un client n’enverra pas d’autres types de paquets vers une destination qui ne comprend pas QUIC ou n’est pas disposée à accepter une connexion QUIC.

La protection initiale des paquets (Section 5.2 de QUIC-TLS) rend difficile pour les serveurs de contrôler le contenu des paquets Initial envoyés par les clients. Un client choisissant un Destination Connection ID imprévisible garantit que les serveurs sont incapables de contrôler toute partie chiffrée des paquets Initial provenant des clients.

Cependant, le champ Token est ouvert au contrôle du serveur et permet effectivement à un serveur d’utiliser les clients pour monter des attaques de falsification de requête. L’utilisation de tokens fournis avec la frame NEW_TOKEN (Section 8.1.3) offre la seule option pour la falsification de requête pendant l’établissement de connexion.

Les clients, cependant, ne sont pas obligés d’utiliser la trame NEW_TOKEN. Les attaques de falsification de requête qui s’appuient sur le champ Token peuvent être évitées si les clients envoient un champ Token vide lorsque l’adresse du serveur a changé par rapport au moment où la trame NEW_TOKEN a été reçue.

Les clients pourraient éviter d’utiliser NEW_TOKEN si l’adresse du serveur change. Cependant, ne pas inclure un champ Token pourrait affecter négativement les performances. Les serveurs pourraient s’appuyer sur NEW_TOKEN pour permettre l’envoi de données dépassant la limite de trois fois sur l’envoi de données ; voir Section 8.1. En particulier, cela affecte les cas où les clients utilisent 0-RTT pour demander des données aux serveurs.

L’envoi d’un paquet Retry (Section 17.2.5) offre au serveur la possibilité de modifier le champ Token. Après avoir envoyé un Retry, le serveur peut également contrôler le champ Destination Connection ID des paquets Initial suivants du client. Cela pourrait aussi permettre un contrôle indirect sur le contenu chiffré des paquets Initial. Cependant, l’échange d’un paquet Retry valide l’adresse du serveur, empêchant ainsi l’utilisation des paquets Initial suivants pour la falsification de requêtes.

Migration de Connexion

Les serveurs peuvent spécifier une adresse préférée, vers laquelle les clients migrent ensuite après avoir confirmé le handshake ; voir Section 9.6. Le champ Destination Connection ID des paquets que le client envoie vers une adresse préférée peut être utilisé pour la falsification de requêtes.

Un client NE DOIT PAS envoyer de trames non-sonde à une adresse préférée avant d’avoir validé cette adresse ; voir Section 8. Cela réduit considérablement les options dont dispose un serveur pour contrôler la partie chiffrée des datagrammes.

Ce document n’offre aucune contre-mesure supplémentaire qui soit spécifique à l’utilisation d’adresses préférées et qui puisse être implémentée par les endpoints. Les mesures génériques décrites dans la Section 21.5.6 pourraient être utilisées comme atténuation supplémentaire.

Attaques actives sur le chemin

Les clients peuvent présenter une adresse source usurpée dans le cadre d’une migration de connexion apparente pour amener un serveur à envoyer des datagrammes vers cette adresse.

Le champ Destination Connection ID dans tous les paquets qu’un serveur envoie par la suite à cette adresse usurpée peut être utilisé pour la contrefaçon de requêtes. Un client pourrait également être en mesure d’influencer le texte chiffré.

Un serveur qui envoie uniquement des paquets de sondage (Section 9.1) vers une adresse avant la validation d’adresse ne fournit à un attaquant qu’un contrôle limité sur la portion chiffrée des datagrammes. Cependant, particulièrement pour la re-liaison NAT, cela peut affecter négativement les performances. Si le serveur envoie des trames transportant des données d’application, un attaquant pourrait être capable de contrôler la majeure partie du contenu des datagrammes.

Ce document n’offre pas de contre-mesures spécifiques qui peuvent être implémentées par les endpoints, à part les mesures génériques décrites dans la Section 21.5.6. Cependant, les contre-mesures pour l’usurpation d’adresse au niveau réseau – en particulier, le filtrage d’entrée BCP38 – sont particulièrement efficaces contre les attaques qui utilisent l’usurpation et proviennent d’un réseau externe.

Attaques actives hors chemin

Les clients qui sont capables de présenter une adresse source falsifiée sur un paquet peuvent amener un serveur à envoyer un paquet de Négociation de Version (Section 17.2.1) à cette adresse.

L’absence de restrictions de taille sur les champs d’ID de connexion pour les paquets d’une version inconnue augmente la quantité de données que le client contrôle à partir du datagramme résultant. Le premier octet de ce paquet n’est pas sous le contrôle du client et les quatre octets suivants sont à zéro, mais le client est capable de contrôler jusqu’à 512 octets à partir du cinquième octet.

Aucune contre-mesure spécifique n’est fournie pour cette attaque, bien que les protections génériques (Section 21.5.6) puissent s’appliquer. Dans ce cas, le filtrage d’entrée BCP38 est également efficace.

Attaques actives limitées sur le chemin

La défense la plus efficace contre les attaques de falsification de requêtes consiste à modifier les services vulnérables pour qu’ils utilisent une authentification forte. Cependant, ce n’est pas toujours quelque chose qui est sous le contrôle d’un déploiement QUIC. Cette section décrit quelques autres mesures que les endpoints QUIC pourraient prendre de manière unilatérale. Ces étapes supplémentaires sont toutes discrétionnaires car, selon les circonstances, elles pourraient interférer avec ou empêcher des utilisations légitimes.

Les services offerts sur les interfaces de bouclage manquent souvent d’authentification appropriée. Les points de terminaison PEUVENT empêcher les tentatives de connexion ou la migration vers une adresse de bouclage. Les points de terminaison NE DEVRAIENT PAS autoriser les connexions ou la migration vers une adresse de bouclage si le même service était précédemment disponible sur une interface différente ou si l’adresse a été fournie par un service à une adresse non-bouclage. Les points de terminaison qui dépendent de ces capacités pourraient offrir une option pour désactiver ces protections.

De même, les endpoints pourraient considérer un changement d’adresse vers une adresse link-local RFC4291 ou une adresse dans une plage d’usage privé RFC1918 depuis une adresse globale, unique-local RFC4193, ou non-privée comme une tentative potentielle de falsification de requête. Les endpoints pourraient refuser d’utiliser complètement ces adresses, mais cela comporte un risque significatif d’interférer avec des utilisations légitimes. Les endpoints NE DEVRAIENT PAS refuser d’utiliser une adresse à moins qu’ils n’aient une connaissance spécifique du réseau indiquant que l’envoi de datagrammes vers des adresses non validées dans une plage donnée n’est pas sûr.

Les endpoints PEUVENT choisir de réduire le risque de falsification de requête en n’incluant pas les valeurs des trames NEW_TOKEN dans les paquets Initial ou en envoyant uniquement des trames de sondage dans les paquets avant de terminer la validation d’adresse. Notez que cela n’empêche pas un attaquant d’utiliser le champ Destination Connection ID pour une attaque.

Les endpoints ne sont pas censés avoir des informations spécifiques sur l’emplacement des serveurs qui pourraient être des cibles vulnérables d’une attaque de falsification de requête. Cependant, il pourrait être possible au fil du temps d’identifier des ports UDP spécifiques qui sont des cibles courantes d’attaques ou des motifs particuliers dans les datagrammes qui sont utilisés pour les attaques. Les endpoints PEUVENT choisir d’éviter d’envoyer des datagrammes vers ces ports ou de ne pas envoyer de datagrammes qui correspondent à ces motifs avant de valider l’adresse de destination. Les endpoints PEUVENT retirer les ID de connexion contenant des motifs connus pour être problématiques sans les utiliser.

Note : Modifier les endpoints pour appliquer ces protections est plus efficace que de déployer des protections basées sur le réseau, car les endpoints n’ont pas besoin d’effectuer de traitement supplémentaire lors de l’envoi vers une adresse qui a été validée.

Attaque par déni de service lors de l’établissement de connexion

Les attaques communément connues sous le nom de Slowloris SLOWLORIS tentent de maintenir de nombreuses connexions ouvertes vers le point de terminaison cible et de les maintenir ouvertes aussi longtemps que possible. Ces attaques peuvent être exécutées contre un point de terminaison QUIC en générant le minimum d’activité nécessaire pour éviter d’être fermées pour inactivité. Cela peut impliquer l’envoi de petites quantités de données, l’ouverture graduelle des fenêtres de contrôle de flux afin de contrôler le taux d’envoi, ou la fabrication de trames ACK qui simulent un taux de perte élevé.

Les déploiements QUIC DEVRAIENT fournir des atténuations contre les attaques Slowloris, telles que l’augmentation du nombre maximum de clients que le serveur autorisera, la limitation du nombre de connexions qu’une seule adresse IP est autorisée à établir, l’imposition de restrictions sur la vitesse de transfert minimale qu’une connexion est autorisée à avoir, et la restriction de la durée pendant laquelle un endpoint est autorisé à rester connecté.

Attaque par amplification

Un expéditeur malveillant pourrait intentionnellement ne pas envoyer certaines parties des données de flux, obligeant le destinataire à allouer des ressources pour les données non envoyées. Cela pourrait causer un engagement disproportionné de mémoire tampon de réception et/ou la création d’une structure de données volumineuse et inefficace chez le destinataire.

Un récepteur adversaire pourrait intentionnellement ne pas accuser réception des paquets contenant des données de flux dans une tentative de forcer l’expéditeur à stocker les données de flux non acquittées pour une retransmission.

L’attaque sur les récepteurs est atténuée si les fenêtres de contrôle de flux correspondent à la mémoire disponible. Cependant, certains récepteurs surengagent la mémoire et annoncent des décalages de contrôle de flux dans l’agrégat qui dépassent la mémoire réellement disponible. La stratégie de surengagement peut conduire à de meilleures performances lorsque les points de terminaison se comportent bien, mais rend les points de terminaison vulnérables à l’attaque de fragmentation de flux.

Les déploiements QUIC DEVRAIENT fournir des mesures d’atténuation pour les attaques de fragmentation de flux. Les mesures d’atténuation pourraient consister à éviter le sur-engagement de mémoire, limiter la taille des structures de données de suivi, retarder le réassemblage des trames STREAM, implémenter des heuristiques basées sur l’âge et la durée des trous de réassemblage, ou une combinaison de ces approches.

Attaque ACK Optimiste

Un endpoint adversaire peut ouvrir un grand nombre de streams, épuisant l’état sur un endpoint. L’endpoint adversaire pourrait répéter le processus sur un grand nombre de connexions, d’une manière similaire aux attaques de SYN flooding en TCP.

Normalement, les clients ouvriront les streams séquentiellement, comme expliqué dans la Section 2.1. Cependant, lorsque plusieurs streams sont initiés à intervalles courts, la perte ou le réordonnancement peut causer la réception des trames STREAM qui ouvrent les streams dans le désordre. En recevant un ID de stream plus élevé, un récepteur est tenu d’ouvrir tous les streams intermédiaires du même type ; voir Section 3.2. Ainsi, sur une nouvelle connexion, l’ouverture du stream 4000000 ouvre 1 million et 1 streams bidirectionnels initiés par le client.

Le nombre de flux actifs est limité par les paramètres de transport initial_max_streams_bidi et initial_max_streams_uni tels que mis à jour par toute trame MAX_STREAMS reçue, comme expliqué dans la Section 4.6. Si choisis judicieusement, ces limites atténuent l’effet de l’attaque par engagement de flux. Cependant, définir la limite trop basse pourrait affecter les performances lorsque les applications s’attendent à ouvrir un grand nombre de flux.

Attaques de falsification de requêtes

QUIC et TLS contiennent tous deux des trames ou des messages qui ont des utilisations légitimes dans certains contextes, mais ces trames ou messages peuvent être détournés pour forcer un pair à dépenser des ressources de traitement sans avoir d’impact observable sur l’état de la connexion.

Les messages peuvent également être utilisés pour modifier et rétablir l’état de manière mineure ou sans conséquence, par exemple en envoyant de petits incréments aux limites de contrôle de flux.

Si les coûts de traitement sont disproportionnellement élevés par rapport à la consommation de bande passante ou à l’effet sur l’état, alors cela pourrait permettre à un pair malveillant d’épuiser la capacité de traitement.

Bien qu’il existe des utilisations légitimes pour tous les messages, les implémentations DEVRAIENT suivre le coût de traitement par rapport au progrès et traiter les quantités excessives de tout paquet non productif comme indicatives d’une attaque. Les points de terminaison PEUVENT répondre à cette condition avec une erreur de connexion ou en supprimant les paquets.

Options de Contrôle pour les Endpoints

Un attaquant sur le chemin pourrait manipuler la valeur des champs ECN dans l’en-tête IP pour influencer le débit de l’expéditeur. RFC3168 traite des manipulations et de leurs effets de manière plus détaillée.

Un attaquant sur chemin limité peut dupliquer et envoyer des paquets avec des champs ECN modifiés pour affecter le débit de l’expéditeur. Si les paquets dupliqués sont rejetés par un récepteur, un attaquant devra faire concourir le paquet dupliqué contre l’original pour réussir cette attaque. Par conséquent, les points de terminaison QUIC ignorent le champ ECN dans un paquet IP à moins qu’au moins un paquet QUIC dans ce paquet IP soit traité avec succès ; voir Section 13.4.

Falsification de requête avec les paquets initiaux du client

Les resets sans état créent une possible attaque de déni de service analogue à une injection de reset TCP. Cette attaque est possible si un attaquant est capable de provoquer la génération d’un token de reset sans état pour une connexion avec un ID de connexion sélectionné. Un attaquant qui peut provoquer la génération de ce token peut réinitialiser une connexion active avec le même ID de connexion.

Si un paquet peut être acheminé vers différentes instances qui partagent une clé statique – par exemple, en modifiant une adresse IP ou un port – alors un attaquant peut amener le serveur à envoyer une réinitialisation sans état. Pour se défendre contre ce type de déni de service, les points de terminaison qui partagent une clé statique pour les réinitialisations sans état (voir Section 10.3.2) DOIVENT être organisés de sorte que les paquets avec un ID de connexion donné arrivent toujours à une instance qui possède l’état de connexion, sauf si cette connexion n’est plus active.

Plus généralement, les serveurs NE DOIVENT PAS générer une réinitialisation sans état si une connexion avec l’ID de connexion correspondant pourrait être active sur n’importe quel endpoint utilisant la même clé statique.

Dans le cas d’un cluster qui utilise l’équilibrage de charge dynamique, il est possible qu’un changement dans la configuration du répartiteur de charge se produise alors qu’une instance active conserve l’état de connexion. Même si une instance conserve l’état de connexion, le changement de routage et la réinitialisation sans état qui en résulte entraîneront la terminaison de la connexion. S’il n’y a aucune chance que le paquet soit routé vers la bonne instance, il est préférable d’envoyer une réinitialisation sans état plutôt que d’attendre que la connexion expire. Cependant, ceci n’est acceptable que si le routage ne peut pas être influencé par un attaquant.

Falsification de requête avec adresses préférées

Ce document définit les paquets de négociation de version QUIC (Section 6), qui peuvent être utilisés pour négocier la version QUIC utilisée entre deux points de terminaison. Cependant, ce document ne spécifie pas comment cette négociation sera effectuée entre cette version et les versions futures ultérieures. En particulier, les paquets de négociation de version ne contiennent aucun mécanisme pour prévenir les attaques de rétrogradation de version. Les versions futures de QUIC qui utilisent les paquets de négociation de version DOIVENT définir un mécanisme qui soit robuste contre les attaques de rétrogradation de version.

Falsification de requête avec migration usurpée

Les déploiements devraient limiter la capacité d’un attaquant à cibler une nouvelle connexion vers une instance de serveur particulière. Idéalement, les décisions de routage sont prises indépendamment des valeurs sélectionnées par le client, y compris les adresses. Une fois qu’une instance est sélectionnée, un ID de connexion peut être choisi de sorte que les paquets ultérieurs soient routés vers la même instance.

Falsification de Requête avec Négociation de Version

La longueur des paquets QUIC peut révéler des informations sur la longueur du contenu de ces paquets. La trame PADDING est fournie pour que les endpoints aient une certaine capacité à masquer la longueur du contenu des paquets ; voir Section 19.1.

Vaincre l’analyse de trafic est difficile et fait l’objet de recherches actives. La longueur n’est pas la seule façon dont l’information pourrait fuiter. Les points de terminaison pourraient également révéler des informations sensibles par d’autres canaux cachés, comme le timing des paquets.

Relay Security

Voici une analyse des messages Relay Request, Relay Response, Relay Intro et Hole Punch dans SSU1.

Contraintes : Il est important que les relais soient rapides. Les allers-retours doivent être minimisés. La bande passante et le processeur ne sont pas aussi importants.

SSU 1 : Alice se connecte d’abord à l’introducer Bob, qui relaie la demande à Charlie (qui est derrière un pare-feu). Après le hole punch, la session est établie entre Alice et Charlie comme dans un établissement direct.

Alice                         Bob                  Charlie
1. RelayRequest ---------------------->
2.      <-------------- RelayResponse    RelayIntro ----------->
3.      <-------------------------------------------- HolePunch
4. SessionRequest -------------------------------------------->
5.      <-------------------------------------------- SessionCreated
6. SessionConfirmed ------------------------------------------>

Authentification : Les messages Relay Request et Relay Response ne sont pas authentifiés de manière sécurisée, car Alice et Bob n’ont généralement pas de session existante ; ces messages utilisent des clés d’introduction publiées. Les messages Relay Request/Response en session sont autorisés et préférés si une session existe.

Le Relay Intro de Bob vers Charlie doit être dans une session existante, il est donc présumé sécurisé.

Bob peut usurper les Relay Intros ou modifier l’IP/port de la Relay Request. Il n’existe aucun mécanisme pour lier cryptographiquement les requêtes aux intros ou pour prévenir ou détecter des Bob malveillants.

Le hash du router de Bob n’est actuellement pas publié dans le Router Info de Charlie, donc cela doit être ajouté si nous voulons que les messages Alice-Bob soient authentifiés. De plus, d’autres paramètres SSU2 devraient être publiés dans le Router Info de Charlie, ou Alice devrait rechercher le Router Info de Bob dans la base de données réseau, ajoutant un délai supplémentaire. L’authentification ajouterait un aller-retour entre Alice et Bob.

En transmettant le hash du router d’Alice à Charlie, Charlie pourrait plus facilement déterminer s’il souhaite recevoir une connexion d’Alice, en vérifiant une liste de bannissement locale. Il n’y a aucun mécanisme permettant à Charlie de rejeter le relais en envoyant un rejet via Bob à Alice. Il n’y a aucun mécanisme permettant à Charlie d’accepter le relais en envoyant une acceptation via Bob à Alice. Alice doit attendre le HolePunch, ou simplement envoyer la SessionRequest à l’aveugle. Le HolePunch peut provenir d’un port différent de celui qu’Alice attendait, à cause du NAT, ce qui peut rendre plus difficile la reconnaissance du router dont provient le HolePunch.

Alice pourrait envoyer ses informations complètes de Router Info dans la Relay Request à Bob, et les transmettre à Charlie dans la Relay Intro.

La Relay Request ne contient pas d’horodatage, elle n’a donc aucune prévention de rejeu. L’IP source peut être usurpée, pour amener Charlie à envoyer un Hole Punch vers n’importe quelle IP/port. La Relay Request n’est pas signée, et même si elle était signée et horodatée, Charlie n’a pas la Router Identity complète pour pouvoir vérifier la signature.

Le protocole définit un champ de défi de longueur variable de 0 à 255 octets. Le défi dans la Relay Request est transmis à Charlie dans la Relay Intro. Cependant, le protocole ne spécifie pas comment créer, utiliser ou vérifier le défi, et il n’est pas implémenté. Si le HolePunch contenait le défi, Alice serait capable de facilement corréler le HolePunch avec Charlie.

Le nonce de quatre octets pourrait nécessiter d’être remplacé ou complété par un ID de connexion de 8 octets.

Le message Hole Punch vide est unique et peut être utilisé par les observateurs présents sur le chemin pour identifier le protocole, ceci devrait être modifié.

Discussion supplémentaire sur la DPI

Voici une analyse du Peer Test dans SSU1.

Contraintes : Il n’est pas particulièrement important que les tests de pairs soient rapides, ou utilisent peu de bande passante, ou peu de CPU, sauf peut-être au démarrage du router, où nous préférons que le router découvre assez rapidement s’il est accessible.

SSU 1 :

Alice                     Bob                  Charlie
1. PeerTest ------------------->
2.                          PeerTest-------------------->
3.                             <-------------------PeerTest
4.      <-------------------PeerTest

5.      <------------------------------------------PeerTest
6. PeerTest------------------------------------------>
7.      <------------------------------------------PeerTest

Parce que la spécification SSU1 est difficile à suivre, nous documentons le contenu des messages ci-dessous.

MessagePathAlice IP incl?Intro Key
1A->B sessionnoAlice
2B->C sessionyesAlice
3C->B sessionyesCharlie
4B->A sessionyesCharlie
5C->AyesCharlie
6A->CnoAlice
7C->AyesCharlie
Authentification : Alice choisira toujours un Bob avec une session existante. Bob rejettera les PeerTests provenant de pairs sans session établie. Le message 1 est envoyé dans la session. Par conséquent, le message 1 est sécurisé et authentifié.

Bob sélectionne un Charlie avec lequel il a une session existante. Les messages 2 et 3 sont envoyés dans la session. Par conséquent, les messages 2 et 3 sont sécurisés et authentifiés.

Le Message 4 devrait être envoyé en session ; cependant, la spécification SSU 1 indiquait précédemment qu’il est envoyé avec la clé d’introduction publiée d’Alice, ce qui signifie qu’il n’est pas en session. Avant la version 0.9.52, Java I2P envoyait effectivement le message avec la clé d’introduction. À partir de la version 0.9.52, la spécification stipule que la clé de session devrait être utilisée, et Java I2P envoie le message en session depuis la version 0.9.52.

Alice ne doit pas avoir de session existante avec Charlie pour que le test puisse se dérouler ; Alice abandonne le test si Bob choisit un Charlie qui a une session avec Alice. Par conséquent, les messages 5-7 ne sont pas sécurisés et authentifiés.

Tous les messages Peer Test contiennent un nonce de 4 octets qui est choisi par Alice. Ce nonce n’est pas utilisé de manière cryptographique.

Attaques possibles sur les messages 5-7 : à rechercher.

Le hash du router d’Alice n’est pas connu de Charlie. Le hash du router de Charlie n’est pas connu d’Alice. Ceux-ci doivent être ajoutés au protocole si nous voulons que les messages Alice-Charlie soient authentifiés. De plus, d’autres paramètres SSU2 devraient être fournis dans les messages Peer Test, ou Charlie devrait rechercher les Router Info d’Alice dans la base de données réseau, ajoutant un délai supplémentaire. L’authentification ajouterait un aller-retour entre Charlie et Alice.

En transférant le hash du router d’Alice à Charlie, Charlie pourrait plus facilement déterminer s’il souhaite participer à un Peer Test avec Alice, en vérifiant une liste de bannissement locale.

Le nonce de quatre octets pourrait devoir être remplacé ou complété par un ID de connexion de 8 octets.

Relay and Peer Test Design Goals

Relay et Peer Test ont des constructions similaires. Dans les deux cas, Alice demande à Bob de transférer une requête de service à Charlie, et Charlie agit ensuite sur cette requête.

Problèmes actuels du test de pairs SSU1 :

  • Peer Test n’a aucune protection contre un Bob malveillant
  • Peer Test n’a aucun moyen pour Bob ou Charlie de rejeter une requête
  • Peer Test n’a aucun moyen pour Alice de connaître l’identité de Charlie ou pour Alice de rejeter un Charlie
  • Peer Test n’a aucun moyen pour Charlie de connaître l’identité d’Alice ou pour Charlie de rejeter une Alice
  • Peer Test a son propre schéma de retransmission ad-hoc
  • Peer Test nécessite une machine à états complexe pour savoir quel message correspond à quel état
  • Sans savoir que Charlie l’a rejetée, Alice considérera le test comme un échec.

Problèmes actuels du relais SSU1 :

La plupart des problèmes de Peer Test listés ci-dessus s’appliquent également au Peer Test.

Nous avons les objectifs suivants pour améliorer la sécurité de Relay et Peer Test :

  • Charlie devrait publier suffisamment d’informations sur ses introducers (Bobs) dans la netDb pour qu’Alice puisse valider les informations si nécessaire. Par exemple, publier un hash de routeur pour chaque introducer permettrait à Alice, si le temps le permet, de récupérer les informations du routeur depuis la netDb.

  • Protéger contre l’usurpation d’adresse ou les menaces sur le chemin qui peuvent usurper, altérer, falsifier ou rejouer les requêtes d’Alice vers Bob. Bob doit s’assurer qu’Alice est un véritable router I2P et que la requête et l’adresse de test présentées sont valides.

  • Protéger contre les Bobs malveillants qui pourraient usurper, altérer, falsifier ou rejouer des requêtes transmises à Charlie. Charlie doit s’assurer qu’Alice et Bob sont tous deux de véritables routeurs I2P et que la requête et l’adresse de test présentées sont valides.

  • Bob doit recevoir suffisamment d’informations d’Alice pour pouvoir valider la requête et ensuite l’accepter ou la refuser. Bob doit avoir un mécanisme pour renvoyer l’acceptation ou le rejet à Alice. Bob ne doit jamais être obligé d’effectuer l’action demandée.

  • Charlie doit recevoir suffisamment d’informations de Bob pour pouvoir valider la demande puis l’accepter ou la refuser. Charlie doit avoir un mécanisme pour renvoyer l’acceptation ou le rejet à Bob, qui le transmettra à Alice. Charlie ne doit jamais être obligé d’exécuter l’action demandée.

  • Alice doit être capable de valider que la réponse transmise via Bob provient réellement de Charlie.

  • Alice et Charlie doivent pouvoir valider que leurs messages directs ultérieurs (non relayés via Bob) proviennent de la source attendue et sont de véritables routers I2P.

Les mécanismes suivants peuvent aider à atteindre ces objectifs :

  • Horodatages

  • Signatures utilisant la clé de signature du router

  • Utilisation des données de défi incluses dans la requête

  • Chiffrement utilisant la clé de chiffrement du router

  • Envoi des hachages de routeur, des Router Identities ou des Router Infos, pas seulement des adresses IP et des ports.

  • Validation des informations du routeur en interrogeant la base de données réseau

  • Vérification des informations du router, des IP et des ports contre les listes de bannissement

  • Limitation de débit

  • Nécessite l’établissement d’une session

Ces mécanismes possibles peuvent augmenter le temps de traitement et la latence des fonctions Relay ou Peer Test. Tous les effets doivent être évalués.

Le relais inter-versions et les tests de pairs devraient également être pris en charge si possible. Cela facilitera une transition progressive de SSU 1 vers SSU 2. Les combinaisons de versions possibles sont :

Alice/BobBob/CharlieAlice/CharlieSupported
111SSU 1
112no, use 1/1/1
121Relay: yes? Peer Test: no
122no, use 1/2/1
211Relay: yes? Peer Test: no
212Relay: yes? Peer Test: no
221no, use 2/2/2
222yes

Objectifs de sécurité

Summary

Nous nous appuyons sur plusieurs protocoles existants, tant au sein d’I2P que sur des standards externes, pour l’inspiration, les conseils et la réutilisation de code :

  • Modèles de menace : À partir de NTCP2 NTCP2, avec des menaces supplémentaires significatives pertinentes pour le transport UDP tel qu’analysé par QUIC RFC 9000 RFC 9001.

  • Choix cryptographiques : De NTCP2.

  • Handshake : Noise XK de NTCP2 et NOISE. Des simplifications importantes de NTCP2 sont possibles grâce à l’encapsulation (limites de messages inhérentes) fournie par UDP.

  • Obscurcissement de clé éphémère de poignée de main : Adapté de NTCP2 mais utilisant ChaCha20 de ECIES au lieu d’AES.

  • En-têtes de paquets : Adaptés de WireGuard WireGuard et QUIC RFC 9000 RFC 9001.

  • Obfuscation d’en-tête de paquet : Adapté de NTCP2 mais utilisant ChaCha20 de ECIES au lieu d’AES.

  • Protection d’en-tête de paquet : Adapté de QUIC RFC 9001 et Nonces

  • En-têtes utilisés comme données associées AEAD comme dans ECIES.

  • Numérotation des paquets : Adapté de WireGuard WireGuard et QUIC RFC 9000 RFC 9001.

  • Messages : Adapté de SSU

  • Fragmentation I2NP : Adapté de SSU

  • Relais et Test de Pairs : Adapté de SSU

  • Signatures des données Relay et Peer Test : À partir de la spécification des structures communes Common

  • Format de bloc : Depuis NTCP2 et ECIES.

  • Rembourrage et options : À partir de NTCP2 et ECIES.

  • Acks, nacks : Adapté de QUIC RFC 9000.

  • Contrôle de flux : TBD

Il n’y a pas de nouvelles primitives cryptographiques qui n’ont pas été utilisées dans I2P auparavant.

Validation d’adresse

Comme pour les autres transports I2P NTCP, NTCP2, et SSU 1, ce transport n’est pas un mécanisme généraliste pour la livraison d’un flux ordonné d’octets. Il est conçu pour le transport de messages I2NP. Aucune abstraction de “flux” n’est fournie.

De plus, comme pour SSU, il contient des fonctionnalités supplémentaires pour la traversée NAT facilitée par les pairs et les tests d’accessibilité (connexions entrantes).

Comme pour SSU 1, il ne fournit PAS de livraison dans l’ordre des messages I2NP. Il ne garantit pas non plus la livraison des messages I2NP. Pour des raisons d’efficacité, ou à cause de la livraison désordonnée des datagrammes UDP ou de la perte de ces datagrammes, les messages I2NP peuvent être livrés à l’extrémité distante dans le désordre, ou peuvent ne pas être livrés du tout. Un message I2NP peut être retransmis plusieurs fois si nécessaire, mais la livraison peut finalement échouer sans provoquer la déconnexion complète de la connexion. De plus, de nouveaux messages I2NP peuvent continuer à être envoyés même pendant qu’une retransmission (récupération de perte) est en cours pour d’autres messages I2NP.

Ce protocole ne prévient PAS complètement la livraison en double des messages I2NP. Le router devrait appliquer l’expiration I2NP et utiliser un filtre de Bloom ou autre mécanisme basé sur l’ID du message I2NP. Voir la section Duplication des messages I2NP ci-dessous.

Noise Protocol Framework

Cette proposition fournit les exigences basées sur le Noise Protocol Framework NOISE (Révision 33, 2017-10-04). Noise a des propriétés similaires au protocole Station-To-Station (STS), qui est la base du protocole SSU. Dans le jargon de Noise, Alice est l’initiateur, et Bob est le répondeur.

SSU2 est basé sur le protocole Noise Noise_XK_25519_ChaChaPoly_SHA256. (L’identifiant réel pour la fonction de dérivation de clé initiale est “Noise_XKchaobfse+hs1+hs2+hs3_25519_ChaChaPoly_SHA256” pour indiquer les extensions I2P - voir la section KDF 1 ci-dessous)

NOTE : Cet identifiant est différent de celui utilisé pour NTCP2, car les trois messages de négociation utilisent l’en-tête comme données associées.

Ce protocole Noise utilise les primitives suivantes :

  • Handshake Pattern: XK Alice transmet sa clé à Bob (X) Alice connaît déjà la clé statique de Bob (K)

  • Fonction DH : X25519 DH X25519 avec une longueur de clé de 32 octets comme spécifié dans RFC 7748.

  • Fonction de chiffrement : ChaChaPoly AEAD_CHACHA20_POLY1305 tel que spécifié dans la RFC 7539 section 2.8. Nonce de 12 octets, avec les 4 premiers octets définis à zéro.

  • Fonction de hachage : SHA256 Hachage standard de 32 octets, déjà largement utilisé dans I2P.

Additions to the Framework

Cette proposition définit les améliorations suivantes à Noise_XK_25519_ChaChaPoly_SHA256. Celles-ci suivent généralement les directives de la section 13 de NOISE.

  1. Les messages de handshake (Session Request, Created, Confirmed) incluent un en-tête de 16 ou 32 octets.

  2. Les en-têtes des messages de handshake (Session Request, Created, Confirmed) sont utilisés comme entrée pour mixHash() avant le chiffrement/déchiffrement pour lier les en-têtes au message.

  3. Les en-têtes sont chiffrés et protégés.

  4. Les clés éphémères en clair sont obscurcies avec le chiffrement ChaCha20 en utilisant une clé et un IV connus. Ceci est plus rapide qu’elligator2.

  5. Le format de la charge utile est défini pour les messages 1, 2, et la phase de données. Bien sûr, ceci n’est pas défini dans Noise.

La phase de données utilise un chiffrement similaire à, mais non compatible avec, la phase de données Noise.

Processing overhead estimate

À déterminer

Definitions

Nous définissons les fonctions suivantes correspondant aux blocs de construction cryptographiques utilisés.

ZEROLEN

zero-length byte array

H(p, d)

SHA-256 hash function that takes a personalization string p and data d, and
produces an output of length 32 bytes.
As defined in [NOISE](https://noiseprotocol.org/noise.html).
|| below means append.

Use SHA-256 as follows::

    H(p, d) := SHA-256(p || d)

MixHash(d)

SHA-256 hash function that takes a previous hash h and new data d,
and produces an output of length 32 bytes.
|| below means append.

Use SHA-256 as follows::

    MixHash(d) := h = SHA-256(h || d)

STREAM

The ChaCha20/Poly1305 AEAD as specified in [RFC 7539](https://tools.ietf.org/html/rfc7539).
S_KEY_LEN = 32 and S_IV_LEN = 12.

ENCRYPT(k, n, plaintext, ad)
    Encrypts plaintext using the cipher key k, and nonce n which MUST be unique for
    the key k.
    Associated data ad is optional.
    Returns a ciphertext that is the size of the plaintext + 16 bytes for the HMAC.

    The entire ciphertext must be indistinguishable from random if the key is secret.

DECRYPT(k, n, ciphertext, ad)
    Decrypts ciphertext using the cipher key k, and nonce n.
    Associated data ad is optional.
    Returns the plaintext.

DH

X25519 public key agreement system. Private keys of 32 bytes, public keys of 32
bytes, produces outputs of 32 bytes. It has the following
functions:

GENERATE_PRIVATE()
    Generates a new private key.

DERIVE_PUBLIC(privkey)
    Returns the public key corresponding to the given private key.

DH(privkey, pubkey)
    Generates a shared secret from the given private and public keys.

HKDF(salt, ikm, info, n)

A cryptographic key derivation function which takes some input key material ikm (which
should have good entropy but is not required to be a uniformly random string), a salt
of length 32 bytes, and a context-specific 'info' value, and produces an output
of n bytes suitable for use as key material.

Use HKDF as specified in [RFC 5869](https://tools.ietf.org/html/rfc5869), using the HMAC hash function SHA-256
as specified in [RFC 2104](https://tools.ietf.org/html/rfc2104). This means that SALT_LEN is 32 bytes max.

MixKey(d)

Use HKDF() with a previous chainKey and new data d, and
sets the new chainKey and k.
As defined in [NOISE](https://noiseprotocol.org/noise.html).

Use HKDF as follows::

    MixKey(d) := output = HKDF(chainKey, d, "", 64)
                 chainKey = output[0:31]
                 k = output[32:63]

Messages

Chaque datagramme UDP contient exactement un message. La longueur du datagramme (après les en-têtes IP et UDP) est la longueur du message. Le remplissage, s’il y en a, est contenu dans un bloc de remplissage à l’intérieur du message. Dans ce document, nous utilisons les termes « datagramme » et « paquet » de manière largement interchangeable. Chaque datagramme (ou paquet) contient un seul message (contrairement à QUIC, où un datagramme peut contenir plusieurs paquets QUIC). L’« en-tête de paquet » est la partie après l’en-tête IP/UDP.

Exception : Le message Session Confirmed est unique en ce qu’il peut être fragmenté sur plusieurs paquets. Voir la section Fragmentation de Session Confirmed ci-dessous pour plus d’informations.

Tous les messages SSU2 font au moins 40 octets de longueur. Tout message d’une longueur de 1 à 39 octets est invalide. Tous les messages SSU2 font au maximum 1472 (IPv4) ou 1452 (IPv6) octets de longueur. Le format de message est basé sur les messages Noise, avec des modifications pour l’encadrement et l’indiscernabilité. Les implémentations utilisant des bibliothèques Noise standard doivent prétraiter les messages reçus au format de message Noise standard. Tous les champs chiffrés sont des textes chiffrés AEAD.

Les messages suivants sont définis :

TypeMessageHeader LengthHeader Encr. Length
0SessionRequest3264
1SessionCreated3264
2SessionConfirmed1616
6Data1616
7PeerTest3232
9Retry3232
10Token Request3232
11HolePunch3232

Session Establishment

La séquence d’établissement standard, lorsqu’Alice possède un token valide précédemment reçu de Bob, est la suivante :

Alice                           Bob

SessionRequest ------------------->
<------------------- SessionCreated
SessionConfirmed ----------------->

Lorsque Alice ne possède pas de token valide, la séquence d’établissement est la suivante :

Alice                           Bob

TokenRequest --------------------->
<---------------------------  Retry
SessionRequest ------------------->
<------------------- SessionCreated
SessionConfirmed ----------------->

Lorsqu’Alice pense qu’elle a un token valide, mais que Bob le rejette (peut-être parce que Bob a redémarré), la séquence d’établissement est la suivante :

Alice                           Bob

SessionRequest ------------------->
<---------------------------  Retry
SessionRequest ------------------->
<------------------- SessionCreated
SessionConfirmed ----------------->

Bob peut rejeter une demande de Session ou de Token en répondant avec un message Retry contenant un bloc Termination avec un code de raison. En fonction du code de raison, Alice ne devrait pas tenter une autre demande pendant une certaine période :

Alice                           Bob

SessionRequest ------------------->
<---------------------------  Retry containing a Termination block

or

TokenRequest --------------------->
<---------------------------  Retry containing a Termination block

En utilisant la terminologie Noise, l’établissement et la séquence de données sont les suivants : (Propriétés de sécurité de la charge utile)

XK(s, rs):           Authentication   Confidentiality
    <- s
    ...
    -> e, es                  0                2
    <- e, ee                  2                1
    -> s, se                  2                5
    <-                        2                5

Une fois qu’une session a été établie, Alice et Bob peuvent échanger des messages de données.

Packet Header

Tous les paquets commencent par un en-tête obscurci (chiffré). Il existe deux types d’en-têtes, long et court. Notez que les 13 premiers octets (ID de connexion de destination, numéro de paquet et type) sont identiques pour tous les en-têtes.

Contre-mesures pour les attaques de falsification de requête générique

L’en-tête long fait 32 octets. Il est utilisé avant qu’une session soit créée, pour Token Request, SessionRequest, SessionCreated, et Retry. Il est également utilisé pour les messages Peer Test et Hole Punch hors session.

Avant le chiffrement de l’en-tête :


+----+----+----+----+----+----+----+----+
  |      Destination Connection ID        |
  +----+----+----+----+----+----+----+----+
  |   Packet Number   |type| ver| id |flag|
  +----+----+----+----+----+----+----+----+
  |        Source Connection ID           |
  +----+----+----+----+----+----+----+----+
  |                 Token                 |
  +----+----+----+----+----+----+----+----+

  Destination Connection ID :: 8 bytes, unsigned big endian integer

  Packet Number :: 4 bytes, unsigned big endian integer

  type :: The message type = 0, 1, 7, 9, 10, or 11

  ver :: The protocol version, equal to 2

  id :: 1 byte, the network ID (currently 2, except for test networks)

  flag :: 1 byte, unused, set to 0 for future compatibility

  Source Connection ID :: 8 bytes, unsigned big endian integer

  Token :: 8 bytes, unsigned big endian integer

Attaques Slowloris

L’en-tête court fait 16 octets. Il est utilisé pour les messages Session Created et pour les messages Data. Les messages non authentifiés tels que Session Request, Retry et Peer Test utiliseront toujours l’en-tête long.

16 octets sont requis, car le récepteur doit déchiffrer les 16 premiers octets pour obtenir le type de message, puis doit déchiffrer 16 octets supplémentaires s’il s’agit effectivement d’un en-tête long, comme indiqué par le type de message.

Pour Session Confirmed, avant le chiffrement d’en-tête :


+----+----+----+----+----+----+----+----+
  |      Destination Connection ID        |
  +----+----+----+----+----+----+----+----+
  |   Packet Number   |type|frag|  flags  |
  +----+----+----+----+----+----+----+----+

  Destination Connection ID :: 8 bytes, unsigned big endian integer

  Packet Number :: 4 bytes, all zeros

  type :: The message type = 2

  frag :: 1 byte fragment info:
         bit order: 76543210 (bit 7 is MSB)
         bits 7-4: fragment number 0-14, big endian
         bits 3-0: total fragments 1-15, big endian

  flags :: 2 bytes, unused, set to 0 for future compatibility

Voir la section Fragmentation de Session Confirmée ci-dessous pour plus d’informations sur le champ frag.

Pour les messages Data, avant le chiffrement de l’en-tête :


+----+----+----+----+----+----+----+----+
  |      Destination Connection ID        |
  +----+----+----+----+----+----+----+----+
  |   Packet Number   |type|flag|moreflags|
  +----+----+----+----+----+----+----+----+

  Destination Connection ID :: 8 bytes, unsigned big endian integer

  Packet Number :: 4 bytes, unsigned big endian integer

  type :: The message type = 6

  flag :: 1 byte flags:
         bit order: 76543210 (bit 7 is MSB)
         bits 7-1: unused, set to 0 for future compatibility
         bits 0: when set to 1, immediate ack requested

  moreflags :: 2 bytes, unused, set to 0 for future compatibility

Attaques de fragmentation et de réassemblage de flux

Les ID de connexion doivent être générés de manière aléatoire. Les ID Source et Destination ne doivent PAS être identiques, afin qu’un attaquant sur le chemin ne puisse pas capturer et renvoyer un paquet à l’expéditeur qui paraisse valide. N’utilisez PAS un compteur pour générer les ID de connexion, afin qu’un attaquant sur le chemin ne puisse pas générer un paquet qui paraisse valide.

Contrairement à QUIC, nous ne changeons pas les identifiants de connexion pendant ou après l’établissement de liaison, même après un message Retry. Les identifiants restent constants du premier message (Token Request ou Session Request) au dernier message (Data avec Termination). De plus, les identifiants de connexion ne changent pas pendant ou après un défi de chemin ou une migration de connexion.

De plus, contrairement à QUIC, les ID de connexion dans les en-têtes sont toujours chiffrés au niveau de l’en-tête. Voir ci-dessous.

Attaque par Engagement de Flux

Si aucun bloc First Packet Number n’est envoyé lors du handshake, les paquets sont numérotés au sein d’une session unique, pour chaque direction, en commençant par 0, jusqu’à un maximum de (2**32 -1). Une session doit être terminée, et une nouvelle session créée, bien avant que le nombre maximum de paquets ne soit envoyé.

Si un bloc First Packet Number est envoyé lors du handshake, les paquets sont numérotés au sein d’une session unique, pour cette direction, en commençant par ce numéro de paquet. Le numéro de paquet peut faire le tour pendant la session. Lorsqu’un maximum de 2**32 paquets ont été envoyés, ramenant le numéro de paquet au premier numéro de paquet, cette session n’est plus valide. Une session doit être terminée, et une nouvelle session créée, bien avant que le nombre maximum de paquets soit envoyé.

TODO rotation des clés, réduire le nombre maximum de paquets ?

Les paquets de handshake qui sont déterminés comme perdus sont retransmis entiers, avec l’en-tête identique incluant le numéro de paquet. Les messages de handshake Session Request, Session Created, et Session Confirmed DOIVENT être retransmis avec le même numéro de paquet et un contenu chiffré identique, afin que le même hash chaîné soit utilisé pour chiffrer la réponse. Le message Retry n’est jamais transmis.

Les paquets de phase de données qui sont déterminés comme perdus ne sont jamais retransmis entiers (sauf pour la terminaison, voir ci-dessous). Il en va de même pour les blocs qui sont contenus dans les paquets perdus. Au lieu de cela, l’information qui pourrait être transportée dans les blocs est envoyée à nouveau dans de nouveaux paquets selon les besoins. Les paquets de données ne sont jamais retransmis avec le même numéro de paquet. Toute retransmission du contenu des paquets (que le contenu reste identique ou non) doit utiliser le prochain numéro de paquet inutilisé.

Retransmettre un paquet entier inchangé tel quel, avec le même numéro de paquet, n’est pas autorisé pour plusieurs raisons. Pour plus de contexte, voir QUIC RFC 9000 section 12.3.

  • Il est inefficace de stocker les paquets pour la retransmission
  • Un nouveau paquet de données apparaît différent à un observateur sur le chemin, impossible de dire qu’il est retransmis
  • Un nouveau paquet reçoit un bloc d’acquittement mis à jour envoyé avec lui, pas l’ancien bloc d’acquittement
  • Vous ne retransmettez que ce qui est nécessaire. certains fragments auraient pu être déjà retransmis une fois et avoir été acquittés
  • Vous pouvez intégrer autant que nécessaire dans chaque paquet retransmis si d’autres sont en attente
  • Les points de terminaison qui suivent tous les paquets individuels dans le but de détecter les doublons risquent d’accumuler un état excessif. Les données requises pour détecter les doublons peuvent être limitées en maintenant un numéro de paquet minimum en dessous duquel tous les paquets sont immédiatement supprimés.
  • Ce schéma est beaucoup plus flexible

De nouveaux paquets sont utilisés pour transporter les informations qui sont déterminées comme ayant été perdues. En général, les informations sont renvoyées lorsqu’un paquet contenant ces informations est déterminé comme perdu, et l’envoi cesse lorsqu’un paquet contenant ces informations reste le même) accusé de réception.

Exception : Un paquet de phase de données contenant un bloc de terminaison peut, mais n’est pas tenu d’être, retransmis entier, tel quel. Voir la section Terminaison de session ci-dessous.

Les paquets suivants contiennent un numéro de paquet aléatoire qui est ignoré :

  • Demande de session
  • Session créée
  • Demande de jeton
  • Nouvelle tentative
  • Test de pair
  • Perforation de NAT

Pour Alice, la numérotation des paquets sortants commence à 0 avec Session Confirmed. Pour Bob, la numérotation des paquets sortants commence à 0 avec le premier paquet Data, qui devrait être un ACK du Session Confirmed. Les numéros de paquets dans un exemple de handshake standard seront :

Alice                           Bob

SessionRequest (r)    ------------>
<-------------   SessionCreated (r)
SessionConfirmed (0)  ------------>
<-------------             Data (0) (Ack-only)
Data (1)              ------------> (May be sent before Ack is received)
<-------------             Data (1)
Data (2)              ------------>
Data (3)              ------------>
Data (4)              ------------>
<-------------             Data (2)

r = random packet number (ignored)
Token Request, Retry, and Peer Test
also have random packet numbers.

Toute retransmission des messages de handshake (SessionRequest, SessionCreated, ou SessionConfirmed) doit être renvoyée sans modification, avec le même numéro de paquet. N’utilisez pas de clés éphémères différentes et ne modifiez pas la charge utile lors de la retransmission de ces messages.

Déni de service par les pairs

L’en-tête (avant obfuscation et protection) est toujours inclus dans les données associées pour la fonction AEAD, afin de lier cryptographiquement l’en-tête aux données.

Attaques par notification explicite de congestion

Le chiffrement d’en-tête a plusieurs objectifs. Voir la section « Discussion supplémentaire sur la DPI » ci-dessus pour le contexte et les hypothèses.

  • Empêcher l’inspection approfondie des paquets (DPI) en ligne d’identifier le protocole
  • Empêcher les motifs dans une série de messages sur la même connexion, sauf pour les retransmissions de handshake
  • Empêcher les motifs dans les messages du même type sur différentes connexions
  • Empêcher le déchiffrement des en-têtes de handshake sans connaissance de la clé d’introduction trouvée dans la netDb
  • Empêcher l’identification des clés éphémères X25519 sans connaissance de la clé d’introduction trouvée dans la netDb
  • Empêcher le déchiffrement du numéro et du type de paquet de la phase de données par tout attaquant en ligne ou hors ligne
  • Empêcher l’injection de paquets de handshake valides par un observateur sur le chemin ou hors du chemin sans connaissance de la clé d’introduction trouvée dans la netDb
  • Empêcher l’injection de paquets de données valides par un observateur sur le chemin ou hors du chemin
  • Permettre une classification rapide et efficace des paquets entrants
  • Fournir une résistance au “sondage” de sorte qu’il n’y ait pas de réponse à une Session Request incorrecte, ou s’il y a une réponse Retry, la réponse n’est pas identifiable comme étant I2P sans connaissance de la clé d’introduction trouvée dans la netDb
  • Le Destination Connection ID n’est pas une donnée critique, et il est acceptable qu’il puisse être déchiffré par un observateur avec connaissance de la clé d’introduction trouvée dans la netDb
  • Le numéro de paquet d’un paquet de phase de données est un nonce AEAD et constitue une donnée critique. Il ne doit pas être déchiffrable par un observateur même avec connaissance de la clé d’introduction trouvée dans la netDb. Voir Nonces.

Les en-têtes sont chiffrés avec des clés connues publiées dans la base de données réseau ou calculées ultérieurement. Pendant la phase de handshake, ceci sert uniquement à résister à l’inspection approfondie des paquets (DPI), car la clé est publique et la clé ainsi que les nonces sont réutilisés, ce qui rend le processus équivalent à une simple obfuscation. Notez que le chiffrement des en-têtes est également utilisé pour obfusquer les clés éphémères X (dans Session Request) et Y (dans Session Created).

Voir la section Gestion des Paquets Entrants ci-dessous pour des conseils supplémentaires.

Les octets 0-15 de tous les en-têtes sont chiffrés en utilisant un schéma de protection d’en-tête par XOR avec des données calculées à partir de clés connues, en utilisant ChaCha20, similaire à QUIC RFC 9001 et Nonces. Cela garantit que l’en-tête court chiffré et la première partie de l’en-tête long apparaîtront comme étant aléatoires.

Pour Session Request et Session Created, les octets 16-31 de l’en-tête long et la clé éphémère Noise de 32 octets sont chiffrés en utilisant ChaCha20. Les données non chiffrées sont aléatoires, donc les données chiffrées apparaîtront comme étant aléatoires.

Pour Retry, les octets 16-31 de l’en-tête long sont chiffrés en utilisant ChaCha20. Les données non chiffrées sont aléatoires, donc les données chiffrées sembleront être aléatoires.

Contrairement au schéma de protection d’en-tête de QUIC RFC 9001, TOUTES les parties de tous les en-têtes, y compris les ID de connexion de destination et source, sont chiffrées. QUIC RFC 9001 et Nonces se concentrent principalement sur le chiffrement de la partie “critique” de l’en-tête, c’est-à-dire le numéro de paquet (nonce ChaCha20). Bien que le chiffrement de l’ID de session rende la classification des paquets entrants un peu plus complexe, cela rend certaines attaques plus difficiles. QUIC définit différents ID de connexion pour différentes phases, et pour le défi de chemin et la migration de connexion. Ici, nous utilisons les mêmes ID de connexion tout au long, car ils sont chiffrés.

Il y a sept phases de clés de protection d’en-tête :

  • Demande de session et demande de jeton
  • Session créée
  • Nouvelle tentative
  • Session confirmée
  • Phase de données
  • Test de pair
  • Perforation de NAT
MessageKey k_header_1Key k_header_2
Token RequestBob Intro KeyBob Intro Key
Session RequestBob Intro KeyBob Intro Key
Session CreatedBob Intro KeySee Session Request K
Session ConfirmedBob Intro KeySee Session Created K
RetryBob Intro KeyBob Intro Key
DataAlice/Bob Intro KeySee data phase KDF
Peer Test 5,7Alice Intro KeyAlice Intro Key
Peer Test 6Charlie Intro KeyCharlie Intro Key
Hole PunchAlice Intro KeyAlice Intro Key
Le chiffrement d’en-tête est conçu pour permettre une classification rapide des paquets entrants, sans heuristiques complexes ni solutions de repli. Ceci est accompli en utilisant la même clé k_header_1 pour presque tous les messages entrants. Même lorsque l’IP source ou le port d’une connexion change en raison d’un changement d’IP réel ou du comportement NAT, le paquet peut être rapidement mappé à une session avec une seule recherche de l’ID de connexion.

Notez que Session Created et Retry sont les SEULS messages qui nécessitent un traitement de fallback pour k_header_1 afin de déchiffrer le Connection ID, car ils utilisent la clé intro de l’expéditeur (Bob). TOUS les autres messages utilisent la clé intro du destinataire pour k_header_1. Le traitement de fallback n’a besoin que de rechercher les connexions sortantes en attente par IP/port source.

Si le traitement de secours par IP/port source ne parvient pas à trouver une connexion sortante en attente, il pourrait y avoir plusieurs causes :

  • Pas un message SSU2
  • Un message SSU2 corrompu
  • La réponse est usurpée ou modifiée par un attaquant
  • Bob a un NAT symétrique
  • Bob a changé d’IP ou de port pendant le traitement du message
  • Bob a envoyé la réponse par une interface différente

Bien qu’un traitement de repli supplémentaire soit possible pour tenter de trouver la connexion sortante en attente et déchiffrer l’ID de connexion en utilisant le k_header_1 pour cette connexion, ce n’est probablement pas nécessaire. Si Bob a des problèmes avec son NAT ou le routage des paquets, il est probablement préférable de laisser la connexion échouer. Cette conception repose sur le fait que les points de terminaison conservent une adresse stable pendant toute la durée de la négociation.

Voir la section Gestion des Paquets Entrants ci-dessous pour des directives supplémentaires.

Voir les sections KDF individuelles ci-dessous pour la dérivation des clés de chiffrement d’en-tête pour cette phase.

Oracle de Réinitialisation sans État

// incoming encrypted packet
  packet = incoming encrypted packet
  len = packet.length

  // take the next-to-last 12 bytes of the packet
  iv = packet[len-24:len-13]
  k_header_1 = header encryption key 1
  data = {0, 0, 0, 0, 0, 0, 0, 0}
  mask = ChaCha20.encrypt(k_header_1, iv, data)

  // encrypt the first part of the header by XORing with the mask
  packet[0:7] ^= mask[0:7]

  // take the last 12 bytes of the packet
  iv = packet[len-12:len-1]
  k_header_2 = header encryption key 2
  data = {0, 0, 0, 0, 0, 0, 0, 0}
  mask = ChaCha20.encrypt(k_header_2, iv, data)

  // encrypt the second part of the header by XORing with the mask
  packet[8:15] ^= mask[0:7]


  // For Session Request and Session Created only:
  iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

  // encrypt the third part of the header and the ephemeral key
  packet[16:63] = ChaCha20.encrypt(k_header_2, iv, packet[16:63])


  // For Retry, Token Request, Peer Test, and Hole Punch only:
  iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

  // encrypt the third part of the header
  packet[16:31] = ChaCha20.encrypt(k_header_2, iv, packet[16:31])

Cette KDF utilise les 24 derniers octets du paquet comme IV pour les deux opérations ChaCha20. Comme tous les paquets se terminent par un MAC de 16 octets, cela exige que toutes les charges utiles de paquet aient un minimum de 8 octets. Cette exigence est également documentée dans les sections de messages ci-dessous.

Rétrogradation de Version

Après avoir déchiffré les 8 premiers octets de l’en-tête, le récepteur connaîtra l’ID de connexion de destination. À partir de là, le récepteur sait quelle clé de chiffrement d’en-tête utiliser pour le reste de l’en-tête, en fonction de la phase de clé de la session.

Le déchiffrement des 8 octets suivants de l’en-tête révélera alors le type de message et permettra de déterminer s’il s’agit d’un en-tête court ou long. S’il s’agit d’un en-tête long, le récepteur doit valider les champs version et netid. Si la version est != 2, ou si le netid est != la valeur attendue (généralement 2, sauf dans les réseaux de test), le récepteur devrait abandonner le message.

Packet Integrity

Tous les messages contiennent soit trois, soit quatre parties :

  • L’en-tête du message
  • Pour Session Request et Session Created uniquement, une clé éphémère
  • Une charge utile chiffrée ChaCha20
  • Un MAC Poly1305

Dans tous les cas, l’en-tête (et si présente, la clé éphémère) est lié au MAC d’authentification pour garantir que l’ensemble du message est intact.

  • Pour les messages de handshake Session Request, Session Created, et Session Confirmed, l’en-tête du message est mixHash() avant la phase de traitement Noise
  • La clé éphémère, si présente, est couverte par un misHash() Noise standard
  • Pour les messages en dehors du handshake Noise, l’en-tête est utilisé comme Données Associées pour le chiffrement ChaCha20/Poly1305.

Les gestionnaires de paquets entrants doivent toujours déchiffrer la charge utile ChaCha20 et valider le MAC avant de traiter le message, avec une exception : Pour atténuer les attaques DoS provenant de paquets avec adresses usurpées contenant des messages Session Request apparents avec un jeton invalide, un gestionnaire n’a PAS BESOIN de tenter de déchiffrer et valider le message complet (nécessitant une opération DH coûteuse en plus du déchiffrement ChaCha20/Poly1305). Le gestionnaire peut répondre avec un message Retry en utilisant les valeurs trouvées dans l’en-tête du message Session Request.

Authenticated Encryption

Il y a trois instances distinctes de chiffrement authentifié (CipherStates). Une pendant la phase de négociation, et deux (transmission et réception) pour la phase de données. Chacune a sa propre clé provenant d’un KDF.

Les données chiffrées/authentifiées seront représentées comme

+----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |   Encrypted and authenticated data    |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

Attaques ciblées par routage

Format de données chiffré et authentifié.

Entrées des fonctions de chiffrement/déchiffrement :


k :: 32 byte cipher key, as generated from KDF

  nonce :: Counter-based nonce, 12 bytes.
           Starts at 0 and incremented for each message.
           First four bytes are always zero.
           Last eight bytes are the counter, little-endian encoded.
           Maximum value is 2**64 - 2.
           Connection must be dropped and restarted after
           it reaches that value.
           The value 2**64 - 1 must never be sent.

  ad :: In handshake phase:
        Associated data, 32 bytes.
        The SHA256 hash of all preceding data.
        In data phase:
        The packet header, 16 bytes.

  data :: Plaintext data, 0 or more bytes

Sortie de la fonction de chiffrement, entrée de la fonction de déchiffrement :


+----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |       ChaCha20 encrypted data         |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+
  |  Poly1305 Message Authentication Code |
  +              (MAC)                    +
  |             16 bytes                  |
  +----+----+----+----+----+----+----+----+

  encrypted data :: Same size as plaintext data, 0 - 65519 bytes

  MAC :: Poly1305 message authentication code, 16 bytes

Pour ChaCha20, ce qui est décrit ici correspond à RFC 7539, qui est également utilisé de manière similaire dans TLS RFC 7905.

Analyse du trafic

  • Étant donné que ChaCha20 est un chiffrement par flot, les textes en clair n’ont pas besoin d’être complétés par du remplissage. Les octets de flux de clés supplémentaires sont supprimés.

  • La clé pour le chiffrement (256 bits) est convenue au moyen du SHA256 KDF. Les détails du KDF pour chaque message sont dans des sections séparées ci-dessous.

AEAD Error Handling

  • Dans tous les messages, la taille du message AEAD est connue à l’avance. En cas d’échec d’authentification AEAD, le destinataire doit arrêter le traitement ultérieur du message et rejeter le message.

  • Bob devrait maintenir une liste noire des adresses IP avec des échecs répétés.

KDF for Session Request

La fonction de dérivation de clé (KDF) génère une clé de chiffrement de phase de handshake k à partir du résultat DH, en utilisant HMAC-SHA256(key, data) tel que défini dans la RFC 2104. Ce sont les fonctions InitializeSymmetric(), MixHash(), et MixKey(), exactement comme définies dans la spécification Noise.

KDF for Initial ChainKey


// Define protocol_name.
  Set protocol_name = "Noise_XKchaobfse+hs1+hs2+hs3_25519_ChaChaPoly_SHA256"
   (52 bytes, US-ASCII encoded, no NULL termination).

  // Define Hash h = 32 bytes
  h = SHA256(protocol_name);

  Define ck = 32 byte chaining key. Copy the h data to ck.
  Set ck = h

  // MixHash(null prologue)
  h = SHA256(h);

  // up until here, can all be precalculated by Alice for all outgoing connections

  // Bob's X25519 static keys
  // bpk is published in routerinfo
  bsk = GENERATE_PRIVATE()
  bpk = DERIVE_PUBLIC(bsk)

  // Bob static key
  // MixHash(bpk)
  // || below means append
  h = SHA256(h || bpk);

  // Bob introduction key
  // bik is published in routerinfo
  bik = RANDOM(32)

  // up until here, can all be precalculated by Bob for all incoming connections

KDF for Session Request


// MixHash(header)
  h = SHA256(h || header)

  This is the "e" message pattern:

  // Alice's X25519 ephemeral keys
  aesk = GENERATE_PRIVATE()
  aepk = DERIVE_PUBLIC(aesk)

  // Alice ephemeral key X
  // MixHash(aepk)
  h = SHA256(h || aepk);

  // h is used as the associated data for the AEAD in Session Request
  // Retain the Hash h for the Session Created KDF


  End of "e" message pattern.

  This is the "es" message pattern:

  // DH(e, rs) == DH(s, re)
  sharedSecret = DH(aesk, bpk) = DH(bsk, aepk)

  // MixKey(DH())
  //[chainKey, k] = MixKey(sharedSecret)
  // ChaChaPoly parameters to encrypt/decrypt
  keydata = HKDF(chainKey, sharedSecret, "", 64)
  chainKey = keydata[0:31]

  // AEAD parameters
  k = keydata[32:63]
  n = 0
  ad = h
  ciphertext = ENCRYPT(k, n, payload, ad)

  // retain the chainKey for Session Created KDF


  End of "es" message pattern.

  // Header encryption keys for this message
  // bik = Bob's intro key
  k_header_1 = bik
  k_header_2 = bik

  // Header encryption keys for next message (Session Created)
  k_header_1 = bik
  k_header_2 = HKDF(chainKey, ZEROLEN, "SessCreateHeader", 32)

  // Header encryption keys for next message (Retry)
  k_header_1 = bik
  k_header_2 = bik

SessionRequest (Type 0)

Alice envoie à Bob, soit comme premier message dans la négociation (handshake), soit en réponse à un message Retry. Bob répond avec un message Session Created. Taille : 80 + taille de la charge utile. Taille minimum : 88

Si Alice n’a pas de jeton valide, Alice devrait envoyer un message Token Request au lieu d’un Session Request, pour éviter la surcharge de chiffrement asymétrique lors de la génération d’un Session Request.

En-tête long. Contenu Noise : clé éphémère X d’Alice Charge utile Noise : DateTime et autres blocs Taille maximale de charge utile : MTU - 108 (IPv4) ou MTU - 128 (IPv6). Pour MTU 1280 : Charge utile maximale est 1172 (IPv4) ou 1152 (IPv6). Pour MTU 1500 : Charge utile maximale est 1392 (IPv4) ou 1372 (IPv6).

Propriétés de sécurité de la charge utile :

XK(s, rs):           Authentication   Confidentiality
    -> e, es                  0                2

    Authentication: None (0).
    This payload may have been sent by any party, including an active attacker.

    Confidentiality: 2.
    Encryption to a known recipient, forward secrecy for sender compromise
    only, vulnerable to replay.  This payload is encrypted based only on DHs
    involving the recipient's static key pair.  If the recipient's static
    private key is compromised, even at a later date, this payload can be
    decrypted.  This message can also be replayed, since there's no ephemeral
    contribution from the recipient.

    "e": Alice generates a new ephemeral key pair and stores it in the e
         variable, writes the ephemeral public key as cleartext into the
         message buffer, and hashes the public key along with the old h to
         derive a new h.

    "es": A DH is performed between the Alice's ephemeral key pair and the
          Bob's static key pair.  The result is hashed along with the old ck to
          derive a new ck and k, and n is set to zero.

La valeur X est chiffrée pour garantir l’indiscernabilité et l’unicité de la charge utile, qui sont des contre-mesures DPI nécessaires. Nous utilisons le chiffrement ChaCha20 pour y parvenir, plutôt que des alternatives plus complexes et plus lentes comme elligator2. Le chiffrement asymétrique avec la clé publique du router de Bob serait beaucoup trop lent. Le chiffrement ChaCha20 utilise la clé d’introduction de Bob telle que publiée dans la base de données réseau.

Le chiffrement ChaCha20 est uniquement pour la résistance à la DPI. Toute partie connaissant la clé d’introduction de Bob, qui est publiée dans la netDb, peut déchiffrer l’en-tête et la valeur X de ce message.

Contenu brut :

+----+----+----+----+----+----+----+----+
  |  Long Header bytes 0-15, ChaCha20     |
  +  encrypted with Bob intro key         +
  |    See Header Encryption KDF          |
  +----+----+----+----+----+----+----+----+
  |  Long Header bytes 16-31, ChaCha20    |
  +  encrypted with Bob intro key n=0     +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +       X, ChaCha20 encrypted           +
  |       with Bob intro key n=0          |
  +              (32 bytes)               +
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |   ChaCha20 encrypted data             |
  +          (length varies)              +
  |  k defined in KDF for Session Request |
  +  n = 0                                +
  |  see KDF for associated data          |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +        Poly1305 MAC (16 bytes)        +
  |                                       |
  +----+----+----+----+----+----+----+----+

  X :: 32 bytes, ChaCha20 encrypted X25519 ephemeral key, little endian
          key: Bob's intro key
          n: 1
          data: 48 bytes (bytes 16-31 of the header, followed by encrypted X)

Données non chiffrées (étiquette d’authentification Poly1305 non montrée) :

+----+----+----+----+----+----+----+----+
  |      Destination Connection ID        |
  +----+----+----+----+----+----+----+----+
  |   Packet Number   |type| ver| id |flag|
  +----+----+----+----+----+----+----+----+
  |        Source Connection ID           |
  +----+----+----+----+----+----+----+----+
  |                 Token                 |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |                   X                   |
  +              (32 bytes)               +
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |     Noise payload (block data)        |
  +          (length varies)              +
  |     see below for allowed blocks      |
  +----+----+----+----+----+----+----+----+


  Destination Connection ID :: Randomly generated by Alice

  id :: 1 byte, the network ID (currently 2, except for test networks)

  ver :: 2

  type :: 0

  flag :: 1 byte, unused, set to 0 for future compatibility

  Packet Number :: Random 4 byte number generated by Alice, ignored

  Source Connection ID :: Randomly generated by Alice,
                          must not be equal to Destination Connection ID

  Token :: 0 if not previously received from Bob

  X :: 32 bytes, X25519 ephemeral key, little endian

Payload

  • Bloc DateTime
  • Bloc Options (optionnel)
  • Bloc Relay Tag Request (optionnel)
  • Bloc Padding (optionnel)

La taille minimale de la charge utile est de 8 octets. Puisque le bloc DateTime ne fait que 7 octets, au moins un autre bloc doit être présent.

Notes

  • La valeur X unique dans le bloc ChaCha20 initial garantit que le texte chiffré est différent pour chaque session.

  • Pour fournir une résistance au probing, Bob ne devrait pas envoyer un message Retry en réponse à un message Session Request à moins que les champs type de message, version de protocole et ID de réseau dans le message Session Request soient valides.

  • Bob doit rejeter les connexions où la valeur de timestamp est trop éloignée de l’heure actuelle. Appelez le delta de temps maximum “D”. Bob doit maintenir un cache local des valeurs de handshake précédemment utilisées et rejeter les doublons, pour prévenir les attaques par rejeu. Les valeurs dans le cache doivent avoir une durée de vie d’au moins 2*D. Les valeurs de cache dépendent de l’implémentation, cependant la valeur X de 32 octets (ou son équivalent chiffré) peut être utilisée. Rejeter en envoyant un message Retry contenant un token zéro et un bloc de terminaison.

  • Les clés éphémères Diffie-Hellman ne doivent jamais être réutilisées, pour éviter les attaques cryptographiques, et leur réutilisation sera rejetée comme une attaque par rejeu.

  • Les options “KE” et “auth” doivent être compatibles, c’est-à-dire que le secret partagé K doit avoir la taille appropriée. Si davantage d’options “auth” sont ajoutées, cela pourrait implicitement changer la signification du flag “KE” pour utiliser un KDF différent ou une taille de troncature différente.

  • Bob doit valider que la clé éphémère d’Alice est un point valide sur la courbe ici.

  • Le padding devrait être limité à une quantité raisonnable. Bob peut rejeter les connexions avec un padding excessif. Bob spécifiera ses options de padding dans Session Created. Recommandations min/max à déterminer. Taille aléatoire de 0 à 31 octets minimum ? (Distribution à déterminer, voir Annexe A.) TODO SAUF SI une taille minimale de paquet est appliquée pour PMTU.

  • En cas de la plupart des erreurs, y compris AEAD, DH, rejeu apparent, ou échec de validation de clé, Bob devrait arrêter tout traitement ultérieur du message et abandonner le message sans répondre.

  • Bob PEUT envoyer un message Retry contenant un token zéro et un bloc Termination avec un code de raison de décalage d’horloge si l’horodatage dans le bloc DateTime est trop décalé.

  • Atténuation DoS : DH est une opération relativement coûteuse. Comme avec le protocole NTCP précédent, les routeurs doivent prendre toutes les mesures nécessaires pour prévenir l’épuisement du CPU ou des connexions. Placer des limites sur le nombre maximum de connexions actives et de configurations de connexion en cours. Appliquer des délais d’attente de lecture (à la fois par lecture et total pour “slowloris”). Limiter les connexions répétées ou simultanées depuis la même source. Maintenir des listes noires pour les sources qui échouent de manière répétée. Ne pas répondre aux échecs AEAD. Alternativement, répondre avec un message Retry avant l’opération DH et la validation AEAD.

  • Champ “ver” : Le protocole Noise global, les extensions, et le protocole SSU2 incluant les spécifications de charge utile, indiquant SSU2. Ce champ peut être utilisé pour indiquer le support des changements futurs.

  • Le champ network ID est utilisé pour identifier rapidement les connexions inter-réseaux. Si ce champ ne correspond pas au network ID de Bob, Bob devrait se déconnecter et bloquer les connexions futures.

  • Bob doit abandonner le message si l’ID de connexion source est égal à l’ID de connexion de destination.

KDF for Session Created and Session Confirmed part 1


// take h saved from Session Request KDF
  // MixHash(ciphertext)
  h = SHA256(h || encrypted Noise payload from Session Request)

  // MixHash(header)
  h = SHA256(h || header)

  This is the "e" message pattern:

  // Bob's X25519 ephemeral keys
  besk = GENERATE_PRIVATE()
  bepk = DERIVE_PUBLIC(besk)

  // h is from KDF for Session Request
  // Bob ephemeral key Y
  // MixHash(bepk)
  h = SHA256(h || bepk);

  // h is used as the associated data for the AEAD in Session Created
  // Retain the Hash h for the Session Confirmed KDF

  End of "e" message pattern.

  This is the "ee" message pattern:

  // MixKey(DH())
  //[chainKey, k] = MixKey(sharedSecret)
  sharedSecret = DH(aesk, bepk) = DH(besk, aepk)
  keydata = HKDF(chainKey, sharedSecret, "", 64)
  chainKey = keydata[0:31]

  // AEAD parameters
  k = keydata[32:63]
  n = 0
  ad = h
  ciphertext = ENCRYPT(k, n, payload, ad)

  // retain the chaining key ck for Session Confirmed KDF

  End of "ee" message pattern.

  // Header encryption keys for this message
  // bik = Bob's intro key
  k_header_1 = bik
  k_header_2: See Session Request KDF above

  // Header protection keys for next message (Session Confirmed)
  k_header_1 = bik
  k_header_2 = HKDF(chainKey, ZEROLEN, "SessionConfirmed", 32)

Migration de Connexion

Bob envoie à Alice, en réponse à un message Session Request. Alice répond avec un message Session Confirmed. Taille : 80 + taille de la charge utile. Taille minimale : 88

Contenu Noise : Clé éphémère Y de Bob Charge utile Noise : DateTime, Address et autres blocs Taille maximale de la charge utile : MTU - 108 (IPv4) ou MTU - 128 (IPv6). Pour MTU 1280 : Charge utile maximale de 1172 (IPv4) ou 1152 (IPv6). Pour MTU 1500 : Charge utile maximale de 1392 (IPv4) ou 1372 (IPv6).

Propriétés de sécurité de la charge utile :

XK(s, rs):           Authentication   Confidentiality
    <- e, ee                  2                1

    Authentication: 2.
    Sender authentication resistant to key-compromise impersonation (KCI).
    The sender authentication is based on an ephemeral-static DH ("es" or "se")
    between the sender's static key pair and the recipient's ephemeral key pair.
    Assuming the corresponding private keys are secure, this authentication cannot be forged.

    Confidentiality: 1.
    Encryption to an ephemeral recipient.
    This payload has forward secrecy, since encryption involves an ephemeral-ephemeral DH ("ee").
    However, the sender has not authenticated the recipient,
    so this payload might be sent to any party, including an active attacker.


    "e": Bob generates a new ephemeral key pair and stores it in the e variable,
    writes the ephemeral public key as cleartext into the message buffer,
    and hashes the public key along with the old h to derive a new h.

    "ee": A DH is performed between the Bob's ephemeral key pair and the Alice's ephemeral key pair.
    The result is hashed along with the old ck to derive a new ck and k, and n is set to zero.

La valeur Y est chiffrée pour assurer l’indistinguabilité et l’unicité de la charge utile, qui sont des contre-mesures DPI nécessaires. Nous utilisons le chiffrement ChaCha20 pour y parvenir, plutôt que des alternatives plus complexes et plus lentes telles qu’elligator2. Le chiffrement asymétrique vers la clé publique du router d’Alice serait bien trop lent. Le chiffrement ChaCha20 utilise la clé d’introduction de Bob, telle que publiée dans la base de données réseau.

Le chiffrement ChaCha20 est uniquement destiné à la résistance DPI. Toute partie connaissant la clé d’introduction de Bob, qui est publiée dans la base de données réseau, et ayant capturé les 32 premiers octets de la Session Request, peut déchiffrer la valeur Y dans ce message.

Contenu brut :

+----+----+----+----+----+----+----+----+
  |  Long Header bytes 0-15, ChaCha20     |
  +  encrypted with Bob intro key and     +
  | derived key, see Header Encryption KDF|
  +----+----+----+----+----+----+----+----+
  |  Long Header bytes 16-31, ChaCha20    |
  +  encrypted with derived key n=0       +
  |  See Header Encryption KDF            |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +       Y, ChaCha20 encrypted           +
  |       with derived key n=0            |
  +              (32 bytes)               +
  |       See Header Encryption KDF       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |   ChaCha20 data                       |
  +   Encrypted and authenticated data    +
  |  length varies                        |
  +  k defined in KDF for Session Created +
  |  n = 0; see KDF for associated data   |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +        Poly1305 MAC (16 bytes)        +
  |                                       |
  +----+----+----+----+----+----+----+----+

  Y :: 32 bytes, ChaCha20 encrypted X25519 ephemeral key, little endian
          key: Bob's intro key
          n: 1
          data: 48 bytes (bytes 16-31 of the header, followed by encrypted Y)

Données non chiffrées (balise d’authentification Poly1305 non affichée) :

+----+----+----+----+----+----+----+----+
  |      Destination Connection ID        |
  +----+----+----+----+----+----+----+----+
  |   Packet Number   |type| ver| id |flag|
  +----+----+----+----+----+----+----+----+
  |        Source Connection ID           |
  +----+----+----+----+----+----+----+----+
  |                 Token                 |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |                  Y                    |
  +              (32 bytes)               +
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |     Noise payload (block data)        |
  +          (length varies)              +
  |      see below for allowed blocks     |
  +----+----+----+----+----+----+----+----+

  Destination Connection ID :: The Source Connection ID
                               received from Alice in Session Request

  id :: 1 byte, the network ID (currently 2, except for test networks)

  ver :: 2

  type :: 0

  flag :: 1 byte, unused, set to 0 for future compatibility

  Packet Number :: Random 4 byte number generated by Bob, ignored

  Source Connection ID :: The Destination Connection ID
                          received from Alice in Session Request

  Token :: 0 (unused)

  Y :: 32 bytes, X25519 ephemeral key, little endian

Payload

  • Bloc DateTime
  • Bloc Address
  • Bloc Relay Tag (optionnel)
  • Bloc New Token (optionnel)
  • Bloc First Packet Number (optionnel)
  • Bloc Options (optionnel)
  • Bloc Termination (non recommandé, envoyer dans un message de nouvelle tentative à la place)
  • Bloc Padding (optionnel)

La taille minimale de la charge utile est de 8 octets. Étant donné que les blocs DateTime et Address totalisent plus que cela, l’exigence est satisfaite avec seulement ces deux blocs.

Notes

  • Alice doit valider que la clé éphémère de Bob est un point valide sur la courbe ici.

  • Le padding devrait être limité à une quantité raisonnable. Alice peut rejeter les connexions avec un padding excessif. Alice spécifiera ses options de padding dans Session Confirmed. Directives min/max à déterminer. Taille aléatoire de 0 à 31 octets minimum ? (Distribution à déterminer, voir Annexe A.) TODO SAUF SI une taille de paquet minimum est appliquée pour PMTU.

  • En cas d’erreur, y compris AEAD, DH, horodatage, rejeu apparent, ou échec de validation de clé, Alice doit arrêter tout traitement de message supplémentaire et fermer la connexion sans répondre.

  • Alice doit rejeter les connexions où la valeur d’horodatage est trop éloignée du temps actuel. Appelons le delta de temps maximum “D”. Alice doit maintenir un cache local des valeurs de handshake précédemment utilisées et rejeter les doublons, pour empêcher les attaques par rejeu. Les valeurs dans le cache doivent avoir une durée de vie d’au moins 2*D. Les valeurs du cache dépendent de l’implémentation, cependant la valeur Y de 32 octets (ou son équivalent chiffré) peut être utilisée.

  • Alice doit abandonner le message si l’IP source et le port ne correspondent pas à l’IP de destination et au port de la Session Request.

  • Alice doit abandonner le message si les ID de connexion de destination et source ne correspondent pas aux ID de connexion source et destination de la requête de session.

  • Bob envoie un bloc de relay tag si demandé par Alice dans la Session Request.

Issues

  • Inclure les options de padding min/max ici ?

KDF for Session Confirmed part 1, using Session Created KDF


// take h saved from Session Created KDF
  // MixHash(ciphertext)
  h = SHA256(h || encrypted Noise payload from Session Created)

  // MixHash(header)
  h = SHA256(h || header)
  // h is used as the associated data for the AEAD in Session Confirmed part 1, below

  This is the "s" message pattern:

  // Alice's X25519 static keys
  ask = GENERATE_PRIVATE()
  apk = DERIVE_PUBLIC(ask)

  // AEAD parameters
  // k is from Session Request
  n = 1
  ad = h
  ciphertext = ENCRYPT(k, n++, apk, ad)

  // MixHash(ciphertext)
  h = SHA256(h || ciphertext);

  // h is used as the associated data for the AEAD in Session Confirmed part 2

  End of "s" message pattern.

  // Header encryption keys for this message
  See Session Confirmed part 2 below

KDF for Session Confirmed part 2


This is the "se" message pattern:

  // DH(ask, bepk) == DH(besk, apk)
  sharedSecret = DH(ask, bepk) = DH(besk, apk)

  // MixKey(DH())
  //[chainKey, k] = MixKey(sharedSecret)
  keydata = HKDF(chainKey, sharedSecret, "", 64)
  chainKey = keydata[0:31]

  // AEAD parameters
  k = keydata[32:63]
  n = 0
  ad = h
  ciphertext = ENCRYPT(k, n, payload, ad)

  // h from Session Confirmed part 1 is used as the associated data for the AEAD in Session Confirmed part 2
  // MixHash(ciphertext)
  h = SHA256(h || ciphertext);

  // retain the chaining key ck for the data phase KDF
  // retain the hash h for the data phase KDF

  End of "se" message pattern.

  // Header encryption keys for this message
  // bik = Bob's intro key
  k_header_1 = bik
  k_header_2: See Session Created KDF above

  // Header protection keys for data phase
  See data phase KDF below

SessionConfirmed (Type 2)

Alice envoie à Bob, en réponse à un message Session Created. Bob répond immédiatement avec un message Data contenant un bloc ACK. Taille : 80 + taille de la charge utile. Taille minimale : Environ 500 (la taille minimale du bloc d’informations du router est d’environ 420 octets)

Contenu Noise : clé statique d’Alice Partie 1 de la charge utile Noise : Aucune Partie 2 de la charge utile Noise : RouterInfo d’Alice, et autres blocs Taille maximale de la charge utile : MTU - 108 (IPv4) ou MTU - 128 (IPv6). Pour MTU 1280 : La charge utile maximale est 1172 (IPv4) ou 1152 (IPv6). Pour MTU 1500 : La charge utile maximale est 1392 (IPv4) ou 1372 (IPv6).

Propriétés de Sécurité de la Charge Utile :

XK(s, rs):           Authentication   Confidentiality
    -> s, se                  2                5

    Authentication: 2.
    Sender authentication resistant to key-compromise impersonation (KCI).  The
    sender authentication is based on an ephemeral-static DH ("es" or "se")
    between the sender's static key pair and the recipient's ephemeral key
    pair.  Assuming the corresponding private keys are secure, this
    authentication cannot be forged.

    Confidentiality: 5.
    Encryption to a known recipient, strong forward secrecy.  This payload is
    encrypted based on an ephemeral-ephemeral DH as well as an ephemeral-static
    DH with the recipient's static key pair.  Assuming the ephemeral private
    keys are secure, and the recipient is not being actively impersonated by an
    attacker that has stolen its static private key, this payload cannot be
    decrypted.

    "s": Alice writes her static public key from the s variable into the
    message buffer, encrypting it, and hashes the output along with the old h
    to derive a new h.

    "se": A DH is performed between the Alice's static key pair and the Bob's
    ephemeral key pair.  The result is hashed along with the old ck to derive a
    new ck and k, and n is set to zero.

Ceci contient deux trames ChaChaPoly. La première est la clé publique statique chiffrée d’Alice. La seconde est la charge utile Noise : le RouterInfo chiffré d’Alice, les options facultatives et le bourrage optionnel. Elles utilisent des clés différentes, car la fonction MixKey() est appelée entre les deux.

Contenu brut :

+----+----+----+----+----+----+----+----+
  |  Short Header 16 bytes, ChaCha20      |
  +  encrypted with Bob intro key and     +
  | derived key, see Header Encryption KDF|
  +----+----+----+----+----+----+----+----+
  |   ChaCha20 frame (32 bytes)           |
  +   Encrypted and authenticated data    +
  +   Alice static key S                  +
  | k defined in KDF for Session Created  |
  +     n = 1                             +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +        Poly1305 MAC (16 bytes)        +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |                                       |
  + Length varies (remainder of packet)   +
  |                                       |
  +   ChaChaPoly frame                    +
  |   Encrypted and authenticated         |
  +   see below for allowed blocks        +
  |                                       |
  +     k defined in KDF for              +
  |     Session Confirmed part 2          |
  +     n = 0                             +
  |     see KDF for associated data       |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +        Poly1305 MAC (16 bytes)        +
  |                                       |
  +----+----+----+----+----+----+----+----+

  S :: 32 bytes, ChaChaPoly encrypted Alice's X25519 static key, little endian
       inside 48 byte ChaChaPoly frame

Données non chiffrées (balises d’authentification Poly1305 non affichées) :

+----+----+----+----+----+----+----+----+
  |      Destination Connection ID        |
  +----+----+----+----+----+----+----+----+
  |   Packet Number   |type|frag|  flags  |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |              S                        |
  +       Alice static key                +
  |          (32 bytes)                   |
  +                                       +
  |                                       |
  +                                       +
  +----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |        Noise Payload                  |
  +        (length varies)                +
  |        see below for allowed blocks   |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

  Destination Connection ID :: As sent in Session Request,
                               or one received in Session Confirmed?

  Packet Number :: 0 always, for all fragments, even if retransmitted

  type :: 2

  frag :: 1 byte fragment info:
         bit order: 76543210 (bit 7 is MSB)
         bits 7-4: fragment number 0-14, big endian
         bits 3-0: total fragments 1-15, big endian

  flags :: 2 bytes, unused, set to 0 for future compatibility

  S :: 32 bytes, Alice's X25519 static key, little endian

Payload

  • Bloc RouterInfo (doit être le premier bloc)
  • Bloc Options (optionnel)
  • Bloc New Token (optionnel)
  • Bloc Relay Request (optionnel)
  • Bloc Peer Test (optionnel)
  • Bloc First Packet Number (optionnel)
  • Blocs I2NP, First Fragment, ou Follow-on Fragment (optionnels, mais probablement pas de place)
  • Bloc Padding (optionnel)

La taille minimale de la charge utile est de 8 octets. Étant donné que le bloc RouterInfo sera bien plus volumineux que cela, l’exigence est satisfaite avec seulement ce bloc.

Notes

  • Bob doit effectuer la validation habituelle des Router Info. S’assurer que le type de signature est pris en charge, vérifier la signature, vérifier que l’horodatage est dans les limites, et toute autre vérification nécessaire. Voir ci-dessous pour les notes sur la gestion des Router Infos fragmentées.

  • Bob doit vérifier que la clé statique d’Alice reçue dans la première trame correspond à la clé statique dans le Router Info. Bob doit d’abord rechercher dans le Router Info une adresse de routeur NTCP ou SSU2 avec une option de version (v) correspondante. Voir les sections Router Info publié et Router Info non publié ci-dessous. Voir ci-dessous les notes sur la gestion des Router Info fragmentés.

  • Si Bob possède une version plus ancienne du RouterInfo d’Alice dans sa netdb, vérifier que la clé statique dans les informations du routeur est identique dans les deux versions, si elle est présente, et si la version plus ancienne date de moins de XXX (voir le temps de rotation des clés ci-dessous)

  • Bob doit valider que la clé statique d’Alice est un point valide sur la courbe ici.

  • Les options doivent être incluses, pour spécifier les paramètres de padding.

  • En cas d’erreur, incluant l’échec de validation AEAD, RI, DH, timestamp ou clé, Bob doit arrêter tout traitement de message supplémentaire et fermer la connexion sans répondre.

  • Contenu de la trame partie 2 du message 3 : Le format de cette trame est le même que le format des trames de phase de données, sauf que la longueur de la trame est envoyée par Alice dans la Session Request. Voir ci-dessous pour le format des trames de phase de données. La trame doit contenir 1 à 4 blocs dans l’ordre suivant :

    1. Bloc Router Info d’Alice (obligatoire)
    2. Bloc Options (optionnel)
    3. Blocs I2NP (optionnels)
    4. Bloc de remplissage (optionnel) Cette trame ne doit jamais contenir d’autre type de bloc. TODO : qu’en est-il du relais et du test de pairs ?
  • Le bloc de remplissage de la partie 2 du message 3 est recommandé.

  • Il peut n’y avoir aucun espace, ou seulement une petite quantité d’espace, disponible pour les blocs I2NP, selon la MTU et la taille du Router Info. N’incluez PAS de blocs I2NP si le Router Info est fragmenté. L’implémentation la plus simple peut être de ne jamais inclure de blocs I2NP dans le message Session Confirmed, et d’envoyer tous les blocs I2NP dans les messages Data suivants. Voir la section bloc Router Info ci-dessous pour la taille maximale des blocs.

Session Confirmed Fragmentation

Le message Session Confirmed doit contenir la Router Info complète signée d’Alice afin que Bob puisse effectuer plusieurs vérifications requises :

  • La clé statique “s” dans le RI correspond à la clé statique dans le handshake
  • La clé d’introduction “i” dans le RI doit être extraite et valide, pour être utilisée dans la phase de données
  • La signature du RI est valide

Malheureusement, le Router Info, même lorsqu’il est compressé en gzip dans le bloc RI, peut dépasser le MTU. Par conséquent, le Session Confirmed peut être fragmenté sur deux paquets ou plus. C’est le SEUL cas dans le protocole SSU2 où une charge utile protégée par AEAD est fragmentée sur deux paquets ou plus.

Les en-têtes de chaque paquet sont construits comme suit :

  • TOUS les en-têtes sont des en-têtes courts avec le même numéro de paquet 0
  • TOUS les en-têtes contiennent un champ “frag”, avec le numéro de fragment et le nombre total de fragments
  • L’en-tête non chiffré du fragment 0 est la donnée associée (AD) pour le message “jumbo”
  • Chaque en-tête est chiffré en utilisant les 24 derniers octets de données de CE paquet

Construisez la série de paquets comme suit :

  • Créer un seul bloc RI (fragment 0 sur 1 dans le champ frag du bloc RI). Nous n’utilisons pas la fragmentation de bloc RI, c’était pour une méthode alternative de résolution du même problème.
  • Créer un payload “jumbo” avec le bloc RI et tout autre bloc à inclure
  • Calculer la taille totale des données (sans inclure l’en-tête), qui est la taille du payload + 64 octets pour la clé statique et les deux MAC
  • Calculer l’espace disponible dans chaque paquet, qui est le MTU moins l’en-tête IP (20 ou 40), moins l’en-tête UDP (8), moins l’en-tête court SSU2 (16). La surcharge totale par paquet est de 44 (IPv4) ou 64 (IPv6).
  • Calculer le nombre de paquets.
  • Calculer la taille des données dans le dernier paquet. Elle doit être supérieure ou égale à 24 octets, afin que le chiffrement d’en-tête fonctionne. Si elle est trop petite, soit ajouter un bloc de padding, OU augmenter la taille du bloc de padding s’il est déjà présent, OU réduire la taille d’un des autres paquets pour que le dernier paquet soit assez grand.
  • Créer l’en-tête non chiffré pour le premier paquet, avec le nombre total de fragments dans le champ frag, et chiffrer le payload “jumbo” avec Noise, en utilisant l’en-tête comme AD, comme d’habitude.
  • Diviser le paquet jumbo chiffré en fragments
  • Ajouter un en-tête non chiffré pour chaque fragment 1-n
  • Chiffrer l’en-tête pour chaque fragment 0-n. Chaque en-tête utilise les MÊMES k_header_1 et k_header_2 tels que définis ci-dessus dans le KDF Session Confirmed.
  • Transmettre tous les fragments

Processus de réassemblage :

Lorsque Bob reçoit un message Session Confirmed, il décrypte l’en-tête, examine le champ frag, et détermine que le Session Confirmed est fragmenté. Il ne décrypte pas (et ne peut pas décrypter) le message tant que tous les fragments ne sont pas reçus et réassemblés.

  • Préserver l’en-tête pour le fragment 0, car il est utilisé comme Noise AD
  • Ignorer les en-têtes des autres fragments avant le réassemblage
  • Réassembler la charge utile “jumbo”, avec l’en-tête du fragment 0 comme AD, et déchiffrer avec Noise
  • Valider le bloc RI comme d’habitude
  • Passer à la phase de données et envoyer ACK 0, comme d’habitude

Il n’existe aucun mécanisme pour que Bob accuse réception des fragments individuels. Lorsque Bob reçoit tous les fragments, les réassemble, les déchiffre et valide le contenu, Bob effectue un split() comme d’habitude, entre dans la phase de données et envoie un ACK du paquet numéro 0.

Si Alice ne reçoit pas d’ACK pour le paquet numéro 0, elle doit retransmettre tous les paquets de session confirmée tels quels.

Exemples :

Pour un MTU de 1500 sur IPv6, la charge utile maximale est de 1372, la surcharge du bloc RI est de 5, la taille maximale des données RI (compressées gzip) est de 1367 (en supposant qu’il n’y ait pas d’autres blocs). Avec deux paquets, la surcharge du 2ème paquet est de 64, il peut donc contenir 1436 octets de charge utile supplémentaires. Donc deux paquets suffisent pour un RI compressé jusqu’à 2803 octets.

Le plus grand RI compressé observé dans le réseau actuel fait environ 1400 octets ; par conséquent, en pratique, deux fragments devraient suffire, même avec un MTU minimum de 1280. Le protocole autorise un maximum de 15 fragments.

Analyse de sécurité :

L’intégrité et la sécurité d’une Session Confirmed fragmentée sont les mêmes que celles d’une Session Confirmed non fragmentée. Toute altération de n’importe quel fragment entraînera l’échec du Noise AEAD après le réassemblage. Les en-têtes des fragments après le fragment 0 ne sont utilisés que pour identifier le fragment. Même si un attaquant sur le chemin avait la clé k_header_2 utilisée pour chiffrer l’en-tête (peu probable, dérivée de la négociation), cela ne permettrait pas à l’attaquant de substituer un fragment valide.

KDF for data phase

La phase de données utilise l’en-tête pour les données associées.

Le KDF génère deux clés de chiffrement k_ab et k_ba à partir de la clé de chaînage ck, en utilisant HMAC-SHA256(key, data) tel que défini dans RFC 2104. Il s’agit de la fonction split(), exactement telle que définie dans la spécification Noise.

// split()
  // chainKey = from handshake phase
  keydata = HKDF(chainKey, ZEROLEN, "", 64)
  k_ab = keydata[0:31]
  k_ba = keydata[32:63]

  // key is k_ab for Alice to Bob
  // key is k_ba for Bob to Alice

  keydata = HKDF(key, ZEROLEN, "HKDFSSU2DataKeys", 64)
  k_data = keydata[0:31]
  k_header_2 = keydata[32:63]


  // AEAD parameters
  k = k_data
  n = 4 byte packet number from header
  ad = 16 byte header, before header encryption
  ciphertext = ENCRYPT(k, n, payload, ad)

  // Header encryption keys for data phase
  // aik = Alice's intro key
  // bik = Bob's intro key
  k_header_1 = Receiver's intro key (aik or bik)
  k_header_2: from above

Data Message (Type 6)

Charge utile Noise : Tous les types de blocs sont autorisés Taille maximale de charge utile : MTU - 60 (IPv4) ou MTU - 80 (IPv6). Pour un MTU de 1500 : La charge utile maximale est de 1440 (IPv4) ou 1420 (IPv6).

À partir de la 2ème partie de Session Confirmed, tous les messages sont à l’intérieur d’une charge utile ChaChaPoly authentifiée et chiffrée. Tout le padding se trouve à l’intérieur du message. À l’intérieur de la charge utile se trouve un format standard avec zéro ou plusieurs “blocs”. Chaque bloc a un type d’un octet et une longueur de deux octets. Les types incluent date/heure, message I2NP, options, terminaison et padding.

Note : Bob peut, mais n’est pas obligé, d’envoyer son RouterInfo à Alice comme premier message à Alice dans la phase de données.

Propriétés de sécurité de la charge utile :

XK(s, rs):           Authentication   Confidentiality
    <-                        2                5
    ->                        2                5

    Authentication: 2.
    Sender authentication resistant to key-compromise impersonation (KCI).
    The sender authentication is based on an ephemeral-static DH ("es" or "se")
    between the sender's static key pair and the recipient's ephemeral key pair.
    Assuming the corresponding private keys are secure, this authentication cannot be forged.

    Confidentiality: 5.
    Encryption to a known recipient, strong forward secrecy.
    This payload is encrypted based on an ephemeral-ephemeral DH as well as
    an ephemeral-static DH with the recipient's static key pair.
    Assuming the ephemeral private keys are secure, and the recipient is not being actively impersonated
    by an attacker that has stolen its static private key, this payload cannot be decrypted.

Notes

  • Le routeur doit abandonner un message avec une erreur AEAD.
+----+----+----+----+----+----+----+----+
  |  Short Header 16 bytes, ChaCha20      |
  +  encrypted with intro key and         +
  |  derived key, see Data Phase KDF      |
  +----+----+----+----+----+----+----+----+
  |   ChaCha20 data                       |
  +   Encrypted and authenticated data    +
  |  length varies                        |
  +  k defined in Data Phase KDF          +
  |  n = packet number from header        |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +        Poly1305 MAC (16 bytes)        +
  |                                       |
  +----+----+----+----+----+----+----+----+

Données non chiffrées (tag d’authentification Poly1305 non affiché) :

+----+----+----+----+----+----+----+----+
  |      Destination Connection ID        |
  +----+----+----+----+----+----+----+----+
  |   Packet Number   |type|    flags     |
  +----+----+----+----+----+----+----+----+
  |     Noise payload (block data)        |
  +          (length varies)              +
  |                                       |
  +----+----+----+----+----+----+----+----+

  Destination Connection ID :: As specified in session setup

  Packet Number :: 4 byte big endian integer

  type :: 6

  flags :: 3 bytes, unused, set to 0 for future compatibility

Notes

  • La taille minimale de la charge utile est de 8 octets. Cette exigence sera respectée par tout bloc ACK, I2NP, First Fragment ou Follow-on Fragment. Si l’exigence n’est pas respectée, un bloc Padding doit être inclus.

  • Chaque numéro de paquet ne peut être utilisé qu’une seule fois. Lors de la retransmission de messages I2NP ou de fragments, un nouveau numéro de paquet doit être utilisé.

KDF for Peer Test


// AEAD parameters
  // bik = Bob's intro key
  k = bik
  n = 4 byte packet number from header
  ad = 32 byte header, before header encryption
  ciphertext = ENCRYPT(k, n, payload, ad)

  // Header encryption keys for this message
  k_header_1 = bik
  k_header_2 = bik

Peer Test (Type 7)

Charlie envoie à Alice, et Alice envoie à Charlie, pour les phases 5-7 du Peer Test uniquement. Les phases 1-4 du Peer Test doivent être envoyées en session en utilisant un bloc Peer Test dans un message Data. Voir les sections Bloc Peer Test et Processus Peer Test ci-dessous pour plus d’informations.

Taille : 48 + taille de la charge utile.

Charge utile Noise : Voir ci-dessous.

Contenu brut :

+----+----+----+----+----+----+----+----+
  |  Long Header bytes 0-15, ChaCha20     |
  +  encrypted with Alice or Charlie      +
  |  intro key                            |
  +----+----+----+----+----+----+----+----+
  |  Long Header bytes 16-31, ChaCha20    |
  +  encrypted with Alice or Charlie      +
  |  intro key                            |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |   ChaCha20 encrypted data             |
  +          (length varies)              +
  |                                       |
  +  see KDF for key and n                +
  |  see KDF for associated data          |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +        Poly1305 MAC (16 bytes)        +
  |                                       |
  +----+----+----+----+----+----+----+----+

Données non chiffrées (tag d’authentification Poly1305 non affiché) :

+----+----+----+----+----+----+----+----+
  |      Destination Connection ID        |
  +----+----+----+----+----+----+----+----+
  |   Packet Number   |type| ver| id |flag|
  +----+----+----+----+----+----+----+----+
  |        Source Connection ID           |
  +----+----+----+----+----+----+----+----+
  |                 Token                 |
  +----+----+----+----+----+----+----+----+
  |    ChaCha20 payload (block data)      |
  +          (length varies)              +
  |    see below for allowed blocks       |
  +----+----+----+----+----+----+----+----+


  Destination Connection ID :: See below

  type :: 7

  ver :: 2

  id :: 1 byte, the network ID (currently 2, except for test networks)

  flag :: 1 byte, unused, set to 0 for future compatibility

  Packet Number :: Random number generated by Alice or Charlie

  Source Connection ID :: See below

  Token :: Randomly generated by Alice or Charlie, ignored

En-tête Long

  • Bloc DateTime
  • Bloc Address (requis pour les messages 6 et 7, voir note ci-dessous)
  • Bloc Peer Test
  • Bloc Padding (optionnel)

La taille minimale de la charge utile est de 8 octets. Étant donné que le bloc Peer Test totalise plus que cela, l’exigence est satisfaite avec seulement ce bloc.

Dans les messages 5 et 7, le bloc Peer Test peut être identique au bloc des messages de session 3 et 4, contenant l’accord signé par Charlie, ou il peut être régénéré. La signature est optionnelle.

Dans le message 6, le bloc Peer Test peut être identique au bloc des messages de session 1 et 2, contenant la requête signée par Alice, ou il peut être régénéré. La signature est optionnelle.

ID de connexion : Les deux ID de connexion sont dérivés du nonce de test. Pour les messages 5 et 7 envoyés de Charlie vers Alice, l’ID de connexion de destination est deux copies du nonce de test de 4 octets en big-endian, c’est-à-dire ((nonce « 32) | nonce). L’ID de connexion source est l’inverse de l’ID de connexion de destination, c’est-à-dire ~((nonce « 32) | nonce). Pour le message 6 envoyé d’Alice vers Charlie, intervertir les deux ID de connexion.

Contenu du bloc d’adresse :

  • Dans le message 5 : Non requis.
  • Dans le message 6 : L’IP et le port de Charlie tels que sélectionnés depuis le RI de Charlie.
  • Dans le message 7 : L’IP et le port réels d’Alice depuis lesquels le message 6 a été reçu.

KDF for Retry

L’exigence pour le message Retry est que Bob n’est pas tenu de déchiffrer le message Session Request pour générer un message Retry en réponse. De plus, ce message doit être rapide à générer, en utilisant uniquement le chiffrement symétrique.


// AEAD parameters
  // bik = Bob's intro key
  k = bik
  n = 4 byte packet number from header
  ad = 32 byte header, before header encryption
  ciphertext = ENCRYPT(k, n, payload, ad)

  // Header encryption keys for this message
  k_header_1 = bik
  k_header_2 = bik

Retry (Type 9)

Bob envoie à Alice, en réponse à un message Session Request ou Token Request. Alice répond avec un nouveau Session Request. Taille : 48 + taille de la charge utile.

Sert également comme message de Termination (c’est-à-dire, “Ne pas réessayer”) si un bloc de Termination est inclus.

Charge utile Noise : Voir ci-dessous.

Contenu brut :

+----+----+----+----+----+----+----+----+
  |  Long Header bytes 0-15, ChaCha20     |
  +  encrypted with Bob intro key         +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |  Long Header bytes 16-31, ChaCha20    |
  +  encrypted with Bob intro key         +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |   ChaCha20 encrypted data             |
  +          (length varies)              +
  |                                       |
  +  see KDF for key and n                +
  |  see KDF for associated data          |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +        Poly1305 MAC (16 bytes)        +
  |                                       |
  +----+----+----+----+----+----+----+----+

Données non chiffrées (tag d’authentification Poly1305 non affiché) :

+----+----+----+----+----+----+----+----+
  |      Destination Connection ID        |
  +----+----+----+----+----+----+----+----+
  |   Packet Number   |type| ver| id |flag|
  +----+----+----+----+----+----+----+----+
  |        Source Connection ID           |
  +----+----+----+----+----+----+----+----+
  |                 Token                 |
  +----+----+----+----+----+----+----+----+
  |    ChaCha20 payload (block data)      |
  +          (length varies)              +
  |    see below for allowed blocks       |
  +----+----+----+----+----+----+----+----+


  Destination Connection ID :: The Source Connection ID
                               received from Alice in Token Request
                               or Session Request

  Packet Number :: Random number generated by Bob

  type :: 9

  ver :: 2

  id :: 1 byte, the network ID (currently 2, except for test networks)

  flag :: 1 byte, unused, set to 0 for future compatibility

  Source Connection ID :: The Destination Connection ID
                          received from Alice in Token Request
                          or Session Request

  Token :: 8 byte unsigned integer, randomly generated by Bob, nonzero,
           or zero if session is rejected and a termination block is included

En-tête Court

  • Bloc DateTime
  • Bloc Address
  • Bloc Options (optionnel)
  • Bloc Termination (optionnel, si la session est rejetée)
  • Bloc Padding (optionnel)

La taille minimale de la charge utile est de 8 octets. Étant donné que les blocs DateTime et Address totalisent plus que cela, l’exigence est satisfaite avec seulement ces deux blocs.

Numérotation des ID de connexion

  • Pour fournir une résistance au sondage, un router ne devrait pas envoyer un message Retry en réponse à un message Session Request ou Token Request à moins que les champs type de message, version de protocole et ID réseau dans le message Request ne soient valides.

  • Pour limiter l’ampleur de toute attaque par amplification qui peut être montée en utilisant des adresses sources usurpées, le message Retry ne doit pas contenir de grandes quantités de remplissage. Il est recommandé que le message Retry ne soit pas plus grand que trois fois la taille du message auquel il répond. Alternativement, utilisez une méthode simple comme ajouter une quantité aléatoire de remplissage dans la plage de 1 à 64 octets.

KDF for Token Request

Ce message doit être rapide à générer, en utilisant uniquement le chiffrement symétrique.


// AEAD parameters
  // bik = Bob's intro key
  k = bik
  n = 4 byte packet number from header
  ad = 32 byte header, before header encryption
  ciphertext = ENCRYPT(k, n, payload, ad)

  // Header encryption keys for this message
  k_header_1 = bik
  k_header_2 = bik

Token Request (Type 10)

Alice envoie à Bob. Bob répond avec un message Retry. Taille : 48 + taille du payload.

Si Alice n’a pas de jeton valide, Alice devrait envoyer ce message au lieu d’une Session Request, pour éviter la surcharge de chiffrement asymétrique lors de la génération d’une Session Request.

Payload Noise : Voir ci-dessous.

Contenu brut :

+----+----+----+----+----+----+----+----+
  |  Long Header bytes 0-15, ChaCha20     |
  +  encrypted with Bob intro key         +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |  Long Header bytes 16-31, ChaCha20    |
  +  encrypted with Bob intro key         +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |   ChaCha20 encrypted data             |
  +          (length varies)              +
  |                                       |
  +  see KDF for key and n                +
  |  see KDF for associated data          |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +        Poly1305 MAC (16 bytes)        +
  |                                       |
  +----+----+----+----+----+----+----+----+

Données non chiffrées (balise d’authentification Poly1305 non affichée) :

+----+----+----+----+----+----+----+----+
  |      Destination Connection ID        |
  +----+----+----+----+----+----+----+----+
  |   Packet Number   |type| ver| id |flag|
  +----+----+----+----+----+----+----+----+
  |        Source Connection ID           |
  +----+----+----+----+----+----+----+----+
  |                 Token                 |
  +----+----+----+----+----+----+----+----+
  |    ChaCha20 payload (block data)      |
  +          (length varies)              +
  |    see below for allowed blocks       |
  +----+----+----+----+----+----+----+----+


  Destination Connection ID :: Randomly generated by Alice

  Packet Number :: Random number generated by Alice

  type :: 10

  ver :: 2

  id :: 1 byte, the network ID (currently 2, except for test networks)

  flag :: 1 byte, unused, set to 0 for future compatibility

  Source Connection ID :: Randomly generated by Alice,
                          must not be equal to Destination Connection ID

  Token :: zero

Numérotation des Paquets

  • Bloc DateTime
  • Bloc de remplissage

La taille minimale de la charge utile est de 8 octets.

Liaison d’En-tête

  • Pour fournir une résistance au probing, un router ne doit pas envoyer un message Retry en réponse à un message Token Request à moins que les champs type de message, version du protocole et ID réseau dans le message Token Request ne soient valides.

  • Ceci n’est PAS un message Noise standard et ne fait pas partie de la négociation. Il n’est pas lié au message de demande de session, si ce n’est par les ID de connexion.

  • Sur la plupart des erreurs, y compris AEAD, ou une répétition apparente Bob devrait arrêter le traitement ultérieur des messages et abandonner le message sans répondre.

  • Bob doit rejeter les connexions où la valeur d’horodatage s’écarte trop du temps actuel. Appelons le delta de temps maximum “D”. Bob doit maintenir un cache local des valeurs de handshake précédemment utilisées et rejeter les doublons, pour prévenir les attaques par rejeu. Les valeurs dans le cache doivent avoir une durée de vie d’au moins 2*D. Les valeurs de cache dépendent de l’implémentation, cependant la valeur X de 32 octets (ou son équivalent chiffré) peut être utilisée.

  • Bob PEUT envoyer un message Retry contenant un token zéro et un bloc Termination avec un code de raison de décalage d’horloge si l’horodatage dans le bloc DateTime est trop décalé.

  • Taille minimale : TBD, mêmes règles que pour Session Created ?

KDF for Hole Punch

Ce message doit être rapide à générer, en utilisant uniquement le chiffrement symétrique.


// AEAD parameters
  // aik = Alice's intro key
  k = aik
  n = 4 byte packet number from header
  ad = 32 byte header, before header encryption
  ciphertext = ENCRYPT(k, n, payload, ad)

  // Header encryption keys for this message
  k_header_1 = aik
  k_header_2 = aik

Hole Punch (Type 11)

Charlie envoie à Alice, en réponse à un Relay Intro reçu de Bob. Alice répond avec une nouvelle Session Request. Taille : 48 + taille de la charge utile.

Payload Noise : Voir ci-dessous.

Contenu brut :

+----+----+----+----+----+----+----+----+
  |  Long Header bytes 0-15, ChaCha20     |
  +  encrypted with Alice intro key       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |  Long Header bytes 16-31, ChaCha20    |
  +  encrypted with Alice intro key       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |   ChaCha20 encrypted data             |
  +          (length varies)              +
  |                                       |
  +  see KDF for key and n                +
  |  see KDF for associated data          |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +        Poly1305 MAC (16 bytes)        +
  |                                       |
  +----+----+----+----+----+----+----+----+

Données non chiffrées (tag d’authentification Poly1305 non affiché) :

+----+----+----+----+----+----+----+----+
  |      Destination Connection ID        |
  +----+----+----+----+----+----+----+----+
  |   Packet Number   |type| ver| id |flag|
  +----+----+----+----+----+----+----+----+
  |        Source Connection ID           |
  +----+----+----+----+----+----+----+----+
  |                 Token                 |
  +----+----+----+----+----+----+----+----+
  |    ChaCha20 payload (block data)      |
  +          (length varies)              +
  |    see below for allowed blocks       |
  +----+----+----+----+----+----+----+----+


  Destination Connection ID :: See below

  Packet Number :: Random number generated by Charlie

  type :: 11

  ver :: 2

  id :: 1 byte, the network ID (currently 2, except for test networks)

  flag :: 1 byte, unused, set to 0 for future compatibility

  Source Connection ID :: See below

  Token :: 8 byte unsigned integer, randomly generated by Charlie, nonzero.

Chiffrement des En-têtes

  • Bloc DateTime
  • Bloc Address
  • Bloc Relay Response
  • Bloc Padding (optionnel)

La taille minimale de la charge utile est de 8 octets. Étant donné que les blocs DateTime et Address totalisent plus que cela, l’exigence est satisfaite avec seulement ces deux blocs.

ID de connexion : Les deux ID de connexion sont dérivés du nonce de relais. L’ID de connexion de destination correspond à deux copies du nonce de relais de 4 octets en big-endian, c’est-à-dire ((nonce « 32) | nonce). L’ID de connexion source est l’inverse de l’ID de connexion de destination, c’est-à-dire ~((nonce « 32) | nonce).

Alice devrait ignorer le token dans l’en-tête. Le token à utiliser dans la Session Request se trouve dans le bloc Relay Response.

Noise Payload

Chaque charge utile Noise contient zéro ou plusieurs « blocs ».

Ceci utilise le même format de bloc que défini dans les spécifications NTCP2 et ECIES. Les types de blocs individuels sont définis différemment. Le terme équivalent dans QUIC RFC 9000 est “frames”.

Il existe des préoccupations selon lesquelles encourager les implémenteurs à partager du code pourrait entraîner des problèmes d’analyse syntaxique. Les implémenteurs devraient soigneusement considérer les avantages et les risques du partage de code, et s’assurer que les règles d’ordonnancement et de validation des blocs sont différentes pour les deux contextes.

Considérations de sécurité

Il y a un ou plusieurs blocs dans la charge utile chiffrée. Un bloc est un format simple Tag-Length-Value (TLV). Chaque bloc contient un identifiant d’un octet, une longueur de deux octets, et zéro ou plusieurs octets de données. Ce format est identique à celui de NTCP2 et ECIES, cependant les définitions de blocs sont différentes.

Pour l’extensibilité, les récepteurs doivent ignorer les blocs avec des identifiants inconnus, et les traiter comme du remplissage.

(Tag d’authentification Poly1305 non affiché) :

+----+----+----+----+----+----+----+----+
  |blk |  size   |       data             |
  +----+----+----+                        +
  |                                       |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+
  |blk |  size   |       data             |
  +----+----+----+                        +
  |                                       |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+
  ~               .   .   .               ~

  blk :: 1 byte, see below
  size :: 2 bytes, big endian, size of data to follow, 0 - TBD
  data :: the data

Le chiffrement d’en-tête utilise les 24 derniers octets du paquet comme IV pour les deux opérations ChaCha20. Comme tous les paquets se terminent par un MAC de 16 octets, cela exige que toutes les charges utiles de paquets fassent un minimum de 8 octets. Si une charge utile ne satisfait pas cette exigence, un bloc de remplissage doit être inclus.

La charge utile ChaChaPoly maximale varie selon le type de message, la MTU, et le type d’adresse IPv4 ou IPv6. La charge utile maximale est MTU - 60 pour IPv4 et MTU - 80 pour IPv6. Les données de charge utile maximales sont MTU - 63 pour IPv4 et MTU - 83 pour IPv6. La limite supérieure est d’environ 1440 octets pour IPv4, MTU 1500, message Data. La taille maximale de bloc total est la taille maximale de charge utile. La taille maximale de bloc unique est la taille maximale de bloc total. Le type de bloc fait 1 octet. La longueur de bloc fait 2 octets. La taille maximale de données de bloc unique est la taille maximale de bloc unique moins 3.

Notes :

  • Les implémenteurs doivent s’assurer que lors de la lecture d’un bloc, des données mal formées ou malveillantes ne provoqueront pas de lectures débordant dans le bloc suivant ou au-delà de la limite du payload.

  • Les implémentations devraient ignorer les types de blocs inconnus pour la compatibilité ascendante.

Types de blocs :

Payload Block TypeType NumberBlock Length
DateTime07
Options115+
Router Info2varies
I2NP Message3varies
First Fragment4varies
Follow-on Fragment5varies
Termination69 typ.
Relay Request7varies
Relay Response8varies
Relay Intro9varies
Peer Test10varies
Next Nonce11TBD
ACK12varies
Address139 or 21
reserved14
Relay Tag Request153
Relay Tag167
New Token1715
Path Challenge18varies
Path Response19varies
First Packet Number207
Congestion214
reserved for experimental features224-253
Padding254varies
reserved for future extension255

Block Ordering Rules

Dans la Session Confirmed, le Router Info doit être le premier bloc.

Dans tous les autres messages, l’ordre n’est pas spécifié, sauf pour les exigences suivantes : Le Padding, s’il est présent, doit être le dernier bloc. La Termination, si elle est présente, doit être le dernier bloc sauf pour le Padding. Plusieurs blocs Padding ne sont pas autorisés dans une seule charge utile.

Block Specifications

Fonction de dérivation de clé (KDF) de chiffrement d’en-tête

Pour la synchronisation temporelle :

+----+----+----+----+----+----+----+
  | 0  |    4    |     timestamp     |
  +----+----+----+----+----+----+----+

  blk :: 0
  size :: 2 bytes, big endian, value = 4
  timestamp :: Unix timestamp, unsigned seconds.
               Wraps around in 2106

Notes :

  • Contrairement à SSU 1, il n’y a pas d’horodatage dans l’en-tête de paquet pour la phase de données dans SSU 2.
  • Les implémentations devraient envoyer périodiquement des blocs DateTime pendant la phase de données.
  • Les implémentations doivent arrondir à la seconde la plus proche pour éviter le biais d’horloge dans le réseau.

Validation d’En-tête

Passer les options mises à jour. Les options incluent : Rembourrage minimum et maximum.

Le bloc d’options aura une longueur variable.

+----+----+----+----+----+----+----+----+
  | 1  |  size   |tmin|tmax|rmin|rmax|tdmy|
  +----+----+----+----+----+----+----+----+
  |tdmy|  rdmy   |  tdelay |  rdelay |    |
  ~----+----+----+----+----+----+----+    ~
  |              more_options             |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

  blk :: 1
  size :: 2 bytes, big endian, size of options to follow, 12 bytes minimum

  tmin, tmax, rmin, rmax :: requested padding limits
      tmin and rmin are for desired resistance to traffic analysis.
      tmax and rmax are for bandwidth limits.
      tmin and tmax are the transmit limits for the router sending this options block.
      rmin and rmax are the receive limits for the router sending this options block.
      Each is a 4.4 fixed-point float representing 0 to 15.9375
      (or think of it as an unsigned 8-bit integer divided by 16.0).
      This is the ratio of padding to data. Examples:
      Value of 0x00 means no padding
      Value of 0x01 means add 6 percent padding
      Value of 0x10 means add 100 percent padding
      Value of 0x80 means add 800 percent (8x) padding
      Alice and Bob will negotiate the minimum and maximum in each direction.
      These are guidelines, there is no enforcement.
      Sender should honor receiver's maximum.
      Sender may or may not honor receiver's minimum, within bandwidth constraints.

  tdmy: Max dummy traffic willing to send, 2 bytes big endian, bytes/sec average
  rdmy: Requested dummy traffic, 2 bytes big endian, bytes/sec average
  tdelay: Max intra-message delay willing to insert, 2 bytes big endian, msec average
  rdelay: Requested intra-message delay, 2 bytes big endian, msec average

  Padding distribution specified as additional parameters?
  Random delay specified as additional parameters?

  more_options :: Format TBD

Problèmes d’options :

  • La négociation des options est à déterminer.

RouterInfo

Transmettre le RouterInfo d’Alice à Bob. Utilisé uniquement dans la charge utile de la partie 2 de Session Confirmed. Ne pas utiliser pendant la phase de données ; utiliser plutôt un message I2NP DatabaseStore.

Taille minimale : Environ 420 octets, sauf si l’identité du router et la signature dans les informations du router sont compressibles, ce qui est peu probable.

REMARQUE : Le bloc Router Info n’est jamais fragmenté. Le champ frag est toujours 0/1. Voir la section Fragmentation Session Confirmed ci-dessus pour plus d’informations.

+----+----+----+----+----+----+----+----+
  | 2  |  size   |flag|frag|              |
  +----+----+----+----+----+              +
  |                                       |
  +       Router Info fragment            +
  | (Alice RI in Session Confirmed)       |
  + (Alice, Bob, or third-party           +
  |  RI in data phase)                    |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

  blk :: 2
  size :: 2 bytes, big endian, 2 + fragment size
  flag :: 1 byte flags
         bit order: 76543210 (bit 7 is MSB)
         bit 0: 0 for local store, 1 for flood request
         bit 1: 0 for uncompressed, 1 for gzip compressed
         bits 7-2: Unused, set to 0 for future compatibility
  frag :: 1 byte fragment info:
         bit order: 76543210 (bit 7 is MSB)
         bits 7-4: fragment number, always 0
         bits 3-0: total fragments, always 1, big endian

  routerinfo :: Alice's or Bob's RouterInfo

Notes :

  • Les Router Info sont optionnellement compressées avec gzip, comme indiqué par le bit de flag 1. Ceci diffère de NTCP2, où elles ne sont jamais compressées, et d’un message DatabaseStore, où elles sont toujours compressées. La compression est optionnelle car elle apporte généralement peu d’avantages pour les petites Router Info, où il y a peu de contenu compressible, mais elle est très bénéfique pour les grandes Router Info avec plusieurs Router Addresses compressibles. La compression est recommandée si elle permet à une Router Info de tenir dans un seul paquet Session Confirmed sans fragmentation.

  • Taille maximale du premier ou unique fragment dans le message Session Confirmed : MTU - 113 pour IPv4 ou MTU - 133 pour IPv6. En supposant un MTU par défaut de 1500 octets, et aucun autre bloc dans le message, 1387 pour IPv4 ou 1367 pour IPv6. 97% des router infos actuels sont plus petits que 1367 sans compression gzip. 99,9% des router infos actuels sont plus petits que 1367 avec compression gzip. En supposant un MTU minimum de 1280 octets, et aucun autre bloc dans le message, 1167 pour IPv4 ou 1147 pour IPv6. 94% des router infos actuels sont plus petits que 1147 sans compression gzip. 97% des router infos actuels sont plus petits que 1147 avec compression gzip.

  • L’octet frag n’est maintenant plus utilisé, le bloc Router Info n’est jamais fragmenté. L’octet frag doit être défini sur fragment 0, total fragments 1. Voir la section Session Confirmed Fragmentation ci-dessus pour plus d’informations.

  • Le flooding ne doit pas être demandé à moins qu’il n’y ait des RouterAddresses publiées dans le RouterInfo. Le router de réception ne doit pas effectuer le flooding du RouterInfo à moins qu’il n’y ait des RouterAddresses publiées dans celui-ci.

  • Ce protocole ne fournit pas d’accusé de réception indiquant que le RouterInfo a été stocké ou diffusé. Si un accusé de réception est souhaité, et que le destinataire est floodfill, l’expéditeur devrait plutôt envoyer un DatabaseStoreMessage I2NP standard avec un jeton de réponse.

I2NP Message

Un message I2NP complet avec un en-tête modifié.

Cela utilise les mêmes 9 octets pour l’en-tête I2NP que dans NTCP2 (type, identifiant de message, expiration courte).

+----+----+----+----+----+----+----+----+
  | 3  |  size   |type|    msg id         |
  +----+----+----+----+----+----+----+----+
  |   short exp       |     message       |
  +----+----+----+----+                   +
  |                                       |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

  blk :: 3
  size :: 2 bytes, big endian, size of type + msg id + exp + message to follow
          I2NP message body size is (size - 9).
  type :: 1 byte, I2NP msg type, see I2NP spec
  msg id :: 4 bytes, big endian, I2NP message ID
  short exp :: 4 bytes, big endian, I2NP message expiration, Unix timestamp, unsigned seconds.
               Wraps around in 2106
  message :: I2NP message body

Notes :

  • Il s’agit du même format d’en-tête I2NP de 9 octets utilisé dans NTCP2.

  • Il s’agit exactement du même format que le bloc First Fragment, mais le type de bloc indique qu’il s’agit d’un message complet.

  • La taille maximale incluant l’en-tête I2NP de 9 octets est MTU - 63 pour IPv4 et MTU - 83 pour IPv6.

ChaCha20/Poly1305

Le premier fragment (fragment #0) d’un message I2NP avec un en-tête modifié.

Cela utilise les mêmes 9 octets pour l’en-tête I2NP que dans NTCP2 (type, identifiant de message, expiration courte).

Le nombre total de fragments n’est pas spécifié.

+----+----+----+----+----+----+----+----+
  | 4  |  size   |type|    msg id         |
  +----+----+----+----+----+----+----+----+
  |   short exp       |                   |
  +----+----+----+----+                   +
  |          partial message              |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

  blk :: 4
  size :: 2 bytes, big endian, size of data to follow
          Fragment size is (size - 9).
  type :: 1 byte, I2NP msg type, see I2NP spec
  msg id :: 4 bytes, big endian, I2NP message ID
  short exp :: 4 bytes, big endian, I2NP message expiration, Unix timestamp, unsigned seconds.
               Wraps around in 2106
  message :: Partial I2NP message body, bytes 0 - (size - 10)

Notes :

  • Il s’agit du même format d’en-tête I2NP de 9 octets utilisé dans NTCP2.

  • Il s’agit exactement du même format que le bloc de Message I2NP, mais le type de bloc indique qu’il s’agit du premier fragment d’un message.

  • La longueur du message partiel doit être supérieure à zéro.

  • Comme dans SSU 1, il est recommandé d’envoyer le dernier fragment en premier, afin que le destinataire connaisse le nombre total de fragments et puisse allouer efficacement les tampons de réception.

  • La taille maximale incluant l’en-tête I2NP de 9 octets est MTU - 63 pour IPv4 et MTU - 83 pour IPv6.

Notes

Un fragment supplémentaire (numéro de fragment supérieur à zéro) d’un message I2NP.

+----+----+----+----+----+----+----+----+
  | 5  |  size   |frag|    msg id         |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |          partial message              |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

  blk :: 5
  size :: 2 bytes, big endian, size of data to follow
          Fragment size is (size - 5).
  frag :: Fragment info:
          Bit order: 76543210 (bit 7 is MSB)
          bits 7-1: fragment number 1 - 127 (0 not allowed)
          bit 0: isLast (1 = true)
  msg id :: 4 bytes, big endian, I2NP message ID
  message :: Partial I2NP message body

Notes :

  • La longueur du message partiel doit être supérieure à zéro.

  • Comme dans SSU 1, il est recommandé d’envoyer le dernier fragment en premier, afin que le récepteur connaisse le nombre total de fragments et puisse allouer efficacement les tampons de réception.

  • Comme dans SSU 1, le numéro de fragment maximum est 127, mais la limite pratique est de 63 ou moins. Les implémentations peuvent limiter le maximum à ce qui est pratique pour une taille de message I2NP maximale d’environ 64 Ko, soit environ 55 fragments avec un MTU minimum de 1280. Voir la section Taille maximale des messages I2NP ci-dessous.

  • La taille maximale d’un message partiel (sans inclure les identifiants de fragment et de message) est MTU - 68 pour IPv4 et MTU - 88 pour IPv6.

Gestion des erreurs AEAD

Fermer la connexion. Ceci doit être le dernier bloc non-rembourré dans la charge utile.

+----+----+----+----+----+----+----+----+
  | 6  |  size   |    valid data packets  |
  +----+----+----+----+----+----+----+----+
      received   | rsn|     addl data     |
  +----+----+----+----+                   +
  ~               .   .   .               ~
  +----+----+----+----+----+----+----+----+

  blk :: 6
  size :: 2 bytes, big endian, value = 9 or more
  valid data packets received :: The number of valid packets received
                                (current receive nonce value)
                                0 if error occurs in handshake phase
                                8 bytes, big endian
  rsn :: reason, 1 byte:
         0: normal close or unspecified
         1: termination received
         2: idle timeout
         3: router shutdown
         4: data phase AEAD failure
         5: incompatible options
         6: incompatible signature type
         7: clock skew
         8: padding violation
         9: AEAD framing error
         10: payload format error
         11: Session Request error
         12: Session Created error
         13: Session Confirmed error
         14: Timeout
         15: RI signature verification fail
         16: s parameter missing, invalid, or mismatched in RouterInfo
         17: banned
         18: bad token
         19: connection limits
         20: incompatible version
         21: wrong net ID
         22: replaced by new session
  addl data :: optional, 0 or more bytes, for future expansion, debugging,
               or reason text.
               Format unspecified and may vary based on reason code.

Notes :

  • Toutes les raisons peuvent ne pas être réellement utilisées, cela dépend de l’implémentation. La plupart des échecs entraîneront généralement l’abandon du message, pas une terminaison. Voir les notes dans les sections des messages de handshake ci-dessus. Les raisons supplémentaires listées sont pour la cohérence, la journalisation, le débogage, ou si la politique change.
  • Il est recommandé qu’un bloc ACK soit inclus avec le bloc de Terminaison.
  • Dans la phase de données, pour toute raison autre que “termination received”, le pair devrait répondre avec un bloc de terminaison avec la raison “termination received”.

RelayRequest

Envoyé dans un message Data en session, d’Alice vers Bob. Voir la section Processus de relais ci-dessous.

+----+----+----+----+----+----+----+----+
  |  7 |  size   |flag|       nonce       |
  +----+----+----+----+----+----+----+----+
  |     relay tag     |     timestamp     |
  +----+----+----+----+----+----+----+----+
  | ver| asz|AlicePort|  Alice IP address |
  +----+----+----+----+----+----+----+----+
  |              signature                |
  +            length varies              +
  |         64 bytes for Ed25519          |
  ~                                       ~
  |                 . . .                 |
  +----+----+----+----+----+----+----+----+

  blk :: 7
  size :: 2 bytes, big endian, size of data to follow
  flag :: 1 byte flags, Unused, set to 0 for future compatibility

  The data below here is covered
  by the signature, and Bob forwards it unmodified.

  nonce :: 4 bytes, randomly generated by Alice
  relay tag :: 4 bytes, the itag from Charlie's RI
  timestamp :: Unix timestamp, unsigned seconds.
               Wraps around in 2106
  ver ::  1 byte SSU version to be used for the introduction:
         1: SSU 1
         2: SSU 2
  asz :: 1 byte endpoint (port + IP) size (6 or 18)
  AlicePort :: 2 byte Alice's port number, big endian
  Alice IP :: (asz - 2) byte representation of Alice's IP address,
              network byte order
  signature :: length varies, 64 bytes for Ed25519.
               Signature of prologue, Bob's hash,
               and signed data above, as signed by
               Alice.

Notes :

  • L’adresse IP est toujours incluse (contrairement à SSU 1) et peut être différente de l’IP utilisée pour la session.

Signature :

Alice signe la demande et l’inclut dans ce bloc ; Bob la transmet dans le bloc Relay Intro à Charlie. Algorithme de signature : Signer les données suivantes avec la clé de signature du router d’Alice :

  • prologue : 16 octets “RelayRequestData”, non terminé par null (non inclus dans le message)
  • bhash : hash de routeur de Bob sur 32 octets (non inclus dans le message)
  • chash : hash de routeur de Charlie sur 32 octets (non inclus dans le message)
  • nonce : nonce de 4 octets
  • relay tag : tag de relais de 4 octets
  • timestamp : timestamp de 4 octets (secondes)
  • ver : version SSU sur 1 octet
  • asz : taille du point de terminaison (port + IP) sur 1 octet (6 ou 18)
  • AlicePort : numéro de port d’Alice sur 2 octets
  • Alice IP : adresse IP d’Alice sur (asz - 2) octets

KDF pour la ChainKey initiale

Envoyé dans un message Data en session, de Charlie vers Bob ou de Bob vers Alice, ET dans le message Hole Punch de Charlie vers Alice. Voir la section Processus de Relais ci-dessous.

+----+----+----+----+----+----+----+----+
  |  8 |  size   |flag|code|    nonce
  +----+----+----+----+----+----+----+----+
       |     timestamp     | ver| csz|Char
  +----+----+----+----+----+----+----+----+
   Port|   Charlie IP addr |              |
  +----+----+----+----+----+              +
  |              signature                |
  +            length varies              +
  |         64 bytes for Ed25519          |
  ~                                       ~
  |                 . . .                 |
  +----+----+----+----+----+----+----+----+
  |                 Token                 |
  +----+----+----+----+----+----+----+----+

  blk :: 8
  size :: 2 bytes, 6
  flag :: 1 byte flags, Unused, set to 0 for future compatibility
  code :: 1 byte status code:
         0: accept
         1: rejected by Bob, reason unspecified
         2: rejected by Bob, Charlie is banned
         3: rejected by Bob, limit exceeded
         4: rejected by Bob, signature failure
         5: rejected by Bob, relay tag not found
         6: rejected by Bob, Alice RI not found
         7-63: other rejected by Bob codes TBD
         64: rejected by Charlie, reason unspecified
         65: rejected by Charlie, unsupported address
         66: rejected by Charlie, limit exceeded
         67: rejected by Charlie, signature failure
         68: rejected by Charlie, Alice is already connected
         69: rejected by Charlie, Alice is banned
         70: rejected by Charlie, Alice is unknown
         71-127: other rejected by Charlie codes TBD
         128: reject, source and reason unspecified
         129-255: other reject codes TBD

  The data below is covered by the signature if the code is 0 (accept).
  Bob forwards it unmodified.

  nonce :: 4 bytes, as received from Bob or Alice

  The data below is present only if the code is 0 (accept).

  timestamp :: Unix timestamp, unsigned seconds.
               Wraps around in 2106
  ver ::  1 byte SSU version to be used for the introduction:
         1: SSU 1
         2: SSU 2
  csz :: 1 byte endpoint (port + IP) size (0 or 6 or 18)
         may be 0 for some rejection codes
  CharliePort :: 2 byte Charlie's port number, big endian
                 not present if csz is 0
  Charlie IP :: (csz - 2) byte representation of Charlie's IP address,
                network byte order
                not present if csz is 0
  signature :: length varies, 64 bytes for Ed25519.
               Signature of prologue, Bob's hash,
               and signed data above, as signed by
               Charlie.
               Not present if rejected by Bob.
  token :: Token generated by Charlie for Alice to use
           in the Session Request.
           Only present if code is 0 (accept)

Notes :

Le token doit être utilisé immédiatement par Alice dans la Session Request.

Signature :

Si Charlie accepte (code de réponse 0) ou refuse (code de réponse 64 ou supérieur), Charlie signe la réponse et l’inclut dans ce bloc ; Bob la transmet dans le bloc Relay Response à Alice. Algorithme de signature : Signer les données suivantes avec la clé de signature du router de Charlie :

  • prologue : 16 octets “RelayAgreementOK”, non terminé par null (non inclus dans le message)
  • bhash : hash de routeur de Bob de 32 octets (non inclus dans le message)
  • nonce : nonce de 4 octets
  • timestamp : timestamp de 4 octets (secondes)
  • ver : version SSU de 1 octet
  • csz : taille du point de terminaison (port + IP) de 1 octet (0 ou 6 ou 18)
  • CharliePort : numéro de port de Charlie de 2 octets (absent si csz vaut 0)
  • Charlie IP : adresse IP de Charlie de (csz - 2) octets (absente si csz vaut 0)

Si Bob rejette (code de réponse 1-63), Bob signe la réponse et l’inclut dans ce bloc. Algorithme de signature : Signer les données suivantes avec la clé de signature du router de Bob :

  • prologue : 16 octets “RelayAgreementOK”, non terminé par null (non inclus dans le message)
  • bhash : Hachage de routeur de Bob sur 32 octets (non inclus dans le message)
  • nonce : nonce sur 4 octets
  • timestamp : horodatage sur 4 octets (secondes)
  • ver : version SSU sur 1 octet
  • csz : 1 octet = 0

KDF pour la demande de session

Envoyé dans un message Data en session, de Bob à Charlie. Voir la section Processus de relais ci-dessous.

Doit être précédé d’un bloc RouterInfo, ou d’un bloc de message I2NP DatabaseStore (ou fragment), contenant les Router Info d’Alice, soit dans la même charge utile (s’il y a de la place), soit dans un message précédent.

+----+----+----+----+----+----+----+----+
  |  9 |  size   |flag|                   |
  +----+----+----+----+                   +
  |                                       |
  +                                       +
  |         Alice Router Hash             |
  +             32 bytes                  +
  |                                       |
  +                   +----+----+----+----+
  |                   |      nonce        |
  +----+----+----+----+----+----+----+----+
  |     relay tag     |     timestamp     |
  +----+----+----+----+----+----+----+----+
  | ver| asz|AlicePort|  Alice IP address |
  +----+----+----+----+----+----+----+----+
  |              signature                |
  +            length varies              +
  |         64 bytes for Ed25519          |
  ~                                       ~
  |                 . . .                 |
  +----+----+----+----+----+----+----+----+

  blk :: 9
  size :: 2 bytes, big endian, size of data to follow
  flag :: 1 byte flags, Unused, set to 0 for future compatibility
  hash :: Alice's 32-byte router hash,

  The data below here is covered
  by the signature, as received from Alice in the Relay Request,
  and Bob forwards it unmodified.

  nonce :: 4 bytes, as received from Alice
  relay tag :: 4 bytes, the itag from Charlie's RI
  timestamp :: Unix timestamp, unsigned seconds.
               Wraps around in 2106
  ver ::  1 byte SSU version to be used for the introduction:
         1: SSU 1
         2: SSU 2
  asz :: 1 byte endpoint (port + IP) size (6 or 18)
  AlicePort :: 2 byte Alice's port number, big endian
  Alice IP :: (asz - 2) byte representation of Alice's IP address,
              network byte order
  signature :: length varies, 64 bytes for Ed25519.
               Signature of prologue, Bob's hash,
               and signed data above, as signed by
               Alice.

Notes :

  • Pour IPv4, l’adresse IP d’Alice fait toujours 4 octets, car Alice essaie de se connecter à Charlie via IPv4. IPv6 est pris en charge, et l’adresse IP d’Alice peut faire 16 octets.

  • Pour IPv4, ce message doit être envoyé via une connexion IPv4 établie, car c’est la seule façon pour Bob de connaître l’adresse IPv4 de Charlie à retourner à Alice dans le RelayResponse_. IPv6 est pris en charge, et ce message peut être envoyé via une connexion IPv6 établie.

  • Toute adresse SSU publiée avec des introducers doit contenir “4” ou “6” dans l’option “caps”.

Signature :

Alice signe la demande et Bob la transmet dans ce bloc à Charlie. Algorithme de vérification : Vérifier les données suivantes avec la clé de signature du router d’Alice :

  • prologue : 16 octets “RelayRequestData”, non terminé par null (non inclus dans le message)
  • bhash : hash de routeur de Bob sur 32 octets (non inclus dans le message)
  • chash : hash de routeur de Charlie sur 32 octets (non inclus dans le message)
  • nonce : nonce sur 4 octets
  • relay tag : tag de relais sur 4 octets
  • timestamp : horodatage sur 4 octets (secondes)
  • ver : version SSU sur 1 octet
  • asz : taille du point de terminaison (port + IP) sur 1 octet (6 ou 18)
  • AlicePort : numéro de port d’Alice sur 2 octets
  • Alice IP : adresse IP d’Alice sur (asz - 2) octets

PeerTest

Envoyé soit dans un message Data en session, ou un message Peer Test hors session. Voir la section Processus de test des pairs ci-dessous.

Pour le message 2, doit être précédé d’un bloc RouterInfo, ou d’un bloc de message I2NP DatabaseStore (ou fragment), contenant les informations du routeur d’Alice, soit dans la même charge utile (s’il y a de la place), soit dans un message précédent.

Pour le message 4, si le relais est accepté (code de raison 0), il doit être précédé d’un bloc RouterInfo, ou d’un bloc de message I2NP DatabaseStore (ou fragment), contenant les informations du routeur de Charlie, soit dans la même charge utile (s’il y a de la place), soit dans un message précédent.

+----+----+----+----+----+----+----+----+
  | 10 |  size   | msg|code|flag|         |
  +----+----+----+----+----+----+         +
  | Alice router hash (message 2 only)    |
  +             or                        +
  | Charlie router hash (message 4 only)  |
  + or all zeros if rejected by Bob       +
  | Not present in messages 1,3,5,6,7     |
  +                             +----+----+
  |                             | ver|
  +----+----+----+----+----+----+----+----+
     nonce       |     timestamp     | asz|
  +----+----+----+----+----+----+----+----+
  |AlicePort|  Alice IP address |         |
  +----+----+----+----+----+----+         +
  |              signature                |
  +            length varies              +
  |         64 bytes for Ed25519          |
  ~                                       ~
  |                 . . .                 |
  +----+----+----+----+----+----+----+----+

  blk :: 10
  size :: 2 bytes, big endian, size of data to follow
  msg :: 1 byte message number 1-7
  code :: 1 byte status code:
         0: accept
         1: rejected by Bob, reason unspecified
         2: rejected by Bob, no Charlie available
         3: rejected by Bob, limit exceeded
         4: rejected by Bob, signature failure
         5: rejected by Bob, address unsupported
         6-63: other rejected by Bob codes TBD
         64: rejected by Charlie, reason unspecified
         65: rejected by Charlie, unsupported address
         66: rejected by Charlie, limit exceeded
         67: rejected by Charlie, signature failure
         68: rejected by Charlie, Alice is already connected
         69: rejected by Charlie, Alice is banned
         70: rejected by Charlie, Alice is unknown
         70-127: other rejected by Charlie codes TBD
         128: reject, source and reason unspecified
         129-255: other reject codes TBD
         reject codes only allowed in messages 3 and 4
  flag :: 1 byte flags, Unused, set to 0 for future compatibility
  hash :: Alice's or Charlie's 32-byte router hash,
          only present in messages 2 and 4.
          All zeros (fake hash) in message 4 if rejected by Bob.

  For messages 1-4, the data below here is covered
  by the signature, if present, and Bob forwards it unmodified.

  ver :: 1 byte SSU version:
         1: SSU 1 (not supported)
         2: SSU 2 (required)
  nonce :: 4 byte test nonce, big endian
  timestamp :: Unix timestamp, unsigned seconds.
               Wraps around in 2106
  asz :: 1 byte endpoint (port + IP) size (6 or 18)
  AlicePort :: 2 byte Alice's port number, big endian
  Alice IP :: (asz - 2) byte representation of Alice's IP address,
              network byte order
  signature :: length varies, 64 bytes for Ed25519.
               Signature of prologue, Bob's hash,
               and signed data above, as signed by
               Alice or Charlie.
               Only present for messages 1-4.
               Optional in message 5-7.

Notes :

  • Contrairement à SSU 1, le message 1 doit inclure l’adresse IP et le port d’Alice.

  • Les tests d’adresses IPv6 sont pris en charge, et la communication Alice-Bob et Alice-Charlie peut se faire via IPv6, si Bob et Charlie indiquent leur support avec une capacité ‘B’ dans leur adresse IPv6 publiée. Voir la Proposition 126 pour plus de détails.

Alice envoie la requête à Bob en utilisant une session existante sur le transport (IPv4 ou IPv6) qu’elle souhaite tester. Lorsque Bob reçoit une requête d’Alice via IPv4, Bob doit sélectionner un Charlie qui annonce une adresse IPv4. Lorsque Bob reçoit une requête d’Alice via IPv6, Bob doit sélectionner un Charlie qui annonce une adresse IPv6. La communication réelle entre Bob et Charlie peut se faire via IPv4 ou IPv6 (c’est-à-dire, indépendamment du type d’adresse d’Alice).

  • Les messages 1-4 doivent être contenus dans un message Data dans une session existante.

  • Bob doit envoyer le RI d’Alice à Charlie avant d’envoyer le message 2.

  • Bob doit envoyer le RI de Charlie à Alice avant d’envoyer le message 4, si accepté (code de raison 0).

  • Les messages 5-7 doivent être contenus dans un message Peer Test hors session.

  • Les messages 5 et 7 peuvent contenir les mêmes données signées que celles envoyées dans les messages 3 et 4, ou elles peuvent être régénérées avec un nouvel horodatage. La signature est optionnelle.

  • Le message 6 peut contenir les mêmes données signées que celles envoyées dans les messages 1 et 2, ou il peut être régénéré avec un nouvel horodatage. La signature est optionnelle.

Signatures :

Alice signe la demande et l’inclut dans le message 1 ; Bob la transmet dans le message 2 à Charlie. Charlie signe la réponse et l’inclut dans le message 3 ; Bob la transmet dans le message 4 à Alice. Algorithme de signature : Signer ou vérifier les données suivantes avec la clé de signature d’Alice ou de Charlie :

  • prologue : 16 octets “PeerTestValidate”, non terminé par null (non inclus dans le message)
  • bhash : Hachage du routeur de Bob de 32 octets (non inclus dans le message)
  • ahash : Hachage du routeur d’Alice de 32 octets (Utilisé uniquement dans la signature pour les messages 3 et 4 ; non inclus dans le message 3 ou 4)
  • ver : 1 octet version SSU
  • nonce : 4 octets nonce de test
  • timestamp : 4 octets horodatage (secondes)
  • asz : 1 octet taille du point de terminaison (port + IP) (6 ou 18)
  • AlicePort : 2 octets numéro de port d’Alice
  • Alice IP : (asz - 2) octets adresse IP d’Alice

Charge utile

À FAIRE uniquement si nous effectuons une rotation des clés

+----+----+----+----+----+----+----+----+
  | 11 |  size   |      TBD               |
  +----+----+----+                        +
  |                                       |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

  blk :: 11
  size :: 2 bytes, big endian, size of data to follow

Notes

4 octets d’accusé de réception transmis, suivis d’un compteur d’accusés de réception et de zéro ou plusieurs plages nack/ack.

Cette conception est adaptée et simplifiée de QUIC. Les objectifs de conception sont les suivants :

  • Nous voulons encoder efficacement un “bitfield”, qui est une séquence de bits représentant les paquets accusés de réception.
  • Le bitfield est principalement composé de 1. Les 1 et les 0 viennent généralement par “groupes” séquentiels.
  • La quantité d’espace disponible dans le paquet pour les accusés de réception varie.
  • Le bit le plus important est celui avec le numéro le plus élevé. Ceux avec des numéros plus bas sont moins importants. En dessous d’une certaine distance du bit le plus élevé, les bits les plus anciens seront “oubliés” et ne seront plus jamais envoyés.

L’encodage spécifié ci-dessous accomplit ces objectifs de conception, en envoyant le numéro du bit le plus élevé qui est défini à 1, ainsi que des bits consécutifs supplémentaires inférieurs à celui-ci qui sont également définis à 1. Après cela, s’il y a de la place, une ou plusieurs “plages” spécifiant le nombre de bits consécutifs à 0 et de bits consécutifs à 1 inférieurs à cela. Voir QUIC RFC 9000 section 13.2.3 pour plus de contexte.

+----+----+----+----+----+----+----+----+
  | 12 |  size   |    Ack Through    |acnt|
  +----+----+----+----+----+----+----+----+
  |  range  |  range  |     .   .   .     |
  +----+----+----+----+                   +
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

  blk :: 12
  size :: 2 bytes, big endian, size of data to follow,
          5 minimum
  ack through :: highest packet number acked
  acnt :: number of acks lower than ack through also acked,
          0-255
  range :: If present,
           1 byte nack count followed by 1 byte ack count,
           0-255 each

Exemples :

Nous voulons ACK uniquement le paquet 10 :

  • Ack Through : 10
  • acnt : 0
  • aucune plage n’est incluse

Nous voulons ACK les paquets 8-10 seulement :

  • Ack Through : 10
  • acnt : 2
  • aucune plage n’est incluse

Nous voulons ACK 10 9 8 6 5 2 1 0, et NACK 7 4 3. L’encodage du bloc ACK est :

  • Ack Through: 10
  • acnt: 2 (ack 9 8)
  • range: 1 2 (nack 7, ack 6 5)
  • range: 2 3 (nack 4 3, ack 2 1 0)

Notes :

  • Les plages peuvent ne pas être présentes. Le nombre maximum de plages n’est pas spécifié, il peut y en avoir autant que le paquet peut en contenir.
  • Range nack peut être zéro si on acquitte plus de 255 paquets consécutifs.
  • Range ack peut être zéro si on refuse plus de 255 paquets consécutifs.
  • Range nack et ack ne peuvent pas être tous les deux zéro.
  • Après la dernière plage, les paquets ne sont ni acquittés ni refusés. La longueur du bloc d’acquittement et la façon dont les anciens acks/nacks sont gérés dépend de l’expéditeur du bloc d’acquittement. Voir les sections d’acquittement ci-dessous pour discussion.
  • L’ack through devrait être le numéro de paquet le plus élevé reçu, et tous les paquets supérieurs n’ont pas été reçus. Cependant, dans des situations limitées, il pourrait être plus bas, comme acquitter un seul paquet qui “comble un trou”, ou une implémentation simplifiée qui ne maintient pas l’état de tous les paquets reçus. Au-dessus du plus haut reçu, les paquets ne sont ni acquittés ni refusés, mais après plusieurs blocs d’acquittement, il peut être approprié de passer en mode de retransmission rapide.
  • Ce format est une version simplifiée de celui de QUIC. Il est conçu pour encoder efficacement un grand nombre d’ACKs, ainsi que des rafales de NACKs.
  • Les blocs ACK sont utilisés pour acquitter les paquets de phase de données. Ils ne doivent être inclus que pour les paquets de phase de données en session.

Address

Port sur 2 octets et adresse IP sur 4 ou 16 octets. Adresse d’Alice, envoyée à Alice par Bob, ou adresse de Bob, envoyée à Bob par Alice.

+----+----+----+----+----+----+----+----+
  | 13 | 6 or 18 |   Port  | IP Address    
  +----+----+----+----+----+----+----+----+
       |
  +----+

  blk :: 13
  size :: 2 bytes, big endian, 6 or 18
  port :: 2 bytes, big endian
  ip :: 4 byte IPv4 or 16 byte IPv6 address,
        big endian (network byte order)

Relay Tag Request

Ceci peut être envoyé par Alice dans un message Session Request, Session Confirmed, ou Data. Non pris en charge dans le message Session Created, car Bob n’a pas encore le RI d’Alice, et ne sait pas si Alice prend en charge le relais. De plus, si Bob reçoit une connexion entrante, il n’a probablement pas besoin d’introducers (sauf peut-être pour l’autre type ipv4/ipv6).

Lorsqu’envoyé dans la Session Request, Bob peut répondre avec un Relay Tag dans le message Session Created, ou peut choisir d’attendre de recevoir le RouterInfo d’Alice dans la Session Confirmed pour valider l’identité d’Alice avant de répondre dans un message Data. Si Bob ne souhaite pas relayer pour Alice, il n’envoie pas de bloc Relay Tag.

+----+----+----+
  | 15 |    0    |
  +----+----+----+

  blk :: 15
  size :: 2 bytes, big endian, value = 0

Charge utile

Ceci peut être envoyé par Bob dans un message Session Confirmed ou Data, en réponse à une Relay Tag Request d’Alice.

Lorsque la Relay Tag Request est envoyée dans le Session Request, Bob peut répondre avec un Relay Tag dans le message Session Created, ou peut choisir d’attendre de recevoir le RouterInfo d’Alice dans le Session Confirmed pour valider l’identité d’Alice avant de répondre dans un message Data. Si Bob ne souhaite pas faire de relais pour Alice, il n’envoie pas de bloc Relay Tag.

+----+----+----+----+----+----+----+
  | 16 |    4    |    relay tag      |
  +----+----+----+----+----+----+----+

  blk :: 16
  size :: 2 bytes, big endian, value = 4
  relay tag :: 4 bytes, big endian, nonzero

Notes

Pour une connexion ultérieure. Généralement inclus dans les messages Session Created et Session Confirmed. Peut également être envoyé à nouveau dans le message Data d’une session de longue durée si le token précédent expire.

+----+----+----+----+----+----+----+----+
  | 17 |   12    |     expires       |
  +----+----+----+----+----+----+----+----+
                  token              |
  +----+----+----+----+----+----+----+

  blk :: 17
  size :: 2 bytes, big endian, value = 12
  expires :: Unix timestamp, unsigned seconds.
             Wraps around in 2106
  token :: 8 bytes, big endian

Problèmes

Un Ping avec des données arbitraires à retourner dans une Path Response, utilisé comme keep-alive ou pour valider un changement d’IP/Port.

+----+----+----+----+----+----+----+----+
  | 18 |  size   |    Arbitrary Data      |
  +----+----+----+                        +
  |                                       |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

  blk :: 18
  size :: 2 bytes, big endian, size of data to follow
  data :: Arbitrary data to be returned in a Path Response
          length as selected by sender

Notes :

Une taille de données minimale de 8 octets, contenant des données aléatoires, est recommandée mais non obligatoire.

Path Response

Un Pong avec les données reçues dans le Path Challenge, en réponse au Path Challenge, utilisé comme keep-alive ou pour valider un changement d’IP/Port.

+----+----+----+----+----+----+----+----+
  | 19 |  size   |                        |
  +----+----+----+                        +
  |    Data received in Path Challenge    |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

  blk :: 19
  size :: 2 bytes, big endian, size of data to follow
  data :: As received in a Path Challenge

First Packet Number

Inclus optionnellement dans la négociation dans chaque direction, pour spécifier le premier numéro de paquet qui sera envoyé. Ceci fournit plus de sécurité pour le chiffrement d’en-tête, similaire à TCP.

Pas entièrement spécifié, pas actuellement pris en charge.

+----+----+----+----+----+----+----+
  | 20 |  size   |  First pkt number |
  +----+----+----+----+----+----+----+

  blk :: 20
  size :: 4
  pkt num :: The first packet number to be sent in the data phase

Congestion

Ce bloc est conçu pour être une méthode extensible d’échange d’informations de contrôle de congestion. Le contrôle de congestion peut être complexe et peut évoluer à mesure que nous acquérons plus d’expérience avec le protocole lors des tests en conditions réelles, ou après le déploiement complet.

Cela maintient toute information de congestion hors des blocs I2NP, First Fragment, Followon Fragment et ACK à forte utilisation, où aucun espace n’est alloué pour les flags. Bien qu’il y ait trois octets de flags inutilisés dans l’en-tête du paquet Data, cela fournit également un espace limité pour l’extensibilité et une protection de chiffrement plus faible.

Bien qu’il soit quelque peu gaspilleur d’utiliser un bloc de 4 octets pour deux bits d’information, en plaçant ceci dans un bloc séparé, nous pouvons facilement l’étendre avec des données supplémentaires telles que les tailles de fenêtre actuelles, le RTT mesuré, ou d’autres drapeaux. L’expérience a montré que les bits de drapeau seuls sont souvent insuffisants et malcommodes pour l’implémentation de schémas avancés de contrôle de congestion. Essayer d’ajouter le support de toute fonctionnalité possible de contrôle de congestion dans, par exemple, le bloc ACK, gaspillerait de l’espace et ajouterait de la complexité à l’analyse de ce bloc.

Les implémentations ne doivent pas présumer que l’autre router prend en charge un bit de flag particulier ou une fonctionnalité incluse ici, sauf si l’implémentation est requise par une version future de cette spécification.

Ce bloc devrait probablement être le dernier bloc non-padding dans le payload.

+----+----+----+----+
  | 21 |  size   |flag|
  +----+----+----+----+

  blk :: 21
  size :: 1 (or more if extended)
  flag :: 1 byte flags
         bit order: 76543210 (bit 7 is MSB)
         bit 0: 1 to request immediate ack
         bit 1: 1 for explicit congestion notification (ECN)
         bits 7-2: Unused, set to 0 for future compatibility

Payload

Ceci est pour le bourrage à l’intérieur des charges utiles AEAD. Le bourrage pour tous les messages se trouve à l’intérieur des charges utiles AEAD.

Le padding devrait approximativement respecter les paramètres négociés. Bob a envoyé ses paramètres tx/rx min/max demandés dans Session Created. Alice a envoyé ses paramètres tx/rx min/max demandés dans Session Confirmed. Des options mises à jour peuvent être envoyées pendant la phase de données. Voir les informations du bloc d’options ci-dessus.

Si présent, ce bloc doit être le dernier dans la charge utile.

+----+----+----+----+----+----+----+----+
  |254 |  size   |      padding           |
  +----+----+----+                        +
  |                                       |
  ~               .   .   .               ~
  |                                       |
  +----+----+----+----+----+----+----+----+

  blk :: 254
  size :: 2 bytes, big endian, size of padding to follow
  padding :: random data

Notes :

  • Size = 0 est autorisé.

  • Stratégies de padding à déterminer.

  • Padding minimum à déterminer.

  • Les payloads composés uniquement de padding sont autorisés.

  • Valeurs par défaut du padding à déterminer.

  • Voir le bloc d’options pour la négociation des paramètres de padding

  • Voir le bloc d’options pour les paramètres de padding min/max

  • Ne pas dépasser le MTU. Si plus de padding est nécessaire, envoyer plusieurs messages.

  • La réponse du router en cas de violation du padding négocié dépend de l’implémentation.

  • La longueur du padding doit être déterminée soit au cas par cas pour chaque message avec des estimations de la distribution de longueur, soit des délais aléatoires doivent être ajoutés. Ces contre-mesures doivent être incluses pour résister à la DPI, car les tailles de messages révéleraient sinon que le trafic I2P est transporté par le protocole de transport. Le schéma exact de padding constitue un domaine de travail futur, l’Annexe A de NTCP2 fournit plus d’informations sur le sujet.

Replay Prevention

SSU2 est conçu pour minimiser l’impact des messages rejoués par un attaquant.

Les messages Token Request, Retry, Session Request, Session Created, Hole Punch, et Peer Test hors session doivent contenir des blocs DateTime.

Alice et Bob valident tous deux que l’horodatage de ces messages se trouve dans une dérive valide (recommandé +/- 2 minutes). Pour la “résistance au sondage”, Bob ne devrait pas répondre aux messages Token Request ou Session Request si la dérive est invalide, car ces messages peuvent être une attaque par rejeu ou de sondage.

Bob peut choisir de rejeter les messages Token Request et Retry dupliqués, même si le décalage est valide, via un filtre de Bloom ou un autre mécanisme. Cependant, la taille et le coût CPU pour répondre à ces messages sont faibles. Dans le pire des cas, un message Token Request rejoué peut invalider un token précédemment envoyé.

Le système de jetons réduit considérablement l’impact des messages Session Request rejoués. Étant donné que les jetons ne peuvent être utilisés qu’une seule fois, un message Session Request rejoué n’aura jamais de jeton valide. Bob peut choisir de rejeter les messages Session Request dupliqués, même si le décalage est valide, via un filtre de Bloom ou un autre mécanisme. Cependant, la taille et le coût CPU de répondre avec un message Retry sont faibles. Au pire, l’envoi d’un message Retry peut invalider un jeton précédemment envoyé.

Les messages Session Created et Session Confirmed dupliqués ne valideront pas car l’état de la négociation Noise ne sera pas dans l’état correct pour les déchiffrer. Dans le pire des cas, un pair peut retransmettre un Session Confirmed en réponse à un Session Created apparemment dupliqué.

Les messages Hole Punch et Peer Test rejoués devraient avoir peu ou pas d’impact.

Les routeurs doivent utiliser le numéro de paquet du message de données pour détecter et supprimer les messages de phase de données dupliqués. Chaque numéro de paquet ne doit être utilisé qu’une seule fois. Les messages rejoués doivent être ignorés.

Handshake Retransmission

Session Request

Si aucun Session Created ou Retry n’est reçu par Alice :

Maintenir les mêmes ID de source et de connexion, clé éphémère, et numéro de paquet 0. Ou, simplement conserver et retransmettre le même paquet chiffré. Le numéro de paquet ne doit pas être incrémenté, car cela changerait la valeur de hachage chaîné utilisée pour chiffrer le message Session Created.

Intervalles de retransmission recommandés : 1,25, 2,5 et 5 secondes (1,25, 3,75 et 8,75 secondes après le premier envoi). Délai d’expiration recommandé : 15 secondes au total

Session Created

Si aucun Session Confirmed n’est reçu par Bob :

Conservez les mêmes identifiants source et de connexion, la clé éphémère, et le numéro de paquet 0. Ou, conservez simplement le paquet chiffré. Le numéro de paquet ne doit pas être incrémenté, car cela changerait la valeur de hachage chaîné utilisée pour chiffrer le message Session Confirmed.

Intervalles de retransmission recommandés : 1, 2 et 4 secondes (1, 3 et 7 secondes après le premier envoi). Délai d’expiration recommandé : 12 secondes au total

Session Confirmed

Dans SSU 1, Alice ne passe pas à la phase de données tant que le premier paquet de données n’est pas reçu de Bob. Cela fait de SSU 1 une configuration à deux allers-retours.

Pour SSU 2, intervalles de retransmission Session Confirmed recommandés : 1,25, 2,5, et 5 secondes (1,25, 3,75, et 8,75 secondes après le premier envoi).

Il existe plusieurs alternatives. Toutes sont à 1 RTT :

  1. Alice suppose que Session Confirmed a été reçu, envoie les messages de données immédiatement, ne retransmet jamais Session Confirmed. Les paquets de données reçus dans le désordre (avant Session Confirmed) seront indéchiffrables, mais seront retransmis. Si Session Confirmed est perdu, tous les messages de données envoyés seront abandonnés.

  2. Comme en 1), envoyer les messages de données immédiatement, mais aussi retransmettre Session Confirmed jusqu’à ce qu’un message de données soit reçu.

  3. Nous pourrions utiliser IK au lieu de XK, car il n’a que deux messages dans le handshake, mais il utilise un DH supplémentaire (4 au lieu de 3).

L’implémentation recommandée est l’option 2). Alice doit conserver les informations nécessaires pour retransmettre le message Session Confirmed. Alice devrait également retransmettre tous les messages Data après que le message Session Confirmed soit retransmis.

Lors de la retransmission de Session Confirmed, maintenir les mêmes ID de source et de connexion, clé éphémère, et numéro de paquet 1. Ou, simplement conserver le paquet chiffré. Le numéro de paquet ne doit pas être incrémenté, car cela changerait la valeur de hachage chaînée qui est une entrée pour la fonction split().

Bob peut conserver (mettre en file d’attente) les messages de données reçus avant le message Session Confirmed. Ni les clés de protection d’en-tête ni les clés de déchiffrement ne sont disponibles avant que le message Session Confirmed soit reçu, donc Bob ne sait pas qu’il s’agit de messages de données, mais cela peut être présumé. Après réception du message Session Confirmed, Bob est capable de déchiffrer et traiter les messages de données mis en file d’attente. Si cela est trop complexe, Bob peut simplement supprimer les messages de données non déchiffrables, car Alice les retransmettra.

Note : Si les paquets de session confirmée sont perdus, Bob retransmettra la session créée. L’en-tête de session créée ne sera pas déchiffrable avec la clé d’introduction d’Alice, car elle est définie avec la clé d’introduction de Bob (sauf si un déchiffrement de repli est effectué avec la clé d’introduction de Bob). Bob peut immédiatement retransmettre les paquets de session confirmée s’ils n’ont pas été précédemment acquittés, et qu’un paquet non déchiffrable est reçu.

Token Request

Si aucun Retry n’est reçu par Alice :

Maintenir les mêmes ID source et de connexion. Une implémentation peut générer un nouveau numéro de paquet aléatoire et chiffrer un nouveau paquet ; ou elle peut réutiliser le même numéro de paquet ou simplement conserver et retransmettre le même paquet chiffré. Le numéro de paquet ne doit pas être incrémenté, car cela changerait la valeur de hachage chaîné utilisée pour chiffrer le message Session Created.

Intervalles de retransmission recommandés : 3 et 6 secondes (3 et 9 secondes après le premier envoi). Délai d’expiration recommandé : 15 secondes au total

Retry

Si aucune demande de session n’est reçue par Bob :

Un message Retry n’est pas retransmis en cas de timeout, pour réduire les impacts des adresses sources usurpées.

Cependant, un message Retry peut être retransmis en réponse à un message Session Request répété reçu avec le token original (invalide), ou en réponse à un message Token Request répété. Dans les deux cas, cela indique que le message Retry a été perdu.

Si un second message Session Request est reçu avec un token différent mais toujours invalide, abandonner la session en attente et ne pas répondre.

Si on renvoie le message Retry : Maintenir les mêmes ID de source et de connexion ainsi que le token. Une implémentation peut générer un nouveau numéro de paquet aléatoire et chiffrer un nouveau paquet ; ou elle peut réutiliser le même numéro de paquet ou simplement conserver et retransmettre le même paquet chiffré.

Total Timeout

Le timeout total recommandé pour le handshake est de 20 secondes.

Duplicates and Error Handling

Les doublons des trois messages de négociation Noise Session Request, Session Created et Session Confirmed doivent être détectés avant MixHash() de l’en-tête. Bien que le traitement Noise AEAD échouera vraisemblablement par la suite, le hash de négociation serait déjà corrompu.

Si l’un des trois messages est corrompu et échoue à l’AEAD, le handshake ne peut pas être récupéré par la suite même avec une retransmission, car MixHash() a déjà été appelé sur le message corrompu.

Tokens

Le Token dans l’en-tête Session Request est utilisé pour l’atténuation des attaques DoS, pour empêcher l’usurpation d’adresse source, et comme résistance aux attaques par rejeu.

Si Bob n’accepte pas le token dans le message Session Request, Bob ne décrypte PAS le message, car cela nécessite une opération DH coûteuse. Bob envoie simplement un message Retry avec un nouveau token.

Si un message de demande de session subséquent est alors reçu avec ce token, Bob procède au déchiffrement de ce message et continue avec la négociation.

Le jeton doit être une valeur de 8 octets générée aléatoirement, si le générateur du jeton stocke les valeurs et l’IP et le port associés (en mémoire ou de manière persistante). Le générateur ne doit pas générer une valeur opaque, par exemple, en utilisant le SipHash (avec une graine secrète K0, K1) de l’IP, du port, et de l’heure ou du jour actuel, pour créer des jetons qui n’ont pas besoin d’être sauvegardés en mémoire, car cette méthode rend difficile le rejet des jetons réutilisés et les attaques par rejeu.

Les jetons ne peuvent être utilisés qu’une seule fois. Un jeton envoyé de Bob à Alice dans un message Retry doit être utilisé immédiatement et expire en quelques secondes. Un jeton envoyé dans un bloc New Token dans une session établie peut être utilisé dans une connexion ultérieure, et il expire au moment spécifié dans ce bloc. L’expiration est spécifiée par l’expéditeur ; les valeurs recommandées sont d’une heure minimum, plusieurs heures maximum.

Si l’IP ou le port d’un router change, il doit supprimer tous les tokens sauvegardés (entrants et sortants) pour l’ancienne IP ou le port, car ils ne sont plus valides. Les tokens peuvent éventuellement être persistés lors des redémarrages du router, selon l’implémentation. L’acceptation d’un token non expiré n’est pas garantie ; si Bob a oublié ou supprimé ses tokens sauvegardés, il enverra un Retry à Alice. Un router peut choisir de limiter le stockage des tokens, et supprimer les tokens stockés les plus anciens même s’ils n’ont pas expiré.

Les blocs New Token peuvent être envoyés d’Alice vers Bob ou de Bob vers Alice. Ils seraient généralement envoyés une fois, pendant ou peu après l’établissement de la session. Le token peut être renvoyé avant ou après expiration avec un nouveau délai d’expiration, ou un nouveau token peut être envoyé. Les routers doivent supposer que seul le dernier token reçu est valide ; il n’y a aucune exigence de stocker plusieurs tokens entrants ou sortants pour la même IP/port.

Un token est lié à la combinaison IP/port source et IP/port destination. Un token reçu sur IPv4 ne peut pas être utilisé pour IPv6 ou vice versa.

Si l’un des pairs migre vers une nouvelle IP ou un nouveau port pendant la session (voir la section Migration de Connexion), tous les tokens précédemment échangés sont invalidés, et de nouveaux tokens doivent être échangés.

Les implémentations peuvent, mais ne sont pas tenues de, sauvegarder les tokens sur le disque et les recharger au redémarrage. Si ils sont persistés, l’implémentation doit s’assurer que l’IP et le port n’ont pas changé depuis l’arrêt avant de les recharger.

I2NP Message Fragmentation

Différences par rapport à SSU 1

Note : Comme dans SSU 1, le fragment initial ne contient pas d’informations sur le nombre total de fragments ou la longueur totale. Les fragments suivants ne contiennent pas d’informations sur leur décalage. Cela offre à l’expéditeur la flexibilité de fragmenter “à la volée” en fonction de l’espace disponible dans le paquet. (Java I2P ne fait pas cela ; il “pré-fragmente” avant que le premier fragment soit envoyé) Cependant, cela impose au destinataire de stocker les fragments reçus dans le désordre et de retarder le réassemblage jusqu’à ce que tous les fragments soient reçus.

Comme dans SSU 1, toute retransmission de fragments doit préserver la longueur (et le décalage implicite) de la transmission précédente du fragment.

SSU 2 sépare bien les trois cas (message complet, fragment initial et fragment de suivi) en trois types de blocs différents, pour améliorer l’efficacité de traitement.

I2NP Message Duplication

Ce protocole ne prévient PAS complètement la livraison en double des messages I2NP. Les doublons au niveau IP ou les attaques par rejeu seront détectés au niveau de la couche SSU2, car chaque numéro de paquet ne peut être utilisé qu’une seule fois.

Lorsque les messages I2NP ou les fragments sont retransmis dans de nouveaux paquets, cependant, cela n’est pas détectable au niveau de la couche SSU2. Le routeur devrait appliquer l’expiration I2NP (à la fois trop ancien et trop loin dans le futur) et utiliser un filtre de Bloom ou un autre mécanisme basé sur l’ID du message I2NP.

Des mécanismes supplémentaires peuvent être utilisés par le router, ou dans l’implémentation SSU2, pour détecter les doublons. Par exemple, SSU2 pourrait maintenir un cache des identifiants de messages reçus récemment. Ceci dépend de l’implémentation.

Congestion Control

Cette proposition spécifie le protocole pour la numérotation des paquets et les blocs ACK. Cela fournit suffisamment d’informations en temps réel pour qu’un transmetteur puisse implémenter un algorithme de contrôle de congestion efficace et réactif, tout en permettant la flexibilité et l’innovation dans cette implémentation. Cette section discute des objectifs d’implémentation et fournit des suggestions. Des conseils généraux peuvent être trouvés dans RFC 9002. Voir également RFC 6298 pour des conseils sur les minuteries de retransmission.

Les paquets de données ACK uniquement ne devraient pas être comptabilisés dans les octets ou paquets en transit et ne sont pas soumis au contrôle de congestion. Contrairement à TCP, SSU2 peut détecter la perte de ces paquets et cette information peut être utilisée pour ajuster l’état de congestion. Cependant, ce document ne spécifie pas de mécanisme pour le faire.

Les paquets contenant d’autres blocs non-data peuvent également être exclus du contrôle de congestion si souhaité, selon l’implémentation. Par exemple :

  • Test de pair
  • Demande/intro/réponse de relais
  • Défi/réponse de chemin

Il est recommandé que le contrôle de congestion soit basé sur le nombre d’octets, non sur le nombre de paquets, en suivant les directives des RFC TCP et QUIC RFC 9002. Une limite supplémentaire du nombre de paquets peut également être utile pour empêcher le débordement de tampon dans le noyau ou dans les middleboxes, selon l’implémentation, bien que cela puisse ajouter une complexité significative. Si la sortie de paquets par session et/ou totale est limitée en bande passante et/ou cadencée, cela peut atténuer le besoin de limitation du nombre de paquets.

Packet Numbers

Dans SSU 1, les ACK et NACK contenaient des numéros de messages I2NP et des masques de bits de fragments. Les transmetteurs suivaient le statut ACK des messages sortants (et leurs fragments) et retransmettaient les fragments selon les besoins.

Dans SSU 2, les ACKs et NACKs contiennent des numéros de paquets. Les transmetteurs doivent maintenir une structure de données avec un mappage des numéros de paquets vers leur contenu. Lorsqu’un paquet est ACKé ou NACKé, le transmetteur doit déterminer quels messages I2NP et fragments étaient dans ce paquet, pour décider quoi retransmettre.

Session Confirmed ACK

Bob envoie un ACK du paquet 0, qui accuse réception du message Session Confirmed et permet à Alice de passer à la phase de données, et de supprimer le volumineux message Session Confirmed sauvegardé pour une éventuelle retransmission. Ceci remplace le DeliveryStatusMessage envoyé par Bob dans SSU 1.

Bob devrait envoyer un ACK dès que possible après avoir reçu le message Session Confirmed. Un petit délai (pas plus de 50 ms) est acceptable, car au moins un message Data devrait arriver presque immédiatement après le message Session Confirmed, de sorte que l’ACK puisse acquitter à la fois le message Session Confirmed et le message Data. Cela empêchera Bob d’avoir à retransmettre le message Session Confirmed.

Generating ACKs

Définition : Paquets déclencheurs d’ACK : Les paquets qui contiennent des blocs déclencheurs d’ack provoquent un ACK du récepteur dans le délai maximal d’accusé de réception et sont appelés paquets déclencheurs d’ack.

Les routers accusent réception de tous les paquets qu’ils reçoivent et traitent. Cependant, seuls les paquets nécessitant un accusé de réception provoquent l’envoi d’un bloc ACK dans le délai maximum d’accusé de réception. Les paquets qui ne nécessitent pas d’accusé de réception ne sont confirmés que lorsqu’un bloc ACK est envoyé pour d’autres raisons.

Lors de l’envoi d’un paquet pour quelque raison que ce soit, un point de terminaison devrait tenter d’inclure un bloc ACK si aucun n’a été envoyé récemment. Cela aide à la détection opportune des pertes chez le pair.

En général, des retours fréquents d’un récepteur améliorent la réponse aux pertes et à la congestion, mais cela doit être équilibré avec la charge excessive générée par un récepteur qui envoie un bloc ACK en réponse à chaque paquet nécessitant un accusé de réception. Les conseils offerts ci-dessous cherchent à trouver cet équilibre.

Les paquets de données en session contenant n’importe quel bloc SAUF les suivants déclenchent un accusé de réception :

  • Bloc ACK
  • Bloc d’adresse
  • Bloc DateTime
  • Bloc de remplissage
  • Bloc de terminaison
  • Tous les blocs dans le même paquet qu’un bloc de terminaison
  • Autres ?

Les paquets contenant un bloc de Termination avec une raison autre que “termination received” sont acquittés avec un paquet contenant un bloc de Termination avec “termination received”.

Les paquets hors session, y compris les messages de handshake et les messages de test de pairs 5-7, ont leurs propres mécanismes d’accusé de réception. Voir ci-dessous.

Handshake ACKs

Voici les cas particuliers :

  • La demande de token est implicitement acquittée par Retry
  • La demande de session est implicitement acquittée par Session Created ou Retry
  • Retry est implicitement acquitté par Session Request
  • Session Created est implicitement acquitté par Session Confirmed
  • Session Confirmed doit être acquitté immédiatement

Sending ACK Blocks

Les blocs ACK sont utilisés pour acquitter les paquets de phase de données. Ils ne doivent être inclus que pour les paquets de phase de données en session.

Chaque paquet doit être acquitté au moins une fois, et les paquets nécessitant un acquittement doivent être acquittés au moins une fois dans un délai maximum.

Un endpoint doit accuser réception de tous les paquets de handshake nécessitant un acquittement immédiatement dans sa délai maximum, à l’exception suivante près. Avant la confirmation du handshake, un endpoint pourrait ne pas disposer des clés de chiffrement d’en-tête de paquet pour déchiffrer les paquets lorsqu’ils sont reçus. Il pourrait donc les mettre en tampon et les accuser réception lorsque les clés requises deviennent disponibles.

Étant donné que les paquets contenant uniquement des blocs ACK ne sont pas soumis au contrôle de congestion, un point de terminaison ne doit pas envoyer plus d’un tel paquet en réponse à la réception d’un paquet sollicitant un accusé de réception.

Un endpoint ne doit pas envoyer un paquet non-ack-eliciting en réponse à un paquet non-ack-eliciting, même s’il y a des lacunes de paquets qui précèdent le paquet reçu. Cela évite une boucle de rétroaction infinie d’accusés de réception, qui pourrait empêcher la connexion de devenir inactive. Les paquets non-ack-eliciting sont finalement acquittés lorsque l’endpoint envoie un bloc ACK en réponse à d’autres événements.

Un endpoint qui n’envoie que des blocs ACK ne recevra pas d’accusés de réception de son pair à moins que ces accusés de réception ne soient inclus dans des paquets avec des blocs nécessitant un accusé de réception. Un endpoint devrait envoyer un bloc ACK avec d’autres blocs lorsqu’il y a de nouveaux paquets nécessitant un accusé de réception à accuser réception. Lorsque seuls des paquets ne nécessitant pas d’accusé de réception doivent être accusés réception, un endpoint PEUT choisir de ne pas envoyer un bloc ACK avec des blocs sortants jusqu’à ce qu’un paquet nécessitant un accusé de réception ait été reçu.

Un point de terminaison qui n’envoie que des paquets non-solliciteurs d’accusé de réception pourrait choisir d’ajouter occasionnellement un bloc solliciteur d’accusé de réception à ces paquets pour s’assurer qu’il reçoit un accusé de réception. Dans ce cas, un point de terminaison NE DOIT PAS envoyer un bloc solliciteur d’accusé de réception dans tous les paquets qui seraient autrement non-solliciteurs d’accusé de réception, pour éviter une boucle de rétroaction infinie d’accusés de réception.

Afin d’aider la détection de perte chez l’expéditeur, un point de terminaison devrait générer et envoyer un bloc ACK sans délai lorsqu’il reçoit un paquet provoquant un accusé de réception dans l’un de ces cas :

  • Lorsque le paquet reçu a un numéro de paquet inférieur à un autre paquet nécessitant un accusé de réception qui a été reçu

  • Lorsque le paquet a un numéro de paquet supérieur au paquet déclencheur d’acquittement le plus élevé qui a été reçu et qu’il y a des paquets manquants entre ce paquet et ce paquet-ci.

  • Lorsque le flag ack-immediate dans l’en-tête du paquet est défini

Les algorithmes sont conçus pour être résistants aux récepteurs qui ne suivent pas les recommandations offertes ci-dessus. Cependant, une implémentation ne devrait s’écarter de ces exigences qu’après avoir soigneusement considéré les implications de performance d’un changement, pour les connexions établies par le point de terminaison et pour les autres utilisateurs du réseau.

ACK Frequency

Un récepteur détermine à quelle fréquence envoyer des accusés de réception en réponse aux paquets nécessitant un accusé de réception. Cette détermination implique un compromis.

Les points de terminaison s’appuient sur des accusés de réception opportuns pour détecter les pertes. Les contrôleurs de congestion basés sur les fenêtres s’appuient sur les accusés de réception pour gérer leur fenêtre de congestion. Dans les deux cas, retarder les accusés de réception peut affecter négativement les performances.

D’autre part, réduire la fréquence des paquets qui ne transportent que des accusés de réception diminue les coûts de transmission et de traitement des paquets aux deux extrémités. Cela peut améliorer le débit de connexion sur des liaisons fortement asymétriques et réduire le volume de trafic d’accusé de réception utilisant la capacité du chemin de retour ; voir Section 3 de RFC 3449.

Un récepteur devrait envoyer un bloc ACK après avoir reçu au moins deux paquets nécessitant un accusé de réception. Cette recommandation est de nature générale et cohérente avec les recommandations pour le comportement des points de terminaison TCP RFC 5681. La connaissance des conditions réseau, la connaissance du contrôleur de congestion du pair, ou des recherches et expérimentations supplémentaires pourraient suggérer des stratégies d’accusé de réception alternatives avec de meilleures caractéristiques de performance.

Un récepteur peut traiter plusieurs paquets disponibles avant de déterminer s’il faut envoyer un bloc ACK en réponse. En général, le récepteur ne devrait pas retarder un ACK de plus de RTT / 6, ou 150 ms maximum.

Le flag ack-immediate dans l’en-tête du paquet de données est une demande pour que le récepteur envoie un ack peu après la réception, probablement dans les quelques ms. En général, le récepteur ne devrait pas retarder un ACK immédiat de plus de RTT / 16, ou 5 ms maximum.

Immediate ACK Flag

Le récepteur ne connaît pas la taille de la fenêtre d’envoi de l’expéditeur, et ne sait donc pas combien de temps attendre avant d’envoyer un ACK. Le flag d’ACK immédiat dans l’en-tête du paquet de données est un moyen important de maintenir un débit maximal en minimisant le RTT effectif. Le flag d’ACK immédiat est l’octet 13 de l’en-tête, bit 0, c’est-à-dire (header[13] & 0x01). Lorsqu’il est défini, un ACK immédiat est demandé. Voir la section sur l’en-tête court ci-dessus pour plus de détails.

Il existe plusieurs stratégies possibles qu’un expéditeur peut utiliser pour déterminer quand définir le flag immediate-ack :

  • Défini une fois tous les N paquets, pour un petit N
  • Défini sur le dernier d’une rafale de paquets
  • Défini lorsque la fenêtre d’envoi est presque pleine, par exemple à plus de 2/3 pleine
  • Défini sur tous les paquets avec des fragments retransmis

Les drapeaux ACK immédiats ne devraient être nécessaires que sur les paquets de données contenant des messages I2NP ou des fragments de messages.

ACK Block Size

Lorsqu’un bloc ACK est envoyé, une ou plusieurs plages de paquets accusés de réception sont incluses. Inclure des accusés de réception pour des paquets plus anciens réduit le risque de retransmissions parasites causées par la perte de blocs ACK précédemment envoyés, au prix de blocs ACK plus volumineux.

Les blocs ACK doivent toujours accuser réception des paquets reçus le plus récemment, et plus les paquets sont désordonnés, plus il est important d’envoyer rapidement un bloc ACK mis à jour, pour empêcher le pair de déclarer un paquet comme perdu et de retransmettre de manière erronée les blocs qu’il contient. Un bloc ACK doit tenir dans un seul paquet. Si ce n’est pas le cas, alors les plages plus anciennes (celles avec les plus petits numéros de paquet) sont omises.

Un récepteur limite le nombre de plages ACK qu’il mémorise et envoie dans les blocs ACK, à la fois pour limiter la taille des blocs ACK et pour éviter l’épuisement des ressources. Après avoir reçu des accusés de réception pour un bloc ACK, le récepteur devrait cesser de suivre ces plages ACK accusées de réception. Les expéditeurs peuvent s’attendre à des accusés de réception pour la plupart des paquets, mais ce protocole ne garantit pas la réception d’un accusé de réception pour chaque paquet que le récepteur traite.

Il est possible que la conservation de nombreuses plages ACK puisse entraîner qu’un bloc ACK devienne trop volumineux. Un récepteur peut supprimer des plages ACK non acquittées pour limiter la taille du bloc ACK, au prix d’une augmentation des retransmissions de la part de l’expéditeur. Ceci est nécessaire si un bloc ACK serait trop volumineux pour tenir dans un paquet. Les récepteurs peuvent également limiter davantage la taille du bloc ACK pour préserver l’espace pour d’autres blocs ou pour limiter la bande passante que consomment les acquittements.

Un récepteur doit conserver une plage d’ACK à moins qu’il ne puisse garantir qu’il n’acceptera pas par la suite des paquets avec des numéros dans cette plage. Maintenir un numéro de paquet minimum qui augmente à mesure que les plages sont supprimées est un moyen d’y parvenir avec un état minimal.

Les récepteurs peuvent rejeter toutes les plages ACK, mais ils doivent conserver le plus grand numéro de paquet qui a été traité avec succès, car celui-ci est utilisé pour récupérer les numéros de paquet des paquets suivants.

La section suivante décrit une approche exemplaire pour déterminer quels paquets accuser réception dans chaque bloc ACK. Bien que l’objectif de cet algorithme soit de générer un accusé de réception pour chaque paquet qui est traité, il est encore possible que les accusés de réception soient perdus.

Limiting Ranges by Tracking ACK Blocks

Lorsqu’un paquet contenant un bloc ACK est envoyé, le champ Ack Through de ce bloc peut être sauvegardé. Lorsqu’un paquet contenant un bloc ACK est acquitté, le récepteur peut cesser d’acquitter les paquets inférieurs ou égaux au champ Ack Through du bloc ACK envoyé.

Un récepteur qui envoie uniquement des paquets ne sollicitant pas d’accusé de réception, comme les blocs ACK, pourrait ne pas recevoir d’accusé de réception pendant une longue période. Cela pourrait amener le récepteur à maintenir l’état d’un grand nombre de blocs ACK pendant une longue période, et les blocs ACK qu’il envoie pourraient être inutilement volumineux. Dans un tel cas, un récepteur pourrait envoyer occasionnellement un PING ou un autre petit bloc sollicitant un accusé de réception, par exemple une fois par aller-retour, pour obtenir un ACK du pair.

Dans les cas sans perte de bloc ACK, cet algorithme permet un minimum de 1 RTT de réordonnancement. Dans les cas avec perte de bloc ACK et réordonnancement, cette approche ne garantit pas que chaque accusé de réception soit vu par l’expéditeur avant qu’il ne soit plus inclus dans le bloc ACK. Les paquets pourraient être reçus dans le désordre, et tous les blocs ACK subséquents les contenant pourraient être perdus. Dans ce cas, l’algorithme de récupération de perte pourrait causer des retransmissions parasites, mais l’expéditeur continuera à progresser.

Congestion

Les transports I2P ne garantissent pas la livraison dans l’ordre des messages I2NP. Par conséquent, la perte d’un message Data contenant un ou plusieurs messages ou fragments I2NP n’empêche PAS la livraison d’autres messages I2NP ; il n’y a pas de blocage en tête de file. Les implémentations devraient continuer à envoyer de nouveaux messages pendant la phase de récupération de perte si la fenêtre d’envoi le permet.

Retransmission

Un expéditeur ne doit pas conserver le contenu complet d’un message, pour le retransmettre de manière identique (sauf pour les messages de handshake, voir ci-dessus). Un expéditeur doit assembler des messages contenant des informations à jour (ACK, NACK, et données non acquittées) à chaque fois qu’il envoie un message. Un expéditeur doit éviter de retransmettre des informations provenant de messages une fois qu’ils sont acquittés. Ceci inclut les messages qui sont acquittés après avoir été déclarés perdus, ce qui peut arriver en présence de réordonnancement du réseau.

Window

À déterminer. Des conseils généraux peuvent être trouvés dans RFC 9002.

Connection Migration

L’adresse IP ou le port d’un pair peut changer durant la durée de vie d’une session. Un changement d’IP peut être causé par la rotation des adresses temporaires IPv6, un changement périodique d’IP imposé par le FAI, un client mobile transitant entre des IP WiFi et cellulaires, ou d’autres changements de réseau local. Un changement de port peut être causé par une nouvelle liaison NAT après expiration de la liaison précédente.

L’adresse IP ou le port d’un pair peut sembler changer en raison de diverses attaques sur le chemin ou hors du chemin, y compris la modification ou l’injection de paquets.

La migration de connexion est le processus par lequel un nouveau point de terminaison source (IP+port) est validé, tout en empêchant les changements qui ne sont pas validés. Ce processus est une version simplifiée de celui défini dans QUIC RFC 9000. Ce processus est défini uniquement pour la phase de données d’une session. La migration n’est pas autorisée pendant la négociation initiale. Tous les paquets de négociation initiale doivent être vérifiés comme provenant de la même IP et du même port que les paquets précédemment envoyés et reçus. En d’autres termes, l’IP et le port d’un pair doivent rester constants pendant la négociation initiale.

Threat Model

(Adapté de QUIC RFC 9000)

Notes

Un pair peut usurper son adresse source pour amener un endpoint à envoyer des quantités excessives de données vers un hôte non consentant. Si l’endpoint envoie significativement plus de données que le pair qui usurpe l’identité, la migration de connexion pourrait être utilisée pour amplifier le volume de données qu’un attaquant peut générer vers une victime.

Fragmentation de Session Confirmée

Un attaquant sur le chemin pourrait provoquer une migration de connexion parasite en copiant et transmettant un paquet avec une adresse usurpée de sorte qu’il arrive avant le paquet original. Le paquet avec l’adresse usurpée sera perçu comme provenant d’une connexion en migration, et le paquet original sera considéré comme un doublon et supprimé. Après une migration parasite, la validation de l’adresse source échouera car l’entité à l’adresse source ne possède pas les clés cryptographiques nécessaires pour lire ou répondre au Path Challenge qui lui est envoyé, même si elle le voulait.

Off-Path Packet Forwarding

Un attaquant hors-chemin qui peut observer les paquets pourrait transmettre des copies de paquets authentiques vers les points de terminaison. Si le paquet copié arrive avant le paquet authentique, cela apparaîtra comme une re-liaison NAT. Tout paquet authentique sera rejeté comme un doublon. Si l’attaquant est capable de continuer à transmettre des paquets, il pourrait être en mesure de provoquer une migration vers un chemin via l’attaquant. Cela place l’attaquant sur le chemin, lui donnant la capacité d’observer ou de supprimer tous les paquets suivants.

Privacy Implications

QUIC RFC 9000 spécifie de changer les ID de connexion lors du changement de chemins réseau. L’utilisation d’un ID de connexion stable sur plusieurs chemins réseau permettrait à un observateur passif de corréler l’activité entre ces chemins. Un point de terminaison qui se déplace entre les réseaux pourrait ne pas souhaiter que son activité soit corrélée par une autre entité que son pair. Cependant, QUIC ne chiffre pas les ID de connexion dans l’en-tête. SSU2 le fait, donc la fuite de confidentialité nécessiterait que l’observateur passif ait également accès à la base de données réseau pour obtenir la clé d’introduction requise pour déchiffrer l’ID de connexion. Même avec la clé d’introduction, ce n’est pas une attaque forte, et nous ne changeons pas les ID de connexion après migration dans SSU2, car cela constituerait une complication significative.

Initiating Path Validation

Durant la phase de données, les pairs doivent vérifier l’IP source et le port de chaque paquet de données reçu. Si l’IP ou le port est différent de celui précédemment reçu, ET que le paquet n’est pas un numéro de paquet dupliqué, ET que le paquet se déchiffre avec succès, la session entre dans la phase de validation de chemin.

De plus, un pair doit vérifier que la nouvelle IP et le port sont valides selon les règles de validation locales (non bloqués, ports non interdits, etc.). Les pairs ne sont PAS tenus de prendre en charge la migration entre IPv4 et IPv6, et peuvent traiter une nouvelle IP dans l’autre famille d’adresses comme invalide, car ce n’est pas un comportement attendu et peut ajouter une complexité d’implémentation significative. En recevant un paquet d’une IP/port invalide, une implémentation peut simplement le rejeter, ou peut initier une validation de chemin avec l’ancienne IP/port.

Lors de l’entrée dans la phase de validation du chemin, suivez les étapes suivantes :

  • Démarrer un minuteur de délai de validation de chemin de plusieurs secondes, ou plusieurs fois le RTO actuel (à déterminer)
  • Réduire la fenêtre de congestion au minimum
  • Réduire le PMTU au minimum (1280)
  • Envoyer un paquet de données contenant un bloc Path Challenge, un bloc Address (contenant la nouvelle IP/port), et, typiquement, un bloc ACK, vers la nouvelle IP et le port. Ce paquet utilise le même ID de connexion et les clés de chiffrement que la session actuelle. Les données du bloc Path Challenge doivent contenir une entropie suffisante (au moins 8 octets) pour qu’elles ne puissent pas être usurpées.
  • Optionnellement, envoyer aussi un Path Challenge vers l’ancienne IP/port, avec des données de bloc différentes. Voir ci-dessous.
  • Démarrer un minuteur de délai Path Response basé sur le RTO actuel (typiquement RTT + un multiple de RTTdev)

Pendant la phase de validation du chemin, la session peut continuer à traiter les paquets entrants. Qu’ils proviennent de l’ancienne ou de la nouvelle IP/port. La session peut également continuer à envoyer et à acquitter les paquets de données. Cependant, la fenêtre de congestion et le PMTU doivent rester aux valeurs minimales pendant la phase de validation du chemin, pour éviter d’être utilisés pour des attaques par déni de service en envoyant de grandes quantités de trafic vers une adresse usurpée.

Une implémentation peut, mais n’est pas tenue, de tenter de valider plusieurs chemins simultanément. Ceci ne vaut probablement pas la complexité. Elle peut, mais n’est pas tenue, de se souvenir d’une IP/port précédente comme étant déjà validée, et d’ignorer la validation de chemin si un pair retourne à son IP/port précédent.

Si une Path Response est reçue, contenant les données identiques envoyées dans le Path Challenge, la Path Validation a réussi. L’IP/port source du message Path Response n’est pas tenu d’être identique à celui auquel le Path Challenge a été envoyé.

Si une Path Response n’est pas reçue avant l’expiration du minuteur Path Response, envoyez un autre Path Challenge et doublez le minuteur Path Response.

Si une Path Response n’est pas reçue avant l’expiration du minuteur de Path Validation, la Path Validation a échoué.

Message Contents

Les messages Data doivent contenir les blocs suivants. L’ordre n’est pas spécifié, sauf que le Padding doit être en dernier :

  • Bloc de Validation de Chemin ou de Réponse de Chemin. La Validation de Chemin contient des données opaques, 8 octets minimum recommandés. La Réponse de Chemin contient les données de la Validation de Chemin.
  • Bloc d’adresse contenant l’IP apparente du destinataire
  • Bloc DateTime
  • Bloc ACK
  • Bloc de bourrage

Il n’est pas recommandé d’inclure d’autres blocs (par exemple, I2NP) dans le message.

Il est autorisé d’inclure un bloc Path Validation dans le message contenant la Path Response, pour initier une validation dans l’autre direction.

Les blocs Path Challenge et Path Response déclenchent un ACK. Le Path Challenge sera acquitté par un message Data contenant les blocs Path Response et ACK. Le Path Response devrait être acquitté par un message Data contenant un bloc ACK.

Routing during Path Validation

La spécification QUIC n’est pas claire sur l’endroit où envoyer les paquets de données pendant la validation de chemin - vers l’ancienne ou la nouvelle adresse IP/port ? Il faut trouver un équilibre entre répondre rapidement aux changements d’IP/port et ne pas envoyer de trafic vers des adresses usurpées. De plus, les paquets usurpés ne doivent pas être autorisés à impacter substantiellement une session existante. Les changements de port uniquement sont susceptibles d’être causés par une re-liaison NAT après une période d’inactivité ; les changements d’IP pourraient se produire pendant les phases de trafic intense dans une ou les deux directions.

Les stratégies font l’objet de recherches et d’affinements. Les possibilités incluent :

  • Ne pas envoyer de paquets de données vers la nouvelle IP/port jusqu’à validation
  • Continuer à envoyer des paquets de données vers l’ancienne IP/port jusqu’à ce que la nouvelle IP/port soit validée
  • Revalider simultanément l’ancienne IP/port
  • Ne pas envoyer de données jusqu’à ce que l’ancienne ou la nouvelle IP/port soit validée
  • Stratégies différentes pour un changement de port uniquement par rapport à un changement d’IP
  • Stratégies différentes pour un changement IPv6 dans le même /32, probablement causé par une rotation d’adresse temporaire

Responding to Path Challenge

À la réception d’un Path Challenge, le pair doit répondre avec un paquet de données contenant un Path Response, avec les données du Path Challenge. TODO Peut-être ??? : Le Path Response doit être envoyé à l’IP/port depuis lequel le Path Challenge a été reçu. Ce n’est PAS NÉCESSAIREMENT l’IP/port qui était précédemment établi pour le pair. Cela garantit que la validation de chemin par un pair ne réussit que si le chemin est fonctionnel dans les deux directions. Voir la section Validation après changement local ci-dessous.

À moins que l’IP/port ne soit différent de l’IP/port précédemment connu pour le pair, traiter un Path Challenge comme un simple ping, et répondre simplement de manière inconditionnelle avec un Path Response. Le récepteur ne conserve ni ne modifie aucun état basé sur un Path Challenge reçu. Si l’IP/port est différent, un pair doit vérifier que la nouvelle IP et le port sont valides selon les règles de validation locales (non bloqués, pas de ports illégaux, etc.). Les pairs ne sont PAS tenus de prendre en charge les réponses inter-familles d’adresses entre IPv4 et IPv6, et peuvent traiter une nouvelle IP dans l’autre famille d’adresses comme invalide, car ce n’est pas un comportement attendu.

Sauf contrainte par le contrôle de congestion, la réponse de chemin (Path Response) devrait être envoyée immédiatement. Les implémentations devraient prendre des mesures pour limiter le débit des réponses de chemin ou la bande passante utilisée si nécessaire.

Un bloc Path Challenge est généralement accompagné d’un bloc Address dans le même message. Si le bloc d’adresse contient une nouvelle IP/port, un pair peut valider cette IP/port et initier des tests de pair de cette nouvelle IP/port, avec le pair de session ou tout autre pair. Si le pair pense qu’il est derrière un pare-feu, et que seul le port a changé, ce changement est probablement dû à une re-liaison NAT, et des tests de pair supplémentaires ne sont probablement pas nécessaires.

Successful Path Validation

Lors de la validation réussie du chemin, la connexion est entièrement migrée vers la nouvelle IP/port. En cas de succès :

  • Quitter la phase de validation du chemin
  • Tous les paquets sont envoyés vers la nouvelle IP et le nouveau port.
  • Les restrictions sur la fenêtre de congestion et PMTU sont supprimées, et elles sont autorisées à augmenter. Ne pas simplement les restaurer aux anciennes valeurs, car le nouveau chemin peut avoir des caractéristiques différentes.
  • Si l’IP a changé, définir le RTT calculé et RTO aux valeurs initiales. Étant donné que les changements de port uniquement résultent couramment d’une re-liaison NAT ou d’autres activités de middlebox, le pair peut à la place conserver son état de contrôle de congestion et son estimation de temps d’aller-retour dans ces cas au lieu de revenir aux valeurs initiales.
  • Supprimer (invalider) tous les tokens envoyés ou reçus pour l’ancienne IP/port (optionnel)
  • Envoyer un nouveau bloc de token pour la nouvelle IP/port (optionnel)

Cancelling Path Validation

Pendant la phase de validation de chemin, tout paquet valide et non-dupliqué qui est reçu depuis l’ancienne IP/port et qui est déchiffré avec succès provoquera l’annulation de la validation de chemin. Il est important qu’une validation de chemin annulée, causée par un paquet usurpé, n’entraîne pas la terminaison ou la perturbation significative d’une session valide.

Sur la validation de chemin annulée :

  • Quitter la phase de validation du chemin
  • Tous les paquets sont envoyés vers l’ancienne IP et le port.
  • Les restrictions sur la fenêtre de congestion et le PMTU sont supprimées, et ils sont autorisés à augmenter, ou, optionnellement, restaurer les valeurs précédentes
  • Retransmettre tout paquet de données qui a été précédemment envoyé vers la nouvelle IP/port vers l’ancienne IP/port.

Failed Path Validation

Il est important qu’une validation de chemin échouée, causée par un paquet usurpé, n’entraîne pas la terminaison ou la perturbation significative d’une session valide.

En cas d’échec de la validation de chemin :

  • Quitter la phase de validation de chemin
  • Tous les paquets sont envoyés vers l’ancienne IP et le port.
  • Les restrictions sur la fenêtre de congestion et PMTU sont supprimées, et elles sont autorisées à augmenter.
  • Optionnellement, démarrer une validation de chemin sur l’ancienne IP et le port. Si elle échoue, terminer la session.
  • Sinon, suivre les règles standard de timeout et de terminaison de session.
  • Retransmettre tous les paquets de données qui ont été précédemment envoyés vers la nouvelle IP/port vers l’ancienne IP/port.

Validation After Local Change

Le processus ci-dessus est défini for les pairs qui reçoivent un paquet d’une IP/port modifiée. Cependant, il peut également être initié dans l’autre direction, par un pair qui détecte que son IP ou port a changé. Un pair peut être capable de détecter que son IP locale a changé ; cependant, il est beaucoup moins probable qu’il détecte que son port a changé à cause d’une re-liaison NAT. Par conséquent, ceci est optionnel.

Lors de la réception d’un path challenge d’un pair dont l’IP ou le port a changé, l’autre pair devrait initier un path challenge dans l’autre direction.

Sécurité des relais

Les blocs Path Validation et Path Response peuvent être utilisés à tout moment comme paquets Ping/Pong. La réception d’un bloc Path Validation ne modifie aucun état chez le récepteur, sauf si elle est reçue depuis une IP/port différente.

Multiple Sessions

Les pairs ne doivent pas établir plusieurs sessions avec le même pair, que ce soit en SSU 1 ou 2, ou avec des adresses IP identiques ou différentes. Cependant, cela pourrait arriver, soit en raison de bogues, soit parce qu’un message de terminaison de session précédent a été perdu, ou dans une situation de concurrence où le message de terminaison n’est pas encore arrivé.

Si Bob a une session existante avec Alice, lorsque Bob reçoit le Session Confirmed d’Alice, complétant la négociation et établissant une nouvelle session, Bob devrait :

  • Migrer tous les messages I2NP sortants non envoyés ou non acquittés de l’ancienne session vers la nouvelle
  • Envoyer une terminaison avec le code de raison 22 sur l’ancienne session
  • Supprimer l’ancienne session et la remplacer par la nouvelle

Session Termination

Sécurité du Test de Pair

Les sessions en phase de handshake sont généralement terminées simplement par expiration du délai d’attente, ou en ne répondant plus. Optionnellement, elles peuvent être terminées en incluant un bloc Termination dans la réponse, mais la plupart des erreurs ne peuvent pas recevoir de réponse en raison de l’absence de clés cryptographiques. Même si des clés sont disponibles pour une réponse incluant un bloc de terminaison, il ne vaut généralement pas la peine d’utiliser le CPU pour effectuer le DH pour la réponse. Une exception PEUT être un bloc Termination dans un message de nouvelle tentative, qui est peu coûteux à générer.

Objectifs de conception des relais et des tests de pairs

Les sessions en phase de données sont terminées en envoyant un message de données qui inclut un bloc Termination. Ce message devrait également inclure un bloc ACK. Il peut, si la session a été active suffisamment longtemps pour qu’un token précédemment envoyé ait expiré ou soit sur le point d’expirer, inclure un bloc New Token. Ce message ne nécessite pas d’accusé de réception. Lors de la réception d’un bloc Termination avec n’importe quelle raison sauf “Termination Received”, le pair répond avec un message de données contenant un bloc Termination avec la raison “Termination Received”.

Après avoir envoyé ou reçu un bloc de Terminaison, la session devrait entrer dans la phase de fermeture pour une période maximale de temps à déterminer. L’état de fermeture est nécessaire pour se protéger contre la perte du paquet contenant le bloc de Terminaison, et les paquets en transit dans l’autre direction. Pendant la phase de fermeture, il n’y a aucune exigence de traiter des paquets reçus supplémentaires. Une session dans l’état de fermeture envoie un paquet contenant un bloc de Terminaison en réponse à tout paquet entrant qu’elle attribue à la session. Une session devrait limiter la fréquence à laquelle elle génère des paquets dans l’état de fermeture. Par exemple, une session pourrait attendre un nombre progressivement croissant de paquets reçus ou une durée de temps avant de répondre aux paquets reçus.

Pour minimiser l’état qu’un router maintient pour une session en cours de fermeture, les sessions peuvent, mais ne sont pas tenues de, envoyer exactement le même paquet avec le même numéro de paquet tel quel en réponse à tout paquet reçu. Note : Permettre la retransmission d’un paquet de terminaison est une exception à l’exigence qu’un nouveau numéro de paquet soit utilisé pour chaque paquet. L’envoi de nouveaux numéros de paquet est principalement avantageux pour la récupération de perte et le contrôle de congestion, qui ne sont pas censés être pertinents pour une connexion fermée. Retransmettre le paquet final nécessite moins d’état.

Après avoir reçu un bloc de Termination avec la raison “Termination Received”, la session peut quitter la phase de fermeture.

Cleanup

Lors de toute terminaison normale ou anormale, les routers doivent mettre à zéro toute donnée éphémère en mémoire, y compris les clés éphémères de handshake, les clés de chiffrement symétriques et les informations connexes.

MTU

Les exigences varient selon que l’adresse publiée est partagée avec SSU 1. Le minimum IPv4 actuel pour SSU 1 est de 620, ce qui est définitivement trop petit.

Le MTU minimum SSU2 est de 1280 pour IPv4 et IPv6, ce qui est identique à ce qui est spécifié dans la RFC 9000. Voir ci-dessous. En augmentant le MTU minimum, les messages de tunnel de 1 Ko et les messages de construction de tunnel courts tiendront dans un seul datagramme, réduisant considérablement la quantité typique de fragmentation. Cela permet également d’augmenter la taille maximale des messages I2NP. Les messages de streaming de 1820 octets devraient tenir dans deux datagrammes.

Un routeur ne doit pas activer SSU2 ou publier une adresse SSU2 à moins que la MTU pour cette adresse soit d’au moins 1280.

Les routeurs doivent publier une MTU non-par-défaut dans chaque adresse de routeur SSU ou SSU2.

Résumé

Adresse partagée avec SSU 1, doit suivre les règles SSU 1. IPv4 : Par défaut et maximum est 1484. Minimum est 1292. (IPv4 MTU + 4) doit être un multiple de 16. IPv6 : Doit être publié, minimum est 1280 et le maximum est 1488. IPv6 MTU doit être un multiple de 16.

Garanties de Livraison

IPv4 : Par défaut et maximum est 1500. Minimum est 1280. IPv6 : Par défaut et maximum est 1500. Minimum est 1280. Pas de règles de multiple de 16, mais devrait probablement être un multiple de 2 au minimum.

Cadre de protocole Noise

Pour SSU 1, l’implémentation Java I2P actuelle effectue la découverte PMTU en commençant par de petits paquets et en augmentant progressivement la taille, ou en augmentant en fonction de la taille des paquets reçus. Cette méthode est rudimentaire et réduit considérablement l’efficacité. Le maintien de cette fonctionnalité dans SSU 2 reste à déterminer.

Des études récentes PMTU suggèrent qu’un minimum de 1200 octets ou plus pour IPv4 fonctionnerait pour plus de 99 % des connexions. QUIC RFC 9000 exige une taille minimale de paquet IP de 1280 octets.

citation RFC 9000 :

La taille maximale de datagramme est définie comme la plus grande taille de charge utile UDP qui peut être envoyée à travers un chemin réseau en utilisant un seul datagramme UDP. QUIC NE DOIT PAS être utilisé si le chemin réseau ne peut pas supporter une taille maximale de datagramme d’au moins 1200 octets.

QUIC suppose une taille minimale de paquet IP d’au moins 1280 octets. Il s’agit de la taille minimale IPv6 [IPv6] et elle est également prise en charge par la plupart des réseaux IPv4 modernes. En supposant une taille d’en-tête IP minimale de 40 octets pour IPv6 et de 20 octets pour IPv4 et une taille d’en-tête UDP de 8 octets, cela résulte en une taille maximale de datagramme de 1232 octets pour IPv6 et de 1252 octets pour IPv4. Ainsi, les réseaux IPv4 modernes et tous les chemins réseau IPv6 sont censés pouvoir prendre en charge QUIC.

Note : Cette exigence de prendre en charge une charge utile UDP de 1200 octets limite l’espace disponible pour les en-têtes d’extension IPv6 à 32 octets ou les options IPv4 à 52 octets si le chemin ne prend en charge que le MTU minimum IPv6 de 1280 octets. Cela affecte les paquets Initial et la validation de chemin.

fin de citation

Ajouts au Framework

QUIC exige que les datagrammes Initial dans les deux directions fassent au moins 1200 octets, pour prévenir les attaques par amplification et s’assurer que la PMTU le supporte dans les deux directions.

Nous pourrions exiger ceci pour Session Request et Session Created, au coût substantiel de la bande passante. Peut-être pourrions-nous faire cela seulement si nous n’avons pas de token, ou après qu’un message Retry soit reçu. À déterminer

QUIC exige que Bob n’envoie pas plus de trois fois la quantité de données reçues jusqu’à ce que l’adresse du client soit validée. SSU2 répond à cette exigence de manière inhérente, car le message Retry a approximativement la même taille que le message Token Request, et est plus petit que le message Session Request. De plus, le message Retry n’est envoyé qu’une seule fois.

Estimation de la surcharge de traitement

QUIC exige que les messages contenant des blocs PATH_CHALLENGE ou PATH_RESPONSE fassent au moins 1200 octets, pour prévenir les attaques par amplification et s’assurer que le PMTU le supporte dans les deux directions.

Nous pourrions également l’exiger, au prix d’un coût substantiel en bande passante. Cependant, ces cas devraient être rares. TBD

Max I2NP Message Size

IPv4 : Aucune fragmentation IP n’est supposée. L’en-tête IP + datagramme fait 28 octets. Ceci suppose qu’il n’y a pas d’options IPv4. La taille maximale du message est MTU - 28. L’en-tête de la phase de données fait 16 octets et le MAC fait 16 octets, totalisant 32 octets. La taille de la charge utile est MTU - 60. La charge utile maximale de la phase de données est de 1440 pour un MTU maximum de 1500. La charge utile maximale de la phase de données est de 1220 pour un MTU minimum de 1280.

IPv6 : Aucune fragmentation IP n’est autorisée. L’en-tête IP + datagramme fait 48 octets. Ceci suppose qu’il n’y a pas d’en-têtes d’extension IPv6. La taille maximale du message est MTU - 48. L’en-tête de phase de données fait 16 octets et le MAC fait 16 octets, pour un total de 32 octets. La taille de la charge utile est MTU - 80. La charge utile maximale de phase de données est de 1420 pour un MTU maximum de 1500. La charge utile maximale de phase de données est de 1200 pour un MTU minimum de 1280.

Dans SSU 1, les directives étaient un maximum strict d’environ 32 Ko pour un message I2NP basé sur 64 fragments maximum et un MTU minimum de 620. En raison de la surcharge pour les LeaseSets groupés et les clés de session, la limite pratique au niveau de l’application était d’environ 6 Ko inférieure, soit environ 26 Ko. Le protocole SSU 1 permet jusqu’à 128 fragments mais les implémentations actuelles le limitent à 64 fragments.

En augmentant le MTU minimum à 1280, avec une charge utile de phase de données d’environ 1200, un message SSU 2 d’environ 76 KB est possible en 64 fragments et 152 KB en 128 fragments. Ceci permet facilement un maximum de 64 KB.

En raison de la fragmentation dans les tunnels et de la fragmentation dans SSU 2, les chances de perte de messages augmentent exponentiellement avec la taille des messages. Nous continuons de recommander une limite pratique d’environ 10 KB au niveau de la couche application pour les datagrammes I2NP.

Peer Test Process

Voir Sécurité du test de pairs ci-dessus pour une analyse du test de pairs SSU1 et les objectifs du test de pairs SSU2.

Alice                     Bob                  Charlie
1. PeerTest ------------------->
                              Alice RI ------------------->
2.                          PeerTest ------------------->
3.                             <------------------ PeerTest
          <---------------- Charlie RI
4.      <------------------ PeerTest

5.      <----------------------------------------- PeerTest
6. PeerTest ----------------------------------------->
7.      <----------------------------------------- PeerTest

Lorsque rejeté par Bob :

Alice                     Bob                  Charlie
1. PeerTest ------------------->
4.      <------------------ PeerTest (reject)

Lorsque rejeté par Charlie :

Alice                     Bob                  Charlie
1. PeerTest ------------------->
                              Alice RI ------------------->
2.                          PeerTest ------------------->
3.                             <------------------ PeerTest (reject)
                        (optional: Bob could try another Charlie here)
4.      <------------------ PeerTest (reject)

NOTE : Les RI peuvent être envoyés soit sous forme de messages I2NP Database Store dans des blocs I2NP, soit sous forme de blocs RI (s’ils sont suffisamment petits). Ceux-ci peuvent être contenus dans les mêmes paquets que les blocs de test de pairs, s’ils sont suffisamment petits.

Les messages 1-4 sont en session utilisant des blocs Peer Test dans un message Data. Les messages 5-7 sont hors session utilisant des blocs Peer Test dans un message Peer Test.

NOTE : Comme dans SSU 1, les messages 4 et 5 peuvent arriver dans n’importe quel ordre. Les messages 5 et/ou 7 peuvent ne pas être reçus du tout si Alice est derrière un pare-feu. Lorsque le message 5 arrive avant le message 4, Alice ne peut pas envoyer immédiatement le message 6, car elle n’a pas encore la clé d’introduction de Charlie pour chiffrer l’en-tête. Lorsque le message 4 arrive avant le message 5, Alice ne devrait pas envoyer immédiatement le message 6, car elle devrait attendre de voir si le message 5 arrive sans ouvrir le pare-feu avec le message 6.

MessagePathIntro Key
1A->B sessionin-session
2B->C sessionin-session
3C->B sessionin-session
4B->A sessionin-session
5C->AAlice
6A->CCharlie
7C->AAlice

Versions

Le test de pairs entre versions différentes n’est pas pris en charge. La seule combinaison de versions autorisée est celle où tous les pairs sont en version 2.

Alice/BobBob/CharlieAlice/CharlieSupported
111SSU 1
112no, use 1/1/1
121no, Bob must s
122no, Bob must s
211no, Bob must s
212no, Bob must s
221no, use 2/2/2
222yes

Établissement de session

Les messages 1-4 sont en session et sont couverts par les processus d’ACK et de retransmission de la phase de données. Les blocs Peer Test déclenchent un accusé de réception.

Les messages 5-7 peuvent être retransmis, inchangés.

En-tête de paquet

Comme dans SSU 1, les tests d’adresses IPv6 sont pris en charge, et la communication Alice-Bob et Alice-Charlie peut se faire via IPv6, si Bob et Charlie indiquent leur support avec une capacité ‘B’ dans leur adresse IPv6 publiée. Voir la Proposition 126 pour les détails.

Comme dans SSU 1 avant la version 0.9.50, Alice envoie la requête à Bob en utilisant une session existante sur le transport (IPv4 ou IPv6) qu’elle souhaite tester. Lorsque Bob reçoit une requête d’Alice via IPv4, Bob doit sélectionner un Charlie qui annonce une adresse IPv4. Lorsque Bob reçoit une requête d’Alice via IPv6, Bob doit sélectionner un Charlie qui annonce une adresse IPv6. La communication réelle Bob-Charlie peut se faire via IPv4 ou IPv6 (c’est-à-dire, indépendamment du type d’adresse d’Alice). Ce n’est PAS le comportement de SSU 1 à partir de la version 0.9.50, où les requêtes mixtes IPv4/v6 sont autorisées.

Processing by Bob

Contrairement à SSU 1, Alice spécifie l’IP et le port de test demandés dans le message 1. Bob devrait valider cette IP et ce port, et rejeter avec le code 5 si invalide. La validation IP recommandée est que, pour IPv4, elle corresponde à l’IP d’Alice, et pour IPv6, au moins les 8 premiers octets de l’IP correspondent. La validation du port devrait rejeter les ports privilégiés et les ports pour les protocoles bien connus.

Relay Process

Voir la section Sécurité des relais ci-dessus pour une analyse du relais SSU1 et les objectifs du relais SSU2.

Alice                         Bob                  Charlie
     lookup Bob RI

     SessionRequest -------------------->
          <------------  SessionCreated
     SessionConfirmed  ----------------->

1. RelayRequest ---------------------->
                                           Alice RI  ------------>
2.                                       RelayIntro ----------->
3.                                  <-------------- RelayResponse
4.      <-------------- RelayResponse

5.      <-------------------------------------------- HolePunch
6. SessionRequest -------------------------------------------->
7.      <-------------------------------------------- SessionCreated
8. SessionConfirmed ------------------------------------------>

Lorsque rejeté par Bob :

Alice                         Bob                  Charlie
     lookup Bob RI

     SessionRequest -------------------->
          <------------  SessionCreated
     SessionConfirmed  ----------------->

1. RelayRequest ---------------------->
4.      <-------------- RelayResponse

Lorsque rejeté par Charlie :

Alice                         Bob                  Charlie
     lookup Bob RI

     SessionRequest -------------------->
          <------------  SessionCreated
     SessionConfirmed  ----------------->

1. RelayRequest ---------------------->
                                           Alice RI  ------------>
2.                                       RelayIntro ----------->
3.                                  <-------------- RelayResponse
4.      <-------------- RelayResponse

NOTE : Les RI peuvent être envoyés soit dans des messages I2NP Database Store dans des blocs I2NP, soit comme blocs RI (s’ils sont assez petits). Ceux-ci peuvent être contenus dans les mêmes paquets que les blocs relay, s’ils sont assez petits.

Dans SSU 1, les informations de routeur de Charlie contiennent l’IP, le port, la clé d’introduction, l’étiquette de relais et l’expiration de chaque introducer.

Dans SSU 2, les informations du routeur de Charlie contiennent le hash du routeur, le tag de relais, et l’expiration de chaque introducer.

Alice devrait réduire le nombre d’allers-retours requis en sélectionnant d’abord un introducer (Bob) auquel elle a déjà une connexion. Ensuite, si aucun n’est disponible, sélectionner un introducer pour lequel elle possède déjà les informations de router.

Le relais inter-versions devrait également être pris en charge si possible. Cela facilitera une transition progressive de SSU 1 vers SSU 2. Les combinaisons de versions autorisées sont (TODO) :

Alice/BobBob/CharlieAlice/CharlieSupported
111SSU 1
112no, use 1/1/1
121yes?
122no, use 1/2/1
211yes?
212yes?
221no, use 2/2/2
222yes

Retransmissions

Relay Request, Relay Intro, et Relay Response sont tous dans la session et sont couverts par les processus d’ACK de phase de données et de retransmission. Les blocs Relay Request, Relay Intro, et Relay Response déclenchent des accusés de réception.

Le hole punch peut être retransmis, comme dans SSU 1.

IPv4/v6

Toutes les fonctionnalités du relais SSU 1 sont prises en charge, y compris celles documentées dans la Proposition 158 et supportées depuis la version 0.9.50. Les introductions IPv4 et IPv6 sont prises en charge. Une demande de relais peut être envoyée via une session IPv4 pour une introduction IPv6, et une demande de relais peut être envoyée via une session IPv6 pour une introduction IPv4.

Processing by Alice

Voici les différences par rapport à SSU 1 et les recommandations pour l’implémentation de SSU 2.

Notes

Dans SSU 1, l’introduction est relativement peu coûteuse, et Alice envoie généralement des Relay Requests à tous les introducers. Dans SSU 2, l’introduction est plus coûteuse, car une connexion doit d’abord être établie avec un introducer. Pour minimiser la latence et la surcharge d’introduction, les étapes de traitement recommandées sont les suivantes :

  • Ignorer tous les introducers qui ont expiré basé sur la valeur iexp dans l’adresse
  • Si une connexion SSU2 est déjà établie vers un ou plusieurs introducers, en choisir un et envoyer la Relay Request uniquement à cet introducer.
  • Sinon, si une Router Info est connue localement pour un ou plusieurs introducers, en choisir un et se connecter uniquement à cet introducer.
  • Sinon, rechercher les Router Infos pour tous les introducers, se connecter à l’introducer dont la Router Info est reçue en premier.

Notes

Dans SSU 1 et SSU 2, la Relay Response et le Hole Punch peuvent être reçus dans n’importe quel ordre, ou peuvent ne pas être reçus du tout.

Dans SSU 1, Alice reçoit généralement la Relay Response (1 RTT) avant le Hole Punch (1 1/2 RTT). Cela pourrait ne pas être bien documenté dans ces spécifications, mais Alice doit recevoir la Relay Response de Bob avant de continuer, pour recevoir l’IP de Charlie. Si le Hole Punch est reçu en premier, Alice ne le reconnaîtra pas, car il ne contient aucune donnée et l’IP source n’est pas reconnue. Après avoir reçu la Relay Response, Alice devrait attendre SOIT de recevoir le Hole Punch de Charlie, SOIT un court délai (recommandé 500 ms) avant d’initier la négociation avec Charlie.

Dans SSU 2, Alice recevra généralement le Hole Punch (1 1/2 RTT) avant la Relay Response (2 RTT). Le SSU 2 Hole Punch est plus facile à traiter que dans SSU 1, car c’est un message complet avec des ID de connexion définis (dérivés du relay nonce) et un contenu incluant l’IP de Charlie. La Relay Response (message Data) et le message Hole Punch contiennent le bloc Relay Response signé identique. Par conséquent, Alice peut initier la négociation avec Charlie après SOIT avoir reçu le Hole Punch de Charlie, SOIT avoir reçu la Relay Response de Bob.

La vérification de signature du Hole Punch inclut le hash du router de l’introducer (Bob). Si des Relay Requests ont été envoyées à plus d’un introducer, il existe plusieurs options pour valider la signature :

  • Essayer chaque hash auquel une requête a été envoyée
  • Utiliser des nonces différents pour chaque introducer, et utiliser cela pour déterminer à quel introducer ce Hole Punch était en réponse
  • Ne pas re-valider la signature si le contenu est identique à celui de la Relay Response, si déjà reçue
  • Ne pas valider la signature du tout

Si Charlie se trouve derrière un NAT symétrique, son port rapporté dans la Relay Response et le Hole Punch peut ne pas être précis. Par conséquent, Alice devrait vérifier le port source UDP du message Hole Punch, et l’utiliser s’il est différent du port rapporté.

Tag Requests by Bob

Dans SSU 1, seule Alice pouvait demander un tag, dans la Session Request. Bob ne pouvait jamais demander un tag, et Alice ne pouvait pas relayer pour Bob.

Dans SSU2, Alice demande généralement un tag dans la Session Request, mais Alice ou Bob peuvent aussi demander un tag pendant la phase de données. Bob n’est généralement pas derrière un firewall après avoir reçu une requête entrante, mais il pourrait l’être après un relais, ou l’état de Bob peut changer, ou il peut demander un introducer pour l’autre type d’adresse (IPv4/v6). Donc, dans SSU2, il est possible qu’Alice et Bob soient simultanément des relais l’un pour l’autre.

Published Router Info

Address Properties

Les propriétés d’adresse suivantes peuvent être publiées, inchangées par rapport à SSU 1, y compris les modifications de la Proposition 158 prises en charge à partir de l’API 0.9.50 :

  • caps: capacités [B,C,4,6]

  • host: IP (IPv4 ou IPv6). Les adresses IPv6 raccourcies (avec “::”) sont autorisées. Peut être présent ou absent si protégé par un pare-feu. Les noms d’hôtes ne sont pas autorisés.

  • iexp[0-2]: Expiration de cet introducer. Chiffres ASCII, en secondes depuis l’époque. Présent uniquement si derrière un pare-feu, et que des introducers sont requis. Optionnel (même si d’autres propriétés pour cet introducer sont présentes).

  • ihost[0-2]: IP de l’introducer (IPv4 ou IPv6). Les adresses IPv6 raccourcies (avec “::”) sont autorisées. Présent uniquement si derrière un pare-feu, et que des introducers sont requis. Les noms d’hôtes ne sont pas autorisés. Adresse SSU uniquement.

  • ikey[0-2]: Clé d’introduction Base 64 de l’introducer. Présente uniquement si derrière un pare-feu, et que des introducers sont requis. Adresse SSU uniquement.

  • iport[0-2] : Port de l’introducer 1024 - 65535. Présent uniquement si derrière un pare-feu, et que des introducers sont requis. Adresse SSU uniquement.

  • itag[0-2]: Tag de l’introducer 1 - (2**32 - 1) Chiffres ASCII. Présent uniquement si derrière un pare-feu, et que des introducers sont requis.

  • key : Clé d’introduction Base 64.

  • mtu : Optionnel. Voir la section MTU ci-dessus.

  • port: 1024 - 65535 Peut être présent ou non si derrière un pare-feu.

Published Addresses

L’adresse RouterAddress publiée (partie du RouterInfo) aura un identifiant de protocole soit “SSU” soit “SSU2”.

Le RouterAddress doit contenir trois options pour indiquer la prise en charge de SSU2 :

  • s=(Base64 key) La clé publique statique Noise actuelle (s) pour cette RouterAddress. Encodée en Base 64 utilisant l’alphabet I2P Base 64 standard. 32 octets en binaire, 44 octets encodés en Base 64, clé publique X25519 little-endian.

  • i=(Base64 key) La clé d’introduction actuelle pour chiffrer les en-têtes de cette RouterAddress. Encodée en Base 64 en utilisant l’alphabet I2P Base 64 standard. 32 octets en binaire, 44 octets encodés en Base 64, clé ChaCha20 big-endian.

  • v=2 La version actuelle (2). Lorsque publié comme “SSU”, un support additionnel pour la version 1 est implicite. Le support pour les versions futures se fera avec des valeurs séparées par des virgules, par ex. v=2,3 L’implémentation devrait vérifier la compatibilité, incluant plusieurs versions si une virgule est présente. Les versions séparées par des virgules doivent être dans l’ordre numérique.

Alice doit vérifier que les trois options sont présentes et valides avant de se connecter en utilisant le protocole SSU2.

Lorsqu’il est publié en tant que “SSU” avec les options “s”, “i” et “v”, et avec les options “host” et “port”, le router doit accepter les connexions entrantes sur cet hôte et ce port pour les protocoles SSU et SSU2, et détecter automatiquement la version du protocole.

Lorsqu’il est publié comme “SSU2” avec les options “s”, “i” et “v”, et avec les options “host” et “port”, le router accepte les connexions entrantes sur cet hôte et ce port pour le protocole SSU2 uniquement.

Si un routeur prend en charge les connexions SSU1 et SSU2 mais n’implémente pas la détection automatique de version pour les connexions entrantes, il doit annoncer à la fois les adresses “SSU” et “SSU2”, et inclure les options SSU2 uniquement dans l’adresse “SSU2”. Le routeur devrait définir une valeur de coût plus faible (priorité plus élevée) dans l’adresse “SSU2” que dans l’adresse “SSU”, afin que SSU2 soit privilégié.

Si plusieurs SSU2 RouterAddresses (soit comme “SSU” ou “SSU2”) sont publiées dans le même RouterInfo (pour des adresses IP ou ports supplémentaires), toutes les adresses spécifiant le même port doivent contenir des options et valeurs SSU2 identiques. En particulier, toutes doivent contenir la même clé statique “s” et clé d’introduction “i”.

Introducers

Lorsque publié en tant que SSU ou SSU2 avec des introducers, les options suivantes sont présentes :

  • ih[0-2]=(Base64 hash) Un hachage de router pour un introducer. Encodé en Base 64 en utilisant l’alphabet I2P Base 64 standard. 32 octets en binaire, 44 octets encodé en Base 64

  • iexp[0-2]: Expiration de cet introducer. Inchangé depuis SSU 1.

  • itag[0-2]: Tag de l’introducer 1 - (2**32 - 1) Inchangé depuis SSU 1.

Les options suivantes sont uniquement pour SSU et ne sont pas utilisées pour SSU2. Dans SSU2, Alice obtient cette information depuis le RI de Charlie à la place.

  • ihost[0-2]
  • ikey[0-2]
  • itag[0-2]

Un router ne doit pas publier l’hôte ou le port dans l’adresse lors de la publication d’introducers. Un router doit publier les capacités 4 et/ou 6 dans l’adresse lors de la publication d’introducers pour indiquer la prise en charge d’IPv4 et/ou IPv6. Ceci est identique à la pratique actuelle pour les adresses SSU 1 récentes.

Note : Si publié en tant que SSU, et qu’il y a un mélange d’introducers SSU 1 et SSU2, les introducers SSU 1 devraient être aux indices inférieurs et les introducers SSU2 devraient être aux indices supérieurs, pour la compatibilité avec les anciens routers.

Unpublished SSU2 Address

Si Alice ne publie pas son adresse SSU2 (en tant que « SSU » ou « SSU2 ») pour les connexions entrantes, elle doit publier une adresse de routeur « SSU2 » contenant uniquement sa clé statique et sa version SSU2, afin que Bob puisse valider la clé après avoir reçu le RouterInfo d’Alice dans la partie 2 de Session Confirmed.

  • s=(Clé Base64) Comme défini ci-dessus pour les adresses publiées.

  • i=(Clé Base64) Comme défini ci-dessus pour les adresses publiées.

  • v=2 Comme défini ci-dessus pour les adresses publiées.

Cette adresse de routeur ne contiendra pas les options “host” ou “port”, car celles-ci ne sont pas requises pour les connexions SSU2 sortantes. Le coût publié pour cette adresse n’a pas strictement d’importance, car elle est uniquement entrante ; cependant, il peut être utile aux autres routeurs si le coût est défini plus élevé (priorité plus faible) que les autres adresses. La valeur suggérée est 14.

Alice peut aussi simplement ajouter les options “i”, “s” et “v” à une adresse “SSU” publiée existante.

Intégrité des Paquets

L’utilisation des mêmes clés statiques pour NTCP2 et SSU2 est autorisée, mais non recommandée.

En raison de la mise en cache des RouterInfos, les routeurs ne doivent pas faire de rotation de la clé publique statique ou de l’IV pendant que le routeur est actif, qu’il soit dans une adresse publiée ou non. Les routeurs doivent stocker de manière persistante cette clé et cet IV pour les réutiliser après un redémarrage immédiat, afin que les connexions entrantes continuent de fonctionner et que les temps de redémarrage ne soient pas exposés. Les routeurs doivent stocker de manière persistante, ou déterminer autrement, l’heure du dernier arrêt, afin que le temps d’arrêt précédent puisse être calculé au démarrage.

Sous réserve des préoccupations concernant l’exposition des heures de redémarrage, les routeurs peuvent faire tourner cette clé ou IV au démarrage si le routeur était précédemment arrêté pendant un certain temps (plusieurs jours au moins).

Si le routeur a des RouterAddresses SSU2 publiées (en tant que SSU ou SSU2), le temps d’arrêt minimum avant la rotation devrait être beaucoup plus long, par exemple un mois, sauf si l’adresse IP locale a changé ou si le routeur effectue un “rekeys”.

Si le routeur a des SSU RouterAddresses publiées, mais pas SSU2 (en tant que SSU ou SSU2), le temps d’arrêt minimum avant la rotation devrait être plus long, par exemple un jour, sauf si l’adresse IP locale a changé ou si le routeur “rekeys”. Ceci s’applique même si l’adresse SSU publiée a des introducers.

Si le routeur n’a pas de RouterAddresses publiées (SSU, SSU2, ou SSU), le temps d’arrêt minimum avant la rotation peut être aussi court que deux heures, même si l’adresse IP change, sauf si le routeur effectue un “rekeys”.

Si le router “rekeys” vers un Router Hash différent, il devrait également générer une nouvelle clé noise et une nouvelle clé intro.

Les implémentations doivent être conscientes que modifier la clé publique statique ou l’IV empêchera les connexions SSU2 entrantes des routeurs qui ont mis en cache une RouterInfo plus ancienne. La publication de RouterInfo, la sélection des pairs de tunnel (incluant à la fois OBGW et le saut le plus proche IB), la sélection de tunnel à zéro saut, la sélection de transport, et autres stratégies d’implémentation doivent prendre cela en compte.

La rotation des clés d’introduction est soumise aux mêmes règles que la rotation des clés.

Note : La durée d’arrêt minimale avant le renouvellement des clés peut être modifiée pour assurer la santé du réseau et pour empêcher le reseeding par un router arrêté pendant une durée modérée.

Identity Hiding

La déniabilité n’est pas un objectif. Voir l’aperçu ci-dessus.

Chaque modèle se voit attribuer des propriétés décrivant la confidentialité fournie à la clé publique statique de l’initiateur, et à la clé publique statique du répondeur. Les hypothèses sous-jacentes sont que les clés privées éphémères sont sécurisées, et que les parties interrompent la négociation si elles reçoivent une clé publique statique de l’autre partie en laquelle elles n’ont pas confiance.

Cette section considère uniquement la fuite d’identité par le biais des champs de clé publique statiques dans les handshakes. Bien sûr, les identités des participants Noise pourraient être exposées par d’autres moyens, notamment les champs de charge utile, l’analyse de trafic, ou les métadonnées telles que les adresses IP.

Alice : (8) Chiffré avec confidentialité persistante vers une partie authentifiée.

Bob: (3) Non transmise, mais un attaquant passif peut vérifier des candidats pour la clé privée du répondeur et déterminer si le candidat est correct.

Bob publie sa clé publique statique dans la netDb. Alice peut ne pas le faire, mais doit l’inclure dans le RI envoyé à Bob.

Packet Guidelines

Chiffrement authentifié

Messages d’établissement de connexion (Session Request/Created/Confirmed, Retry) étapes de base, dans l’ordre :

  • Créer un en-tête de 16 ou 32 octets
  • Créer la charge utile
  • mixHash() l’en-tête (sauf pour Retry)
  • Chiffrer la charge utile en utilisant Noise (sauf pour Retry, utiliser ChaChaPoly avec l’en-tête comme AD)
  • Chiffrer l’en-tête, et pour Session Request/Created, la clé éphémère

Étapes de base des messages de phase de données, dans l’ordre :

  • Créer un en-tête de 16 octets
  • Créer la charge utile
  • Chiffrer la charge utile en utilisant ChaChaPoly avec l’en-tête comme AD
  • Chiffrer l’en-tête

Inbound Packet Handling

Charge utile

Traitement initial de tous les messages entrants :

  • Déchiffrer les 8 premiers octets de l’en-tête (le Destination Connection ID) avec la clé intro
  • Rechercher la connexion par le Destination Connection ID
  • Si la connexion est trouvée et est en phase de données, aller à la section phase de données
  • Si la connexion n’est pas trouvée, aller à la section handshake
  • Remarque : Les messages Peer Test et Hole Punch peuvent également être recherchés par le Destination Connection ID créé à partir du nonce de test ou de relais.

Traitement des messages de handshake (Session Request/Created/Confirmed, Retry, Token Request) et autres messages hors session (Peer Test, Hole Punch) :

  • Déchiffrer les octets 8-15 de l’en-tête (le type de paquet, la version et l’ID réseau) avec la clé intro. Si c’est une Session Request, Token Request, Peer Test ou Hole Punch valide, continuer
  • Si ce n’est pas un message valide, rechercher une connexion sortante en attente par l’IP/port source du paquet, traiter le paquet comme un Session Created ou Retry. Re-déchiffrer les 8 premiers octets de l’en-tête avec la clé correcte, et les octets 8-15 de l’en-tête (le type de paquet, la version et l’ID réseau). Si c’est un Session Created ou Retry valide, continuer
  • Si ce n’est pas un message valide, échouer, ou mettre en file d’attente comme possible paquet de phase de données hors séquence
  • Pour Session Request/Created, Retry, Token Request, Peer Test et Hole Punch, déchiffrer les octets 16-31 de l’en-tête
  • Pour Session Request/Created, déchiffrer la clé éphémère
  • Valider tous les champs de l’en-tête, arrêter si non valide
  • mixHash() l’en-tête
  • Pour Session Request/Created/Confirmed, déchiffrer la charge utile en utilisant Noise
  • Pour Retry et la phase de données, déchiffrer la charge utile en utilisant ChaChaPoly
  • Traiter l’en-tête et la charge utile

Traitement des messages de phase de données :

  • Déchiffrer les octets 8-15 de l’en-tête (le type de paquet, la version et l’ID réseau) avec la clé correcte
  • Déchiffrer la charge utile en utilisant ChaChaPoly avec l’en-tête comme AD
  • Traiter l’en-tête et la charge utile

Details

Dans SSU 1, la classification des paquets entrants est difficile, car il n’y a pas d’en-tête pour indiquer le numéro de session. Les routeurs doivent d’abord faire correspondre l’IP source et le port à un état de pair existant, et si aucun n’est trouvé, tenter plusieurs déchiffrements avec différentes clés pour trouver l’état de pair approprié ou en démarrer un nouveau. Dans le cas où l’IP source ou le port d’une session existante change, possiblement à cause du comportement NAT, le routeur peut utiliser des heuristiques coûteuses pour tenter de faire correspondre le paquet à une session existante et récupérer le contenu.

SSU 2 est conçu pour minimiser l’effort de classification des paquets entrants tout en maintenant une résistance au DPI et autres menaces sur le chemin. Le numéro Connection ID est inclus dans l’en-tête pour tous les types de messages, et chiffré (obfusqué) en utilisant ChaCha20 avec une clé et un nonce connus. De plus, le type de message est également inclus dans l’en-tête (chiffré avec protection d’en-tête vers une clé connue puis obfusqué avec ChaCha20) et peut être utilisé pour une classification supplémentaire. En aucun cas un DH d’essai ou une autre opération cryptographique asymétrique n’est nécessaire pour classifier un paquet.

Pour presque tous les messages de tous les pairs, la clé ChaCha20 pour le chiffrement de l’ID de connexion est la clé d’introduction du routeur de destination telle que publiée dans la netDb.

Les seules exceptions sont les premiers messages envoyés de Bob à Alice (Session Created ou Retry) où la clé d’introduction d’Alice n’est pas encore connue de Bob. Dans ces cas, la clé d’introduction de Bob est utilisée comme clé.

Le protocole est conçu pour minimiser le traitement de classification des paquets qui pourrait nécessiter des opérations cryptographiques supplémentaires dans plusieurs étapes de repli ou des heuristiques complexes. De plus, la grande majorité des paquets reçus ne nécessiteront pas une recherche de repli (potentiellement coûteuse) par IP/port source et un second déchiffrement d’en-tête. Seuls Session Created et Retry (et possiblement d’autres à déterminer) nécessiteront le traitement de repli. Si un point de terminaison change d’IP ou de port après la création de session, l’ID de connexion est toujours utilisé pour rechercher la session. Il n’est jamais nécessaire d’utiliser des heuristiques pour trouver la session, par exemple en cherchant une session différente avec la même IP mais un port différent.

Par conséquent, les étapes de traitement recommandées dans la logique de boucle du récepteur sont :

  1. Déchiffrer les 8 premiers octets avec ChaCha20 en utilisant la clé d’introduction locale, pour récupérer le Destination Connection ID. Si le Connection ID correspond à une session entrante actuelle ou en attente :

a) En utilisant la clé appropriée, déchiffrer les octets d’en-tête 8-15

  to recover the version, net ID, and message type.

b) Si le type de message est Session Confirmed, il s’agit d’un en-tête long.

  Verify the net ID and protocol version are valid.
  Decrypt the bytes 15-31 of the header with ChaCha20
  using the local intro key. Then MixHash() the
  decrypted 32 byte header and decrypt the message with Noise.

c) Si le type de message est valide mais n’est pas Session Confirmed,

  it is a short header.
  Verify the net ID and protocol version are valid.
  decrypt the rest of the message with ChaCha20/Poly1305
  using the session key, using the decrypted 16-byte header
  as the AD.

d) (optionnel) Si l’ID de connexion est une session entrante en attente

  awaiting a Session Confirmed message,
  but the net ID, protocol, or message type is not valid,
  it could be a Data message received out-of-order before the
  Session Confirmed, so the data phase header protection keys are not yet known,
  and the header bytes 8-15 were incorrectly decrypted.
  Queue the message, and attempt to decrypt it once the
  Session Confirmed message is received.

e) Si b) ou c) échoue, abandonner le message.

  1. Si l’ID de connexion ne correspond pas à une session actuelle : Vérifier que l’en-tête en clair aux octets 8-15 est valide (sans effectuer d’opération de protection d’en-tête). Vérifier que l’ID réseau et la version du protocole sont valides, et que le type de message est Session Request, ou autre type de message autorisé hors session (TBD).

a) Si tout est valide et que le type de message est Session Request,

  decrypt bytes 16-31 of the header and the 32-byte X value
  with ChaCha20 using the local intro key.
  • Si le token aux octets d’en-tête 24-31 est accepté, alors MixHash() l’en-tête de 32 octets déchiffré et déchiffrer le message avec Noise. Envoyer une Session Created en réponse.
    • Si le token n’est pas accepté, envoyer un message Retry à l’IP/port source avec un token. Ne pas tenter de déchiffrer le message avec Noise pour éviter les attaques DDoS.

b) Si le type de message est un autre message qui est valide

  out-of-session, presumably with a short header,
  decrypt the rest of the message with ChaCha20/Poly1305
  using the intro key, and using the decrypted 16-byte header
  as the AD. Process the message.

c) Si a) ou b) échoue, aller à l’étape 3)

  1. Rechercher une session sortante en attente par l’adresse IP/port source du paquet.

a) Si trouvé, re-déchiffrer les 8 premiers octets avec ChaCha20 en utilisant la clé d’introduction de Bob

  to recover the Destination Connection ID.

b) Si l’ID de connexion correspond à la session en attente :

  Using the correct key, decrypt bytes 8-15 of the header
  to recover the version, net ID, and message type.
  Verify the net ID and protocol version are valid, and
  the message type is Session Created or Retry, or other message type
  allowed out-of-session (TBD).
  • Si tout est valide et que le type de message est Session Created, déchiffrer les 16 octets suivants de l’en-tête et la valeur Y de 32 octets avec ChaCha20 en utilisant la clé intro de Bob. Puis MixHash() l’en-tête déchiffré de 32 octets et déchiffrer le message avec Noise. Envoyer un Session Confirmed en réponse.

    • Si tout est valide et que le type de message est Retry, déchiffrer les octets 16-31 de l’en-tête avec ChaCha20 en utilisant la clé intro de Bob. Déchiffrer et valider le message en utilisant ChaCha20/Poly1305 avec TBD comme clé et TBD comme nonce et l’en-tête déchiffré de 32 octets comme AD. Renvoyer un Session Request avec le jeton reçu en réponse.
    • Si le type de message est un autre message qui est valide hors session, probablement avec un en-tête court, déchiffrer le reste du message avec ChaCha20/Poly1305 en utilisant la clé intro, et en utilisant l’en-tête déchiffré de 16 octets comme AD. Traiter le message.

    c) If a pending outbound session is not found, or the connection ID does not match the pending session, drop the message, unless the port is shared with SSU 1.

  1. Si SSU 1 s’exécute sur le même port, tentez de traiter le message comme un paquet SSU 1.

Error Handling

En général, une session (en phase de handshake ou de données) ne devrait jamais être détruite après avoir reçu un paquet avec un type de message inattendu. Cela empêche les attaques par injection de paquets. Ces paquets seront également couramment reçus après la retransmission d’un paquet de handshake, lorsque les clés de déchiffrement d’en-tête ne sont plus valides.

Dans la plupart des cas, il suffit d’abandonner le paquet. Une implémentation peut, mais n’est pas tenue de, retransmettre le paquet précédemment envoyé (message de handshake ou ACK 0) en réponse.

Après avoir envoyé Session Created en tant que Bob, les paquets inattendus sont généralement des paquets Data qui ne peuvent pas être déchiffrés car les paquets Session Confirmed ont été perdus ou reçus dans le désordre. Mettez les paquets en file d’attente et tentez de les déchiffrer après avoir reçu les paquets Session Confirmed.

Après avoir reçu Session Confirmed en tant que Bob, les paquets inattendus sont généralement des paquets Session Confirmed retransmis, parce que l’ACK 0 du Session Confirmed a été perdu. Les paquets inattendus peuvent être abandonnés. Une implémentation peut, mais n’est pas tenue de, envoyer un paquet Data contenant un bloc ACK en réponse.

Notes

Pour Session Created et Session Confirmed, les implémentations doivent soigneusement valider tous les champs d’en-tête déchiffrés (Connection IDs, numéro de paquet, type de paquet, version, id, frag, et flags) AVANT d’appeler mixHash() sur l’en-tête et de tenter de déchiffrer la charge utile avec Noise AEAD. Si le déchiffrement Noise AEAD échoue, aucun traitement supplémentaire ne peut être effectué, car mixHash() aura corrompu l’état de la négociation, à moins qu’une implémentation stocke et “annule” l’état de hachage.

Version Detection

Il pourrait ne pas être possible de détecter efficacement si les paquets entrants sont de version 1 ou 2 sur le même port d’entrée. Les étapes ci-dessus peuvent avoir du sens à effectuer avant le traitement SSU 1, pour éviter de tenter des opérations DH d’essai en utilisant les deux versions de protocole.

À déterminer si nécessaire.

  • Délai d’expiration de retransmission de handshake sortant : 1,25 seconde, avec backoff exponentiel (retransmissions à 1,25, 3,75 et 8,75 secondes)
  • Délai d’expiration total de handshake sortant : 15 secondes
  • Délai d’expiration de retransmission de handshake entrant : 1 seconde, avec backoff exponentiel (retransmissions à 1, 3 et 7 secondes)
  • Délai d’expiration total de handshake entrant : 12 secondes
  • Délai d’expiration après envoi de retry : 9 secondes
  • Délai ACK : max(10, min(rtt/6, 150)) ms
  • Délai ACK immédiat : min(rtt/16, 5) ms
  • Plages ACK max : 256 ?
  • Profondeur ACK max : 512 ?
  • Distribution de padding : 0-15 octets, ou plus

Variants, Fallbacks, and General Issues

À déterminer

Packet Overhead Analysis

Suppose IPv4, sans inclure le rembourrage supplémentaire, sans inclure les tailles d’en-têtes IP et UDP. Le rembourrage est un rembourrage mod-16 pour SSU 1 uniquement.

SSU 1

MessageHeader+MACKeysDataPaddingTotalNotes
Session Request4025653304Incl.
Session Created37256791336Incl.
Session Confirmed3746213512Incl.
Data (RI)3710141051Incl.
Data (1 full msg)371451Incl.
Total2254
SSU 2
MessageHeader+MACsKeysDataPaddingTotalNotes
Session Request4832787DateTi
Session Created48321696DateTi
Session Confirmed4832100510851000 b
Data (1 full msg)321446
Total1314
TODO SAUF SI la taille minimale de paquet dans Session Request et Created est appliquée pour PMTU.