Status
Rollout-Plan:
| Feature | Testing (not default) | Enabled by default |
|---|---|---|
| Local test code | 2022-02 | |
| Joint test code | 2022-03 | |
| Joint test in-net | 0.9.54 2022-05 | |
| Freeze basic protocol | 0.9.54 2022-05 | |
| Basic Session | 0.9.55 2022-08 | 0.9.56 2022-11 |
| Address Validation (Retry) | 0.9.55 2022-08 | 0.9.56 2022-11 |
| Fragmented RI in handshake | 0.9.55 2022-08 | 0.9.56 2022-11 |
| New Token | 0.9.55 2022-08 | 0.9.57 2022-11 |
| Freeze extended protocol | 0.9.55 2022-08 | |
| Relay | 0.9.55 2022-08 | 0.9.56 2022-11 |
| Peer Test | 0.9.55 2022-08 | 0.9.56 2022-11 |
| Enable for random 2% | 0.9.55 2022-08 | |
| Path Validation | 0.9.55+ dev | 0.9.56 2022-11 |
| Connection Migration | 0.9.55+ dev | 0.9.56 2022-11 |
| Immediate ACK flag | 0.9.55+ dev | 0.9.56 2022-11 |
| Key Rotation | 0.9.57 2023-02 | 0.9.58 2023-05 |
| Disable SSU 1 (i2pd) | 0.9.56 2022-11 | |
| Disable SSU 1 (Java I2P) | 0.9.58 2023-05 | 0.9.61 2023-12 |
| Eine grundlegende Session umfasst die Handshake- und Datenphase. Das erweiterte Protokoll beinhaltet Relay und Peer-Test. |
Überblick
Dieser Vorschlag beschreibt ein authentifiziertes Schlüsselaustauschprotokoll zur Verbesserung der Widerstandsfähigkeit von SSU gegen verschiedene Formen der automatisierten Identifikation und Angriffe.
Der Vorschlag ist wie folgt strukturiert: die Sicherheitsziele werden dargestellt, gefolgt von einer Diskussion des grundlegenden Protokolls. Anschließend wird eine vollständige Spezifikation aller Protokollnachrichten gegeben. Schließlich werden Router-Adressen und Versionsidentifikation besprochen.
Wie bei anderen I2P-Transportprotokollen ist SSU2 für den Punkt-zu-Punkt-Transport (Router-zu-Router) von I2NP-Nachrichten definiert. Es ist kein Mehrzweck-Datenkanal. Wie SSU bietet es auch zwei zusätzliche Dienste: Relaying für NAT-Traversierung und Peer Testing zur Bestimmung der eingehenden Erreichbarkeit. Es bietet auch einen dritten Dienst, der in SSU nicht vorhanden ist, für Verbindungsmigration, wenn ein Peer IP oder Port wechselt.
Motivation
SSU ist die einzige verbleibende Protokollschicht, die ElGamal erfordert, welches sehr langsam ist. Die Flusskontrolle für SSU ist komplex und funktioniert nicht gut. Teile von SSU sind anfällig für Address-Spoofing-Angriffe. Der Handshake verwendet nicht Noise.
Designziele
CPU-Verbrauch durch Eliminierung von ElGamal reduzieren. X25519 für den DH verwenden.
Behalten Sie die Peer Test- und Relay-Funktionen bei und erhöhen Sie deren Sicherheit.
Macht die Implementierung einfacher, indem sie Standard-Flusskontrollalgorithmen ermöglicht.
Setup-Latenz reduzieren. Die mittlere Setup-Zeit beträgt derzeit etwa 135 ms für NTCP2 und 187 ms für SSU, obwohl NTCP2 einen zusätzlichen Round Trip hat; das Ersetzen von ElGamal in SSU2 sollte diese reduzieren, aber auch andere Änderungen könnten helfen.
Durchsatz beibehalten oder erhöhen im Vergleich zu SSU 1, gemessen über eine Reihe von simulierten Latenzen und Paketverlust-Prozentsätzen in einem Testnetz.
Verhindert Traffic-Amplifikation und Fehlrouting-Angriffe durch gefälschte Quelladressen mittels “address validation”.
Paketidentifikation vereinfachen, um die Abhängigkeit von Fallback-Mechanismen und Heuristiken zu reduzieren, die den Code übermäßig komplex machen.
Formalisierung und Verbesserung der Verbindungsmigration, wenn sich die IP oder der Port des Peers ändert. Migriere Verbindungen nicht, bis die Adressvalidierung abgeschlossen ist, um Angriffe zu verhindern. Einige SSU 1 Implementierungen verwenden teure Heuristiken zur Behandlung von Port-Änderungen aufgrund von NAT-Rebinding. Keine bekannten SSU 1 Implementierungen können IP-Änderungen überhaupt handhaben.
Unterstütze SSU 1 und 2 auf einem einzelnen Port, automatische Erkennung, und veröffentlicht als ein einziger “Transport” (d.h. RouterAddress) in der NetDB.
Veröffentliche Unterstützung für nur Version 1, nur 2, oder 1+2 in der NetDB in einem separaten Feld, und standardmäßig nur Version 1 (binde die Versionsunterstützung nicht an eine bestimmte Router-Version)
Sicherstellen, dass alle Implementierungen (Java/i2pd/Go) Version 2-Unterstützung nach ihrem eigenen Zeitplan hinzufügen können (oder auch nicht)
Füge zufällige Auffüllung zu allen Nachrichten hinzu, einschließlich Handshake- und Datennachrichten. Alle Auffüllung muss durch den MAC abgedeckt sein, im Gegensatz zur End-of-Packet-Auffüllung in SSU 1. Stelle einen Optionsmechanismus bereit, damit beide Seiten minimale und maximale Auffüllung und/oder Auffüllungsverteilung anfordern können. Die Spezifika der Auffüllungsverteilung sind implementierungsabhängig und können in dem Protokoll selbst spezifiziert sein oder auch nicht.
Verschleiere die Header und Inhalte von Nachrichten, die nicht vollständig verschlüsselt sind, ausreichend, damit DPI-Boxen und AV-Signaturen sie nicht einfach klassifizieren können. Stelle außerdem sicher, dass die Nachrichten, die an einen einzelnen Peer oder eine Gruppe von Peers gehen, kein ähnliches Bitmuster aufweisen.
Behebung des Bitverlusts in DH aufgrund des Java-Formats Ticket1112, und Beschleunigung des DH durch Umstellung auf X25519.
Wechseln zu einer echten Schlüsselableitungsfunktion (KDF) anstatt das DH-Ergebnis direkt zu verwenden
“Probing resistance” hinzufügen (wie Tor es nennt); dies umfasst replay resistance.
2-Wege-authentifizierten Schlüsselaustausch (2W-AKE) beibehalten. 1W-AKE ist für unsere Anwendung nicht ausreichend.
Verlassen Sie sich auf den statischen öffentlichen Schlüssel, der in der RouterInfo veröffentlicht wird, als weiteren Teil der Authentifizierung.
Optionen/Version im Handshake für zukünftige Erweiterbarkeit hinzufügen.
Füge nicht signifikant zur für den Verbindungsaufbau erforderlichen CPU hinzu; reduziere sie wenn möglich erheblich.
Entfernung der Anforderung für Padding auf ein Vielfaches von 16 Bytes, die durch AES-Verschlüsselung in SSU 1 auferlegt wurde.
Verwende Standard ChaCha/Poly1305 für Verschlüsselung und MAC, um die AES-Verschlüsselung und den nicht-standardmäßigen HMAC-MD5-128 MAC aus SSU 1 zu ersetzen.
Verwende separate Verschlüsselungsschlüssel für Senden und Empfangen, anstatt der gemeinsamen Schlüssel für beide Richtungen, die in SSU 1 verwendet werden.
Verwende einen 3-Nachrichten-, Ein-Roundtrip-Handshake, wie in NTCP2. Entferne die Verzögerung beim Warten auf Datennachrichten, die SSU effektiv zu einem Zwei-Roundtrip-Handshake macht.
Dramatische Verbesserung der Effizienz von ACKs und NACKs, die in SSU 1 schrecklich ist. Reduzierung der für ACKs und NACKs erforderlichen Bandbreite und Erhöhung der für Daten verfügbaren Paketgröße. Effiziente Kodierung von NACKs für einen Burst fehlender Nachrichten, was über WiFi häufig vorkommt.
Reduziere die Komplexität, die für die Implementierung der I2NP-Nachrichtenfragmentierung erforderlich ist. Umgehe Fragmentierungsmechanismen und Codierung für vollständige I2NP-Nachrichten.
Minimiere den Protokoll-Overhead vor dem Padding, insbesondere für ACKs. Obwohl Padding hinzugefügt wird, ist Overhead vor dem Padding dennoch Overhead. Knoten mit geringer Bandbreite müssen SSU2 verwenden können.
Zeitstempel für Replay- und Skew-Erkennung verwalten.
Vermeiden Sie alle Probleme mit dem Jahr 2038 bei Zeitstempeln, muss mindestens bis 2106 funktionieren.
Erhöhe die minimale MTU von 620 auf 1280 für mehr Effizienz, einfachere Implementierung und Vergrößerung der maximalen I2NP-Nachrichtengröße. Fragmentierung und Wiederzusammensetzung sind sehr kostspielig. Durch die Bereitstellung von Platz für 1028 Byte große Tunnel-Nachrichten wird die große Mehrheit der I2NP- Nachrichten keine Fragmentierung benötigen.
Erhöhe die maximale MTU von 1488 (1484 für IPv6) auf 1500 für bessere Effizienz. Entferne die Anforderung, dass die MTU ein Vielfaches von 16 sein muss.
Erhöhen der maximalen I2NP-Nachrichtengröße von etwa 32K in SSU 1 auf etwa 64 KB wie in NTCP2.
Entferne die Signatur der IP- und Port-Felder aus dem Handshake, damit router, die ihre externe IP und ihren Port nicht kennen, eine Verbindung herstellen können.
Behalten Sie den IP/Port-Erkennungsmechanismus von SSU 1 im Handshake bei, damit Router ihre externe IP und ihren Port erfahren können.
Beziehen Sie Vertreter von Java-, C++- und Go-router-Entwicklern in das Design ein.
Non-Goals
Kugelsichere DPI-Resistenz… das wären pluggable transports, Proposal 109.
Ein TLS-basierter (oder HTTPS-ähnlicher) Transport… das wäre Proposal 104.
Timing-basierte DPI-Resistenz (Inter-Message-Timing/Verzögerungen können implementierungsabhängig sein; Intra-Message-Verzögerungen können an jedem Punkt eingeführt werden, einschließlich vor dem Senden des zufälligen Paddings, zum Beispiel). Künstliche Verzögerungen (was obfs4 IAT oder Inter-Arrival-Time nennt) sind unabhängig vom Protokoll selbst.
Abstreitbarkeit der Teilnahme an einer Sitzung (es sind Signaturen enthalten).
Nicht-Ziele, die teilweise überdacht oder diskutiert werden können:
Der Grad des Schutzes gegen Deep Packet Inspection (DPI)
Post-Quantum (PQ) Sicherheit
Abstreitbarkeit
Security Goals
Wir betrachten drei Parteien:
- Alice, die eine neue Sitzung einrichten möchte.
- Bob, mit dem Alice eine Sitzung einrichten möchte.
- Mallory, der “Man in the Middle” zwischen Alice und Bob.
Höchstens zwei Teilnehmer können aktive Angriffe durchführen.
Alice und Bob besitzen beide ein statisches Schlüsselpaar, das in ihrer RouterIdentity enthalten ist.
Das vorgeschlagene Protokoll versucht, Alice und Bob zu ermöglichen, sich auf einen gemeinsamen geheimen Schlüssel (K) unter den folgenden Anforderungen zu einigen:
Sicherheit des privaten Schlüssels: weder Bob noch Mallory erfahren etwas über Alices statischen privaten Schlüssel. Symmetrisch dazu erfährt Alice nichts über Bobs statischen privaten Schlüssel.
Der Session-Key K ist nur Alice und Bob bekannt.
Perfect Forward Secrecy: Der vereinbarte Sitzungsschlüssel bleibt auch in Zukunft geheim, selbst wenn die statischen privaten Schlüssel von Alice und/oder Bob nach der Schlüsselvereinbarung preisgegeben werden.
Zweiseitige Authentifizierung: Alice ist sicher, dass sie eine Sitzung mit Bob etabliert hat, und umgekehrt.
Schutz gegen Online-DPI: Sicherstellen, dass es nicht trivial ist zu erkennen, dass Alice und Bob am Protokoll beteiligt sind, indem nur einfache Deep Packet Inspection (DPI) Techniken verwendet werden. Siehe unten.
Begrenzte Abstreitbarkeit: weder Alice noch Bob können die Teilnahme am Protokoll abstreiten, aber wenn einer von beiden den gemeinsamen Schlüssel preisgibt, kann die andere Partei die Authentizität des Inhalts der übertragenen Daten abstreiten.
Der vorliegende Vorschlag versucht, alle fünf Anforderungen basierend auf dem Station-To-Station (STS) Protokoll zu erfüllen. Beachten Sie, dass dieses Protokoll auch die Grundlage für das SSU Protokoll bildet.
Additional DPI Discussion
Wir nehmen zwei DPI-Komponenten an:
Online DPI
Online-DPI inspiziert alle Datenflüsse in Echtzeit. Verbindungen können blockiert oder anderweitig manipuliert werden. Verbindungsdaten oder Metadaten können identifiziert und für die Offline-Analyse gespeichert werden. Die Online-DPI hat keinen Zugang zur I2P-Netzwerkdatenbank. Die Online-DPI verfügt nur über begrenzte Echtzeit-Rechenkapazität, einschließlich Längenberechnung, Feldinspektion und einfache Berechnungen wie XOR. Die Online-DPI verfügt über die Fähigkeit schneller Echtzeit-Kryptographiefunktionen wie ChaCha20, AEAD und Hashing, aber diese wären zu kostspielig, um sie auf die meisten oder alle Datenflüsse anzuwenden. Jede Anwendung dieser kryptographischen Operationen würde nur auf Datenflüsse auf IP/Port-Kombinationen angewendet, die zuvor durch Offline-Analyse identifiziert wurden. Die Online-DPI verfügt nicht über die Fähigkeit aufwändiger kryptographischer Funktionen wie DH oder elligator2. Die Online-DPI ist nicht speziell für die Erkennung von I2P entwickelt, obwohl sie möglicherweise über begrenzte Klassifizierungsregeln für diesen Zweck verfügt.
Es ist ein Ziel, die Protokollidentifikation durch eine Online-DPI zu verhindern.
Der Begriff der Online- oder “direkten” DPI wird hier so verstanden, dass er die folgenden Angreiferfähigkeiten umfasst:
Die Fähigkeit, alle vom Ziel gesendeten oder empfangenen Daten zu inspizieren.
Die Fähigkeit, Operationen an den beobachteten Daten durchzuführen, wie etwa das Anwenden von Blockchiffren oder Hash-Funktionen.
Die Fähigkeit, zuvor gesendete Nachrichten zu speichern und mit ihnen zu vergleichen.
Die Fähigkeit, Pakete zu modifizieren, zu verzögern oder zu fragmentieren.
Jedoch wird angenommen, dass die Online-DPI die folgenden Einschränkungen hat:
Die Unmöglichkeit, IP-Adressen auf router-Hashes abzubilden. Während dies mit Echtzeitzugriff auf die Netzwerkdatenbank trivial wäre, würde es ein DPI-System erfordern, das speziell darauf ausgelegt ist, I2P anzugreifen.
Die Unfähigkeit, Timing-Informationen zur Erkennung des Protokolls zu verwenden.
Generell gesprochen enthält die Online-DPI-Toolbox keine integrierten Werkzeuge, die speziell für I2P-Erkennung entwickelt wurden. Dies schließt die Erstellung von “Honeypots” ein, die beispielsweise nicht-zufällige Polsterung in ihren Nachrichten enthalten würden. Beachten Sie, dass dies Machine-Learning-Systeme oder hochgradig konfigurierbare DPI-Tools nicht ausschließt, solange sie die anderen Anforderungen erfüllen.
Um Payload-Analyse entgegenzuwirken, wird sichergestellt, dass alle Nachrichten ununterscheidbar von zufälligen Daten sind. Dies erfordert auch, dass ihre Länge zufällig ist, was komplizierter ist als nur zufälliges Padding hinzuzufügen. Tatsächlich argumentieren die Autoren in Anhang A, dass ein naives (d.h. gleichmäßiges) Padding-Schema das Problem nicht löst. Anhang A schlägt daher vor, entweder zufällige Verzögerungen einzubauen oder ein alternatives Padding-Schema zu entwickeln, das angemessenen Schutz gegen den vorgeschlagenen Angriff bieten kann.
Um sich gegen den sechsten Punkt oben zu schützen, sollten Implementierungen zufällige Verzögerungen in das Protokoll einbauen. Solche Techniken werden von diesem Vorschlag nicht abgedeckt, könnten aber auch die Probleme mit der Padding-Länge lösen. Zusammenfassend bietet der Vorschlag guten Schutz gegen Payload-Analyse (wenn die Überlegungen in Anhang A berücksichtigt werden), aber nur begrenzten Schutz gegen Flow-Analyse.
Offline DPI
Offline-DPI untersucht Daten, die von der Online-DPI gespeichert wurden, für eine spätere Analyse. Die Offline-DPI kann speziell für die Erkennung von I2P entwickelt worden sein. Die Offline-DPI hat keinen Echtzeitszugriff auf die I2P-Netzwerkdatenbank. Die Offline-DPI hat Zugriff auf diese und andere I2P-Spezifikationen. Die Offline-DPI verfügt über unbegrenzte Rechenkapazität, einschließlich aller in dieser Spezifikation definierten kryptographischen Funktionen.
Die Offline-DPI hat nicht die Fähigkeit, bestehende Verbindungen zu blockieren. Die Offline-DPI hat die Fähigkeit, nahezu in Echtzeit (innerhalb von Minuten nach der Einrichtung) durch Paketinjektion an Host/Port von Parteien zu senden. Die Offline-DPI hat die Fähigkeit, nahezu in Echtzeit (innerhalb von Minuten nach der Einrichtung) vorherige Nachrichten (modifiziert oder nicht) für “Probing” oder andere Zwecke zu wiederholen.
Es ist nicht das Ziel, die Protokollidentifikation durch eine Offline-DPI zu verhindern. Alle Dekodierung von verschleierten Daten in den ersten beiden Nachrichten, die von I2P routern implementiert wird, kann auch von der Offline-DPI implementiert werden.
Es ist ein Ziel, versuchte Verbindungen abzulehnen, die eine Wiederholung vorheriger Nachrichten verwenden.
Address Validation
Das Folgende ist aus QUIC RFC 9000 kopiert. Für jeden Abschnitt überprüfen und bearbeiten.
Adressvalidierung stellt sicher, dass ein Endpunkt nicht für einen Traffic-Amplification-Angriff verwendet werden kann. Bei einem solchen Angriff wird ein Paket an einen Server gesendet, das gefälschte Quelladressinformationen enthält, die ein Opfer identifizieren. Wenn ein Server als Antwort auf dieses Paket größere oder mehr Pakete generiert, kann der Angreifer den Server nutzen, um mehr Daten an das Opfer zu senden, als er allein senden könnte.
Die primäre Verteidigung gegen Verstärkungsangriffe besteht darin, zu überprüfen, dass ein Peer in der Lage ist, Pakete an der Transportadresse zu empfangen, die er angibt. Daher MUSS ein Endpunkt, nachdem er Pakete von einer noch nicht validierten Adresse erhalten hat, die Menge der Daten, die er an die nicht validierte Adresse sendet, auf das Dreifache der von dieser Adresse empfangenen Datenmenge begrenzen. Diese Begrenzung der Antwortgröße wird als Anti-Amplification-Limit bezeichnet.
Die Adressvalidierung wird sowohl während der Verbindungsherstellung (siehe Abschnitt 8.1) als auch während der Verbindungsmigration (siehe Abschnitt 8.2) durchgeführt.
Address Validation during Connection Establishment
Die Verbindungsherstellung bietet implizit eine Adressvalidierung für beide Endpunkte. Insbesondere bestätigt der Empfang eines mit Handshake-Schlüsseln geschützten Pakets, dass der Peer ein Initial-Paket erfolgreich verarbeitet hat. Sobald ein Endpunkt ein Handshake-Paket vom Peer erfolgreich verarbeitet hat, kann er die Peer-Adresse als validiert betrachten.
Zusätzlich KANN ein Endpunkt die Peer-Adresse als validiert betrachten, wenn der Peer eine vom Endpunkt gewählte Verbindungs-ID verwendet und die Verbindungs-ID mindestens 64 Bits Entropie enthält.
Für den Client ermöglicht der Wert des Destination Connection ID-Feldes in seinem ersten Initial-Paket die Validierung der Serveradresse als Teil der erfolgreichen Verarbeitung jedes Pakets. Initial-Pakete vom Server sind mit Schlüsseln geschützt, die aus diesem Wert abgeleitet werden (siehe Abschnitt 5.2 von QUIC-TLS). Alternativ wird der Wert vom Server in Version Negotiation-Paketen (Abschnitt 6) zurückgegeben oder im Integrity Tag in Retry-Paketen eingefügt (Abschnitt 5.8 von QUIC-TLS).
Vor der Validierung der Client-Adresse DÜRFEN Server NICHT mehr als dreimal so viele Bytes senden, wie die Anzahl der Bytes, die sie empfangen haben. Dies begrenzt das Ausmaß jedes Verstärkungsangriffs, der unter Verwendung gefälschter Quelladressen durchgeführt werden kann. Um eine Verstärkung vor der Adressvalidierung zu vermeiden, MÜSSEN Server alle Payload-Bytes zählen, die in Datagrammen empfangen wurden, die eindeutig einer einzelnen Verbindung zugeordnet sind. Dies schließt Datagramme ein, die erfolgreich verarbeitete Pakete enthalten, und Datagramme, die Pakete enthalten, die alle verworfen werden.
Clients MÜSSEN sicherstellen, dass UDP-Datagramme, die Initial-Pakete enthalten, UDP-Payloads von mindestens 1200 Bytes haben und bei Bedarf PADDING-Frames hinzufügen. Ein Client, der gepolsterte Datagramme sendet, ermöglicht es dem Server, mehr Daten zu senden, bevor die Adressvalidierung abgeschlossen ist.
Der Verlust eines Initial- oder Handshake-Pakets vom Server kann zu einem Deadlock führen, wenn der Client keine zusätzlichen Initial- oder Handshake-Pakete sendet. Ein Deadlock könnte auftreten, wenn der Server sein Anti-Verstärkungslimit erreicht und der Client Bestätigungen für alle gesendeten Daten erhalten hat. In diesem Fall, wenn der Client keinen Grund hat, zusätzliche Pakete zu senden, wird der Server nicht in der Lage sein, weitere Daten zu senden, da er die Adresse des Clients nicht validiert hat. Um diesen Deadlock zu verhindern, MÜSSEN Clients ein Paket bei einem Probe Timeout (PTO) senden; siehe Abschnitt 6.2 von QUIC-RECOVERY. Konkret MUSS der Client ein Initial-Paket in einem UDP-Datagramm senden, das mindestens 1200 Bytes enthält, wenn er keine Handshake-Schlüssel hat, ansonsten ein Handshake-Paket senden.
Ein Server möchte möglicherweise die Client-Adresse validieren, bevor er den kryptographischen Handshake startet. QUIC verwendet ein Token im Initial-Paket, um eine Adressvalidierung vor Abschluss des Handshakes zu ermöglichen. Dieses Token wird dem Client während der Verbindungsherstellung mit einem Retry-Paket übermittelt (siehe Abschnitt 8.1.2) oder in einer vorherigen Verbindung unter Verwendung des NEW_TOKEN-Frames (siehe Abschnitt 8.1.3).
Zusätzlich zu den Sendebeschränkungen, die vor der Adressvalidierung auferlegt werden, sind Server auch durch die vom Congestion Controller festgelegten Limits eingeschränkt in dem, was sie senden können. Clients sind nur durch den Congestion Controller beschränkt.
Token Construction
Ein Token, das in einem NEW_TOKEN Frame oder einem Retry-Paket gesendet wird, MUSS so konstruiert werden, dass der Server identifizieren kann, wie es einem Client bereitgestellt wurde. Diese Token werden im selben Feld übertragen, erfordern aber eine unterschiedliche Behandlung durch die Server.
Address Validation Using Retry Packets
Nach Empfang des Initial-Pakets des Clients kann der Server eine Adressvalidierung anfordern, indem er ein Retry-Paket (Abschnitt 17.2.5) sendet, das ein Token enthält. Dieses Token MUSS vom Client in allen Initial-Paketen wiederholt werden, die er für diese Verbindung sendet, nachdem er das Retry-Paket erhalten hat.
Als Antwort auf die Verarbeitung eines Initial-Pakets, das ein Token enthält, welches in einem Retry-Paket bereitgestellt wurde, kann ein Server kein weiteres Retry-Paket senden; er kann die Verbindung nur ablehnen oder ihr Fortfahren erlauben.
Solange es für einen Angreifer nicht möglich ist, einen gültigen Token für seine eigene Adresse zu generieren (siehe Abschnitt 8.1.4) und der Client in der Lage ist, diesen Token zurückzugeben, beweist es dem Server, dass er den Token erhalten hat.
Ein Server kann auch ein Retry-Paket verwenden, um die Zustands- und Verarbeitungskosten der Verbindungsherstellung aufzuschieben. Die Anforderung, dass der Server eine andere Verbindungs-ID bereitstellt, zusammen mit dem in Abschnitt 18.2 definierten original_destination_connection_id Transport-Parameter, zwingt den Server zu demonstrieren, dass er oder eine mit ihm kooperierende Instanz das ursprüngliche Initial-Paket vom Client erhalten hat. Die Bereitstellung einer anderen Verbindungs-ID gewährt dem Server auch eine gewisse Kontrolle darüber, wie nachfolgende Pakete geroutet werden. Dies kann verwendet werden, um Verbindungen an eine andere Server-Instanz weiterzuleiten.
Wenn ein Server ein Client Initial empfängt, das ein ungültiges Retry-Token enthält, aber ansonsten gültig ist, weiß er, dass der Client kein weiteres Retry-Token akzeptieren wird. Der Server kann ein solches Paket verwerfen und dem Client erlauben, eine Zeitüberschreitung zu erreichen, um einen Handshake-Fehler zu erkennen, aber das könnte eine erhebliche Latenzstrafe für den Client bedeuten. Stattdessen SOLLTE der Server die Verbindung sofort schließen (Abschnitt 10.2) mit einem INVALID_TOKEN-Fehler. Beachten Sie, dass ein Server zu diesem Zeitpunkt noch keinen Zustand für die Verbindung etabliert hat und daher nicht in die Schließungsphase eintritt.
Ein Ablauf, der die Verwendung eines Retry-Pakets zeigt, ist in Abbildung 9 dargestellt.
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
Ein Server DARF Clients während einer Verbindung ein Adressvalidierungs-Token bereitstellen, das bei einer nachfolgenden Verbindung verwendet werden kann. Adressvalidierung ist besonders wichtig bei 0-RTT, da ein Server potenziell eine erhebliche Menge an Daten als Antwort auf 0-RTT-Daten an einen Client sendet.
Der Server verwendet den NEW_TOKEN Frame (Abschnitt 19.7), um dem Client ein Adressvalidierungs-Token bereitzustellen, das zur Validierung zukünftiger Verbindungen verwendet werden kann. In einer zukünftigen Verbindung fügt der Client dieses Token in Initial-Pakete ein, um eine Adressvalidierung zu ermöglichen. Der Client MUSS das Token in alle Initial-Pakete einschließen, die er sendet, es sei denn, ein Retry ersetzt das Token durch ein neueres. Der Client DARF das in einem Retry bereitgestellte Token NICHT für zukünftige Verbindungen verwenden. Server KÖNNEN jedes Initial-Paket verwerfen, das nicht das erwartete Token trägt.
Im Gegensatz zu dem Token, das für ein Retry-Paket erstellt und sofort verwendet wird, kann das im NEW_TOKEN-Frame gesendete Token nach Ablauf einer gewissen Zeit verwendet werden. Daher SOLLTE ein Token eine Ablaufzeit haben, die entweder eine explizite Ablaufzeit oder ein Ausstellungszeitstempel sein kann, der zur dynamischen Berechnung der Ablaufzeit verwendet werden kann. Ein Server kann die Ablaufzeit speichern oder sie in verschlüsselter Form im Token einschließen.
Ein mit NEW_TOKEN ausgestelltes Token DARF NICHT Informationen enthalten, die es einem Beobachter ermöglichen würden, Werte mit der Verbindung zu verknüpfen, auf der es ausgestellt wurde. Beispielsweise kann es nicht die vorherige Verbindungs-ID oder Adressierungsinformationen enthalten, es sei denn, die Werte sind verschlüsselt. Ein Server MUSS sicherstellen, dass jeder NEW_TOKEN Frame, den er sendet, für alle Clients eindeutig ist, mit Ausnahme derjenigen, die zur Reparatur von Verlusten zuvor gesendeter NEW_TOKEN Frames gesendet werden. Informationen, die es dem Server ermöglichen, zwischen Tokens von Retry und NEW_TOKEN zu unterscheiden, KÖNNEN für andere Entitäten als den Server zugänglich sein.
Es ist unwahrscheinlich, dass die Client-Port-Nummer bei zwei verschiedenen Verbindungen identisch ist; die Validierung des Ports wird daher wahrscheinlich nicht erfolgreich sein.
Ein Token, das in einem NEW_TOKEN-Frame empfangen wird, ist für jeden Server anwendbar, für den die Verbindung als autoritativ betrachtet wird (z.B. Servernamen, die im Zertifikat enthalten sind). Beim Verbinden zu einem Server, für den der Client einen anwendbaren und ungenutzten Token besitzt, SOLLTE er diesen Token in das Token-Feld seines Initial-Pakets einschließen. Das Einschließen eines Tokens könnte es dem Server ermöglichen, die Client-Adresse ohne eine zusätzliche Roundtrip-Zeit zu validieren. Ein Client DARF NICHT einen Token einschließen, der nicht auf den Server anwendbar ist, zu dem er sich verbindet, es sei denn, der Client hat das Wissen, dass der Server, der den Token ausgestellt hat, und der Server, zu dem sich der Client verbindet, die Tokens gemeinsam verwalten. Ein Client KANN einen Token von jeder vorherigen Verbindung zu diesem Server verwenden.
Ein Token ermöglicht es einem Server, Aktivitäten zwischen der Verbindung, bei der das Token ausgestellt wurde, und jeder Verbindung, bei der es verwendet wird, zu korrelieren. Clients, die die Kontinuität ihrer Identität mit einem Server unterbrechen möchten, können Tokens verwerfen, die über den NEW_TOKEN frame bereitgestellt wurden. Im Vergleich dazu MUSS ein Token, das in einem Retry-Paket erhalten wurde, sofort während des Verbindungsversuchs verwendet werden und kann nicht in nachfolgenden Verbindungsversuchen verwendet werden.
Ein Client SOLLTE NICHT ein Token aus einem NEW_TOKEN-Frame für verschiedene Verbindungsversuche wiederverwenden. Die Wiederverwendung eines Tokens ermöglicht es Entitäten im Netzwerkpfad, Verbindungen miteinander zu verknüpfen; siehe Abschnitt 9.5.
Clients können mehrere Token über eine einzige Verbindung erhalten. Abgesehen von der Verhinderung der Verknüpfbarkeit kann jeder Token bei jedem Verbindungsversuch verwendet werden. Server können zusätzliche Token senden, um entweder die Adressvalidierung für mehrere Verbindungsversuche zu ermöglichen oder ältere Token zu ersetzen, die möglicherweise ungültig werden könnten. Für einen Client bedeutet diese Mehrdeutigkeit, dass das Senden des neuesten ungenutzten Tokens am wahrscheinlichsten effektiv ist. Obwohl das Speichern und Verwenden älterer Token keine negativen Folgen hat, können Clients ältere Token als weniger wahrscheinlich nützlich für den Server zur Adressvalidierung betrachten.
Wenn ein Server ein Initial-Paket mit einem Adressvalidierungs-Token erhält, MUSS er versuchen, das Token zu validieren, es sei denn, er hat die Adressvalidierung bereits abgeschlossen. Wenn das Token ungültig ist, dann SOLLTE der Server so verfahren, als hätte der Client keine validierte Adresse, einschließlich des möglichen Versendens eines Retry-Pakets. Token, die mit NEW_TOKEN-Frames und Retry-Paketen bereitgestellt werden, können von Servern unterschieden werden (siehe Abschnitt 8.1.1), und letztere können strenger validiert werden. Wenn die Validierung erfolgreich ist, SOLLTE der Server dann den Handshake fortsetzen lassen.
Hinweis: Der Grund dafür, den Client als nicht validiert zu behandeln, anstatt das Paket zu verwerfen, ist, dass der Client das Token möglicherweise in einer vorherigen Verbindung über den NEW_TOKEN-Frame erhalten hat, und wenn der Server den Zustand verloren hat, könnte er das Token überhaupt nicht validieren können, was zu einem Verbindungsfehler führen würde, wenn das Paket verworfen wird.
In einem zustandslosen Design kann ein Server verschlüsselte und authentifizierte Token verwenden, um Informationen an Clients zu übertragen, die der Server später wiederherstellen und zur Validierung einer Client-Adresse nutzen kann. Token sind nicht in den kryptografischen Handshake integriert und daher nicht authentifiziert. Beispielsweise könnte ein Client möglicherweise ein Token wiederverwenden. Um Angriffe zu vermeiden, die diese Eigenschaft ausnutzen, kann ein Server die Verwendung von Token auf die Informationen beschränken, die zur Validierung von Client-Adressen erforderlich sind.
Clients KÖNNEN auf einer Verbindung erhaltene Token für jeden Verbindungsversuch mit derselben Version verwenden. Bei der Auswahl eines zu verwendenden Tokens müssen Clients keine anderen Eigenschaften der Verbindung berücksichtigen, die versucht wird, einschließlich der Auswahl möglicher Anwendungsprotokolle, Session-Tickets oder andere Verbindungseigenschaften.
Address Validation Token Integrity
Ein Adressvalidierungstoken MUSS schwer zu erraten sein. Die Einbeziehung eines Zufallswerts mit mindestens 128 Bit Entropie in dem Token wäre ausreichend, aber dies hängt davon ab, dass sich der Server den Wert merkt, den er an Clients sendet.
Ein token-basiertes Schema ermöglicht es dem Server, jeden mit der Validierung verbundenen Zustand an den Client auszulagern. Damit dieses Design funktioniert, MUSS der Token durch Integritätsschutz gegen Änderung oder Fälschung durch Clients abgesichert sein. Ohne Integritätsschutz könnten bösartige Clients Werte für Token generieren oder erraten, die vom Server akzeptiert würden. Nur der Server benötigt Zugriff auf den Integritätsschutz-Schlüssel für Token.
Es ist kein einheitlich definiertes Format für das Token erforderlich, da der Server, der das Token generiert, es auch verbraucht. Tokens, die in Retry-Paketen gesendet werden, SOLLTEN Informationen enthalten, die es dem Server ermöglichen zu überprüfen, dass die Quell-IP-Adresse und der Port in Client-Paketen konstant bleiben.
Tokens, die in NEW_TOKEN-Frames gesendet werden, MÜSSEN Informationen enthalten, die es dem Server ermöglichen zu überprüfen, dass sich die Client-IP-Adresse seit der Ausstellung des Tokens nicht geändert hat. Server können Tokens aus NEW_TOKEN-Frames verwenden, um zu entscheiden, kein Retry-Paket zu senden, auch wenn sich die Client-Adresse geändert hat. Wenn sich die Client-IP-Adresse geändert hat, MUSS der Server das Anti-Amplification-Limit einhalten; siehe Abschnitt 8. Beachten Sie, dass bei Vorhandensein von NAT diese Anforderung möglicherweise unzureichend ist, um andere Hosts, die sich das NAT teilen, vor Amplification-Angriffen zu schützen.
Angreifer könnten Tokens wiederverwenden, um Server als Verstärker in DDoS-Angriffen zu nutzen. Um sich gegen solche Angriffe zu schützen, MÜSSEN Server sicherstellen, dass die Wiederholung von Tokens verhindert oder begrenzt wird. Server SOLLTEN sicherstellen, dass Tokens, die in Retry-Paketen gesendet werden, nur für kurze Zeit akzeptiert werden, da sie von Clients sofort zurückgegeben werden. Tokens, die in NEW_TOKEN-Frames (Abschnitt 19.7) bereitgestellt werden, müssen länger gültig sein, SOLLTEN aber NICHT mehrfach akzeptiert werden. Server werden ermutigt, Tokens wenn möglich nur einmal verwenden zu lassen; Tokens KÖNNEN zusätzliche Informationen über Clients enthalten, um die Anwendbarkeit oder Wiederverwendung weiter einzuschränken.
Online DPI
Pfadvalidierung wird von beiden Peers während der Verbindungsmigration (siehe Abschnitt 9) verwendet, um die Erreichbarkeit nach einer Adressänderung zu überprüfen. Bei der Pfadvalidierung testen Endpunkte die Erreichbarkeit zwischen einer bestimmten lokalen Adresse und einer bestimmten Peer-Adresse, wobei eine Adresse das 2-Tupel aus IP-Adresse und Port ist.
Path-Validierungstests überprüfen, dass Pakete, die über einen Pfad zu einem Peer gesendet werden, von diesem Peer empfangen werden. Path-Validierung wird verwendet, um sicherzustellen, dass Pakete, die von einem migrierenden Peer empfangen werden, keine gefälschte Quelladresse enthalten.
Die Pfadvalidierung überprüft nicht, ob ein Peer in der Rückrichtung senden kann. Bestätigungen können nicht für die Rückpfadvalidierung verwendet werden, da sie unzureichende Entropie enthalten und möglicherweise gefälscht werden könnten. Endpunkte bestimmen die Erreichbarkeit in jede Richtung eines Pfades unabhängig voneinander, und daher kann die Rückerreichbarkeit nur durch den Peer selbst festgestellt werden.
Path-Validierung kann jederzeit von beiden Endpunkten verwendet werden. Beispielsweise könnte ein Endpunkt prüfen, ob ein Peer noch im Besitz seiner Adresse ist nach einer Zeit der Ruhe.
Pfadvalidierung ist nicht als NAT-Traversal-Mechanismus konzipiert. Obwohl der hier beschriebene Mechanismus für die Erstellung von NAT-Bindungen, die NAT-Traversal unterstützen, wirksam sein könnte, wird erwartet, dass ein Endpunkt Pakete empfangen kann, ohne zuvor ein Paket auf diesem Pfad gesendet zu haben. Effektives NAT-Traversal benötigt zusätzliche Synchronisationsmechanismen, die hier nicht bereitgestellt werden.
Ein Endpunkt KANN andere Frames zusammen mit den PATH_CHALLENGE- und PATH_RESPONSE-Frames einschließen, die für die Pfadvalidierung verwendet werden. Insbesondere kann ein Endpunkt PADDING-Frames mit einem PATH_CHALLENGE-Frame für die Path Maximum Transmission Unit Discovery (PMTUD) einschließen; siehe Abschnitt 14.2.1. Ein Endpunkt kann auch seinen eigenen PATH_CHALLENGE-Frame einschließen, wenn er einen PATH_RESPONSE-Frame sendet.
Ein Endpunkt verwendet eine neue Verbindungs-ID für Sonden, die von einer neuen lokalen Adresse gesendet werden; siehe Abschnitt 9.5. Beim Testen eines neuen Pfades kann ein Endpunkt sicherstellen, dass sein Peer eine ungenutzte Verbindungs-ID für Antworten verfügbar hat. Das Senden von NEW_CONNECTION_ID und PATH_CHALLENGE frames im selben Paket, falls das active_connection_id_limit des Peers es erlaubt, stellt sicher, dass eine ungenutzte Verbindungs-ID für den Peer beim Senden einer Antwort verfügbar sein wird.
Ein Endpoint kann wählen, gleichzeitig mehrere Pfade zu prüfen. Die Anzahl der gleichzeitigen Pfade, die für Prüfungen verwendet werden, ist durch die Anzahl der zusätzlichen Verbindungs-IDs begrenzt, die sein Peer zuvor bereitgestellt hat, da jede neue lokale Adresse, die für eine Prüfung verwendet wird, eine zuvor ungenutzte Verbindungs-ID erfordert.
Offline-DPI
Um die Pfadvalidierung zu initiieren, sendet ein Endpunkt einen PATH_CHALLENGE-Frame mit einer unvorhersagbaren Nutzlast auf dem zu validierenden Pfad.
Ein Endpunkt KANN mehrere PATH_CHALLENGE-Frames senden, um sich gegen Paketverlust abzusichern. Ein Endpunkt SOLLTE jedoch NICHT mehrere PATH_CHALLENGE-Frames in einem einzigen Paket senden.
Ein Endpunkt SOLLTE NICHT einen neuen Pfad mit Paketen, die einen PATH_CHALLENGE Frame enthalten, häufiger sondieren, als er ein Initial-Paket senden würde. Dies stellt sicher, dass Connection Migration nicht mehr Last auf einem neuen Pfad verursacht als das Aufbauen einer neuen Verbindung.
Der Endpunkt MUSS unvorhersagbare Daten in jedem PATH_CHALLENGE-Frame verwenden, damit er die Antwort des Peers mit dem entsprechenden PATH_CHALLENGE verknüpfen kann.
Ein Endpunkt MUSS Datagramme, die einen PATH_CHALLENGE Frame enthalten, auf mindestens die kleinste zulässige maximale Datagrammgröße von 1200 Bytes erweitern, es sei denn, das Anti-Amplification-Limit für den Pfad erlaubt nicht das Senden eines Datagramms dieser Größe. Das Senden von UDP-Datagrammen dieser Größe stellt sicher, dass der Netzwerkpfad vom Endpunkt zum Peer für QUIC verwendet werden kann; siehe Abschnitt 14.
Wenn ein Endpunkt nicht in der Lage ist, die Datagramm-Größe aufgrund der Anti-Verstärkungsgrenze auf 1200 Bytes zu erweitern, wird die Pfad-MTU nicht validiert. Um sicherzustellen, dass die Pfad-MTU groß genug ist, MUSS der Endpunkt eine zweite Pfadvalidierung durchführen, indem er einen PATH_CHALLENGE-Frame in einem Datagramm von mindestens 1200 Bytes sendet. Diese zusätzliche Validierung kann durchgeführt werden, nachdem eine PATH_RESPONSE erfolgreich empfangen wurde oder wenn genügend Bytes auf dem Pfad empfangen wurden, sodass das Senden des größeren Datagramms nicht zur Überschreitung der Anti-Verstärkungsgrenze führt.
Im Gegensatz zu anderen Fällen, in denen Datagramme erweitert werden, DÜRFEN Endpunkte Datagramme, die zu klein erscheinen, NICHT verwerfen, wenn sie PATH_CHALLENGE oder PATH_RESPONSE enthalten.
Path Validation Responses
Beim Empfang eines PATH_CHALLENGE frames MUSS ein Endpunkt antworten, indem er die im PATH_CHALLENGE frame enthaltenen Daten in einem PATH_RESPONSE frame zurücksendet. Ein Endpunkt DARF die Übertragung eines Pakets, das einen PATH_RESPONSE frame enthält, NICHT verzögern, es sei denn, er wird durch Congestion Control eingeschränkt.
Ein PATH_RESPONSE Frame MUSS auf dem Netzwerkpfad gesendet werden, auf dem der PATH_CHALLENGE Frame empfangen wurde. Dies stellt sicher, dass die Pfadvalidierung durch einen Peer nur erfolgreich ist, wenn der Pfad in beiden Richtungen funktionsfähig ist. Diese Anforderung DARF NICHT vom Endpunkt durchgesetzt werden, der die Pfadvalidierung initiiert, da dies einen Angriff auf die Migration ermöglichen würde; siehe Abschnitt 9.3.3.
Ein Endpunkt MUSS Datagramme, die einen PATH_RESPONSE-Frame enthalten, auf mindestens die kleinste erlaubte maximale Datagrammgröße von 1200 Bytes erweitern. Dies überprüft, dass der Pfad in der Lage ist, Datagramme dieser Größe in beide Richtungen zu übertragen. Ein Endpunkt DARF jedoch das Datagramm mit dem PATH_RESPONSE NICHT erweitern, wenn die resultierenden Daten das Anti-Amplification-Limit überschreiten würden. Dies wird voraussichtlich nur auftreten, wenn die empfangene PATH_CHALLENGE nicht in einem erweiterten Datagramm gesendet wurde.
Ein Endpunkt DARF NICHT mehr als einen PATH_RESPONSE Frame als Antwort auf einen PATH_CHALLENGE Frame senden; siehe Abschnitt 13.3. Es wird erwartet, dass der Peer bei Bedarf weitere PATH_CHALLENGE Frames sendet, um zusätzliche PATH_RESPONSE Frames hervorzurufen.
Adressvalidierung während der Verbindungsherstellung
Die Pfadvalidierung ist erfolgreich, wenn ein PATH_RESPONSE-Frame empfangen wird, der die Daten enthält, die in einem vorherigen PATH_CHALLENGE-Frame gesendet wurden. Ein PATH_RESPONSE-Frame, der auf einem beliebigen Netzwerkpfad empfangen wird, validiert den Pfad, auf dem der PATH_CHALLENGE gesendet wurde.
Wenn ein Endpunkt einen PATH_CHALLENGE Frame in einem Datagramm sendet, das nicht auf mindestens 1200 Bytes erweitert ist, und wenn die Antwort darauf die Peer-Adresse validiert, wird der Pfad validiert, aber nicht die Pfad-MTU. Infolgedessen kann der Endpunkt nun mehr als das Dreifache der Datenmenge senden, die empfangen wurde. Der Endpunkt MUSS jedoch eine weitere Pfadvalidierung mit einem erweiterten Datagramm initiieren, um zu überprüfen, dass der Pfad die erforderliche MTU unterstützt.
Der Empfang einer Bestätigung für ein Paket, das einen PATH_CHALLENGE-Frame enthält, ist keine ausreichende Validierung, da die Bestätigung von einem bösartigen Peer gefälscht werden kann.
Token-Konstruktion
Die Pfadvalidierung schlägt nur fehl, wenn der Endpunkt, der versucht den Pfad zu validieren, seinen Versuch der Pfadvalidierung aufgibt.
Endpunkte SOLLTEN die Pfadvalidierung basierend auf einem Timer aufgeben. Beim Setzen dieses Timers wird Implementierungen geraten, dass der neue Pfad eine längere Round-Trip-Zeit als der ursprüngliche haben könnte. Ein Wert von drei Mal dem größeren Wert aus der aktuellen PTO oder der PTO für den neuen Pfad (unter Verwendung von kInitialRtt, wie in QUIC-RECOVERY definiert) wird EMPFOHLEN.
Dieses Timeout ermöglicht es, dass mehrere PTOs ablaufen, bevor die Pfadvalidierung fehlschlägt, sodass der Verlust eines einzelnen PATH_CHALLENGE- oder PATH_RESPONSE-Frames nicht zum Scheitern der Pfadvalidierung führt.
Beachten Sie, dass der Endpoint möglicherweise Pakete mit anderen Frames auf dem neuen Pfad empfängt, aber ein PATH_RESPONSE Frame mit entsprechenden Daten ist erforderlich, damit die Pfadvalidierung erfolgreich ist.
Wenn ein Endpunkt die Pfadvalidierung aufgibt, bestimmt er, dass der Pfad nicht verwendbar ist. Dies impliziert nicht zwangsläufig einen Ausfall der Verbindung – Endpunkte können weiterhin Pakete über andere Pfade senden, wie es angemessen ist. Wenn keine Pfade verfügbar sind, kann ein Endpunkt warten, bis ein neuer Pfad verfügbar wird, oder die Verbindung schließen. Ein Endpunkt, der keinen gültigen Netzwerkpfad zu seinem Peer hat, KANN dies mit dem Verbindungsfehler NO_VIABLE_PATH signalisieren, wobei zu beachten ist, dass dies nur möglich ist, wenn der Netzwerkpfad existiert, aber die erforderliche MTU nicht unterstützt (Abschnitt 14).
Eine Pfadvalidierung kann aus anderen Gründen als einem Fehler abgebrochen werden. Dies geschieht hauptsächlich, wenn eine Verbindungsmigration zu einem neuen Pfad eingeleitet wird, während eine Pfadvalidierung auf dem alten Pfad noch läuft.
Connection Migration
Das Folgende ist aus QUIC RFC 9000 kopiert. Überprüfen und bearbeiten Sie jeden Abschnitt.
Die Verwendung einer Verbindungs-ID ermöglicht es Verbindungen, Änderungen an Endpunkt-Adressen (IP-Adresse und Port) zu überstehen, wie sie beispielsweise durch die Migration eines Endpunkts zu einem neuen Netzwerk verursacht werden. Dieser Abschnitt beschreibt den Prozess, durch den ein Endpunkt zu einer neuen Adresse migriert.
Das Design von QUIC basiert darauf, dass Endpunkte für die Dauer des Handshakes eine stabile Adresse beibehalten. Ein Endpunkt DARF NICHT eine Verbindungsmigration initiieren, bevor der Handshake bestätigt ist, wie in Abschnitt 4.1.2 von QUIC-TLS definiert.
Wenn der Peer den disable_active_migration Transportparameter gesendet hat, DARF ein Endpunkt auch KEINE Pakete (einschließlich Sondierungspakete; siehe Abschnitt 9.1) von einer anderen lokalen Adresse an die Adresse senden, die der Peer während des Handshakes verwendet hat, es sei denn, der Endpunkt hat auf einen preferred_address Transportparameter vom Peer reagiert. Wenn der Peer diese Anforderung verletzt, MUSS der Endpunkt entweder die eingehenden Pakete auf diesem Pfad ohne Erzeugung eines Stateless Reset verwerfen oder mit der Pfadvalidierung fortfahren und dem Peer die Migration erlauben. Die Erzeugung eines Stateless Reset oder das Schließen der Verbindung würde es Dritten im Netzwerk ermöglichen, Verbindungen durch Spoofing oder anderweitige Manipulation des beobachteten Verkehrs zum Schließen zu bringen.
Nicht alle Änderungen der Peer-Adresse sind beabsichtigte oder aktive Migrationen. Der Peer könnte NAT-Rebinding erfahren: eine Adressänderung aufgrund einer Middlebox, üblicherweise einem NAT, die einen neuen ausgehenden Port oder sogar eine neue ausgehende IP-Adresse für einen Flow zuweist. Ein Endpoint MUSS eine Pfadvalidierung (Abschnitt 8.2) durchführen, wenn er eine Änderung der Adresse eines Peers erkennt, es sei denn, er hat diese Adresse zuvor validiert.
Wenn ein Endpunkt keinen validierten Pfad hat, über den Pakete gesendet werden können, DARF er den Verbindungszustand verwerfen. Ein Endpunkt, der Connection Migration unterstützt, DARF warten, bis ein neuer Pfad verfügbar wird, bevor er den Verbindungszustand verwirft.
Dieses Dokument schränkt die Migration von Verbindungen zu neuen Client-Adressen ein, außer wie in Abschnitt 9.6 beschrieben. Clients sind für die Initiierung aller Migrationen verantwortlich. Server senden keine non-probing Pakete (siehe Abschnitt 9.1) an eine Client-Adresse, bis sie ein non-probing Paket von dieser Adresse sehen. Wenn ein Client Pakete von einer unbekannten Server-Adresse erhält, MUSS der Client diese Pakete verwerfen.
Adressvalidierung mit Retry-Paketen
Ein Endpunkt KANN die Peer-Erreichbarkeit von einer neuen lokalen Adresse mittels Pfadvalidierung (Abschnitt 8.2) prüfen, bevor die Verbindung zu der neuen lokalen Adresse migriert wird. Ein Fehlschlagen der Pfadvalidierung bedeutet lediglich, dass der neue Pfad für diese Verbindung nicht nutzbar ist. Das Fehlschlagen der Validierung eines Pfads führt nicht zum Beenden der Verbindung, es sei denn, es sind keine gültigen alternativen Pfade verfügbar.
PATH_CHALLENGE, PATH_RESPONSE, NEW_CONNECTION_ID und PADDING Frames sind “Probing Frames”, und alle anderen Frames sind “Non-Probing Frames”. Ein Paket, das nur Probing Frames enthält, ist ein “Probing Packet”, und ein Paket, das andere Frames enthält, ist ein “Non-Probing Packet”.
Adressvalidierung für zukünftige Verbindungen
Ein Endpunkt kann eine Verbindung zu einer neuen lokalen Adresse migrieren, indem er Pakete mit non-probing Frames von dieser Adresse sendet.
Jeder Endpunkt validiert die Adresse seines Peers während der Verbindungsherstellung. Daher kann ein migrierender Endpunkt an seinen Peer senden, da er weiß, dass der Peer bereit ist, an der aktuellen Adresse des Peers zu empfangen. Somit kann ein Endpunkt zu einer neuen lokalen Adresse migrieren, ohne zuerst die Adresse des Peers zu validieren.
Um die Erreichbarkeit auf dem neuen Pfad zu etablieren, initiiert ein Endpunkt eine Pfadvalidierung (Abschnitt 8.2) auf dem neuen Pfad. Ein Endpunkt KANN die Pfadvalidierung aufschieben, bis nachdem ein Peer den nächsten Nicht-Probing-Frame an seine neue Adresse sendet.
Bei der Migration unterstützt der neue Pfad möglicherweise nicht die aktuelle Senderate des Endpunkts. Daher setzt der Endpunkt seine Congestion Controller und RTT-Schätzung zurück, wie in Abschnitt 9.4 beschrieben.
Der neue Pfad könnte nicht dieselbe ECN-Fähigkeit haben. Daher validiert der Endpunkt die ECN-Fähigkeit wie in Abschnitt 13.4 beschrieben.
Integrität des Address Validation Token
Der Empfang eines Pakets von einer neuen Peer-Adresse, das einen nicht-probierenden Frame enthält, zeigt an, dass der Peer zu dieser Adresse migriert ist.
Wenn der Empfänger die Migration zulässt, MUSS er nachfolgende Pakete an die neue Peer-Adresse senden und MUSS eine Pfadvalidierung (Abschnitt 8.2) einleiten, um das Eigentum des Peers an der Adresse zu verifizieren, falls noch keine Validierung läuft. Wenn der Empfänger keine ungenutzten Verbindungs-IDs vom Peer hat, wird er nichts auf dem neuen Pfad senden können, bis der Peer eine bereitstellt; siehe Abschnitt 9.5.
Ein Endpunkt ändert die Adresse, an die er Pakete sendet, nur als Reaktion auf das Paket mit der höchsten Nummer, das kein Probing-Paket ist. Dies stellt sicher, dass ein Endpunkt keine Pakete an eine alte Peer-Adresse sendet, falls er neu sortierte Pakete empfängt.
Ein Endpoint KANN Daten an eine nicht validierte Peer-Adresse senden, MUSS jedoch gegen potentielle Angriffe schützen, wie in den Abschnitten 9.3.1 und 9.3.2 beschrieben. Ein Endpoint KANN die Validierung einer Peer-Adresse überspringen, wenn diese Adresse kürzlich gesehen wurde. Insbesondere wenn ein Endpoint zu einem zuvor validierten Pfad zurückkehrt, nachdem eine Form von unechter Migration erkannt wurde, kann das Überspringen der Adressvalidierung und die Wiederherstellung des Verlusterkennungs- und Staukontrollzustands die Leistungsauswirkungen des Angriffs reduzieren.
Nachdem ein Endpunkt die Adresse geändert hat, an die er Nicht-Probing-Pakete sendet, kann er jede Pfadvalidierung für andere Adressen aufgeben.
Das Empfangen eines Pakets von einer neuen Peer-Adresse könnte das Resultat einer NAT-Neubindung beim Peer sein.
Nach der Verifizierung einer neuen Client-Adresse SOLLTE der Server neue Adressvalidierungstoken (Abschnitt 8) an den Client senden.
Pfad-Validierung
Es ist möglich, dass ein Peer seine Quelladresse fälscht, um einen Endpunkt dazu zu bringen, übermäßige Datenmengen an einen unwilligen Host zu senden. Wenn der Endpunkt deutlich mehr Daten sendet als der fälschende Peer, könnte Connection Migration dazu verwendet werden, das Datenvolumen zu verstärken, das ein Angreifer gegen ein Opfer erzeugen kann.
Wie in Abschnitt 9.3 beschrieben, ist ein Endpunkt verpflichtet, die neue Adresse eines Peers zu validieren, um zu bestätigen, dass der Peer im Besitz der neuen Adresse ist. Bis die Adresse eines Peers als gültig erachtet wird, begrenzt ein Endpunkt die Datenmenge, die er an diese Adresse sendet; siehe Abschnitt 8. Ohne diese Begrenzung riskiert ein Endpunkt, für einen Denial-of-Service-Angriff gegen ein ahnungsloses Opfer missbraucht zu werden.
Wenn ein Endpunkt die Validierung einer Peer-Adresse wie oben beschrieben überspringt, muss er seine Senderate nicht begrenzen.
Einleitung der Pfadvalidierung
Ein Angreifer auf dem Übertragungsweg könnte eine unechte Verbindungsmigration verursachen, indem er ein Paket mit einer gefälschten Adresse kopiert und weiterleitet, sodass es vor dem ursprünglichen Paket ankommt. Das Paket mit der gefälschten Adresse wird als von einer migrierenden Verbindung stammend erkannt, und das ursprüngliche Paket wird als Duplikat betrachtet und verworfen. Nach einer unechten Migration wird die Validierung der Quelladresse fehlschlagen, da die Entität an der Quelladresse nicht über die notwendigen kryptographischen Schlüssel verfügt, um den PATH_CHALLENGE-Frame zu lesen oder darauf zu antworten, der an sie gesendet wird, selbst wenn sie es wollte.
Um die Verbindung vor Fehlschlägen aufgrund einer solchen unechten Migration zu schützen, MUSS ein Endpunkt zur Verwendung der zuletzt validierten Peer-Adresse zurückkehren, wenn die Validierung einer neuen Peer-Adresse fehlschlägt. Zusätzlich wird der Empfang von Paketen mit höheren Paketnummern von der legitimierten Peer-Adresse eine weitere Verbindungsmigration auslösen. Dies wird dazu führen, dass die Validierung der Adresse der unechten Migration aufgegeben wird und somit Migrationen, die durch den Angreifer durch das Einschleusen eines einzelnen Pakets initiiert wurden, eingedämmt werden.
Wenn ein Endpunkt keinen Zustand über die zuletzt validierte Peer-Adresse hat, MUSS er die Verbindung stillschweigend schließen, indem er den gesamten Verbindungszustand verwirft. Dies führt dazu, dass neue Pakete auf der Verbindung generisch behandelt werden. Beispielsweise KANN ein Endpunkt einen Stateless Reset als Antwort auf alle weiteren eingehenden Pakete senden.
Pfadvalidierungs-Antworten
Ein Off-Path-Angreifer, der Pakete beobachten kann, könnte Kopien echter Pakete an Endpunkte weiterleiten. Wenn das kopierte Paket vor dem echten Paket ankommt, wird dies als NAT-Rebinding erscheinen. Jedes echte Paket wird als Duplikat verworfen. Wenn der Angreifer in der Lage ist, weiterhin Pakete weiterzuleiten, könnte er eine Migration zu einem Pfad über den Angreifer verursachen. Dies bringt den Angreifer auf den Pfad und gibt ihm die Möglichkeit, alle nachfolgenden Pakete zu beobachten oder zu verwerfen.
Diese Art von Angriff beruht darauf, dass der Angreifer einen Pfad verwendet, der ungefähr die gleichen Eigenschaften wie der direkte Pfad zwischen den Endpunkten aufweist. Der Angriff ist zuverlässiger, wenn relativ wenige Pakete gesendet werden oder wenn Paketverlust mit dem versuchten Angriff zusammenfällt.
Ein nicht-sondierendes Paket, das auf dem ursprünglichen Pfad empfangen wird und die maximale empfangene Paketnummer erhöht, veranlasst den Endpunkt, zu diesem Pfad zurückzukehren. Das Anfordern von Paketen auf diesem Pfad erhöht die Wahrscheinlichkeit, dass der Angriff erfolglos ist. Daher beruht die Eindämmung dieses Angriffs darauf, den Austausch von Paketen auszulösen.
Als Reaktion auf eine offensichtliche Migration MÜSSEN Endpunkte den zuvor aktiven Pfad mit einem PATH_CHALLENGE-Frame validieren. Dies führt zum Senden neuer Pakete auf diesem Pfad. Wenn der Pfad nicht mehr brauchbar ist, wird der Validierungsversuch timeout und fehlschlagen; wenn der Pfad brauchbar, aber nicht mehr erwünscht ist, wird die Validierung erfolgreich sein, führt aber nur dazu, dass Sondierungspakete auf dem Pfad gesendet werden.
Ein Endpunkt, der eine PATH_CHALLENGE auf einem aktiven Pfad erhält, SOLLTE als Antwort ein non-probing packet senden. Wenn das non-probing packet vor jeder Kopie eines Angreifers ankommt, führt dies dazu, dass die Verbindung zurück zum ursprünglichen Pfad migriert wird. Jede nachfolgende Migration zu einem anderen Pfad startet diesen gesamten Prozess neu.
Diese Verteidigung ist unvollkommen, aber dies wird nicht als ernsthaftes Problem betrachtet. Wenn der Pfad über den Angriff trotz mehrfacher Versuche, den ursprünglichen Pfad zu nutzen, zuverlässig schneller ist als der ursprüngliche Pfad, ist es nicht möglich, zwischen einem Angriff und einer Verbesserung im Routing zu unterscheiden.
Ein Endpunkt könnte auch Heuristiken verwenden, um die Erkennung dieser Art von Angriff zu verbessern. Zum Beispiel ist NAT-Rebinding unwahrscheinlich, wenn kürzlich Pakete auf dem alten Pfad empfangen wurden; ähnlich ist Rebinding auf IPv6-Pfaden selten. Endpunkte können auch nach duplizierten Paketen suchen. Umgekehrt deutet eine Änderung der Verbindungs-ID eher auf eine beabsichtigte Migration als auf einen Angriff hin.
Erfolgreiche Path-Validierung
Die verfügbare Kapazität auf dem neuen Pfad ist möglicherweise nicht dieselbe wie auf dem alten Pfad. Pakete, die auf dem alten Pfad gesendet werden, DÜRFEN NICHT zur Staukontrolle oder RTT-Schätzung für den neuen Pfad beitragen.
Bei der Bestätigung der Inhaberschaft einer neuen Adresse durch einen Peer MUSS ein Endpunkt sofort den Congestion Controller und den Round-Trip-Time-Estimator für den neuen Pfad auf die Anfangswerte zurücksetzen (siehe Anhänge A.3 und B.3 von QUIC-RECOVERY), es sei denn, die einzige Änderung in der Adresse des Peers ist seine Portnummer. Da Änderungen nur des Ports häufig das Ergebnis von NAT-Rebinding oder anderen Middlebox-Aktivitäten sind, KANN der Endpunkt stattdessen seinen Congestion Control-Zustand und seine Round-Trip-Schätzung in diesen Fällen beibehalten, anstatt zu den Anfangswerten zurückzukehren. In Fällen, in denen der von einem alten Pfad beibehaltene Congestion Control-Zustand auf einem neuen Pfad mit wesentlich anderen Eigenschaften verwendet wird, könnte ein Sender zu aggressiv übertragen, bis sich der Congestion Controller und der RTT-Estimator angepasst haben. Allgemein wird Implementierungen geraten, bei der Verwendung vorheriger Werte auf einem neuen Pfad vorsichtig zu sein.
Es könnte zu einer scheinbaren Neuordnung beim Empfänger kommen, wenn ein Endpunkt während der Migrationsperiode Daten und Sonden von/zu mehreren Adressen sendet, da die beiden resultierenden Pfade unterschiedliche Rundlaufzeiten haben könnten. Ein Empfänger von Paketen auf mehreren Pfaden wird dennoch ACK-Frames senden, die alle empfangenen Pakete abdecken.
Obwohl während der Verbindungsmigration mehrere Pfade verwendet werden könnten, könnte ein einziger Congestion Control-Kontext und ein einziger Loss Recovery-Kontext (wie in QUIC-RECOVERY beschrieben) ausreichend sein. Beispielsweise könnte ein Endpunkt den Wechsel zu einem neuen Congestion Control-Kontext verzögern, bis bestätigt ist, dass ein alter Pfad nicht mehr benötigt wird (wie im Fall, der in Abschnitt 9.3.3 beschrieben ist).
Ein Sender kann Ausnahmen für Probe-Pakete machen, sodass deren Verlusterkennung unabhängig ist und nicht unnötig dazu führt, dass der Congestion Controller seine Senderate reduziert. Ein Endpunkt könnte einen separaten Timer setzen, wenn ein PATH_CHALLENGE gesendet wird, der abgebrochen wird, falls die entsprechende PATH_RESPONSE empfangen wird. Wenn der Timer ausläuft, bevor die PATH_RESPONSE empfangen wird, könnte der Endpunkt ein neues PATH_CHALLENGE senden und den Timer für eine längere Zeitspanne neu starten. Dieser Timer SOLLTE wie in Abschnitt 6.2.1 von QUIC-RECOVERY beschrieben gesetzt werden und DARF NICHT aggressiver sein.
Fehlerhafte Pfadvalidierung
Die Verwendung einer stabilen Verbindungs-ID auf mehreren Netzwerkpfaden würde es einem passiven Beobachter ermöglichen, Aktivitäten zwischen diesen Pfaden zu korrelieren. Ein Endpunkt, der sich zwischen Netzwerken bewegt, möchte möglicherweise nicht, dass seine Aktivitäten von einer anderen Entität als seinem Peer korreliert werden, daher werden unterschiedliche Verbindungs-IDs verwendet, wenn von verschiedenen lokalen Adressen gesendet wird, wie in Abschnitt 5.1 besprochen. Damit dies wirksam ist, müssen Endpunkte sicherstellen, dass die von ihnen bereitgestellten Verbindungs-IDs nicht von einer anderen Entität verknüpft werden können.
Zu jedem Zeitpunkt KÖNNEN Endpunkte die Destination Connection ID, die sie übertragen, zu einem Wert ändern, der nicht auf einem anderen Pfad verwendet wurde.
Ein Endpoint DARF NICHT eine Connection ID wiederverwenden, wenn er von mehr als einer lokalen Adresse sendet – zum Beispiel beim Einleiten einer Connection Migration wie in Abschnitt 9.2 beschrieben oder beim Prüfen eines neuen Netzwerkpfads wie in Abschnitt 9.1 beschrieben.
Ebenso DARF ein Endpunkt eine Connection ID NICHT wiederverwenden, wenn er an mehr als eine Zieladresse sendet. Aufgrund von Netzwerkänderungen außerhalb der Kontrolle seines Peers könnte ein Endpunkt Pakete von einer neuen Quelladresse mit demselben Destination Connection ID Feldwert erhalten, in welchem Fall er die aktuelle Connection ID mit der neuen Remote-Adresse weiterhin verwenden DARF, während er weiterhin von derselben lokalen Adresse sendet.
Diese Anforderungen bezüglich der Wiederverwendung von Verbindungs-IDs gelten nur für das Senden von Paketen, da unbeabsichtigte Pfadänderungen ohne Änderung der Verbindungs-ID möglich sind. Beispielsweise kann nach einer Phase der Netzwerkinaktivität NAT-Rebinding dazu führen, dass Pakete auf einem neuen Pfad gesendet werden, wenn der Client das Senden wieder aufnimmt. Ein Endpunkt reagiert auf ein solches Ereignis wie in Abschnitt 9.3 beschrieben.
Die Verwendung unterschiedlicher Verbindungs-IDs für Pakete, die in beide Richtungen auf jedem neuen Netzwerkpfad gesendet werden, eliminiert die Nutzung der Verbindungs-ID zur Verknüpfung von Paketen derselben Verbindung über verschiedene Netzwerkpfade hinweg. Header-Schutz stellt sicher, dass Paketnummern nicht zur Korrelation von Aktivitäten verwendet werden können. Dies verhindert nicht, dass andere Eigenschaften von Paketen, wie Timing und Größe, zur Korrelation von Aktivitäten verwendet werden.
Ein Endpoint SOLLTE NICHT eine Migration mit einem Peer initiieren, der eine Verbindungs-ID der Länge Null angefordert hat, da der Verkehr über den neuen Pfad trivial mit dem Verkehr über den alten verknüpfbar sein könnte. Wenn der Server in der Lage ist, Pakete mit einer Verbindungs-ID der Länge Null der richtigen Verbindung zuzuordnen, bedeutet dies, dass der Server andere Informationen verwendet, um Pakete zu demultiplexen. Zum Beispiel könnte ein Server jedem Client eine eindeutige Adresse bereitstellen – beispielsweise unter Verwendung von HTTP alternative services ALTSVC. Informationen, die eine korrekte Weiterleitung von Paketen über mehrere Netzwerkpfade ermöglichen könnten, werden es auch anderen Entitäten als dem Peer ermöglichen, Aktivitäten auf diesen Pfaden zu verknüpfen.
Ein Client könnte die Verlinkbarkeit reduzieren wollen, indem er zu einer neuen Verbindungs-ID, einem neuen Quell-UDP-Port oder einer neuen IP-Adresse wechselt (siehe RFC8981), wenn er Datenverkehr nach einer Periode der Inaktivität sendet. Das gleichzeitige Ändern der Adresse, von der aus er Pakete sendet, könnte dazu führen, dass der Server eine Verbindungsmigration erkennt. Dies stellt sicher, dass die Mechanismen, die Migration unterstützen, auch für Clients ausgeübt werden, die keine NAT-Neubindungen oder echte Migrationen erfahren. Das Ändern der Adresse kann dazu führen, dass ein Peer seinen Congestion Control-Zustand zurücksetzt (siehe Abschnitt 9.4), daher SOLLTEN Adressen nur selten geändert werden.
Ein Endpunkt, der verfügbare Verbindungs-IDs erschöpft hat, kann keine neuen Pfade testen oder Migration initiieren, noch kann er auf Tests oder Migrationsversuche seines Peers antworten. Um sicherzustellen, dass Migration möglich ist und Pakete, die über verschiedene Pfade gesendet werden, nicht korreliert werden können, SOLLTEN Endpunkte neue Verbindungs-IDs bereitstellen, bevor Peers migrieren; siehe Abschnitt 5.1.1. Falls ein Peer möglicherweise verfügbare Verbindungs-IDs erschöpft hat, könnte ein migrierender Endpunkt einen NEW_CONNECTION_ID Frame in alle Pakete einbeziehen, die über einen neuen Netzwerkpfad gesendet werden.
Server’s Preferred Address
QUIC ermöglicht es Servern, Verbindungen auf einer IP-Adresse anzunehmen und zu versuchen, diese Verbindungen kurz nach dem Handshake auf eine bevorzugte Adresse zu übertragen. Dies ist besonders nützlich, wenn Clients zunächst eine Verbindung zu einer Adresse herstellen, die von mehreren Servern gemeinsam genutzt wird, aber lieber eine Unicast-Adresse verwenden möchten, um die Verbindungsstabilität zu gewährleisten. Dieser Abschnitt beschreibt das Protokoll für die Migration einer Verbindung zu einer bevorzugten Serveradresse.
Die Migration einer Verbindung zu einer neuen Server-Adresse während einer bestehenden Verbindung wird von der in diesem Dokument spezifizierten QUIC-Version nicht unterstützt. Wenn ein Client Pakete von einer neuen Server-Adresse erhält, obwohl der Client keine Migration zu dieser Adresse eingeleitet hat, SOLLTE der Client diese Pakete verwerfen.
Erkundung eines neuen Pfads
Ein Server übermittelt eine bevorzugte Adresse, indem er den preferred_address Transport-Parameter in den TLS-Handshake einbezieht.
Server KÖNNEN eine bevorzugte Adresse jeder Adressfamilie (IPv4 und IPv6) kommunizieren, um Clients zu ermöglichen, diejenige auszuwählen, die am besten zu ihrer Netzwerkanbindung passt.
Sobald der Handshake bestätigt ist, SOLLTE der Client eine der beiden vom Server bereitgestellten Adressen auswählen und die Pfadvalidierung einleiten (siehe Abschnitt 8.2). Ein Client konstruiert Pakete unter Verwendung einer zuvor nicht verwendeten aktiven Verbindungs-ID, die entweder aus dem preferred_address Transport-Parameter oder einem NEW_CONNECTION_ID Frame stammt.
Sobald die Pfadvalidierung erfolgreich ist, SOLLTE der Client damit beginnen, alle zukünftigen Pakete unter Verwendung der neuen Verbindungs-ID an die neue Serveradresse zu senden und die Verwendung der alten Serveradresse einstellen. Falls die Pfadvalidierung fehlschlägt, MUSS der Client weiterhin alle zukünftigen Pakete an die ursprüngliche IP-Adresse des Servers senden.
Einleitung der Verbindungsmigration
Ein Client, der zu einer bevorzugten Adresse migriert, MUSS die Adresse, die er wählt, vor der Migration validieren; siehe Abschnitt 21.5.3.
Ein Server könnte jederzeit nach dem Akzeptieren einer Verbindung ein Paket erhalten, das an seine bevorzugte IP-Adresse adressiert ist. Wenn dieses Paket einen PATH_CHALLENGE Frame enthält, sendet der Server ein Paket mit einem PATH_RESPONSE Frame gemäß Abschnitt 8.2. Der Server MUSS Non-Probing-Pakete von seiner ursprünglichen Adresse senden, bis er ein Non-Probing-Paket vom Client an seiner bevorzugten Adresse erhält und bis der Server den neuen Pfad validiert hat.
Der Server MUSS auf dem Pfad zum Client von seiner bevorzugten Adresse aus prüfen. Dies hilft dabei, sich gegen unechte Migration zu schützen, die von einem Angreifer initiiert wurde.
Sobald der Server seine Pfadvalidierung abgeschlossen hat und ein nicht-sondierendes Paket mit einer neuen größten Paketnummer auf seiner bevorzugten Adresse erhalten hat, beginnt der Server damit, nicht-sondierende Pakete ausschließlich von seiner bevorzugten IP-Adresse an den Client zu senden. Der Server SOLLTE neuere Pakete für diese Verbindung verwerfen, die auf der alten IP-Adresse empfangen werden. Der Server KANN weiterhin verzögerte Pakete verarbeiten, die auf der alten IP-Adresse empfangen werden.
Die Adressen, die ein Server im preferred_address Transport-Parameter bereitstellt, sind nur für die Verbindung gültig, in der sie bereitgestellt werden. Ein Client DARF diese NICHT für andere Verbindungen verwenden, einschließlich Verbindungen, die von der aktuellen Verbindung wiederaufgenommen werden.
Auf Connection Migration reagieren
Ein Client könnte eine Verbindungsmigration durchführen müssen, bevor er zur bevorzugten Adresse des Servers migriert ist. In diesem Fall SOLLTE der Client die Pfadvalidierung sowohl zur ursprünglichen als auch zur bevorzugten Serveradresse von der neuen Adresse des Clients gleichzeitig durchführen.
Wenn die Pfadvalidierung der vom Server bevorzugten Adresse erfolgreich ist, MUSS der Client die Validierung der ursprünglichen Adresse aufgeben und zur Verwendung der vom Server bevorzugten Adresse wechseln. Wenn die Pfadvalidierung der vom Server bevorzugten Adresse fehlschlägt, aber die Validierung der ursprünglichen Serveradresse erfolgreich ist, KANN der Client zu seiner neuen Adresse migrieren und weiterhin an die ursprüngliche Adresse des Servers senden.
Wenn Pakete, die an der bevorzugten Adresse des Servers empfangen werden, eine andere Quelladresse haben als während des Handshakes vom Client beobachtet, MUSS der Server sich gegen potenzielle Angriffe schützen, wie in den Abschnitten 9.3.1 und 9.3.2 beschrieben. Zusätzlich zu einer absichtlichen gleichzeitigen Migration könnte dies auch auftreten, weil das Zugriffsnetzwerk des Clients ein anderes NAT-Binding für die bevorzugte Adresse des Servers verwendet hat.
Server SOLLTEN eine Pfadvalidierung zur neuen Adresse des Clients einleiten, wenn sie ein Probe-Paket von einer anderen Adresse erhalten; siehe Abschnitt 8.
Ein Client, der zu einer neuen Adresse migriert, SOLLTE eine bevorzugte Adresse aus derselben Adressfamilie für den Server verwenden.
Die Verbindungs-ID, die im preferred_address Transport-Parameter bereitgestellt wird, ist nicht spezifisch für die bereitgestellten Adressen. Diese Verbindungs-ID wird bereitgestellt, um sicherzustellen, dass der Client eine Verbindungs-ID für die Migration zur Verfügung hat, aber der Client KANN diese Verbindungs-ID auf jedem Pfad verwenden.
Peer-Adress-Spoofing
QUIC empfiehlt, dass Endpunkte, die Daten über IPv6 senden, ein IPv6 Flow Label in Übereinstimmung mit RFC 6437 anwenden SOLLTEN, es sei denn, die lokale API erlaubt nicht das Setzen von IPv6 Flow Labels.
Leider erlaubt die Java-API nicht das Setzen von IPv6-Flow-Labels.
Nicht-Ziele
Das Folgende ist kopiert aus QUIC RFC 9000. Überprüfen und bearbeiten Sie jeden Abschnitt.
Das Ziel von QUIC ist es, eine sichere Transportverbindung bereitzustellen. Abschnitt 21.1 bietet einen Überblick über diese Eigenschaften; nachfolgende Abschnitte diskutieren Einschränkungen und Vorbehalte bezüglich dieser Eigenschaften, einschließlich Beschreibungen bekannter Angriffe und Gegenmaßnahmen.
On-Path-Adress-Spoofing
Eine vollständige Sicherheitsanalyse von QUIC liegt außerhalb des Rahmens dieses Dokuments. Dieser Abschnitt bietet eine informelle Beschreibung der gewünschten Sicherheitseigenschaften als Hilfe für Implementierer und um die Protokollanalyse zu unterstützen.
QUIC geht vom Bedrohungsmodell aus, das in SEC-CONS beschrieben wird, und bietet Schutz vor vielen der Angriffe, die aus diesem Modell entstehen.
Zu diesem Zweck werden Angriffe in passive und aktive Angriffe unterteilt. Passive Angreifer haben die Fähigkeit, Pakete aus dem Netzwerk zu lesen, während aktive Angreifer zusätzlich die Fähigkeit haben, Pakete in das Netzwerk zu schreiben. Ein passiver Angriff könnte jedoch einen Angreifer umfassen, der die Fähigkeit hat, eine Routing-Änderung oder andere Modifikation im Pfad zu verursachen, den die Pakete einer Verbindung nehmen.
Angreifer werden zusätzlich als entweder on-path Angreifer oder off-path Angreifer kategorisiert. Ein on-path Angreifer kann jedes Paket, das er beobachtet, lesen, modifizieren oder entfernen, sodass das Paket sein Ziel nicht mehr erreicht, während ein off-path Angreifer die Pakete beobachtet, aber nicht verhindern kann, dass das ursprüngliche Paket sein beabsichtigtes Ziel erreicht. Beide Arten von Angreifern können auch beliebige Pakete übertragen. Diese Definition unterscheidet sich von der in Abschnitt 3.5 von SEC-CONS insofern, als ein off-path Angreifer in der Lage ist, Pakete zu beobachten.
Die Eigenschaften des Handshakes, geschützter Pakete und der Verbindungsmigration werden separat betrachtet.
Off-Path-Paketweiterleitung
Der QUIC-Handshake integriert den TLS 1.3-Handshake und übernimmt die kryptographischen Eigenschaften, die in Anhang E.1 von TLS13 beschrieben sind. Viele der Sicherheitseigenschaften von QUIC hängen davon ab, dass der TLS-Handshake diese Eigenschaften bereitstellt. Jeder Angriff auf den TLS-Handshake könnte QUIC beeinträchtigen.
Jeder Angriff auf den TLS-Handshake, der die Geheimhaltung oder Eindeutigkeit von Sitzungsschlüsseln oder die Authentifizierung der teilnehmenden Peers kompromittiert, beeinträchtigt andere Sicherheitsgarantien von QUIC, die von diesen Schlüsseln abhängen. Beispielsweise hängt die Migration (Abschnitt 9) von der Wirksamkeit der Vertraulichkeitsschutzmaßnahmen ab, sowohl für die Aushandlung von Schlüsseln mittels des TLS-Handshakes als auch für den QUIC-Paketschutz, um Verknüpfbarkeit über Netzwerkpfade hinweg zu vermeiden.
Ein Angriff auf die Integrität des TLS-Handshakes könnte es einem Angreifer ermöglichen, die Auswahl des Anwendungsprotokolls oder der QUIC-Version zu beeinflussen.
Zusätzlich zu den Eigenschaften, die TLS bietet, bietet der QUIC-Handshake einen gewissen Schutz gegen DoS-Angriffe auf den Handshake.
Verlusterkennung und Staukontrolle
Adressvalidierung (Abschnitt 8) wird verwendet, um zu überprüfen, dass eine Entität, die eine bestimmte Adresse beansprucht, in der Lage ist, Pakete an dieser Adresse zu empfangen. Die Adressvalidierung begrenzt Verstärkungsangriffsziele auf Adressen, für die ein Angreifer Pakete beobachten kann.
Vor der Adressvalidierung sind Endpunkte in dem, was sie senden können, eingeschränkt. Endpunkte können nicht mehr Daten an eine nicht validierte Adresse senden, als das Dreifache der von dieser Adresse empfangenen Daten.
Hinweis: Das Anti-Verstärkungs-Limit gilt nur, wenn ein Endpunkt auf Pakete antwortet, die von einer nicht validierten Adresse empfangen wurden. Das Anti-Verstärkungs-Limit gilt nicht für Clients beim Aufbau einer neuen Verbindung oder beim Initiieren einer Verbindungsmigration.
Datenschutzimplikationen der Verbindungsmigration
Die Berechnung des ersten Flights des Servers für einen vollständigen Handshake ist potenziell aufwendig und erfordert sowohl eine Signatur- als auch eine Schlüsselaustausch-Berechnung. Um rechnerische DoS-Angriffe zu verhindern, bietet das Retry-Paket einen kostengünstigen Token-Austausch-Mechanismus, der es Servern ermöglicht, die IP-Adresse eines Clients zu validieren, bevor teure Berechnungen durchgeführt werden, zum Preis eines einzigen Round-Trips. Nach einem erfolgreichen Handshake können Server neue Token an einen Client ausgeben, wodurch neue Verbindungsaufbauten ohne diese Kosten ermöglicht werden.
Bevorzugte Adresse des Servers
Ein Angreifer auf dem Pfad oder abseits des Pfades kann einen Handshake zum Scheitern bringen, indem er Initial-Pakete ersetzt oder um die Wette sendet. Sobald gültige Initial-Pakete ausgetauscht wurden, sind nachfolgende Handshake-Pakete mit den Handshake-Schlüsseln geschützt, und ein Angreifer auf dem Pfad kann ein Handshake-Versagen nicht anders herbeiführen als durch das Verwerfen von Paketen, um Endpunkte dazu zu bringen, den Versuch aufzugeben.
Ein Angreifer auf dem Übertragungsweg kann auch die Adressen von Paketen auf beiden Seiten ersetzen und dadurch bewirken, dass der Client oder Server eine falsche Sicht auf die entfernten Adressen hat. Ein solcher Angriff ist nicht von den Funktionen unterscheidbar, die von einem NAT ausgeführt werden.
Kommunikation einer bevorzugten Adresse
Der gesamte Handshake ist kryptographisch geschützt, wobei die Initial-Pakete mit versionsspezifischen Schlüsseln verschlüsselt werden und die Handshake- und späteren Pakete mit Schlüsseln verschlüsselt werden, die aus dem TLS-Schlüsselaustausch abgeleitet sind. Darüber hinaus ist die Parameteraushandlung in das TLS-Transcript eingebunden und bietet somit dieselben Integritätsgarantien wie eine gewöhnliche TLS-Aushandlung. Ein Angreifer kann die Transport-Parameter des Clients beobachten (solange er das versionsspezifische Salt kennt), kann aber die Transport-Parameter des Servers nicht beobachten und die Parameteraushandlung nicht beeinflussen.
Verbindungs-IDs sind unverschlüsselt, aber integritätsgeschützt in allen Paketen.
Diese Version von QUIC beinhaltet keinen Mechanismus zur Versionsaushandlung; Implementierungen inkompatibler Versionen werden einfach beim Aufbau einer Verbindung fehlschlagen.
Migration zu einer bevorzugten Adresse
Paketschutz (Abschnitt 12.1) wendet authentifizierte Verschlüsselung auf alle Pakete außer Version Negotiation-Paketen an, obwohl Initial- und Retry-Pakete aufgrund der Verwendung versionsspezifischen Schlüsselmaterials nur begrenzten Schutz haben; siehe QUIC-TLS für weitere Details. Dieser Abschnitt betrachtet passive und aktive Angriffe gegen geschützte Pakete.
Sowohl On-Path- als auch Off-Path-Angreifer können einen passiven Angriff durchführen, bei dem sie beobachtete Pakete für einen späteren Offline-Angriff gegen den Paketschutz speichern; dies gilt für jeden Beobachter jedes Pakets in jedem Netzwerk.
Ein Angreifer, der Pakete einschleust, ohne gültige Pakete für eine Verbindung beobachten zu können, wird wahrscheinlich nicht erfolgreich sein, da der Paketschutz sicherstellt, dass gültige Pakete nur von Endpunkten generiert werden, die das während des Handshake etablierte Schlüsselmaterial besitzen; siehe Abschnitte 7 und 21.1.1. Ebenso sollte kein aktiver Angreifer, der Pakete beobachtet und versucht, neue Daten einzufügen oder bestehende Daten in diesen Paketen zu modifizieren, in der Lage sein, Pakete zu generieren, die vom empfangenden Endpunkt als gültig erachtet werden, außer Initial-Paketen.
Ein Spoofing-Angriff, bei dem ein aktiver Angreifer ungeschützte Teile eines Pakets umschreibt, das er weiterleitet oder einschleust, wie etwa die Quell- oder Zieladresse, ist nur dann wirksam, wenn der Angreifer Pakete an den ursprünglichen Endpunkt weiterleiten kann. Der Paketschutz stellt sicher, dass die Paket-Payloads nur von den Endpunkten verarbeitet werden können, die den Handshake abgeschlossen haben, und ungültige Pakete werden von diesen Endpunkten ignoriert.
Ein Angreifer kann auch die Grenzen zwischen Paketen und UDP-Datagrammen modifizieren, wodurch mehrere Pakete zu einem einzigen Datagramm zusammengefasst oder zusammengefasste Pakete in mehrere Datagramme aufgeteilt werden. Abgesehen von Datagrammen, die Initial-Pakete enthalten und Padding erfordern, hat die Modifikation der Anordnung von Paketen in Datagrammen keine funktionale Auswirkung auf eine Verbindung, obwohl sie einige Leistungsmerkmale ändern könnte.
Interaktion von Client-Migration und bevorzugter Adresse
Connection migration (Abschnitt 9) bietet Endpunkten die Möglichkeit, zwischen IP-Adressen und Ports auf mehreren Pfaden zu wechseln, wobei jeweils ein Pfad für die Übertragung und den Empfang von Non-Probing-Frames verwendet wird. Path validation (Abschnitt 8.2) stellt sicher, dass ein Peer sowohl bereit als auch in der Lage ist, auf einem bestimmten Pfad gesendete Pakete zu empfangen. Dies hilft dabei, die Auswirkungen von Address Spoofing zu reduzieren, indem die Anzahl der an eine gefälschte Adresse gesendeten Pakete begrenzt wird.
Dieser Abschnitt beschreibt die beabsichtigten Sicherheitseigenschaften der Verbindungsmigration unter verschiedenen Arten von DoS-Angriffen.
Verwendung von IPv6 Flow Label und Migration
Ein Angreifer, der bewirken kann, dass ein von ihm beobachtetes Paket sein beabsichtigtes Ziel nicht mehr erreicht, wird als On-Path-Angreifer betrachtet. Wenn sich ein Angreifer zwischen einem Client und Server befindet, sind Endpunkte verpflichtet, Pakete durch den Angreifer zu senden, um Konnektivität auf einem gegebenen Pfad herzustellen.
Ein Angreifer auf dem Übertragungsweg kann:
Pakete untersuchen
IP- und UDP-Paket-Header modifizieren
Neue Pakete einschleusen
Pakete verzögern
Pakete neu ordnen
Pakete verwerfen
Datagramme an Paketgrenzen aufteilen und zusammenführen
Ein On-Path-Angreifer kann nicht:
- Einen authentifizierten Teil eines Pakets modifizieren und bewirken, dass der Empfänger dieses Paket akzeptiert
Ein Angreifer im Übertragungsweg hat die Möglichkeit, die von ihm beobachteten Pakete zu modifizieren; jedoch führen Änderungen an einem authentifizierten Teil eines Pakets dazu, dass es vom empfangenden Endpunkt als ungültig verworfen wird, da Paket-Payloads sowohl authentifiziert als auch verschlüsselt sind.
QUIC zielt darauf ab, die Fähigkeiten eines Angreifers im Übertragungsweg wie folgt einzuschränken:
Ein Angreifer im Pfad kann die Nutzung eines Pfads für eine Verbindung verhindern, wodurch die Verbindung fehlschlägt, wenn sie keinen anderen Pfad verwenden kann, der den Angreifer nicht enthält. Dies kann durch das Verwerfen aller Pakete, deren Modifikation so dass sie nicht entschlüsselt werden können, oder andere Methoden erreicht werden.
Ein Angreifer im Pfad kann die Migration zu einem neuen Pfad, auf dem sich der Angreifer ebenfalls im Pfad befindet, verhindern, indem er die Pfadvalidierung auf dem neuen Pfad zum Scheitern bringt.
Ein On-Path-Angreifer kann nicht verhindern, dass ein Client zu einem Pfad migriert, auf dem sich der Angreifer nicht befindet.
Ein Angreifer auf dem Übertragungsweg kann den Durchsatz einer Verbindung reduzieren, indem er Pakete verzögert oder verwirft.
Ein Angreifer auf dem Übertragungsweg kann nicht dazu führen, dass ein Endpunkt ein Paket akzeptiert, bei dem er einen authentifizierten Teil dieses Pakets modifiziert hat.
Off-Path Active Attacks
Ein Off-Path-Angreifer befindet sich nicht direkt auf dem Pfad zwischen einem Client und Server, könnte aber in der Lage sein, Kopien einiger oder aller Pakete zu erhalten, die zwischen dem Client und dem Server gesendet werden. Er ist auch in der Lage, Kopien dieser Pakete an beide Endpunkte zu senden.
Ein off-path Angreifer kann:
Pakete inspizieren
Neue Pakete einschleusen
Neu anordnen von eingeschleusten Paketen
Ein off-path Angreifer kann nicht:
Pakete modifizieren, die von Endpunkten gesendet werden
Pakete verzögern
Pakete verwerfen
Ursprüngliche Pakete neu ordnen
Ein Off-Path-Angreifer kann modifizierte Kopien von Paketen erstellen, die er beobachtet hat, und diese Kopien in das Netzwerk einschleusen, möglicherweise mit gefälschten Quell- und Zieladressen.
Für die Zwecke dieser Diskussion wird angenommen, dass ein Off-Path-Angreifer die Fähigkeit besitzt, eine modifizierte Kopie eines Pakets in das Netzwerk einzuschleusen, die den Zielendpunkt vor der Ankunft des ursprünglichen, vom Angreifer beobachteten Pakets erreicht. Mit anderen Worten, ein Angreifer hat die Fähigkeit, konsistent ein “Rennen” mit den legitimen Paketen zwischen den Endpunkten zu “gewinnen”, wodurch möglicherweise das ursprüngliche Paket vom Empfänger ignoriert wird.
Es wird außerdem angenommen, dass ein Angreifer über die notwendigen Ressourcen verfügt, um den NAT-Zustand zu beeinflussen. Insbesondere kann ein Angreifer dazu führen, dass ein Endpunkt seine NAT-Bindung verliert und dann denselben Port für die Verwendung mit seinem eigenen Datenverkehr erhält.
QUIC zielt darauf ab, die Fähigkeiten eines Off-Path-Angreifers wie folgt einzuschränken:
Ein Off-Path-Angreifer kann Pakete um die Wette senden und versuchen, ein “begrenzter” On-Path-Angreifer zu werden.
Ein Off-Path-Angreifer kann die Pfadvalidierung für weitergeleitete Pakete mit der als Off-Path-Angreifer aufgeführten Quelladresse erfolgreich machen, solange er eine verbesserte Konnektivität zwischen dem Client und dem Server bereitstellen kann.
Ein Off-Path-Angreifer kann eine Verbindung nicht zum Schließen bringen, sobald der Handshake abgeschlossen ist.
Ein Off-Path-Angreifer kann die Migration zu einem neuen Pfad nicht zum Scheitern bringen, wenn er den neuen Pfad nicht beobachten kann.
Ein Off-Path-Angreifer kann während der Migration zu einem neuen Pfad, für den er ebenfalls ein Off-Path-Angreifer ist, zu einem eingeschränkten On-Path-Angreifer werden.
Ein off-path Angreifer kann zu einem eingeschränkten on-path Angreifer werden, indem er den gemeinsamen NAT-Status so beeinflusst, dass er Pakete an den Server von derselben IP-Adresse und dem Port sendet, die der Client ursprünglich verwendet hat.
Überblick über Sicherheitseigenschaften
Ein begrenzter On-Path-Angreifer ist ein Off-Path-Angreifer, der eine verbesserte Weiterleitung von Paketen angeboten hat, indem er ursprüngliche Pakete zwischen dem Server und dem Client dupliziert und weiterleitet, wodurch diese Pakete vor den ursprünglichen Kopien ankommen, sodass die ursprünglichen Pakete vom Ziel-Endpunkt verworfen werden.
Ein eingeschränkter On-Path-Angreifer unterscheidet sich von einem On-Path-Angreifer dadurch, dass er sich nicht auf dem ursprünglichen Pfad zwischen den Endpunkten befindet und daher die ursprünglichen Pakete, die von einem Endpunkt gesendet werden, immer noch ihr Ziel erreichen. Das bedeutet, dass ein zukünftiges Versagen beim Weiterleiten kopierter Pakete zum Ziel schneller als über ihren ursprünglichen Pfad nicht verhindern wird, dass die ursprünglichen Pakete ihr Ziel erreichen.
Ein eingeschränkter On-Path-Angreifer kann:
Pakete inspizieren
Neue Pakete einschleusen
Unverschlüsselte Paketheader modifizieren
Pakete neu ordnen
Ein begrenzter On-Path-Angreifer kann nicht:
Pakete verzögern, sodass sie später ankommen als Pakete, die über den ursprünglichen Pfad gesendet wurden
Pakete verwerfen
Den authentifizierten und verschlüsselten Teil eines Pakets modifizieren und den Empfänger dazu bringen, dieses Paket zu akzeptieren
Ein begrenzter On-Path-Angreifer kann Pakete nur so weit verzögern, dass die ursprünglichen Pakete vor den duplizierten Paketen ankommen, was bedeutet, dass er kein Routing mit schlechterer Latenz als der ursprüngliche Pfad anbieten kann. Wenn ein begrenzter On-Path-Angreifer Pakete verwirft, wird die ursprüngliche Kopie dennoch am Zielendpunkt ankommen.
QUIC zielt darauf ab, die Fähigkeiten eines begrenzten Off-Path-Angreifers wie folgt einzuschränken:
Ein begrenzter On-Path-Angreifer kann eine Verbindung nicht zum Schließen bringen, sobald der Handshake abgeschlossen ist.
Ein begrenzter On-Path-Angreifer kann nicht dazu führen, dass eine inaktive Verbindung geschlossen wird, wenn der Client als erster die Aktivität wieder aufnimmt.
Ein begrenzter On-Path-Angreifer kann dazu führen, dass eine inaktive Verbindung als verloren betrachtet wird, wenn der Server als erster die Aktivität wieder aufnimmt.
Beachten Sie, dass diese Garantien dieselben Garantien sind, die für jedes NAT aus denselben Gründen bereitgestellt werden.
Handshake
Als verschlüsseltes und authentifiziertes Transportprotokoll bietet QUIC eine Reihe von Schutzmaßnahmen gegen Denial-of-Service-Angriffe. Sobald der kryptographische Handshake abgeschlossen ist, verwerfen QUIC-Endpunkte die meisten Pakete, die nicht authentifiziert sind, was die Fähigkeit eines Angreifers, bestehende Verbindungen zu stören, erheblich einschränkt.
Sobald eine Verbindung hergestellt ist, könnten QUIC-Endpunkte einige nicht authentifizierte ICMP-Pakete akzeptieren (siehe Abschnitt 14.2.1), aber die Verwendung dieser Pakete ist extrem eingeschränkt. Der einzige andere Pakettyp, den ein Endpunkt möglicherweise akzeptiert, ist ein stateless reset (Abschnitt 10.3), der darauf angewiesen ist, dass das Token geheim gehalten wird, bis es verwendet wird.
Während der Erstellung einer Verbindung bietet QUIC nur Schutz gegen Angriffe von außerhalb des Netzwerkpfads. Alle QUIC-Pakete enthalten einen Nachweis, dass der Empfänger ein vorangegangenes Paket von seinem Peer gesehen hat.
Adressen können sich während des Handshakes nicht ändern, daher können Endpunkte Pakete verwerfen, die über einen anderen Netzwerkpfad empfangen werden.
Die Source und Destination Connection ID Felder sind das primäre Schutzmittel gegen Off-Path-Angriffe während des Handshakes; siehe Abschnitt 8.1. Diese müssen mit denen übereinstimmen, die von einem Peer gesetzt wurden. Mit Ausnahme von Initial und Stateless Resets akzeptiert ein Endpunkt nur Pakete, die ein Destination Connection ID Feld enthalten, das mit einem Wert übereinstimmt, den der Endpunkt zuvor gewählt hat. Dies ist der einzige Schutz, der für Version Negotiation Pakete angeboten wird.
Das Destination Connection ID-Feld in einem Initial-Paket wird von einem Client so gewählt, dass es unvorhersagbar ist, was einem zusätzlichen Zweck dient. Die Pakete, die den kryptographischen Handshake übertragen, werden mit einem Schlüssel geschützt, der aus dieser Connection ID und einem Salt abgeleitet wird, das spezifisch für die QUIC-Version ist. Dies ermöglicht es Endpunkten, denselben Prozess zur Authentifizierung empfangener Pakete zu verwenden, den sie auch nach Abschluss des kryptographischen Handshakes verwenden. Pakete, die nicht authentifiziert werden können, werden verworfen. Der Schutz von Paketen auf diese Weise bietet eine starke Gewähr dafür, dass der Absender des Pakets das Initial-Paket gesehen und verstanden hat.
Diese Schutzmaßnahmen sind nicht dafür vorgesehen, gegen einen Angreifer wirksam zu sein, der QUIC-Pakete vor der Verbindungsherstellung empfangen kann. Ein solcher Angreifer kann möglicherweise Pakete senden, die von QUIC-Endpunkten akzeptiert werden. Diese Version von QUIC versucht, diese Art von Angriff zu erkennen, erwartet jedoch, dass Endpunkte beim Aufbau einer Verbindung versagen, anstatt sich zu erholen. Zum größten Teil ist das kryptographische Handshake-Protokoll QUIC-TLS dafür verantwortlich, Manipulationen während des Handshakes zu erkennen.
Endpunkte dürfen andere Methoden verwenden, um Störungen des Handshakes zu erkennen und eine Wiederherstellung zu versuchen. Ungültige Pakete können mit anderen Methoden identifiziert und verworfen werden, aber in diesem Dokument wird keine spezifische Methode vorgeschrieben.
Anti-Amplifikation
Ein Angreifer könnte möglicherweise ein Adressvalidierungstoken (Abschnitt 8) von einem Server erhalten und dann die IP-Adresse freigeben, die er zur Erlangung dieses Tokens verwendet hat. Zu einem späteren Zeitpunkt kann der Angreifer eine 0-RTT-Verbindung mit einem Server initiieren, indem er dieselbe Adresse fälscht, die nun möglicherweise einen anderen (Opfer-)Endpunkt adressiert. Der Angreifer kann somit potenziell verursachen, dass der Server Daten im Umfang eines anfänglichen Überlastungsfensters an das Opfer sendet.
Server SOLLTEN Schutzmaßnahmen gegen diesen Angriff bereitstellen, indem sie die Verwendung und Lebensdauer von Adressvalidierungstoken begrenzen; siehe Abschnitt 8.1.3.
Server-seitige DoS
Ein Endpunkt, der Pakete bestätigt, die er nicht erhalten hat, könnte dazu führen, dass ein Congestion Controller das Senden mit Raten erlaubt, die über das hinausgehen, was das Netzwerk unterstützt. Ein Endpunkt KANN Paketnummern beim Senden von Paketen überspringen, um dieses Verhalten zu erkennen. Ein Endpunkt kann dann die Verbindung sofort mit einem Verbindungsfehler vom Typ PROTOCOL_VIOLATION schließen; siehe Abschnitt 10.2.
On-Path Handshake-Beendigung
Ein Request-Forgery-Angriff tritt auf, wenn ein Endpunkt seinen Peer dazu veranlasst, eine Anfrage an ein Opfer zu stellen, wobei die Anfrage vom Endpunkt kontrolliert wird. Request-Forgery-Angriffe zielen darauf ab, einem Angreifer Zugang zu Fähigkeiten seines Peers zu verschaffen, die dem Angreifer andernfalls nicht zur Verfügung stehen würden. Bei einem Netzwerkprotokoll wird ein Request-Forgery-Angriff oft verwendet, um jede implizite Autorisierung auszunutzen, die dem Peer vom Opfer aufgrund der Position des Peers im Netzwerk gewährt wird.
Damit Request Forgery wirksam ist, muss ein Angreifer in der Lage sein zu beeinflussen, welche Pakete der Peer sendet und wohin diese Pakete gesendet werden. Wenn ein Angreifer einen verwundbaren Service mit einer kontrollierten Payload angreifen kann, könnte dieser Service Aktionen durchführen, die dem Peer des Angreifers zugeschrieben werden, aber vom Angreifer entschieden werden.
Zum Beispiel nutzen Cross-Site Request Forgery CSRF Angriffe im Web aus, dass ein Client Anfragen sendet, die Autorisierungs-Cookies COOKIE enthalten, wodurch eine Website Zugang zu Informationen und Aktionen erhält, die eigentlich auf eine andere Website beschränkt sein sollten.
Da QUIC über UDP läuft, besteht die primäre Angriffsmodalität von Belang darin, dass ein Angreifer die Adresse auswählen kann, an die sein Peer UDP-Datagramme sendet, und einen Teil des ungeschützten Inhalts dieser Pakete kontrollieren kann. Da ein Großteil der von QUIC-Endpunkten gesendeten Daten geschützt ist, umfasst dies die Kontrolle über Chiffretexte. Ein Angriff ist erfolgreich, wenn ein Angreifer einen Peer dazu bringen kann, ein UDP-Datagramm an einen Host zu senden, der aufgrund des Inhalts im Datagramm eine Aktion ausführt.
Dieser Abschnitt behandelt Möglichkeiten, wie QUIC für Request Forgery-Angriffe verwendet werden könnte.
Dieser Abschnitt beschreibt auch begrenzte Gegenmaßnahmen, die von QUIC-Endpunkten implementiert werden können. Diese Mitigationen können einseitig von einer QUIC-Implementierung oder -Bereitstellung eingesetzt werden, ohne dass potenzielle Ziele für Request-Forgery-Angriffe Maßnahmen ergreifen müssen. Diese Gegenmaßnahmen könnten jedoch unzureichend sein, wenn UDP-basierte Dienste Anfragen nicht ordnungsgemäß autorisieren.
Da der in Abschnitt 21.5.4 beschriebene Migration-Angriff sehr mächtig ist und keine angemessenen Gegenmaßnahmen hat, sollten QUIC-Server-Implementierungen davon ausgehen, dass Angreifer sie dazu bringen können, beliebige UDP-Payloads an beliebige Ziele zu senden. QUIC-Server SOLLTEN NICHT in Netzwerken eingesetzt werden, die keine Ingress-Filterung BCP38 implementieren und zusätzlich unzureichend gesicherte UDP-Endpunkte haben.
Obwohl es im Allgemeinen nicht möglich ist sicherzustellen, dass Clients nicht gemeinsam mit verwundbaren Endpunkten lokalisiert sind, erlaubt diese Version von QUIC keine Server-Migration und verhindert somit Spoofing-Migrationsangriffe auf Clients. Jede zukünftige Erweiterung, die Server-Migration ermöglicht, MUSS auch Gegenmaßnahmen für Fälschungsangriffe definieren.
Parameter-Verhandlung
QUIC bietet einem Angreifer einige Möglichkeiten, zu beeinflussen oder zu kontrollieren, wohin sein Peer UDP-Datagramme sendet:
Erstmalige Verbindungsherstellung (Abschnitt 7), bei der ein Server wählen kann, wohin ein Client Datagramme sendet – zum Beispiel durch das Befüllen von DNS-Einträgen;
bevorzugte Adressen (Abschnitt 9.6), bei denen ein Server wählen kann, wohin ein Client Datagramme sendet;
gefälschte Verbindungsmigrationen (Abschnitt 9.3.1), bei denen ein Client Source-Address-Spoofing verwenden kann, um zu wählen, wohin ein Server nachfolgende Datagramme sendet; und
gefälschte Pakete, die einen Server dazu veranlassen, ein Version Negotiation Paket zu senden (Abschnitt 21.5.5).
In allen Fällen kann der Angreifer seinen Peer dazu veranlassen, Datagramme an ein Opfer zu senden, das möglicherweise QUIC nicht versteht. Das heißt, diese Pakete werden vom Peer vor der Adressvalidierung gesendet; siehe Abschnitt 8.
Außerhalb des verschlüsselten Teils von Paketen bietet QUIC einem Endpunkt mehrere Optionen zur Kontrolle des Inhalts von UDP-Datagrammen, die sein Peer sendet. Das Destination Connection ID-Feld bietet direkte Kontrolle über Bytes, die früh in Paketen erscheinen, die vom Peer gesendet werden; siehe Abschnitt 5.1. Das Token-Feld in Initial-Paketen bietet einem Server Kontrolle über andere Bytes von Initial-Paketen; siehe Abschnitt 17.2.2.
In dieser Version von QUIC gibt es keine Maßnahmen, um die indirekte Kontrolle über die verschlüsselten Teile von Paketen zu verhindern. Es ist notwendig anzunehmen, dass Endpunkte in der Lage sind, den Inhalt von Frames zu kontrollieren, die ein Peer sendet, insbesondere solche Frames, die Anwendungsdaten übertragen, wie STREAM-Frames. Obwohl dies zu einem gewissen Grad von den Details des Anwendungsprotokolls abhängt, ist eine gewisse Kontrolle in vielen Protokoll-Nutzungskontexten möglich. Da der Angreifer Zugang zu Paketschutzschlüsseln hat, ist er wahrscheinlich in der Lage vorherzusagen, wie ein Peer zukünftige Pakete verschlüsseln wird. Eine erfolgreiche Kontrolle über den Datagramm-Inhalt erfordert dann nur, dass der Angreifer in der Lage ist, die Paketnummer und Platzierung von Frames in Paketen mit einem gewissen Maß an Zuverlässigkeit vorherzusagen.
Dieser Abschnitt geht davon aus, dass eine Begrenzung der Kontrolle über Datagramm-Inhalte nicht durchführbar ist. Der Fokus der Abschwächungsmaßnahmen in den nachfolgenden Abschnitten liegt darauf, die Möglichkeiten zu begrenzen, wie Datagramme, die vor der Adressvalidierung gesendet werden, für Request Forgery verwendet werden können.
Geschützte Pakete
Ein Angreifer, der als Server agiert, kann die IP-Adresse und den Port wählen, unter denen er seine Verfügbarkeit bewirbt, daher wird angenommen, dass Initial-Pakete von Clients für diese Art von Angriff nutzbar sind. Die im Handshake implizite Adressvalidierung stellt sicher, dass – bei einer neuen Verbindung – ein Client keine anderen Pakettypen an ein Ziel sendet, das QUIC nicht versteht oder nicht bereit ist, eine QUIC-Verbindung zu akzeptieren.
Der initiale Paketschutz (Abschnitt 5.2 von QUIC-TLS) macht es für Server schwierig, den Inhalt von Initial-Paketen zu kontrollieren, die von Clients gesendet werden. Ein Client, der eine unvorhersagbare Destination Connection ID wählt, stellt sicher, dass Server keinen Teil des verschlüsselten Bereichs von Initial-Paketen von Clients kontrollieren können.
Das Token-Feld unterliegt jedoch der Serverkontrolle und ermöglicht es einem Server, Clients für Request-Forgery-Angriffe zu verwenden. Die Verwendung von Tokens, die mit dem NEW_TOKEN-Frame (Abschnitt 8.1.3) bereitgestellt werden, bietet die einzige Möglichkeit für Request Forgery während der Verbindungsherstellung.
Clients sind jedoch nicht verpflichtet, den NEW_TOKEN Frame zu verwenden. Request Forgery-Angriffe, die auf das Token-Feld angewiesen sind, können vermieden werden, wenn Clients ein leeres Token-Feld senden, wenn sich die Serveradresse seit dem Empfang des NEW_TOKEN Frames geändert hat.
Clients könnten die Verwendung von NEW_TOKEN vermeiden, wenn sich die Serveradresse ändert. Das Weglassen eines Token-Feldes könnte jedoch die Leistung beeinträchtigen. Server könnten sich auf NEW_TOKEN verlassen, um das Senden von Daten zu ermöglichen, die das dreifache Limit für das Senden von Daten überschreiten; siehe Abschnitt 8.1. Dies betrifft insbesondere Fälle, in denen Clients 0-RTT verwenden, um Daten von Servern anzufordern.
Das Senden eines Retry-Pakets (Abschnitt 17.2.5) bietet einem Server die Möglichkeit, das Token-Feld zu ändern. Nach dem Senden eines Retry kann der Server auch das Destination Connection ID-Feld nachfolgender Initial-Pakete vom Client kontrollieren. Dies könnte auch eine indirekte Kontrolle über den verschlüsselten Inhalt von Initial-Paketen ermöglichen. Jedoch validiert der Austausch eines Retry-Pakets die Adresse des Servers und verhindert dadurch die Verwendung nachfolgender Initial-Pakete für Request Forgery.
Verbindungsmigration
Server können eine bevorzugte Adresse angeben, zu der Clients dann nach der Bestätigung des Handshakes migrieren; siehe Abschnitt 9.6. Das Destination Connection ID Feld von Paketen, die der Client an eine bevorzugte Adresse sendet, kann für Request Forgery verwendet werden.
Ein Client DARF NICHT vor der Validierung einer bevorzugten Adresse Non-Probing-Frames an diese Adresse senden; siehe Abschnitt 8. Dies reduziert die Möglichkeiten eines Servers zur Kontrolle des verschlüsselten Teils von Datagrammen erheblich.
Dieses Dokument bietet keine zusätzlichen Gegenmaßnahmen, die spezifisch für die Verwendung von bevorzugten Adressen sind und von Endpunkten implementiert werden können. Die generischen Maßnahmen, die in Abschnitt 21.5.6 beschrieben sind, könnten als weitere Schadensbegrenzung verwendet werden.
On-Path Active Angriffe
Clients können eine gefälschte Quelladresse als Teil einer scheinbaren Verbindungsmigration präsentieren, um einen Server dazu zu bringen, Datagramme an diese Adresse zu senden.
Das Feld Destination Connection ID in allen Paketen, die ein Server anschließend an diese gefälschte Adresse sendet, kann für Request-Forgery verwendet werden. Ein Client könnte möglicherweise auch den Ciphertext beeinflussen.
Ein Server, der vor der Adressvalidierung nur Probing-Pakete (Abschnitt 9.1) an eine Adresse sendet, bietet einem Angreifer nur begrenzte Kontrolle über den verschlüsselten Teil von Datagrammen. Jedoch kann dies, insbesondere bei NAT-Rebinding, die Leistung beeinträchtigen. Wenn der Server Frames mit Anwendungsdaten sendet, könnte ein Angreifer möglicherweise den größten Teil des Inhalts von Datagrammen kontrollieren.
Dieses Dokument bietet keine spezifischen Gegenmaßnahmen, die von Endpunkten implementiert werden können, abgesehen von den allgemeinen Maßnahmen, die in Abschnitt 21.5.6 beschrieben sind. Jedoch sind Gegenmaßnahmen gegen Adressfälschung auf Netzwerkebene – insbesondere Ingress-Filterung BCP38 – besonders wirksam gegen Angriffe, die Spoofing verwenden und aus einem externen Netzwerk stammen.
Off-Path Active Angriffe
Clients, die in der Lage sind, eine gefälschte Quelladresse in einem Paket zu präsentieren, können dazu führen, dass ein Server ein Version Negotiation-Paket (Abschnitt 17.2.1) an diese Adresse sendet.
Das Fehlen von Größenbeschränkungen bei den Connection-ID-Feldern für Pakete einer unbekannten Version erhöht die Menge an Daten, die der Client aus dem resultierenden Datagramm kontrolliert. Das erste Byte dieses Pakets steht nicht unter Client-Kontrolle und die nächsten vier Bytes sind null, aber der Client kann bis zu 512 Bytes ab dem fünften Byte kontrollieren.
Für diesen Angriff werden keine spezifischen Gegenmaßnahmen bereitgestellt, obwohl generische Schutzmaßnahmen (Abschnitt 21.5.6) anwendbar sein könnten. In diesem Fall ist auch ingress filtering BCP38 wirksam.
Begrenzte On-Path Active Attacks
Die wirksamste Verteidigung gegen Request-Forgery-Angriffe ist es, verwundbare Dienste so zu modifizieren, dass sie starke Authentifizierung verwenden. Dies liegt jedoch nicht immer in der Kontrolle einer QUIC-Implementierung. Dieser Abschnitt skizziert einige andere Schritte, die QUIC-Endpunkte einseitig unternehmen könnten. Diese zusätzlichen Schritte sind alle optional, da sie je nach Umständen legitime Nutzungen behindern oder verhindern könnten.
Dienste, die über Loopback-Schnittstellen angeboten werden, verfügen oft nicht über eine ordnungsgemäße Authentifizierung. Endpunkte KÖNNEN Verbindungsversuche oder Migration zu einer Loopback-Adresse verhindern. Endpunkte SOLLTEN Verbindungen oder Migration zu einer Loopback-Adresse NICHT zulassen, wenn derselbe Dienst zuvor über eine andere Schnittstelle verfügbar war oder wenn die Adresse von einem Dienst an einer Nicht-Loopback-Adresse bereitgestellt wurde. Endpunkte, die auf diese Funktionen angewiesen sind, könnten eine Option anbieten, diese Schutzmaßnahmen zu deaktivieren.
Ebenso könnten Endpunkte eine Änderung der Adresse zu einer link-lokalen Adresse RFC4291 oder einer Adresse in einem privaten Bereich RFC1918 von einer globalen, unique-lokalen RFC4193 oder nicht-privaten Adresse als einen möglichen Versuch einer Request-Fälschung betrachten. Endpunkte könnten diese Adressen vollständig ablehnen, aber das birgt ein erhebliches Risiko, legitime Verwendungen zu beeinträchtigen. Endpunkte SOLLTEN NICHT die Verwendung einer Adresse ablehnen, es sei denn, sie haben spezifisches Wissen über das Netzwerk, das anzeigt, dass das Senden von Datagrammen an nicht validierte Adressen in einem bestimmten Bereich nicht sicher ist.
Endpunkte KÖNNEN das Risiko von Request Forgery reduzieren, indem sie keine Werte aus NEW_TOKEN frames in Initial-Paketen einschließen oder nur Probing-Frames in Paketen vor Abschluss der Adressvalidierung senden. Beachten Sie, dass dies einen Angreifer nicht daran hindert, das Destination Connection ID-Feld für einen Angriff zu verwenden.
Endpoints wird nicht erwartet, dass sie spezifische Informationen über den Standort von Servern haben, die verwundbare Ziele eines Request-Forgery-Angriffs sein könnten. Es könnte jedoch im Laufe der Zeit möglich sein, spezifische UDP-Ports zu identifizieren, die häufige Angriffsziele sind, oder bestimmte Muster in Datagrammen, die für Angriffe verwendet werden. Endpoints KÖNNEN wählen, das Senden von Datagrammen an diese Ports zu vermeiden oder keine Datagramme zu senden, die diesen Mustern entsprechen, bevor sie die Zieladresse validieren. Endpoints KÖNNEN Verbindungs-IDs, die bekanntermaßen problematische Muster enthalten, außer Betrieb nehmen, ohne sie zu verwenden.
Hinweis: Das Modifizieren von Endpunkten zur Anwendung dieser Schutzmaßnahmen ist effizienter als das Bereitstellen netzwerkbasierter Schutzmaßnahmen, da Endpunkte keine zusätzliche Verarbeitung durchführen müssen, wenn sie an eine Adresse senden, die validiert wurde.
Handshake Denial of Service
Die Angriffe, die allgemein als Slowloris SLOWLORIS bekannt sind, versuchen viele Verbindungen zum Ziel-Endpunkt offen zu halten und diese so lange wie möglich geöffnet zu lassen. Diese Angriffe können gegen einen QUIC-Endpunkt ausgeführt werden, indem die minimale Aktivität erzeugt wird, die notwendig ist, um eine Schließung wegen Inaktivität zu vermeiden. Dies kann das Senden kleiner Datenmengen, das schrittweise Öffnen von Flow-Control-Fenstern zur Kontrolle der Sender-Rate oder die Erzeugung von ACK-Frames umfassen, die eine hohe Verlustrate simulieren.
QUIC-Implementierungen SOLLTEN Schutzmaßnahmen gegen Slowloris-Angriffe bereitstellen, wie etwa die Erhöhung der maximalen Anzahl von Clients, die der Server zulässt, die Begrenzung der Anzahl von Verbindungen, die eine einzelne IP-Adresse aufbauen darf, die Einführung von Beschränkungen für die minimale Übertragungsgeschwindigkeit einer Verbindung und die Begrenzung der Zeitdauer, für die ein Endpunkt verbunden bleiben darf.
Amplification Attack
Ein böswilliger Sender könnte absichtlich Teile der Stream-Daten nicht senden, wodurch der Empfänger Ressourcen für die nicht gesendeten Daten bereitstellt. Dies könnte zu einer unverhältnismäßigen Speicherbelegung des Empfangspuffers und/oder zur Erstellung einer großen und ineffizienten Datenstruktur beim Empfänger führen.
Ein gegnerischer Empfänger könnte absichtlich Pakete mit Stream-Daten nicht bestätigen, um den Sender zu zwingen, die unbestätigten Stream-Daten für eine Neuübertragung zu speichern.
Der Angriff auf Empfänger wird abgemildert, wenn Flow-Control-Fenster dem verfügbaren Speicher entsprechen. Jedoch werden einige Empfänger Speicher überbelegen und Flow-Control-Offsets in der Gesamtheit bewerben, die den tatsächlich verfügbaren Speicher überschreiten. Die Überbelegungsstrategie kann zu besserer Leistung führen, wenn sich Endpunkte ordnungsgemäß verhalten, macht aber Endpunkte anfällig für den Stream-Fragmentierungsangriff.
QUIC-Implementierungen SOLLTEN Schutzmaßnahmen gegen Stream-Fragmentierungsangriffe bereitstellen. Schutzmaßnahmen könnten darin bestehen, eine Überallokation von Speicher zu vermeiden, die Größe von Tracking-Datenstrukturen zu begrenzen, die Wiederzusammensetzung von STREAM-Frames zu verzögern, Heuristiken basierend auf dem Alter und der Dauer von Wiederzusammensetzungslücken zu implementieren oder eine Kombination dieser Maßnahmen anzuwenden.
Optimistischer ACK-Angriff
Ein feindlicher Endpunkt kann eine große Anzahl von Streams öffnen und dadurch den Zustand eines Endpunkts erschöpfen. Der feindliche Endpunkt könnte diesen Prozess bei einer großen Anzahl von Verbindungen wiederholen, ähnlich wie bei SYN-Flooding-Angriffen in TCP.
Normalerweise öffnen Clients streams sequenziell, wie in Abschnitt 2.1 erläutert. Wenn jedoch mehrere streams in kurzen Abständen initiiert werden, können Verluste oder Neuordnungen dazu führen, dass STREAM-Frames, die streams öffnen, außerhalb der Reihenfolge empfangen werden. Beim Empfang einer höher nummerierten stream-ID ist ein Empfänger verpflichtet, alle dazwischenliegenden streams des gleichen Typs zu öffnen; siehe Abschnitt 3.2. Daher öffnet das Öffnen von stream 4000000 bei einer neuen Verbindung 1 Million und 1 client-initiierte bidirektionale streams.
Die Anzahl der aktiven Streams wird durch die Transport-Parameter initial_max_streams_bidi und initial_max_streams_uni begrenzt, die durch empfangene MAX_STREAMS-Frames aktualisiert werden, wie in Abschnitt 4.6 erklärt. Wenn diese Limits umsichtig gewählt werden, mildern sie die Auswirkungen des Stream-Commitment-Angriffs ab. Jedoch könnte eine zu niedrige Einstellung der Limits die Leistung beeinträchtigen, wenn Anwendungen erwarten, eine große Anzahl von Streams zu öffnen.
Request Forgery Angriffe
QUIC und TLS enthalten beide Frames oder Nachrichten, die in manchen Kontexten legitime Verwendungszwecke haben, aber diese Frames oder Nachrichten können missbraucht werden, um einen Peer dazu zu bringen, Verarbeitungsressourcen aufzuwenden, ohne dass dies eine beobachtbare Auswirkung auf den Zustand der Verbindung hat.
Nachrichten können auch verwendet werden, um Zustände auf kleine oder unerhebliche Weise zu ändern und zurückzusetzen, beispielsweise durch das Senden kleiner Erhöhungen an Flusskontrollgrenzen.
Wenn die Verarbeitungskosten unverhältnismäßig hoch im Vergleich zum Bandbreitenverbrauch oder zur Auswirkung auf den Zustand sind, könnte dies einem bösartigen Peer ermöglichen, die Verarbeitungskapazität zu erschöpfen.
Obwohl es legitime Verwendungen für alle Nachrichten gibt, SOLLTEN Implementierungen die Verarbeitungskosten im Verhältnis zum Fortschritt verfolgen und übermäßige Mengen von nicht-produktiven Paketen als Anzeichen eines Angriffs behandeln. Endpunkte KÖNNEN auf diese Bedingung mit einem Verbindungsfehler oder durch das Verwerfen von Paketen reagieren.
Steuerungsoptionen für Endpunkte
Ein Angreifer auf dem Übertragungsweg könnte den Wert der ECN-Felder im IP-Header manipulieren, um die Übertragungsrate des Senders zu beeinflussen. RFC3168 behandelt Manipulationen und deren Auswirkungen detaillierter.
Ein begrenzter On-Path-Angreifer kann Pakete duplizieren und mit modifizierten ECN-Feldern senden, um die Rate des Senders zu beeinflussen. Wenn duplizierte Pakete von einem Empfänger verworfen werden, muss ein Angreifer das duplizierte Paket gegen das Original antreten lassen, um bei diesem Angriff erfolgreich zu sein. Daher ignorieren QUIC-Endpunkte das ECN-Feld in einem IP-Paket, es sei denn, mindestens ein QUIC-Paket in diesem IP-Paket wird erfolgreich verarbeitet; siehe Abschnitt 13.4.
Request Forgery mit Client Initial Packets
Stateless Resets schaffen einen möglichen Denial-of-Service-Angriff, der einer TCP-Reset-Injektion ähnelt. Dieser Angriff ist möglich, wenn ein Angreifer dazu in der Lage ist, die Generierung eines Stateless-Reset-Tokens für eine Verbindung mit einer ausgewählten Connection ID zu verursachen. Ein Angreifer, der die Generierung dieses Tokens verursachen kann, kann eine aktive Verbindung mit derselben Connection ID zurücksetzen.
Wenn ein Paket an verschiedene Instanzen weitergeleitet werden kann, die einen statischen Schlüssel teilen – zum Beispiel durch Änderung einer IP-Adresse oder eines Ports – dann kann ein Angreifer den Server dazu bringen, einen stateless reset zu senden. Um sich gegen diese Art von Denial-of-Service-Angriff zu verteidigen, MÜSSEN Endpunkte, die einen statischen Schlüssel für stateless resets teilen (siehe Abschnitt 10.3.2), so angeordnet werden, dass Pakete mit einer gegebenen connection ID immer bei einer Instanz ankommen, die einen Verbindungszustand hat, es sei denn, diese Verbindung ist nicht mehr aktiv.
Allgemeiner ausgedrückt DÜRFEN Server KEINEN stateless reset generieren, wenn eine Verbindung mit der entsprechenden connection ID auf einem beliebigen Endpunkt aktiv sein könnte, der denselben statischen Schlüssel verwendet.
Im Fall eines Clusters, der dynamisches Lastausgleich verwendet, ist es möglich, dass eine Änderung in der Load-Balancer-Konfiguration auftreten könnte, während eine aktive Instanz den Verbindungsstatus beibehält. Selbst wenn eine Instanz den Verbindungsstatus beibehält, führt die Änderung im Routing und der daraus resultierende zustandslose Reset dazu, dass die Verbindung beendet wird. Wenn es keine Chance gibt, dass das Paket zur korrekten Instanz geroutet wird, ist es besser, einen zustandslosen Reset zu senden, als darauf zu warten, dass die Verbindung eine Zeitüberschreitung erreicht. Dies ist jedoch nur akzeptabel, wenn das Routing nicht von einem Angreifer beeinflusst werden kann.
Request Forgery mit bevorzugten Adressen
Dieses Dokument definiert QUIC Version Negotiation-Pakete (Abschnitt 6), die zur Aushandlung der zwischen zwei Endpunkten verwendeten QUIC-Version genutzt werden können. Allerdings spezifiziert dieses Dokument nicht, wie diese Aushandlung zwischen dieser Version und nachfolgenden zukünftigen Versionen durchgeführt wird. Insbesondere enthalten Version Negotiation-Pakete keinen Mechanismus zur Verhinderung von Version-Downgrade-Angriffen. Zukünftige QUIC-Versionen, die Version Negotiation-Pakete verwenden, MÜSSEN einen Mechanismus definieren, der robust gegen Version-Downgrade-Angriffe ist.
Request Forgery mit gefälschter Migration
Deployments sollten die Fähigkeit eines Angreifers begrenzen, eine neue Verbindung auf eine bestimmte Server-Instanz zu richten. Idealerweise werden Routing-Entscheidungen unabhängig von client-gewählten Werten getroffen, einschließlich Adressen. Sobald eine Instanz ausgewählt ist, kann eine Verbindungs-ID gewählt werden, damit spätere Pakete an dieselbe Instanz geroutet werden.
Request Forgery mit Version Negotiation
Die Länge von QUIC-Paketen kann Informationen über die Länge des Inhalts dieser Pakete preisgeben. Der PADDING-Frame wird bereitgestellt, damit Endpunkte die Möglichkeit haben, die Länge des Paketinhalts zu verschleiern; siehe Abschnitt 19.1.
Die Überwindung der Verkehrsanalyse ist herausfordernd und Gegenstand aktiver Forschung. Die Länge ist nicht die einzige Art, wie Informationen preisgegeben werden könnten. Endpunkte könnten auch sensible Informationen durch andere Seitenkanäle preisgeben, wie etwa das Timing von Paketen.
Relay Security
Folgende ist eine Analyse von Relay Request, Relay Response, Relay Intro und Hole Punch in SSU1.
Einschränkungen: Es ist wichtig, dass Relays schnell sind. Roundtrips sollten minimiert werden. Bandbreite und CPU sind nicht so wichtig.
SSU 1: Alice verbindet sich zuerst mit dem Introducer Bob, der die Anfrage an Charlie weiterleitet (der sich hinter einer Firewall befindet). Nach dem Hole Punch wird die Sitzung zwischen Alice und Charlie wie bei einer direkten Verbindung aufgebaut.
Alice Bob Charlie
1. RelayRequest ---------------------->
2. <-------------- RelayResponse RelayIntro ----------->
3. <-------------------------------------------- HolePunch
4. SessionRequest -------------------------------------------->
5. <-------------------------------------------- SessionCreated
6. SessionConfirmed ------------------------------------------>
Authentifizierung: Relay Request und Relay Response sind nicht sicher unauthentifiziert, da Alice und Bob normalerweise keine bestehende Sitzung haben; diese Nachrichten verwenden veröffentlichte Intro-Schlüssel. Sitzungsinterne Relay Request/Response ist erlaubt und bevorzugt, wenn eine Sitzung existiert.
Relay Intro von Bob zu Charlie muss in einer bestehenden Session erfolgen, daher wird sie als sicher vorausgesetzt.
Bob kann Relay Intros fälschen oder IP/Port aus der Relay Request ändern. Es gibt keine Mechanismen, um Anfragen kryptographisch an Intros zu binden oder anderweitig bösartige Bobs zu verhindern oder zu erkennen.
Bobs router Hash ist derzeit nicht in Charlies Router Info veröffentlicht, daher muss dieser hinzugefügt werden, wenn wir möchten, dass die Alice-Bob-Nachrichten authentifiziert werden. Zusätzlich müssten andere SSU2-Parameter in Charlies Router Info veröffentlicht werden, oder Alice müsste Bobs Router Info in der Netzwerkdatenbank nachschlagen, was zusätzliche Verzögerung hinzufügt. Die Authentifizierung würde einen Roundtrip zwischen Alice und Bob hinzufügen.
Durch die Weiterleitung von Alices router hash an Charlie könnte Charlie leichter bestimmen, ob er eine Verbindung von Alice erhalten möchte, indem er eine lokale Sperrliste überprüft. Es gibt keinen Mechanismus für Charlie, das Relay abzulehnen, indem er eine Ablehnung über Bob an Alice sendet. Es gibt keinen Mechanismus für Charlie, das Relay zu akzeptieren, indem er eine Annahme über Bob an Alice sendet. Alice muss auf den HolePunch warten oder einfach die SessionRequest blind senden. Der HolePunch kann von einem anderen Port kommen, als Alice erwartet hat, aufgrund von NAT, was es schwieriger machen kann, zu erkennen, von welchem router der HolePunch stammt.
Alice könnte ihre vollständige Router Info in der Relay Request an Bob senden und diese in der Relay Intro an Charlie weiterleiten.
Die Relay Request enthält keinen Zeitstempel, daher hat sie keinen Schutz vor Replay-Angriffen. Die Quell-IP kann gefälscht werden, um Charlie dazu zu bringen, einen Hole Punch an eine beliebige IP/Port zu senden. Die Relay Request ist nicht signiert, und selbst wenn sie signiert und mit einem Zeitstempel versehen wäre, hat Charlie nicht die vollständige Router Identity, um die Signatur verifizieren zu können.
Das Protokoll definiert ein Challenge-Feld variabler Länge von 0-255 Bytes. Die Challenge in der Relay Request wird an Charlie in der Relay Intro weitergegeben. Das Protokoll spezifiziert jedoch nicht, wie die Challenge erstellt, verwendet oder verifiziert werden soll, und sie ist nicht implementiert. Wenn der HolePunch die Challenge enthalten würde, könnte Alice den HolePunch leicht mit Charlie korrelieren.
Vier-Byte-Nonce muss möglicherweise durch eine 8-Byte-Verbindungs-ID ersetzt oder ergänzt werden.
Die leere Hole Punch-Nachricht ist einzigartig und könnte von Beobachtern im Netzwerkpfad zur Identifizierung des Protokolls verwendet werden, dies sollte geändert werden.
Zusätzliche DPI-Diskussion
Folgende ist eine Analyse des Peer Test in SSU1.
Einschränkungen: Es ist nicht besonders wichtig, dass Peer Tests schnell, bandbreitenschonend oder CPU-schonend sind, außer vielleicht beim Router-Start, wo wir bevorzugen, dass der Router seine Erreichbarkeit ziemlich schnell ermittelt.
SSU 1:
Alice Bob Charlie
1. PeerTest ------------------->
2. PeerTest-------------------->
3. <-------------------PeerTest
4. <-------------------PeerTest
5. <------------------------------------------PeerTest
6. PeerTest------------------------------------------>
7. <------------------------------------------PeerTest
Da die SSU1-Spezifikation schwer nachvollziehbar ist, dokumentieren wir die Nachrichteninhalte nachfolgend.
| Message | Path | Alice IP incl? | Intro Key |
|---|---|---|---|
| 1 | A->B session | no | Alice |
| 2 | B->C session | yes | Alice |
| 3 | C->B session | yes | Charlie |
| 4 | B->A session | yes | Charlie |
| 5 | C->A | yes | Charlie |
| 6 | A->C | no | Alice |
| 7 | C->A | yes | Charlie |
| Authentifizierung: Alice wird immer einen Bob mit einer bestehenden Sitzung wählen. Bob wird PeerTests von Peers ohne etablierte Sitzung ablehnen. Nachricht 1 wird innerhalb der Sitzung gesendet. Daher ist Nachricht 1 sicher und authentifiziert. |
Bob wählt einen Charlie aus, mit dem er bereits eine bestehende Sitzung hat. Nachrichten 2 und 3 werden innerhalb der Sitzung gesendet. Daher sind Nachrichten 2 und 3 sicher und authentifiziert.
Message 4 sollte in-session gesendet werden; jedoch besagte die SSU 1-Spezifikation zuvor, dass sie mit Alices veröffentlichtem Intro-Key gesendet wird, was bedeutet, dass sie nicht in-session ist. Vor 0.9.52 sendete Java I2P tatsächlich mit dem Intro-Key. Ab 0.9.52 besagt die Spezifikation, dass der Session-Key verwendet werden sollte, und Java I2P sendet die Message ab 0.9.52 in-session.
Alice darf keine bestehende Sitzung mit Charlie haben, damit der Test fortgesetzt werden kann; Alice bricht den Test ab, wenn Bob einen Charlie auswählt, der eine Sitzung mit Alice hat. Daher sind die Nachrichten 5-7 nicht sicher und authentifiziert.
Alle Peer Test-Nachrichten enthalten eine 4-Byte-Nonce, die von Alice gewählt wird. Diese Nonce wird nicht kryptographisch verwendet.
Mögliche Angriffe auf Nachrichten 5-7: zu erforschen.
Alice’s router hash ist Charlie nicht bekannt. Charlie’s router hash ist Alice nicht bekannt. Diese müssen zum Protokoll hinzugefügt werden, wenn wir wollen, dass die Alice-Charlie-Nachrichten authentifiziert werden. Zusätzlich müssten andere SSU2-Parameter in den Peer Test-Nachrichten bereitgestellt werden, oder Charlie müsste Alice’s Router Info in der Netzwerkdatenbank nachschlagen, was zusätzliche Verzögerung hinzufügt. Authentifizierung würde einen Round-Trip zwischen Charlie und Alice hinzufügen.
Indem Alice’s Router-Hash an Charlie weitergeleitet wird, könnte Charlie leichter bestimmen, ob er an einem Peer Test mit Alice teilnehmen möchte, indem er eine lokale Sperrliste überprüft.
Vier-Byte-Nonce muss möglicherweise durch eine 8-Byte-Verbindungs-ID ersetzt oder ergänzt werden.
Relay and Peer Test Design Goals
Relay und Peer Test haben ähnliche Strukturen. In beiden Fällen fordert Alice Bob auf, eine Serviceanfrage an Charlie weiterzuleiten, und Charlie handelt dann entsprechend dieser Anfrage.
Aktuelle SSU1 Peer Test Probleme:
- Peer Test hat keinen Schutz gegen einen bösartigen Bob
- Peer Test bietet Bob oder Charlie keine Möglichkeit, eine Anfrage abzulehnen
- Peer Test bietet Alice keine Möglichkeit, Charlies Identität zu erfahren oder Charlie abzulehnen
- Peer Test bietet Charlie keine Möglichkeit, Alices Identität zu erfahren oder Alice abzulehnen
- Peer Test verwendet ein eigenes Ad-hoc-Wiederübertragungsschema
- Peer Test erfordert eine komplexe Zustandsmaschine, um zu wissen, welche Nachricht für welchen Zustand bestimmt ist
- Ohne zu wissen, dass Charlie sie abgelehnt hat, wird Alice den Test als Fehlschlag betrachten.
Aktuelle SSU1 Relay-Probleme:
Die meisten der oben aufgeführten Peer Test-Probleme gelten auch für Peer Test.
Wir haben die folgenden Ziele bei der Verbesserung der Sicherheit von Relay und Peer Test:
Charlie sollte genügend Informationen über seine Introducer (Bobs) in der netDb veröffentlichen, damit Alice die Informationen bei Bedarf validieren kann. Zum Beispiel würde die Veröffentlichung eines Router-Hash für jeden Introducer es Alice ermöglichen, sofern die Zeit es erlaubt, die Router-Informationen aus der netDb abzurufen.
Schutz vor Adressfälschung oder On-Path-Bedrohungen, die Anfragen von Alice an Bob fälschen, verändern, nachahmen oder wiederholen könnten. Bob muss sicherstellen, dass Alice ein echter I2P router ist und dass die präsentierte Anfrage und Testadresse gültig sind.
Schutz vor bösartigen Bobs, die Anfragen an Charlie spoofing, verändern, fälschen oder wiederholen könnten. Charlie muss sicherstellen, dass sowohl Alice als auch Bob tatsächliche I2P router sind und dass die präsentierte Anfrage und Testadresse gültig sind.
Bob muss ausreichende Informationen von Alice erhalten, um die Anfrage validieren und dann annehmen oder ablehnen zu können. Bob muss über einen Mechanismus verfügen, um die Annahme oder Ablehnung an Alice zurückzusenden. Bob darf niemals dazu verpflichtet werden, die angeforderte Aktion auszuführen.
Charlie muss genügend Informationen von Bob erhalten, um die Anfrage validieren und dann annehmen oder ablehnen zu können. Charlie muss über einen Mechanismus verfügen, um die Annahme oder Ablehnung an Bob zurückzusenden, damit dieser sie an Alice weiterleiten kann. Charlie darf niemals dazu verpflichtet sein, die angeforderte Aktion auszuführen.
Alice muss in der Lage sein zu validieren, dass die über Bob weitergeleitete Antwort tatsächlich von Charlie stammt.
Alice und Charlie müssen in der Lage sein zu validieren, dass ihre nachfolgenden direkten Nachrichten (nicht über Bob weitergeleitet) von der erwarteten Quelle stammen und tatsächliche I2P router sind.
Die folgenden Mechanismen können dabei helfen, diese Ziele zu erreichen:
Zeitstempel
Signaturen mit dem Router-Signaturschlüssel
Verwendung von Challenge-Daten, die in der Anfrage enthalten sind
Verschlüsselung mit dem Router-Verschlüsselungsschlüssel
Senden von router-Hashes, Router Identities oder Router Infos, nicht nur IPs und Ports.
Validierung von Router-Informationen durch Abfrage der Netzwerkdatenbank
Überprüfung von Router-Informationen, IPs und Ports gegen Sperrlisten
Rate-Limiting
Erfordert Sitzungsaufbau
Diese möglichen Mechanismen können die Verarbeitungszeit und Latenz der Relay- oder Peer-Test-Funktionen erhöhen. Alle Auswirkungen müssen evaluiert werden.
Cross-Version-Weiterleitung und Peer-Tests sollten ebenfalls unterstützt werden, wenn möglich. Dies wird einen schrittweisen Übergang von SSU 1 zu SSU 2 erleichtern. Die möglichen Versionskombinationen sind:
| Alice/Bob | Bob/Charlie | Alice/Charlie | Supported |
|---|---|---|---|
| 1 | 1 | 1 | SSU 1 |
| 1 | 1 | 2 | no, use 1/1/1 |
| 1 | 2 | 1 | Relay: yes? Peer Test: no |
| 1 | 2 | 2 | no, use 1/2/1 |
| 2 | 1 | 1 | Relay: yes? Peer Test: no |
| 2 | 1 | 2 | Relay: yes? Peer Test: no |
| 2 | 2 | 1 | no, use 2/2/2 |
| 2 | 2 | 2 | yes |
Sicherheitsziele
Summary
Wir stützen uns auf verschiedene bestehende Protokolle, sowohl innerhalb von I2P als auch auf externe Standards, für Inspiration, Orientierung und Code-Wiederverwendung:
Bedrohungsmodelle: Von NTCP2 NTCP2, mit erheblichen zusätzlichen Bedrohungen, die für UDP-Transport relevant sind, wie von QUIC RFC 9000 RFC 9001 analysiert.
Kryptographische Entscheidungen: Aus NTCP2.
Handshake: Noise XK von NTCP2 und NOISE. Erhebliche Vereinfachungen gegenüber NTCP2 sind aufgrund der Kapselung (inhärente Nachrichtengrenzen) möglich, die UDP bereitstellt.
Handshake-Verschleierung für temporäre Schlüssel: Angepasst von NTCP2, aber mit ChaCha20 aus ECIES anstelle von AES.
Packet-Header: Adaptiert von WireGuard WireGuard und QUIC RFC 9000 RFC 9001.
Paket-Header-Verschleierung: Adaptiert von NTCP2, verwendet jedoch ChaCha20 aus ECIES anstelle von AES.
Header, die als AEAD associated data verwendet werden, wie in ECIES.
Paketnummerierung: Adaptiert von WireGuard WireGuard und QUIC RFC 9000 RFC 9001.
Messages: Adaptiert von SSU
I2NP-Fragmentierung: Adaptiert von SSU
Relay und Peer Testing: Adaptiert von SSU
Signaturen von Relay- und Peer-Test-Daten: Aus der Common Structures Spezifikation Common
Acks, nacks: Angepasst von QUIC RFC 9000.
Flusskontrolle: TBD
Es gibt keine neuen kryptographischen Primitive, die nicht bereits zuvor in I2P verwendet wurden.
Adressvalidierung
Wie bei anderen I2P-Transportprotokollen NTCP, NTCP2 und SSU 1 ist dieser Transport keine allgemeine Einrichtung für die Übertragung eines geordneten Byte-Streams. Er ist für den Transport von I2NP-Nachrichten konzipiert. Es wird keine “Stream”-Abstraktion bereitgestellt.
Darüber hinaus enthält es wie bei SSU zusätzliche Funktionen für peer-unterstützte NAT-Durchquerung und Tests der Erreichbarkeit (eingehende Verbindungen).
Wie bei SSU 1 bietet es KEINE geordnete Zustellung von I2NP-Nachrichten. Es bietet auch keine garantierte Zustellung von I2NP-Nachrichten. Aus Effizienzgründen oder aufgrund der ungeordneten Zustellung von UDP-Datagrammen oder des Verlusts dieser Datagramme können I2NP-Nachrichten am anderen Ende ungeordnet zugestellt werden oder gar nicht zugestellt werden. Eine I2NP-Nachricht kann bei Bedarf mehrmals erneut übertragen werden, aber die Zustellung kann schließlich fehlschlagen, ohne dass die gesamte Verbindung getrennt wird. Außerdem können neue I2NP-Nachrichten weiterhin gesendet werden, auch während die erneute Übertragung (Verlustwiederherstellung) für andere I2NP-Nachrichten stattfindet.
Dieses Protokoll verhindert NICHT vollständig die doppelte Zustellung von I2NP-Nachrichten. Der Router sollte das I2NP-Ablaufdatum durchsetzen und einen Bloom-Filter oder anderen Mechanismus basierend auf der I2NP-Nachrichten-ID verwenden. Siehe den Abschnitt I2NP Message Duplication weiter unten.
Noise Protocol Framework
Dieser Vorschlag stellt die Anforderungen basierend auf dem Noise Protocol Framework NOISE (Revision 33, 2017-10-04) bereit. Noise hat ähnliche Eigenschaften wie das Station-To-Station-Protokoll (STS), welches die Grundlage für das SSU-Protokoll bildet. In der Noise-Terminologie ist Alice der Initiator und Bob der Responder.
SSU2 basiert auf dem Noise-Protokoll Noise_XK_25519_ChaChaPoly_SHA256. (Die tatsächliche Kennung für die anfängliche Schlüsselableitungsfunktion ist “Noise_XKchaobfse+hs1+hs2+hs3_25519_ChaChaPoly_SHA256”, um I2P-Erweiterungen anzuzeigen - siehe KDF 1-Abschnitt unten)
HINWEIS: Dieser Identifikator unterscheidet sich von dem für NTCP2 verwendeten, da alle drei Handshake-Nachrichten den Header als zugehörige Daten verwenden.
Dieses Noise-Protokoll verwendet die folgenden Primitive:
Handshake Pattern: XK Alice überträgt ihren Schlüssel an Bob (X) Alice kennt Bobs statischen Schlüssel bereits (K)
DH Function: X25519 X25519 DH mit einer Schlüssellänge von 32 Bytes wie in RFC 7748 spezifiziert.
Cipher Function: ChaChaPoly AEAD_CHACHA20_POLY1305 wie in RFC 7539 Abschnitt 2.8 spezifiziert. 12 Byte Nonce, wobei die ersten 4 Bytes auf null gesetzt sind.
Hash Function: SHA256 Standard 32-Byte-Hash, bereits umfangreich in I2P verwendet.
Additions to the Framework
Dieser Vorschlag definiert die folgenden Verbesserungen für Noise_XK_25519_ChaChaPoly_SHA256. Diese folgen im Allgemeinen den Richtlinien in NOISE Abschnitt 13.
Handshake-Nachrichten (Session Request, Created, Confirmed) enthalten einen 16 oder 32 Byte Header.
Die Header für die Handshake-Nachrichten (Session Request, Created, Confirmed) werden als Eingabe für mixHash() vor der Verschlüsselung/Entschlüsselung verwendet, um die Header an die Nachricht zu binden.
Header sind verschlüsselt und geschützt.
Klartext-Ephemeral-Schlüssel werden mit ChaCha20-Verschlüsselung unter Verwendung eines bekannten Schlüssels und IV verschleiert. Dies ist schneller als elligator2.
Das Payload-Format ist für Nachrichten 1, 2 und die Datenphase definiert. Natürlich ist dies in Noise nicht definiert.
Die Datenphase verwendet eine Verschlüsselung, die der Noise-Datenphase ähnlich, aber nicht kompatibel mit ihr ist.
Processing overhead estimate
TBD
Definitions
Wir definieren die folgenden Funktionen, die den verwendeten kryptographischen Bausteinen entsprechen.
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
Jedes UDP-Datagramm enthält genau eine Nachricht. Die Länge des Datagramms (nach den IP- und UDP-Headern) entspricht der Länge der Nachricht. Padding, falls vorhanden, ist in einem Padding-Block innerhalb der Nachricht enthalten. In diesem Dokument verwenden wir die Begriffe “Datagramm” und “Paket” größtenteils synonym. Jedes Datagramm (oder Paket) enthält eine einzelne Nachricht (im Gegensatz zu QUIC, wo ein Datagramm mehrere QUIC-Pakete enthalten kann). Der “Paket-Header” ist der Teil nach dem IP/UDP-Header.
Ausnahme: Die Session Confirmed Nachricht ist einzigartig, da sie über mehrere Pakete fragmentiert werden kann. Siehe den Abschnitt Session Confirmed Fragmentation unten für weitere Informationen.
Alle SSU2-Nachrichten sind mindestens 40 Bytes lang. Jede Nachricht mit einer Länge von 1-39 Bytes ist ungültig. Alle SSU2-Nachrichten sind höchstens 1472 (IPv4) oder 1452 (IPv6) Bytes lang. Das Nachrichtenformat basiert auf Noise-Nachrichten, mit Modifikationen für Framing und Ununterscheidbarkeit. Implementierungen, die Standard-Noise-Bibliotheken verwenden, müssen empfangene Nachrichten zum Standard-Noise-Nachrichtenformat vorverarbeiten. Alle verschlüsselten Felder sind AEAD-Chiffretexte.
Die folgenden Nachrichten sind definiert:
| Type | Message | Header Length | Header Encr. Length |
|---|---|---|---|
| 0 | SessionRequest | 32 | 64 |
| 1 | SessionCreated | 32 | 64 |
| 2 | SessionConfirmed | 16 | 16 |
| 6 | Data | 16 | 16 |
| 7 | PeerTest | 32 | 32 |
| 9 | Retry | 32 | 32 |
| 10 | Token Request | 32 | 32 |
| 11 | HolePunch | 32 | 32 |
Session Establishment
Die standardmäßige Verbindungsaufbau-Sequenz, wenn Alice ein gültiges Token hat, das sie zuvor von Bob erhalten hat, ist wie folgt:
Alice Bob
SessionRequest ------------------->
<------------------- SessionCreated
SessionConfirmed ----------------->
Wenn Alice kein gültiges Token hat, ist die Establishment-Sequenz wie folgt:
Alice Bob
TokenRequest --------------------->
<--------------------------- Retry
SessionRequest ------------------->
<------------------- SessionCreated
SessionConfirmed ----------------->
Wenn Alice glaubt, dass sie ein gültiges Token hat, Bob es aber ablehnt (vielleicht weil Bob neu gestartet wurde), ist die Aufbausequenz wie folgt:
Alice Bob
SessionRequest ------------------->
<--------------------------- Retry
SessionRequest ------------------->
<------------------- SessionCreated
SessionConfirmed ----------------->
Bob kann eine Session- oder Token-Anfrage ablehnen, indem er mit einer Retry-Nachricht antwortet, die einen Termination-Block mit einem Grund-Code enthält. Basierend auf dem Grund-Code sollte Alice für eine bestimmte Zeit keine weitere Anfrage versuchen:
Alice Bob
SessionRequest ------------------->
<--------------------------- Retry containing a Termination block
or
TokenRequest --------------------->
<--------------------------- Retry containing a Termination block
Mit Noise-Terminologie ist die Einrichtungs- und Datensequenz wie folgt: (Payload Security Properties)
XK(s, rs): Authentication Confidentiality
<- s
...
-> e, es 0 2
<- e, ee 2 1
-> s, se 2 5
<- 2 5
Sobald eine Session etabliert wurde, können Alice und Bob Data-Nachrichten austauschen.
Packet Header
Alle Pakete beginnen mit einem verschleierten (verschlüsselten) Header. Es gibt zwei Header-Typen: lang und kurz. Beachten Sie, dass die ersten 13 Bytes (Destination Connection ID, Paketnummer und Typ) für alle Header gleich sind.
Allgemeine Gegenmaßnahmen gegen Request Forgery
Der lange Header ist 32 Bytes groß. Er wird verwendet, bevor eine Session erstellt wird, für Token Request, SessionRequest, SessionCreated und Retry. Er wird auch für sessionlose Peer Test und Hole Punch Nachrichten verwendet.
Vor Header-Verschlüsselung:
+----+----+----+----+----+----+----+----+
| 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
Slowloris-Angriffe
Der kurze Header ist 16 Bytes lang. Er wird für Session Created und für Data-Nachrichten verwendet. Nicht authentifizierte Nachrichten wie Session Request, Retry und Peer Test verwenden immer den langen Header.
16 Bytes sind erforderlich, da der Empfänger die ersten 16 Bytes entschlüsseln muss, um den Nachrichtentyp zu erhalten, und dann zusätzliche 16 Bytes entschlüsseln muss, falls es sich tatsächlich um einen langen Header handelt, wie durch den Nachrichtentyp angezeigt.
Für Session Confirmed, vor der Header-Verschlüsselung:
+----+----+----+----+----+----+----+----+
| 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
Siehe den Abschnitt Session Confirmed Fragmentation weiter unten für weitere Informationen über das frag-Feld.
Für Data-Nachrichten, vor der Header-Verschlüsselung:
+----+----+----+----+----+----+----+----+
| 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
Stream-Fragmentierung und Reassembly-Angriffe
Connection IDs müssen zufällig generiert werden. Quell- und Ziel-IDs dürfen NICHT identisch sein, damit ein Angreifer auf dem Übertragungsweg kein Paket abfangen und an den Absender zurücksenden kann, das gültig aussieht. Verwenden Sie KEINEN Zähler zur Generierung von Connection IDs, damit ein Angreifer auf dem Übertragungsweg kein Paket generieren kann, das gültig aussieht.
Im Gegensatz zu QUIC ändern wir die Verbindungs-IDs nicht während oder nach dem Handshake, auch nicht nach einer Retry-Nachricht. Die IDs bleiben konstant von der ersten Nachricht (Token Request oder Session Request) bis zur letzten Nachricht (Data with Termination). Zusätzlich ändern sich die Verbindungs-IDs nicht während oder nach Path Challenge oder Connection Migration.
Ebenfalls anders als bei QUIC ist, dass Verbindungs-IDs in den Headern immer header-verschlüsselt sind. Siehe unten.
Stream Commitment Angriff
Wenn kein First Packet Number Block im Handshake gesendet wird, werden Pakete innerhalb einer einzelnen Sitzung für jede Richtung nummeriert, beginnend bei 0 bis zu einem Maximum von (2**32 -1). Eine Sitzung muss beendet und eine neue Sitzung erstellt werden, deutlich bevor die maximale Anzahl von Paketen gesendet wird.
Wenn ein First Packet Number Block während des Handshakes gesendet wird, werden Pakete innerhalb einer einzelnen Session für diese Richtung nummeriert, beginnend mit dieser Paketnummer. Die Paketnummer kann während der Session überlaufen. Wenn maximal 2**32 Pakete gesendet wurden und die Paketnummer zur ersten Paketnummer zurückspringt, ist diese Session nicht mehr gültig. Eine Session muss beendet und eine neue Session erstellt werden, deutlich bevor die maximale Anzahl von Paketen gesendet wird.
TODO Schlüsselrotation, maximale Paketnummer reduzieren?
Handshake-Pakete, die als verloren bestimmt werden, werden vollständig retransmittiert, mit dem identischen Header einschließlich Paketnummer. Die Handshake-Nachrichten Session Request, Session Created und Session Confirmed MÜSSEN mit derselben Paketnummer und identischen verschlüsselten Inhalten retransmittiert werden, damit derselbe verkettete Hash zur Verschlüsselung der Antwort verwendet wird. Die Retry-Nachricht wird niemals übertragen.
Datenphasen-Pakete, die als verloren eingestuft werden, werden niemals vollständig erneut übertragen (außer bei der Terminierung, siehe unten). Dasselbe gilt für die Blöcke, die in verlorenen Paketen enthalten sind. Stattdessen werden die Informationen, die möglicherweise in Blöcken übertragen werden, bei Bedarf erneut in neuen Paketen gesendet. Datenpakete werden niemals mit derselben Paketnummer erneut übertragen. Jede erneute Übertragung von Paketinhalten (unabhängig davon, ob die Inhalte gleich bleiben oder nicht) muss die nächste unbenutzte Paketnummer verwenden.
Die unveränderte Weiterleitung eines ganzen Pakets im ursprünglichen Zustand mit derselben Paketnummer ist aus mehreren Gründen nicht erlaubt. Für Hintergrundinformationen siehe QUIC RFC 9000 Abschnitt 12.3.
- Es ist ineffizient, Pakete für die Neuübertragung zu speichern
- Ein neues Paket sieht für einen Beobachter auf dem Pfad anders aus, er kann nicht erkennen, dass es erneut übertragen wird
- Ein neues Paket erhält einen aktualisierten ack-Block, nicht den alten ack-Block
- Du überträgst nur das, was notwendig ist. Einige Fragmente könnten bereits einmal erneut übertragen und bestätigt worden sein
- Du kannst so viel wie nötig in jedes erneut übertragene Paket packen, wenn mehr aussteht
- Endpunkte, die alle einzelnen Pakete zum Zweck der Erkennung von Duplikaten verfolgen, laufen Gefahr, übermäßig viel Zustand anzusammeln. Die für die Erkennung von Duplikaten erforderlichen Daten können begrenzt werden, indem eine minimale Paketnummer beibehalten wird, unter der alle Pakete sofort verworfen werden.
- Dieses Schema ist viel flexibler
Neue Pakete werden verwendet, um Informationen zu übertragen, die als verloren gegangen eingestuft wurden. Im Allgemeinen werden Informationen erneut gesendet, wenn ein Paket, das diese Informationen enthält, als verloren eingestuft wird, und das Senden wird beendet, wenn ein Paket, das diese Informationen enthält, bestätigt wird (remain the same).
Ausnahme: Ein Data-Phase-Paket, das einen Termination-Block enthält, kann, aber muss nicht, vollständig und unverändert erneut übertragen werden. Siehe den Abschnitt Session Termination unten.
Die folgenden Pakete enthalten eine zufällige Paketnummer, die ignoriert wird:
- Session Request
- Session Created
- Token Request
- Retry
- Peer Test
- Hole Punch
Für Alice beginnt die ausgehende Paketnummerierung bei 0 mit Session Confirmed. Für Bob beginnt die ausgehende Paketnummerierung bei 0 mit dem ersten Data-Paket, welches ein ACK des Session Confirmed sein sollte. Die Paketnummern in einem beispielhaften Standard-Handshake werden sein:
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.
Jede Wiederübertragung von Handshake-Nachrichten (SessionRequest, SessionCreated oder SessionConfirmed) muss unverändert mit derselben Paketnummer erneut gesendet werden. Verwenden Sie keine unterschiedlichen ephemeren Schlüssel und ändern Sie die Nutzdaten nicht beim Wiedersenden dieser Nachrichten.
Peer Denial of Service
Der Header (vor Verschleierung und Schutz) ist immer in den zugehörigen Daten für die AEAD-Funktion enthalten, um den Header kryptographisch an die Daten zu binden.
Explicit Congestion Notification Angriffe
Header-Verschlüsselung hat mehrere Ziele. Siehe den Abschnitt “Additional DPI Discussion” oben für Hintergrund und Annahmen.
- Online-DPI daran hindern, das Protokoll zu identifizieren
- Muster in einer Serie von Nachrichten derselben Verbindung verhindern, außer bei Handshake-Wiederholungsübertragungen
- Muster in Nachrichten desselben Typs in verschiedenen Verbindungen verhindern
- Entschlüsselung von Handshake-Headern verhindern ohne Kenntnis des introduction key aus der netDb
- Identifizierung von X25519 ephemeral keys verhindern ohne Kenntnis des introduction key aus der netDb
- Entschlüsselung von Paketnummer und -typ der Datenphase verhindern durch jeden Online- oder Offline-Angreifer
- Einschleusung gültiger Handshake-Pakete durch einen On-Path- oder Off-Path-Beobachter verhindern ohne Kenntnis des introduction key aus der netDb
- Einschleusung gültiger Datenpakete durch einen On-Path- oder Off-Path-Beobachter verhindern
- Schnelle und effiziente Klassifizierung eingehender Pakete ermöglichen
- “Probing”-Resistenz bieten, sodass es keine Antwort auf eine fehlerhafte Session Request gibt, oder falls es eine Retry-Antwort gibt, die Antwort nicht als I2P identifizierbar ist ohne Kenntnis des introduction key aus der netDb
- Die Destination Connection ID ist kein kritischer Datenbestandteil, und es ist in Ordnung, wenn sie von einem Beobachter entschlüsselt werden kann, der Kenntnis des introduction key aus der netDb hat
- Die Paketnummer eines Datenphase-Pakets ist eine AEAD-Nonce und stellt kritische Daten dar. Sie darf nicht von einem Beobachter entschlüsselbar sein, selbst mit Kenntnis des introduction key aus der netDb. Siehe Nonces.
Header werden mit bekannten Schlüsseln verschlüsselt, die in der Netzwerkdatenbank veröffentlicht oder später berechnet werden. In der Handshake-Phase dient dies nur dem DPI-Widerstand, da der Schlüssel öffentlich ist und Schlüssel und Nonces wiederverwendet werden, sodass es praktisch nur Verschleierung ist. Beachten Sie, dass die Header-Verschlüsselung auch verwendet wird, um die ephemeren Schlüssel X (in Session Request) und Y (in Session Created) zu verschleiern.
Siehe den Abschnitt “Inbound Packet Handling” unten für weitere Anleitungen.
Die Bytes 0-15 aller Header werden mit einem Header-Schutzschema verschlüsselt, indem sie mit Daten XOR-verknüpft werden, die aus bekannten Schlüsseln berechnet werden, unter Verwendung von ChaCha20, ähnlich wie bei QUIC RFC 9001 und Nonces. Dies stellt sicher, dass der verschlüsselte kurze Header und der erste Teil des langen Headers zufällig erscheinen.
Für Session Request und Session Created werden die Bytes 16-31 des langen Headers und der 32-Byte Noise ephemeral key mit ChaCha20 verschlüsselt. Die unverschlüsselten Daten sind zufällig, daher werden die verschlüsselten Daten ebenfalls zufällig erscheinen.
Für Retry werden die Bytes 16-31 des langen Headers mit ChaCha20 verschlüsselt. Die unverschlüsselten Daten sind zufällig, daher werden die verschlüsselten Daten ebenfalls zufällig erscheinen.
Im Gegensatz zum QUIC RFC 9001 Header-Protection-Schema werden ALLE Teile aller Header, einschließlich Ziel- und Quell-Connection-IDs, verschlüsselt. QUIC RFC 9001 und Nonces konzentrieren sich hauptsächlich auf die Verschlüsselung des “kritischen” Teils des Headers, d.h. der Paketnummer (ChaCha20-Nonce). Während die Verschlüsselung der Session-ID die Klassifizierung eingehender Pakete etwas komplexer macht, erschwert sie einige Angriffe. QUIC definiert verschiedene Connection-IDs für verschiedene Phasen und für Path-Challenge und Connection-Migration. Hier verwenden wir durchgehend dieselben Connection-IDs, da sie verschlüsselt sind.
Es gibt sieben Header Protection Key-Phasen:
- Session Request und Token Request
- Session Created
- Retry
- Session Confirmed
- Data Phase
- Peer Test
- Hole Punch
| Message | Key k_header_1 | Key k_header_2 |
|---|---|---|
| Token Request | Bob Intro Key | Bob Intro Key |
| Session Request | Bob Intro Key | Bob Intro Key |
| Session Created | Bob Intro Key | See Session Request K |
| Session Confirmed | Bob Intro Key | See Session Created K |
| Retry | Bob Intro Key | Bob Intro Key |
| Data | Alice/Bob Intro Key | See data phase KDF |
| Peer Test 5,7 | Alice Intro Key | Alice Intro Key |
| Peer Test 6 | Charlie Intro Key | Charlie Intro Key |
| Hole Punch | Alice Intro Key | Alice Intro Key |
| Header-Verschlüsselung ist darauf ausgelegt, eine schnelle Klassifizierung eingehender Pakete zu ermöglichen, ohne komplexe Heuristiken oder Fallback-Mechanismen. Dies wird erreicht, indem derselbe k_header_1-Schlüssel für fast alle eingehenden Nachrichten verwendet wird. Selbst wenn sich die Quell-IP oder der Port einer Verbindung aufgrund einer tatsächlichen IP-Änderung oder NAT-Verhalten ändert, kann das Paket schnell einer Session mit einer einzigen Abfrage der Verbindungs-ID zugeordnet werden. |
Beachten Sie, dass Session Created und Retry die EINZIGEN Nachrichten sind, die eine Fallback-Verarbeitung für k_header_1 zur Entschlüsselung der Connection ID benötigen, da sie den intro key des Absenders (Bob) verwenden. ALLE anderen Nachrichten verwenden den intro key des Empfängers für k_header_1. Die Fallback-Verarbeitung muss nur ausstehende ausgehende Verbindungen nach Quell-IP/Port nachschlagen.
Wenn die Fallback-Verarbeitung nach Quell-IP/Port keine ausstehende ausgehende Verbindung finden kann, könnte es mehrere Ursachen geben:
- Keine SSU2-Nachricht
- Eine beschädigte SSU2-Nachricht
- Die Antwort ist gefälscht oder von einem Angreifer modifiziert
- Bob hat ein symmetrisches NAT
- Bob hat IP oder Port während der Verarbeitung der Nachricht geändert
- Bob hat die Antwort über eine andere Schnittstelle gesendet
Obwohl zusätzliche Fallback-Verarbeitung möglich ist, um zu versuchen, die ausstehende ausgehende Verbindung zu finden und die Verbindungs-ID mit dem k_header_1 für diese Verbindung zu entschlüsseln, ist dies wahrscheinlich nicht notwendig. Wenn Bob Probleme mit seinem NAT oder Paket-Routing hat, ist es wahrscheinlich besser, die Verbindung fehlschlagen zu lassen. Dieses Design beruht darauf, dass Endpunkte eine stabile Adresse für die Dauer des Handshakes beibehalten.
Siehe den Abschnitt zur Verarbeitung eingehender Pakete unten für zusätzliche Richtlinien.
Siehe die einzelnen KDF-Abschnitte unten für die Ableitung der Header-Verschlüsselungsschlüssel für diese Phase.
Stateless Reset Oracle
// 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])
Diese KDF verwendet die letzten 24 Bytes des Pakets als IV für die beiden ChaCha20-Operationen. Da alle Pakete mit einem 16-Byte-MAC enden, erfordert dies, dass alle Paket-Payloads mindestens 8 Bytes groß sind. Diese Anforderung wird zusätzlich in den Nachrichtenabschnitten unten dokumentiert.
Version-Downgrade
Nach der Entschlüsselung der ersten 8 Bytes des Headers kennt der Empfänger die Destination Connection ID. Von dort aus weiß der Empfänger, welchen Header-Verschlüsselungsschlüssel er für den Rest des Headers verwenden muss, basierend auf der Schlüsselphase der Sitzung.
Die Entschlüsselung der nächsten 8 Bytes des Headers wird dann den Nachrichtentyp preisgeben und es ermöglichen zu bestimmen, ob es sich um einen kurzen oder langen Header handelt. Wenn es sich um einen langen Header handelt, muss der Empfänger die Versions- und netid-Felder validieren. Wenn die Version != 2 ist oder die netid != dem erwarteten Wert (normalerweise 2, außer in Testnetzwerken), sollte der Empfänger die Nachricht verwerfen.
Packet Integrity
Alle Nachrichten enthalten entweder drei oder vier Teile:
- Der Nachrichten-Header
- Nur für Session Request und Session Created, ein ephemerer Schlüssel
- Eine ChaCha20-verschlüsselte Payload
- Ein Poly1305 MAC
In allen Fällen ist der Header (und falls vorhanden, der ephemere Schlüssel) an den Authentifizierungs-MAC gebunden, um sicherzustellen, dass die gesamte Nachricht unversehrt ist.
- Bei Handshake-Nachrichten Session Request, Session Created und Session Confirmed wird der Nachrichten-Header vor der Noise-Verarbeitungsphase mixHash()ed
- Der ephemeral key, falls vorhanden, wird durch einen Standard-Noise misHash() abgedeckt
- Bei Nachrichten außerhalb des Noise-Handshakes wird der Header als Associated Data für die ChaCha20/Poly1305-Verschlüsselung verwendet.
Eingehende Paket-Handler müssen immer die ChaCha20-Payload entschlüsseln und den MAC validieren, bevor sie die Nachricht verarbeiten, mit einer Ausnahme: Um DoS-Angriffe von address-spoofed Paketen abzumildern, die scheinbare Session Request-Nachrichten mit einem ungültigen Token enthalten, muss ein Handler NICHT versuchen, die vollständige Nachricht zu entschlüsseln und zu validieren (was eine aufwändige DH-Operation zusätzlich zur ChaCha20/Poly1305-Entschlüsselung erfordern würde). Der Handler kann mit einer Retry-Nachricht antworten, die die im Header der Session Request-Nachricht gefundenen Werte verwendet.
Authenticated Encryption
Es gibt drei separate authentifizierte Verschlüsselungsinstanzen (CipherStates). Eine während der Handshake-Phase und zwei (Senden und Empfangen) für die Datenphase. Jede hat ihren eigenen Schlüssel aus einer KDF.
Verschlüsselte/authentifizierte Daten werden dargestellt als
+----+----+----+----+----+----+----+----+
| |
+ +
| Encrypted and authenticated data |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
Gezielte Angriffe durch Routing
Verschlüsseltes und authentifiziertes Datenformat.
Eingaben für die Verschlüsselungs-/Entschlüsselungsfunktionen:
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
Ausgabe der Verschlüsselungsfunktion, Eingabe der Entschlüsselungsfunktion:
+----+----+----+----+----+----+----+----+
| |
+ +
| 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
Für ChaCha20 entspricht das hier Beschriebene RFC 7539, das auch ähnlich in TLS RFC 7905 verwendet wird.
Verkehrsanalyse
Da ChaCha20 eine Stream-Cipher ist, müssen Klartexte nicht aufgefüllt werden. Zusätzliche Keystream-Bytes werden verworfen.
Der Schlüssel für die Chiffre (256 Bits) wird mittels SHA256 KDF vereinbart. Die Details des KDF für jede Nachricht sind in separaten Abschnitten unten aufgeführt.
AEAD Error Handling
In allen Nachrichten ist die AEAD-Nachrichtengröße im Voraus bekannt. Bei einem AEAD-Authentifizierungsfehler muss der Empfänger die weitere Nachrichtenverarbeitung stoppen und die Nachricht verwerfen.
Bob sollte eine Blacklist von IP-Adressen mit wiederholten Fehlern führen.
KDF for Session Request
Die Key Derivation Function (KDF) generiert einen Handshake-Phasen-Chiffrierschlüssel k aus dem DH-Ergebnis, unter Verwendung von HMAC-SHA256(key, data) wie in RFC 2104 definiert. Dies sind die Funktionen InitializeSymmetric(), MixHash() und MixKey(), genau wie in der Noise-Spezifikation definiert.
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 sendet an Bob, entweder als erste Nachricht im Handshake oder als Antwort auf eine Retry-Nachricht. Bob antwortet mit einer Session Created-Nachricht. Größe: 80 + Payload-Größe. Mindestgröße: 88
Wenn Alice kein gültiges Token hat, sollte Alice eine Token Request Nachricht anstelle einer Session Request senden, um den Overhead der asymmetrischen Verschlüsselung bei der Generierung einer Session Request zu vermeiden.
Langer Header. Noise-Inhalt: Alices ephemerer Schlüssel X Noise-Payload: DateTime und andere Blöcke Maximale Payload-Größe: MTU - 108 (IPv4) oder MTU - 128 (IPv6). Für 1280 MTU: Maximale Payload ist 1172 (IPv4) oder 1152 (IPv6). Für 1500 MTU: Maximale Payload ist 1392 (IPv4) oder 1372 (IPv6).
Payload-Sicherheitseigenschaften:
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.
Der X-Wert wird verschlüsselt, um Payload-Ununterscheidbarkeit und Eindeutigkeit sicherzustellen, welche notwendige DPI-Gegenmaßnahmen sind. Wir verwenden ChaCha20-Verschlüsselung, um dies zu erreichen, anstatt komplexerer und langsamerer Alternativen wie elligator2. Asymmetrische Verschlüsselung mit Bobs router public key wäre viel zu langsam. Die ChaCha20-Verschlüsselung verwendet Bobs intro key, wie er in der netDb veröffentlicht ist.
ChaCha20-Verschlüsselung dient nur der DPI-Resistenz. Jede Partei, die Bobs Einführungsschlüssel kennt, der in der netDb veröffentlicht ist, kann den Header und X-Wert in dieser Nachricht entschlüsseln.
Rohe Inhalte:
+----+----+----+----+----+----+----+----+
| 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)
Unverschlüsselte Daten (Poly1305-Authentifizierungs-Tag nicht dargestellt):
+----+----+----+----+----+----+----+----+
| 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
- DateTime-Block
- Options-Block (optional)
- Relay Tag Request-Block (optional)
- Padding-Block (optional)
Die minimale Payload-Größe beträgt 8 Bytes. Da der DateTime-Block nur 7 Bytes groß ist, muss mindestens ein weiterer Block vorhanden sein.
Notes
Der eindeutige X-Wert im anfänglichen ChaCha20-Block stellt sicher, dass der Chiffretext für jede Sitzung unterschiedlich ist.
Um Widerstand gegen Sondierungsangriffe zu bieten, sollte Bob keine Retry-Nachricht als Antwort auf eine Session Request-Nachricht senden, es sei denn, die Felder für Nachrichtentyp, Protokollversion und Netzwerk-ID in der Session Request-Nachricht sind gültig.
Bob muss Verbindungen ablehnen, bei denen der Zeitstempel-Wert zu weit von der aktuellen Zeit abweicht. Nennen wir die maximale Zeitdifferenz “D”. Bob muss einen lokalen Cache von zuvor verwendeten Handshake-Werten führen und Duplikate ablehnen, um Replay-Angriffe zu verhindern. Werte im Cache müssen eine Lebensdauer von mindestens 2*D haben. Die Cache-Werte sind implementierungsabhängig, jedoch kann der 32-Byte X-Wert (oder dessen verschlüsseltes Äquivalent) verwendet werden. Ablehnung durch Senden einer Retry-Nachricht mit einem Null-Token und einem Terminierungsblock.
Diffie-Hellman ephemere Schlüssel dürfen niemals wiederverwendet werden, um kryptographische Angriffe zu verhindern, und eine Wiederverwendung wird als Replay-Angriff abgelehnt.
Die “KE”- und “auth”-Optionen müssen kompatibel sein, d.h. das geteilte Geheimnis K muss die entsprechende Größe haben. Wenn weitere “auth”-Optionen hinzugefügt werden, könnte dies implizit die Bedeutung des “KE”-Flags ändern, um eine andere KDF oder eine andere Kürzungsgröße zu verwenden.
Bob muss hier validieren, dass Alices ephemeral key ein gültiger Punkt auf der Kurve ist.
Padding sollte auf eine angemessene Menge begrenzt werden. Bob kann Verbindungen mit übermäßigem Padding ablehnen. Bob wird seine Padding-Optionen in Session Created angeben. Min/Max-Richtlinien noch festzulegen. Zufällige Größe von 0 bis 31 Bytes minimum? (Verteilung noch zu bestimmen, siehe Anhang A.) TODO ES SEI DENN minimale Paketgröße wird für PMTU durchgesetzt.
Bei den meisten Fehlern, einschließlich AEAD, DH, offensichtlichem Replay oder Schlüsselvalidierungsfehlern, sollte Bob die weitere Nachrichtenverarbeitung stoppen und die Nachricht ohne Antwort verwerfen.
Bob KANN eine Retry-Nachricht senden, die ein Null-Token und einen Termination-Block mit einem Clock-Skew-Grund-Code enthält, wenn der Zeitstempel im DateTime-Block zu stark abweicht.
DoS-Schutz: DH ist eine relativ aufwändige Operation. Wie beim vorherigen NTCP-Protokoll sollten Router alle notwendigen Maßnahmen ergreifen, um CPU- oder Verbindungserschöpfung zu verhindern. Setzen Sie Limits für maximale aktive Verbindungen und maximale laufende Verbindungsaufbauten. Erzwingen Sie Read-Timeouts (sowohl pro Lesevorgang als auch insgesamt für “slowloris”). Begrenzen Sie wiederholte oder gleichzeitige Verbindungen von derselben Quelle. Führen Sie Blacklists für Quellen, die wiederholt fehlschlagen. Antworten Sie nicht auf AEAD-Fehler. Alternativ antworten Sie mit einer Retry-Nachricht vor der DH-Operation und AEAD-Validierung.
“ver”-Feld: Das gesamte Noise-Protokoll, Erweiterungen und SSU2-Protokoll einschließlich Payload-Spezifikationen, das SSU2 anzeigt. Dieses Feld kann verwendet werden, um Unterstützung für zukünftige Änderungen anzuzeigen.
Das Network-ID-Feld wird verwendet, um netzwerkübergreifende Verbindungen schnell zu identifizieren. Wenn dieses Feld nicht mit Bobs Network-ID übereinstimmt, sollte Bob die Verbindung trennen und zukünftige Verbindungen blockieren.
Bob muss die Nachricht verwerfen, wenn die Source Connection ID der Destination Connection ID entspricht.
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)
Verbindungsmigration
Bob sendet an Alice, als Antwort auf eine Session Request Nachricht. Alice antwortet mit einer Session Confirmed Nachricht. Größe: 80 + Payload-Größe. Mindestgröße: 88
Noise-Inhalt: Bobs ephemerer Schlüssel Y Noise-Payload: DateTime, Address und andere Blöcke Maximale Payload-Größe: MTU - 108 (IPv4) oder MTU - 128 (IPv6). Für 1280 MTU: Maximaler Payload ist 1172 (IPv4) oder 1152 (IPv6). Für 1500 MTU: Maximaler Payload ist 1392 (IPv4) oder 1372 (IPv6).
Payload-Sicherheitseigenschaften:
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.
Der Y-Wert wird verschlüsselt, um Payload-Ununterscheidbarkeit und Eindeutigkeit sicherzustellen, welche notwendige DPI-Gegenmaßnahmen sind. Wir verwenden ChaCha20-Verschlüsselung, um dies zu erreichen, anstatt komplexerer und langsamerer Alternativen wie elligator2. Asymmetrische Verschlüsselung zu Alice’s router public key wäre viel zu langsam. ChaCha20-Verschlüsselung verwendet Bob’s intro key, wie sie in der netDb veröffentlicht ist.
ChaCha20-Verschlüsselung dient ausschließlich der DPI-Resistenz. Jede Partei, die Bobs Intro-Schlüssel kennt, welcher in der netDb veröffentlicht ist, und die ersten 32 Bytes der Session Request abgefangen hat, kann den Y-Wert in dieser Nachricht entschlüsseln.
Rohe Inhalte:
+----+----+----+----+----+----+----+----+
| 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)
Unverschlüsselte Daten (Poly1305 Auth-Tag nicht angezeigt):
+----+----+----+----+----+----+----+----+
| 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
- DateTime Block
- Address Block
- Relay Tag Block (optional)
- New Token Block (optional)
- First Packet Number Block (optional)
- Options Block (optional)
- Termination Block (nicht empfohlen, stattdessen in einer Retry-Nachricht senden)
- Padding Block (optional)
Die minimale Payload-Größe beträgt 8 Bytes. Da die DateTime- und Address-Blöcke zusammen mehr als das ergeben, ist die Anforderung bereits mit diesen beiden Blöcken erfüllt.
Notes
Alice muss hier validieren, dass Bobs ephemerer Schlüssel ein gültiger Punkt auf der Kurve ist.
Padding sollte auf eine angemessene Menge begrenzt werden. Alice kann Verbindungen mit übermäßigem Padding ablehnen. Alice wird ihre Padding-Optionen in Session Confirmed angeben. Min/Max-Richtlinien sind noch zu bestimmen. Zufällige Größe von 0 bis 31 Bytes mindestens? (Verteilung ist noch zu bestimmen, siehe Anhang A.) TODO UNLESS minimum packet size is enforced for PMTU.
Bei jedem Fehler, einschließlich AEAD, DH, Zeitstempel, offensichtlicher Wiederholung oder Schlüsselvalidierungsfehlern, muss Alice die weitere Nachrichtenverarbeitung stoppen und die Verbindung ohne Antwort schließen.
Alice muss Verbindungen ablehnen, bei denen der Zeitstempel-Wert zu weit von der aktuellen Zeit abweicht. Nennen wir die maximale Zeitdifferenz “D”. Alice muss einen lokalen Cache von zuvor verwendeten Handshake-Werten führen und Duplikate ablehnen, um Replay-Angriffe zu verhindern. Werte im Cache müssen eine Lebensdauer von mindestens 2*D haben. Die Cache-Werte sind implementierungsabhängig, jedoch kann der 32-Byte Y-Wert (oder sein verschlüsseltes Äquivalent) verwendet werden.
Alice muss die Nachricht verwerfen, wenn die Quell-IP und der Port nicht mit der Ziel-IP und dem Port der Session Request übereinstimmen.
Alice muss die Nachricht verwerfen, wenn die Destination- und Source-Connection-IDs nicht mit den Source- und Destination-Connection-IDs der Session Request übereinstimmen.
Bob sendet einen Relay-Tag-Block, falls von Alice in der Session Request angefordert.
Issues
- Min/Max-Padding-Optionen hier einschließen?
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 sendet an Bob als Antwort auf eine Session Created-Nachricht. Bob antwortet sofort mit einer Data-Nachricht, die einen ACK-Block enthält. Größe: 80 + Nutzdatengröße. Mindestgröße: Etwa 500 (minimale Router-Info-Blockgröße beträgt etwa 420 Bytes)
Noise-Inhalt: Alices statischer Schlüssel Noise-Payload-Teil 1: Keiner Noise-Payload-Teil 2: Alices RouterInfo und andere Blöcke Maximale Payload-Größe: MTU - 108 (IPv4) oder MTU - 128 (IPv6). Für 1280 MTU: Maximale Payload ist 1172 (IPv4) oder 1152 (IPv6). Für 1500 MTU: Maximale Payload ist 1392 (IPv4) oder 1372 (IPv6).
Payload-Sicherheitseigenschaften:
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.
Dies enthält zwei ChaChaPoly-Frames. Der erste ist Alices verschlüsselter statischer öffentlicher Schlüssel. Der zweite ist die Noise-Payload: Alices verschlüsselte RouterInfo, optionale Optionen und optionales Padding. Sie verwenden unterschiedliche Schlüssel, da die MixKey()-Funktion dazwischen aufgerufen wird.
Rohe Inhalte:
+----+----+----+----+----+----+----+----+
| 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
Unverschlüsselte Daten (Poly1305 Auth-Tags nicht angezeigt):
+----+----+----+----+----+----+----+----+
| 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
- RouterInfo Block (muss der erste Block sein)
- Options Block (optional)
- New Token Block (optional)
- Relay Request Block (optional)
- Peer Test Block (optional)
- First Packet Number Block (optional)
- I2NP, First Fragment, oder Follow-on Fragment Blocks (optional, aber wahrscheinlich kein Platz)
- Padding Block (optional)
Die minimale Payload-Größe beträgt 8 Bytes. Da der RouterInfo-Block deutlich mehr als das umfasst, wird die Anforderung bereits allein durch diesen Block erfüllt.
Notes
Bob muss die übliche Router Info Validierung durchführen. Sicherstellen, dass der Signaturtyp unterstützt wird, die Signatur verifizieren, prüfen, dass der Zeitstempel innerhalb der Grenzen liegt, und alle anderen notwendigen Überprüfungen durchführen. Siehe unten für Hinweise zum Umgang mit fragmentierten Router Infos.
Bob muss verifizieren, dass Alices statischer Schlüssel, der im ersten Frame empfangen wurde, mit dem statischen Schlüssel in der Router Info übereinstimmt. Bob muss zuerst die Router Info nach einer NTCP- oder SSU2-Router-Adresse mit einer passenden Version-(v)-Option durchsuchen. Siehe die Abschnitte Published Router Info und Unpublished Router Info unten. Siehe unten für Hinweise zum Umgang mit fragmentierten Router Infos.
Wenn Bob eine ältere Version von Alices RouterInfo in seiner netdb hat, überprüfen Sie, dass der statische Schlüssel in der Router-Info in beiden gleich ist, falls vorhanden, und wenn die ältere Version weniger als XXX alt ist (siehe Schlüsselrotationszeit unten)
Bob muss hier validieren, dass Alices statischer Schlüssel ein gültiger Punkt auf der Kurve ist.
Optionen sollten enthalten sein, um Padding-Parameter zu spezifizieren.
Bei jedem Fehler, einschließlich AEAD-, RI-, DH-, Zeitstempel- oder Schlüsselvalidierungsfehlern, muss Bob die weitere Nachrichtenverarbeitung stoppen und die Verbindung ohne Antwort schließen.
Message 3 Teil 2 Frame-Inhalt: Das Format dieses Frames ist das gleiche wie das Format von Datenphasen-Frames, außer dass die Länge des Frames von Alice in der Session Request gesendet wird. Siehe unten für das Datenphasen-Frame-Format. Der Frame muss 1 bis 4 Blöcke in der folgenden Reihenfolge enthalten:
- Alice’s Router Info Block (erforderlich)
- Options Block (optional)
- I2NP Blöcke (optional)
- Padding Block (optional) Dieser Frame darf niemals andere Block-Typen enthalten. TODO: was ist mit Relay und Peer Test?
Message 3 Teil 2 Padding-Block wird empfohlen.
Es steht möglicherweise kein Platz oder nur ein geringer Platz für I2NP-Blöcke zur Verfügung, abhängig von der MTU und der Router Info-Größe. Fügen Sie KEINE I2NP-Blöcke hinzu, wenn die Router Info fragmentiert ist. Die einfachste Implementierung kann darin bestehen, niemals I2NP-Blöcke in der Session Confirmed-Nachricht zu inkludieren und alle I2NP-Blöcke in nachfolgenden Data-Nachrichten zu senden. Siehe Router Info-Block-Sektion unten für die maximale Blockgröße.
Session Confirmed Fragmentation
Die Session Confirmed-Nachricht muss die vollständige signierte Router Info von Alice enthalten, damit Bob mehrere erforderliche Prüfungen durchführen kann:
- Der statische Schlüssel “s” in der RI stimmt mit dem statischen Schlüssel im Handshake überein
- Der Einführungsschlüssel “i” in der RI muss extrahiert und gültig sein, um in der Datenphase verwendet zu werden
- Die RI-Signatur ist gültig
Leider kann die Router Info, selbst wenn sie im RI-Block gzip-komprimiert ist, die MTU überschreiten. Daher kann die Session Confirmed über zwei oder mehr Pakete fragmentiert werden. Dies ist der EINZIGE Fall im SSU2-Protokoll, bei dem eine AEAD-geschützte Nutzlast über zwei oder mehr Pakete fragmentiert wird.
Die Header für jedes Paket werden wie folgt konstruiert:
- ALLE Header sind kurze Header mit derselben Paketnummer 0
- ALLE Header enthalten ein “frag”-Feld mit der Fragmentnummer und der Gesamtzahl der Fragmente
- Der unverschlüsselte Header von Fragment 0 sind die zugehörigen Daten (AD) für die “Jumbo”-Nachricht
- Jeder Header wird mit den letzten 24 Bytes der Daten in DIESEM Paket verschlüsselt
Konstruiere die Paketfolge wie folgt:
- Erstelle einen einzelnen RI-Block (Fragment 0 von 1 im RI-Block-Frag-Feld). Wir verwenden keine RI-Block-Fragmentierung, das war für eine alternative Methode zur Lösung desselben Problems.
- Erstelle eine “Jumbo”-Payload mit dem RI-Block und allen anderen einzuschließenden Blöcken
- Berechne die Gesamtdatengröße (ohne Header), welche die Payload-Größe + 64 Bytes für den statischen Schlüssel und zwei MACs ist
- Berechne den verfügbaren Platz in jedem Paket, welcher die MTU minus dem IP-Header (20 oder 40), minus dem UDP-Header (8), minus dem SSU2-Short-Header (16) ist. Gesamter Overhead pro Paket beträgt 44 (IPv4) oder 64 (IPv6).
- Berechne die Anzahl der Pakete.
- Berechne die Größe der Daten im letzten Paket. Sie muss größer als oder gleich 24 Bytes sein, damit die Header-Verschlüsselung funktioniert. Wenn sie zu klein ist, entweder einen Padding-Block hinzufügen, ODER die Größe des Padding-Blocks vergrößern falls bereits vorhanden, ODER die Größe eines der anderen Pakete reduzieren, damit das letzte Paket groß genug wird.
- Erstelle den unverschlüsselten Header für das erste Paket, mit der Gesamtzahl der Fragmente im Frag-Feld, und verschlüssle die “Jumbo”- Payload mit Noise, unter Verwendung des Headers als AD, wie üblich.
- Teile das verschlüsselte Jumbo-Paket in Fragmente auf
- Füge einen unverschlüsselten Header für jedes Fragment 1-n hinzu
- Verschlüssle den Header für jedes Fragment 0-n. Jeder Header verwendet die SELBEN k_header_1 und k_header_2 wie oben in der Session Confirmed KDF definiert.
- Übertrage alle Fragmente
Reassembly-Prozess:
Wenn Bob eine Session Confirmed-Nachricht erhält, entschlüsselt er den Header, prüft das frag-Feld und stellt fest, dass die Session Confirmed fragmentiert ist. Er entschlüsselt die Nachricht nicht (und kann es auch nicht), bis alle Fragmente empfangen und wieder zusammengesetzt wurden.
- Den Header für Fragment 0 beibehalten, da er als Noise AD verwendet wird
- Die Header für andere Fragmente vor der Reassemblierung verwerfen
- Die “Jumbo”-Payload mit dem Header für Fragment 0 als AD reassemblieren und mit Noise entschlüsseln
- Den RI-Block wie gewohnt validieren
- Zur Datenphase übergehen und ACK 0 wie gewohnt senden
Es gibt keinen Mechanismus für Bob, einzelne Fragmente zu bestätigen. Wenn Bob alle Fragmente empfängt, sie wieder zusammenfügt, entschlüsselt und den Inhalt validiert, führt Bob wie gewöhnlich einen split() durch, wechselt in die Datenphase und sendet eine ACK für Paketnummer 0.
Wenn Alice keine ACK für Paketnummer 0 erhält, muss sie alle session confirmed Pakete unverändert erneut übertragen.
Beispiele:
Für 1500 MTU über IPv6 beträgt die maximale Nutzlast 1372, der RI-Block-Overhead ist 5, die maximale (gzip-komprimierte) RI-Datengröße ist 1367 (unter der Annahme, dass keine anderen Blöcke vorhanden sind). Bei zwei Paketen beträgt der Overhead des zweiten Pakets 64, sodass es weitere 1436 Bytes an Nutzlast aufnehmen kann. Zwei Pakete reichen also für eine komprimierte RI von bis zu 2803 Bytes aus.
Die größte komprimierte RI, die im aktuellen Netzwerk beobachtet wurde, ist etwa 1400 Bytes groß; daher sollten in der Praxis zwei Fragmente ausreichen, selbst bei einer minimalen MTU von 1280. Das Protokoll erlaubt maximal 15 Fragmente.
Sicherheitsanalyse:
Die Integrität und Sicherheit einer fragmentierten Session Confirmed ist dieselbe wie die einer nicht-fragmentierten. Jede Änderung eines Fragments wird dazu führen, dass das Noise AEAD nach der Wiederzusammensetzung fehlschlägt. Die Header der Fragmente nach Fragment 0 werden nur zur Identifikation des Fragments verwendet. Selbst wenn ein Angreifer im Übertragungsweg den k_header_2-Schlüssel besäße, der zur Verschlüsselung des Headers verwendet wird (unwahrscheinlich, abgeleitet aus dem Handshake), würde dies dem Angreifer nicht erlauben, ein gültiges Fragment zu ersetzen.
KDF for data phase
Die Datenphase verwendet den Header für zugehörige Daten.
Die KDF generiert zwei Chiffrierschlüssel k_ab und k_ba aus dem chaining key ck, unter Verwendung von HMAC-SHA256(key, data) wie in RFC 2104 definiert. Dies ist die split()-Funktion, genau wie in der Noise-Spezifikation definiert.
// 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)
Noise-Payload: Alle Block-Typen sind erlaubt. Maximale Payload-Größe: MTU - 60 (IPv4) oder MTU - 80 (IPv6). Für 1500 MTU: Maximales Payload ist 1440 (IPv4) oder 1420 (IPv6).
Ab dem 2. Teil von Session Confirmed befinden sich alle Nachrichten innerhalb einer authentifizierten und verschlüsselten ChaChaPoly-Nutzlast. Alle Auffüllungen befinden sich innerhalb der Nachricht. Innerhalb der Nutzlast befindet sich ein Standardformat mit null oder mehr “Blöcken”. Jeder Block hat einen Ein-Byte-Typ und eine Zwei-Byte-Länge. Typen umfassen Datum/Zeit, I2NP-Nachricht, Optionen, Beendigung und Auffüllung.
Hinweis: Bob kann, ist aber nicht verpflichtet, seine RouterInfo als erste Nachricht an Alice in der Datenphase zu senden.
Sicherheitseigenschaften der Nutzdaten:
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
- Der Router muss eine Nachricht mit einem AEAD-Fehler verwerfen.
+----+----+----+----+----+----+----+----+
| 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) +
| |
+----+----+----+----+----+----+----+----+
Unverschlüsselte Daten (Poly1305 Auth-Tag nicht gezeigt):
+----+----+----+----+----+----+----+----+
| 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
Die minimale Payload-Größe beträgt 8 Bytes. Diese Anforderung wird von jedem ACK-, I2NP-, First Fragment- oder Follow-on Fragment-Block erfüllt. Falls die Anforderung nicht erfüllt wird, muss ein Padding-Block eingefügt werden.
Jede Paketnummer darf nur einmal verwendet werden. Beim erneuten Übertragen von I2NP-Nachrichten oder -Fragmenten muss eine neue Paketnummer verwendet werden.
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 sendet an Alice, und Alice sendet an Charlie, nur für Peer Test Phasen 5-7. Peer Test Phasen 1-4 müssen innerhalb der Session mit einem Peer Test Block in einer Data-Nachricht gesendet werden. Siehe die Abschnitte Peer Test Block und Peer Test Process unten für weitere Informationen.
Größe: 48 + Payload-Größe.
Noise payload: Siehe unten.
Roher Inhalt:
+----+----+----+----+----+----+----+----+
| 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) +
| |
+----+----+----+----+----+----+----+----+
Unverschlüsselte Daten (Poly1305-Authentifizierungs-Tag nicht angezeigt):
+----+----+----+----+----+----+----+----+
| 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
Langer Header
- DateTime Block
- Address Block (erforderlich für Nachrichten 6 und 7, siehe Hinweis unten)
- Peer Test Block
- Padding Block (optional)
Die minimale Payload-Größe beträgt 8 Bytes. Da der Peer Test Block insgesamt mehr als das umfasst, wird die Anforderung nur mit diesem Block erfüllt.
In Nachrichten 5 und 7 kann der Peer Test Block identisch mit dem Block aus den In-Session-Nachrichten 3 und 4 sein, der die von Charlie signierte Vereinbarung enthält, oder er kann neu generiert werden. Die Signatur ist optional.
In Nachricht 6 kann der Peer Test Block identisch mit dem Block aus den In-Session-Nachrichten 1 und 2 sein, der die von Alice signierte Anfrage enthält, oder er kann neu generiert werden. Signatur ist optional.
Verbindungs-IDs: Die beiden Verbindungs-IDs werden aus der Test-Nonce abgeleitet. Für Nachrichten 5 und 7, die von Charlie an Alice gesendet werden, ist die Ziel-Verbindungs-ID zwei Kopien der 4-Byte Big-Endian Test-Nonce, d.h. ((nonce « 32) | nonce). Die Quell-Verbindungs-ID ist das Inverse der Ziel-Verbindungs-ID, d.h. ~((nonce « 32) | nonce). Für Nachricht 6, die von Alice an Charlie gesendet wird, werden die beiden Verbindungs-IDs vertauscht.
Inhalt des Adressblocks:
- In Nachricht 5: Nicht erforderlich.
- In Nachricht 6: Charlies IP und Port wie aus Charlies RI ausgewählt.
- In Nachricht 7: Alices tatsächliche IP und Port, von der Nachricht 6 empfangen wurde.
KDF for Retry
Die Anforderung für die Retry-Nachricht ist, dass Bob nicht verpflichtet ist, die Session Request-Nachricht zu entschlüsseln, um eine Retry-Nachricht als Antwort zu generieren. Außerdem muss diese Nachricht schnell zu generieren sein und nur symmetrische Verschlüsselung verwenden.
// 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 sendet an Alice, als Antwort auf eine Session Request oder Token Request Nachricht. Alice antwortet mit einer neuen Session Request. Größe: 48 + Payload-Größe.
Dient auch als Termination-Nachricht (d.h. „Nicht wiederholen"), falls ein Termination-Block enthalten ist.
Noise-Payload: Siehe unten.
Rohe Inhalte:
+----+----+----+----+----+----+----+----+
| 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) +
| |
+----+----+----+----+----+----+----+----+
Unverschlüsselte Daten (Poly1305-Authentifizierungstag nicht gezeigt):
+----+----+----+----+----+----+----+----+
| 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
Kurze Kopfzeile
- DateTime-Block
- Adress-Block
- Options-Block (optional)
- Termination-Block (optional, wenn Session abgelehnt wird)
- Padding-Block (optional)
Die minimale Payload-Größe beträgt 8 Bytes. Da die DateTime- und Address-Blöcke zusammen mehr als das ausmachen, ist die Anforderung bereits mit diesen beiden Blöcken erfüllt.
Verbindungs-ID-Nummerierung
Um Widerstand gegen Probing zu bieten, sollte ein router keine Retry-Nachricht als Antwort auf eine Session Request- oder Token Request-Nachricht senden, es sei denn, die Felder für Nachrichtentyp, Protokollversion und Netzwerk-ID in der Request-Nachricht sind gültig.
Um das Ausmaß von Verstärkungsangriffen zu begrenzen, die mit gefälschten Quelladressen durchgeführt werden können, darf die Retry-Nachricht keine großen Mengen an Padding enthalten. Es wird empfohlen, dass die Retry-Nachricht nicht größer ist als das Dreifache der Größe der Nachricht, auf die sie antwortet. Alternativ kann eine einfache Methode verwendet werden, wie das Hinzufügen einer zufälligen Menge an Padding im Bereich von 1-64 Bytes.
KDF for Token Request
Diese Nachricht muss schnell zu generieren sein und darf nur symmetrische Verschlüsselung verwenden.
// 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 sendet an Bob. Bob antwortet mit einer Retry-Nachricht. Größe: 48 + Payload-Größe.
Wenn Alice kein gültiges Token hat, sollte Alice diese Nachricht anstelle einer Session Request senden, um den asymmetrischen Verschlüsselungsaufwand bei der Generierung einer Session Request zu vermeiden.
Noise-Payload: Siehe unten.
Roher Inhalt:
+----+----+----+----+----+----+----+----+
| 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) +
| |
+----+----+----+----+----+----+----+----+
Unverschlüsselte Daten (Poly1305-Authentifizierungs-Tag nicht gezeigt):
+----+----+----+----+----+----+----+----+
| 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
Paket-Nummerierung
- DateTime-Block
- Padding-Block
Die minimale Nutzlastgröße beträgt 8 Bytes.
Header Binding
Um Probing-Resistenz zu gewährleisten, sollte ein Router keine Retry-Nachricht als Antwort auf eine Token Request-Nachricht senden, es sei denn, die Felder für Nachrichtentyp, Protokollversion und Netzwerk-ID in der Token Request-Nachricht sind gültig.
Dies ist KEINE Standard-Noise-Nachricht und ist nicht Teil des Handshakes. Sie ist nicht an die Session Request-Nachricht gebunden, außer durch Verbindungs-IDs.
Bei den meisten Fehlern, einschließlich AEAD oder offensichtlicher Replay-Angriffe, sollte Bob die weitere Nachrichtenverarbeitung stoppen und die Nachricht ohne Antwort verwerfen.
Bob muss Verbindungen ablehnen, bei denen der Zeitstempel-Wert zu weit von der aktuellen Zeit abweicht. Nennen wir die maximale Zeitdifferenz “D”. Bob muss einen lokalen Cache von zuvor verwendeten Handshake-Werten führen und Duplikate ablehnen, um Replay-Angriffe zu verhindern. Werte im Cache müssen eine Lebensdauer von mindestens 2*D haben. Die Cache-Werte sind implementierungsabhängig, jedoch kann der 32-Byte X-Wert (oder sein verschlüsseltes Äquivalent) verwendet werden.
Bob KANN eine Retry-Nachricht senden, die ein Null-Token und einen Termination-Block mit einem Clock-Skew-Grund-Code enthält, wenn der Zeitstempel im DateTime-Block zu stark abweicht.
Minimale Größe: TBD, gleiche Regeln wie für Session Created?
KDF for Hole Punch
Diese Nachricht muss schnell zu generieren sein und darf nur symmetrische Verschlüsselung verwenden.
// 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 sendet an Alice, als Antwort auf eine Relay Intro, die von Bob empfangen wurde. Alice antwortet mit einer neuen Session Request. Größe: 48 + Payload-Größe.
Noise-Payload: Siehe unten.
Roher Inhalt:
+----+----+----+----+----+----+----+----+
| 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) +
| |
+----+----+----+----+----+----+----+----+
Unverschlüsselte Daten (Poly1305-Authentifizierungs-Tag nicht angezeigt):
+----+----+----+----+----+----+----+----+
| 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.
Header-Verschlüsselung
- DateTime-Block
- Address-Block
- Relay Response-Block
- Padding-Block (optional)
Die minimale Payload-Größe beträgt 8 Bytes. Da die DateTime- und Address-Blöcke zusammen mehr als das ausmachen, ist die Anforderung bereits mit diesen beiden Blöcken erfüllt.
Connection IDs: Die beiden Connection IDs werden aus der Relay-Nonce abgeleitet. Die Destination Connection ID besteht aus zwei Kopien der 4-Byte-Big-Endian-Relay-Nonce, d.h. ((nonce « 32) | nonce). Die Source Connection ID ist die Umkehrung der Destination Connection ID, d.h. ~((nonce « 32) | nonce).
Alice sollte das Token im Header ignorieren. Das Token, das in der Session Request verwendet werden soll, befindet sich im Relay Response Block.
Noise Payload
Jede Noise-Nutzlast enthält null oder mehr „Blöcke".
Dies verwendet das gleiche Blockformat wie in den NTCP2- und ECIES-Spezifikationen definiert. Einzelne Blocktypen sind unterschiedlich definiert. Der entsprechende Begriff in QUIC RFC 9000 ist “frames”.
Es gibt Bedenken, dass die Ermutigung von Implementierern, Code zu teilen, zu Parsing-Problemen führen könnte. Implementierer sollten sorgfältig die Vorteile und Risiken des Code-Teilens abwägen und sicherstellen, dass die Reihenfolge- und gültigen Block-Regeln für die beiden Kontexte unterschiedlich sind.
Sicherheitsüberlegungen
Es gibt einen oder mehrere Blöcke in der verschlüsselten Payload. Ein Block ist ein einfaches Tag-Length-Value (TLV) Format. Jeder Block enthält eine ein-Byte-Kennung, eine zwei-Byte-Länge und null oder mehr Datenbytes. Dieses Format ist identisch mit dem in NTCP2 und ECIES, jedoch sind die Blockdefinitionen unterschiedlich.
Für die Erweiterbarkeit müssen Empfänger Blöcke mit unbekannten Kennungen ignorieren und sie als Padding behandeln.
(Poly1305 Authentifizierungs-Tag nicht dargestellt):
+----+----+----+----+----+----+----+----+
|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
Header-Verschlüsselung verwendet die letzten 24 Bytes des Pakets als IV für die beiden ChaCha20-Operationen. Da alle Pakete mit einem 16-Byte-MAC enden, erfordert dies, dass alle Paket-Payloads mindestens 8 Bytes groß sind. Wenn ein Payload diese Anforderung anderweitig nicht erfüllen würde, muss ein Padding-Block eingefügt werden.
Die maximale ChaChaPoly-Payload variiert je nach Nachrichtentyp, MTU und IPv4- oder IPv6-Adresstyp. Die maximale Payload beträgt MTU - 60 für IPv4 und MTU - 80 für IPv6. Die maximalen Payload-Daten betragen MTU - 63 für IPv4 und MTU - 83 für IPv6. Die Obergrenze liegt bei etwa 1440 Bytes für IPv4, 1500 MTU, Data-Nachricht. Die maximale Gesamtblockgröße entspricht der maximalen Payload-Größe. Die maximale Einzelblockgröße entspricht der maximalen Gesamtblockgröße. Der Blocktyp umfasst 1 Byte. Die Blocklänge umfasst 2 Bytes. Die maximale Einzelblock-Datengröße ist die maximale Einzelblockgröße minus 3.
Hinweise:
Implementer müssen sicherstellen, dass beim Lesen eines Blocks fehlerhafte oder bösartige Daten nicht dazu führen, dass Lesevorgänge in den nächsten Block oder über die Payload-Grenze hinaus überlaufen.
Implementierungen sollten unbekannte Blocktypen für Vorwärtskompatibilität ignorieren.
Block-Typen:
| Payload Block Type | Type Number | Block Length |
|---|---|---|
| DateTime | 0 | 7 |
| Options | 1 | 15+ |
| Router Info | 2 | varies |
| I2NP Message | 3 | varies |
| First Fragment | 4 | varies |
| Follow-on Fragment | 5 | varies |
| Termination | 6 | 9 typ. |
| Relay Request | 7 | varies |
| Relay Response | 8 | varies |
| Relay Intro | 9 | varies |
| Peer Test | 10 | varies |
| Next Nonce | 11 | TBD |
| ACK | 12 | varies |
| Address | 13 | 9 or 21 |
| reserved | 14 | – |
| Relay Tag Request | 15 | 3 |
| Relay Tag | 16 | 7 |
| New Token | 17 | 15 |
| Path Challenge | 18 | varies |
| Path Response | 19 | varies |
| First Packet Number | 20 | 7 |
| Congestion | 21 | 4 |
| reserved for experimental features | 224-253 | |
| Padding | 254 | varies |
| reserved for future extension | 255 |
Block Ordering Rules
In der Session Confirmed muss die Router Info der erste Block sein.
In allen anderen Nachrichten ist die Reihenfolge nicht festgelegt, außer für die folgenden Anforderungen: Padding, falls vorhanden, muss der letzte Block sein. Termination, falls vorhanden, muss der letzte Block außer Padding sein. Mehrere Padding-Blöcke sind in einer einzigen Payload nicht erlaubt.
Block Specifications
Header-Verschlüsselung KDF
Für Zeitsynchronisation:
+----+----+----+----+----+----+----+
| 0 | 4 | timestamp |
+----+----+----+----+----+----+----+
blk :: 0
size :: 2 bytes, big endian, value = 4
timestamp :: Unix timestamp, unsigned seconds.
Wraps around in 2106
Hinweise:
- Anders als in SSU 1 gibt es in SSU 2 keinen Zeitstempel im Paket-Header für die Datenphase.
- Implementierungen sollten regelmäßig DateTime-Blöcke in der Datenphase senden.
- Implementierungen müssen auf die nächste Sekunde runden, um Uhrenabweichungen im Netzwerk zu verhindern.
Header-Validierung
Aktualisierte Optionen übergeben. Optionen umfassen: Minimales und maximales Padding.
Der Optionsblock wird eine variable Länge haben.
+----+----+----+----+----+----+----+----+
| 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
Optionen-Probleme:
- Die Optionsverhandlung ist noch zu bestimmen.
RouterInfo
Übertrage Alices RouterInfo an Bob. Wird nur im Session Confirmed Teil 2 Payload verwendet. Nicht in der Datenphase zu verwenden; verwende stattdessen eine I2NP DatabaseStore Message.
Mindestgröße: Etwa 420 Bytes, es sei denn, die Router-Identität und Signatur in den Router-Informationen sind komprimierbar, was unwahrscheinlich ist.
HINWEIS: Der Router Info Block wird niemals fragmentiert. Das frag-Feld ist immer 0/1. Siehe den Abschnitt Session Confirmed Fragmentation oben für weitere Informationen.
+----+----+----+----+----+----+----+----+
| 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
Anmerkungen:
Die Router Info ist optional mit gzip komprimiert, wie durch Flag-Bit 1 angezeigt. Dies unterscheidet sich von NTCP2, wo sie niemals komprimiert wird, und von einer DatabaseStore Message, wo sie immer komprimiert wird. Kompression ist optional, da sie normalerweise wenig Nutzen für kleine Router Infos bringt, wo es wenig komprimierbaren Inhalt gibt, aber sehr vorteilhaft für große Router Infos mit mehreren komprimierbaren Router Addresses ist. Kompression wird empfohlen, wenn sie es einer Router Info ermöglicht, in ein einzelnes Session Confirmed Paket ohne Fragmentierung zu passen.
Maximale Größe des ersten oder einzigen Fragments in der Session Confirmed Nachricht: MTU - 113 für IPv4 oder MTU - 133 für IPv6. Bei angenommener Standard-MTU von 1500 Bytes und ohne andere Blöcke in der Nachricht, 1387 für IPv4 oder 1367 für IPv6. 97% der aktuellen Router-Infos sind kleiner als 1367 ohne gzip-Komprimierung. 99,9% der aktuellen Router-Infos sind kleiner als 1367 wenn gzip-komprimiert. Bei angenommener Mindest-MTU von 1280 Bytes und ohne andere Blöcke in der Nachricht, 1167 für IPv4 oder 1147 für IPv6. 94% der aktuellen Router-Infos sind kleiner als 1147 ohne gzip-Komprimierung. 97% der aktuellen Router-Infos sind kleiner als 1147 wenn gzip-komprimiert.
Das frag-Byte wird nun nicht mehr verwendet, der Router Info-Block wird niemals fragmentiert. Das frag-Byte muss auf Fragment 0, Gesamtfragmente 1 gesetzt werden. Siehe den Abschnitt Session Confirmed Fragmentation oben für weitere Informationen.
Flooding darf nur angefordert werden, wenn veröffentlichte RouterAddresses in der RouterInfo vorhanden sind. Der empfangende Router darf die RouterInfo nur dann flooden, wenn veröffentlichte RouterAddresses darin enthalten sind.
Dieses Protokoll stellt keine Bestätigung bereit, dass die RouterInfo gespeichert oder geflutet wurde. Falls eine Bestätigung gewünscht wird und der Empfänger floodfill ist, sollte der Sender stattdessen eine Standard-I2NP DatabaseStoreMessage mit einem Reply-Token senden.
I2NP Message
Eine vollständige I2NP-Nachricht mit einem modifizierten Header.
Dies verwendet dieselben 9 Bytes für den I2NP-Header wie in NTCP2 (Typ, Nachrichten-ID, kurze Ablaufzeit).
+----+----+----+----+----+----+----+----+
| 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
Hinweise:
Dies ist das gleiche 9-Byte I2NP Header-Format, das in NTCP2 verwendet wird.
Dies ist exakt das gleiche Format wie der First Fragment Block, aber der Block-Typ zeigt an, dass dies eine vollständige Nachricht ist.
Maximale Größe einschließlich 9-Byte I2NP Header ist MTU - 63 für IPv4 und MTU - 83 für IPv6.
ChaCha20/Poly1305
Das erste Fragment (Fragment #0) einer I2NP-Nachricht mit einem modifizierten Header.
Dies verwendet dieselben 9 Bytes für den I2NP-Header wie in NTCP2 (Typ, Nachrichten-ID, kurze Ablaufzeit).
Die Gesamtanzahl der Fragmente ist nicht angegeben.
+----+----+----+----+----+----+----+----+
| 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)
Hinweise:
Dies ist das gleiche 9-Byte I2NP Header-Format, das in NTCP2 verwendet wird.
Dies ist exakt dasselbe Format wie der I2NP Message Block, aber der Block-Typ zeigt an, dass dies das erste Fragment einer Nachricht ist.
Die Länge der Teilnachricht muss größer als null sein.
Wie bei SSU 1 wird empfohlen, das letzte Fragment zuerst zu senden, damit der Empfänger die Gesamtzahl der Fragmente kennt und Empfangspuffer effizient zuweisen kann.
Die maximale Größe einschließlich des 9-Byte I2NP Headers beträgt MTU - 63 für IPv4 und MTU - 83 für IPv6.
Hinweise
Ein zusätzliches Fragment (Fragmentnummer größer als null) einer I2NP-Nachricht.
+----+----+----+----+----+----+----+----+
| 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
Hinweise:
Die Länge der Teilnachricht muss größer als null sein.
Wie in SSU 1 wird empfohlen, das letzte Fragment zuerst zu senden, damit der Empfänger die Gesamtzahl der Fragmente kennt und Empfangspuffer effizient zuweisen kann.
Wie bei SSU 1 ist die maximale Fragment-Nummer 127, aber das praktische Limit liegt bei 63 oder weniger. Implementierungen können das Maximum auf das beschränken, was für eine maximale I2NP-Nachrichtengröße von etwa 64 KB praktikabel ist, was etwa 55 Fragmenten bei einer minimalen MTU von 1280 entspricht. Siehe den Abschnitt “Max I2NP Message Size” unten.
Maximale Größe von Teilnachrichten (ohne frag und message id) ist MTU - 68 für IPv4 und MTU - 88 für IPv6.
AEAD-Fehlerbehandlung
Verbindung trennen. Dies muss der letzte Nicht-Padding-Block in der Nutzlast sein.
+----+----+----+----+----+----+----+----+
| 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.
Hinweise:
- Nicht alle Gründe werden möglicherweise tatsächlich verwendet, implementierungsabhängig. Die meisten Fehler führen im Allgemeinen dazu, dass die Nachricht verworfen wird, nicht zu einer Beendigung. Siehe Hinweise in den Handshake-Nachrichtenbereichen oben. Zusätzlich aufgeführte Gründe dienen der Konsistenz, Protokollierung, Fehlersuche oder falls sich die Richtlinien ändern.
- Es wird empfohlen, dass ein ACK-Block zusammen mit dem Termination-Block eingefügt wird.
- In der Datenphase sollte der Peer für jeden anderen Grund als “termination received” mit einem Termination-Block mit dem Grund “termination received” antworten.
RelayRequest
Gesendet in einer Data-Nachricht innerhalb der Sitzung, von Alice zu Bob. Siehe Abschnitt Relay-Prozess unten.
+----+----+----+----+----+----+----+----+
| 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.
Hinweise:
- Die IP-Adresse ist immer enthalten (im Gegensatz zu SSU 1) und kann sich von der für die Sitzung verwendeten IP unterscheiden.
Signatur:
Alice signiert die Anfrage und fügt sie in diesen Block ein; Bob leitet sie im Relay Intro Block an Charlie weiter. Signatur-Algorithmus: Signiere die folgenden Daten mit Alices router Signing-Schlüssel:
- Prolog: 16 Bytes “RelayRequestData”, nicht null-terminiert (nicht in der Nachricht enthalten)
- bhash: Bobs 32-Byte router hash (nicht in der Nachricht enthalten)
- chash: Charlies 32-Byte router hash (nicht in der Nachricht enthalten)
- Nonce: 4 Byte Nonce
- Relay-Tag: 4 Byte Relay-Tag
- Zeitstempel: 4 Byte Zeitstempel (Sekunden)
- ver: 1 Byte SSU-Version
- asz: 1 Byte Endpunkt-Größe (Port + IP) (6 oder 18)
- AlicePort: 2 Byte Alices Portnummer
- Alice IP: (asz - 2) Byte Alice IP-Adresse
KDF für Initial ChainKey
Gesendet in einer Data-Nachricht innerhalb der Sitzung, von Charlie an Bob oder von Bob an Alice, UND in der Hole Punch-Nachricht von Charlie an Alice. Siehe Abschnitt Relay Process unten.
+----+----+----+----+----+----+----+----+
| 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)
Hinweise:
Das Token muss sofort von Alice in der Session Request verwendet werden.
Signatur:
Wenn Charlie zustimmt (Antwortcode 0) oder ablehnt (Antwortcode 64 oder höher), signiert Charlie die Antwort und fügt sie in diesen Block ein; Bob leitet sie im Relay Response Block an Alice weiter. Signaturalgorithmus: Signiere die folgenden Daten mit Charlies router Signaturschlüssel:
- prologue: 16 Bytes “RelayAgreementOK”, nicht null-terminiert (nicht in der Nachricht enthalten)
- bhash: Bobs 32-Byte Router-Hash (nicht in der Nachricht enthalten)
- nonce: 4 Byte Nonce
- timestamp: 4 Byte Zeitstempel (Sekunden)
- ver: 1 Byte SSU-Version
- csz: 1 Byte Endpunkt (Port + IP) Größe (0 oder 6 oder 18)
- CharliePort: 2 Byte Charlies Portnummer (nicht vorhanden wenn csz 0 ist)
- Charlie IP: (csz - 2) Byte Charlie IP-Adresse (nicht vorhanden wenn csz 0 ist)
Wenn Bob ablehnt (Antwortcode 1-63), signiert Bob die Antwort und fügt sie in diesen Block ein. Signaturalgorithmus: Signiere die folgenden Daten mit Bobs router Signaturschlüssel:
- prologue: 16 Bytes “RelayAgreementOK”, nicht null-terminiert (nicht in der Nachricht enthalten)
- bhash: Bobs 32-Byte router hash (nicht in der Nachricht enthalten)
- nonce: 4 Byte nonce
- timestamp: 4 Byte Zeitstempel (Sekunden)
- ver: 1 Byte SSU-Version
- csz: 1 Byte = 0
KDF für Session Request
Gesendet in einer Data-Nachricht in der Sitzung, von Bob zu Charlie. Siehe Abschnitt Relay Process unten.
Muss von einem RouterInfo-Block oder I2NP DatabaseStore-Nachrichtenblock (oder Fragment) vorangestellt werden, der Alice’s Router Info enthält, entweder in derselben Payload (falls Platz vorhanden ist) oder in einer vorherigen Nachricht.
+----+----+----+----+----+----+----+----+
| 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.
Hinweise:
Für IPv4 ist Alices IP-Adresse immer 4 Bytes lang, da Alice versucht, sich über IPv4 mit Charlie zu verbinden. IPv6 wird unterstützt, und Alices IP-Adresse kann 16 Bytes lang sein.
Für IPv4 muss diese Nachricht über eine etablierte IPv4-Verbindung gesendet werden, da dies der einzige Weg ist, wie Bob Charlies IPv4-Adresse kennt, um sie in der RelayResponse_ an Alice zurückzusenden. IPv6 wird unterstützt, und diese Nachricht kann über eine etablierte IPv6-Verbindung gesendet werden.
Jede SSU-Adresse, die mit Introducern veröffentlicht wird, muss “4” oder “6” in der “caps”-Option enthalten.
Signatur:
Alice signiert die Anfrage und Bob leitet sie in diesem Block an Charlie weiter. Verifikationsalgorithmus: Überprüfe die folgenden Daten mit dem Signierschlüssel von Alice’s Router:
- prologue: 16 Bytes “RelayRequestData”, nicht null-terminiert (nicht in der Nachricht enthalten)
- bhash: Bobs 32-Byte router hash (nicht in der Nachricht enthalten)
- chash: Charlies 32-Byte router hash (nicht in der Nachricht enthalten)
- nonce: 4 Byte nonce
- relay tag: 4 Byte relay tag
- timestamp: 4 Byte Zeitstempel (Sekunden)
- ver: 1 Byte SSU Version
- asz: 1 Byte Endpunkt (Port + IP) Größe (6 oder 18)
- AlicePort: 2 Byte Alices Portnummer
- Alice IP: (asz - 2) Byte Alice IP-Adresse
PeerTest
Wird entweder in einer Data-Nachricht während einer Sitzung oder in einer Peer Test-Nachricht außerhalb einer Sitzung gesendet. Siehe Abschnitt Peer Test Process weiter unten.
Für Nachricht 2 muss ein RouterInfo-Block oder I2NP DatabaseStore-Nachrichtenblock (oder -Fragment) vorangestellt werden, der Alice’s Router Info enthält, entweder in derselben Payload (falls Platz vorhanden ist) oder in einer vorherigen Nachricht.
Für Nachricht 4 muss, wenn das Relay akzeptiert wird (Grund-Code 0), ein RouterInfo-Block oder I2NP DatabaseStore-Nachrichtenblock (oder -fragment) mit Charlies Router Info vorangestellt werden, entweder in derselben Nutzlast (falls Platz vorhanden ist) oder in einer vorherigen Nachricht.
+----+----+----+----+----+----+----+----+
| 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.
Hinweise:
Im Gegensatz zu SSU 1 muss Nachricht 1 Alices IP-Adresse und Port enthalten.
Testen von IPv6-Adressen wird unterstützt, und Alice-Bob- sowie Alice-Charlie-Kommunikation kann über IPv6 erfolgen, wenn Bob und Charlie ihre Unterstützung durch eine ‘B’-Capability in ihrer veröffentlichten IPv6-Adresse anzeigen. Siehe Proposal 126 für Details.
Alice sendet die Anfrage an Bob über eine bestehende Sitzung über das Transport-Protokoll (IPv4 oder IPv6), das sie testen möchte. Wenn Bob eine Anfrage von Alice über IPv4 erhält, muss Bob einen Charlie auswählen, der eine IPv4-Adresse bewirbt. Wenn Bob eine Anfrage von Alice über IPv6 erhält, muss Bob einen Charlie auswählen, der eine IPv6-Adresse bewirbt. Die tatsächliche Bob-Charlie-Kommunikation kann über IPv4 oder IPv6 erfolgen (d.h. unabhängig von Alices Adresstyp).
Die Nachrichten 1-4 müssen in einer Data-Nachricht in einer bestehenden Sitzung enthalten sein.
Bob muss Alices RI an Charlie senden, bevor er Nachricht 2 sendet.
Bob muss Charlies RI vor dem Senden von Nachricht 4 an Alice senden, falls akzeptiert (Grund-Code 0).
Nachrichten 5-7 müssen in einer Peer Test-Nachricht außerhalb der Sitzung enthalten sein.
Nachrichten 5 und 7 können die gleichen signierten Daten enthalten, die in Nachrichten 3 und 4 gesendet wurden, oder sie können mit einem neuen Zeitstempel neu generiert werden. Signatur ist optional.
Nachricht 6 kann dieselben signierten Daten enthalten, die in den Nachrichten 1 und 2 gesendet wurden, oder sie kann mit einem neuen Zeitstempel neu generiert werden. Die Signatur ist optional.
Signaturen:
Alice signiert die Anfrage und fügt sie in Nachricht 1 ein; Bob leitet sie in Nachricht 2 an Charlie weiter. Charlie signiert die Antwort und fügt sie in Nachricht 3 ein; Bob leitet sie in Nachricht 4 an Alice weiter. Signaturalgorithmus: Signiere oder verifiziere die folgenden Daten mit Alices oder Charlies Signaturschlüssel:
- prologue: 16 Bytes “PeerTestValidate”, nicht null-terminiert (nicht in der Nachricht enthalten)
- bhash: Bobs 32-Byte Router-Hash (nicht in der Nachricht enthalten)
- ahash: Alices 32-Byte Router-Hash (Nur in der Signatur für Nachrichten 3 und 4 verwendet; nicht in Nachricht 3 oder 4 enthalten)
- ver: 1 Byte SSU-Version
- nonce: 4 Byte Test-Nonce
- timestamp: 4 Byte Zeitstempel (Sekunden)
- asz: 1 Byte Endpunkt-Größe (Port + IP) (6 oder 18)
- AlicePort: 2 Byte Alices Port-Nummer
- Alice IP: (asz - 2) Byte Alice IP-Adresse
Nutzlast
TODO nur wenn wir Schlüssel rotieren
+----+----+----+----+----+----+----+----+
| 11 | size | TBD |
+----+----+----+ +
| |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
blk :: 11
size :: 2 bytes, big endian, size of data to follow
Notizen
4 Byte Ack Through, gefolgt von einer Ack-Anzahl und null oder mehr Nack/Ack-Bereichen.
Dieses Design ist von QUIC adaptiert und vereinfacht. Die Designziele sind wie folgt:
- Wir möchten ein “bitfield” effizient kodieren, welches eine Sequenz von Bits ist, die bestätigte Pakete repräsentiert.
- Das bitfield besteht hauptsächlich aus 1en. Sowohl die 1en als auch die 0en kommen normalerweise in aufeinanderfolgenden “Gruppen” vor.
- Die verfügbare Menge an Platz im Paket für Bestätigungen variiert.
- Das wichtigste Bit ist das mit der höchsten Nummer. Niedriger nummerierte sind weniger wichtig. Unterhalb einer bestimmten Entfernung vom höchsten Bit werden die ältesten Bits “vergessen” und nie wieder gesendet.
Die unten spezifizierte Kodierung erreicht diese Designziele, indem sie die Nummer des höchsten Bits sendet, das auf 1 gesetzt ist, zusammen mit zusätzlichen aufeinanderfolgenden Bits niedriger als dieses, die ebenfalls auf 1 gesetzt sind. Danach, wenn Platz vorhanden ist, ein oder mehrere “Bereiche”, die die Anzahl der aufeinanderfolgenden 0-Bits und aufeinanderfolgenden 1-Bits niedriger als diese spezifizieren. Siehe QUIC RFC 9000 Abschnitt 13.2.3 für weiteren Hintergrund.
+----+----+----+----+----+----+----+----+
| 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
Beispiele:
Wir möchten nur Paket 10 bestätigen (ACK):
- Ack Through: 10
- acnt: 0
- keine Bereiche sind enthalten
Wir möchten nur die Pakete 8-10 bestätigen (ACK):
- Ack Through: 10
- acnt: 2
- keine Bereiche sind enthalten
Wir möchten 10 9 8 6 5 2 1 0 ACK-en und 7 4 3 NACK-en. Die Kodierung des ACK-Blocks ist:
- 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)
Hinweise:
- Bereiche sind möglicherweise nicht vorhanden. Die maximale Anzahl von Bereichen ist nicht spezifiziert, es können so viele sein, wie in das Paket passen.
- Range nack kann null sein, wenn mehr als 255 aufeinanderfolgende Pakete bestätigt werden.
- Range ack kann null sein, wenn mehr als 255 aufeinanderfolgende Pakete negativ bestätigt werden.
- Range nack und ack dürfen nicht beide null sein.
- Nach dem letzten Bereich werden Pakete weder bestätigt noch negativ bestätigt. Die Länge des ack-Blocks und wie alte acks/nacks behandelt werden, liegt beim Sender des ack-Blocks. Siehe ack-Abschnitte unten für Diskussion.
- Das ack through sollte die höchste empfangene Paketnummer sein, und alle höheren Pakete wurden nicht empfangen. In begrenzten Situationen könnte es jedoch niedriger sein, wie etwa beim Bestätigen eines einzelnen Pakets, das “eine Lücke füllt”, oder bei einer vereinfachten Implementierung, die nicht den Zustand aller empfangenen Pakete aufrechterhält. Oberhalb des höchsten empfangenen Pakets werden Pakete weder bestätigt noch negativ bestätigt, aber nach mehreren ack-Blöcken kann es angemessen sein, in den Fast-Retransmit-Modus zu wechseln.
- Dieses Format ist eine vereinfachte Version des in QUIC verwendeten. Es ist darauf ausgelegt, eine große Anzahl von ACKs effizient zu kodieren, zusammen mit Bursts von NACKs.
- ACK-Blöcke werden verwendet, um Datenphase-Pakete zu bestätigen. Sie sollen nur für In-Session-Datenphase-Pakete eingefügt werden.
Address
2 Byte Port und 4 oder 16 Byte IP-Adresse. Alices Adresse, von Bob an Alice gesendet, oder Bobs Adresse, von Alice an Bob gesendet.
+----+----+----+----+----+----+----+----+
| 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
Dies kann von Alice in einer Session Request, Session Confirmed oder Data Nachricht gesendet werden. Nicht unterstützt in der Session Created Nachricht, da Bob noch nicht über Alices RI verfügt und nicht weiß, ob Alice Relay unterstützt. Außerdem, wenn Bob eine eingehende Verbindung erhält, benötigt er wahrscheinlich keine Introducers (außer vielleicht für den anderen Typ ipv4/ipv6).
Wenn in der Session Request gesendet, kann Bob mit einem Relay Tag in der Session Created-Nachricht antworten, oder er kann warten, bis er Alices RouterInfo in der Session Confirmed erhält, um Alices Identität zu validieren, bevor er in einer Data-Nachricht antwortet. Wenn Bob nicht für Alice weiterleiten möchte, sendet er keinen Relay Tag-Block.
+----+----+----+
| 15 | 0 |
+----+----+----+
blk :: 15
size :: 2 bytes, big endian, value = 0
Nutzlast
Dies kann von Bob in einer Session Confirmed- oder Data-Nachricht gesendet werden, als Antwort auf eine Relay Tag Request von Alice.
Wenn die Relay Tag Request in der Session Request gesendet wird, kann Bob mit einem Relay Tag in der Session Created Nachricht antworten, oder er kann warten, bis er Alices RouterInfo in der Session Confirmed erhält, um Alices Identität zu validieren, bevor er in einer Data-Nachricht antwortet. Wenn Bob nicht für Alice weiterleiten möchte, sendet er keinen Relay Tag Block.
+----+----+----+----+----+----+----+
| 16 | 4 | relay tag |
+----+----+----+----+----+----+----+
blk :: 16
size :: 2 bytes, big endian, value = 4
relay tag :: 4 bytes, big endian, nonzero
Hinweise
Für eine nachfolgende Verbindung. Normalerweise in den Session Created und Session Confirmed Nachrichten enthalten. Kann auch erneut in der Data-Nachricht einer langlebigen Sitzung gesendet werden, wenn der vorherige Token abläuft.
+----+----+----+----+----+----+----+----+
| 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
Probleme
Ein Ping mit beliebigen Daten, die in einer Path Response zurückgegeben werden sollen, verwendet als Keep-Alive oder zur Validierung einer IP/Port-Änderung.
+----+----+----+----+----+----+----+----+
| 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
Hinweise:
Eine Mindestdatengröße von 8 Bytes mit zufälligen Daten wird empfohlen, ist aber nicht erforderlich.
Path Response
Ein Pong mit den im Path Challenge empfangenen Daten, als Antwort auf die Path Challenge, verwendet als Keep-Alive oder zur Validierung einer IP/Port-Änderung.
+----+----+----+----+----+----+----+----+
| 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
Optional in beiden Richtungen im Handshake enthalten, um die erste Paketnummer anzugeben, die gesendet wird. Dies bietet mehr Sicherheit für die Header-Verschlüsselung, ähnlich wie bei TCP.
Nicht vollständig spezifiziert, derzeit nicht unterstützt.
+----+----+----+----+----+----+----+
| 20 | size | First pkt number |
+----+----+----+----+----+----+----+
blk :: 20
size :: 4
pkt num :: The first packet number to be sent in the data phase
Congestion
Dieser Block ist darauf ausgelegt, eine erweiterbare Methode zum Austausch von Congestion Control-Informationen zu sein. Congestion Control kann komplex sein und könnte sich weiterentwickeln, wenn wir mehr Erfahrung mit dem Protokoll in Live-Tests sammeln oder nach dem vollständigen Rollout.
Dies hält alle Überlastungsinformationen aus den stark genutzten I2NP-, First Fragment-, Followon Fragment- und ACK-Blöcken heraus, wo kein Platz für Flags vorgesehen ist. Obwohl es drei Bytes ungenutzte Flags im Data-Paket-Header gibt, bietet das auch nur begrenzten Raum für Erweiterbarkeit und schwächeren Verschlüsselungsschutz.
Obwohl es etwas verschwenderisch ist, einen 4-Byte-Block für zwei Bits an Informationen zu verwenden, können wir durch die Platzierung in einem separaten Block diesen leicht mit zusätzlichen Daten wie aktuellen Fenstergrößen, gemessener RTT oder anderen Flags erweitern. Die Erfahrung hat gezeigt, dass Flag-Bits allein oft unzureichend und umständlich für die Implementierung fortgeschrittener Congestion-Control-Schemata sind. Der Versuch, Unterstützung für jede mögliche Congestion-Control-Funktion beispielsweise im ACK-Block hinzuzufügen, würde Speicherplatz verschwenden und die Komplexität beim Parsen dieses Blocks erhöhen.
Implementierungen sollten nicht davon ausgehen, dass der andere Router ein bestimmtes Flag-Bit oder eine hier enthaltene Funktion unterstützt, es sei denn, die Implementierung wird durch eine zukünftige Version dieser Spezifikation vorgeschrieben.
Dieser Block sollte wahrscheinlich der letzte Nicht-Padding-Block in der Payload sein.
+----+----+----+----+
| 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
Nutzlast
Dies dient zur Polsterung innerhalb von AEAD-Payloads. Polsterung für alle Nachrichten befindet sich innerhalb von AEAD-Payloads.
Das Padding sollte ungefähr den ausgehandelten Parametern entsprechen. Bob hat seine angeforderten tx/rx min/max Parameter in Session Created gesendet. Alice hat ihre angeforderten tx/rx min/max Parameter in Session Confirmed gesendet. Aktualisierte Optionen können während der Datenphase gesendet werden. Siehe Informationen zum Optionsblock oben.
Falls vorhanden, muss dies der letzte Block in der Payload sein.
+----+----+----+----+----+----+----+----+
|254 | size | padding |
+----+----+----+ +
| |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
blk :: 254
size :: 2 bytes, big endian, size of padding to follow
padding :: random data
Hinweise:
Größe = 0 ist erlaubt.
Padding-Strategien sind noch zu definieren.
Minimum-Padding ist noch zu definieren.
Reine Padding-Payloads sind erlaubt.
Padding-Standards sind noch zu definieren.
Siehe options block für die Aushandlung von Padding-Parametern
Siehe options block für min/max Padding-Parameter
Die MTU darf nicht überschritten werden. Falls mehr Padding erforderlich ist, mehrere Nachrichten senden.
Router-Antwort bei Verletzung der ausgehandelten Padding-Vereinbarung ist implementierungsabhängig.
Die Padding-Länge soll entweder auf einer Pro-Nachricht-Basis entschieden werden und Schätzungen der Längenverteilung, oder zufällige Verzögerungen sollten hinzugefügt werden. Diese Gegenmaßnahmen sind zu inkludieren, um DPI zu widerstehen, da Nachrichtengrößen andernfalls verraten würden, dass I2P-Traffic vom Transportprotokoll übertragen wird. Das genaue Padding-Schema ist ein Bereich zukünftiger Arbeit, Anhang A von NTCP2 bietet weitere Informationen zu diesem Thema.
Replay Prevention
SSU2 ist darauf ausgelegt, die Auswirkungen von Nachrichten zu minimieren, die von einem Angreifer wiedergegeben werden.
Token Request, Retry, Session Request, Session Created, Hole Punch und out-of-session Peer Test Nachrichten müssen DateTime-Blöcke enthalten.
Sowohl Alice als auch Bob validieren, dass die Zeit für diese Nachrichten innerhalb einer gültigen Abweichung liegt (empfohlen +/- 2 Minuten). Für “probing resistance” sollte Bob nicht auf Token Request oder Session Request Nachrichten antworten, wenn die Abweichung ungültig ist, da diese Nachrichten ein Replay- oder Probing-Angriff sein könnten.
Bob kann sich dafür entscheiden, doppelte Token Request- und Retry-Nachrichten abzulehnen, auch wenn die Abweichung gültig ist, über einen Bloom-Filter oder einen anderen Mechanismus. Die Größe und CPU-Kosten für die Beantwortung dieser Nachrichten sind jedoch gering. Im schlimmsten Fall kann eine wiedergespielte Token Request-Nachricht einen zuvor gesendeten Token ungültig machen.
Das Token-System minimiert die Auswirkungen von wiederholten Session Request-Nachrichten erheblich. Da Tokens nur einmal verwendet werden können, wird eine wiederholte Session Request-Nachricht niemals ein gültiges Token haben. Bob kann sich dafür entscheiden, doppelte Session Request-Nachrichten abzulehnen, auch wenn die Abweichung gültig ist, über einen Bloom-Filter oder einen anderen Mechanismus. Die Größe und CPU-Kosten für die Antwort mit einer Retry-Nachricht sind jedoch gering. Im schlimmsten Fall kann das Senden einer Retry-Nachricht ein zuvor gesendetes Token ungültig machen.
Doppelte Session Created und Session Confirmed Nachrichten werden nicht validiert, da der Noise-Handshake-Zustand nicht im korrekten Zustand sein wird, um sie zu entschlüsseln. Im schlimmsten Fall könnte ein Peer eine Session Confirmed als Antwort auf eine scheinbar doppelte Session Created erneut übertragen.
Wiedergesendete Hole Punch und Peer Test Nachrichten sollten wenig oder gar keine Auswirkungen haben.
Router müssen die Datenpaket-Nummer verwenden, um doppelte Datenphase-Nachrichten zu erkennen und zu verwerfen. Jede Paketnummer sollte nur einmal verwendet werden. Wiederholte Nachrichten müssen ignoriert werden.
Handshake Retransmission
Session Request
Falls Alice keine Session Created oder Retry erhält:
Behalten Sie dieselben Quell- und Verbindungs-IDs, den ephemeral key und die Paketnummer 0 bei. Oder behalten Sie einfach dasselbe verschlüsselte Paket bei und übertragen es erneut. Die Paketnummer darf nicht erhöht werden, da dies den verketteten Hash-Wert ändern würde, der zur Verschlüsselung der Session Created-Nachricht verwendet wird.
Empfohlene Übertragungswiederholungsintervalle: 1,25, 2,5 und 5 Sekunden (1,25, 3,75 und 8,75 Sekunden nach dem ersten Senden). Empfohlenes Timeout: 15 Sekunden insgesamt
Session Created
Wenn Bob keine Session Confirmed empfängt:
Behalten Sie dieselben Quell- und Verbindungs-IDs, den ephemeral key und die Paketnummer 0 bei. Oder behalten Sie einfach das verschlüsselte Paket. Die Paketnummer darf nicht erhöht werden, da dies den verketteten Hash-Wert ändern würde, der zur Verschlüsselung der Session Confirmed-Nachricht verwendet wird.
Empfohlene Übertragungsintervalle: 1, 2 und 4 Sekunden (1, 3 und 7 Sekunden nach dem ersten Versenden). Empfohlenes Timeout: 12 Sekunden insgesamt
Session Confirmed
In SSU 1 wechselt Alice nicht in die Datenphase, bis das erste Datenpaket von Bob empfangen wird. Dies macht SSU 1 zu einem Setup mit zwei Roundtrips.
Für SSU 2, empfohlene Session Confirmed Wiederholungsintervalle: 1,25, 2,5 und 5 Sekunden (1,25, 3,75 und 8,75 Sekunden nach dem ersten Versand).
Es gibt mehrere Alternativen. Alle sind 1 RTT:
Alice nimmt an, dass Session Confirmed empfangen wurde, sendet sofort Datennachrichten und übermittelt Session Confirmed niemals erneut. Datenpakete, die außerhalb der Reihenfolge empfangen werden (vor Session Confirmed), sind nicht entschlüsselbar, werden aber erneut übertragen. Wenn Session Confirmed verloren geht, werden alle gesendeten Datennachrichten verworfen.
Wie in 1), sende Datennachrichten sofort, aber übertrage auch Session Confirmed erneut, bis eine Datennachricht empfangen wird.
Wir könnten IK anstelle von XK verwenden, da es nur zwei Nachrichten im Handshake hat, aber es verwendet einen zusätzlichen DH (4 anstatt 3).
Die empfohlene Implementierung ist Option 2). Alice muss die Informationen behalten, die erforderlich sind, um die Session Confirmed Nachricht erneut zu übertragen. Alice sollte auch alle Data-Nachrichten erneut übertragen, nachdem die Session Confirmed Nachricht erneut übertragen wurde.
Beim erneuten Übertragen von Session Confirmed die gleichen Quell- und Verbindungs-IDs, den ephemeral key und die Paketnummer 1 beibehalten. Oder einfach das verschlüsselte Paket behalten. Die Paketnummer darf nicht erhöht werden, da dies den verketteten Hash-Wert ändern würde, der als Eingabe für die split()-Funktion dient.
Bob kann die vor der Session Confirmed-Nachricht empfangenen Datennachrichten beibehalten (in die Warteschlange einreihen). Weder die Header-Schutzschlüssel noch die Entschlüsselungsschlüssel sind verfügbar, bevor die Session Confirmed-Nachricht empfangen wird, sodass Bob nicht weiß, dass es sich um Datennachrichten handelt, aber das kann angenommen werden. Nachdem die Session Confirmed-Nachricht empfangen wurde, ist Bob in der Lage, die in der Warteschlange befindlichen Datennachrichten zu entschlüsseln und zu verarbeiten. Falls dies zu komplex ist, kann Bob einfach die nicht entschlüsselbaren Datennachrichten verwerfen, da Alice sie erneut übertragen wird.
Hinweis: Wenn die session confirmed Pakete verloren gehen, wird Bob session created erneut übertragen. Der session created Header wird nicht mit Alices intro key entschlüsselbar sein, da er mit Bobs intro key gesetzt ist (außer es wird eine Fallback-Entschlüsselung mit Bobs intro key durchgeführt). Bob kann die session confirmed Pakete sofort erneut übertragen, wenn sie zuvor nicht bestätigt wurden und ein nicht entschlüsselbares Paket empfangen wird.
Token Request
Wenn Alice kein Retry erhält:
Behalten Sie dieselben Quell- und Verbindungs-IDs bei. Eine Implementierung kann eine neue zufällige Paketnummer generieren und ein neues Paket verschlüsseln; oder sie kann dieselbe Paketnummer wiederverwenden oder einfach dasselbe verschlüsselte Paket beibehalten und erneut übertragen. Die Paketnummer darf nicht erhöht werden, da dies den verketteten Hash-Wert ändern würde, der zur Verschlüsselung der Session Created-Nachricht verwendet wird.
Empfohlene Retransmission-Intervalle: 3 und 6 Sekunden (3 und 9 Sekunden nach dem ersten Senden). Empfohlenes Timeout: insgesamt 15 Sekunden
Retry
Wenn keine Session Request von Bob empfangen wird:
Eine Retry-Nachricht wird bei einem Timeout nicht erneut übertragen, um die Auswirkungen gefälschter Quelladressen zu reduzieren.
Eine Retry-Nachricht kann jedoch als Antwort auf eine wiederholte Session Request-Nachricht, die mit dem ursprünglichen (ungültigen) Token empfangen wird, oder als Antwort auf eine wiederholte Token Request-Nachricht erneut übertragen werden. In beiden Fällen zeigt dies an, dass die Retry-Nachricht verloren gegangen ist.
Wenn eine zweite Session Request-Nachricht mit einem anderen, aber dennoch ungültigen Token empfangen wird, verwerfen Sie die ausstehende Session und antworten Sie nicht.
Beim erneuten Senden der Retry-Nachricht: Behalten Sie dieselben Quell- und Verbindungs-IDs sowie das Token bei. Eine Implementierung kann eine neue zufällige Paketnummer generieren und ein neues Paket verschlüsseln; Oder sie kann dieselbe Paketnummer wiederverwenden oder einfach dasselbe verschlüsselte Paket beibehalten und erneut übertragen.
Total Timeout
Die empfohlene Gesamtzeit für das Timeout beim Handshake beträgt 20 Sekunden.
Duplicates and Error Handling
Duplikate der drei Noise-Handshake-Nachrichten Session Request, Session Created und Session Confirmed müssen vor MixHash() des Headers erkannt werden. Während die Noise AEAD-Verarbeitung danach vermutlich fehlschlagen wird, wäre der Handshake-Hash bereits beschädigt.
Wenn eine der drei Nachrichten beschädigt ist und bei AEAD fehlschlägt, kann der Handshake anschließend auch bei einer Neuübertragung nicht wiederhergestellt werden, da MixHash() bereits mit der beschädigten Nachricht aufgerufen wurde.
Tokens
Das Token im Session Request Header wird zur DoS-Abwehr, zur Verhinderung von Quelladress-Spoofing und als Schutz gegen Replay-Angriffe verwendet.
Wenn Bob das Token in der Session Request-Nachricht nicht akzeptiert, entschlüsselt Bob die Nachricht NICHT, da dies eine aufwändige DH-Operation erfordert. Bob sendet einfach eine Retry-Nachricht mit einem neuen Token.
Wenn dann eine nachfolgende Session Request-Nachricht mit diesem Token empfangen wird, entschlüsselt Bob diese Nachricht und setzt den Handshake fort.
Der Token muss ein zufällig generierter 8-Byte-Wert sein, wenn der Generator des Tokens die Werte und die zugehörige IP und Port (im Arbeitsspeicher oder persistent) speichert. Der Generator darf keinen undurchsichtigen Wert generieren, zum Beispiel unter Verwendung des SipHash (mit einem geheimen Seed K0, K1) der IP, des Ports und der aktuellen Stunde oder des aktuellen Tags, um Tokens zu erstellen, die nicht im Arbeitsspeicher gespeichert werden müssen, da diese Methode es schwierig macht, wiederverwendete Tokens und Replay-Angriffe abzulehnen.
Tokens können nur einmal verwendet werden. Ein Token, der von Bob an Alice in einer Retry-Nachricht gesendet wird, muss sofort verwendet werden und läuft nach wenigen Sekunden ab. Ein Token, der in einem New Token Block in einer etablierten Sitzung gesendet wird, kann in einer nachfolgenden Verbindung verwendet werden und läuft zu dem in diesem Block angegebenen Zeitpunkt ab. Der Ablaufzeitpunkt wird vom Sender festgelegt; empfohlene Werte sind mindestens eine Stunde, maximal mehrere Stunden.
Wenn sich die IP-Adresse oder der Port eines routers ändert, muss er alle gespeicherten Token (sowohl eingehende als auch ausgehende) für die alte IP-Adresse oder den alten Port löschen, da sie nicht mehr gültig sind. Token können optional über router-Neustarts hinweg gespeichert werden, abhängig von der Implementierung. Die Annahme eines nicht abgelaufenen Tokens ist nicht garantiert; wenn Bob seine gespeicherten Token vergessen oder gelöscht hat, wird er einen Retry an Alice senden. Ein router kann sich dafür entscheiden, die Token-Speicherung zu begrenzen und die ältesten gespeicherten Token zu entfernen, auch wenn sie noch nicht abgelaufen sind.
Neue Token-Blöcke können von Alice an Bob oder von Bob an Alice gesendet werden. Sie würden typischerweise einmal gesendet werden, während oder kurz nach der Sitzungsetablierung. Das Token kann vor oder nach Ablauf mit einer neuen Ablaufzeit erneut gesendet werden, oder ein neues Token kann gesendet werden. Router sollten davon ausgehen, dass nur das zuletzt erhaltene Token gültig ist; es gibt keine Anforderung, mehrere eingehende oder ausgehende Token für dieselbe IP/Port zu speichern.
Ein Token ist an die Kombination aus Quell-IP/Port und Ziel-IP/Port gebunden. Ein Token, das über IPv4 empfangen wurde, darf nicht für IPv6 verwendet werden oder umgekehrt.
Wenn einer der beiden Peers während der Sitzung zu einer neuen IP oder einem neuen Port migriert (siehe Abschnitt Connection Migration), werden alle zuvor ausgetauschten Token ungültig und neue Token müssen ausgetauscht werden.
Implementierungen können Tokens auf der Festplatte speichern und beim Neustart wieder laden, sind aber nicht dazu verpflichtet. Falls gespeichert, muss die Implementierung sicherstellen, dass sich IP und Port seit dem Herunterfahren nicht geändert haben, bevor sie wieder geladen werden.
I2NP Message Fragmentation
Unterschiede zu SSU 1
Hinweis: Wie bei SSU 1 enthält das erste Fragment keine Informationen über die Gesamtanzahl der Fragmente oder die Gesamtlänge. Nachfolgende Fragmente enthalten keine Informationen über ihren Offset. Dies bietet dem Sender die Flexibilität, “on the fly” basierend auf dem verfügbaren Platz im Paket zu fragmentieren. (Java I2P macht dies nicht; es “pre-fragmentiert” bevor das erste Fragment gesendet wird) Allerdings belastet es den Empfänger, Fragmente zu speichern, die außerhalb der Reihenfolge empfangen werden, und die Wiederzusammensetzung zu verzögern, bis alle Fragmente empfangen wurden.
Wie bei SSU 1 muss jede Neuübertragung von Fragmenten die Länge (und den impliziten Offset) der vorherigen Übertragung des Fragments beibehalten.
SSU 2 trennt die drei Fälle (vollständige Nachricht, erstes Fragment und Folgefragment) in drei verschiedene Blocktypen, um die Verarbeitungseffizienz zu verbessern.
I2NP Message Duplication
Dieses Protokoll verhindert NICHT vollständig die doppelte Zustellung von I2NP-Nachrichten. Duplikate auf IP-Ebene oder Replay-Angriffe werden auf der SSU2-Ebene erkannt, da jede Paketnummer nur einmal verwendet werden darf.
Wenn I2NP-Nachrichten oder Fragmente jedoch in neuen Paketen erneut übertragen werden, ist dies auf der SSU2-Schicht nicht erkennbar. Der Router sollte das I2NP-Ablaufdatum durchsetzen (sowohl zu alt als auch zu weit in der Zukunft) und einen Bloom-Filter oder einen anderen Mechanismus basierend auf der I2NP-Nachrichten-ID verwenden.
Zusätzliche Mechanismen können vom Router oder in der SSU2-Implementierung verwendet werden, um Duplikate zu erkennen. Beispielsweise könnte SSU2 einen Cache von kürzlich empfangenen Nachrichten-IDs verwalten. Dies ist implementierungsabhängig.
Congestion Control
Dieser Vorschlag spezifiziert das Protokoll für Paketnummerierung und ACK-Blöcke. Dies bietet ausreichende Echtzeitinformationen für einen Sender, um einen effizienten und reaktionsschnellen Congestion Control-Algorithmus zu implementieren, während Flexibilität und Innovation in dieser Implementierung ermöglicht wird. Dieser Abschnitt diskutiert Implementierungsziele und bietet Vorschläge. Allgemeine Anleitung ist in RFC 9002 zu finden. Siehe auch RFC 6298 für Anleitung zu Retransmission-Timern.
ACK-only Datenpakete sollten nicht für Bytes oder Pakete in-flight gezählt werden und unterliegen nicht der Staukontrolle. Im Gegensatz zu TCP kann SSU2 den Verlust dieser Pakete erkennen und diese Information kann verwendet werden, um den Stau-Zustand anzupassen. Dieses Dokument spezifiziert jedoch keinen Mechanismus dafür.
Pakete, die einige andere Nicht-Daten-Blöcke enthalten, können ebenfalls von der Überlastungskontrolle ausgeschlossen werden, falls gewünscht, implementierungsabhängig. Zum Beispiel:
- Peer Test
- Relay-Anfrage/Einführung/Antwort
- Pfad-Challenge/Antwort
Es wird empfohlen, dass die Staukontrolle auf der Byte-Anzahl und nicht auf der Paket-Anzahl basiert, entsprechend den Richtlinien in den TCP RFCs und QUIC RFC 9002. Eine zusätzliche Paket-Anzahl-Begrenzung kann ebenfalls nützlich sein, um Pufferüberlauf im Kernel oder in Middleboxes zu verhindern, implementierungsabhängig, obwohl dies erhebliche Komplexität hinzufügen kann. Wenn die pro-Session und/oder gesamte Paket-Ausgabe bandbreitenbegrenzt und/oder getaktet ist, kann dies die Notwendigkeit einer Paket-Anzahl-Begrenzung mindern.
Packet Numbers
In SSU 1 enthielten ACKs und NACKs I2NP-Nachrichtennummern und Fragment-Bitmasken. Sender verfolgten den ACK-Status ausgehender Nachrichten (und ihrer Fragmente) und übertrugen Fragmente bei Bedarf erneut.
In SSU 2 enthalten ACKs und NACKs Paketnummern. Sender müssen eine Datenstruktur mit einer Zuordnung von Paketnummern zu deren Inhalten verwalten. Wenn ein Paket ACKed oder NACKed wird, muss der Sender bestimmen, welche I2NP-Nachrichten und Fragmente in diesem Paket enthalten waren, um zu entscheiden, was erneut übertragen werden soll.
Session Confirmed ACK
Bob sendet eine ACK für Paket 0, welche die Session Confirmed-Nachricht bestätigt und Alice erlaubt, zur Datenphase überzugehen und die große Session Confirmed-Nachricht zu verwerfen, die für eine mögliche Neuübertragung gespeichert wurde. Dies ersetzt die DeliveryStatusMessage, die von Bob in SSU 1 gesendet wurde.
Bob sollte ein ACK so schnell wie möglich senden, nachdem er die Session Confirmed-Nachricht erhalten hat. Eine kleine Verzögerung (nicht mehr als 50 ms) ist akzeptabel, da mindestens eine Data-Nachricht fast unmittelbar nach der Session Confirmed-Nachricht ankommen sollte, sodass das ACK sowohl die Session Confirmed- als auch die Data-Nachricht bestätigen kann. Dies verhindert, dass Bob die Session Confirmed-Nachricht erneut übertragen muss.
Generating ACKs
Definition: Ack-eliciting packets: Pakete, die ack-eliciting Blöcke enthalten, bewirken eine ACK vom Empfänger innerhalb der maximalen Bestätigungsverzögerung und werden ack-eliciting packets genannt.
Router bestätigen alle Pakete, die sie empfangen und verarbeiten. Allerdings führen nur bestätigungspflichtige Pakete dazu, dass ein ACK-Block innerhalb der maximalen ACK-Verzögerung gesendet wird. Pakete, die nicht bestätigungspflichtig sind, werden nur bestätigt, wenn ein ACK-Block aus anderen Gründen gesendet wird.
Beim Senden eines Pakets aus beliebigem Grund sollte ein Endpunkt versuchen, einen ACK-Block einzuschließen, falls kürzlich keiner gesendet wurde. Dies hilft bei der zeitnahen Verlusterkennung beim Peer.
Im Allgemeinen verbessert häufiges Feedback von einem Empfänger die Verlust- und Überlastungsreaktion, aber dies muss gegen die übermäßige Last abgewogen werden, die von einem Empfänger erzeugt wird, der als Antwort auf jedes ACK-auslösende Paket einen ACK-Block sendet. Die unten angebotene Anleitung versucht, dieses Gleichgewicht zu finden.
In-Session-Datenpakete, die einen beliebigen Block AUSSER den folgenden enthalten, erfordern eine Bestätigung:
- ACK-Block
- Adress-Block
- DateTime-Block
- Padding-Block
- Termination-Block
- Alle Blöcke im selben Paket wie ein Termination-Block
- Andere?
Pakete, die einen Termination-Block mit einem anderen Grund als “termination received” enthalten, werden mit einem Paket bestätigt, das einen Termination-Block mit “termination received” enthält.
Out-of-Session-Pakete, einschließlich Handshake-Nachrichten und Peer-Test-Nachrichten 5-7, haben ihre eigenen Bestätigungsmechanismen. Siehe unten.
Handshake ACKs
Dies sind Sonderfälle:
- Token Request wird implizit durch Retry bestätigt
- Session Request wird implizit durch Session Created oder Retry bestätigt
- Retry wird implizit durch Session Request bestätigt
- Session Created wird implizit durch Session Confirmed bestätigt
- Session Confirmed sollte sofort bestätigt werden
Sending ACK Blocks
ACK-Blöcke werden verwendet, um Data-Phase-Pakete zu bestätigen. Sie sollen nur für In-Session-Data-Phase-Pakete eingeschlossen werden.
Jedes Paket sollte mindestens einmal bestätigt werden, und Pakete, die eine Bestätigung erfordern, müssen mindestens einmal innerhalb einer maximalen Verzögerung bestätigt werden.
Ein Endpoint muss alle ack-auslösenden Handshake-Pakete unverzüglich innerhalb seiner maximalen Verzögerung bestätigen, mit folgender Ausnahme. Vor der Handshake-Bestätigung verfügt ein Endpoint möglicherweise nicht über die Paket-Header-Verschlüsselungsschlüssel zum Entschlüsseln der Pakete, wenn sie empfangen werden. Er könnte sie daher puffern und bestätigen, wenn die erforderlichen Schlüssel verfügbar werden.
Da Pakete, die nur ACK-Blöcke enthalten, nicht staukontrolliert sind, darf ein Endpunkt nicht mehr als ein solches Paket als Antwort auf den Empfang eines ACK-auslösenden Pakets senden.
Ein Endpunkt darf kein nicht-bestätigungspflichtiges Paket als Antwort auf ein nicht-bestätigungspflichtiges Paket senden, selbst wenn es Paketlücken gibt, die dem empfangenen Paket vorangehen. Dies verhindert eine unendliche Rückkopplungsschleife von Bestätigungen, die verhindern könnte, dass die Verbindung jemals in den Leerlauf übergeht. Nicht-bestätigungspflichtige Pakete werden schließlich bestätigt, wenn der Endpunkt einen ACK-Block als Antwort auf andere Ereignisse sendet.
Ein Endpunkt, der nur ACK-Blöcke sendet, wird keine Bestätigungen von seinem Peer erhalten, es sei denn, diese Bestätigungen sind in Paketen mit ack-eliciting Blöcken enthalten. Ein Endpunkt sollte einen ACK-Block mit anderen Blöcken senden, wenn neue ack-eliciting Pakete zu bestätigen sind. Wenn nur non-ack-eliciting Pakete bestätigt werden müssen, KANN ein Endpunkt wählen, keinen ACK-Block mit ausgehenden Blöcken zu senden, bis ein ack-eliciting Paket empfangen wurde.
Ein Endpunkt, der nur Pakete sendet, die keine Bestätigung erfordern, könnte sich dafür entscheiden, gelegentlich einen bestätigungspflichtigen Block zu diesen Paketen hinzuzufügen, um sicherzustellen, dass er eine Bestätigung erhält. In diesem Fall DARF ein Endpunkt NICHT in allen Paketen, die andernfalls keine Bestätigung erfordern würden, einen bestätigungspflichtigen Block senden, um eine unendliche Rückkopplungsschleife von Bestätigungen zu vermeiden.
Um die Verlusterkennung beim Sender zu unterstützen, sollte ein Endpunkt unverzüglich einen ACK-Block generieren und senden, wenn er ein ACK-auslösendes Paket in einem der folgenden Fälle empfängt:
Wenn das empfangene Paket eine Paketnummer hat, die kleiner ist als die eines anderen ack-eliciting Pakets, das empfangen wurde
Wenn das Paket eine Paketnummer hat, die größer ist als das höchstnummerierte bestätigungspflichtige Paket, das empfangen wurde, und es fehlende Pakete zwischen diesem Paket und jenem Paket gibt.
Wenn das ack-immediate Flag im Packet-Header gesetzt ist
Die Algorithmen sollen robust gegen Empfänger sein, die den oben angebotenen Leitlinien nicht folgen. Eine Implementierung sollte jedoch nur nach sorgfältiger Abwägung der Leistungsauswirkungen einer Änderung von diesen Anforderungen abweichen, sowohl für Verbindungen, die vom Endpunkt hergestellt werden, als auch für andere Nutzer des Netzwerks.
ACK Frequency
Ein Empfänger bestimmt, wie häufig Bestätigungen als Antwort auf bestätigungsauslösende Pakete gesendet werden sollen. Diese Bestimmung beinhaltet einen Kompromiss.
Endpunkte sind auf rechtzeitige Bestätigungen angewiesen, um Verluste zu erkennen. Fensterbasierte Congestion Controller sind auf Bestätigungen angewiesen, um ihr Congestion Window zu verwalten. In beiden Fällen kann das Verzögern von Bestätigungen die Leistung beeinträchtigen.
Andererseits reduziert die Verringerung der Häufigkeit von Paketen, die nur Bestätigungen übertragen, die Kosten für Paketübertragung und -verarbeitung an beiden Endpunkten. Dies kann den Verbindungsdurchsatz bei stark asymmetrischen Verbindungen verbessern und das Volumen des Bestätigungsverkehrs reduzieren, der die Kapazität des Rückpfads nutzt; siehe Abschnitt 3 von RFC 3449.
Ein Empfänger sollte einen ACK-Block senden, nachdem er mindestens zwei ACK-auslösende Pakete erhalten hat. Diese Empfehlung ist allgemeiner Natur und konsistent mit den Empfehlungen für TCP-Endpunkt-Verhalten RFC 5681. Kenntnisse über Netzwerkbedingungen, Kenntnisse über den Congestion Controller des Peers oder weitere Forschung und Experimente könnten alternative Bestätigungsstrategien mit besseren Leistungscharakteristika nahelegen.
Ein Empfänger kann mehrere verfügbare Pakete verarbeiten, bevor er entscheidet, ob er einen ACK-Block als Antwort sendet. Im Allgemeinen sollte der Empfänger eine ACK nicht länger als RTT / 6 oder maximal 150 ms verzögern.
Das ack-immediate Flag im Datenpaket-Header ist eine Anfrage, dass der Empfänger kurz nach dem Empfang ein ACK sendet, wahrscheinlich innerhalb weniger ms. Im Allgemeinen sollte der Empfänger ein sofortiges ACK nicht um mehr als RTT / 16 oder maximal 5 ms verzögern.
Immediate ACK Flag
Der Empfänger kennt die Send-Window-Größe des Senders nicht und weiß daher nicht, wie lange er warten soll, bevor er ein ACK sendet. Das Immediate-ACK-Flag im Datenpaket-Header ist ein wichtiger Weg, um maximalen Durchsatz durch Minimierung der effektiven RTT aufrechtzuerhalten. Das Immediate-ACK-Flag ist Header-Byte 13, Bit 0, d.h. (header[13] & 0x01). Wenn gesetzt, wird ein sofortiges ACK angefordert. Siehe den Abschnitt über Short Header oben für Details.
Es gibt mehrere mögliche Strategien, die ein Sender verwenden kann, um zu bestimmen, wann das immediate-ack-Flag gesetzt werden soll:
- Wird einmal alle N Pakete gesetzt, für ein kleines N
- Wird beim letzten Paket in einem Paket-Burst gesetzt
- Wird gesetzt, wenn das Sendefenster fast voll ist, zum Beispiel über 2/3 voll
- Wird bei allen Paketen mit erneut übertragenen Fragmenten gesetzt
Immediate ACK-Flags sollten nur bei Datenpaketen erforderlich sein, die I2NP-Nachrichten oder Nachrichtenfragmente enthalten.
ACK Block Size
Wenn ein ACK-Block gesendet wird, werden ein oder mehrere Bereiche von bestätigten Paketen eingeschlossen. Das Einbeziehen von Bestätigungen für ältere Pakete reduziert die Wahrscheinlichkeit von irrtümlichen Neuübertragungen, die durch den Verlust zuvor gesendeter ACK-Blöcke verursacht werden, auf Kosten größerer ACK-Blöcke.
ACK-Blöcke sollten immer die zuletzt empfangenen Pakete bestätigen, und je ungeordneter die Pakete sind, desto wichtiger ist es, schnell einen aktualisierten ACK-Block zu senden, um zu verhindern, dass der Peer ein Paket als verloren erklärt und die darin enthaltenen Blöcke fälschlicherweise erneut überträgt. Ein ACK-Block muss in ein einzelnes Paket passen. Wenn dies nicht der Fall ist, werden ältere Bereiche (die mit den kleinsten Paketnummern) weggelassen.
Ein Empfänger begrenzt die Anzahl der ACK-Bereiche, die er sich merkt und in ACK-Blöcken sendet, sowohl um die Größe von ACK-Blöcken zu begrenzen als auch um Ressourcenerschöpfung zu vermeiden. Nachdem er Bestätigungen für einen ACK-Block erhalten hat, sollte der Empfänger aufhören, diese bestätigten ACK-Bereiche zu verfolgen. Sender können Bestätigungen für die meisten Pakete erwarten, aber dieses Protokoll garantiert nicht den Erhalt einer Bestätigung für jedes Paket, das der Empfänger verarbeitet.
Es ist möglich, dass das Beibehalten vieler ACK-Bereiche dazu führen könnte, dass ein ACK-Block zu groß wird. Ein Empfänger kann unbestätigte ACK-Bereiche verwerfen, um die ACK-Block-Größe zu begrenzen, auf Kosten erhöhter Neuübertragungen vom Sender. Dies ist notwendig, wenn ein ACK-Block zu groß wäre, um in ein Paket zu passen. Empfänger können die ACK-Block-Größe auch weiter begrenzen, um Platz für andere Blöcke zu bewahren oder um die Bandbreite zu begrenzen, die Bestätigungen verbrauchen.
Ein Empfänger muss einen ACK-Bereich beibehalten, es sei denn, er kann sicherstellen, dass er anschließend keine Pakete mit Nummern in diesem Bereich akzeptiert. Die Aufrechterhaltung einer minimalen Paketnummer, die steigt, während Bereiche verworfen werden, ist eine Möglichkeit, dies mit minimalem Zustand zu erreichen.
Empfänger können alle ACK-Bereiche verwerfen, aber sie müssen die größte Paketnummer beibehalten, die erfolgreich verarbeitet wurde, da diese zur Wiederherstellung von Paketnummern aus nachfolgenden Paketen verwendet wird.
Der folgende Abschnitt beschreibt einen beispielhaften Ansatz zur Bestimmung, welche Pakete in jedem ACK-Block bestätigt werden sollen. Obwohl das Ziel dieses Algorithmus darin besteht, eine Bestätigung für jedes verarbeitete Paket zu generieren, ist es dennoch möglich, dass Bestätigungen verloren gehen.
Limiting Ranges by Tracking ACK Blocks
Wenn ein Paket mit einem ACK-Block gesendet wird, kann das Ack Through-Feld in diesem Block gespeichert werden. Wenn ein Paket mit einem ACK-Block bestätigt wird, kann der Empfänger aufhören, Pakete zu bestätigen, die kleiner oder gleich dem Ack Through-Feld im gesendeten ACK-Block sind.
Ein Empfänger, der nur Pakete sendet, die keine Bestätigung erfordern, wie ACK-Blöcke, könnte für eine lange Zeit keine Bestätigung erhalten. Dies könnte dazu führen, dass der Empfänger den Status für eine große Anzahl von ACK-Blöcken über einen langen Zeitraum aufrechterhält, und die ACK-Blöcke, die er sendet, könnten unnötig groß sein. In einem solchen Fall könnte ein Empfänger gelegentlich ein PING oder einen anderen kleinen bestätigungsanfordernden Block senden, beispielsweise einmal pro Rundlaufzeit, um eine ACK-Antwort vom Peer zu erhalten.
In Fällen ohne ACK-Block-Verlust ermöglicht dieser Algorithmus eine minimale Neuanordnung von 1 RTT. In Fällen mit ACK-Block-Verlust und Neuanordnung garantiert dieser Ansatz nicht, dass jede Bestätigung vom Sender gesehen wird, bevor sie nicht mehr im ACK-Block enthalten ist. Pakete könnten außer der Reihe empfangen werden, und alle nachfolgenden ACK-Blöcke, die sie enthalten, könnten verloren gehen. In diesem Fall könnte der Verlustwiederherstellungsalgorithmus falsche Neuübertragungen verursachen, aber der Sender wird weiterhin Fortschritte machen.
Congestion
I2P-Transporte garantieren nicht die Zustellung von I2NP-Nachrichten in der richtigen Reihenfolge. Daher verhindert der Verlust einer Data-Nachricht, die eine oder mehrere I2NP-Nachrichten oder -Fragmente enthält, NICHT die Zustellung anderer I2NP-Nachrichten; es gibt keine Head-of-Line-Blockierung. Implementierungen sollten während der Verlustwiederherstellungsphase weiterhin neue Nachrichten senden, wenn das Sendefenster dies zulässt.
Retransmission
Ein Sender sollte nicht den vollständigen Inhalt einer Nachricht behalten, um sie identisch erneut zu übertragen (außer bei Handshake-Nachrichten, siehe oben). Ein Sender muss jedes Mal, wenn er eine Nachricht sendet, Nachrichten mit aktuellen Informationen (ACKs, NACKs und unbestätigte Daten) zusammenstellen. Ein Sender sollte vermeiden, Informationen aus Nachrichten erneut zu übertragen, sobald diese bestätigt wurden. Dies schließt Nachrichten ein, die nach ihrer Verlusterklärung bestätigt werden, was bei Netzwerk-Reordering auftreten kann.
Window
TBD. Allgemeine Leitlinien finden sich in RFC 9002.
Connection Migration
Die IP oder der Port eines Peers kann sich während der Lebensdauer einer Sitzung ändern. Eine IP-Änderung kann durch IPv6-Rotation temporärer Adressen, ISP-gesteuerte periodische IP-Änderungen, einen mobilen Client beim Wechsel zwischen WiFi- und Mobilfunk-IPs oder andere lokale Netzwerkänderungen verursacht werden. Eine Port-Änderung kann durch eine NAT-Neubindung verursacht werden, nachdem die vorherige Bindung abgelaufen ist.
Die IP-Adresse oder der Port eines Peers kann sich aufgrund verschiedener On-Path- und Off-Path-Angriffe zu ändern scheinen, einschließlich der Modifikation oder Injektion von Paketen.
Connection Migration ist der Prozess, bei dem ein neuer Quell-Endpunkt (IP+Port) validiert wird, während Änderungen verhindert werden, die nicht validiert sind. Dieser Prozess ist eine vereinfachte Version von dem in QUIC RFC 9000 definierten. Dieser Prozess ist nur für die Datenphase einer Session definiert. Migration ist während des Handshakes nicht erlaubt. Alle Handshake-Pakete müssen verifiziert werden, dass sie von derselben IP und demselben Port stammen wie zuvor gesendete und empfangene Pakete. Mit anderen Worten, die IP und der Port eines Peers müssen während des Handshakes konstant sein.
Threat Model
(Adaptiert von QUIC RFC 9000)
Hinweise
Ein Peer kann seine Quell-Adresse fälschen, um einen Endpoint dazu zu bringen, übermäßige Datenmengen an einen unwilligen Host zu senden. Wenn der Endpoint deutlich mehr Daten sendet als der fälschende Peer, könnte Connection Migration verwendet werden, um das Datenvolumen zu verstärken, das ein Angreifer gegen ein Opfer generieren kann.
Session Confirmed Fragmentation
Ein Angreifer auf dem Übertragungsweg könnte eine unechte Verbindungsmigration verursachen, indem er ein Paket mit einer gefälschten Adresse kopiert und weiterleitet, sodass es vor dem ursprünglichen Paket ankommt. Das Paket mit der gefälschten Adresse wird so wahrgenommen, als käme es von einer migrierenden Verbindung, und das ursprüngliche Paket wird als Duplikat angesehen und verworfen. Nach einer unechten Migration wird die Validierung der Quelladresse fehlschlagen, weil die Entität an der Quelladresse nicht über die notwendigen kryptographischen Schlüssel verfügt, um die Path Challenge zu lesen oder darauf zu antworten, die an sie gesendet wird, selbst wenn sie es wollte.
Off-Path Packet Forwarding
Ein Off-Path-Angreifer, der Pakete beobachten kann, könnte Kopien echter Pakete an Endpunkte weiterleiten. Wenn das kopierte Paket vor dem echten Paket ankommt, wird dies als NAT-Rebinding erscheinen. Jedes echte Paket wird als Duplikat verworfen. Wenn der Angreifer in der Lage ist, weiterhin Pakete weiterzuleiten, könnte er eine Migration zu einem Pfad über den Angreifer verursachen. Dies platziert den Angreifer on-path und gibt ihm die Fähigkeit, alle nachfolgenden Pakete zu beobachten oder zu verwerfen.
Privacy Implications
QUIC RFC 9000 spezifizierte das Ändern von Verbindungs-IDs beim Wechsel von Netzwerkpfaden. Die Verwendung einer stabilen Verbindungs-ID auf mehreren Netzwerkpfaden würde es einem passiven Beobachter ermöglichen, Aktivitäten zwischen diesen Pfaden zu korrelieren. Ein Endpunkt, der zwischen Netzwerken wechselt, möchte möglicherweise nicht, dass seine Aktivität von einer anderen Entität als seinem Peer korreliert wird. QUIC verschlüsselt jedoch die Verbindungs-IDs im Header nicht. SSU2 tut dies jedoch, sodass das Datenschutzleck erfordern würde, dass der passive Beobachter auch Zugang zur Netzwerkdatenbank hat, um den Einführungsschlüssel zu erhalten, der zur Entschlüsselung der Verbindungs-ID erforderlich ist. Selbst mit dem Einführungsschlüssel ist dies kein starker Angriff, und wir ändern Verbindungs-IDs nach der Migration in SSU2 nicht, da dies eine erhebliche Komplikation wäre.
Initiating Path Validation
Während der Datenphase müssen Peers überprüfen, dass die Quell-IP und der Port jedes empfangenen Datenpakets stimmen. Wenn sich die IP oder der Port von zuvor empfangenen unterscheidet UND das Paket keine doppelte Paketnummer ist UND das Paket erfolgreich entschlüsselt wird, tritt die Sitzung in die Pfadvalidierungsphase ein.
Zusätzlich muss ein Peer verifizieren, dass die neue IP und der Port gemäß den lokalen Validierungsregeln gültig sind (nicht blockiert, keine illegalen Ports, etc.). Peers sind NICHT verpflichtet, Migration zwischen IPv4 und IPv6 zu unterstützen, und können eine neue IP in der anderen Adressfamilie als ungültig behandeln, da dies kein erwartetes Verhalten ist und erhebliche Implementierungskomplexität hinzufügen kann. Beim Empfang eines Pakets von einer ungültigen IP/Port kann eine Implementierung es einfach verwerfen oder eine Pfadvalidierung mit der alten IP/Port initiieren.
Beim Eintreten in die Pfadvalidierungsphase führen Sie die folgenden Schritte aus:
- Starte einen Pfadvalidierungs-Timeout-Timer von mehreren Sekunden, oder mehreren Malen der aktuellen RTO (TBD)
- Reduziere das Congestion Window auf das Minimum
- Reduziere die PMTU auf das Minimum (1280)
- Sende ein Datenpaket, das einen Path Challenge Block, einen Address Block (enthält die neue IP/Port), und typischerweise einen ACK Block enthält, an die neue IP und den Port. Dieses Paket verwendet dieselbe Connection ID und Verschlüsselungsschlüssel wie die aktuelle Sitzung. Die Path Challenge Block Daten müssen ausreichend Entropie enthalten (mindestens 8 Bytes), damit sie nicht gespoooft werden können.
- Optional, sende auch eine Path Challenge an die alte IP/Port, mit anderen Block-Daten. Siehe unten.
- Starte einen Path Response Timeout-Timer basierend auf der aktuellen RTO (typischerweise RTT + ein Vielfaches von RTTdev)
Während der Pfadvalidierungsphase kann die Session weiterhin eingehende Pakete verarbeiten. Sowohl von der alten als auch von der neuen IP/Port. Die Session kann auch weiterhin Datenpakete senden und bestätigen. Jedoch müssen das Congestion Window und die PMTU während der Pfadvalidierungsphase bei den Minimalwerten bleiben, um zu verhindern, dass sie für Denial-of-Service-Angriffe verwendet werden, indem große Mengen an Traffic an eine gefälschte Adresse gesendet werden.
Eine Implementierung kann, ist aber nicht verpflichtet, versuchen, mehrere Pfade gleichzeitig zu validieren. Dies ist wahrscheinlich die Komplexität nicht wert. Sie kann, ist aber nicht verpflichtet, sich an eine vorherige IP/Port als bereits validiert zu erinnern und die Pfadvalidierung zu überspringen, wenn ein Peer zu seiner vorherigen IP/Port zurückkehrt.
Wenn eine Path Response empfangen wird, die die identischen Daten enthält, die in der Path Challenge gesendet wurden, war die Path Validation erfolgreich. Die Quell-IP/Port der Path Response-Nachricht muss nicht dieselbe sein, an die die Path Challenge gesendet wurde.
Wenn keine Path Response vor Ablauf des Path Response Timers empfangen wird, sende eine weitere Path Challenge und verdopple den Path Response Timer.
Wenn eine Path Response nicht empfangen wird, bevor der Path Validation Timer abläuft, ist die Path Validation fehlgeschlagen.
Message Contents
Die Data-Nachrichten sollten die folgenden Blöcke enthalten. Die Reihenfolge ist nicht spezifiziert, außer dass Padding zuletzt stehen muss:
- Path Validation- oder Path Response-Block. Path Validation enthält undurchsichtige Daten, empfohlen mindestens 8 Bytes. Path Response enthält die Daten aus der Path Validation.
- Address-Block mit der scheinbaren IP des Empfängers
- DateTime-Block
- ACK-Block
- Padding-Block
Es wird nicht empfohlen, andere Blöcke (zum Beispiel I2NP) in die Nachricht einzufügen.
Es ist erlaubt, einen Path Validation Block in die Nachricht einzuschließen, die die Path Response enthält, um eine Validierung in die andere Richtung zu initiieren.
Path Challenge- und Path Response-Blöcke sind ACK-auslösend. Die Path Challenge wird durch eine Data-Nachricht bestätigt, die die Path Response- und ACK-Blöcke enthält. Die Path Response sollte durch eine Data-Nachricht bestätigt werden, die einen ACK-Block enthält.
Routing during Path Validation
Die QUIC-Spezifikation ist nicht eindeutig darüber, wohin Datenpakete während der Pfadvalidierung gesendet werden sollen - an die alte oder neue IP/Port-Kombination? Es muss ein Gleichgewicht gefunden werden zwischen der schnellen Reaktion auf IP/Port-Änderungen und dem Vermeiden, Datenverkehr an gefälschte Adressen zu senden. Außerdem dürfen gefälschte Pakete eine bestehende Sitzung nicht wesentlich beeinträchtigen. Reine Port-Änderungen werden wahrscheinlich durch NAT-Rebinding nach einer Ruhephase verursacht; IP-Änderungen könnten während Phasen mit hohem Datenverkehr in eine oder beide Richtungen auftreten.
Strategien unterliegen Forschung und Verfeinerung. Möglichkeiten umfassen:
- Keine Datenpakete an die neue IP/Port senden, bis diese validiert ist
- Weiterhin Datenpakete an die alte IP/Port senden, bis die neue IP/Port validiert ist
- Gleichzeitige Revalidierung der alten IP/Port
- Keine Daten senden, bis entweder die alte oder neue IP/Port validiert ist
- Unterschiedliche Strategien für reine Port-Änderungen im Vergleich zu IP-Änderungen
- Unterschiedliche Strategien für eine IPv6-Änderung innerhalb desselben /32, wahrscheinlich verursacht durch temporäre Adressrotation
Responding to Path Challenge
Beim Empfang einer Path Challenge muss der Peer mit einem Datenpaket antworten, das eine Path Response mit den Daten aus der Path Challenge enthält. TODO Vielleicht???: Die Path Response muss an die IP/den Port gesendet werden, von dem die Path Challenge empfangen wurde. Dies ist NICHT ZWINGEND die IP/der Port, die zuvor für den Peer etabliert wurde. Dies stellt sicher, dass die Pfadvalidierung durch einen Peer nur erfolgreich ist, wenn der Pfad in beide Richtungen funktionsfähig ist. Siehe den Abschnitt Validation after Local Change unten.
Sofern sich die IP/der Port nicht von der zuvor bekannten IP/dem zuvor bekannten Port des Peers unterscheidet, behandle eine Path Challenge als einfachen Ping und antworte bedingungslos mit einer Path Response. Der Empfänger behält oder ändert keinen Zustand basierend auf einer empfangenen Path Challenge. Wenn sich die IP/der Port unterscheidet, muss ein Peer überprüfen, dass die neue IP und der neue Port gemäß lokalen Validierungsregeln gültig sind (nicht blockiert, keine illegalen Ports, etc.). Peers sind NICHT verpflichtet, adressfamilien-übergreifende Antworten zwischen IPv4 und IPv6 zu unterstützen und können eine neue IP in der anderen Adressfamilie als ungültig behandeln, da dies kein erwartetes Verhalten ist.
Sofern nicht durch Staukontrolle eingeschränkt, sollte die Path Response sofort gesendet werden. Implementierungen sollten Maßnahmen ergreifen, um Path Responses oder die verwendete Bandbreite bei Bedarf zu begrenzen.
Ein Path Challenge Block wird im Allgemeinen von einem Address Block in derselben Nachricht begleitet. Wenn der Address Block eine neue IP/Port enthält, kann ein Peer diese IP/Port validieren und Peer-Tests dieser neuen IP/Port initiieren, mit dem Session-Peer oder jedem anderen Peer. Wenn der Peer denkt, dass er durch eine Firewall geschützt ist, und sich nur der Port geändert hat, ist diese Änderung wahrscheinlich auf NAT-Rebinding zurückzuführen, und weitere Peer-Tests sind wahrscheinlich nicht erforderlich.
Successful Path Validation
Bei erfolgreicher Pfadvalidierung wird die Verbindung vollständig zur neuen IP/zum neuen Port migriert. Bei Erfolg:
- Den Pfadvalidierungsphase beenden
- Alle Pakete werden an die neue IP und den neuen Port gesendet.
- Die Beschränkungen für das Congestion Window und die PMTU werden aufgehoben und dürfen wieder ansteigen. Stellen Sie sie nicht einfach auf die alten Werte zurück, da der neue Pfad andere Eigenschaften haben kann.
- Wenn sich die IP geändert hat, setzen Sie die berechnete RTT und RTO auf Anfangswerte. Da Änderungen nur des Ports häufig das Ergebnis von NAT-Rebinding oder anderen Middlebox-Aktivitäten sind, kann der Peer stattdessen seinen Congestion Control-Zustand und die Round-Trip-Schätzung in diesen Fällen beibehalten, anstatt zu den Anfangswerten zurückzukehren.
- Token löschen (invalidieren), die für die alte IP/Port gesendet oder empfangen wurden (optional)
- Einen neuen Token-Block für die neue IP/Port senden (optional)
Cancelling Path Validation
Während der Pfadvalidierungsphase führen alle gültigen, nicht-duplizierten Pakete, die von der alten IP/dem alten Port empfangen und erfolgreich entschlüsselt werden, dazu, dass die Pfadvalidierung abgebrochen wird. Es ist wichtig, dass eine abgebrochene Pfadvalidierung, die durch ein gefälschtes Paket verursacht wurde, nicht dazu führt, dass eine gültige Sitzung beendet oder erheblich gestört wird.
Bei abgebrochener Pfadvalidierung:
- Die Pfadvalidierungsphase verlassen
- Alle Pakete werden an die alte IP und den alten Port gesendet.
- Die Beschränkungen für das Congestion Window und die PMTU werden aufgehoben und dürfen ansteigen oder optional die vorherigen Werte wiederherstellen
- Alle Datenpakete, die zuvor an die neue IP/den neuen Port gesendet wurden, an die alte IP/den alten Port erneut übertragen.
Failed Path Validation
Es ist wichtig, dass eine fehlgeschlagene Pfadvalidierung, die durch ein gefälschtes Paket verursacht wurde, nicht dazu führt, dass eine gültige Sitzung beendet oder erheblich gestört wird.
Bei fehlgeschlagener Pfadvalidierung:
- Die Path-Validierung-Phase verlassen
- Alle Pakete werden an die alte IP und den alten Port gesendet.
- Die Beschränkungen für das Congestion Window und PMTU werden aufgehoben, und sie dürfen wieder ansteigen.
- Optional eine Path-Validierung auf der alten IP und dem alten Port starten. Falls sie fehlschlägt, die Session beenden.
- Andernfalls den Standard-Regeln für Session-Timeout und -Beendigung folgen.
- Alle Datenpakete, die zuvor an die neue IP/den neuen Port gesendet wurden, an die alte IP/den alten Port erneut übertragen.
Validation After Local Change
Der oben beschriebene Prozess ist für Peers definiert, die ein Paket von einer geänderten IP/Port erhalten. Er kann jedoch auch in die andere Richtung initiiert werden, von einem Peer, der erkennt, dass sich seine IP oder sein Port geändert hat. Ein Peer kann möglicherweise erkennen, dass sich seine lokale IP geändert hat; es ist jedoch viel weniger wahrscheinlich, dass er erkennt, dass sich sein Port aufgrund einer NAT-Neubindung geändert hat. Daher ist dies optional.
Beim Empfang einer Path Challenge von einem Peer, dessen IP oder Port sich geändert hat, sollte der andere Peer eine Path Challenge in die andere Richtung initiieren.
Relay-Sicherheit
Path Validation und Path Response Blöcke können jederzeit als Ping/Pong-Pakete verwendet werden. Der Empfang eines Path Validation Blocks verändert keinen Zustand beim Empfänger, es sei denn, er wird von einer anderen IP/Port empfangen.
Multiple Sessions
Peers sollten nicht mehrere Sitzungen mit demselben Peer aufbauen, weder SSU 1 oder 2, noch mit derselben oder verschiedenen IP-Adressen. Dies könnte jedoch passieren, entweder aufgrund von Fehlern, oder weil eine vorherige Sitzungsbeendigungsnachricht verloren ging, oder in einer Wettlaufsituation, in der die Beendigungsnachricht noch nicht angekommen ist.
Wenn Bob eine bestehende Session mit Alice hat und Bob die Session Confirmed von Alice erhält, wodurch der Handshake abgeschlossen und eine neue Session etabliert wird, sollte Bob:
- Migriere alle nicht gesendeten oder unbestätigten ausgehenden I2NP-Nachrichten von der alten Sitzung zur neuen
- Sende eine Beendigung mit Grund-Code 22 an die alte Sitzung
- Entferne die alte Sitzung und ersetze sie durch die neue
Session Termination
Peer Test Sicherheit
Sessions in der Handshake-Phase werden im Allgemeinen einfach durch Zeitüberschreitung oder durch das Ausbleiben weiterer Antworten beendet. Optional können sie durch das Einfügen eines Termination-Blocks in die Antwort beendet werden, aber die meisten Fehler können aufgrund fehlender kryptographischer Schlüssel nicht beantwortet werden. Selbst wenn Schlüssel für eine Antwort mit einem Termination-Block verfügbar sind, ist es normalerweise die CPU-Zeit nicht wert, den DH für die Antwort durchzuführen. Eine Ausnahme KANN ein Termination-Block in einer Wiederholungsnachricht sein, der kostengünstig zu generieren ist.
Relay- und Peer-Test-Designziele
Sessions in der Datenphase werden beendet, indem eine Datennachricht gesendet wird, die einen Termination-Block enthält. Diese Nachricht sollte auch einen ACK-Block enthalten. Sie kann, falls die Session lange genug aktiv war, dass ein zuvor gesendetes Token abgelaufen ist oder kurz vor dem Ablauf steht, einen New Token-Block enthalten. Diese Nachricht ist nicht ack-eliciting. Beim Empfang eines Termination-Blocks mit einem anderen Grund als “Termination Received” antwortet der Peer mit einer Datennachricht, die einen Termination-Block mit dem Grund “Termination Received” enthält.
Nach dem Senden oder Empfangen eines Termination-Blocks sollte die Session für eine maximale Zeitdauer (noch zu bestimmen) in die Schließungsphase eintreten. Der Schließungszustand ist notwendig, um gegen den Verlust des Pakets mit dem Termination-Block und gegen Pakete zu schützen, die in der anderen Richtung bereits unterwegs sind. Während der Schließungsphase besteht keine Anforderung, weitere empfangene Pakete zu verarbeiten. Eine Session im Schließungszustand sendet ein Paket mit einem Termination-Block als Antwort auf jedes eingehende Paket, das sie der Session zuordnet. Eine Session sollte die Rate begrenzen, mit der sie Pakete im Schließungszustand generiert. Beispielsweise könnte eine Session auf eine progressiv zunehmende Anzahl empfangener Pakete oder Zeitdauer warten, bevor sie auf empfangene Pakete antwortet.
Um den Zustand zu minimieren, den ein Router für eine sich schließende Sitzung aufrechterhält, können Sitzungen als Antwort auf jedes empfangene Paket das exakt gleiche Paket mit derselben Paketnummer unverändert senden, sind jedoch nicht dazu verpflichtet. Hinweis: Die Erlaubnis zur Neuübertragung eines Beendigungspakets ist eine Ausnahme von der Anforderung, dass für jedes Paket eine neue Paketnummer verwendet werden muss. Das Senden neuer Paketnummern ist hauptsächlich für die Verlustwiederherstellung und Staukontrolle von Vorteil, was bei einer geschlossenen Verbindung nicht relevant sein dürfte. Die Neuübertragung des finalen Pakets erfordert weniger Zustand.
Nach dem Empfang eines Termination-Blocks mit dem Grund “Termination Received” kann die Sitzung die Schließungsphase verlassen.
Cleanup
Bei jeder normalen oder abnormalen Beendigung sollten Router alle im Speicher befindlichen ephemeren Daten überschreiben, einschließlich ephemerer Handshake-Schlüssel, symmetrischer Kryptoschlüssel und verwandter Informationen.
MTU
Die Anforderungen variieren je nachdem, ob die veröffentlichte Adresse mit SSU 1 geteilt wird. Das aktuelle SSU 1 IPv4-Minimum beträgt 620, was definitiv zu klein ist.
Die minimale SSU2 MTU beträgt 1280 sowohl für IPv4 als auch für IPv6, was der Spezifikation in RFC 9000 entspricht. Siehe unten. Durch die Erhöhung der minimalen MTU passen 1 KB tunnel-Nachrichten und kurze tunnel build-Nachrichten in ein Datagramm, was die typische Menge an Fragmentierung erheblich reduziert. Dies ermöglicht auch eine Erhöhung der maximalen I2NP-Nachrichtengröße. 1820-Byte-Streaming-Nachrichten sollten in zwei Datagramme passen.
Ein Router darf SSU2 nicht aktivieren oder eine SSU2-Adresse veröffentlichen, es sei denn, die MTU für diese Adresse beträgt mindestens 1280.
Router müssen eine von der Standardeinstellung abweichende MTU in jeder SSU- oder SSU2-Router-Adresse veröffentlichen.
Zusammenfassung
Geteilte Adresse mit SSU 1, muss SSU 1-Regeln befolgen. IPv4: Standard und Maximum ist 1484. Minimum ist 1292. (IPv4 MTU + 4) muss ein Vielfaches von 16 sein. IPv6: Muss veröffentlicht werden, Minimum ist 1280 und das Maximum ist 1488. IPv6 MTU muss ein Vielfaches von 16 sein.
Liefergarantien
IPv4: Standard und Maximum ist 1500. Minimum ist 1280. IPv6: Standard und Maximum ist 1500. Minimum ist 1280. Keine Vielfaches-von-16-Regeln, sollte aber wahrscheinlich mindestens ein Vielfaches von 2 sein.
Noise Protocol Framework
Für SSU 1 führt das aktuelle Java I2P PMTU-Erkennung durch, indem es mit kleinen Paketen beginnt und die Größe schrittweise erhöht, oder die Größe basierend auf der empfangenen Paketgröße steigert. Dies ist grob und reduziert die Effizienz erheblich. Die Fortsetzung dieser Funktion in SSU 2 ist noch zu entscheiden.
Aktuelle Studien PMTU legen nahe, dass ein Minimum von 1200 oder mehr für IPv4 für mehr als 99% der Verbindungen funktionieren würde. QUIC RFC 9000 erfordert eine minimale IP-Paketgröße von 1280 Bytes.
Zitat aus RFC 9000:
Die maximale Datagram-Größe ist definiert als die größte UDP-Payload-Größe, die über einen Netzwerkpfad mit einem einzigen UDP-Datagram gesendet werden kann. QUIC DARF NICHT verwendet werden, wenn der Netzwerkpfad keine maximale Datagram-Größe von mindestens 1200 Bytes unterstützen kann.
QUIC geht von einer minimalen IP-Paketgröße von mindestens 1280 Bytes aus. Dies ist die IPv6-Mindestgröße [IPv6] und wird auch von den meisten modernen IPv4-Netzwerken unterstützt. Unter der Annahme einer minimalen IP-Header-Größe von 40 Bytes für IPv6 und 20 Bytes für IPv4 sowie einer UDP-Header-Größe von 8 Bytes ergibt sich eine maximale Datagramm-Größe von 1232 Bytes für IPv6 und 1252 Bytes für IPv4. Daher wird erwartet, dass moderne IPv4- und alle IPv6-Netzwerkpfade QUIC unterstützen können.
Hinweis: Diese Anforderung zur Unterstützung einer UDP-Nutzlast von 1200 Bytes begrenzt den verfügbaren Platz für IPv6-Erweiterungsheader auf 32 Bytes oder IPv4-Optionen auf 52 Bytes, wenn der Pfad nur die IPv6-Mindest-MTU von 1280 Bytes unterstützt. Dies betrifft Initial-Pakete und die Pfadvalidierung.
Zitatende
Ergänzungen zum Framework
QUIC erfordert, dass Initial-Datagramme in beide Richtungen mindestens 1200 Bytes groß sind, um Verstärkungsangriffe zu verhindern und sicherzustellen, dass die PMTU dies in beide Richtungen unterstützt.
Wir könnten dies für Session Request und Session Created verlangen, was erhebliche Bandbreitenkosten verursachen würde. Möglicherweise könnten wir dies nur tun, wenn wir kein Token haben oder nachdem eine Retry-Nachricht empfangen wurde. TBD
QUIC erfordert, dass Bob nicht mehr als das Dreifache der empfangenen Datenmenge sendet, bis die Client-Adresse validiert ist. SSU2 erfüllt diese Anforderung von sich aus, da die Retry-Nachricht etwa die gleiche Größe wie die Token Request-Nachricht hat und kleiner als die Session Request-Nachricht ist. Außerdem wird die Retry-Nachricht nur einmal gesendet.
Schätzung des Verarbeitungsaufwands
QUIC erfordert, dass Nachrichten, die PATH_CHALLENGE- oder PATH_RESPONSE-Blöcke enthalten, mindestens 1200 Bytes groß sind, um Verstärkungsangriffe zu verhindern und sicherzustellen, dass die PMTU dies in beide Richtungen unterstützt.
Wir könnten dies ebenfalls verlangen, allerdings mit erheblichen Kosten bei der Bandbreite. Diese Fälle sollten jedoch selten auftreten. TBD
Max I2NP Message Size
IPv4: Es wird keine IP-Fragmentierung angenommen. IP + Datagramm-Header sind 28 Bytes. Dies geht davon aus, dass keine IPv4-Optionen vorhanden sind. Maximale Nachrichtengröße ist MTU - 28. Der Datenphasen-Header ist 16 Bytes und MAC ist 16 Bytes, insgesamt 32 Bytes. Payload-Größe ist MTU - 60. Maximale Datenphasen-Payload ist 1440 für eine maximale MTU von 1500. Maximale Datenphasen-Payload ist 1220 für eine minimale MTU von 1280.
IPv6: IP-Fragmentierung ist nicht erlaubt. IP + Datagramm-Header sind 48 Bytes. Dies setzt voraus, dass keine IPv6-Erweiterungs-Header vorhanden sind. Maximale Nachrichtengröße ist MTU - 48. Der Header der Datenphase ist 16 Bytes und der MAC ist 16 Bytes, insgesamt 32 Bytes. Die Payload-Größe ist MTU - 80. Maximale Datenphase-Payload ist 1420 für eine maximale MTU von 1500. Maximale Datenphase-Payload ist 1200 für eine minimale MTU von 1280.
In SSU 1 waren die Richtlinien eine strikte Obergrenze von etwa 32 KB für eine I2NP-Nachricht basierend auf maximal 64 Fragmenten und einer minimalen MTU von 620. Aufgrund des Overheads für gebündelte LeaseSets und Session-Keys lag die praktische Grenze auf Anwendungsebene etwa 6KB niedriger, also bei etwa 26KB. Das SSU 1 Protokoll erlaubt 128 Fragmente, aber aktuelle Implementierungen begrenzen es auf 64 Fragmente.
Durch die Erhöhung der minimalen MTU auf 1280, mit einer Datenphase-Nutzlast von etwa 1200, ist eine SSU 2-Nachricht von etwa 76 KB in 64 Fragmenten und 152 KB in 128 Fragmenten möglich. Dies ermöglicht problemlos ein Maximum von 64 KB.
Aufgrund der Fragmentierung in Tunneln und der Fragmentierung in SSU 2 steigt die Wahrscheinlichkeit von Nachrichtenverlusten exponentiell mit der Nachrichtengröße. Wir empfehlen weiterhin eine praktische Begrenzung von etwa 10 KB auf der Anwendungsschicht für I2NP-Datagramme.
Peer Test Process
Siehe Peer Test Sicherheit oben für eine Analyse des SSU1 Peer Test und die Ziele für SSU2 Peer Test.
Alice Bob Charlie
1. PeerTest ------------------->
Alice RI ------------------->
2. PeerTest ------------------->
3. <------------------ PeerTest
<---------------- Charlie RI
4. <------------------ PeerTest
5. <----------------------------------------- PeerTest
6. PeerTest ----------------------------------------->
7. <----------------------------------------- PeerTest
Wenn von Bob abgelehnt:
Alice Bob Charlie
1. PeerTest ------------------->
4. <------------------ PeerTest (reject)
Wenn von Charlie abgelehnt:
Alice Bob Charlie
1. PeerTest ------------------->
Alice RI ------------------->
2. PeerTest ------------------->
3. <------------------ PeerTest (reject)
(optional: Bob could try another Charlie here)
4. <------------------ PeerTest (reject)
HINWEIS: RI kann entweder als I2NP Database Store-Nachrichten in I2NP-Blöcken oder als RI-Blöcke (falls klein genug) gesendet werden. Diese können in denselben Paketen wie die Peer-Test-Blöcke enthalten sein, falls sie klein genug sind.
Nachrichten 1-4 sind in-session und verwenden Peer Test-Blöcke in einer Data-Nachricht. Nachrichten 5-7 sind out-of-session und verwenden Peer Test-Blöcke in einer Peer Test-Nachricht.
HINWEIS: Wie in SSU 1 können Nachrichten 4 und 5 in beliebiger Reihenfolge ankommen. Nachricht 5 und/oder 7 werden möglicherweise gar nicht empfangen, wenn Alice durch eine Firewall geschützt ist. Wenn Nachricht 5 vor Nachricht 4 ankommt, kann Alice nicht sofort Nachricht 6 senden, da sie noch nicht über Charlies intro key verfügt, um den Header zu verschlüsseln. Wenn Nachricht 4 vor Nachricht 5 ankommt, sollte Alice nicht sofort Nachricht 6 senden, da sie abwarten sollte, ob Nachricht 5 ankommt, ohne die Firewall mit Nachricht 6 zu öffnen.
| Message | Path | Intro Key |
|---|---|---|
| 1 | A->B session | in-session |
| 2 | B->C session | in-session |
| 3 | C->B session | in-session |
| 4 | B->A session | in-session |
| 5 | C->A | Alice |
| 6 | A->C | Charlie |
| 7 | C->A | Alice |
Versions
Cross-Version-Peer-Tests werden nicht unterstützt. Die einzige erlaubte Versionskombination ist, wenn alle Peers Version 2 verwenden.
| Alice/Bob | Bob/Charlie | Alice/Charlie | Supported |
|---|---|---|---|
| 1 | 1 | 1 | SSU 1 |
| 1 | 1 | 2 | no, use 1/1/1 |
| 1 | 2 | 1 | no, Bob must s |
| 1 | 2 | 2 | no, Bob must s |
| 2 | 1 | 1 | no, Bob must s |
| 2 | 1 | 2 | no, Bob must s |
| 2 | 2 | 1 | no, use 2/2/2 |
| 2 | 2 | 2 | yes |
Sitzungsaufbau
Nachrichten 1-4 sind in-session und werden von den ACK- und Retransmissionsprozessen der Datenphase abgedeckt. Peer Test-Blöcke erfordern eine Bestätigung.
Nachrichten 5-7 können unverändert erneut übertragen werden.
Paket-Header
Wie bei SSU 1 wird die Überprüfung von IPv6-Adressen unterstützt, und die Alice-Bob- sowie Alice-Charlie-Kommunikation kann über IPv6 erfolgen, wenn Bob und Charlie ihre Unterstützung durch eine ‘B’-Fähigkeit in ihrer veröffentlichten IPv6-Adresse anzeigen. Siehe Proposal 126 für Details.
Wie in SSU 1 vor 0.9.50 sendet Alice die Anfrage an Bob über eine bestehende Session über das Transport-Protokoll (IPv4 oder IPv6), das sie testen möchte. Wenn Bob eine Anfrage von Alice über IPv4 erhält, muss Bob einen Charlie auswählen, der eine IPv4-Adresse bewirbt. Wenn Bob eine Anfrage von Alice über IPv6 erhält, muss Bob einen Charlie auswählen, der eine IPv6-Adresse bewirbt. Die tatsächliche Bob-Charlie-Kommunikation kann über IPv4 oder IPv6 erfolgen (d.h. unabhängig von Alices Adresstyp). Dies ist NICHT das Verhalten von SSU 1 ab 0.9.50, wo gemischte IPv4/v6-Anfragen erlaubt sind.
Processing by Bob
Anders als in SSU 1 gibt Alice die angeforderte Test-IP und den Port in Nachricht 1 an. Bob sollte diese IP und den Port validieren und mit Code 5 ablehnen, falls sie ungültig sind. Die empfohlene IP-Validierung ist, dass bei IPv4 sie mit Alices IP übereinstimmt, und bei IPv6 mindestens die ersten 8 Bytes der IP übereinstimmen. Die Port-Validierung sollte privilegierte Ports und Ports für bekannte Protokolle ablehnen.
Relay Process
Siehe Relay-Sicherheit oben für eine Analyse des SSU1 Relay und die Ziele für SSU2 Relay.
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 ------------------------------------------>
Wenn von Bob abgelehnt:
Alice Bob Charlie
lookup Bob RI
SessionRequest -------------------->
<------------ SessionCreated
SessionConfirmed ----------------->
1. RelayRequest ---------------------->
4. <-------------- RelayResponse
Wenn von Charlie abgelehnt:
Alice Bob Charlie
lookup Bob RI
SessionRequest -------------------->
<------------ SessionCreated
SessionConfirmed ----------------->
1. RelayRequest ---------------------->
Alice RI ------------>
2. RelayIntro ----------->
3. <-------------- RelayResponse
4. <-------------- RelayResponse
HINWEIS: RI können entweder als I2NP Database Store Nachrichten in I2NP Blöcken oder als RI Blöcke (falls klein genug) gesendet werden. Diese können in den gleichen Paketen wie die Relay-Blöcke enthalten sein, falls sie klein genug sind.
In SSU 1 enthalten Charlies Router-Informationen die IP, den Port, den Intro-Schlüssel, das Relay-Tag und die Ablaufzeit jedes Introducers.
In SSU 2 enthält Charlies Router-Info den Router-Hash, Relay-Tag und das Ablaufdatum jedes Introducers.
Alice sollte die Anzahl der erforderlichen Round-Trips reduzieren, indem sie zuerst einen Introducer (Bob) auswählt, zu dem sie bereits eine Verbindung hat. Zweitens, falls keiner vorhanden ist, sollte sie einen Introducer auswählen, für den sie bereits die Router-Informationen besitzt.
Cross-Version-Relaying sollte ebenfalls unterstützt werden, wenn möglich. Dies wird einen schrittweisen Übergang von SSU 1 zu SSU 2 erleichtern. Die erlaubten Versionskombinationen sind (TODO):
| Alice/Bob | Bob/Charlie | Alice/Charlie | Supported |
|---|---|---|---|
| 1 | 1 | 1 | SSU 1 |
| 1 | 1 | 2 | no, use 1/1/1 |
| 1 | 2 | 1 | yes? |
| 1 | 2 | 2 | no, use 1/2/1 |
| 2 | 1 | 1 | yes? |
| 2 | 1 | 2 | yes? |
| 2 | 2 | 1 | no, use 2/2/2 |
| 2 | 2 | 2 | yes |
Retransmissions
Relay Request, Relay Intro und Relay Response sind alle in-session und werden von den ACK- und Wiederübertragungsprozessen der Datenphase abgedeckt. Relay Request, Relay Intro und Relay Response Blöcke lösen ACKs aus.
Hole Punch kann retransmittiert werden, wie in SSU 1.
IPv4/v6
Alle Funktionen des SSU 1 Relay werden unterstützt, einschließlich derer, die in Proposal 158 dokumentiert und ab Version 0.9.50 unterstützt werden. IPv4- und IPv6-Introductions werden unterstützt. Eine Relay Request kann über eine IPv4-Sitzung für eine IPv6-Introduction gesendet werden, und eine Relay Request kann über eine IPv6-Sitzung für eine IPv4-Introduction gesendet werden.
Processing by Alice
Es folgen Unterschiede zu SSU 1 und Empfehlungen für die SSU 2 Implementierung.
Notizen
In SSU 1 ist die Introduction relativ kostengünstig, und Alice sendet normalerweise Relay Requests an alle Introducer. In SSU 2 ist die Introduction aufwändiger, da zuerst eine Verbindung mit einem Introducer hergestellt werden muss. Um die Introduction-Latenz und den Overhead zu minimieren, werden folgende Verarbeitungsschritte empfohlen:
- Ignoriere alle Introducer, die basierend auf dem iexp-Wert in der Adresse abgelaufen sind
- Falls bereits eine SSU2-Verbindung zu einem oder mehreren Introducern besteht, wähle einen aus und sende die Relay Request nur an diesen Introducer.
- Andernfalls, falls eine Router Info für einen oder mehrere Introducer lokal bekannt ist, wähle einen aus und verbinde dich nur mit diesem Introducer.
- Andernfalls suche die Router Infos für alle Introducer auf, verbinde dich mit dem Introducer, dessen Router Info zuerst empfangen wird.
Anmerkungen
In sowohl SSU 1 als auch SSU 2 können die Relay Response und der Hole Punch in beliebiger Reihenfolge empfangen werden oder möglicherweise gar nicht empfangen werden.
In SSU 1 erhält Alice normalerweise die Relay Response (1 RTT) vor dem Hole Punch (1 1/2 RTT). Es mag in diesen Spezifikationen nicht gut dokumentiert sein, aber Alice muss die Relay Response von Bob erhalten, bevor sie fortfährt, um Charlies IP zu erhalten. Wenn der Hole Punch zuerst empfangen wird, wird Alice ihn nicht erkennen, da er keine Daten enthält und die Quell-IP nicht erkannt wird. Nach Erhalt der Relay Response sollte Alice warten, bis sie ENTWEDER den Hole Punch von Charlie erhält ODER eine kurze Verzögerung (empfohlen 500 ms) abwartet, bevor sie den Handshake mit Charlie initiiert.
In SSU 2 wird Alice normalerweise den Hole Punch (1 1/2 RTT) vor der Relay Response (2 RTT) erhalten. Der SSU 2 Hole Punch ist einfacher zu verarbeiten als in SSU 1, da es sich um eine vollständige Nachricht mit definierten Verbindungs-IDs (abgeleitet von der Relay-Nonce) und Inhalten einschließlich Charlies IP handelt. Die Relay Response (Data-Nachricht) und die Hole Punch-Nachricht enthalten den identischen signierten Relay Response-Block. Daher kann Alice den Handshake mit Charlie initiieren, nachdem sie ENTWEDER den Hole Punch von Charlie erhalten hat ODER die Relay Response von Bob erhalten hat.
Die Signaturverifikation des Hole Punch beinhaltet den router hash des Introducers (Bob). Wenn Relay Requests an mehr als einen Introducer gesendet wurden, gibt es mehrere Möglichkeiten, die Signatur zu validieren:
- Versuche jeden Hash, an den eine Anfrage gesendet wurde
- Verwende verschiedene Nonces für jeden Introducer und nutze dies, um zu bestimmen, welcher Introducer dieser Hole Punch als Antwort diente
- Validiere die Signatur nicht erneut, wenn der Inhalt identisch zu dem in der Relay Response ist, falls bereits empfangen
- Validiere die Signatur überhaupt nicht
Wenn Charlie sich hinter einem symmetrischen NAT befindet, ist sein gemeldeter Port in der Relay Response und Hole Punch möglicherweise nicht korrekt. Daher sollte Alice den UDP-Quellport der Hole Punch-Nachricht überprüfen und diesen verwenden, falls er sich von dem gemeldeten Port unterscheidet.
Tag Requests by Bob
In SSU 1 konnte nur Alice ein Tag anfordern, im Session Request. Bob konnte niemals ein Tag anfordern, und Alice konnte nicht für Bob weiterleiten.
In SSU2 fordert Alice im Allgemeinen ein Tag in der Session Request an, aber sowohl Alice als auch Bob können auch ein Tag in der Datenphase anfordern. Bob ist im Allgemeinen nicht durch eine Firewall blockiert, nachdem er eine eingehende Anfrage erhalten hat, aber es könnte nach einem Relay der Fall sein, oder Bobs Zustand könnte sich ändern, oder er könnte einen Introducer für den anderen Adresstyp (IPv4/v6) anfordern. Daher ist es in SSU2 möglich, dass sowohl Alice als auch Bob gleichzeitig Relays für die andere Partei sind.
Published Router Info
Address Properties
Die folgenden Adresseigenschaften können veröffentlicht werden, unverändert von SSU 1, einschließlich der Änderungen in Proposal 158, die ab API 0.9.50 unterstützt werden:
caps: [B,C,4,6] Fähigkeiten
host: IP (IPv4 oder IPv6). Verkürzte IPv6-Adresse (mit “::”) ist erlaubt. Kann vorhanden sein oder nicht, wenn eine Firewall aktiv ist. Hostnamen sind nicht erlaubt.
iexp[0-2]: Ablaufzeit dieses Introducers. ASCII-Ziffern, in Sekunden seit der Epoche. Nur vorhanden wenn firewalled, und Introducer erforderlich sind. Optional (auch wenn andere Eigenschaften für diesen Introducer vorhanden sind).
ihost[0-2]: IP-Adresse des Introducers (IPv4 oder IPv6). Verkürzte IPv6-Adresse (mit “::”) ist erlaubt. Nur vorhanden wenn firewalled, und Introducer erforderlich sind. Hostnamen sind nicht erlaubt. Nur SSU-Adresse.
ikey[0-2]: Base 64 Einführungsschlüssel des Introducers. Nur vorhanden wenn hinter einer Firewall und Introducer erforderlich sind. Nur für SSU-Adressen.
iport[0-2]: Port des Introducers 1024 - 65535. Nur vorhanden wenn firewalled, und Introducer erforderlich sind. Nur SSU-Adresse.
itag[0-2]: Introducer-Tag 1 - (2**32 - 1) ASCII-Ziffern. Nur vorhanden, wenn firewalled und Introducer erforderlich sind.
key: Base 64 Einführungsschlüssel.
mtu: Optional. Siehe MTU-Abschnitt oben.
port: 1024 - 65535 Kann vorhanden sein oder nicht, wenn eine Firewall aktiv ist.
Published Addresses
Die veröffentlichte RouterAddress (Teil der RouterInfo) wird eine Protokoll-Kennung von entweder “SSU” oder “SSU2” haben.
Die RouterAddress muss drei Optionen enthalten, um SSU2-Unterstützung anzuzeigen:
s=(Base64 key) Der aktuelle statische öffentliche Noise-Schlüssel (s) für diese RouterAddress. Base 64 kodiert unter Verwendung des Standard-I2P-Base-64-Alphabets. 32 Bytes in binärer Form, 44 Bytes als Base 64 kodiert, little-endian X25519 öffentlicher Schlüssel.
i=(Base64 key) Der aktuelle Einführungsschlüssel zur Verschlüsselung der Header für diese RouterAddress. Base 64 kodiert mit dem Standard-I2P Base 64 Alphabet. 32 Bytes im Binärformat, 44 Bytes als Base 64 kodiert, Big-Endian ChaCha20-Schlüssel.
v=2 Die aktuelle Version (2). Wenn als “SSU” veröffentlicht, ist zusätzliche Unterstützung für Version 1 impliziert. Unterstützung für zukünftige Versionen erfolgt mit kommagetrennten Werten, z.B. v=2,3 Die Implementierung sollte Kompatibilität prüfen, einschließlich mehrerer Versionen, wenn ein Komma vorhanden ist. Kommagetrennte Versionen müssen in numerischer Reihenfolge stehen.
Alice muss überprüfen, dass alle drei Optionen vorhanden und gültig sind, bevor sie eine Verbindung über das SSU2-Protokoll herstellt.
Wenn als “SSU” mit “s”, “i” und “v” Optionen veröffentlicht, und mit “host” und “port” Optionen, muss der router eingehende Verbindungen auf diesem Host und Port sowohl für SSU als auch SSU2 Protokolle akzeptieren und die Protokollversion automatisch erkennen.
Wenn als “SSU2” mit “s”, “i” und “v” Optionen veröffentlicht, und mit “host” und “port” Optionen, akzeptiert der Router eingehende Verbindungen auf diesem Host und Port nur für das SSU2 Protokoll.
Wenn ein Router sowohl SSU1- als auch SSU2-Verbindungen unterstützt, aber keine automatische Versionserkennung für eingehende Verbindungen implementiert, muss er sowohl “SSU”- als auch “SSU2”-Adressen bekanntgeben und die SSU2-Optionen nur in der “SSU2”-Adresse einschließen. Der Router sollte einen niedrigeren Kostenwert (höhere Priorität) in der “SSU2”-Adresse als in der “SSU”-Adresse setzen, damit SSU2 bevorzugt wird.
Wenn mehrere SSU2 RouterAddresses (entweder als “SSU” oder “SSU2”) in derselben RouterInfo veröffentlicht werden (für zusätzliche IP-Adressen oder Ports), müssen alle Adressen, die denselben Port spezifizieren, identische SSU2-Optionen und -Werte enthalten. Insbesondere müssen alle denselben statischen Schlüssel “s” und Einführungsschlüssel “i” enthalten.
Introducers
Wenn als SSU oder SSU2 mit Introducern veröffentlicht, sind die folgenden Optionen vorhanden:
ih[0-2]=(Base64 hash) Ein router hash für einen Introducer. Base 64 kodiert unter Verwendung des Standard-I2P Base 64 Alphabets. 32 Bytes binär, 44 Bytes als Base 64 kodiert
iexp[0-2]: Ablaufzeit dieses Introducers. Unverändert von SSU 1.
itag[0-2]: Introducer’s Tag 1 - (2**32 - 1) Unverändert gegenüber SSU 1.
Die folgenden Optionen gelten nur für SSU und werden nicht für SSU2 verwendet. In SSU2 erhält Alice diese Informationen stattdessen aus Charlies RI.
- ihost[0-2]
- ikey[0-2]
- itag[0-2]
Ein Router darf beim Veröffentlichen von Introducern keine Host- oder Port-Angaben in der Adresse publizieren. Ein Router muss beim Veröffentlichen von Introducern 4- und/oder 6-Caps in der Adresse publizieren, um die Unterstützung für IPv4 und/oder IPv6 anzuzeigen. Dies entspricht der aktuellen Praxis für aktuelle SSU 1-Adressen.
Hinweis: Falls als SSU veröffentlicht und es eine Mischung aus SSU 1 und SSU2 Introducern gibt, sollten die SSU 1 Introducer bei den niedrigeren Indizes und die SSU2 Introducer bei den höheren Indizes stehen, um Kompatibilität mit älteren Routern zu gewährleisten.
Unpublished SSU2 Address
Wenn Alice ihre SSU2-Adresse nicht (als “SSU” oder “SSU2”) für eingehende Verbindungen veröffentlicht, muss sie eine “SSU2”-Router-Adresse veröffentlichen, die nur ihren statischen Schlüssel und die SSU2-Version enthält, damit Bob den Schlüssel nach Erhalt von Alices RouterInfo in Session Confirmed Teil 2 validieren kann.
s=(Base64 key) Wie oben für veröffentlichte Adressen definiert.
i=(Base64 key) Wie oben für veröffentlichte Adressen definiert.
v=2 Wie oben für veröffentlichte Adressen definiert.
Diese Router-Adresse wird keine “host”- oder “port”-Optionen enthalten, da diese für ausgehende SSU2-Verbindungen nicht erforderlich sind. Die veröffentlichten Kosten für diese Adresse sind nicht strikt von Bedeutung, da sie nur für eingehende Verbindungen bestimmt ist; es kann jedoch für andere Router hilfreich sein, wenn die Kosten höher gesetzt werden (niedrigere Priorität) als bei anderen Adressen. Der vorgeschlagene Wert ist 14.
Alice kann auch einfach die Optionen “i”, “s” und “v” zu einer bereits veröffentlichten “SSU”-Adresse hinzufügen.
Paket-Integrität
Die Verwendung derselben statischen Schlüssel für NTCP2 und SSU2 ist erlaubt, aber nicht empfohlen.
Aufgrund der Zwischenspeicherung von RouterInfos dürfen Router den statischen öffentlichen Schlüssel oder IV nicht rotieren, während der Router läuft, unabhängig davon, ob er in einer veröffentlichten Adresse steht oder nicht. Router müssen diesen Schlüssel und IV dauerhaft speichern, um sie nach einem sofortigen Neustart wiederzuverwenden, damit eingehende Verbindungen weiterhin funktionieren und Neustartzeiten nicht preisgegeben werden. Router müssen die letzte Shutdown-Zeit dauerhaft speichern oder anderweitig bestimmen, damit die vorherige Downtime beim Start berechnet werden kann.
Unter Berücksichtigung von Bedenken bezüglich der Preisgabe von Neustartzeiten können Router diesen Schlüssel oder IV beim Start rotieren, wenn der Router zuvor für eine längere Zeit nicht aktiv war (mindestens mehrere Tage).
Wenn der Router veröffentlichte SSU2 RouterAddresses (als SSU oder SSU2) hat, sollte die minimale Ausfallzeit vor der Rotation viel länger sein, zum Beispiel ein Monat, es sei denn, die lokale IP-Adresse hat sich geändert oder der Router führt ein “rekeys” durch.
Wenn der Router veröffentlichte SSU RouterAddresses hat, aber nicht SSU2 (als SSU oder SSU2), sollte die minimale Ausfallzeit vor der Rotation länger sein, zum Beispiel ein Tag, es sei denn, die lokale IP-Adresse hat sich geändert oder der Router führt ein “rekeys” durch. Dies gilt auch, wenn die veröffentlichte SSU-Adresse introducers hat.
Wenn der router keine veröffentlichten RouterAddresses (SSU, SSU2 oder SSU) hat, kann die minimale Ausfallzeit vor der Rotation nur zwei Stunden betragen, auch wenn sich die IP-Adresse ändert, es sei denn, der router führt ein “rekeys” durch.
Wenn der Router einen “rekey” zu einem anderen Router Hash durchführt, sollte er auch einen neuen Noise-Schlüssel und Intro-Schlüssel generieren.
Implementierungen müssen sich bewusst sein, dass eine Änderung des statischen öffentlichen Schlüssels oder IV eingehende SSU2-Verbindungen von Routern verhindert, die eine ältere RouterInfo zwischengespeichert haben. RouterInfo-Veröffentlichung, Tunnel-Peer-Auswahl (einschließlich sowohl OBGW als auch IB nächstgelegener Hop), Zero-Hop-Tunnel-Auswahl, Transport-Auswahl und andere Implementierungsstrategien müssen dies berücksichtigen.
Die Rotation der Intro-Schlüssel unterliegt denselben Regeln wie die Schlüsselrotation.
Hinweis: Die minimale Ausfallzeit vor dem Rekeying kann angepasst werden, um die Netzwerkgesundheit zu gewährleisten und zu verhindern, dass ein router, der für eine moderate Zeit ausgefallen war, ein Reseeding durchführt.
Identity Hiding
Bestreitbarkeit ist kein Ziel. Siehe Übersicht oben.
Jedem Muster werden Eigenschaften zugewiesen, die die Vertraulichkeit beschreiben, die für den statischen öffentlichen Schlüssel des Initiators und für den statischen öffentlichen Schlüssel des Responders bereitgestellt wird. Die zugrunde liegenden Annahmen sind, dass ephemerale private Schlüssel sicher sind und dass die Parteien den Handshake abbrechen, wenn sie einen statischen öffentlichen Schlüssel von der anderen Partei erhalten, dem sie nicht vertrauen.
Dieser Abschnitt betrachtet nur die Preisgabe von Identitäten durch statische öffentliche Schlüsselfelder in Handshakes. Natürlich könnten die Identitäten der Noise-Teilnehmer auch durch andere Mittel preisgegeben werden, einschließlich Payload-Feldern, Traffic-Analyse oder Metadaten wie IP-Adressen.
Alice: (8) Verschlüsselt mit Forward Secrecy an eine authentifizierte Partei.
Bob: (3) Nicht übertragen, aber ein passiver Angreifer kann Kandidaten für den privaten Schlüssel des Responders prüfen und bestimmen, ob der Kandidat korrekt ist.
Bob veröffentlicht seinen statischen öffentlichen Schlüssel in der netDb. Alice muss das möglicherweise nicht tun, aber muss ihn in die RI einbeziehen, die an Bob gesendet wird.
Packet Guidelines
Authentifizierte Verschlüsselung
Handshake-Nachrichten (Session Request/Created/Confirmed, Retry) grundlegende Schritte, in der Reihenfolge:
- 16- oder 32-Byte-Header erstellen
- Payload erstellen
- mixHash() auf den Header anwenden (außer bei Retry)
- Payload mit Noise verschlüsseln (außer bei Retry, verwende ChaChaPoly mit dem Header als AD)
- Header verschlüsseln, und bei Session Request/Created den ephemeral key
Grundlegende Schritte für Data-Phase-Nachrichten, in der Reihenfolge:
- 16-Byte-Header erstellen
- Payload erstellen
- Payload mit ChaChaPoly verschlüsseln, wobei der Header als AD verwendet wird
- Header verschlüsseln
Inbound Packet Handling
Nutzlast
Erste Verarbeitung aller eingehenden Nachrichten:
- Die ersten 8 Bytes des Headers (die Destination Connection ID) mit dem Intro-Schlüssel entschlüsseln
- Die Verbindung anhand der Destination Connection ID nachschlagen
- Wenn die Verbindung gefunden wird und sich in der Datenphase befindet, zur Datenphase-Sektion gehen
- Wenn die Verbindung nicht gefunden wird, zur Handshake-Sektion gehen
- Hinweis: Peer Test und Hole Punch Nachrichten können ebenfalls anhand der Destination Connection ID nachgeschlagen werden, die aus der Test- oder Relay-Nonce erstellt wurde.
Handshake-Nachrichten (Session Request/Created/Confirmed, Retry, Token Request) und andere Nachrichten außerhalb der Sitzung (Peer Test, Hole Punch) Verarbeitung:
- Entschlüssele Bytes 8-15 des Headers (den Pakettyp, Version und Netz-ID) mit dem Intro-Schlüssel. Wenn es sich um eine gültige Session Request, Token Request, Peer Test oder Hole Punch handelt, fortfahren
- Wenn es sich nicht um eine gültige Nachricht handelt, suche eine ausstehende ausgehende Verbindung anhand der Paketquell-IP/Port, behandle das Paket als Session Created oder Retry. Entschlüssele die ersten 8 Bytes des Headers erneut mit dem korrekten Schlüssel, und die Bytes 8-15 des Headers (den Pakettyp, Version und Netz-ID). Wenn es sich um eine gültige Session Created oder Retry handelt, fortfahren
- Wenn es sich nicht um eine gültige Nachricht handelt, fehlschlagen oder als mögliches außer der Reihenfolge befindliches Datenphasen-Paket einreihen
- Für Session Request/Created, Retry, Token Request, Peer Test und Hole Punch, entschlüssele Bytes 16-31 des Headers
- Für Session Request/Created, entschlüssele den ephemeral key
- Validiere alle Header-Felder, stoppe wenn nicht gültig
- mixHash() den Header
- Für Session Request/Created/Confirmed, entschlüssele die Payload mit Noise
- Für Retry und Datenphase, entschlüssele die Payload mit ChaChaPoly
- Verarbeite den Header und die Payload
Verarbeitung von Data-Phase-Nachrichten:
- Entschlüssele die Bytes 8-15 des Headers (der Pakettyp, Version und Netz-ID) mit dem korrekten Schlüssel
- Entschlüssele die Payload mit ChaChaPoly unter Verwendung des Headers als AD
- Verarbeite den Header und die Payload
Details
In SSU 1 ist die Klassifizierung eingehender Pakete schwierig, da es keinen Header gibt, der die Sitzungsnummer anzeigt. Router müssen zunächst die Quell-IP und den Port mit einem bestehenden Peer-Zustand abgleichen, und falls nicht gefunden, mehrere Entschlüsselungen mit verschiedenen Schlüsseln versuchen, um den entsprechenden Peer-Zustand zu finden oder einen neuen zu starten. Falls sich die Quell-IP oder der Port für eine bestehende Sitzung ändert, möglicherweise aufgrund von NAT-Verhalten, kann der Router teure Heuristiken verwenden, um zu versuchen, das Paket einer bestehenden Sitzung zuzuordnen und den Inhalt wiederherzustellen.
SSU 2 ist darauf ausgelegt, den Aufwand für die eingehende Paketklassifizierung zu minimieren, während gleichzeitig DPI-Resistenz und andere Bedrohungen auf dem Übertragungsweg aufrechterhalten werden. Die Connection ID-Nummer ist im Header für alle Nachrichtentypen enthalten und wird mit ChaCha20 unter Verwendung eines bekannten Schlüssels und einer bekannten Nonce verschlüsselt (verschleiert). Zusätzlich ist auch der Nachrichtentyp im Header enthalten (verschlüsselt mit Header-Schutz zu einem bekannten Schlüssel und dann mit ChaCha20 verschleiert) und kann für zusätzliche Klassifizierung verwendet werden. In keinem Fall ist eine Test-DH oder andere asymmetrische Krypto-Operation zur Klassifizierung eines Pakets erforderlich.
Für fast alle Nachrichten von allen Peers ist der ChaCha20-Schlüssel für die Connection ID-Verschlüsselung der introduction key des Ziel-routers, wie er in der netDb veröffentlicht ist.
Die einzigen Ausnahmen sind die ersten Nachrichten, die von Bob an Alice gesendet werden (Session Created oder Retry), bei denen Bobs introduction key Alice noch nicht bekannt ist. In diesen Fällen wird Bobs introduction key als Schlüssel verwendet.
Das Protokoll ist darauf ausgelegt, die Paketklassifizierungsverarbeitung zu minimieren, die zusätzliche Krypto-Operationen in mehreren Fallback-Schritten oder komplexe Heuristiken erfordern könnte. Zusätzlich wird die überwiegende Mehrheit der empfangenen Pakete keine (möglicherweise aufwändige) Fallback-Suche nach Quell-IP/Port und eine zweite Header-Entschlüsselung erfordern. Nur Session Created und Retry (und möglicherweise andere noch zu bestimmende) werden die Fallback-Verarbeitung erfordern. Wenn ein Endpunkt nach der Session-Erstellung die IP oder den Port ändert, wird die Verbindungs-ID weiterhin verwendet, um die Session zu finden. Es ist niemals notwendig, Heuristiken zu verwenden, um die Session zu finden, beispielsweise durch Suche nach einer anderen Session mit der gleichen IP aber einem anderen Port.
Daher sind die empfohlenen Verarbeitungsschritte in der Empfänger-Loop-Logik:
- Entschlüssele die ersten 8 Bytes mit ChaCha20 unter Verwendung des lokalen introduction key, um die Destination Connection ID wiederherzustellen. Falls die Connection ID mit einer aktuellen oder ausstehenden eingehenden Session übereinstimmt:
a) Mit dem entsprechenden Schlüssel die Header-Bytes 8-15 entschlüsseln
to recover the version, net ID, and message type.
b) Wenn der Nachrichtentyp Session Confirmed ist, handelt es sich um einen langen Header.
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) Wenn der Nachrichtentyp gültig ist, aber nicht 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) (optional) Falls die Verbindungs-ID eine ausstehende eingehende Sitzung ist
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) Falls b) oder c) fehlschlägt, die Nachricht verwerfen.
- Wenn die Verbindungs-ID nicht mit einer aktuellen Session übereinstimmt: Prüfen Sie, ob der Klartext-Header bei den Bytes 8-15 gültig ist (ohne eine Header-Schutz-Operation durchzuführen). Verifizieren Sie, dass die Netz-ID und Protokollversion gültig sind, und der Nachrichtentyp Session Request ist, oder ein anderer Nachrichtentyp der außerhalb einer Session erlaubt ist (TBD).
a) Wenn alles gültig ist und der Nachrichtentyp Session Request ist,
decrypt bytes 16-31 of the header and the 32-byte X value
with ChaCha20 using the local intro key.
- Wenn der Token in den Header-Bytes 24-31 akzeptiert wird,
dann MixHash() den entschlüsselten 32-Byte-Header und
entschlüssele die Nachricht mit Noise.
Sende eine Session Created als Antwort.
- Wenn der Token nicht akzeptiert wird, sende eine Retry-Nachricht an die
Quell-IP/Port mit einem Token. Versuche nicht,
die Nachricht mit Noise zu entschlüsseln, um DDoS-Angriffe zu vermeiden.
b) Wenn der Nachrichtentyp eine andere gültige Nachricht ist
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) Falls a) oder b) fehlschlägt, gehe zu Schritt 3)
- Suche eine ausstehende ausgehende Sitzung anhand der Quell-IP/Port des Pakets.
a) Falls gefunden, die ersten 8 Bytes erneut mit ChaCha20 unter Verwendung von Bobs introduction key entschlüsseln
to recover the Destination Connection ID.
b) Falls die Verbindungs-ID mit der ausstehenden Sitzung übereinstimmt:
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).
Wenn alles gültig ist und der Nachrichtentyp Session Created ist, entschlüssele die nächsten 16 Bytes des Headers und den 32-Byte Y-Wert mit ChaCha20 unter Verwendung von Bobs intro key. Dann MixHash() den entschlüsselten 32-Byte Header und entschlüssele die Nachricht mit Noise. Sende eine Session Confirmed als Antwort.
- Wenn alles gültig ist und der Nachrichtentyp Retry ist, entschlüssele Bytes 16-31 des Headers mit ChaCha20 unter Verwendung von Bobs intro key. Entschlüssele und validiere die Nachricht mit ChaCha20/Poly1305 unter Verwendung von TBD als Schlüssel und TBD als Nonce und dem entschlüsselten 32-Byte Header als AD. Sende erneut eine Session Request mit dem erhaltenen Token als Antwort.
- Wenn der Nachrichtentyp eine andere Nachricht ist, die gültig außerhalb einer Session ist, vermutlich mit einem kurzen Header, entschlüssele den Rest der Nachricht mit ChaCha20/Poly1305 unter Verwendung des intro key und unter Verwendung des entschlüsselten 16-Byte Headers als AD. Verarbeite die Nachricht.
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.
- Falls SSU 1 auf dem gleichen Port läuft, versuche die Nachricht als SSU 1-Paket zu verarbeiten.
Error Handling
Im Allgemeinen sollte eine Session (in der Handshake- oder Datenphase) niemals zerstört werden, nachdem ein Paket mit einem unerwarteten Nachrichtentyp empfangen wurde. Dies verhindert Paket-Injection-Angriffe. Diese Pakete werden auch häufig nach der Neuübertragung eines Handshake-Pakets empfangen, wenn die Header-Entschlüsselungsschlüssel nicht mehr gültig sind.
In den meisten Fällen wird das Paket einfach verworfen. Eine Implementierung kann, ist aber nicht verpflichtet, das zuvor gesendete Paket (Handshake-Nachricht oder ACK 0) als Antwort erneut zu übertragen.
Nach dem Senden von Session Created als Bob sind unerwartete Pakete häufig Data-Pakete, die nicht entschlüsselt werden können, weil die Session Confirmed-Pakete verloren gegangen oder außer der Reihenfolge angekommen sind. Reihen Sie die Pakete in die Warteschlange ein und versuchen Sie, sie nach dem Empfang der Session Confirmed-Pakete zu entschlüsseln.
Nachdem Session Confirmed als Bob empfangen wurde, sind unerwartete Pakete häufig erneut übertragene Session Confirmed-Pakete, da das ACK 0 des Session Confirmed verloren ging. Die unerwarteten Pakete können verworfen werden. Eine Implementierung kann, ist aber nicht verpflichtet, ein Data-Paket mit einem ACK-Block als Antwort zu senden.
Notes
Für Session Created und Session Confirmed müssen Implementierungen alle entschlüsselten Header-Felder (Connection IDs, Paketnummer, Pakettyp, Version, ID, Frag und Flags) sorgfältig validieren, BEVOR sie mixHash() auf den Header anwenden und versuchen, die Payload mit Noise AEAD zu entschlüsseln. Wenn die Noise AEAD-Entschlüsselung fehlschlägt, darf keine weitere Verarbeitung erfolgen, da mixHash() den Handshake-Zustand korrumpiert haben wird, es sei denn, eine Implementierung speichert den Hash-Zustand und macht ihn rückgängig.
Version Detection
Es ist möglicherweise nicht effizient möglich zu erkennen, ob eingehende Pakete Version 1 oder 2 am selben eingehenden Port sind. Die oben genannten Schritte könnten sinnvoll vor der SSU 1-Verarbeitung durchgeführt werden, um zu vermeiden, dass DH-Operationen mit beiden Protokollversionen versucht werden.
Noch zu bestimmen, falls erforderlich.
Recommended Constants
- Outbound Handshake-Wiederübertragungstimeout: 1,25 Sekunden, mit exponentieller Verzögerung (Wiederübertragungen bei 1,25, 3,75 und 8,75 Sekunden)
- Gesamter Outbound Handshake-Timeout: 15 Sekunden
- Inbound Handshake-Wiederübertragungstimeout: 1 Sekunde, mit exponentieller Verzögerung (Wiederübertragungen bei 1, 3 und 7 Sekunden)
- Gesamter Inbound Handshake-Timeout: 12 Sekunden
- Timeout nach Senden eines Wiederholungsversuchs: 9 Sekunden
- ACK-Verzögerung: max(10, min(rtt/6, 150)) ms
- Sofortige ACK-Verzögerung: min(rtt/16, 5) ms
- Max ACK-Bereiche: 256?
- Max ACK-Tiefe: 512?
- Padding-Verteilung: 0-15 Bytes oder mehr
Variants, Fallbacks, and General Issues
TBD
Packet Overhead Analysis
Geht von IPv4 aus, ohne zusätzliche Auffüllung, ohne IP- und UDP-Header-Größen. Auffüllung ist Mod-16-Auffüllung nur für SSU 1.
SSU 1
| Message | Header+MAC | Keys | Data | Padding | Total | Notes |
|---|---|---|---|---|---|---|
| Session Request | 40 | 256 | 5 | 3 | 304 | Incl. |
| Session Created | 37 | 256 | 79 | 1 | 336 | Incl. |
| Session Confirmed | 37 | 462 | 13 | 512 | Incl. | |
| Data (RI) | 37 | 1014 | 1051 | Incl. | ||
| Data (1 full msg) | 37 | 14 | 51 | Incl. | ||
| Total | 2254 | |||||
| SSU 2 |
| Message | Header+MACs | Keys | Data | Padding | Total | Notes |
|---|---|---|---|---|---|---|
| Session Request | 48 | 32 | 7 | 87 | DateTi | |
| Session Created | 48 | 32 | 16 | 96 | DateTi | |
| Session Confirmed | 48 | 32 | 1005 | 1085 | 1000 b | |
| Data (1 full msg) | 32 | 14 | 46 | |||
| Total | 1314 | |||||
| TODO FALLS nicht die minimale Paketgröße in Session Request und Created für PMTU durchgesetzt wird. |