상태
배포 계획:
| 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 |
| 기본 세션에는 핸드셰이크와 데이터 단계가 포함됩니다. 확장 프로토콜에는 릴레이와 피어 테스트가 포함됩니다. |
개요
이 제안서는 다양한 형태의 자동화된 식별 및 공격에 대한 SSU의 저항성을 향상시키기 위한 인증된 키 합의 프로토콜을 설명합니다.
제안서는 다음과 같이 구성됩니다: 보안 목표가 제시되고, 기본 프로토콜에 대한 논의가 이어집니다. 다음으로, 모든 프로토콜 메시지의 완전한 명세가 제공됩니다. 마지막으로, router 주소와 버전 식별에 대해 논의됩니다.
다른 I2P 전송 방식과 마찬가지로, SSU2는 I2NP 메시지의 지점 간(router-to-router) 전송을 위해 정의됩니다. 범용 데이터 파이프가 아닙니다. SSU와 같이, NAT 통과를 위한 Relaying과 인바운드 도달 가능성 확인을 위한 Peer Testing이라는 두 가지 추가 서비스를 제공합니다. 또한 피어가 IP 또는 포트를 변경할 때 연결 마이그레이션을 위한 세 번째 서비스도 제공하는데, 이는 SSU에는 없는 기능입니다.
동기
SSU는 매우 느린 ElGamal을 필요로 하는 유일한 남은 프로토콜 계층입니다. SSU의 플로우 제어는 복잡하고 제대로 작동하지 않습니다. SSU의 일부분은 주소 스푸핑 공격에 취약합니다. 핸드셰이크에서 Noise를 사용하지 않습니다.
설계 목표
ElGamal을 제거하여 CPU 사용량 감소. DH에는 X25519 사용.
Peer Test와 Relay 기능을 유지하고, 이들의 보안을 강화합니다.
표준 플로우 제어 알고리즘을 허용하여 구현을 더 쉽게 만듭니다.
설정 지연 시간을 줄입니다. 현재 중앙값 설정 시간은 NTCP2의 경우 약 135ms, SSU의 경우 187ms입니다. NTCP2가 추가 라운드 트립을 가지고 있음에도 불구하고 이러한 결과를 보입니다. SSU2에서 ElGamal을 대체하면 이를 줄일 수 있지만, 다른 변경 사항들도 도움이 될 수 있습니다.
테스트넷에서 시뮬레이션된 다양한 지연시간과 패킷 손실률 범위에 걸쳐 측정한 결과, SSU 1과 비교하여 최대 처리량을 유지하거나 증가시킨다.
스푸핑된 소스 주소로부터 “주소 검증"을 통해 트래픽 증폭 및 잘못된 라우팅 공격을 방지
패킷 식별을 더 쉽게 만들어 코드를 지나치게 복잡하게 만드는 fallback과 휴리스틱에 대한 의존성을 줄입니다.
피어의 IP 또는 포트가 변경될 때 연결 마이그레이션을 공식화하고 개선합니다. 공격을 방지하기 위해 주소 검증이 완료될 때까지 연결을 마이그레이션하지 않습니다. 일부 SSU 1 구현체는 NAT 리바인딩으로 인한 포트 변경을 처리하기 위해 비용이 많이 드는 휴리스틱을 사용합니다. 알려진 SSU 1 구현체 중에는 IP 변경을 전혀 처리할 수 없는 것들이 있습니다.
단일 포트에서 SSU 1과 2를 지원하고, 자동 감지하며, NetDB에서 단일 “transport” (즉, RouterAddress)로 게시됩니다.
NetDB에서 별도 필드에 버전 1만, 버전 2만, 또는 1+2 지원을 게시하고, 기본값을 버전 1만으로 설정 (버전 지원을 특정 router 버전에 바인딩하지 않음)
모든 구현체(Java/i2pd/Go)가 각자의 일정에 따라 버전 2 지원을 추가할 수 있도록(또는 추가하지 않도록) 보장
핸드셰이크 및 데이터 메시지를 포함한 모든 메시지에 무작위 패딩을 추가합니다. 모든 패딩은 SSU 1의 패킷 끝 패딩과 달리 MAC으로 보호되어야 합니다. 양쪽에서 최소 및 최대 패딩 그리고/또는 패딩 분포를 요청할 수 있는 옵션 메커니즘을 제공합니다. 패딩 분포의 세부 사항은 구현에 따라 다르며 프로토콜 자체에서 지정될 수도 있고 그렇지 않을 수도 있습니다.
완전히 암호화되지 않은 메시지의 헤더와 내용을 DPI 박스와 AV 시그니처가 쉽게 분류할 수 없을 정도로 충분히 난독화합니다. 또한 단일 피어 또는 피어 세트로 전송되는 메시지가 유사한 비트 패턴을 갖지 않도록 보장합니다.
Java 형식으로 인한 DH의 비트 손실 수정 Ticket1112, 그리고 X25519로 전환하여 DH 속도 향상.
DH 결과를 그대로 사용하지 않고 실제 키 유도 함수(KDF)로 전환
“probing resistance” (Tor에서 부르는 용어) 추가; 여기에는 replay resistance가 포함됨.
2방향 인증 키 교환(2W-AKE)을 유지합니다. 1W-AKE는 우리 애플리케이션에 충분하지 않습니다.
RouterInfo에 게시된 정적 공개 키를 인증의 또 다른 부분으로 의존합니다.
향후 확장성을 위해 핸드셰이크에 옵션/버전을 추가합니다.
연결 설정에 필요한 CPU를 크게 증가시키지 말고, 가능하다면 크게 줄여야 함.
SSU 1의 AES 암호화에서 요구되던 16바이트 배수로의 패딩 요구사항 제거
암호화 및 MAC에 표준 ChaCha/Poly1305를 사용하여, SSU 1에서 사용된 AES 암호화 및 비표준 HMAC-MD5-128 MAC을 대체합니다.
송신과 수신에 각각 별도의 암호화 키를 사용하며, SSU 1에서 사용하던 양방향 공통 키 방식 대신 이를 적용합니다.
NTCP2에서와 같이 3-메시지, 1-라운드트립 핸드셰이크를 사용합니다. SSU를 사실상 2-라운드트립 핸드셰이크로 만드는 데이터 메시지 대기 지연을 제거합니다.
SSU 1에서 끔찍했던 ACK와 NACK의 효율성을 극적으로 개선합니다. ACK와 NACK에 필요한 대역폭을 줄이고, 데이터에 사용할 수 있는 패킷 크기를 증가시킵니다. WiFi에서 흔히 발생하는 연속된 누락 메시지에 대한 NACK를 효율적으로 인코딩합니다.
I2NP 메시지 분할 구현에 필요한 복잡성을 줄입니다. 완전한 I2NP 메시지에 대한 분할 메커니즘과 인코딩을 우회합니다.
패딩 전에 프로토콜 오버헤드를 최소화하십시오. 특히 ACK의 경우. 패딩이 추가되더라도, 패딩 전 오버헤드는 여전히 오버헤드입니다. 낮은 대역폭 노드들이 SSU2를 사용할 수 있어야 합니다.
재생 공격 및 시간 편차 탐지를 위한 타임스탬프를 유지합니다.
타임스탬프에서 2038년 문제를 방지하고, 최소 2106년까지 작동해야 함.
효율성, 구현 용이성, 최대 I2NP 메시지 크기 증가를 위해 최소 MTU를 620에서 1280으로 증가합니다. 분할과 재조립은 매우 비용이 많이 듭니다. 1028 바이트 터널 메시지를 위한 공간을 제공함으로써, 대부분의 I2NP 메시지는 분할이 필요하지 않게 됩니다.
효율성을 위해 최대 MTU를 1488(IPv6의 경우 1484)에서 1500으로 증가. MTU가 16의 배수여야 한다는 요구사항 제거.
SSU 1에서 약 32K였던 최대 I2NP 메시지 크기를 NTCP2에서와 같이 약 64 KB로 증가시킵니다.
핸드셰이크에서 IP와 포트 필드의 서명을 제거하여, 외부 IP와 포트를 모르는 router들도 연결할 수 있도록 합니다.
핸드셰이크에서 SSU 1의 IP/포트 발견 메커니즘을 유지하여, 라우터들이 자신의 외부 IP와 포트를 학습할 수 있도록 합니다.
설계에 Java, C++, Go router 개발자 대표들을 포함한다.
Non-Goals
완벽한 DPI 저항성… 이는 플러그 가능한 전송 방식이 될 것입니다, Proposal 109.
TLS 기반 (또는 HTTPS 유사) 전송… 이것은 Proposal 104입니다.
타이밍 기반 DPI 저항성 (메시지 간 타이밍/지연은 구현에 따라 달라질 수 있으며, 메시지 내 지연은 예를 들어 랜덤 패딩을 전송하기 전을 포함하여 어느 지점에서든 도입될 수 있습니다). 인위적 지연 (obfs4에서 IAT 또는 inter-arrival time이라고 부르는 것)은 프로토콜 자체와는 독립적입니다.
세션 참여에 대한 부인 가능성 (서명이 포함되어 있음).
부분적으로 재검토되거나 논의될 수 있는 비목표들:
Deep Packet Inspection (DPI)에 대한 보호 수준
Post-Quantum (PQ) 보안
부인 가능성
Security Goals
우리는 세 당사자를 고려합니다:
- 새로운 세션을 설정하고자 하는 Alice
- Alice가 세션을 설정하고자 하는 대상인 Bob
- Alice와 Bob 사이의 “중간자(man in the middle)“인 Mallory
최대 두 명의 참가자가 능동적 공격에 참여할 수 있습니다.
Alice와 Bob은 모두 정적 키 쌍을 소유하고 있으며, 이는 그들의 RouterIdentity에 포함되어 있습니다.
제안된 프로토콜은 다음 요구사항에 따라 Alice와 Bob이 공유 비밀 키(K)에 합의할 수 있도록 시도합니다:
개인키 보안: Bob이나 Mallory 모두 Alice의 정적 개인키에 대해 아무것도 알 수 없습니다. 마찬가지로 Alice도 Bob의 정적 개인키에 대해 아무것도 알 수 없습니다.
세션 키 K는 Alice와 Bob만 알고 있습니다.
완전 순방향 비밀성(Perfect forward secrecy): 합의된 세션 키는 키가 합의된 후 Alice와/또는 Bob의 정적 개인 키가 노출되더라도 미래에도 비밀로 유지됩니다.
양방향 인증: Alice는 Bob과 세션을 설정했다는 것을 확신하고, Bob도 마찬가지입니다.
온라인 DPI에 대한 보호: 단순한 deep packet inspection(DPI) 기법만으로는 Alice와 Bob이 해당 프로토콜에 참여하고 있다는 것을 감지하는 것이 쉽지 않도록 보장합니다. 아래를 참조하세요.
제한적 부인방지: Alice와 Bob 모두 프로토콜 참여를 부인할 수 없지만, 둘 중 누구든 공유 키를 유출하면 상대방은 전송된 데이터 내용의 진위성을 부인할 수 있다.
현재 제안은 Station-To-Station (STS) 프로토콜을 기반으로 다섯 가지 요구사항을 모두 제공하려고 시도합니다. 이 프로토콜은 SSU 프로토콜의 기반이기도 합니다.
Additional DPI Discussion
우리는 두 개의 DPI 구성 요소를 가정합니다:
Online DPI
실시간으로 모든 플로우를 검사하는 온라인 DPI. 연결이 차단되거나 다른 방식으로 조작될 수 있습니다. 연결 데이터나 메타데이터가 식별되어 오프라인 분석을 위해 저장될 수 있습니다. 온라인 DPI는 I2P 네트워크 데이터베이스에 접근할 수 없습니다. 온라인 DPI는 길이 계산, 필드 검사, XOR과 같은 간단한 계산을 포함하여 제한적인 실시간 연산 능력만을 가지고 있습니다. 온라인 DPI는 ChaCha20, AEAD, 해싱과 같은 빠른 실시간 암호화 기능을 수행할 수 있지만, 대부분 또는 모든 플로우에 적용하기에는 너무 비용이 많이 듭니다. 이러한 암호화 작업의 적용은 오프라인 분석에 의해 사전에 식별된 IP/포트 조합의 플로우에만 적용됩니다. 온라인 DPI는 DH나 elligator2와 같은 높은 오버헤드의 암호화 기능을 수행할 능력이 없습니다. 온라인 DPI는 I2P를 탐지하기 위해 특별히 설계되지 않았지만, 해당 목적을 위한 제한적인 분류 규칙을 가지고 있을 수 있습니다.
온라인 DPI에 의한 프로토콜 식별을 방지하는 것이 목표입니다.
온라인 또는 “직접적인” DPI의 개념은 여기서 다음과 같은 적대자 능력을 포함하는 것으로 간주됩니다:
대상이 송신하거나 수신하는 모든 데이터를 검사할 수 있는 능력.
블록 암호나 해시 함수 적용과 같이 관찰된 데이터에 대한 연산을 수행할 수 있는 능력.
이전에 전송된 메시지를 저장하고 비교할 수 있는 기능.
패킷을 수정, 지연 또는 분할할 수 있는 능력.
그러나 온라인 DPI는 다음과 같은 제약 사항을 가지고 있다고 가정합니다:
IP 주소를 router 해시에 매핑할 수 없다는 점. 이는 네트워크 데이터베이스에 실시간 접근이 있다면 간단하지만, I2P를 특별히 표적으로 하도록 설계된 DPI 시스템이 필요할 것이다.
프로토콜을 탐지하기 위해 타이밍 정보를 사용할 수 없음.
일반적으로, 온라인 DPI 도구상자는 I2P 탐지를 위해 특별히 설계된 내장 도구를 포함하지 않습니다. 여기에는 예를 들어 메시지에 비무작위 패딩을 포함하는 “honeypot” 생성도 포함됩니다. 이것이 다른 요구 사항을 충족하는 한 머신 러닝 시스템이나 고도로 구성 가능한 DPI 도구를 배제하지는 않는다는 점을 참고하세요.
페이로드 분석에 대응하기 위해 모든 메시지가 랜덤과 구별할 수 없도록 보장합니다. 이는 또한 메시지의 길이가 랜덤이어야 함을 요구하는데, 이는 단순히 랜덤 패딩을 추가하는 것보다 더 복잡합니다. 실제로 부록 A에서 저자들은 단순한(즉, 균등한) 패딩 방식으로는 문제가 해결되지 않는다고 주장합니다. 따라서 부록 A는 랜덤 지연을 포함하거나 제안된 공격에 대해 합리적인 보호를 제공할 수 있는 대안적인 패딩 방식을 개발할 것을 제안합니다.
위의 여섯 번째 항목으로부터 보호하기 위해, 구현체들은 프로토콜에 랜덤 지연을 포함해야 합니다. 이러한 기법들은 본 제안서에서 다루지 않지만, 패딩 길이 문제들도 해결할 수 있습니다. 요약하면, 이 제안서는 페이로드 분석에 대한 양호한 보호를 제공하지만 (부록 A의 고려사항들을 감안할 때), 플로우 분석에 대해서는 제한적인 보호만을 제공합니다.
Offline DPI
온라인 DPI가 저장한 데이터를 나중에 분석하기 위해 검사하는 오프라인 DPI. 오프라인 DPI는 I2P를 탐지하도록 특별히 설계될 수 있습니다. 오프라인 DPI는 I2P 네트워크 데이터베이스에 실시간으로 접근할 수 없습니다. 오프라인 DPI는 이 문서와 다른 I2P 사양들에 접근할 수 있습니다. 오프라인 DPI는 이 사양에서 정의된 모든 암호화 함수를 포함하여 무제한의 계산 능력을 가지고 있습니다.
오프라인 DPI는 기존 연결을 차단할 수 있는 능력이 없습니다. 오프라인 DPI는 패킷 주입을 통해 거의 실시간으로 (설정 후 몇 분 이내에) 대상의 호스트/포트로 전송할 수 있는 기능을 가지고 있습니다. 오프라인 DPI는 “탐지” 또는 기타 목적으로 거의 실시간으로 (설정 후 몇 분 이내에) 이전 메시지를 (수정 여부에 관계없이) 재전송할 수 있는 기능을 가지고 있습니다.
오프라인 DPI에 의한 프로토콜 식별을 방지하는 것은 목표가 아닙니다. I2P router에 의해 구현되는 처음 두 메시지의 모든 난독화된 데이터 디코딩은 오프라인 DPI에 의해서도 구현될 수 있습니다.
이전 메시지의 재전송을 사용한 연결 시도를 거부하는 것이 목표입니다.
Address Validation
다음은 QUIC RFC 9000에서 복사한 내용입니다. 각 섹션을 검토하고 편집하세요.
주소 검증은 엔드포인트가 트래픽 증폭 공격에 사용되지 않도록 보장합니다. 이러한 공격에서는 피해자를 식별하는 위조된 소스 주소 정보가 포함된 패킷이 서버로 전송됩니다. 서버가 해당 패킷에 대한 응답으로 더 많거나 더 큰 패킷을 생성하는 경우, 공격자는 서버를 이용하여 자신이 직접 보낼 수 있는 양보다 더 많은 데이터를 피해자에게 전송할 수 있습니다.
증폭 공격에 대한 주된 방어책은 피어가 자신이 주장하는 전송 주소에서 패킷을 수신할 수 있는지 확인하는 것입니다. 따라서 아직 검증되지 않은 주소로부터 패킷을 수신한 후, 엔드포인트는 검증되지 않은 주소로 보내는 데이터의 양을 해당 주소로부터 수신한 데이터 양의 3배로 제한해야 합니다. 이러한 응답 크기 제한을 증폭 방지 제한(anti-amplification limit)이라고 합니다.
주소 검증은 연결 설정 중(섹션 8.1 참조)과 연결 마이그레이션 중(섹션 8.2 참조) 모두에서 수행됩니다.
Address Validation during Connection Establishment
연결 설정은 양쪽 엔드포인트에 대해 암시적으로 주소 검증을 제공합니다. 특히, Handshake 키로 보호된 패킷의 수신은 피어가 Initial 패킷을 성공적으로 처리했음을 확인해 줍니다. 엔드포인트가 피어로부터 Handshake 패킷을 성공적으로 처리하면, 피어 주소가 검증되었다고 간주할 수 있습니다.
추가로, endpoint는 상대방이 endpoint에서 선택한 connection ID를 사용하고 해당 connection ID에 최소 64비트의 엔트로피가 포함되어 있는 경우 상대방 주소를 검증된 것으로 간주할 수 있습니다(MAY).
클라이언트의 경우, 첫 번째 Initial 패킷의 Destination Connection ID 필드 값을 통해 패킷을 성공적으로 처리하는 과정의 일부로 서버 주소를 검증할 수 있습니다. 서버로부터의 Initial 패킷들은 이 값으로부터 파생된 키로 보호됩니다(QUIC-TLS의 섹션 5.2 참조). 또는, 이 값은 Version Negotiation 패킷(섹션 6)에서 서버에 의해 에코되거나 Retry 패킷의 Integrity Tag에 포함됩니다(QUIC-TLS의 섹션 5.8).
클라이언트 주소를 검증하기 전에, 서버는 수신한 바이트 수의 3배를 초과하는 바이트를 전송해서는 안 됩니다(MUST NOT). 이는 스푸핑된 소스 주소를 사용하여 수행할 수 있는 증폭 공격의 규모를 제한합니다. 주소 검증 이전의 증폭을 방지하기 위해, 서버는 단일 연결에 고유하게 귀속되는 데이터그램에서 수신된 모든 페이로드 바이트를 계산해야 합니다(MUST). 여기에는 성공적으로 처리된 패킷이 포함된 데이터그램과 모든 패킷이 폐기된 데이터그램이 포함됩니다.
클라이언트는 Initial 패킷을 포함하는 UDP 데이터그램이 최소 1200바이트의 UDP 페이로드를 가지도록 보장해야 하며, 필요에 따라 PADDING 프레임을 추가해야 합니다. 패딩된 데이터그램을 전송하는 클라이언트는 서버가 주소 검증을 완료하기 전에 더 많은 데이터를 전송할 수 있도록 합니다.
서버로부터 Initial 또는 Handshake 패킷이 손실되면 클라이언트가 추가 Initial 또는 Handshake 패킷을 보내지 않을 경우 교착 상태가 발생할 수 있습니다. 서버가 증폭 방지 제한에 도달하고 클라이언트가 전송한 모든 데이터에 대한 승인을 받았을 때 교착 상태가 발생할 수 있습니다. 이 경우 클라이언트가 추가 패킷을 보낼 이유가 없으면, 서버는 클라이언트의 주소를 검증하지 않았기 때문에 더 많은 데이터를 보낼 수 없게 됩니다. 이러한 교착 상태를 방지하기 위해 클라이언트는 Probe Timeout (PTO)에서 반드시 패킷을 보내야 합니다. QUIC-RECOVERY의 섹션 6.2를 참조하십시오. 구체적으로, 클라이언트는 Handshake 키가 없는 경우 최소 1200바이트를 포함하는 UDP 데이터그램에서 Initial 패킷을 보내야 하며, 그렇지 않은 경우 Handshake 패킷을 보내야 합니다.
서버는 암호화 handshake를 시작하기 전에 클라이언트 주소를 검증하고자 할 수 있습니다. QUIC는 handshake 완료 전에 주소 검증을 제공하기 위해 Initial 패킷에서 토큰을 사용합니다. 이 토큰은 Retry 패킷을 통한 연결 설정 중에 클라이언트에게 전달되거나(섹션 8.1.2 참조), NEW_TOKEN 프레임을 사용하는 이전 연결에서 전달됩니다(섹션 8.1.3 참조).
주소 검증 이전에 부과된 전송 제한에 더하여, 서버는 혼잡 제어기에서 설정한 제한에 의해 전송할 수 있는 것이 제약됩니다. 클라이언트는 혼잡 제어기에 의해서만 제약됩니다.
Token Construction
NEW_TOKEN 프레임이나 Retry 패킷에서 전송되는 토큰은 서버가 클라이언트에게 어떻게 제공되었는지 식별할 수 있는 방식으로 구성되어야 합니다. 이러한 토큰들은 동일한 필드에 전달되지만 서버에서는 서로 다른 처리가 필요합니다.
Address Validation Using Retry Packets
클라이언트의 Initial 패킷을 수신하면, 서버는 토큰을 포함하는 Retry 패킷(Section 17.2.5)을 전송하여 주소 검증을 요청할 수 있습니다. 이 토큰은 클라이언트가 Retry 패킷을 수신한 후 해당 연결에 대해 전송하는 모든 Initial 패킷에서 반복되어야 합니다.
Retry 패킷에서 제공된 토큰을 포함하는 Initial 패킷을 처리하는 응답으로, 서버는 다른 Retry 패킷을 보낼 수 없습니다. 연결을 거부하거나 진행을 허용할 수만 있습니다.
공격자가 자신의 주소에 대한 유효한 토큰을 생성할 수 없고(섹션 8.1.4 참조) 클라이언트가 해당 토큰을 반환할 수 있는 한, 클라이언트가 토큰을 받았다는 것을 서버에 증명할 수 있습니다.
서버는 또한 Retry 패킷을 사용하여 연결 설정의 상태 및 처리 비용을 연기할 수 있습니다. 서버가 섹션 18.2에 정의된 original_destination_connection_id transport parameter와 함께 다른 connection ID를 제공하도록 요구하는 것은 서버 또는 서버와 협력하는 엔티티가 클라이언트로부터 원본 Initial 패킷을 수신했음을 증명하도록 강제합니다. 다른 connection ID를 제공하는 것은 또한 서버에게 후속 패킷이 라우팅되는 방식에 대한 일부 제어권을 부여합니다. 이는 연결을 다른 서버 인스턴스로 지시하는 데 사용될 수 있습니다.
서버가 유효하지 않은 Retry token을 포함하지만 다른 면에서는 유효한 클라이언트 Initial을 수신하면, 클라이언트가 다른 Retry token을 수락하지 않을 것임을 알 수 있습니다. 서버는 이러한 패킷을 폐기하고 클라이언트가 타임아웃되어 핸드셰이크 실패를 감지하도록 허용할 수 있지만, 이는 클라이언트에게 상당한 지연 시간 페널티를 부과할 수 있습니다. 대신, 서버는 INVALID_TOKEN 오류로 즉시 연결을 종료(Section 10.2)해야 합니다(SHOULD). 이 시점에서 서버는 연결에 대한 어떤 상태도 설정하지 않았으므로 종료 기간에 진입하지 않습니다.
Retry 패킷의 사용을 보여주는 플로우가 그림 9에 나타나 있습니다.
Client Server
Initial[0]: CRYPTO[CH] ->
<- Retry+Token
Initial+Token[1]: CRYPTO[CH] ->
Initial[0]: CRYPTO[SH] ACK[1]
Handshake[0]: CRYPTO[EE, CERT, CV, FIN]
<- 1-RTT[0]: STREAM[1, "..."]
Figure 9: Example Handshake with Retry
Address Validation for Future Connections
서버는 한 연결에서 클라이언트에게 주소 검증 토큰을 제공할 수 있으며(MAY), 이는 후속 연결에서 사용할 수 있습니다. 주소 검증은 0-RTT에서 특히 중요한데, 서버가 0-RTT 데이터에 응답하여 클라이언트에게 상당한 양의 데이터를 잠재적으로 전송하기 때문입니다.
서버는 NEW_TOKEN 프레임(섹션 19.7)을 사용하여 클라이언트에게 향후 연결을 검증하는 데 사용할 수 있는 주소 검증 토큰을 제공합니다. 향후 연결에서 클라이언트는 주소 검증을 제공하기 위해 Initial 패킷에 이 토큰을 포함합니다. 클라이언트는 Retry가 토큰을 더 새로운 것으로 교체하지 않는 한, 전송하는 모든 Initial 패킷에 토큰을 포함해야 합니다(MUST). 클라이언트는 향후 연결에 대해 Retry에서 제공된 토큰을 사용해서는 안 됩니다(MUST NOT). 서버는 예상된 토큰을 포함하지 않는 모든 Initial 패킷을 폐기할 수 있습니다(MAY).
Retry 패킷을 위해 생성되어 즉시 사용되는 토큰과 달리, NEW_TOKEN 프레임에서 전송되는 토큰은 일정 시간이 지난 후에 사용될 수 있습니다. 따라서 토큰은 만료 시간을 가져야 하며(SHOULD), 이는 명시적인 만료 시간이거나 만료 시간을 동적으로 계산하는 데 사용할 수 있는 발행 타임스탬프일 수 있습니다. 서버는 만료 시간을 저장하거나 토큰에 암호화된 형태로 포함시킬 수 있습니다.
NEW_TOKEN으로 발급된 토큰은 관찰자가 해당 토큰이 발급된 연결과 값들을 연결할 수 있게 하는 정보를 포함해서는 안 됩니다. 예를 들어, 값들이 암호화되지 않은 경우 이전 연결 ID나 주소 정보를 포함할 수 없습니다. 서버는 이전에 전송된 NEW_TOKEN 프레임의 손실을 복구하기 위해 전송된 것들을 제외하고, 전송하는 모든 NEW_TOKEN 프레임이 모든 클라이언트에 대해 고유함을 보장해야 합니다. 서버가 Retry와 NEW_TOKEN의 토큰을 구별할 수 있게 하는 정보는 서버가 아닌 다른 개체들이 접근할 수 있습니다.
두 개의 서로 다른 연결에서 클라이언트 포트 번호가 동일할 가능성은 낮으므로, 포트를 검증하는 것은 성공할 가능성이 낮습니다.
NEW_TOKEN 프레임에서 받은 토큰은 해당 연결이 권한을 가진 것으로 간주되는 모든 서버에 적용됩니다(예: 인증서에 포함된 서버 이름). 클라이언트가 적용 가능하고 사용되지 않은 토큰을 보유한 서버에 연결할 때, Initial 패킷의 Token 필드에 해당 토큰을 포함해야 합니다(SHOULD). 토큰을 포함하면 서버가 추가 라운드 트립 없이 클라이언트 주소를 검증할 수 있습니다. 클라이언트는 연결하려는 서버에 적용되지 않는 토큰을 포함해서는 안 됩니다(MUST NOT). 단, 토큰을 발급한 서버와 클라이언트가 연결하려는 서버가 토큰을 공동으로 관리하고 있다는 지식을 클라이언트가 가지고 있는 경우는 예외입니다. 클라이언트는 해당 서버에 대한 이전 연결에서 받은 토큰을 사용할 수 있습니다(MAY).
토큰은 서버가 토큰이 발급된 연결과 토큰이 사용된 모든 연결 간의 활동을 상관관계로 연결할 수 있게 합니다. 서버와의 신원 연속성을 끊고자 하는 클라이언트는 NEW_TOKEN 프레임을 사용하여 제공된 토큰을 폐기할 수 있습니다. 이에 비해, Retry 패킷에서 획득한 토큰은 연결 시도 중에 즉시 사용되어야 하며 후속 연결 시도에서는 사용될 수 없습니다.
클라이언트는 NEW_TOKEN 프레임의 토큰을 서로 다른 연결 시도에 재사용해서는 안 됩니다(SHOULD NOT). 토큰을 재사용하면 네트워크 경로상의 엔티티가 연결들을 연관지을 수 있습니다. 섹션 9.5를 참조하세요.
클라이언트는 단일 연결에서 여러 토큰을 받을 수 있습니다. 연결 가능성을 방지하는 것 외에도, 모든 토큰은 어떤 연결 시도에서든 사용할 수 있습니다. 서버는 여러 연결 시도에 대한 주소 검증을 활성화하거나 무효가 될 수 있는 오래된 토큰을 교체하기 위해 추가 토큰을 보낼 수 있습니다. 클라이언트의 경우, 이러한 모호성은 가장 최근의 사용하지 않은 토큰을 보내는 것이 가장 효과적일 가능성이 높다는 것을 의미합니다. 오래된 토큰을 저장하고 사용하는 것이 부정적인 결과를 가져오지는 않지만, 클라이언트는 오래된 토큰이 서버의 주소 검증에 유용할 가능성이 낮다고 간주할 수 있습니다.
서버가 주소 검증 토큰이 포함된 Initial 패킷을 수신할 때, 이미 주소 검증을 완료하지 않았다면 반드시 토큰을 검증하려고 시도해야 합니다. 토큰이 유효하지 않다면, 서버는 클라이언트가 검증된 주소를 가지지 않은 것처럼 진행해야 하며, 이는 잠재적으로 Retry 패킷을 전송하는 것을 포함합니다. NEW_TOKEN 프레임과 Retry 패킷으로 제공된 토큰들은 서버에 의해 구별될 수 있고(섹션 8.1.1 참조), 후자는 더 엄격하게 검증될 수 있습니다. 검증이 성공하면, 서버는 핸드셰이크가 진행되도록 허용해야 합니다.
참고: 패킷을 폐기하는 대신 클라이언트를 검증되지 않은 것으로 처리하는 이유는 클라이언트가 NEW_TOKEN frame을 사용하여 이전 연결에서 토큰을 받았을 수 있고, 서버가 상태를 잃어버린 경우 토큰을 전혀 검증할 수 없어 패킷이 폐기되면 연결 실패로 이어질 수 있기 때문입니다.
상태 비저장(stateless) 설계에서 서버는 암호화되고 인증된 토큰을 사용하여 클라이언트에게 정보를 전달할 수 있으며, 서버는 나중에 이를 복구하여 클라이언트 주소를 검증하는 데 사용할 수 있습니다. 토큰은 암호화 핸드셰이크에 통합되지 않으므로 인증되지 않습니다. 예를 들어, 클라이언트가 토큰을 재사용할 수 있을지도 모릅니다. 이러한 속성을 악용하는 공격을 피하기 위해, 서버는 토큰 사용을 클라이언트 주소 검증에 필요한 정보로만 제한할 수 있습니다.
클라이언트는 한 연결에서 획득한 토큰을 동일한 버전을 사용하는 모든 연결 시도에 사용할 수 있습니다. 사용할 토큰을 선택할 때, 클라이언트는 시도되는 연결의 다른 속성들을 고려할 필요가 없으며, 여기에는 가능한 애플리케이션 프로토콜 선택, 세션 티켓, 또는 기타 연결 속성들이 포함됩니다.
Address Validation Token Integrity
주소 검증 토큰은 추측하기 어려워야 합니다. 토큰에 최소 128비트의 엔트로피를 가진 무작위 값을 포함하는 것으로 충분하지만, 이는 서버가 클라이언트에게 보낸 값을 기억하는 것에 의존합니다.
토큰 기반 체계는 서버가 검증과 관련된 모든 상태를 클라이언트에게 위임할 수 있게 합니다. 이 설계가 작동하려면 토큰은 클라이언트의 수정이나 위조에 대한 무결성 보호로 보호되어야 합니다. 무결성 보호가 없다면 악의적인 클라이언트가 서버에서 받아들여질 토큰 값을 생성하거나 추측할 수 있습니다. 오직 서버만이 토큰의 무결성 보호 키에 접근할 수 있어야 합니다.
토큰을 생성하는 서버가 동시에 이를 소비하기 때문에 토큰에 대한 단일하고 명확하게 정의된 형식이 필요하지 않습니다. Retry 패킷에서 전송되는 토큰은 클라이언트 패킷의 소스 IP 주소와 포트가 일정하게 유지되는지 서버가 검증할 수 있도록 하는 정보를 포함해야 합니다(SHOULD).
NEW_TOKEN 프레임에서 전송되는 토큰은 토큰이 발급되었을 때로부터 클라이언트 IP 주소가 변경되지 않았음을 서버가 확인할 수 있는 정보를 반드시 포함해야 합니다. 서버는 클라이언트 주소가 변경되었더라도 NEW_TOKEN 프레임의 토큰을 사용하여 Retry 패킷을 보내지 않기로 결정할 수 있습니다. 클라이언트 IP 주소가 변경된 경우, 서버는 증폭 방지 제한을 반드시 준수해야 합니다. 섹션 8을 참조하십시오. NAT가 있는 환경에서는 이 요구사항이 NAT를 공유하는 다른 호스트를 증폭 공격으로부터 보호하기에 불충분할 수 있습니다.
공격자들은 DDoS 공격에서 서버를 증폭기로 사용하기 위해 토큰을 재전송할 수 있습니다. 이러한 공격을 방지하기 위해 서버는 토큰의 재전송이 방지되거나 제한되도록 보장해야 합니다(MUST). 서버는 Retry 패킷으로 전송된 토큰이 클라이언트에 의해 즉시 반환되므로 짧은 시간 동안만 허용되도록 보장해야 합니다(SHOULD). NEW_TOKEN 프레임(섹션 19.7)에서 제공되는 토큰은 더 오래 유효해야 하지만 여러 번 허용되어서는 안 됩니다(SHOULD NOT). 서버는 가능한 경우 토큰을 한 번만 사용할 수 있도록 허용하는 것이 권장됩니다. 토큰은 적용 가능성이나 재사용을 더욱 제한하기 위해 클라이언트에 대한 추가 정보를 포함할 수 있습니다(MAY).
온라인 DPI
경로 검증은 주소 변경 후 도달 가능성을 확인하기 위해 연결 마이그레이션(섹션 9 참조) 중에 두 peer 모두에서 사용됩니다. 경로 검증에서 엔드포인트는 특정 로컬 주소와 특정 peer 주소 간의 도달 가능성을 테스트하며, 여기서 주소는 IP 주소와 포트의 2-tuple입니다.
경로 검증은 peer에게 경로를 통해 전송된 패킷이 해당 peer에 의해 수신되는지 테스트합니다. 경로 검증은 마이그레이션하는 peer로부터 수신된 패킷이 스푸핑된 소스 주소를 포함하지 않도록 보장하기 위해 사용됩니다.
경로 검증은 peer가 반환 방향으로 전송할 수 있는지 검증하지 않습니다. 확인응답(Acknowledgment)은 충분하지 않은 엔트로피를 포함하고 있으며 스푸핑될 수 있기 때문에 반환 경로 검증에 사용될 수 없습니다. 엔드포인트는 경로의 각 방향에서 도달 가능성을 독립적으로 판단하므로, 반환 도달 가능성은 peer에 의해서만 설정될 수 있습니다.
경로 검증은 언제든지 양쪽 엔드포인트에서 사용할 수 있습니다. 예를 들어, 엔드포인트는 일정 기간의 비활성 상태 후에 피어가 여전히 자신의 주소를 소유하고 있는지 확인할 수 있습니다.
경로 검증은 NAT traversal 메커니즘으로 설계되지 않았습니다. 여기서 설명된 메커니즘이 NAT traversal을 지원하는 NAT 바인딩 생성에 효과적일 수 있지만, 기대되는 것은 한 엔드포인트가 해당 경로에서 먼저 패킷을 보내지 않고도 패킷을 수신할 수 있다는 것입니다. 효과적인 NAT traversal에는 여기서 제공되지 않는 추가적인 동기화 메커니즘이 필요합니다.
엔드포인트는 경로 검증에 사용되는 PATH_CHALLENGE 및 PATH_RESPONSE 프레임과 함께 다른 프레임을 포함할 수 있습니다(MAY). 특히, 엔드포인트는 경로 최대 전송 단위 발견(PMTUD)을 위해 PATH_CHALLENGE 프레임과 함께 PADDING 프레임을 포함할 수 있습니다. 섹션 14.2.1을 참조하십시오. 엔드포인트는 PATH_RESPONSE 프레임을 전송할 때 자체 PATH_CHALLENGE 프레임을 포함할 수도 있습니다.
엔드포인트는 새로운 로컬 주소에서 전송되는 프로브에 대해 새로운 connection ID를 사용합니다. 섹션 9.5를 참조하십시오. 새로운 경로를 프로빙할 때, 엔드포인트는 피어가 응답에 사용할 수 있는 미사용 connection ID를 보유하고 있음을 보장할 수 있습니다. 피어의 active_connection_id_limit이 허용하는 경우, 동일한 패킷에서 NEW_CONNECTION_ID와 PATH_CHALLENGE 프레임을 전송하면 응답을 전송할 때 피어가 미사용 connection ID를 사용할 수 있도록 보장합니다.
엔드포인트는 동시에 여러 경로를 탐사하도록 선택할 수 있습니다. 탐사에 사용되는 동시 경로의 수는 피어가 이전에 제공한 추가 connection ID의 수로 제한됩니다. 탐사에 사용되는 각 새로운 로컬 주소는 이전에 사용되지 않은 connection ID를 필요로 하기 때문입니다.
오프라인 DPI
경로 검증을 시작하기 위해, 엔드포인트는 검증할 경로에서 예측 불가능한 페이로드를 포함하는 PATH_CHALLENGE 프레임을 전송합니다.
엔드포인트는 패킷 손실을 방지하기 위해 여러 PATH_CHALLENGE 프레임을 전송할 수 있습니다(MAY). 그러나 엔드포인트는 단일 패킷에서 여러 PATH_CHALLENGE 프레임을 전송해서는 안 됩니다(SHOULD NOT).
엔드포인트는 PATH_CHALLENGE 프레임을 포함한 패킷으로 새로운 경로를 탐지할 때, Initial 패킷을 보내는 빈도보다 더 자주 탐지해서는 안 됩니다(SHOULD NOT). 이는 연결 마이그레이션이 새로운 연결을 설정하는 것보다 새로운 경로에 더 많은 부하를 가하지 않도록 보장합니다.
엔드포인트는 모든 PATH_CHALLENGE 프레임에서 예측 불가능한 데이터를 사용해야 하며, 이를 통해 피어의 응답을 해당하는 PATH_CHALLENGE와 연관시킬 수 있습니다.
엔드포인트는 PATH_CHALLENGE 프레임을 포함하는 데이터그램을 최소 허용 최대 데이터그램 크기인 1200바이트 이상으로 확장해야 하며, 경로의 증폭 방지 제한으로 인해 이 크기의 데이터그램을 전송할 수 없는 경우는 예외입니다. 이 크기의 UDP 데이터그램을 전송하면 엔드포인트에서 피어까지의 네트워크 경로가 QUIC에 사용될 수 있음을 보장합니다. 섹션 14를 참조하십시오.
엔드포인트가 증폭 공격 방지 제한으로 인해 데이터그램 크기를 1200바이트로 확장할 수 없는 경우, 경로 MTU가 검증되지 않습니다. 경로 MTU가 충분히 큰지 확인하기 위해, 엔드포인트는 최소 1200바이트의 데이터그램에 PATH_CHALLENGE 프레임을 전송하여 두 번째 경로 검증을 수행해야 합니다. 이 추가 검증은 PATH_RESPONSE가 성공적으로 수신된 후 또는 더 큰 데이터그램을 전송해도 증폭 공격 방지 제한을 초과하지 않을 만큼 충분한 바이트가 경로에서 수신되었을 때 수행할 수 있습니다.
데이터그램이 확장되는 다른 경우와 달리, 엔드포인트는 PATH_CHALLENGE 또는 PATH_RESPONSE를 포함할 때 너무 작아 보이는 데이터그램을 폐기해서는 안 됩니다.
Path Validation Responses
PATH_CHALLENGE 프레임을 수신하면, 엔드포인트는 PATH_CHALLENGE 프레임에 포함된 데이터를 PATH_RESPONSE 프레임으로 에코하여 응답해야 합니다. 엔드포인트는 혼잡 제어에 의해 제약을 받지 않는 한 PATH_RESPONSE 프레임이 포함된 패킷의 전송을 지연해서는 안 됩니다.
PATH_RESPONSE 프레임은 PATH_CHALLENGE 프레임이 수신된 네트워크 경로에서 반드시 전송되어야 합니다. 이는 피어에 의한 경로 검증이 경로가 양방향으로 작동할 때만 성공하도록 보장합니다. 이 요구사항은 경로 검증을 시작하는 엔드포인트에 의해 강제되어서는 안 되며, 이는 마이그레이션에 대한 공격을 가능하게 할 수 있습니다. 섹션 9.3.3을 참조하십시오.
엔드포인트는 PATH_RESPONSE frame을 포함하는 datagram을 최소 허용 최대 datagram 크기인 1200바이트 이상으로 확장해야 합니다. 이는 경로가 양방향으로 이 크기의 datagram을 전송할 수 있음을 검증합니다. 그러나 엔드포인트는 PATH_RESPONSE를 포함하는 datagram을 확장할 때 결과 데이터가 증폭 방지 제한을 초과하는 경우 확장해서는 안 됩니다. 이는 수신된 PATH_CHALLENGE가 확장된 datagram으로 전송되지 않은 경우에만 발생할 것으로 예상됩니다.
엔드포인트는 하나의 PATH_CHALLENGE 프레임에 대한 응답으로 둘 이상의 PATH_RESPONSE 프레임을 전송해서는 안 됩니다(MUST NOT). 섹션 13.3을 참조하십시오. 피어는 추가적인 PATH_RESPONSE 프레임을 유발하기 위해 필요에 따라 더 많은 PATH_CHALLENGE 프레임을 전송할 것으로 예상됩니다.
연결 설정 중 주소 검증
경로 검증은 이전 PATH_CHALLENGE 프레임에서 전송된 데이터를 포함하는 PATH_RESPONSE 프레임이 수신되었을 때 성공합니다. 임의의 네트워크 경로에서 수신된 PATH_RESPONSE 프레임은 PATH_CHALLENGE가 전송된 경로를 검증합니다.
엔드포인트가 최소 1200바이트로 확장되지 않은 데이터그램에서 PATH_CHALLENGE 프레임을 전송하고, 이에 대한 응답이 피어 주소를 검증하는 경우, 경로는 검증되지만 경로 MTU는 검증되지 않습니다. 결과적으로 엔드포인트는 이제 수신한 데이터 양의 3배 이상을 전송할 수 있습니다. 그러나 엔드포인트는 경로가 필요한 MTU를 지원하는지 확인하기 위해 확장된 데이터그램으로 다른 경로 검증을 시작해야 합니다(MUST).
PATH_CHALLENGE 프레임이 포함된 패킷에 대한 확인응답을 받는 것만으로는 적절한 검증이 되지 않습니다. 악의적인 피어가 확인응답을 위조할 수 있기 때문입니다.
토큰 구성
경로 검증은 경로를 검증하려고 시도하는 엔드포인트가 경로 검증 시도를 포기할 때만 실패합니다.
엔드포인트는 타이머를 기반으로 경로 검증을 중단해야 합니다(SHOULD). 이 타이머를 설정할 때, 구현체는 새로운 경로가 원래 경로보다 더 긴 왕복 시간을 가질 수 있다는 점에 주의해야 합니다. 현재 PTO 또는 새로운 경로의 PTO 중 더 큰 값의 3배(QUIC-RECOVERY에서 정의된 kInitialRtt 사용)가 권장됩니다(RECOMMENDED).
이 타임아웃은 경로 검증 실패 전에 여러 PTO가 만료될 수 있도록 하여, 단일 PATH_CHALLENGE 또는 PATH_RESPONSE 프레임의 손실이 경로 검증 실패를 일으키지 않도록 합니다.
endpoint가 새로운 경로에서 다른 프레임을 포함하는 패킷을 수신할 수 있지만, 경로 검증이 성공하려면 적절한 데이터가 포함된 PATH_RESPONSE 프레임이 필요합니다.
엔드포인트가 경로 검증을 포기할 때, 해당 경로가 사용 불가능하다고 판단합니다. 이것이 반드시 연결 실패를 의미하는 것은 아닙니다 – 엔드포인트는 적절한 다른 경로를 통해 패킷을 계속 전송할 수 있습니다. 사용 가능한 경로가 없는 경우, 엔드포인트는 새로운 경로가 사용 가능해질 때까지 기다리거나 연결을 닫을 수 있습니다. 피어로의 유효한 네트워크 경로가 없는 엔드포인트는 NO_VIABLE_PATH 연결 오류를 사용하여 이를 신호할 수 있지만, 이는 네트워크 경로가 존재하지만 필요한 MTU를 지원하지 않는 경우에만 가능하다는 점에 유의해야 합니다(섹션 14).
경로 검증은 실패 이외의 다른 이유로도 중단될 수 있습니다. 주로 이는 기존 경로에서 경로 검증이 진행 중일 때 새로운 경로로의 연결 마이그레이션이 시작되는 경우에 발생합니다.
Connection Migration
다음은 QUIC RFC 9000에서 복사한 내용입니다. 각 섹션을 검토하고 편집하세요.
연결 ID의 사용은 엔드포인트가 새로운 네트워크로 마이그레이션할 때 발생하는 것과 같이 엔드포인트 주소(IP 주소 및 포트)의 변경에도 연결이 유지될 수 있게 합니다. 이 섹션에서는 엔드포인트가 새로운 주소로 마이그레이션하는 과정을 설명합니다.
QUIC의 설계는 핸드셰이크 기간 동안 엔드포인트가 안정적인 주소를 유지하는 것에 의존합니다. QUIC-TLS의 섹션 4.1.2에서 정의된 바와 같이, 엔드포인트는 핸드셰이크가 확인되기 전에 연결 마이그레이션을 시작해서는 안 됩니다.
peer가 disable_active_migration transport parameter를 전송한 경우, endpoint는 peer가 handshake 중에 사용한 주소로 다른 로컬 주소에서 패킷(probing 패킷 포함; 섹션 9.1 참조)을 전송해서는 안 되며, endpoint가 peer로부터 preferred_address transport parameter에 따라 행동한 경우는 예외입니다. peer가 이 요구사항을 위반하는 경우, endpoint는 해당 경로에서 들어오는 패킷을 Stateless Reset을 생성하지 않고 드롭하거나 경로 검증을 진행하고 peer의 마이그레이션을 허용해야 합니다. Stateless Reset을 생성하거나 연결을 닫는 것은 네트워크의 제3자가 관찰된 트래픽을 스푸핑하거나 조작하여 연결을 닫도록 할 수 있게 합니다.
모든 peer 주소 변경이 의도적이거나 능동적인 마이그레이션은 아닙니다. peer는 NAT 리바인딩을 경험할 수 있습니다: 이는 middlebox(보통 NAT)가 플로우에 대해 새로운 outgoing 포트나 심지어 새로운 outgoing IP 주소를 할당하여 발생하는 주소 변경입니다. endpoint는 peer의 주소에 대한 변경을 감지하면 이전에 해당 주소를 검증한 적이 없는 한 반드시 path validation(섹션 8.2)을 수행해야 합니다.
엔드포인트가 패킷을 전송할 유효한 경로가 없는 경우, 연결 상태를 폐기할 수 있습니다(MAY). 연결 마이그레이션이 가능한 엔드포인트는 연결 상태를 폐기하기 전에 새로운 경로가 사용 가능해질 때까지 기다릴 수 있습니다(MAY).
이 문서는 섹션 9.6에 설명된 경우를 제외하고는 새로운 클라이언트 주소로의 연결 마이그레이션을 제한합니다. 클라이언트는 모든 마이그레이션을 시작할 책임이 있습니다. 서버는 해당 주소에서 비-probing 패킷을 보기 전까지는 클라이언트 주소로 비-probing 패킷(섹션 9.1 참조)을 보내지 않습니다. 클라이언트가 알 수 없는 서버 주소에서 패킷을 받는 경우, 클라이언트는 이러한 패킷을 폐기해야 합니다(MUST).
재시도 패킷을 사용한 주소 검증
엔드포인트는 연결을 새로운 로컬 주소로 마이그레이션하기 전에 경로 검증(Section 8.2)을 사용하여 새로운 로컬 주소에서 피어 도달 가능성을 조사할 수 있습니다(MAY). 경로 검증 실패는 단순히 새로운 경로가 이 연결에 사용할 수 없다는 의미입니다. 경로 검증 실패는 사용 가능한 유효한 대안 경로가 없는 경우가 아니라면 연결을 종료시키지 않습니다.
PATH_CHALLENGE, PATH_RESPONSE, NEW_CONNECTION_ID, PADDING 프레임은 “probing frames"이며, 다른 모든 프레임은 “non-probing frames"입니다. probing frames만 포함하는 패킷은 “probing packet"이고, 다른 프레임을 포함하는 패킷은 “non-probing packet"입니다.
향후 연결을 위한 주소 검증
엔드포인트는 해당 주소에서 non-probing 프레임이 포함된 패킷을 전송하여 연결을 새로운 로컬 주소로 이주할 수 있습니다.
각 엔드포인트는 연결 설정 중에 상대방의 주소를 검증합니다. 따라서 마이그레이션하는 엔드포인트는 상대방이 현재 주소에서 수신할 의향이 있다는 것을 알고 상대방에게 전송할 수 있습니다. 따라서 엔드포인트는 먼저 상대방의 주소를 검증하지 않고도 새로운 로컬 주소로 마이그레이션할 수 있습니다.
새로운 경로에서 도달 가능성을 확립하기 위해, 엔드포인트는 새로운 경로에서 경로 검증(Section 8.2)을 시작합니다. 엔드포인트는 피어가 새로운 주소로 다음 non-probing 프레임을 보낼 때까지 경로 검증을 연기할 수 있습니다.
마이그레이션할 때, 새로운 경로는 엔드포인트의 현재 전송 속도를 지원하지 않을 수 있습니다. 따라서 엔드포인트는 Section 9.4에서 설명한 대로 혼잡 제어기와 RTT 추정값을 재설정합니다.
새로운 경로는 동일한 ECN 기능을 갖지 않을 수 있습니다. 따라서 엔드포인트는 섹션 13.4에 설명된 대로 ECN 기능을 검증합니다.
주소 검증 토큰 무결성
비프로빙 프레임을 포함하는 새로운 피어 주소로부터 패킷을 수신하는 것은 피어가 해당 주소로 마이그레이션했음을 나타냅니다.
수신자가 마이그레이션을 허용하는 경우, 후속 패킷을 새로운 피어 주소로 전송해야 하며(MUST), 검증이 이미 진행 중이 아닌 경우 피어의 주소 소유권을 확인하기 위해 경로 검증(Section 8.2)을 시작해야 합니다(MUST). 수신자가 피어로부터 사용되지 않은 연결 ID를 가지고 있지 않은 경우, 피어가 하나를 제공할 때까지 새로운 경로에서 아무것도 전송할 수 없습니다. Section 9.5를 참조하십시오.
엔드포인트는 가장 높은 번호의 비탐지(non-probing) 패킷에 응답하여 패킷을 전송하는 주소만 변경합니다. 이는 엔드포인트가 순서가 바뀐 패킷을 수신하는 경우 이전 피어 주소로 패킷을 전송하지 않도록 보장합니다.
엔드포인트는 검증되지 않은 피어 주소로 데이터를 전송할 수 있지만(MAY), 섹션 9.3.1과 9.3.2에서 설명된 잠재적 공격에 대해 보호해야 합니다(MUST). 엔드포인트는 해당 주소가 최근에 확인된 경우 피어 주소 검증을 건너뛸 수 있습니다(MAY). 특히, 엔드포인트가 어떤 형태의 가짜 마이그레이션을 탐지한 후 이전에 검증된 경로로 돌아가는 경우, 주소 검증을 건너뛰고 손실 탐지 및 혼잡 상태를 복원하면 공격의 성능 영향을 줄일 수 있습니다.
비탐지 패킷을 전송하는 주소를 변경한 후, 엔드포인트는 다른 주소에 대한 경로 검증을 포기할 수 있습니다.
새로운 peer 주소로부터 패킷을 수신하는 것은 해당 peer에서 NAT rebinding의 결과일 수 있습니다.
새로운 클라이언트 주소를 검증한 후, 서버는 클라이언트에게 새로운 주소 검증 토큰(Section 8)을 보내야 합니다(SHOULD).
경로 검증
피어가 자신의 소스 주소를 스푸핑하여 엔드포인트가 원하지 않는 호스트에 과도한 양의 데이터를 전송하도록 유도할 가능성이 있습니다. 엔드포인트가 스푸핑하는 피어보다 훨씬 많은 데이터를 전송하는 경우, 연결 마이그레이션이 공격자가 피해자에게 생성할 수 있는 데이터 볼륨을 증폭시키는 데 사용될 수 있습니다.
섹션 9.3에서 설명한 바와 같이, 엔드포인트는 피어의 새로운 주소에 대한 피어의 소유권을 확인하기 위해 피어의 새 주소를 검증해야 합니다. 피어의 주소가 유효하다고 판단될 때까지, 엔드포인트는 해당 주소로 전송하는 데이터의 양을 제한합니다(섹션 8 참조). 이러한 제한이 없다면, 엔드포인트는 의심하지 않는 피해자에 대한 서비스 거부 공격에 이용될 위험이 있습니다.
엔드포인트가 위에서 설명한 대로 피어 주소의 검증을 건너뛰는 경우, 전송 속도를 제한할 필요가 없습니다.
경로 검증 시작
경로상 공격자는 스푸핑된 주소로 패킷을 복사하고 전달하여 원본 패킷보다 먼저 도착하도록 함으로써 가짜 연결 마이그레이션을 발생시킬 수 있습니다. 스푸핑된 주소를 가진 패킷은 마이그레이션하는 연결에서 온 것으로 보이고, 원본 패킷은 중복으로 간주되어 삭제됩니다. 가짜 마이그레이션 이후에는 소스 주소 검증이 실패하게 되는데, 이는 소스 주소의 엔티티가 전송된 PATH_CHALLENGE 프레임을 읽거나 응답하는 데 필요한 암호화 키를 가지고 있지 않기 때문입니다. 설령 응답하고 싶어도 말입니다.
이러한 가짜 마이그레이션으로 인한 연결 실패를 방지하기 위해, 엔드포인트는 새로운 피어 주소의 검증이 실패할 때 마지막으로 검증된 피어 주소를 사용하는 것으로 되돌아가야 합니다. 또한, 정당한 피어 주소로부터 더 높은 패킷 번호를 가진 패킷을 수신하면 또 다른 연결 마이그레이션이 트리거됩니다. 이는 가짜 마이그레이션의 주소 검증을 포기하게 하여, 공격자가 단일 패킷을 주입하여 시작한 마이그레이션을 억제합니다.
엔드포인트가 마지막으로 검증된 peer 주소에 대한 상태가 없는 경우, 모든 연결 상태를 폐기하여 연결을 조용히 종료해야 합니다(MUST). 이로 인해 연결의 새로운 패킷들이 일반적으로 처리됩니다. 예를 들어, 엔드포인트는 추가로 들어오는 패킷에 대한 응답으로 Stateless Reset을 전송할 수 있습니다(MAY).
경로 검증 응답
패킷을 관찰할 수 있는 off-path 공격자는 정상 패킷의 복사본을 엔드포인트로 전달할 수 있습니다. 복사된 패킷이 정상 패킷보다 먼저 도착하면 이는 NAT rebinding으로 나타날 것입니다. 모든 정상 패킷은 중복으로 간주되어 폐기됩니다. 공격자가 계속해서 패킷을 전달할 수 있다면 공격자를 거치는 경로로의 migration을 야기할 수 있습니다. 이는 공격자를 on-path에 위치시켜 모든 후속 패킷을 관찰하거나 드롭할 수 있는 능력을 부여합니다.
이러한 스타일의 공격은 공격자가 엔드포인트 간의 직접 경로와 거의 동일한 특성을 가진 경로를 사용하는 것에 의존합니다. 상대적으로 적은 수의 패킷이 전송되거나 패킷 손실이 공격 시도와 일치할 때 공격은 더욱 신뢰할 수 있습니다.
최대 수신 패킷 번호를 증가시키는 원본 경로에서 수신된 비탐사 패킷은 엔드포인트가 해당 경로로 다시 이동하도록 합니다. 이 경로에서 패킷을 유도하면 공격이 실패할 가능성이 높아집니다. 따라서 이 공격의 완화는 패킷 교환을 유발하는 것에 의존합니다.
명백한 마이그레이션에 대한 응답으로, 엔드포인트는 PATH_CHALLENGE 프레임을 사용하여 이전에 활성화된 경로를 검증해야 합니다. 이는 해당 경로에서 새로운 패킷의 전송을 유도합니다. 경로가 더 이상 사용 가능하지 않다면, 검증 시도는 시간 초과되어 실패할 것입니다. 경로가 사용 가능하지만 더 이상 원하지 않는다면, 검증은 성공하지만 해당 경로에서 프로빙 패킷만 전송되는 결과를 낳습니다.
활성 경로에서 PATH_CHALLENGE를 수신하는 엔드포인트는 응답으로 비탐색(non-probing) 패킷을 전송해야 합니다. 비탐색 패킷이 공격자가 만든 복사본보다 먼저 도착하면 연결이 원래 경로로 다시 마이그레이션됩니다. 다른 경로로의 후속 마이그레이션은 이 전체 과정을 다시 시작합니다.
이 방어책은 불완전하지만, 이는 심각한 문제로 간주되지 않습니다. 원래 경로를 사용하려는 여러 시도에도 불구하고 공격을 통한 경로가 원래 경로보다 안정적으로 빠르다면, 공격과 라우팅 개선을 구별하는 것은 불가능합니다.
엔드포인트는 또한 휴리스틱을 사용하여 이러한 스타일의 공격 탐지를 개선할 수 있습니다. 예를 들어, 이전 경로에서 최근에 패킷이 수신된 경우 NAT 리바인딩은 일어날 가능성이 낮습니다. 마찬가지로 IPv6 경로에서는 리바인딩이 드뭅니다. 엔드포인트는 또한 중복된 패킷을 찾을 수 있습니다. 반대로 connection ID의 변경은 공격보다는 의도적인 마이그레이션을 나타낼 가능성이 높습니다.
성공적인 경로 검증
새 경로에서 사용 가능한 용량은 기존 경로와 동일하지 않을 수 있습니다. 기존 경로에서 전송된 패킷은 새 경로의 혼잡 제어나 RTT 추정에 기여해서는 안 됩니다.
피어의 새 주소 소유권을 확인한 후, 엔드포인트는 피어 주소의 유일한 변경 사항이 포트 번호인 경우가 아닌 한, 새 경로에 대한 혼잡 제어기와 왕복 시간 추정기를 즉시 초기값으로 재설정해야 합니다(QUIC-RECOVERY의 부록 A.3 및 B.3 참조). 포트만 변경되는 경우는 일반적으로 NAT 재바인딩이나 기타 미들박스 활동의 결과이므로, 엔드포인트는 초기값으로 되돌리는 대신 해당 경우에 혼잡 제어 상태와 왕복 시간 추정치를 유지할 수 있습니다. 이전 경로의 혼잡 제어 상태가 상당히 다른 특성을 가진 새 경로에서 사용되는 경우, 혼잡 제어기와 RTT 추정기가 적응할 때까지 송신자가 너무 공격적으로 전송할 수 있습니다. 일반적으로 구현체는 새 경로에서 이전 값을 사용할 때 신중하게 접근하는 것이 권장됩니다.
마이그레이션 기간 동안 엔드포인트가 여러 주소로부터/로 데이터와 프로브를 전송할 때, 두 결과 경로가 서로 다른 왕복 시간을 가질 수 있으므로 수신자에서 명백한 재정렬이 발생할 수 있습니다. 여러 경로에서 패킷을 수신하는 수신자는 여전히 모든 수신된 패킷을 포함하는 ACK 프레임을 전송합니다.
연결 마이그레이션 중에 여러 경로가 사용될 수 있지만, 단일 혼잡 제어 컨텍스트와 단일 손실 복구 컨텍스트(QUIC-RECOVERY에 설명된 대로)만으로도 충분할 수 있습니다. 예를 들어, 엔드포인트는 기존 경로가 더 이상 필요하지 않다는 것이 확인될 때까지 새로운 혼잡 제어 컨텍스트로의 전환을 지연시킬 수 있습니다(섹션 9.3.3에서 설명한 경우와 같이).
발신자는 probe 패킷에 대한 예외를 만들어 손실 탐지가 독립적이 되도록 하고 혼잡 제어기가 전송 속도를 부당하게 줄이지 않도록 할 수 있습니다. 엔드포인트는 PATH_CHALLENGE가 전송될 때 별도의 타이머를 설정할 수 있으며, 해당 PATH_RESPONSE가 수신되면 이 타이머가 취소됩니다. PATH_RESPONSE가 수신되기 전에 타이머가 만료되면, 엔드포인트는 새로운 PATH_CHALLENGE를 전송하고 더 긴 시간 동안 타이머를 다시 시작할 수 있습니다. 이 타이머는 QUIC-RECOVERY의 섹션 6.2.1에서 설명된 대로 설정되어야 하며(SHOULD) 더 공격적이어서는 안 됩니다(MUST NOT).
경로 검증 실패
여러 네트워크 경로에서 안정적인 connection ID를 사용하면 수동적 관찰자가 해당 경로들 간의 활동을 연관지을 수 있습니다. 네트워크 간을 이동하는 엔드포인트는 자신의 피어 이외의 다른 개체에 의해 활동이 연관되는 것을 원하지 않을 수 있으므로, Section 5.1에서 논의된 바와 같이 서로 다른 로컬 주소에서 전송할 때 다른 connection ID가 사용됩니다. 이것이 효과적이려면, 엔드포인트들은 자신이 제공하는 connection ID들이 다른 개체에 의해 연결될 수 없도록 보장해야 합니다.
언제든지 엔드포인트는 다른 경로에서 사용되지 않은 값으로 전송하는 Destination Connection ID를 변경할 수 있습니다.
엔드포인트는 둘 이상의 로컬 주소에서 전송할 때 connection ID를 재사용해서는 안 됩니다(MUST NOT) – 예를 들어, 섹션 9.2에서 설명하는 연결 마이그레이션을 시작할 때나 섹션 9.1에서 설명하는 새로운 네트워크 경로를 탐지할 때입니다.
마찬가지로, endpoint는 둘 이상의 목적지 주소로 전송할 때 connection ID를 재사용해서는 안 됩니다. 피어의 제어를 벗어난 네트워크 변경으로 인해, endpoint는 동일한 Destination Connection ID 필드 값을 가진 새로운 소스 주소로부터 패킷을 수신할 수 있으며, 이 경우 동일한 로컬 주소에서 전송하면서 새로운 원격 주소와 함께 현재 connection ID를 계속 사용할 수 있습니다.
연결 ID 재사용에 관한 이러한 요구사항은 패킷 전송에만 적용되며, 연결 ID 변경 없이 의도치 않은 경로 변경이 발생할 수 있습니다. 예를 들어, 네트워크 비활성 기간 후 NAT rebinding으로 인해 클라이언트가 전송을 재개할 때 패킷이 새로운 경로로 전송될 수 있습니다. 엔드포인트는 이러한 이벤트에 대해 섹션 9.3에서 설명한 대로 응답합니다.
각 새로운 네트워크 경로에서 양방향으로 전송되는 패킷에 서로 다른 connection ID를 사용하면 서로 다른 네트워크 경로에서 동일한 연결의 패킷을 연결하는 데 connection ID가 사용되는 것을 방지할 수 있습니다. 헤더 보호는 패킷 번호가 활동을 연관시키는 데 사용될 수 없도록 보장합니다. 이것이 타이밍이나 크기와 같은 패킷의 다른 속성이 활동을 연관시키는 데 사용되는 것을 방지하지는 않습니다.
endpoint는 길이가 0인 connection ID를 요청한 peer와의 migration을 시작해서는 안 됩니다(SHOULD NOT). 새로운 경로를 통한 트래픽이 기존 경로의 트래픽과 쉽게 연결될 수 있기 때문입니다. 서버가 길이가 0인 connection ID를 가진 패킷을 올바른 연결과 연관시킬 수 있다면, 이는 서버가 패킷을 역다중화하기 위해 다른 정보를 사용하고 있다는 의미입니다. 예를 들어, 서버는 모든 클라이언트에게 고유한 주소를 제공할 수 있습니다 – 예를 들어, HTTP alternative services ALTSVC를 사용하여. 여러 네트워크 경로에서 패킷의 올바른 라우팅을 허용할 수 있는 정보는 또한 해당 경로에서의 활동이 peer가 아닌 다른 엔티티에 의해 연결되도록 할 것입니다.
클라이언트는 비활성 기간 후 트래픽을 전송할 때 새로운 connection ID, 소스 UDP 포트, 또는 IP 주소로 전환하여 연결가능성을 줄이고자 할 수 있습니다(RFC8981 참조). 동시에 패킷을 전송하는 주소를 변경하면 서버가 연결 마이그레이션을 감지할 수 있습니다. 이는 NAT 리바인딩이나 실제 마이그레이션을 경험하지 않는 클라이언트에 대해서도 마이그레이션을 지원하는 메커니즘이 동작하도록 보장합니다. 주소 변경은 피어가 혼잡 제어 상태를 재설정하도록 할 수 있으므로([섹션 9.4] 참조), 주소는 드물게만 변경되어야 합니다(SHOULD).
사용 가능한 connection ID를 모두 소진한 endpoint는 새로운 경로를 탐사하거나 마이그레이션을 시작할 수 없으며, 피어의 탐사나 마이그레이션 시도에 응답할 수도 없습니다. 마이그레이션이 가능하고 서로 다른 경로로 전송된 패킷들이 연관될 수 없도록 보장하기 위해, endpoint는 피어가 마이그레이션하기 전에 새로운 connection ID를 제공해야 합니다(SHOULD). 섹션 5.1.1을 참조하세요. 피어가 사용 가능한 connection ID를 소진했을 가능성이 있다면, 마이그레이션하는 endpoint는 새로운 네트워크 경로로 전송되는 모든 패킷에 NEW_CONNECTION_ID 프레임을 포함할 수 있습니다.
Server’s Preferred Address
QUIC은 서버가 하나의 IP 주소에서 연결을 수락하고 핸드셰이크 직후 이러한 연결을 더 선호하는 주소로 전송을 시도할 수 있게 합니다. 이는 클라이언트가 처음에 여러 서버가 공유하는 주소에 연결하지만 연결 안정성을 보장하기 위해 유니캐스트 주소 사용을 선호하는 경우 특히 유용합니다. 이 섹션에서는 선호하는 서버 주소로 연결을 마이그레이션하는 프로토콜을 설명합니다.
연결 중에 새로운 서버 주소로 연결을 마이그레이션하는 것은 이 문서에서 명시된 QUIC 버전에서 지원되지 않습니다. 클라이언트가 해당 주소로의 마이그레이션을 시작하지 않았는데 새로운 서버 주소로부터 패킷을 받는 경우, 클라이언트는 이러한 패킷들을 폐기해야 합니다(SHOULD).
새로운 경로 탐사
서버는 TLS handshake에 preferred_address transport parameter를 포함하여 선호하는 주소를 전달합니다.
서버는 클라이언트가 자신의 네트워크 연결에 가장 적합한 주소를 선택할 수 있도록 각 주소 패밀리(IPv4 및 IPv6)의 선호 주소를 전달할 수 있습니다(MAY).
핸드셰이크가 확인되면, 클라이언트는 서버에서 제공한 두 주소 중 하나를 선택하고 경로 검증을 시작해야 합니다(섹션 8.2 참조). 클라이언트는 preferred_address transport parameter 또는 NEW_CONNECTION_ID 프레임에서 가져온 이전에 사용되지 않은 활성 연결 ID를 사용하여 패킷을 구성합니다.
경로 검증이 성공하는 즉시, 클라이언트는 새로운 connection ID를 사용하여 새로운 서버 주소로 모든 향후 패킷 전송을 시작해야 하며(SHOULD) 이전 서버 주소 사용을 중단해야 합니다. 경로 검증이 실패하면, 클라이언트는 서버의 원래 IP 주소로 모든 향후 패킷을 계속 전송해야 합니다(MUST).
연결 마이그레이션 시작
선호 주소로 마이그레이션하는 클라이언트는 마이그레이션하기 전에 선택한 주소를 검증해야 합니다. 섹션 21.5.3을 참조하세요.
서버는 연결을 수락한 후 언제든지 선호하는 IP 주소로 전송된 패킷을 받을 수 있습니다. 이 패킷이 PATH_CHALLENGE 프레임을 포함하는 경우, 서버는 섹션 8.2에 따라 PATH_RESPONSE 프레임을 포함하는 패킷을 전송합니다. 서버는 클라이언트로부터 선호하는 주소에서 비탐지 패킷을 받고 서버가 새로운 경로를 검증할 때까지 원래 주소에서 비탐지 패킷을 보내야 합니다.
서버는 선호하는 주소에서 클라이언트 방향의 경로를 반드시 탐지해야 합니다. 이는 공격자가 시작한 허위 마이그레이션을 방지하는 데 도움이 됩니다.
서버가 경로 검증을 완료하고 선호하는 주소에서 새로운 최대 패킷 번호를 가진 비탐지 패킷을 받으면, 서버는 선호하는 IP 주소에서만 클라이언트로 비탐지 패킷을 전송하기 시작합니다. 서버는 이 연결에 대해 이전 IP 주소에서 수신된 새로운 패킷을 삭제해야 합니다(SHOULD). 서버는 이전 IP 주소에서 수신된 지연된 패킷을 계속 처리할 수 있습니다(MAY).
서버가 preferred_address transport parameter에서 제공하는 주소들은 해당 주소들이 제공된 연결에서만 유효합니다. 클라이언트는 현재 연결에서 재개된 연결을 포함하여 다른 연결에 이러한 주소들을 사용해서는 안 됩니다.
Connection Migration에 대한 응답
클라이언트는 서버의 선호 주소로 마이그레이션하기 전에 연결 마이그레이션을 수행해야 할 수도 있습니다. 이 경우, 클라이언트는 클라이언트의 새 주소에서 원래 서버 주소와 선호 서버 주소 모두에 대해 동시에 경로 검증을 수행해야 합니다(SHOULD).
서버의 선호 주소에 대한 경로 검증이 성공하면, 클라이언트는 원래 주소의 검증을 포기하고 서버의 선호 주소 사용으로 마이그레이션해야 합니다. 서버의 선호 주소에 대한 경로 검증이 실패하지만 서버의 원래 주소 검증이 성공하면, 클라이언트는 새로운 주소로 마이그레이션하고 서버의 원래 주소로 계속 전송할 수 있습니다.
서버의 선호 주소로 수신된 패킷의 소스 주소가 핸드셰이크 동안 클라이언트에서 관찰된 것과 다른 경우, 서버는 섹션 9.3.1과 9.3.2에 설명된 잠재적 공격으로부터 보호해야 합니다. 의도적인 동시 마이그레이션 외에도, 클라이언트의 액세스 네트워크가 서버의 선호 주소에 대해 다른 NAT 바인딩을 사용했기 때문에 이런 상황이 발생할 수도 있습니다.
서버는 다른 주소로부터 프로브 패킷을 수신했을 때 클라이언트의 새 주소에 대한 경로 검증을 시작해야 합니다(SHOULD). 섹션 8을 참조하세요.
새 주소로 마이그레이션하는 클라이언트는 서버에 대해 동일한 주소 패밀리의 선호 주소를 사용해야 합니다(SHOULD).
preferred_address 전송 매개변수에서 제공된 connection ID는 제공된 주소에 국한되지 않습니다. 이 connection ID는 클라이언트가 마이그레이션을 위해 사용할 수 있는 connection ID를 확보하도록 제공되지만, 클라이언트는 이 connection ID를 임의의 경로에서 사용할 수 있습니다.
피어 주소 스푸핑
QUIC은 IPv6를 사용하여 데이터를 전송하는 엔드포인트가 로컬 API에서 IPv6 플로우 레이블 설정을 허용하지 않는 경우를 제외하고는 RFC 6437에 따라 IPv6 플로우 레이블을 적용해야 한다고 권장합니다.
안타깝게도 Java API는 IPv6 flow label 설정을 허용하지 않습니다.
비목표
다음은 QUIC RFC 9000에서 복사된 내용입니다. 각 섹션을 검토하고 편집하십시오.
QUIC의 목표는 안전한 전송 연결을 제공하는 것입니다. 섹션 21.1은 이러한 속성들에 대한 개요를 제공하며, 후속 섹션들에서는 알려진 공격과 대응책에 대한 설명을 포함하여 이러한 속성들에 관한 제약 사항과 주의점들을 논의합니다.
경로상 주소 스푸핑
QUIC의 완전한 보안 분석은 이 문서의 범위를 벗어납니다. 이 섹션은 구현자들을 돕고 프로토콜 분석을 안내하기 위해 원하는 보안 속성에 대한 비공식적인 설명을 제공합니다.
QUIC는 SEC-CONS에 설명된 위협 모델을 가정하고, 해당 모델에서 발생하는 많은 공격에 대한 보호를 제공합니다.
이러한 목적을 위해 공격은 수동적 공격과 능동적 공격으로 나뉩니다. 수동적 공격자는 네트워크에서 패킷을 읽을 수 있는 능력을 가지고 있는 반면, 능동적 공격자는 네트워크에 패킷을 쓸 수 있는 능력도 가지고 있습니다. 하지만 수동적 공격에는 연결을 구성하는 패킷이 통과하는 경로에서 라우팅 변경이나 기타 수정을 발생시킬 수 있는 능력을 가진 공격자가 포함될 수 있습니다.
공격자는 추가적으로 경로상 공격자(on-path attacker) 또는 경로외 공격자(off-path attacker)로 분류됩니다. 경로상 공격자는 관찰하는 패킷을 읽고, 수정하거나 제거하여 해당 패킷이 더 이상 목적지에 도달하지 못하도록 할 수 있는 반면, 경로외 공격자는 패킷을 관찰하지만 원본 패킷이 의도된 목적지에 도달하는 것을 막을 수는 없습니다. 두 유형의 공격자 모두 임의의 패킷을 전송할 수도 있습니다. 이 정의는 경로외 공격자가 패킷을 관찰할 수 있다는 점에서 SEC-CONS의 섹션 3.5와 다릅니다.
핸드셰이크, 보호된 패킷, 그리고 연결 마이그레이션의 속성들은 별도로 고려됩니다.
Off-Path 패킷 포워딩
QUIC handshake는 TLS 1.3 handshake를 통합하고 TLS13의 부록 E.1에서 설명된 암호화 속성들을 상속받습니다. QUIC의 많은 보안 속성들은 TLS handshake가 이러한 속성들을 제공하는 것에 의존합니다. TLS handshake에 대한 모든 공격은 QUIC에 영향을 미칠 수 있습니다.
세션 키의 기밀성이나 고유성, 또는 참여 피어의 인증을 손상시키는 TLS handshake에 대한 모든 공격은 해당 키에 의존하는 QUIC이 제공하는 다른 보안 보장에 영향을 미칩니다. 예를 들어, 마이그레이션(섹션 9)은 네트워크 경로 간 연결 가능성을 방지하기 위해 TLS handshake를 사용한 키 협상과 QUIC 패킷 보호 모두에 대한 기밀성 보호의 효과에 의존합니다.
TLS 핸드셰이크의 무결성에 대한 공격은 공격자가 애플리케이션 프로토콜이나 QUIC 버전 선택에 영향을 미칠 수 있게 할 수 있습니다.
TLS에서 제공하는 속성들 외에도, QUIC 핸드셰이크는 핸드셰이크에 대한 DoS 공격에 대해 일정한 방어 기능을 제공합니다.
손실 감지 및 혼잡 제어
주소 검증(섹션 8)은 특정 주소를 주장하는 엔티티가 해당 주소에서 패킷을 수신할 수 있는지 확인하는 데 사용됩니다. 주소 검증은 증폭 공격 대상을 공격자가 패킷을 관찰할 수 있는 주소로 제한합니다.
주소 검증 이전에는 엔드포인트가 전송할 수 있는 내용이 제한됩니다. 엔드포인트는 검증되지 않은 주소로 해당 주소로부터 수신한 데이터의 3배를 초과하는 데이터를 전송할 수 없습니다.
참고: 증폭 방지 제한은 엔드포인트가 검증되지 않은 주소로부터 수신된 패킷에 응답할 때만 적용됩니다. 증폭 방지 제한은 새로운 연결을 설정하거나 연결 마이그레이션을 시작할 때 클라이언트에는 적용되지 않습니다.
연결 마이그레이션의 프라이버시 영향
전체 handshake를 위한 서버의 첫 번째 flight 계산은 서명과 키 교환 계산을 모두 필요로 하므로 잠재적으로 비용이 많이 들 수 있습니다. 계산적 DoS 공격을 방지하기 위해 Retry 패킷은 저렴한 토큰 교환 메커니즘을 제공하여 서버가 단일 왕복 비용으로 값비싼 계산을 수행하기 전에 클라이언트의 IP 주소를 검증할 수 있도록 합니다. 성공적인 handshake 후, 서버는 클라이언트에게 새로운 토큰을 발급할 수 있으며, 이를 통해 이러한 비용 없이 새로운 연결 설정이 가능합니다.
서버의 선호 주소
경로상 또는 경로외 공격자는 Initial 패킷을 교체하거나 경합시켜 핸드셰이크 실패를 강제할 수 있습니다. 유효한 Initial 패킷이 교환된 후에는 후속 Handshake 패킷들이 Handshake 키로 보호되며, 경로상 공격자는 엔드포인트가 시도를 포기하도록 패킷을 드롭하는 것 외에는 핸드셰이크 실패를 강제할 수 없습니다.
경로 상의 공격자는 양쪽의 패킷 주소를 교체할 수도 있으며, 따라서 클라이언트나 서버가 원격 주소에 대해 잘못된 정보를 갖게 할 수 있습니다. 이러한 공격은 NAT에서 수행하는 기능과 구별할 수 없습니다.
선호 주소 전달
전체 핸드셰이크는 암호학적으로 보호되며, Initial 패킷은 버전별 키로 암호화되고 Handshake 및 이후 패킷은 TLS 키 교환에서 파생된 키로 암호화됩니다. 또한 매개변수 협상이 TLS transcript에 포함되어 일반적인 TLS 협상과 동일한 무결성 보장을 제공합니다. 공격자는 클라이언트의 전송 매개변수를 관찰할 수 있지만(버전별 salt를 알고 있는 경우) 서버의 전송 매개변수는 관찰할 수 없으며 매개변수 협상에 영향을 줄 수 없습니다.
Connection ID는 모든 패킷에서 암호화되지 않지만 무결성이 보호됩니다.
이 버전의 QUIC는 버전 협상 메커니즘을 포함하지 않습니다. 호환되지 않는 버전의 구현은 단순히 연결 설정에 실패합니다.
선호 주소로의 마이그레이션
패킷 보호(섹션 12.1)는 버전 협상 패킷을 제외한 모든 패킷에 인증된 암호화를 적용하지만, Initial 및 Retry 패킷은 버전별 키 자료 사용으로 인해 제한된 보호를 받습니다. 자세한 내용은 QUIC-TLS를 참조하세요. 이 섹션에서는 보호된 패킷에 대한 수동적 및 능동적 공격을 다룹니다.
경로상 공격자와 경로외 공격자 모두 관찰된 패킷을 저장하여 향후 패킷 보호에 대한 오프라인 공격을 수행하는 수동적 공격을 시도할 수 있습니다. 이는 모든 네트워크에서 모든 패킷을 관찰하는 모든 관찰자에게 해당됩니다.
연결에 대한 유효한 패킷을 관찰할 수 없이 패킷을 주입하는 공격자는 성공할 가능성이 낮습니다. 패킷 보호 기능이 핸드셰이크 중에 설정된 키 자료를 소유한 엔드포인트만이 유효한 패킷을 생성할 수 있도록 보장하기 때문입니다(섹션 7 및 21.1.1 참조). 마찬가지로, 패킷을 관찰하고 해당 패킷에 새로운 데이터를 삽입하거나 기존 데이터를 수정하려고 시도하는 능동적 공격자는 Initial 패킷을 제외하고는 수신 엔드포인트에서 유효하다고 간주되는 패킷을 생성할 수 없어야 합니다.
스푸핑 공격은 능동적인 공격자가 전달하거나 주입하는 패킷의 보호되지 않은 부분(예: 송신지 또는 목적지 주소)을 다시 쓰는 공격으로, 공격자가 원래 엔드포인트로 패킷을 전달할 수 있는 경우에만 효과적입니다. 패킷 보호는 패킷 페이로드가 핸드셰이크를 완료한 엔드포인트에서만 처리될 수 있도록 보장하며, 유효하지 않은 패킷은 해당 엔드포인트에서 무시됩니다.
공격자는 패킷과 UDP 데이터그램 간의 경계를 수정하여 여러 패킷을 단일 데이터그램으로 병합하거나 병합된 패킷을 여러 데이터그램으로 분할할 수도 있습니다. 패딩이 필요한 Initial 패킷을 포함하는 데이터그램을 제외하고는, 데이터그램 내 패킷 배치 방식의 수정이 연결에 기능적인 영향을 주지는 않지만 일부 성능 특성을 변경할 수는 있습니다.
클라이언트 마이그레이션과 선호 주소의 상호작용
연결 마이그레이션(섹션 9)은 엔드포인트가 여러 경로에서 IP 주소와 포트 간에 전환할 수 있는 기능을 제공하며, 비프로빙 프레임의 전송 및 수신을 위해 한 번에 하나의 경로를 사용합니다. 경로 검증(섹션 8.2)은 피어가 특정 경로로 전송된 패킷을 수신할 의지와 능력이 모두 있음을 확인합니다. 이는 스푸핑된 주소로 전송되는 패킷의 수를 제한하여 주소 스푸핑의 영향을 줄이는 데 도움이 됩니다.
이 섹션은 다양한 유형의 DoS 공격 하에서 연결 마이그레이션의 의도된 보안 속성을 설명합니다.
IPv6 Flow Label 및 마이그레이션 사용
공격자가 관찰한 패킷이 더 이상 의도된 목적지에 도달하지 못하도록 할 수 있다면, 이는 on-path 공격자로 간주됩니다. 공격자가 클라이언트와 서버 사이에 존재할 때, 엔드포인트들은 주어진 경로에서 연결성을 설정하기 위해 공격자를 통해 패킷을 전송해야 합니다.
경로상 공격자는 다음을 할 수 있습니다:
패킷 검사
IP 및 UDP 패킷 헤더 수정
새로운 패킷 주입
패킷 지연
패킷 재정렬
패킷 드롭
패킷 경계를 따라 데이터그램을 분할하고 병합
경로상 공격자는 다음을 할 수 없습니다:
- 패킷의 인증된 부분을 수정하여 수신자가 해당 패킷을 받아들이도록 하는 것
경로상 공격자는 관찰하는 패킷을 수정할 기회를 가지고 있지만, 패킷의 인증된 부분에 대한 모든 수정은 패킷 페이로드가 인증되고 암호화되어 있기 때문에 수신 종단점에서 유효하지 않은 것으로 간주되어 폐기됩니다.
QUIC는 경로상 공격자의 능력을 다음과 같이 제한하는 것을 목표로 합니다:
경로상의 공격자는 연결에 대한 경로 사용을 방해하여, 공격자가 포함되지 않은 다른 경로를 사용할 수 없는 경우 연결이 실패하도록 만들 수 있습니다. 이는 모든 패킷을 드롭하거나, 복호화가 실패하도록 패킷을 수정하거나, 기타 방법을 통해 달성할 수 있습니다.
경로상 공격자는 새로운 경로에서 경로 검증을 실패하게 만들어서, 공격자가 역시 경로상에 있는 새로운 경로로의 마이그레이션을 방지할 수 있습니다.
경로상 공격자는 클라이언트가 공격자가 경로상에 있지 않은 경로로 마이그레이션하는 것을 방지할 수 없다.
경로상의 공격자는 패킷을 지연시키거나 드롭하여 연결의 처리량을 감소시킬 수 있습니다.
경로상 공격자는 패킷의 인증된 부분을 수정한 패킷을 엔드포인트가 수락하도록 할 수 없다.
Off-Path Active Attacks
오프-패스 공격자는 클라이언트와 서버 사이의 경로에 직접적으로 위치하지는 않지만, 클라이언트와 서버 간에 전송되는 일부 또는 모든 패킷의 사본을 획득할 수 있습니다. 또한 이러한 패킷의 사본을 양쪽 종단점 중 하나로 전송할 수도 있습니다.
경로 외부 공격자는 다음을 할 수 있습니다:
패킷 검사
새로운 패킷 주입
삽입된 패킷 재정렬
경로 외부 공격자는 다음을 할 수 없습니다:
엔드포인트에서 전송된 패킷 수정
패킷 지연
패킷 드롭
원본 패킷 재정렬
경로 외부 공격자는 관찰한 패킷의 수정된 복사본을 생성하고, 위조된 소스 및 목적지 주소와 함께 해당 복사본을 네트워크에 주입할 수 있습니다.
이 논의의 목적상, 경로 외부 공격자(off-path attacker)가 네트워크에 수정된 패킷 복사본을 주입할 수 있는 능력을 가지고 있으며, 이 패킷이 공격자가 관찰한 원본 패킷이 도착하기 전에 목적지 엔드포인트에 도달할 것이라고 가정합니다. 다시 말해, 공격자는 엔드포인트 간의 정당한 패킷들과의 경쟁에서 지속적으로 “승리"할 수 있는 능력을 가지고 있어, 잠재적으로 원본 패킷이 수신자에 의해 무시되도록 할 수 있습니다.
또한 공격자가 NAT 상태에 영향을 미치는 데 필요한 리소스를 가지고 있다고 가정합니다. 특히 공격자는 엔드포인트가 NAT 바인딩을 잃게 한 다음, 자신의 트래픽에 사용하기 위해 동일한 포트를 획득할 수 있습니다.
QUIC은 경로 외부 공격자(off-path attacker)의 능력을 다음과 같이 제한하는 것을 목표로 합니다:
경로 외부 공격자는 패킷을 경쟁시켜 “제한적인” 경로상 공격자가 되려고 시도할 수 있습니다.
경로 외부 공격자는 클라이언트와 서버 간의 연결성을 개선할 수 있는 한, 자신의 주소를 소스 주소로 나열한 전달된 패킷에 대해 경로 검증이 성공하도록 할 수 있습니다.
핸드셰이크가 완료된 후에는 off-path 공격자가 연결을 종료시킬 수 없습니다.
경로 외부 공격자는 새로운 경로를 관찰할 수 없다면 새로운 경로로의 마이그레이션을 실패하게 만들 수 없습니다.
경로 외부 공격자는 자신이 마찬가지로 경로 외부 공격자인 새로운 경로로의 마이그레이션 중에 제한된 경로상 공격자가 될 수 있습니다.
오프패스 공격자는 클라이언트가 원래 사용했던 동일한 IP 주소와 포트에서 서버로 패킷을 보내도록 공유 NAT 상태에 영향을 주어 제한적인 온패스 공격자가 될 수 있습니다.
보안 속성 개요
제한된 경로상 공격자는 서버와 클라이언트 간의 원본 패킷을 복제하고 전달하여 패킷 라우팅을 개선한다고 제안하는 경로외 공격자로, 이로 인해 해당 패킷들이 원본 복사본보다 먼저 도착하게 되어 목적지 엔드포인트에서 원본 패킷들이 드롭되도록 합니다.
제한된 경로상 공격자(limited on-path attacker)는 엔드포인트 간의 원본 경로상에 위치하지 않는다는 점에서 경로상 공격자(on-path attacker)와 다르며, 따라서 엔드포인트에서 전송된 원본 패킷들은 여전히 목적지에 도달합니다. 이는 향후 복사된 패킷들을 원본 경로보다 빠르게 목적지로 라우팅하는 데 실패하더라도 원본 패킷들이 목적지에 도달하는 것을 막지 않는다는 것을 의미합니다.
제한된 경로상 공격자는 다음을 할 수 있습니다:
패킷 검사
새로운 패킷 주입
암호화되지 않은 패킷 헤더 수정
패킷 재정렬
제한된 경로상 공격자는 다음을 할 수 없습니다:
원래 경로로 전송된 패킷보다 늦게 도착하도록 패킷을 지연시킴
패킷 드롭
패킷의 인증되고 암호화된 부분을 수정하여 수신자가 해당 패킷을 수락하도록 만드는 것
제한된 경로상 공격자는 중복 패킷이 도착하기 전에 원본 패킷이 도착하는 지점까지만 패킷을 지연시킬 수 있으며, 이는 원본 경로보다 더 나쁜 지연 시간을 가진 라우팅을 제공할 수 없음을 의미합니다. 제한된 경로상 공격자가 패킷을 드롭하더라도 원본 사본은 여전히 목적지 엔드포인트에 도착할 것입니다.
QUIC는 제한된 경로 외 공격자의 능력을 다음과 같이 제한하는 것을 목표로 합니다:
핸드셰이크가 완료된 후에는 제한된 경로상 공격자가 연결을 강제로 종료시킬 수 없습니다.
제한된 경로상 공격자는 클라이언트가 먼저 활동을 재개하는 경우 유휴 연결을 종료시킬 수 없습니다.
제한된 경로상 공격자는 서버가 먼저 활동을 재개하는 경우 유휴 연결이 손실된 것으로 간주되도록 할 수 있습니다.
이러한 보장은 동일한 이유로 모든 NAT에 대해 제공되는 것과 같은 보장입니다.
핸드셰이크
암호화되고 인증된 전송 방식으로서 QUIC은 서비스 거부 공격에 대한 다양한 보호 기능을 제공합니다. 암호화 핸드셰이크가 완료되면 QUIC 엔드포인트는 인증되지 않은 대부분의 패킷을 폐기하여 공격자가 기존 연결을 방해할 수 있는 능력을 크게 제한합니다.
연결이 설정되면 QUIC 엔드포인트는 일부 인증되지 않은 ICMP 패킷을 수락할 수 있지만(섹션 14.2.1 참조), 이러한 패킷의 사용은 매우 제한적입니다. 엔드포인트가 수락할 수 있는 유일한 다른 유형의 패킷은 stateless reset(섹션 10.3)이며, 이는 토큰이 사용될 때까지 비밀로 유지되는 것에 의존합니다.
연결 생성 중에 QUIC는 네트워크 경로 외부로부터의 공격에 대한 보호만을 제공합니다. 모든 QUIC 패킷은 수신자가 상대방으로부터 이전 패킷을 확인했다는 증명을 포함합니다.
주소는 핸드셰이크 중에 변경될 수 없으므로, 엔드포인트는 다른 네트워크 경로로 수신된 패킷을 폐기할 수 있습니다.
Source와 Destination Connection ID 필드는 핸드셰이크 중 경로 외 공격(off-path attack)에 대한 주요 보호 수단입니다. 섹션 8.1을 참조하십시오. 이들은 피어가 설정한 값과 일치해야 합니다. Initial과 Stateless Reset을 제외하고, 엔드포인트는 이전에 엔드포인트가 선택한 값과 일치하는 Destination Connection ID 필드를 포함한 패킷만 수락합니다. 이것이 Version Negotiation 패킷에 제공되는 유일한 보호입니다.
Initial 패킷의 Destination Connection ID 필드는 클라이언트가 예측 불가능하도록 선택하며, 이는 추가적인 목적을 제공합니다. 암호화 핸드셰이크를 전달하는 패킷들은 이 connection ID와 QUIC 버전에 특정한 salt로부터 파생된 키로 보호됩니다. 이를 통해 엔드포인트는 암호화 핸드셰이크가 완료된 후 사용하는 것과 동일한 프로세스를 사용하여 수신한 패킷을 인증할 수 있습니다. 인증할 수 없는 패킷은 폐기됩니다. 이러한 방식으로 패킷을 보호하는 것은 패킷 발신자가 Initial 패킷을 보았고 이를 이해했다는 강력한 보증을 제공합니다.
이러한 보호 기능은 연결이 설정되기 전에 QUIC 패킷을 수신할 수 있는 공격자에 대해 효과적이지 않도록 의도되었습니다. 이러한 공격자는 QUIC 엔드포인트에서 수락될 수 있는 패킷을 잠재적으로 전송할 수 있습니다. 이 버전의 QUIC는 이러한 종류의 공격을 탐지하려고 시도하지만, 엔드포인트가 복구하는 대신 연결 설정에 실패할 것으로 예상합니다. 대부분의 경우, 암호화 handshake 프로토콜 QUIC-TLS이 handshake 중 변조를 탐지할 책임이 있습니다.
엔드포인트는 handshake 간섭을 감지하고 복구를 시도하기 위해 다른 방법을 사용할 수 있습니다. 유효하지 않은 패킷은 다른 방법을 사용하여 식별하고 폐기할 수 있지만, 이 문서에서는 특정 방법을 의무화하지 않습니다.
증폭 방지
공격자는 서버로부터 주소 검증 토큰(Section 8)을 받은 후 해당 토큰을 획득하는 데 사용했던 IP 주소를 해제할 수 있습니다. 나중에 공격자는 동일한 주소를 스푸핑하여 서버와 0-RTT 연결을 시작할 수 있는데, 이 주소는 이제 다른 (피해자) 엔드포인트를 가리킬 수 있습니다. 따라서 공격자는 서버가 초기 혼잡 윈도우 크기만큼의 데이터를 피해자에게 전송하도록 유발할 가능성이 있습니다.
서버는 주소 검증 토큰의 사용량과 수명을 제한하여 이 공격에 대한 완화책을 제공해야 합니다(SHOULD). 섹션 8.1.3을 참조하세요.
서버 측 DoS
수신하지 않은 패킷을 승인하는 엔드포인트는 혼잡 제어기가 네트워크가 지원하는 것을 넘어서는 속도로 전송을 허용하게 할 수 있습니다. 엔드포인트는 이러한 동작을 감지하기 위해 패킷을 전송할 때 패킷 번호를 건너뛸 수 있습니다(MAY). 그러면 엔드포인트는 PROTOCOL_VIOLATION 유형의 연결 오류로 즉시 연결을 닫을 수 있습니다. 섹션 10.2를 참조하십시오.
경로상 핸드셰이크 종료
요청 위조 공격은 엔드포인트가 피어로 하여금 피해자를 향한 요청을 발행하도록 하는 공격으로, 이때 요청은 해당 엔드포인트에 의해 제어됩니다. 요청 위조 공격은 공격자가 피어의 기능에 접근할 수 있도록 하는 것을 목표로 하며, 이는 공격자가 직접적으로는 사용할 수 없는 기능일 수 있습니다. 네트워킹 프로토콜에서 요청 위조 공격은 종종 네트워크에서 피어의 위치로 인해 피해자가 피어에게 부여한 암시적 권한을 악용하는 데 사용됩니다.
요청 위조가 효과적이려면, 공격자가 피어가 보내는 패킷과 이러한 패킷이 전송되는 위치에 영향을 미칠 수 있어야 합니다. 공격자가 제어된 페이로드로 취약한 서비스를 대상으로 할 수 있다면, 해당 서비스는 공격자의 피어에게 귀속되지만 공격자가 결정하는 작업을 수행할 수 있습니다.
예를 들어, 웹에서 사이트 간 요청 위조 CSRF 공격은 클라이언트가 인증 쿠키 COOKIE를 포함한 요청을 발행하도록 하여, 한 사이트가 다른 사이트로 제한되어야 할 정보와 동작에 접근할 수 있게 합니다.
QUIC은 UDP 위에서 실행되므로, 주요 우려되는 공격 방식은 공격자가 피어가 UDP 데이터그램을 보내는 주소를 선택할 수 있고 해당 패킷의 보호되지 않은 콘텐츠 일부를 제어할 수 있는 경우입니다. QUIC 엔드포인트가 보내는 대부분의 데이터는 보호되므로, 여기에는 암호문에 대한 제어도 포함됩니다. 공격자가 피어로 하여금 데이터그램의 콘텐츠를 기반으로 특정 작업을 수행할 호스트에 UDP 데이터그램을 보내도록 할 수 있다면 공격이 성공한 것입니다.
이 섹션에서는 QUIC이 요청 위조 공격에 사용될 수 있는 방법들에 대해 논의합니다.
이 섹션은 또한 QUIC 엔드포인트에서 구현할 수 있는 제한적인 대응책에 대해서도 설명합니다. 이러한 완화 조치는 요청 위조 공격의 잠재적 대상이 조치를 취하지 않더라도 QUIC 구현 또는 배포에서 일방적으로 사용할 수 있습니다. 그러나 UDP 기반 서비스가 요청을 적절히 인증하지 않는 경우 이러한 대응책은 불충분할 수 있습니다.
섹션 21.5.4에서 설명한 마이그레이션 공격은 매우 강력하며 적절한 대응책이 없기 때문에, QUIC 서버 구현체들은 공격자가 임의의 목적지로 임의의 UDP 페이로드를 생성하도록 할 수 있다고 가정해야 합니다. QUIC 서버는 ingress filtering BCP38을 배포하지 않고 또한 부적절하게 보안된 UDP 엔드포인트를 가진 네트워크에 배포되어서는 안 됩니다.
클라이언트가 취약한 엔드포인트와 동일한 위치에 있지 않다는 것을 일반적으로 보장할 수는 없지만, 이 버전의 QUIC은 서버 마이그레이션을 허용하지 않아 클라이언트에 대한 스푸핑된 마이그레이션 공격을 방지합니다. 서버 마이그레이션을 허용하는 향후 확장은 반드시 위조 공격에 대한 대응책도 정의해야 합니다.
파라미터 협상
QUIC는 공격자가 피어가 UDP 데이터그램을 보내는 위치에 영향을 주거나 제어할 수 있는 몇 가지 기회를 제공합니다:
초기 연결 설정 (Section 7), 여기서 서버는 클라이언트가 데이터그램을 보낼 위치를 선택할 수 있습니다 – 예를 들어, DNS 레코드를 채움으로써;
선호 주소 (Section 9.6), 서버가 클라이언트가 데이터그램을 보낼 위치를 선택할 수 있는 경우;
spoofed connection migrations (Section 9.3.1), 여기서 클라이언트가 소스 주소 스푸핑을 사용하여 서버가 후속 데이터그램을 보낼 위치를 선택할 수 있습니다; 그리고
서버가 Version Negotiation 패킷을 전송하도록 하는 스푸핑된 패킷 (Section 21.5.5).
모든 경우에서 공격자는 자신의 피어가 QUIC을 이해하지 못할 수 있는 피해자에게 데이터그램을 보내도록 할 수 있습니다. 즉, 이러한 패킷들은 주소 검증 이전에 피어에 의해 전송됩니다. 섹션 8을 참조하세요.
패킷의 암호화된 부분 외부에서 QUIC는 엔드포인트가 피어가 보내는 UDP 데이터그램의 내용을 제어할 수 있는 여러 옵션을 제공합니다. Destination Connection ID 필드는 피어가 보낸 패킷의 초기 부분에 나타나는 바이트에 대한 직접적인 제어를 제공합니다(섹션 5.1 참조). Initial 패킷의 Token 필드는 서버가 Initial 패킷의 다른 바이트들을 제어할 수 있게 합니다(섹션 17.2.2 참조).
이 버전의 QUIC에는 패킷의 암호화된 부분에 대한 간접적인 제어를 방지하는 조치가 없습니다. 엔드포인트가 피어가 보내는 프레임의 내용을 제어할 수 있다고 가정해야 하며, 특히 STREAM 프레임과 같이 애플리케이션 데이터를 전달하는 프레임들을 제어할 수 있다고 봐야 합니다. 이는 어느 정도 애플리케이션 프로토콜의 세부 사항에 따라 다르지만, 많은 프로토콜 사용 상황에서 일부 제어가 가능합니다. 공격자가 패킷 보호 키에 접근할 수 있으므로, 피어가 향후 패킷을 어떻게 암호화할지 예측할 수 있을 가능성이 높습니다. 데이터그램 내용에 대한 성공적인 제어는 공격자가 패킷 번호와 패킷 내 프레임 배치를 어느 정도의 신뢰성을 가지고 예측할 수 있기만 하면 됩니다.
이 섹션에서는 데이터그램 내용에 대한 제어를 제한하는 것이 실현 가능하지 않다고 가정합니다. 후속 섹션의 완화 조치들은 주소 검증 이전에 전송되는 데이터그램이 요청 위조에 사용될 수 있는 방법들을 제한하는 데 중점을 둡니다.
보호된 패킷
서버 역할을 하는 공격자는 자신의 가용성을 광고하는 IP 주소와 포트를 선택할 수 있으므로, 클라이언트로부터의 Initial 패킷은 이런 종류의 공격에 사용 가능한 것으로 간주됩니다. 핸드셰이크에 내재된 주소 검증은 새로운 연결에 대해 클라이언트가 QUIC을 이해하지 못하거나 QUIC 연결을 받아들이려 하지 않는 목적지로 다른 유형의 패킷을 전송하지 않도록 보장합니다.
초기 패킷 보호(QUIC-TLS의 섹션 5.2)는 서버가 클라이언트에서 보낸 Initial 패킷의 내용을 제어하기 어렵게 만듭니다. 예측 불가능한 Destination Connection ID를 선택하는 클라이언트는 서버가 클라이언트로부터의 Initial 패킷의 암호화된 부분을 제어할 수 없도록 보장합니다.
그러나 Token 필드는 서버 제어에 열려 있으며 서버가 클라이언트를 사용하여 요청 위조 공격을 수행할 수 있도록 허용합니다. NEW_TOKEN 프레임(섹션 8.1.3)과 함께 제공되는 토큰의 사용은 연결 설정 중 요청 위조를 위한 유일한 옵션을 제공합니다.
그러나 클라이언트는 NEW_TOKEN 프레임을 사용할 의무가 없습니다. NEW_TOKEN 프레임이 수신되었을 때와 서버 주소가 변경된 경우 클라이언트가 빈 Token 필드를 전송하면 Token 필드에 의존하는 요청 위조 공격을 방지할 수 있습니다.
클라이언트는 서버 주소가 변경되는 경우 NEW_TOKEN 사용을 피할 수 있습니다. 그러나 Token 필드를 포함하지 않으면 성능에 악영향을 미칠 수 있습니다. 서버는 NEW_TOKEN에 의존하여 데이터 전송의 3배 제한을 초과하는 데이터 전송을 가능하게 할 수 있습니다. 섹션 8.1을 참조하세요. 특히, 이는 클라이언트가 0-RTT를 사용하여 서버로부터 데이터를 요청하는 경우에 영향을 미칩니다.
Retry 패킷(섹션 17.2.5)을 전송하는 것은 서버에게 Token 필드를 변경할 수 있는 옵션을 제공합니다. Retry를 전송한 후, 서버는 클라이언트로부터 오는 후속 Initial 패킷의 Destination Connection ID 필드도 제어할 수 있습니다. 이는 또한 Initial 패킷의 암호화된 콘텐츠에 대한 간접적인 제어를 허용할 수 있습니다. 그러나 Retry 패킷의 교환은 서버의 주소를 검증하여, 후속 Initial 패킷이 요청 위조에 사용되는 것을 방지합니다.
연결 마이그레이션
서버는 선호하는 주소를 지정할 수 있으며, 클라이언트는 핸드셰이크를 확인한 후 해당 주소로 이전합니다. 섹션 9.6을 참조하세요. 클라이언트가 선호하는 주소로 보내는 패킷의 Destination Connection ID 필드는 요청 위조에 사용될 수 있습니다.
클라이언트는 해당 주소를 검증하기 전에 선호 주소로 비탐지(non-probing) 프레임을 전송해서는 안 됩니다(MUST NOT). 섹션 8을 참조하세요. 이는 서버가 데이터그램의 암호화된 부분을 제어할 수 있는 옵션을 크게 줄여줍니다.
이 문서는 선호 주소 사용과 관련하여 특정되고 엔드포인트에서 구현할 수 있는 추가적인 대응책을 제공하지 않습니다. 섹션 21.5.6에서 설명된 일반적인 조치들을 추가 완화 방안으로 사용할 수 있습니다.
경로상 능동 공격
클라이언트는 서버가 해당 주소로 데이터그램을 전송하도록 하기 위해 명백한 연결 마이그레이션의 일부로 위조된 소스 주소를 제시할 수 있습니다.
서버가 이후에 이 스푸핑된 주소로 보내는 모든 패킷의 Destination Connection ID 필드는 요청 위조에 사용될 수 있습니다. 클라이언트는 또한 암호문에 영향을 미칠 수 있습니다.
주소 검증 이전에 주소에 대해 probing 패킷(섹션 9.1)만 전송하는 서버는 공격자에게 데이터그램의 암호화된 부분에 대한 제한적인 제어권만을 제공합니다. 그러나 특히 NAT rebinding의 경우, 이는 성능에 부정적인 영향을 미칠 수 있습니다. 서버가 애플리케이션 데이터를 포함하는 프레임을 전송하는 경우, 공격자는 데이터그램 내용의 대부분을 제어할 수 있을 것입니다.
이 문서는 섹션 21.5.6에서 설명된 일반적인 조치를 제외하고는 엔드포인트에서 구현할 수 있는 구체적인 대응책을 제공하지 않습니다. 그러나 네트워크 수준에서의 주소 스푸핑에 대한 대응책, 특히 ingress filtering BCP38은 스푸핑을 사용하고 외부 네트워크에서 발생하는 공격에 대해 특히 효과적입니다.
경로 외부 능동 공격
패킷에서 위조된 소스 주소를 제시할 수 있는 클라이언트는 서버가 해당 주소로 Version Negotiation 패킷(섹션 17.2.1)을 보내도록 할 수 있습니다.
알려지지 않은 버전의 패킷에 대한 connection ID 필드의 크기 제한이 없다는 것은 클라이언트가 결과 데이터그램에서 제어하는 데이터의 양을 증가시킵니다. 이 패킷의 첫 번째 바이트는 클라이언트 제어 하에 있지 않고 다음 네 바이트는 0이지만, 클라이언트는 다섯 번째 바이트부터 최대 512바이트까지 제어할 수 있습니다.
이 공격에 대한 특정 대응책은 제공되지 않지만, 일반적인 보호 방법(섹션 21.5.6)이 적용될 수 있습니다. 이 경우 ingress filtering BCP38도 효과적입니다.
제한된 경로상 능동 공격
요청 위조 공격에 대한 가장 효과적인 방어는 취약한 서비스를 수정하여 강력한 인증을 사용하는 것입니다. 그러나 이것이 항상 QUIC 배포의 제어 범위 내에 있는 것은 아닙니다. 이 섹션에서는 QUIC 엔드포인트가 일방적으로 취할 수 있는 몇 가지 다른 단계들을 설명합니다. 이러한 추가 단계들은 상황에 따라 정당한 사용을 방해하거나 막을 수 있기 때문에 모두 재량적입니다.
루프백 인터페이스를 통해 제공되는 서비스는 종종 적절한 인증이 부족합니다. 엔드포인트는 루프백 주소로의 연결 시도나 마이그레이션을 방지할 수 있습니다(MAY). 엔드포인트는 동일한 서비스가 이전에 다른 인터페이스에서 사용 가능했거나 해당 주소가 루프백이 아닌 주소의 서비스에서 제공된 경우 루프백 주소로의 연결이나 마이그레이션을 허용해서는 안 됩니다(SHOULD NOT). 이러한 기능에 의존하는 엔드포인트는 이러한 보호 기능을 비활성화하는 옵션을 제공할 수 있습니다.
마찬가지로, 엔드포인트는 글로벌, unique-local RFC4193, 또는 비사설 주소에서 link-local 주소 RFC4291 또는 사설 사용 범위 RFC1918의 주소로 변경되는 것을 잠재적인 요청 위조 시도로 간주할 수 있습니다. 엔드포인트는 이러한 주소들의 사용을 완전히 거부할 수 있지만, 이는 정당한 사용을 방해할 상당한 위험을 수반합니다. 엔드포인트는 특정 범위에서 검증되지 않은 주소로 데이터그램을 전송하는 것이 안전하지 않다는 네트워크에 대한 구체적인 지식이 없는 한 주소 사용을 거부해서는 안 됩니다(SHOULD NOT).
엔드포인트는 Initial 패킷에 NEW_TOKEN 프레임의 값을 포함하지 않거나 주소 검증 완료 이전의 패킷에서만 probing 프레임을 전송함으로써 요청 위조의 위험을 줄이는 것을 선택할 수 있습니다. 이것이 공격자가 Destination Connection ID 필드를 공격에 사용하는 것을 방지하지는 않는다는 점에 주의하십시오.
엔드포인트는 요청 위조 공격의 취약한 대상이 될 수 있는 서버의 위치에 대한 구체적인 정보를 가지고 있을 것으로 예상되지 않습니다. 그러나 시간이 지나면서 공격의 일반적인 대상이 되는 특정 UDP 포트나 공격에 사용되는 데이터그램의 특정 패턴을 식별하는 것이 가능할 수 있습니다. 엔드포인트는 대상 주소를 검증하기 전에 이러한 포트로 데이터그램을 전송하지 않거나 이러한 패턴과 일치하는 데이터그램을 전송하지 않도록 선택할 수 있습니다(MAY). 엔드포인트는 문제가 있는 것으로 알려진 패턴을 포함하는 연결 ID를 사용하지 않고 폐기할 수 있습니다(MAY).
참고: 이러한 보호 기능을 적용하기 위해 엔드포인트를 수정하는 것이 네트워크 기반 보호를 배포하는 것보다 더 효율적입니다. 엔드포인트는 검증된 주소로 전송할 때 추가적인 처리를 수행할 필요가 없기 때문입니다.
핸드셰이크 서비스 거부 공격
일반적으로 Slowloris SLOWLORIS로 알려진 공격은 대상 엔드포인트에 많은 연결을 열어두고 가능한 한 오랫동안 유지하려고 시도합니다. 이러한 공격은 비활성으로 인한 연결 종료를 피하기 위해 필요한 최소한의 활동을 생성하여 QUIC 엔드포인트에 대해 실행될 수 있습니다. 이는 소량의 데이터 전송, 송신자 속도를 제어하기 위해 플로우 제어 윈도우를 점진적으로 열기, 또는 높은 손실률을 시뮬레이션하는 ACK 프레임을 조작하는 것을 포함할 수 있습니다.
QUIC 배포에서는 서버가 허용할 최대 클라이언트 수 증가, 단일 IP 주소가 만들 수 있는 연결 수 제한, 연결이 가져야 하는 최소 전송 속도에 대한 제한 부과, 엔드포인트가 연결을 유지할 수 있는 시간 길이 제한과 같은 Slowloris 공격에 대한 완화 조치를 제공해야 합니다(SHOULD).
증폭 공격
악의적인 발송자가 의도적으로 스트림 데이터의 일부분을 전송하지 않아서, 수신자가 전송되지 않은 데이터에 대해 리소스를 할당하게 만들 수 있습니다. 이는 불균형적인 수신 버퍼 메모리 할당 및/또는 수신자에서 크고 비효율적인 데이터 구조의 생성을 야기할 수 있습니다.
악의적인 수신자는 송신자가 재전송을 위해 확인되지 않은 스트림 데이터를 저장하도록 강제하려는 시도로 스트림 데이터를 포함한 패킷을 의도적으로 확인하지 않을 수 있습니다.
수신자에 대한 공격은 flow control 윈도우가 사용 가능한 메모리에 대응할 때 완화됩니다. 그러나 일부 수신자는 메모리를 과다 할당하고 실제 사용 가능한 메모리를 초과하는 총합의 flow control 오프셋을 광고할 것입니다. 과다 할당 전략은 엔드포인트가 올바르게 동작할 때 더 나은 성능으로 이어질 수 있지만, 엔드포인트를 스트림 분할 공격에 취약하게 만듭니다.
QUIC 배포는 스트림 단편화 공격에 대한 완화 조치를 제공해야 합니다(SHOULD). 완화 조치는 메모리 과다 할당 방지, 추적 데이터 구조의 크기 제한, STREAM 프레임의 재조립 지연, 재조립 홀의 수명과 지속 시간에 기반한 휴리스틱 구현, 또는 이들의 조합으로 구성될 수 있습니다.
낙관적 ACK 공격
악의적인 endpoint는 많은 수의 스트림을 열어 endpoint의 상태를 고갈시킬 수 있습니다. 악의적인 endpoint는 TCP의 SYN flooding 공격과 유사한 방식으로 많은 수의 연결에서 이 과정을 반복할 수 있습니다.
일반적으로 클라이언트는 섹션 2.1에서 설명한 대로 스트림을 순차적으로 열 것입니다. 그러나 여러 스트림이 짧은 간격으로 시작될 때, 손실이나 재정렬로 인해 스트림을 여는 STREAM 프레임이 순서대로 수신되지 않을 수 있습니다. 더 높은 번호의 스트림 ID를 수신하면, 수신자는 같은 유형의 모든 중간 스트림을 열어야 합니다. 섹션 3.2를 참조하세요. 따라서 새 연결에서 스트림 4000000을 열면 100만 개와 1개의 클라이언트 시작 양방향 스트림이 열립니다.
활성 스트림의 수는 섹션 4.6에서 설명된 바와 같이 수신된 MAX_STREAMS 프레임에 의해 업데이트된 initial_max_streams_bidi 및 initial_max_streams_uni 전송 매개변수에 의해 제한됩니다. 신중하게 선택된다면, 이러한 제한은 스트림 커밋 공격의 효과를 완화합니다. 그러나 제한을 너무 낮게 설정하면 애플리케이션이 많은 수의 스트림을 열기를 기대할 때 성능에 영향을 줄 수 있습니다.
요청 위조 공격
QUIC과 TLS는 모두 일부 상황에서 정당한 용도를 가진 프레임이나 메시지를 포함하고 있지만, 이러한 프레임이나 메시지는 연결 상태에 관찰 가능한 영향을 주지 않으면서 피어가 처리 리소스를 소모하도록 악용될 수 있습니다.
메시지는 또한 플로우 제어 한도에 작은 증분을 전송하는 것과 같이 작거나 중요하지 않은 방식으로 상태를 변경하고 되돌리는 데 사용될 수도 있습니다.
처리 비용이 대역폭 소비나 상태에 미치는 영향에 비해 불균형적으로 클 경우, 악의적인 peer가 처리 용량을 고갈시킬 수 있습니다.
모든 메시지에는 정당한 사용 목적이 있지만, 구현체들은 진행 상황 대비 처리 비용을 추적해야 하며(SHOULD) 비생산적인 패킷의 과도한 양을 공격의 징후로 간주해야 합니다. 엔드포인트는 이러한 상황에 연결 오류로 응답하거나 패킷을 드롭하여 대응할 수 있습니다(MAY).
엔드포인트 제어 옵션
경로상 공격자가 IP 헤더의 ECN 필드 값을 조작하여 송신자의 전송률에 영향을 줄 수 있습니다. RFC3168에서는 조작과 그 영향에 대해 더 자세히 논의하고 있습니다.
제한된 경로상 공격자는 송신자의 전송률에 영향을 주기 위해 수정된 ECN 필드가 포함된 패킷을 복제하여 전송할 수 있습니다. 수신자가 중복 패킷을 폐기하는 경우, 공격자는 이 공격이 성공하려면 중복 패킷과 원본 패킷 간의 경쟁에서 승리해야 합니다. 따라서 QUIC 엔드포인트는 해당 IP 패킷 내 최소 하나의 QUIC 패킷이 성공적으로 처리되지 않는 한 IP 패킷의 ECN 필드를 무시합니다. 섹션 13.4를 참조하십시오.
Client Initial Packets을 이용한 요청 위조
Stateless reset은 TCP reset injection과 유사한 서비스 거부 공격을 가능하게 합니다. 이 공격은 공격자가 선택된 connection ID를 가진 연결에 대해 stateless reset token이 생성되도록 할 수 있는 경우에 가능합니다. 이러한 토큰이 생성되도록 할 수 있는 공격자는 동일한 connection ID를 가진 활성 연결을 재설정할 수 있습니다.
패킷이 정적 키를 공유하는 다른 인스턴스로 라우팅될 수 있는 경우 – 예를 들어, IP 주소나 포트를 변경하여 – 공격자는 서버가 stateless reset을 전송하도록 할 수 있습니다. 이러한 스타일의 서비스 거부 공격을 방어하기 위해, stateless reset을 위해 정적 키를 공유하는 엔드포인트들(섹션 10.3.2 참조)은 주어진 connection ID를 가진 패킷이 해당 연결이 더 이상 활성화되어 있지 않은 경우를 제외하고는 항상 연결 상태를 가진 인스턴스에 도착하도록 배치되어야 합니다.
더 일반적으로, 서버는 해당하는 connection ID를 가진 연결이 동일한 정적 키를 사용하는 어떤 엔드포인트에서든 활성화될 수 있는 경우 stateless reset을 생성해서는 안 됩니다.
동적 로드 밸런싱을 사용하는 클러스터의 경우, 활성 인스턴스가 연결 상태를 유지하고 있는 동안 로드 밸런서 구성이 변경될 수 있습니다. 인스턴스가 연결 상태를 유지하더라도, 라우팅의 변경과 그에 따른 stateless reset은 연결이 종료되는 결과를 가져옵니다. 패킷이 올바른 인스턴스로 라우팅될 가능성이 없다면, 연결이 타임아웃될 때까지 기다리는 것보다 stateless reset을 보내는 것이 낫습니다. 하지만 이는 라우팅이 공격자에 의해 영향을 받을 수 없는 경우에만 허용됩니다.
선호 주소를 이용한 요청 위조
이 문서는 두 엔드포인트 간에 사용되는 QUIC 버전을 협상하는 데 사용할 수 있는 QUIC Version Negotiation 패킷(섹션 6)을 정의합니다. 그러나 이 문서는 이 버전과 향후 후속 버전 간에 이러한 협상이 어떻게 수행될지 명시하지 않습니다. 특히, Version Negotiation 패킷에는 버전 다운그레이드 공격을 방지하는 메커니즘이 포함되어 있지 않습니다. Version Negotiation 패킷을 사용하는 향후 QUIC 버전은 버전 다운그레이드 공격에 대해 견고한 메커니즘을 정의해야 합니다.
스푸핑된 마이그레이션을 통한 요청 위조
배포는 공격자가 특정 서버 인스턴스에 대한 새로운 연결을 대상으로 하는 능력을 제한해야 합니다. 이상적으로는 라우팅 결정이 주소를 포함한 클라이언트가 선택한 값과 독립적으로 이루어져야 합니다. 인스턴스가 선택되면, 이후 패킷이 동일한 인스턴스로 라우팅되도록 연결 ID를 선택할 수 있습니다.
버전 협상을 통한 요청 위조
QUIC 패킷의 길이는 해당 패킷 내용의 길이에 대한 정보를 노출할 수 있습니다. PADDING 프레임은 엔드포인트가 패킷 내용의 길이를 어느 정도 모호하게 만들 수 있는 능력을 제공하기 위해 제공됩니다. 섹션 19.1을 참조하십시오.
트래픽 분석을 무력화하는 것은 어려운 일이며 활발한 연구의 주제입니다. 길이가 정보가 유출될 수 있는 유일한 방법은 아닙니다. 엔드포인트는 패킷의 타이밍과 같은 다른 사이드 채널을 통해서도 민감한 정보를 노출할 수 있습니다.
Relay Security
다음은 SSU1에서 Relay Request, Relay Response, Relay Intro, 그리고 Hole Punch에 대한 분석입니다.
제약사항: Relay가 빠른 것이 중요합니다. 왕복 시간을 최소화해야 합니다. 대역폭과 CPU는 그만큼 중요하지 않습니다.
SSU 1: Alice가 먼저 introducer Bob에게 연결하면, Bob이 요청을 Charlie(방화벽으로 보호됨)에게 릴레이합니다. 홀 펀치 후, Alice와 Charlie 간에 직접 설정과 같이 세션이 설정됩니다.
Alice Bob Charlie
1. RelayRequest ---------------------->
2. <-------------- RelayResponse RelayIntro ----------->
3. <-------------------------------------------- HolePunch
4. SessionRequest -------------------------------------------->
5. <-------------------------------------------- SessionCreated
6. SessionConfirmed ------------------------------------------>
인증: Relay Request와 Relay Response는 Alice와 Bob이 일반적으로 기존 세션을 갖지 않기 때문에 안전하게 인증되지 않으며, 이러한 메시지들은 공개된 intro key를 사용합니다. 세션이 존재하는 경우 세션 내 Relay Request/Response가 허용되고 선호됩니다.
Bob에서 Charlie로의 Relay Intro는 기존 세션에 있어야 하므로 안전하다고 가정됩니다.
Bob은 Relay Intro를 위조하거나 Relay Request에서 IP/포트를 변경할 수 있습니다. 요청을 intro에 암호학적으로 바인딩하거나 악의적인 Bob을 방지하거나 탐지하는 메커니즘은 존재하지 않습니다.
Bob의 router hash는 현재 Charlie의 Router Info에 게시되어 있지 않으므로, Alice-Bob 메시지를 인증하려면 이를 추가해야 합니다. 또한 다른 SSU2 매개변수들이 Charlie의 Router Info에 게시되어야 하거나, Alice가 네트워크 데이터베이스에서 Bob의 Router Info를 조회해야 하므로 추가적인 지연이 발생합니다. 인증은 Alice와 Bob 사이에 왕복 통신을 추가하게 됩니다.
Bob을 통해 Alice의 router hash를 Charlie에게 전달함으로써, Charlie는 로컬 차단 목록을 확인하여 Alice로부터의 연결을 수신할지 여부를 보다 쉽게 결정할 수 있습니다. Charlie가 Bob을 통해 Alice에게 거부 응답을 보내서 relay를 거부할 수 있는 메커니즘은 없습니다. Charlie가 Bob을 통해 Alice에게 수락 응답을 보내서 relay를 수락할 수 있는 메커니즘은 없습니다. Alice는 HolePunch를 기다리거나, 단순히 SessionRequest를 맹목적으로 보내야 합니다. NAT로 인해 HolePunch가 Alice가 예상했던 것과 다른 포트에서 올 수 있으며, 이는 HolePunch가 어떤 router에서 왔는지 인식하는 것을 어렵게 만들 수 있습니다.
Alice는 Relay Request에서 자신의 전체 Router Info를 Bob에게 보낼 수 있으며, 이는 Relay Intro에서 Charlie에게 전달됩니다.
Relay Request에는 타임스탬프가 포함되어 있지 않으므로 재생 공격 방지 기능이 없습니다. 소스 IP를 스푸핑하여 Charlie가 임의의 IP/포트로 Hole Punch를 보내도록 할 수 있습니다. Relay Request는 서명되지 않으며, 서명되고 타임스탬프가 있더라도 Charlie는 서명을 검증할 수 있는 전체 Router Identity를 갖고 있지 않습니다.
프로토콜은 0-255바이트의 가변 길이 챌린지 필드를 정의합니다. Relay Request의 챌린지는 Relay Intro에서 Charlie에게 전달됩니다. 그러나 프로토콜은 챌린지를 생성, 사용 또는 검증하는 방법을 명시하지 않으며, 이는 구현되지 않았습니다. HolePunch에 챌린지가 포함되어 있다면, Alice는 HolePunch를 Charlie와 쉽게 연관시킬 수 있을 것입니다.
4바이트 nonce는 8바이트 연결 ID로 교체되거나 보완되어야 할 수 있습니다.
빈 Hole Punch 메시지는 고유하며 경로상의 관찰자들이 프로토콜을 식별하는 데 사용될 수 있으므로, 이는 변경되어야 합니다.
추가 DPI 논의
다음은 SSU1에서 Peer Test에 대한 분석입니다.
제약 사항: Peer Test가 빠르거나, 저대역폭이거나, 저CPU 사용량일 필요는 특별히 없습니다. 다만 router 시작 시에는 예외일 수 있는데, 이때는 router가 자신의 도달 가능성을 상당히 빠르게 발견하는 것을 선호합니다.
SSU 1:
Alice Bob Charlie
1. PeerTest ------------------->
2. PeerTest-------------------->
3. <-------------------PeerTest
4. <-------------------PeerTest
5. <------------------------------------------PeerTest
6. PeerTest------------------------------------------>
7. <------------------------------------------PeerTest
SSU1 사양을 따르기 어렵기 때문에 아래에 메시지 내용을 문서화합니다.
| 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 |
| 인증: Alice는 항상 기존 세션이 있는 Bob을 선택할 것입니다. Bob은 확립된 세션이 없는 피어로부터의 PeerTest를 거부할 것입니다. 메시지 1은 세션 내에서 전송됩니다. 따라서 메시지 1은 안전하고 인증됩니다. |
Bob은 기존 세션이 있는 Charlie를 선택합니다. 메시지 2와 3은 세션 내에서 전송됩니다. 따라서 메시지 2와 3은 안전하고 인증됩니다.
메시지 4는 세션 내에서 전송되어야 합니다. 그러나 SSU 1 명세서는 이전에 Alice의 공개된 intro key로 전송한다고 명시했는데, 이는 세션 외 전송을 의미합니다. 0.9.52 이전에는 Java I2P가 실제로 intro key로 전송했습니다. 0.9.52부터는 명세서에서 세션 키를 사용해야 한다고 명시하고 있으며, Java I2P는 0.9.52부터 메시지를 세션 내에서 전송합니다.
Alice는 테스트가 진행되려면 Charlie와 기존 세션이 없어야 합니다. Bob이 Alice와 세션이 있는 Charlie를 선택하면 Alice는 테스트를 중단합니다. 따라서 메시지 5-7은 안전하지 않고 인증되지 않습니다.
모든 Peer Test 메시지에는 Alice가 선택한 4바이트 nonce가 포함됩니다. 이 nonce는 암호화 목적으로 사용되지 않습니다.
메시지 5-7에 대한 가능한 공격: 연구가 필요함.
Alice의 router hash는 Charlie에게 알려지지 않았습니다. Charlie의 router hash는 Alice에게 알려지지 않았습니다. Alice-Charlie 메시지가 인증되기를 원한다면 이것들이 프로토콜에 추가되어야 합니다. 또한, 다른 SSU2 매개변수들이 Peer Test 메시지에 제공되어야 하거나, Charlie가 네트워크 데이터베이스에서 Alice의 Router Info를 조회해야 하며, 이는 추가적인 지연을 발생시킵니다. 인증은 Charlie와 Alice 간에 라운드트립을 추가할 것입니다.
Alice의 router hash를 Charlie에게 전달함으로써, Charlie는 로컬 차단 목록을 확인하여 Alice와 Peer Test에 참여할지 여부를 더 쉽게 결정할 수 있습니다.
4바이트 nonce는 8바이트 연결 ID로 교체되거나 보완될 필요가 있을 수 있습니다.
Relay and Peer Test Design Goals
Relay와 Peer Test는 비슷한 구조를 가지고 있습니다. 두 경우 모두 Alice가 Bob에게 Charlie로 서비스 요청을 전달해달라고 요청하고, 그러면 Charlie가 해당 요청에 따라 행동합니다.
현재 SSU1 Peer Test 문제점들:
- Peer Test는 악의적인 Bob에 대한 보호 기능이 없습니다
- Peer Test는 Bob이나 Charlie가 요청을 거부할 방법이 없습니다
- Peer Test는 Alice가 Charlie의 신원을 알거나 Alice가 Charlie를 거부할 방법이 없습니다
- Peer Test는 Charlie가 Alice의 신원을 알거나 Charlie가 Alice를 거부할 방법이 없습니다
- Peer Test는 자체적인 임시방편 재전송 방식을 사용합니다
- Peer Test는 어떤 메시지가 어떤 상태에 해당하는지 알기 위해 복잡한 상태 머신이 필요합니다
- Charlie가 자신을 거부했다는 사실을 모르면, Alice는 테스트를 실패로 간주할 것입니다.
현재 SSU1 Relay 문제들:
위에 나열된 Peer Test 문제들 대부분이 Peer Test에도 적용됩니다.
우리는 Relay와 Peer Test의 보안을 개선하기 위해 다음과 같은 목표를 가지고 있습니다:
Charlie는 Alice가 필요시 정보를 검증할 수 있도록 자신의 introducer들(Bob들)에 대한 충분한 정보를 netDb에 게시해야 한다. 예를 들어, 각 introducer에 대한 라우터 해시를 게시하면 Alice가 시간이 허락할 때 netDb에서 라우터 정보를 가져올 수 있게 된다.
Alice에서 Bob으로의 요청을 스푸핑, 변조, 위조 또는 재전송할 수 있는 주소 스푸핑이나 경로상 위협으로부터 보호합니다. Bob은 Alice가 실제 I2P router이며 제시된 요청과 테스트 주소가 유효한지 확인해야 합니다.
악의적인 Bob이 Charlie에게 전달되는 요청을 스푸핑, 변조, 위조 또는 재생할 수 있는 공격으로부터 보호합니다. Charlie는 Alice와 Bob이 모두 실제 I2P router이며 제시된 요청과 테스트 주소가 유효한지 확인해야 합니다.
Bob은 요청을 검증하고 수락하거나 거부할 수 있도록 Alice로부터 충분한 정보를 받아야 합니다. Bob은 수락 또는 거부를 Alice에게 다시 전송할 수 있는 메커니즘을 가져야 합니다. Bob은 요청된 작업을 수행하도록 요구받아서는 안 됩니다.
Charlie는 요청을 검증하고 승인하거나 거부할 수 있도록 Bob으로부터 충분한 정보를 받아야 합니다. Charlie는 승인 또는 거부를 Bob에게 다시 보내어 Alice에게 전달할 수 있는 메커니즘을 가져야 합니다. Charlie는 요청된 작업을 수행하도록 요구받아서는 안 됩니다.
Alice는 Bob을 통해 전달된 응답이 실제로 Charlie로부터 발생했음을 검증할 수 있어야 한다.
Alice와 Charlie는 후속 직접 메시지들(Bob을 통해 릴레이되지 않은)이 예상된 소스로부터 온 것이며 실제 I2P router들임을 검증할 수 있어야 합니다.
다음 메커니즘들이 이러한 목표 달성에 도움이 될 수 있습니다:
타임스탬프
라우터 서명 키를 사용한 서명
요청에 포함된 challenge 데이터 사용
라우터 암호화 키를 사용한 암호화
IP와 포트뿐만 아니라 router 해시, Router Identity, 또는 Router Info 전송.
네트워크 데이터베이스를 조회하여 router 정보 검증
라우터 정보, IP, 포트를 차단 목록과 대조하여 확인
속도 제한
세션 설정 요구
이러한 가능한 메커니즘들은 Relay 또는 Peer Test 기능의 처리 시간과 지연시간을 증가시킬 수 있습니다. 모든 영향을 평가해야 합니다.
가능하다면 버전 간 릴레이 및 피어 테스트도 지원되어야 합니다. 이는 SSU 1에서 SSU 2로의 점진적 전환을 촉진할 것입니다. 가능한 버전 조합은 다음과 같습니다:
| 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 |
보안 목표
Summary
우리는 영감, 지침, 그리고 코드 재사용을 위해 I2P 내부와 외부 표준의 여러 기존 프로토콜에 의존하고 있습니다:
위협 모델: NTCP2 NTCP2에서 시작하여, QUIC RFC 9000 RFC 9001에서 분석된 UDP 전송과 관련된 중요한 추가 위협들을 포함.
암호화 선택사항: NTCP2에서 참조.
Handshake: NTCP2와 NOISE의 Noise XK. UDP가 제공하는 캡슐화(고유한 메시지 경계) 덕분에 NTCP2의 상당한 단순화가 가능합니다.
핸드셰이크 임시 키 난독화: NTCP2에서 적용되었으나 AES 대신 ECIES의 ChaCha20을 사용합니다.
ECIES에서와 같이 AEAD 연관 데이터로 사용되는 헤더.
패킷 번호 매기기: WireGuard WireGuard와 QUIC RFC 9000 RFC 9001에서 적용됨.
메시지: SSU에서 각색됨
I2NP Fragmentation: SSU에서 적용됨
릴레이 및 피어 테스팅: SSU에서 적용됨
Relay 및 Peer Test 데이터의 서명: 공통 구조 사양에서 Common
Acks, nacks: QUIC RFC 9000에서 채택됨.
플로우 제어: TBD
I2P에서 이전에 사용되지 않은 새로운 암호화 기본 요소는 없습니다.
주소 검증
다른 I2P 전송 방식인 NTCP, NTCP2, SSU 1과 마찬가지로, 이 전송 방식은 순서가 보장된 바이트 스트림 전송을 위한 범용 기능이 아닙니다. I2NP 메시지 전송을 위해 설계되었습니다. “스트림” 추상화는 제공되지 않습니다.
또한 SSU의 경우, 피어 지원 NAT 통과 및 도달 가능성 테스트(인바운드 연결)를 위한 추가 기능을 포함합니다.
SSU 1의 경우, I2NP 메시지의 순서대로 전달을 제공하지 않습니다. 또한 I2NP 메시지의 보장된 전달도 제공하지 않습니다. 효율성을 위해, 또는 UDP 데이터그램의 순서가 바뀐 전달이나 해당 데이터그램의 손실로 인해, I2NP 메시지가 원격 끝단에 순서가 바뀐 채로 전달되거나 전혀 전달되지 않을 수 있습니다. 필요한 경우 I2NP 메시지가 여러 번 재전송될 수 있지만, 전체 연결이 끊어지지 않고도 전달이 결국 실패할 수 있습니다. 또한 다른 I2NP 메시지에 대해 재전송(손실 복구)이 발생하는 동안에도 새로운 I2NP 메시지가 계속 전송될 수 있습니다.
이 프로토콜은 I2NP 메시지의 중복 전달을 완전히 방지하지 않습니다. router는 I2NP 만료를 적용하고 I2NP 메시지 ID를 기반으로 한 Bloom filter 또는 기타 메커니즘을 사용해야 합니다. 아래의 I2NP Message Duplication 섹션을 참조하십시오.
Noise Protocol Framework
이 제안은 Noise Protocol Framework NOISE (Revision 33, 2017-10-04)를 기반으로 한 요구사항을 제공합니다. Noise는 SSU 프로토콜의 기반이 되는 Station-To-Station (STS) 프로토콜과 유사한 속성을 가지고 있습니다. Noise 용어에서 Alice는 개시자(initiator)이고, Bob은 응답자(responder)입니다.
SSU2는 Noise 프로토콜 Noise_XK_25519_ChaChaPoly_SHA256을 기반으로 합니다. (초기 키 유도 함수의 실제 식별자는 “Noise_XKchaobfse+hs1+hs2+hs3_25519_ChaChaPoly_SHA256"이며 I2P 확장을 나타냅니다 - 아래 KDF 1 섹션 참조)
참고: 이 식별자는 NTCP2에 사용되는 것과 다릅니다. 세 개의 핸드셰이크 메시지가 모두 헤더를 연관 데이터로 사용하기 때문입니다.
이 Noise 프로토콜은 다음 프리미티브들을 사용합니다:
Handshake Pattern: XK Alice가 자신의 키를 Bob에게 전송 (X) Alice는 이미 Bob의 정적 키를 알고 있음 (K)
DH Function: X25519 RFC 7748에 명시된 대로 32바이트 키 길이를 가진 X25519 DH.
Cipher Function: ChaChaPoly RFC 7539 섹션 2.8에서 명시된 AEAD_CHACHA20_POLY1305. 12바이트 nonce, 처음 4바이트는 0으로 설정.
Hash Function: SHA256 I2P에서 이미 광범위하게 사용되고 있는 표준 32바이트 해시입니다.
Additions to the Framework
이 제안은 Noise_XK_25519_ChaChaPoly_SHA256에 대한 다음 개선사항들을 정의합니다. 이들은 일반적으로 NOISE 섹션 13의 지침을 따릅니다.
핸드셰이크 메시지(Session Request, Created, Confirmed)는 16 또는 32바이트 헤더를 포함합니다.
핸드셰이크 메시지(Session Request, Created, Confirmed)의 헤더는 암호화/복호화 전에 mixHash()의 입력으로 사용되어 헤더를 메시지에 바인딩합니다.
헤더가 암호화되고 보호됩니다.
Cleartext ephemeral 키들은 알려진 키와 IV를 사용하여 ChaCha20 암호화로 난독화됩니다. 이는 elligator2보다 빠릅니다.
페이로드 형식은 메시지 1, 2, 그리고 데이터 단계에 대해 정의됩니다. 물론 이는 Noise에서 정의되지 않습니다.
데이터 단계는 Noise 데이터 단계와 유사하지만 호환되지 않는 암호화를 사용합니다.
Processing overhead estimate
추후 결정
Definitions
사용되는 암호화 구성 요소에 해당하는 다음 함수들을 정의합니다.
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
각 UDP 데이터그램은 정확히 하나의 메시지를 포함합니다. 데이터그램의 길이(IP 및 UDP 헤더 이후)는 메시지의 길이입니다. 패딩이 있는 경우, 메시지 내부의 패딩 블록에 포함됩니다. 이 문서에서는 “데이터그램"과 “패킷"이라는 용어를 대부분 같은 의미로 사용합니다. 각 데이터그램(또는 패킷)은 단일 메시지를 포함합니다(하나의 데이터그램이 여러 QUIC 패킷을 포함할 수 있는 QUIC와는 다름). “패킷 헤더"는 IP/UDP 헤더 이후의 부분입니다.
예외: Session Confirmed 메시지는 여러 패킷에 걸쳐 분할될 수 있다는 점에서 고유합니다. 자세한 내용은 아래의 Session Confirmed Fragmentation 섹션을 참조하십시오.
모든 SSU2 메시지는 최소 40바이트 길이입니다. 1-39바이트 길이의 메시지는 유효하지 않습니다. 모든 SSU2 메시지는 1472(IPv4) 또는 1452(IPv6)바이트 이하의 길이입니다. 메시지 형식은 Noise 메시지를 기반으로 하며, 프레이밍 및 구별 불가능성을 위해 수정되었습니다. 표준 Noise 라이브러리를 사용하는 구현체는 수신된 메시지를 표준 Noise 메시지 형식으로 전처리해야 합니다. 모든 암호화된 필드는 AEAD 암호문입니다.
다음 메시지들이 정의됩니다:
| 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
Alice가 Bob으로부터 이전에 받은 유효한 토큰을 가지고 있을 때의 표준 연결 설정 순서는 다음과 같습니다:
Alice Bob
SessionRequest ------------------->
<------------------- SessionCreated
SessionConfirmed ----------------->
Alice가 유효한 토큰을 가지고 있지 않을 때, 설정 순서는 다음과 같습니다:
Alice Bob
TokenRequest --------------------->
<--------------------------- Retry
SessionRequest ------------------->
<------------------- SessionCreated
SessionConfirmed ----------------->
Alice가 유효한 토큰을 가지고 있다고 생각하지만 Bob이 이를 거부하는 경우(Bob이 재시작했기 때문일 수 있음), 설정 시퀀스는 다음과 같습니다:
Alice Bob
SessionRequest ------------------->
<--------------------------- Retry
SessionRequest ------------------->
<------------------- SessionCreated
SessionConfirmed ----------------->
Bob은 이유 코드가 포함된 Termination 블록을 담은 Retry 메시지로 응답하여 Session 또는 Token Request를 거부할 수 있습니다. 이유 코드에 따라 Alice는 일정 시간 동안 다른 요청을 시도하지 않아야 합니다:
Alice Bob
SessionRequest ------------------->
<--------------------------- Retry containing a Termination block
or
TokenRequest --------------------->
<--------------------------- Retry containing a Termination block
Noise 용어를 사용하여, 설정 및 데이터 시퀀스는 다음과 같습니다: (페이로드 보안 속성)
XK(s, rs): Authentication Confidentiality
<- s
...
-> e, es 0 2
<- e, ee 2 1
-> s, se 2 5
<- 2 5
세션이 설정되면 Alice와 Bob은 Data 메시지를 교환할 수 있습니다.
Packet Header
모든 패킷은 난독화된(암호화된) 헤더로 시작됩니다. 헤더 유형은 긴 헤더와 짧은 헤더, 두 가지가 있습니다. 처음 13바이트(Destination Connection ID, 패킷 번호, 그리고 유형)는 모든 헤더에서 동일하다는 점에 주목하세요.
일반적인 요청 위조 대책
긴 헤더는 32바이트입니다. 세션이 생성되기 전에 Token Request, SessionRequest, SessionCreated, Retry에 사용됩니다. 또한 세션 외 Peer Test 및 Hole Punch 메시지에도 사용됩니다.
헤더 암호화 이전:
+----+----+----+----+----+----+----+----+
| 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 공격
짧은 헤더는 16바이트입니다. Session Created와 Data 메시지에 사용됩니다. Session Request, Retry, Peer Test와 같은 인증되지 않은 메시지는 항상 긴 헤더를 사용합니다.
16바이트가 필요한 이유는 수신자가 메시지 유형을 얻기 위해 첫 16바이트를 복호화해야 하고, 메시지 유형에서 나타내는 바와 같이 실제로 긴 헤더인 경우 추가로 16바이트를 더 복호화해야 하기 때문입니다.
Session Confirmed의 경우, 헤더 암호화 이전:
+----+----+----+----+----+----+----+----+
| 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
아래의 Session Confirmed Fragmentation 섹션에서 frag 필드에 대한 자세한 정보를 참조하세요.
Data 메시지의 경우, 헤더 암호화 이전:
+----+----+----+----+----+----+----+----+
| 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
스트림 단편화 및 재조립 공격
Connection ID는 무작위로 생성되어야 합니다. Source와 Destination ID는 동일하지 않아야 하므로, 경로상의 공격자가 패킷을 캡처하여 유효해 보이는 패킷을 발신자에게 다시 보낼 수 없습니다. Connection ID를 생성할 때 카운터를 사용하지 마십시오. 그렇지 않으면 경로상의 공격자가 유효해 보이는 패킷을 생성할 수 있습니다.
QUIC과 달리, 우리는 핸드셰이크 중이나 후에, 심지어 Retry 메시지 이후에도 연결 ID를 변경하지 않습니다. ID는 첫 번째 메시지(Token Request 또는 Session Request)부터 마지막 메시지(Termination이 포함된 Data)까지 일정하게 유지됩니다. 또한 연결 ID는 경로 챌린지나 연결 마이그레이션 중이나 후에도 변경되지 않습니다.
QUIC과 다른 점은 헤더의 connection ID가 항상 헤더 암호화된다는 것입니다. 아래를 참조하세요.
Stream Commitment 공격
핸드셰이크에서 First Packet Number 블록이 전송되지 않는 경우, 패킷은 단일 세션 내에서 각 방향별로 0부터 시작하여 최대 (2**32 -1)까지 번호가 매겨집니다. 최대 패킷 수가 전송되기 훨씬 전에 세션을 종료하고 새로운 세션을 생성해야 합니다.
핸드셰이크에서 First Packet Number 블록이 전송되면, 해당 방향에 대해 단일 세션 내에서 패킷은 해당 패킷 번호부터 시작하여 번호가 매겨집니다. 패킷 번호는 세션 중에 순환할 수 있습니다. 최대 2**32개의 패킷이 전송되어 패킷 번호가 첫 번째 패킷 번호로 다시 순환하면, 해당 세션은 더 이상 유효하지 않습니다. 최대 패킷 수가 전송되기 훨씬 전에 세션을 종료하고 새로운 세션을 생성해야 합니다.
TODO 키 로테이션, 최대 패킷 수 감소?
손실된 것으로 판단되는 handshake 패킷들은 패킷 번호를 포함한 동일한 헤더와 함께 전체가 재전송됩니다. handshake 메시지인 Session Request, Session Created, Session Confirmed는 동일한 패킷 번호와 동일한 암호화된 내용으로 재전송되어야 하므로, 응답을 암호화하는 데 동일한 연결된 해시가 사용됩니다. Retry 메시지는 절대 전송되지 않습니다.
손실된 것으로 판단되는 데이터 단계 패킷은 전체적으로 재전송되지 않습니다(종료의 경우 제외, 아래 참조). 손실된 패킷 내에 포함된 블록에도 동일하게 적용됩니다. 대신, 블록에서 전달될 수 있는 정보는 필요에 따라 새로운 패킷으로 다시 전송됩니다. 데이터 패킷은 동일한 패킷 번호로 재전송되지 않습니다. 패킷 내용의 재전송(내용이 동일하게 유지되는지 여부와 관계없이)은 반드시 다음 사용되지 않은 패킷 번호를 사용해야 합니다.
동일한 패킷 번호로 변경되지 않은 전체 패킷을 그대로 재전송하는 것은 여러 가지 이유로 허용되지 않습니다. 배경 정보는 QUIC RFC 9000 섹션 12.3을 참조하십시오.
- 재전송을 위해 패킷을 저장하는 것은 비효율적입니다
- 새로운 패킷 데이터는 경로상의 관찰자에게 다르게 보이므로, 재전송된 것인지 알 수 없습니다
- 새로운 패킷은 이전 ack 블록이 아닌 업데이트된 ack 블록과 함께 전송됩니다
- 필요한 부분만 재전송합니다. 일부 fragment는 이미 한 번 재전송되어 ack를 받았을 수 있습니다
- 더 많은 데이터가 대기 중인 경우 각 재전송 패킷에 필요한 만큼 담을 수 있습니다
- 중복 탐지 목적으로 모든 개별 패킷을 추적하는 엔드포인트는 과도한 상태 누적의 위험이 있습니다. 중복 탐지에 필요한 데이터는 최소 패킷 번호를 유지하여 해당 번호 미만의 모든 패킷을 즉시 삭제함으로써 제한할 수 있습니다.
- 이 방식은 훨씬 더 유연합니다
새로운 패킷들은 손실된 것으로 판단된 정보를 전달하는 데 사용됩니다. 일반적으로, 해당 정보를 포함한 패킷이 손실된 것으로 판단될 때 정보가 다시 전송되며, 해당 정보를 포함한 패킷이 remain the same) 확인응답될 때 전송이 중단됩니다.
예외: Termination 블록을 포함하는 데이터 단계 패킷은 전체를 그대로 재전송할 수 있지만 필수는 아닙니다. 아래 Session Termination 섹션을 참조하십시오.
다음 패킷들은 무시되는 랜덤 패킷 번호를 포함합니다:
- Session Request
- Session Created
- Token Request
- Retry
- Peer Test
- Hole Punch
Alice의 경우, 아웃바운드 패킷 번호는 Session Confirmed와 함께 0부터 시작됩니다. Bob의 경우, 아웃바운드 패킷 번호는 첫 번째 Data 패킷과 함께 0부터 시작되며, 이는 Session Confirmed의 ACK여야 합니다. 표준 핸드셰이크 예시에서 패킷 번호는 다음과 같습니다:
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.
핸드셰이크 메시지(SessionRequest, SessionCreated 또는 SessionConfirmed)의 재전송은 동일한 패킷 번호로 변경 없이 다시 전송되어야 합니다. 이러한 메시지를 재전송할 때 다른 ephemeral 키를 사용하거나 페이로드를 변경하지 마십시오.
피어 서비스 거부 공격
헤더(난독화 및 보호 이전)는 헤더를 데이터에 암호학적으로 바인딩하기 위해 AEAD 함수의 연관 데이터에 항상 포함됩니다.
명시적 혼잡 알림 공격
헤더 암호화는 여러 목표를 가지고 있습니다. 배경과 가정에 대해서는 위의 “Additional DPI Discussion” 섹션을 참조하세요.
- 온라인 DPI가 프로토콜을 식별하는 것을 방지
- 핸드셰이크 재전송을 제외하고, 동일한 연결에서 일련의 메시지들의 패턴을 방지
- 서로 다른 연결에서 동일한 유형 메시지들의 패턴을 방지
- netDb에 있는 introduction key에 대한 지식 없이는 핸드셰이크 헤더의 복호화를 방지
- netDb에 있는 introduction key에 대한 지식 없이는 X25519 임시 키의 식별을 방지
- 온라인 또는 오프라인 공격자에 의한 데이터 단계 패킷 번호 및 타입의 복호화를 방지
- netDb에 있는 introduction key에 대한 지식 없이는 경로상 또는 경로외 관찰자가 유효한 핸드셰이크 패킷을 주입하는 것을 방지
- 경로상 또는 경로외 관찰자가 유효한 데이터 패킷을 주입하는 것을 방지
- 들어오는 패킷의 신속하고 효율적인 분류 허용
- 잘못된 Session Request에 대해 응답이 없거나, Retry 응답이 있더라도 netDb에 있는 introduction key에 대한 지식 없이는 해당 응답을 I2P로 식별할 수 없도록 하는 “프로빙” 저항성 제공
- Destination Connection ID는 중요한 데이터가 아니며, netDb에 있는 introduction key에 대한 지식을 가진 관찰자가 이를 복호화할 수 있어도 문제없음
- 데이터 단계 패킷의 패킷 번호는 AEAD nonce이며 중요한 데이터입니다. netDb에 있는 introduction key에 대한 지식을 가진 관찰자라도 이를 복호화할 수 없어야 합니다. Nonces 참조.
헤더는 네트워크 데이터베이스에 게시된 알려진 키 또는 나중에 계산된 키로 암호화됩니다. 핸드셰이크 단계에서 이는 DPI 저항만을 위한 것으로, 키가 공개적이고 키와 논스가 재사용되므로 사실상 단순한 난독화입니다. 헤더 암호화는 또한 임시 키 X(Session Request에서)와 Y(Session Created에서)를 난독화하는 데 사용된다는 점에 유의하십시오.
추가 지침은 아래의 인바운드 패킷 처리 섹션을 참조하세요.
모든 헤더의 바이트 0-15는 QUIC RFC 9001 및 Nonces와 유사하게 ChaCha20을 사용하여 알려진 키로부터 계산된 데이터와 XOR 연산을 통해 헤더 보호 방식으로 암호화됩니다. 이를 통해 암호화된 짧은 헤더와 긴 헤더의 첫 번째 부분이 무작위로 나타나도록 보장합니다.
Session Request와 Session Created의 경우, long header의 16-31바이트와 32바이트 Noise ephemeral key는 ChaCha20을 사용하여 암호화됩니다. 암호화되지 않은 데이터는 무작위이므로, 암호화된 데이터는 무작위로 보일 것입니다.
Retry의 경우, long header의 16-31바이트는 ChaCha20을 사용하여 암호화됩니다. 암호화되지 않은 데이터는 무작위이므로, 암호화된 데이터도 무작위로 보일 것입니다.
QUIC RFC 9001 헤더 보호 방식과 달리, 목적지 및 소스 연결 ID를 포함한 모든 헤더의 모든 부분이 암호화됩니다. QUIC RFC 9001과 Nonces는 주로 헤더의 “중요한” 부분, 즉 패킷 번호(ChaCha20 nonce)를 암호화하는 데 중점을 둡니다. 세션 ID를 암호화하면 수신 패킷 분류가 다소 복잡해지지만, 일부 공격을 더 어렵게 만듭니다. QUIC는 서로 다른 단계와 경로 챌린지 및 연결 이전을 위해 다른 연결 ID를 정의합니다. 여기서는 연결 ID가 암호화되므로 전체적으로 동일한 연결 ID를 사용합니다.
7개의 헤더 보호 키 단계가 있습니다:
- Session Request와 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 |
| 헤더 암호화는 복잡한 휴리스틱이나 대체 방법 없이 인바운드 패킷의 신속한 분류를 가능하게 하도록 설계되었습니다. 이는 거의 모든 인바운드 메시지에 동일한 k_header_1 키를 사용함으로써 달성됩니다. 실제 IP 변경이나 NAT 동작으로 인해 연결의 소스 IP나 포트가 변경되더라도, connection ID의 단일 조회를 통해 패킷을 세션에 신속하게 매핑할 수 있습니다. |
Session Created와 Retry는 Connection ID를 복호화하기 위해 k_header_1에 대한 fallback 처리가 필요한 유일한 메시지입니다. 이들은 송신자(Bob)의 intro key를 사용하기 때문입니다. 다른 모든 메시지는 k_header_1에 대해 수신자의 intro key를 사용합니다. fallback 처리는 소스 IP/포트별로 대기 중인 아웃바운드 연결을 조회하기만 하면 됩니다.
소스 IP/포트에 의한 폴백 처리가 대기 중인 아웃바운드 연결을 찾지 못하는 경우, 여러 가지 원인이 있을 수 있습니다:
- SSU2 메시지가 아님
- 손상된 SSU2 메시지
- 응답이 공격자에 의해 스푸핑되거나 수정됨
- Bob이 대칭 NAT를 사용함
- Bob이 메시지 처리 중에 IP 또는 포트를 변경함
- Bob이 다른 인터페이스로 응답을 전송함
k_header_1을 사용하여 대기 중인 아웃바운드 연결을 찾고 해당 연결의 connection ID를 복호화하는 추가적인 폴백 처리가 가능하지만, 이는 아마도 필요하지 않을 것입니다. Bob이 자신의 NAT이나 패킷 라우팅에 문제가 있다면, 연결이 실패하도록 두는 것이 더 나을 것입니다. 이 설계는 엔드포인트들이 핸드셰이크 기간 동안 안정적인 주소를 유지한다는 것에 의존합니다.
추가 가이드라인은 아래의 Inbound Packet Handling 섹션을 참조하세요.
해당 단계의 헤더 암호화 키 도출에 대해서는 아래의 개별 KDF 섹션을 참조하세요.
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])
이 KDF는 패킷의 마지막 24바이트를 두 ChaCha20 연산의 IV로 사용합니다. 모든 패킷이 16바이트 MAC로 끝나므로, 모든 패킷 페이로드는 최소 8바이트여야 합니다. 이 요구사항은 아래 메시지 섹션에서 추가로 문서화되어 있습니다.
버전 다운그레이드
헤더의 처음 8바이트를 복호화한 후, 수신자는 Destination Connection ID를 알게 됩니다. 그 시점부터 수신자는 세션의 키 단계(key phase)를 기반으로 헤더의 나머지 부분에 사용할 헤더 암호화 키를 알게 됩니다.
헤더의 다음 8바이트를 복호화하면 메시지 유형이 드러나고 짧은 헤더인지 긴 헤더인지 판단할 수 있습니다. 긴 헤더인 경우, 수신자는 version 및 netid 필드를 검증해야 합니다. version이 != 2이거나 netid가 != 예상 값(일반적으로 2, 테스트 네트워크 제외)인 경우, 수신자는 메시지를 폐기해야 합니다.
Packet Integrity
모든 메시지는 3개 또는 4개의 부분을 포함합니다:
- 메시지 헤더
- Session Request와 Session Created에만 해당하는 임시 키
- ChaCha20으로 암호화된 페이로드
- Poly1305 MAC
모든 경우에 헤더(그리고 존재하는 경우 임시 키)는 전체 메시지가 손상되지 않았음을 보장하기 위해 인증 MAC에 바인딩됩니다.
- handshake 메시지인 Session Request, Session Created, Session Confirmed의 경우, 메시지 헤더는 Noise 처리 단계 이전에 mixHash()됩니다
- ephemeral key가 존재하는 경우, 표준 Noise misHash()로 처리됩니다
- Noise handshake 외부의 메시지의 경우, 헤더는 ChaCha20/Poly1305 암호화를 위한 Associated Data로 사용됩니다.
인바운드 패킷 핸들러는 메시지를 처리하기 전에 항상 ChaCha20 페이로드를 복호화하고 MAC을 검증해야 하며, 한 가지 예외가 있습니다: 유효하지 않은 토큰을 포함한 Session Request 메시지로 보이는 주소 스푸핑된 패킷으로부터의 DoS 공격을 완화하기 위해, 핸들러는 전체 메시지를 복호화하고 검증을 시도할 필요가 없습니다 (ChaCha20/Poly1305 복호화에 더해 비용이 많이 드는 DH 연산이 필요함). 핸들러는 Session Request 메시지의 헤더에서 찾은 값을 사용하여 Retry 메시지로 응답할 수 있습니다.
Authenticated Encryption
세 개의 개별적인 인증된 암호화 인스턴스(CipherStates)가 있습니다. 하나는 핸드셰이크 단계 중에 사용되고, 두 개(송신 및 수신)는 데이터 단계에 사용됩니다. 각각은 KDF에서 생성된 고유한 키를 가집니다.
암호화/인증된 데이터는 다음과 같이 표현됩니다
+----+----+----+----+----+----+----+----+
| |
+ +
| Encrypted and authenticated data |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
라우팅을 통한 표적 공격
암호화되고 인증된 데이터 형식.
암호화/복호화 함수의 입력값들:
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
암호화 함수의 출력, 복호화 함수의 입력:
+----+----+----+----+----+----+----+----+
| |
+ +
| 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
ChaCha20의 경우, 여기에 설명된 내용은 TLS RFC 7905에서도 유사하게 사용되는 RFC 7539에 해당합니다.
트래픽 분석
ChaCha20은 스트림 암호이므로 평문을 패딩할 필요가 없습니다. 추가 키스트림 바이트는 폐기됩니다.
암호화를 위한 키(256비트)는 SHA256 KDF를 통해 합의됩니다. 각 메시지에 대한 KDF의 세부 사항은 아래 별도 섹션에서 다룹니다.
AEAD Error Handling
모든 메시지에서 AEAD 메시지 크기는 미리 알려져 있습니다. AEAD 인증 실패 시, 수신자는 추가 메시지 처리를 중단하고 메시지를 폐기해야 합니다.
Bob은 반복적인 실패가 있는 IP들의 블랙리스트를 유지해야 한다.
KDF for Session Request
Key Derivation Function (KDF)은 RFC 2104에 정의된 HMAC-SHA256(key, data)을 사용하여 DH 결과로부터 handshake 단계 암호 키 k를 생성합니다. 이는 Noise 사양에 정확히 정의된 InitializeSymmetric(), MixHash(), 그리고 MixKey() 함수들입니다.
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가 Bob에게 전송하는 메시지로, handshake의 첫 번째 메시지이거나 Retry 메시지에 대한 응답입니다. Bob은 Session Created 메시지로 응답합니다. 크기: 80 + payload 크기. 최소 크기: 88
Alice가 유효한 토큰을 가지고 있지 않다면, Session Request 생성 시 비대칭 암호화 오버헤드를 피하기 위해 Session Request 대신 Token Request 메시지를 보내야 합니다.
긴 헤더. Noise 내용: Alice의 임시 키 X Noise 페이로드: DateTime 및 기타 블록 최대 페이로드 크기: MTU - 108 (IPv4) 또는 MTU - 128 (IPv6). 1280 MTU의 경우: 최대 페이로드는 1172 (IPv4) 또는 1152 (IPv6). 1500 MTU의 경우: 최대 페이로드는 1392 (IPv4) 또는 1372 (IPv6).
페이로드 보안 속성:
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.
X 값은 페이로드 구별 불가능성과 고유성을 보장하기 위해 암호화되며, 이는 필수적인 DPI 대응책입니다. 이를 달성하기 위해 elligator2와 같은 더 복잡하고 느린 대안 대신 ChaCha20 암호화를 사용합니다. Bob의 router 공개 키에 대한 비대칭 암호화는 너무 느릴 것입니다. ChaCha20 암호화는 netDb에 게시된 Bob의 intro 키를 사용합니다.
ChaCha20 암호화는 DPI 저항을 위한 것입니다. 네트워크 데이터베이스에 공개된 Bob의 introduction key를 아는 모든 당사자는 이 메시지의 헤더와 X 값을 복호화할 수 있습니다.
원본 내용:
+----+----+----+----+----+----+----+----+
| 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)
암호화되지 않은 데이터 (Poly1305 인증 태그는 표시되지 않음):
+----+----+----+----+----+----+----+----+
| 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 블록
- Options 블록 (선택사항)
- Relay Tag Request 블록 (선택사항)
- Padding 블록 (선택사항)
최소 페이로드 크기는 8바이트입니다. DateTime 블록은 7바이트에 불과하므로 최소한 하나의 다른 블록이 존재해야 합니다.
Notes
초기 ChaCha20 블록의 고유한 X 값은 모든 세션마다 암호문이 다르도록 보장합니다.
프로빙 저항성을 제공하기 위해, Bob은 Session Request 메시지의 메시지 타입, 프로토콜 버전, 네트워크 ID 필드가 유효하지 않은 경우 Session Request 메시지에 대한 응답으로 Retry 메시지를 보내서는 안 됩니다.
Bob은 타임스탬프 값이 현재 시간과 너무 많이 차이나는 연결을 거부해야 합니다. 최대 델타 시간을 “D"라고 합니다. Bob은 이전에 사용된 핸드셰이크 값들의 로컬 캐시를 유지하고 중복을 거부하여 재생 공격을 방지해야 합니다. 캐시의 값들은 최소 2*D의 수명을 가져야 합니다. 캐시 값은 구현에 따라 다르지만, 32바이트 X 값(또는 그에 상응하는 암호화된 값)이 사용될 수 있습니다. 영 토큰과 종료 블록을 포함한 Retry 메시지를 전송하여 거부합니다.
Diffie-Hellman 임시 키는 암호학적 공격을 방지하기 위해 절대 재사용되어서는 안 되며, 재사용 시 재생 공격으로 간주되어 거부됩니다.
“KE"와 “auth” 옵션들은 호환되어야 합니다. 즉, 공유 비밀 K는 적절한 크기여야 합니다. 더 많은 “auth” 옵션이 추가되면, 이는 “KE” 플래그의 의미를 암묵적으로 변경하여 다른 KDF나 다른 잘림 크기를 사용하게 할 수 있습니다.
Bob은 여기서 Alice의 임시 키가 곡선 상의 유효한 점인지 검증해야 합니다.
패딩은 합리적인 양으로 제한되어야 합니다. Bob은 과도한 패딩이 있는 연결을 거부할 수 있습니다. Bob은 Session Created에서 자신의 패딩 옵션을 지정할 것입니다. 최소/최대 가이드라인 TBD. 최소 0에서 31바이트까지의 랜덤 크기? (분포는 결정 예정, 부록 A 참조.) PMTU에 대해 최소 패킷 크기가 강제되지 않는 한 TODO.
대부분의 오류(AEAD, DH, 명백한 재전송 공격, 또는 키 검증 실패 포함)에서 Bob은 추가 메시지 처리를 중단하고 응답 없이 메시지를 삭제해야 합니다.
Bob은 DateTime 블록의 타임스탬프가 너무 많이 편향된 경우, 영(zero) 토큰과 클록 스큐 이유 코드를 포함한 Termination 블록이 담긴 Retry 메시지를 보낼 수 있다(MAY).
DoS 완화: DH는 상대적으로 비용이 많이 드는 연산입니다. 이전 NTCP 프로토콜과 마찬가지로, router들은 CPU나 연결 고갈을 방지하기 위해 모든 필요한 조치를 취해야 합니다. 최대 활성 연결 수와 진행 중인 최대 연결 설정 수에 제한을 두세요. 읽기 타임아웃을 강제하세요 (읽기별 및 “slowloris"에 대한 전체). 동일한 소스로부터의 반복적이거나 동시 연결을 제한하세요. 반복적으로 실패하는 소스에 대한 블랙리스트를 유지하세요. AEAD 실패에 응답하지 마세요. 또는, DH 연산과 AEAD 검증 이전에 Retry 메시지로 응답하세요.
“ver” 필드: 전체 Noise 프로토콜, 확장, 그리고 페이로드 사양을 포함한 SSU2 프로토콜로, SSU2를 나타냅니다. 이 필드는 향후 변경사항에 대한 지원을 나타내는 데 사용될 수 있습니다.
network ID 필드는 네트워크 간 연결을 빠르게 식별하는 데 사용됩니다. 이 필드가 Bob의 network ID와 일치하지 않으면, Bob은 연결을 끊고 향후 연결을 차단해야 합니다.
Bob은 Source Connection ID가 Destination Connection ID와 같을 경우 메시지를 삭제해야 합니다.
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)
연결 마이그레이션
Bob이 Session Request 메시지에 대한 응답으로 Alice에게 보냅니다. Alice는 Session Confirmed 메시지로 응답합니다. 크기: 80 + 페이로드 크기. 최소 크기: 88
Noise 내용: Bob의 임시 키 Y Noise 페이로드: DateTime, Address, 및 기타 블록 최대 페이로드 크기: MTU - 108 (IPv4) 또는 MTU - 128 (IPv6). 1280 MTU의 경우: 최대 페이로드는 1172 (IPv4) 또는 1152 (IPv6). 1500 MTU의 경우: 최대 페이로드는 1392 (IPv4) 또는 1372 (IPv6).
페이로드 보안 속성:
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.
Y 값은 페이로드의 구별 불가능성과 고유성을 보장하기 위해 암호화되며, 이는 필요한 DPI 대응책입니다. 이를 달성하기 위해 elligator2와 같은 더 복잡하고 느린 대안보다는 ChaCha20 암호화를 사용합니다. Alice의 router 공개 키에 대한 비대칭 암호화는 너무 느릴 것입니다. ChaCha20 암호화는 netDb에 게시된 Bob의 intro key를 사용합니다.
ChaCha20 암호화는 DPI 저항용으로만 사용됩니다. network database에 게시된 Bob의 intro key를 알고 있고 Session Request의 첫 32바이트를 캡처한 당사자는 이 메시지의 Y 값을 복호화할 수 있습니다.
원본 내용:
+----+----+----+----+----+----+----+----+
| 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)
암호화되지 않은 데이터 (Poly1305 인증 태그는 표시되지 않음):
+----+----+----+----+----+----+----+----+
| 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 블록
- Address 블록
- Relay Tag 블록 (선택사항)
- New Token 블록 (선택사항)
- First Packet Number 블록 (선택사항)
- Options 블록 (선택사항)
- Termination 블록 (권장하지 않음, 대신 재시도 메시지로 전송)
- Padding 블록 (선택사항)
최소 페이로드 크기는 8바이트입니다. DateTime과 Address 블록의 총 크기가 이보다 크므로, 이 두 블록만으로도 요구사항이 충족됩니다.
Notes
Alice는 여기서 Bob의 ephemeral 키가 곡선상의 유효한 점인지 검증해야 합니다.
패딩은 합리적인 수준으로 제한되어야 합니다. Alice는 과도한 패딩이 있는 연결을 거부할 수 있습니다. Alice는 Session Confirmed에서 자신의 패딩 옵션을 명시할 것입니다. 최소/최대 가이드라인 TBD. 최소 0에서 31바이트까지의 랜덤 크기? (분포는 결정될 예정, 부록 A 참조.) PMTU에 대해 최소 패킷 크기가 강제되지 않는 한 TODO.
AEAD, DH, 타임스탬프, 명백한 재전송, 또는 키 검증 실패를 포함한 모든 오류 시, Alice는 추가 메시지 처리를 중단하고 응답 없이 연결을 종료해야 합니다.
Alice는 타임스탬프 값이 현재 시간과 너무 많이 차이나는 연결을 거부해야 합니다. 최대 델타 시간을 “D"라고 합니다. Alice는 이전에 사용된 handshake 값들의 로컬 캐시를 유지하고 중복을 거부하여 재생 공격을 방지해야 합니다. 캐시의 값들은 최소 2*D의 수명을 가져야 합니다. 캐시 값들은 구현에 따라 달라지지만, 32바이트 Y 값(또는 그것의 암호화된 동등물)이 사용될 수 있습니다.
Alice는 소스 IP와 포트가 Session Request의 목적지 IP와 포트와 일치하지 않으면 메시지를 폐기해야 합니다.
Alice는 Destination과 Source Connection ID가 Session Request의 Source와 Destination Connection ID와 일치하지 않으면 메시지를 drop해야 합니다.
Bob은 Session Request에서 Alice가 요청한 경우 relay tag 블록을 전송합니다.
Issues
- 여기에 최소/최대 패딩 옵션을 포함할까요?
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가 Session Created 메시지에 응답하여 Bob에게 전송합니다. Bob은 ACK 블록을 포함한 Data 메시지로 즉시 응답합니다. 크기: 80 + payload 크기. 최소 크기: 약 500 (최소 router info 블록 크기는 약 420바이트)
Noise 콘텐츠: Alice의 정적 키 Noise payload 파트 1: 없음 Noise payload 파트 2: Alice의 RouterInfo 및 기타 블록 최대 payload 크기: MTU - 108 (IPv4) 또는 MTU - 128 (IPv6). 1280 MTU의 경우: 최대 payload는 1172 (IPv4) 또는 1152 (IPv6). 1500 MTU의 경우: 최대 payload는 1392 (IPv4) 또는 1372 (IPv6).
페이로드 보안 속성:
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.
이것은 두 개의 ChaChaPoly 프레임을 포함합니다. 첫 번째는 Alice의 암호화된 정적 공개 키입니다. 두 번째는 Noise payload입니다: Alice의 암호화된 RouterInfo, 선택적 옵션들, 그리고 선택적 패딩입니다. 이들은 서로 다른 키를 사용하는데, 그 사이에 MixKey() 함수가 호출되기 때문입니다.
원본 내용:
+----+----+----+----+----+----+----+----+
| 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
암호화되지 않은 데이터 (Poly1305 인증 태그는 표시되지 않음):
+----+----+----+----+----+----+----+----+
| 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 블록 (첫 번째 블록이어야 함)
- Options 블록 (선택사항)
- New Token 블록 (선택사항)
- Relay Request 블록 (선택사항)
- Peer Test 블록 (선택사항)
- First Packet Number 블록 (선택사항)
- I2NP, First Fragment, 또는 Follow-on Fragment 블록 (선택사항이지만 공간이 부족할 수 있음)
- Padding 블록 (선택사항)
최소 페이로드 크기는 8바이트입니다. RouterInfo 블록이 그보다 훨씬 클 것이므로, 해당 블록만으로도 요구사항이 충족됩니다.
Notes
Bob은 일반적인 Router Info 검증을 수행해야 합니다. 서명 유형이 지원되는지 확인하고, 서명을 검증하며, 타임스탬프가 범위 내에 있는지 확인하고, 기타 필요한 검사를 수행합니다. 조각화된 Router Info 처리에 대한 참고사항은 아래를 참조하세요.
Bob은 첫 번째 프레임에서 받은 Alice의 정적 키가 Router Info의 정적 키와 일치하는지 확인해야 합니다. Bob은 먼저 Router Info에서 일치하는 버전(v) 옵션을 가진 NTCP 또는 SSU2 Router Address를 검색해야 합니다. 아래의 Published Router Info 및 Unpublished Router Info 섹션을 참조하세요. 조각화된 Router Info 처리에 대한 참고사항은 아래를 참조하세요.
Bob이 자신의 netdb에 Alice의 RouterInfo의 이전 버전을 가지고 있다면, 두 버전에서 router info의 정적 키가 동일한지 확인하고(존재하는 경우), 이전 버전이 XXX보다 오래되지 않았는지 확인한다(아래 키 회전 시간 참조)
Bob은 여기서 Alice의 정적 키가 곡선 상의 유효한 점인지 검증해야 합니다.
패딩 매개변수를 지정하기 위한 옵션들이 포함되어야 합니다.
모든 오류(AEAD, RI, DH, 타임스탬프 또는 키 검증 실패 포함) 발생 시, Bob은 추가 메시지 처리를 중단하고 응답하지 않고 연결을 종료해야 합니다.
Message 3 part 2 프레임 내용: 이 프레임의 형식은 데이터 단계 프레임의 형식과 동일하지만, 프레임의 길이는 Session Request에서 Alice가 전송합니다. 데이터 단계 프레임 형식은 아래를 참조하세요. 프레임은 다음 순서로 1개에서 4개의 블록을 포함해야 합니다:
- Alice의 Router Info 블록 (필수)
- Options 블록 (선택사항)
- I2NP 블록 (선택사항)
- Padding 블록 (선택사항) 이 프레임은 다른 블록 유형을 절대 포함해서는 안 됩니다. TODO: relay와 peer test는 어떻게 처리할까?
메시지 3 파트 2 패딩 블록이 권장됩니다.
MTU와 Router Info 크기에 따라 I2NP 블록을 위한 공간이 없거나 매우 적을 수 있습니다. Router Info가 분할된 경우 I2NP 블록을 포함하지 마십시오. 가장 간단한 구현은 Session Confirmed 메시지에 I2NP 블록을 포함하지 않고, 모든 I2NP 블록을 후속 Data 메시지에서 전송하는 것일 수 있습니다. 최대 블록 크기는 아래 Router Info 블록 섹션을 참조하세요.
Session Confirmed Fragmentation
Session Confirmed 메시지는 Bob이 여러 필수 검사를 수행할 수 있도록 Alice로부터 완전히 서명된 Router Info를 포함해야 합니다:
- RI의 정적 키 “s"가 핸드셰이크의 정적 키와 일치함
- RI의 소개 키 “i"는 추출 가능하고 유효해야 하며, 데이터 단계에서 사용됨
- RI 서명이 유효함
안타깝게도 Router Info는 RI 블록에서 gzip 압축되었을 때조차 MTU를 초과할 수 있습니다. 따라서 Session Confirmed는 두 개 이상의 패킷에 걸쳐 분할될 수 있습니다. 이는 SSU2 프로토콜에서 AEAD로 보호된 페이로드가 두 개 이상의 패킷에 걸쳐 분할되는 유일한 경우입니다.
각 패킷의 헤더는 다음과 같이 구성됩니다:
- 모든 헤더는 동일한 패킷 번호 0을 가진 짧은 헤더입니다
- 모든 헤더는 조각 번호와 전체 조각 수를 포함하는 “frag” 필드를 포함합니다
- 조각 0의 암호화되지 않은 헤더는 “jumbo” 메시지의 연관 데이터(AD)입니다
- 각 헤더는 해당 패킷의 데이터 마지막 24바이트를 사용하여 암호화됩니다
다음과 같이 패킷 시리즈를 구성합니다:
- 단일 RI 블록을 생성합니다 (RI 블록 frag 필드에서 1개 중 fragment 0). RI 블록 단편화는 사용하지 않습니다. 이는 동일한 문제를 해결하는 대안적 방법을 위한 것이었습니다.
- RI 블록과 포함할 다른 블록들이 있는 “jumbo” 페이로드를 생성합니다
- 총 데이터 크기를 계산합니다 (헤더는 포함하지 않음). 이는 페이로드 크기 + 정적 키와 두 개의 MAC을 위한 64바이트입니다
- 각 패킷에서 사용 가능한 공간을 계산합니다. 이는 MTU에서 IP 헤더 (20 또는 40), UDP 헤더 (8), SSU2 short 헤더 (16)를 뺀 값입니다. 패킷당 총 오버헤드는 44 (IPv4) 또는 64 (IPv6)입니다.
- 패킷 수를 계산합니다.
- 마지막 패킷의 데이터 크기를 계산합니다. 헤더 암호화가 작동하도록 24바이트 이상이어야 합니다. 너무 작으면, 패딩 블록을 추가하거나, 이미 있는 경우 패딩 블록의 크기를 늘리거나, 마지막 패킷이 충분히 클 수 있도록 다른 패킷 중 하나의 크기를 줄입니다.
- 첫 번째 패킷의 암호화되지 않은 헤더를 생성합니다. frag 필드에 총 fragment 수를 포함하고, 평소와 같이 헤더를 AD로 사용하여 Noise로 “jumbo” 페이로드를 암호화합니다.
- 암호화된 jumbo 패킷을 fragment로 분할합니다
- 각 fragment 1-n에 대해 암호화되지 않은 헤더를 추가합니다
- 각 fragment 0-n의 헤더를 암호화합니다. 각 헤더는 위의 Session Confirmed KDF에서 정의된 것과 동일한 k_header_1 및 k_header_2를 사용합니다.
- 모든 fragment를 전송합니다
재조립 과정:
Bob이 Session Confirmed 메시지를 수신하면, 헤더를 복호화하고 frag 필드를 검사하여 Session Confirmed가 단편화되었음을 확인합니다. 모든 단편이 수신되고 재조립될 때까지는 메시지를 복호화하지 않으며(복호화할 수도 없습니다).
- fragment 0의 헤더는 Noise AD로 사용되므로 보존
- 재조립 전에 다른 fragment들의 헤더는 폐기
- fragment 0의 헤더를 AD로 사용하여 “jumbo” 페이로드를 재조립하고 Noise로 복호화
- 일반적인 방법으로 RI 블록 검증
- 데이터 단계로 진행하고 일반적인 방법으로 ACK 0 전송
Bob이 개별 fragment들을 ack할 메커니즘은 없습니다. Bob이 모든 fragment들을 수신하고, 재조립하고, 복호화하고, 내용을 검증하면, Bob은 평소와 같이 split()을 수행하고, 데이터 단계에 진입하여 패킷 번호 0의 ACK를 전송합니다.
Alice가 패킷 번호 0의 ACK를 받지 못하면, 모든 세션 확인 패킷을 그대로 재전송해야 합니다.
예제:
IPv6를 통한 1500 MTU의 경우, 최대 페이로드는 1372이고, RI 블록 오버헤드는 5이므로, 최대 (gzip 압축된) RI 데이터 크기는 1367입니다 (다른 블록이 없다고 가정). 두 개의 패킷을 사용하면, 두 번째 패킷의 오버헤드는 64이므로 1436바이트의 추가 페이로드를 담을 수 있습니다. 따라서 두 개의 패킷으로 최대 2803바이트의 압축된 RI를 처리할 수 있습니다.
현재 네트워크에서 확인된 가장 큰 압축된 RI는 약 1400바이트입니다. 따라서 실제로는 최소 1280 MTU에서도 두 개의 fragment면 충분합니다. 프로토콜은 최대 15개의 fragment를 허용합니다.
보안 분석:
단편화된 Session Confirmed의 무결성과 보안은 단편화되지 않은 것과 동일합니다. 어떤 단편의 변경이라도 재조립 후 Noise AEAD가 실패하게 됩니다. 단편 0 이후 단편들의 헤더는 단편을 식별하는 용도로만 사용됩니다. 경로상 공격자가 헤더를 암호화하는 데 사용되는 k_header_2 키를 가지고 있다고 해도 (핸드셰이크에서 파생되므로 가능성은 낮음), 이것이 공격자가 유효한 단편을 대체할 수 있게 해주지는 않습니다.
KDF for data phase
데이터 단계는 연관된 데이터를 위해 헤더를 사용합니다.
KDF는 RFC 2104에 정의된 HMAC-SHA256(key, data)을 사용하여 chaining key ck에서 두 개의 cipher key k_ab와 k_ba를 생성합니다. 이것은 Noise 스펙에 정확히 정의된 split() 함수입니다.
// 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: 모든 블록 타입이 허용됨 최대 payload 크기: MTU - 60 (IPv4) 또는 MTU - 80 (IPv6). 1500 MTU의 경우: 최대 payload는 1440 (IPv4) 또는 1420 (IPv6).
Session Confirmed의 2번째 부분부터 시작하여, 모든 메시지는 인증되고 암호화된 ChaChaPoly 페이로드 내부에 있습니다. 모든 패딩은 메시지 내부에 있습니다. 페이로드 내부에는 0개 이상의 “블록"이 있는 표준 형식이 있습니다. 각 블록은 1바이트 타입과 2바이트 길이를 가집니다. 타입에는 날짜/시간, I2NP 메시지, 옵션, 종료, 패딩이 포함됩니다.
참고: Bob은 데이터 단계에서 Alice에게 보내는 첫 번째 메시지로 자신의 RouterInfo를 전송할 수 있지만, 반드시 그래야 하는 것은 아닙니다.
페이로드 보안 속성:
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
- router는 AEAD 오류가 있는 메시지를 삭제해야 합니다.
+----+----+----+----+----+----+----+----+
| Short Header 16 bytes, ChaCha20 |
+ encrypted with intro key and +
| derived key, see Data Phase KDF |
+----+----+----+----+----+----+----+----+
| ChaCha20 data |
+ Encrypted and authenticated data +
| length varies |
+ k defined in Data Phase KDF +
| n = packet number from header |
+ +
| |
+----+----+----+----+----+----+----+----+
| |
+ Poly1305 MAC (16 bytes) +
| |
+----+----+----+----+----+----+----+----+
암호화되지 않은 데이터 (Poly1305 인증 태그는 표시되지 않음):
+----+----+----+----+----+----+----+----+
| 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
최소 페이로드 크기는 8바이트입니다. 이 요구사항은 모든 ACK, I2NP, First Fragment, 또는 Follow-on Fragment 블록에 의해 충족됩니다. 요구사항이 충족되지 않으면 Padding 블록이 포함되어야 합니다.
각 패킷 번호는 한 번만 사용할 수 있습니다. I2NP 메시지나 프래그먼트를 재전송할 때는 새로운 패킷 번호를 사용해야 합니다.
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는 Alice에게 보내고, Alice는 Charlie에게 보내며, 이는 Peer Test 단계 5-7에만 해당됩니다. Peer Test 단계 1-4는 Data 메시지의 Peer Test 블록을 사용하여 세션 내에서 전송되어야 합니다. 자세한 정보는 아래의 Peer Test Block 및 Peer Test Process 섹션을 참조하십시오.
크기: 48 + payload 크기.
Noise payload: 아래를 참조하십시오.
원시 내용:
+----+----+----+----+----+----+----+----+
| 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) +
| |
+----+----+----+----+----+----+----+----+
암호화되지 않은 데이터 (Poly1305 인증 태그는 표시되지 않음):
+----+----+----+----+----+----+----+----+
| 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
긴 헤더
- DateTime 블록
- Address 블록 (메시지 6과 7에 필수, 아래 참고 사항 참조)
- Peer Test 블록
- Padding 블록 (선택사항)
최소 페이로드 크기는 8바이트입니다. Peer Test 블록의 전체 크기가 이보다 크므로, 이 블록만으로도 요구사항을 충족합니다.
메시지 5와 7에서 Peer Test 블록은 세션 내 메시지 3과 4의 블록과 동일할 수 있으며, Charlie가 서명한 합의를 포함하거나 재생성될 수 있습니다. 서명은 선택사항입니다.
메시지 6에서, Peer Test 블록은 Alice가 서명한 요청을 포함하는 세션 내 메시지 1과 2의 블록과 동일할 수 있거나, 재생성될 수 있습니다. 서명은 선택사항입니다.
Connection ID: 두 개의 connection ID는 테스트 nonce에서 파생됩니다. Charlie에서 Alice로 전송되는 메시지 5와 7의 경우, Destination Connection ID는 4바이트 big-endian 테스트 nonce의 두 개 복사본입니다. 즉, ((nonce « 32) | nonce)입니다. Source Connection ID는 Destination Connection ID의 역입니다. 즉, ~((nonce « 32) | nonce)입니다. Alice에서 Charlie로 전송되는 메시지 6의 경우, 두 connection ID를 교환합니다.
주소 블록 내용:
- 메시지 5에서: 필요하지 않음.
- 메시지 6에서: Charlie의 RI에서 선택된 Charlie의 IP와 포트.
- 메시지 7에서: 메시지 6이 수신된 Alice의 실제 IP와 포트.
KDF for Retry
Retry 메시지의 요구사항은 Bob이 응답으로 Retry 메시지를 생성하기 위해 Session Request 메시지를 복호화할 필요가 없다는 것입니다. 또한 이 메시지는 대칭 암호화만을 사용하여 빠르게 생성되어야 합니다.
// 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이 Session Request 또는 Token Request 메시지에 대한 응답으로 Alice에게 보냅니다. Alice는 새로운 Session Request로 응답합니다. 크기: 48 + payload 크기.
Termination 블록이 포함된 경우 Termination 메시지(즉, “재시도 안 함”)로도 사용됩니다.
Noise payload: 아래를 참조하세요.
원시 내용:
+----+----+----+----+----+----+----+----+
| 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) +
| |
+----+----+----+----+----+----+----+----+
암호화되지 않은 데이터 (Poly1305 인증 태그는 표시되지 않음):
+----+----+----+----+----+----+----+----+
| 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
짧은 헤더
- DateTime 블록
- Address 블록
- Options 블록 (선택사항)
- Termination 블록 (선택사항, 세션이 거부된 경우)
- Padding 블록 (선택사항)
최소 payload 크기는 8바이트입니다. DateTime과 Address 블록의 총 크기가 그보다 크므로, 이 두 블록만으로도 요구사항이 충족됩니다.
연결 ID 번호 매기기
탐지 저항성을 제공하기 위해, router는 Request 메시지의 메시지 타입, 프로토콜 버전, 네트워크 ID 필드가 유효하지 않은 경우 Session Request 또는 Token Request 메시지에 대한 응답으로 Retry 메시지를 보내지 않아야 합니다.
스푸핑된 소스 주소를 사용하여 수행할 수 있는 증폭 공격의 규모를 제한하기 위해, Retry 메시지는 많은 양의 패딩을 포함해서는 안 됩니다. Retry 메시지는 응답하는 메시지 크기의 3배보다 크지 않을 것을 권장합니다. 또는 1-64바이트 범위에서 임의의 패딩을 추가하는 것과 같은 간단한 방법을 사용하십시오.
KDF for Token Request
이 메시지는 대칭 암호화만을 사용하여 빠르게 생성되어야 합니다.
// 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가 Bob에게 전송합니다. Bob은 Retry 메시지로 응답합니다. 크기: 48 + 페이로드 크기.
Alice가 유효한 토큰을 가지고 있지 않다면, Session Request 생성 시 비대칭 암호화 오버헤드를 피하기 위해 Session Request 대신 이 메시지를 보내야 합니다.
Noise payload: 아래 참조.
원시 내용:
+----+----+----+----+----+----+----+----+
| 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) +
| |
+----+----+----+----+----+----+----+----+
암호화되지 않은 데이터 (Poly1305 인증 태그는 표시되지 않음):
+----+----+----+----+----+----+----+----+
| 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
패킷 번호 매기기
- DateTime 블록
- Padding 블록
최소 페이로드 크기는 8바이트입니다.
헤더 바인딩
프로빙 저항성을 제공하기 위해, router는 Token Request 메시지의 메시지 타입, 프로토콜 버전, 네트워크 ID 필드가 유효하지 않은 경우 Token Request 메시지에 대한 응답으로 Retry 메시지를 보내서는 안 됩니다.
이는 표준 Noise 메시지가 아니며 handshake의 일부가 아닙니다. 연결 ID 외에는 Session Request 메시지와 연결되어 있지 않습니다.
대부분의 오류에서는 AEAD나 명백한 재생 공격을 포함하여 Bob은 추가 메시지 처리를 중단하고 응답하지 않고 메시지를 삭제해야 합니다.
Bob은 타임스탬프 값이 현재 시간과 너무 많이 차이나는 연결을 거부해야 합니다. 최대 델타 시간을 “D"라고 합니다. Bob은 이전에 사용된 핸드셰이크 값들의 로컬 캐시를 유지하고 중복을 거부하여 재생 공격을 방지해야 합니다. 캐시의 값들은 최소 2*D의 수명을 가져야 합니다. 캐시 값은 구현에 따라 다르지만, 32바이트 X 값(또는 그 암호화된 동등물)을 사용할 수 있습니다.
Bob은 DateTime 블록의 타임스탬프가 너무 많이 비뚤어진 경우 제로 토큰과 클록 스큐 이유 코드가 포함된 Termination 블록을 담은 Retry 메시지를 보낼 수 있다(MAY).
최소 크기: TBD, Session Created와 동일한 규칙?
KDF for Hole Punch
이 메시지는 대칭 암호화만을 사용하여 빠르게 생성되어야 합니다.
// 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는 Bob으로부터 받은 Relay Intro에 응답하여 Alice에게 보냅니다. Alice는 새로운 Session Request로 응답합니다. 크기: 48 + 페이로드 크기.
Noise payload: 아래 참조.
원시 내용:
+----+----+----+----+----+----+----+----+
| 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) +
| |
+----+----+----+----+----+----+----+----+
암호화되지 않은 데이터 (Poly1305 인증 태그는 표시되지 않음):
+----+----+----+----+----+----+----+----+
| 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.
헤더 암호화
- DateTime 블록
- Address 블록
- Relay Response 블록
- Padding 블록 (선택사항)
최소 페이로드 크기는 8바이트입니다. DateTime과 Address 블록의 총합이 그보다 크므로, 이 두 블록만으로도 요구사항이 충족됩니다.
Connection ID: 두 개의 connection ID는 relay nonce에서 파생됩니다. Destination Connection ID는 4바이트 빅 엔디안 relay nonce의 두 개 복사본입니다, 즉 ((nonce « 32) | nonce). Source Connection ID는 Destination Connection ID의 역수입니다, 즉 ~((nonce « 32) | nonce).
Alice는 헤더의 토큰을 무시해야 합니다. Session Request에서 사용할 토큰은 Relay Response 블록에 있습니다.
Noise Payload
각 Noise 페이로드는 0개 이상의 “블록"을 포함합니다.
이는 NTCP2 및 ECIES 명세서에서 정의된 것과 동일한 블록 형식을 사용합니다. 개별 블록 유형은 다르게 정의됩니다. QUIC RFC 9000에서 이에 해당하는 용어는 “프레임"입니다.
구현자들이 코드를 공유하도록 권장하는 것이 파싱 문제로 이어질 수 있다는 우려가 있습니다. 구현자들은 코드 공유의 이점과 위험성을 신중히 고려해야 하며, 두 컨텍스트에서 순서와 유효한 블록 규칙이 다르도록 보장해야 합니다.
보안 고려사항
암호화된 페이로드에는 하나 이상의 블록이 있습니다. 블록은 간단한 Tag-Length-Value (TLV) 형식입니다. 각 블록은 1바이트 식별자, 2바이트 길이, 그리고 0개 이상의 데이터 바이트를 포함합니다. 이 형식은 NTCP2와 ECIES의 형식과 동일하지만, 블록 정의는 다릅니다.
확장성을 위해 수신자는 알 수 없는 식별자를 가진 블록을 무시하고 패딩으로 처리해야 합니다.
(Poly1305 인증 태그는 표시되지 않음):
+----+----+----+----+----+----+----+----+
|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
헤더 암호화는 두 개의 ChaCha20 연산을 위한 IV로 패킷의 마지막 24바이트를 사용합니다. 모든 패킷이 16바이트 MAC으로 끝나므로, 모든 패킷 페이로드는 최소 8바이트여야 합니다. 페이로드가 이 요구사항을 충족하지 않는 경우, Padding 블록을 포함해야 합니다.
최대 ChaChaPoly 페이로드는 메시지 유형, MTU, IPv4 또는 IPv6 주소 유형에 따라 달라집니다. 최대 페이로드는 IPv4의 경우 MTU - 60이고 IPv6의 경우 MTU - 80입니다. 최대 페이로드 데이터는 IPv4의 경우 MTU - 63이고 IPv6의 경우 MTU - 83입니다. 상한선은 IPv4, 1500 MTU, Data 메시지의 경우 약 1440바이트입니다. 최대 전체 블록 크기는 최대 페이로드 크기입니다. 최대 단일 블록 크기는 최대 전체 블록 크기입니다. 블록 유형은 1바이트입니다. 블록 길이는 2바이트입니다. 최대 단일 블록 데이터 크기는 최대 단일 블록 크기에서 3을 뺀 값입니다.
참고사항:
구현자는 블록을 읽을 때, 잘못된 형식이거나 악의적인 데이터가 다음 블록이나 페이로드 경계를 넘어서 읽기가 발생하지 않도록 보장해야 합니다.
구현체들은 순방향 호환성을 위해 알 수 없는 블록 타입을 무시해야 합니다.
블록 유형:
| 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
Session Confirmed에서 Router Info는 첫 번째 블록이어야 합니다.
다른 모든 메시지에서는 순서가 지정되지 않습니다. 단, 다음 요구사항은 예외입니다: Padding이 있는 경우 마지막 블록이어야 합니다. Termination이 있는 경우 Padding을 제외하고 마지막 블록이어야 합니다. 단일 페이로드에서는 여러 개의 Padding 블록이 허용되지 않습니다.
Block Specifications
헤더 암호화 KDF
시간 동기화의 경우:
+----+----+----+----+----+----+----+
| 0 | 4 | timestamp |
+----+----+----+----+----+----+----+
blk :: 0
size :: 2 bytes, big endian, value = 4
timestamp :: Unix timestamp, unsigned seconds.
Wraps around in 2106
참고사항:
- SSU 1과 달리 SSU 2에서는 데이터 단계의 패킷 헤더에 타임스탬프가 없습니다.
- 구현체들은 데이터 단계에서 주기적으로 DateTime 블록을 전송해야 합니다.
- 구현체들은 네트워크에서 클럭 편향을 방지하기 위해 가장 가까운 초 단위로 반올림해야 합니다.
헤더 검증
업데이트된 옵션을 전달합니다. 옵션에는 최소 및 최대 패딩이 포함됩니다.
Options 블록은 가변 길이입니다.
+----+----+----+----+----+----+----+----+
| 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
옵션 문제:
- 옵션 협상은 TBD입니다.
RouterInfo
Alice의 RouterInfo를 Bob에게 전달합니다. Session Confirmed part 2 payload에서만 사용됩니다. 데이터 단계에서는 사용하지 않으며, 대신 I2NP DatabaseStore Message를 사용하세요.
최소 크기: 약 420바이트, 단 router info 내의 router identity와 signature가 압축 가능한 경우는 예외이며, 이는 가능성이 낮습니다.
참고: Router Info 블록은 절대 분할되지 않습니다. frag 필드는 항상 0/1입니다. 자세한 내용은 위의 Session Confirmed Fragmentation 섹션을 참조하십시오.
+----+----+----+----+----+----+----+----+
| 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
참고사항:
Router Info는 플래그 비트 1로 표시되는 바와 같이 선택적으로 gzip으로 압축됩니다. 이는 절대 압축되지 않는 NTCP2나 항상 압축되는 DatabaseStore Message와는 다릅니다. 압축은 압축 가능한 콘텐츠가 거의 없는 작은 Router Info의 경우에는 일반적으로 효과가 적지만, 압축 가능한 여러 Router Address를 가진 큰 Router Info에는 매우 유익하기 때문에 선택사항입니다. 압축은 Router Info가 분할 없이 단일 Session Confirmed 패킷에 맞도록 하는 경우 권장됩니다.
Session Confirmed 메시지에서 첫 번째 또는 유일한 fragment의 최대 크기: IPv4의 경우 MTU - 113 또는 IPv6의 경우 MTU - 133. 1500바이트 기본 MTU를 가정하고 메시지에 다른 블록이 없다면, IPv4의 경우 1387 또는 IPv6의 경우 1367. 현재 router info의 97%는 gzip 압축 없이 1367보다 작습니다. 현재 router info의 99.9%는 gzip 압축 시 1367보다 작습니다. 1280바이트 최소 MTU를 가정하고 메시지에 다른 블록이 없다면, IPv4의 경우 1167 또는 IPv6의 경우 1147. 현재 router info의 94%는 gzip 압축 없이 1147보다 작습니다. 현재 router info의 97%는 gzip 압축 시 1147보다 작습니다.
frag 바이트는 이제 사용되지 않으며, Router Info 블록은 절대 분할되지 않습니다. frag 바이트는 fragment 0, total fragments 1로 설정되어야 합니다. 자세한 내용은 위의 Session Confirmed Fragmentation 섹션을 참조하십시오.
RouterInfo에 게시된 RouterAddress가 있는 경우에만 플러딩을 요청해야 합니다. 수신하는 router는 게시된 RouterAddress가 포함되어 있지 않은 경우 RouterInfo를 플러딩해서는 안 됩니다.
이 프로토콜은 RouterInfo가 저장되거나 flood되었다는 확인응답을 제공하지 않습니다. 확인응답이 필요하고 수신자가 floodfill인 경우, 발신자는 대신 reply token과 함께 표준 I2NP DatabaseStoreMessage를 전송해야 합니다.
I2NP Message
수정된 헤더를 포함한 완전한 I2NP 메시지.
이것은 NTCP2에서와 동일한 9바이트를 I2NP 헤더에 사용합니다 (타입, 메시지 ID, 짧은 만료시간).
+----+----+----+----+----+----+----+----+
| 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
참고사항:
이것은 NTCP2에서 사용되는 것과 동일한 9바이트 I2NP 헤더 형식입니다.
이는 First Fragment 블록과 정확히 동일한 형식이지만, 블록 타입이 이것이 완전한 메시지임을 나타냅니다.
9바이트 I2NP 헤더를 포함한 최대 크기는 IPv4의 경우 MTU - 63이고 IPv6의 경우 MTU - 83입니다.
ChaCha20/Poly1305
수정된 헤더를 가진 I2NP 메시지의 첫 번째 조각(fragment #0).
이는 NTCP2에서와 동일한 9바이트를 I2NP 헤더에 사용합니다 (타입, 메시지 ID, 짧은 만료).
전체 fragment 수가 지정되지 않았습니다.
+----+----+----+----+----+----+----+----+
| 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)
참고사항:
이것은 NTCP2에서 사용되는 것과 동일한 9바이트 I2NP 헤더 형식입니다.
이는 I2NP Message 블록과 정확히 동일한 형식이지만, 블록 타입이 이것이 메시지의 첫 번째 fragment임을 나타냅니다.
부분 메시지 길이는 0보다 커야 합니다.
SSU 1에서와 같이, 마지막 프래그먼트를 먼저 전송하는 것이 권장되며, 이를 통해 수신자가 전체 프래그먼트 수를 알고 수신 버퍼를 효율적으로 할당할 수 있습니다.
I2NP 헤더 9바이트를 포함한 최대 크기는 IPv4의 경우 MTU - 63이고 IPv6의 경우 MTU - 83입니다.
참고사항
I2NP 메시지의 추가 조각(0보다 큰 조각 번호).
+----+----+----+----+----+----+----+----+
| 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
참고사항:
부분 메시지 길이는 0보다 커야 합니다.
SSU 1에서와 같이, 마지막 조각을 먼저 전송하는 것이 권장되며, 이를 통해 수신자가 총 조각 수를 알고 수신 버퍼를 효율적으로 할당할 수 있습니다.
SSU 1에서와 같이 최대 프래그먼트 번호는 127이지만, 실제 제한은 63 이하입니다. 구현체들은 최대값을 약 64 KB의 최대 I2NP 메시지 크기에 실용적인 수준으로 제한할 수 있으며, 이는 1280 최소 MTU에서 약 55개의 프래그먼트에 해당합니다. 아래의 Max I2NP Message Size 섹션을 참조하십시오.
최대 부분 메시지 크기(frag 및 message id 제외)는 IPv4의 경우 MTU - 68이고 IPv6의 경우 MTU - 88입니다.
AEAD 오류 처리
연결을 끊습니다. 이것은 페이로드에서 패딩이 아닌 마지막 블록이어야 합니다.
+----+----+----+----+----+----+----+----+
| 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.
참고사항:
- 모든 이유가 실제로 사용되는 것은 아니며, 구현에 따라 달라집니다. 대부분의 실패는 일반적으로 연결 종료가 아닌 메시지 폐기를 초래합니다. 위의 handshake 메시지 섹션의 참고사항을 참조하세요. 나열된 추가 이유들은 일관성, 로깅, 디버깅 또는 정책 변경을 위한 것입니다.
- Termination 블록과 함께 ACK 블록을 포함하는 것이 권장됩니다.
- 데이터 단계에서 “termination received” 이외의 이유로 인해, 피어는 “termination received” 이유와 함께 termination 블록으로 응답해야 합니다.
RelayRequest
세션 내에서 Alice에서 Bob으로 Data 메시지로 전송됩니다. 아래의 Relay Process 섹션을 참조하세요.
+----+----+----+----+----+----+----+----+
| 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.
참고사항:
- IP 주소는 항상 포함되며(SSU 1과 달리) 세션에 사용된 IP와 다를 수 있습니다.
서명:
Alice는 요청에 서명하고 이를 이 블록에 포함시킵니다. Bob은 이를 Relay Intro 블록에서 Charlie에게 전달합니다. 서명 알고리즘: Alice의 router 서명 키로 다음 데이터에 서명합니다:
- prologue: 16바이트 “RelayRequestData”, null로 끝나지 않음 (메시지에 포함되지 않음)
- bhash: Bob의 32바이트 router 해시 (메시지에 포함되지 않음)
- chash: Charlie의 32바이트 router 해시 (메시지에 포함되지 않음)
- nonce: 4바이트 nonce
- relay tag: 4바이트 relay tag
- timestamp: 4바이트 timestamp (초 단위)
- ver: 1바이트 SSU 버전
- asz: 1바이트 endpoint (포트 + IP) 크기 (6 또는 18)
- AlicePort: 2바이트 Alice의 포트 번호
- Alice IP: (asz - 2)바이트 Alice IP 주소
초기 ChainKey를 위한 KDF
세션 내 Data 메시지로 Charlie에서 Bob으로 또는 Bob에서 Alice로 전송되며, Charlie에서 Alice로의 Hole Punch 메시지에서도 전송됩니다. 아래 Relay Process 섹션을 참조하세요.
+----+----+----+----+----+----+----+----+
| 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)
참고사항:
토큰은 Alice가 Session Request에서 즉시 사용되어야 합니다.
서명:
Charlie가 동의하거나 (응답 코드 0) 거부하는 경우 (응답 코드 64 이상), Charlie는 응답에 서명하고 이를 이 블록에 포함합니다; Bob은 이를 Relay Response 블록에서 Alice에게 전달합니다. 서명 알고리즘: Charlie의 router 서명 키로 다음 데이터에 서명합니다:
- prologue: 16바이트 “RelayAgreementOK”, null로 종료되지 않음 (메시지에 포함되지 않음)
- bhash: Bob의 32바이트 router 해시 (메시지에 포함되지 않음)
- nonce: 4바이트 nonce
- timestamp: 4바이트 타임스탬프 (초 단위)
- ver: 1바이트 SSU 버전
- csz: 1바이트 엔드포인트 (포트 + IP) 크기 (0 또는 6 또는 18)
- CharliePort: 2바이트 Charlie의 포트 번호 (csz가 0인 경우 존재하지 않음)
- Charlie IP: (csz - 2)바이트 Charlie IP 주소 (csz가 0인 경우 존재하지 않음)
Bob이 거부하는 경우 (응답 코드 1-63), Bob은 응답에 서명하고 이를 이 블록에 포함시킵니다. 서명 알고리즘: Bob의 router 서명 키로 다음 데이터에 서명:
- prologue: 16바이트 “RelayAgreementOK”, null로 종료되지 않음 (메시지에 포함되지 않음)
- bhash: Bob의 32바이트 router 해시 (메시지에 포함되지 않음)
- nonce: 4바이트 nonce
- timestamp: 4바이트 timestamp (초)
- ver: 1바이트 SSU 버전
- csz: 1바이트 = 0
Session Request를 위한 KDF
세션 내에서 Data 메시지로 Bob에서 Charlie에게 전송됩니다. 아래의 Relay Process 섹션을 참조하세요.
RouterInfo 블록 또는 Alice의 Router Info를 포함하는 I2NP DatabaseStore 메시지 블록(또는 fragment)이 앞에 와야 하며, 이는 동일한 payload 내에 포함되거나(공간이 있는 경우) 이전 메시지에 포함되어야 합니다.
+----+----+----+----+----+----+----+----+
| 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.
참고사항:
IPv4의 경우, Alice의 IP 주소는 항상 4바이트입니다. Alice가 IPv4를 통해 Charlie에 연결하려고 시도하기 때문입니다. IPv6가 지원되며, Alice의 IP 주소는 16바이트일 수 있습니다.
IPv4의 경우, 이 메시지는 확립된 IPv4 연결을 통해 전송되어야 합니다. 이는 Bob이 Alice에게 RelayResponse_로 돌려보낼 Charlie의 IPv4 주소를 알 수 있는 유일한 방법이기 때문입니다. IPv6는 지원되며, 이 메시지는 확립된 IPv6 연결을 통해 전송될 수 있습니다.
introducer와 함께 게시되는 모든 SSU 주소는 “caps” 옵션에 “4” 또는 “6"을 포함해야 합니다.
서명:
Alice가 요청에 서명하고 Bob이 이 블록에서 Charlie에게 전달합니다. 검증 알고리즘: Alice의 router 서명 키로 다음 데이터를 검증합니다:
- prologue: 16바이트 “RelayRequestData”, null로 종료되지 않음 (메시지에 포함되지 않음)
- bhash: Bob의 32바이트 router 해시 (메시지에 포함되지 않음)
- chash: Charlie의 32바이트 router 해시 (메시지에 포함되지 않음)
- nonce: 4바이트 nonce
- relay tag: 4바이트 relay tag
- timestamp: 4바이트 타임스탬프 (초)
- ver: 1바이트 SSU 버전
- asz: 1바이트 엔드포인트 (포트 + IP) 크기 (6 또는 18)
- AlicePort: 2바이트 Alice의 포트 번호
- Alice IP: (asz - 2)바이트 Alice IP 주소
PeerTest
세션 내 Data 메시지 또는 세션 외 Peer Test 메시지로 전송됩니다. 아래 Peer Test Process 섹션을 참조하세요.
메시지 2의 경우, RouterInfo 블록이나 Alice의 Router Info를 포함하는 I2NP DatabaseStore 메시지 블록(또는 조각)이 앞에 와야 하며, 이는 동일한 페이로드(공간이 있는 경우) 또는 이전 메시지에 포함되어야 합니다.
메시지 4의 경우, relay가 승인되면 (reason code 0), Charlie의 Router Info를 포함하는 RouterInfo 블록 또는 I2NP DatabaseStore 메시지 블록(또는 fragment)이 앞에 와야 하며, 이는 동일한 payload 내에(공간이 있다면) 또는 이전 메시지에 포함되어야 합니다.
+----+----+----+----+----+----+----+----+
| 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.
참고사항:
SSU 1과 달리, 메시지 1에는 Alice의 IP 주소와 포트가 반드시 포함되어야 합니다.
IPv6 주소 테스트가 지원되며, Bob과 Charlie가 게시된 IPv6 주소에서 ‘B’ 기능으로 지원을 나타내는 경우, Alice-Bob 및 Alice-Charlie 통신이 IPv6를 통해 이루어질 수 있습니다. 자세한 내용은 Proposal 126을 참조하세요.
Alice는 테스트하고자 하는 전송 계층(IPv4 또는 IPv6)을 통해 기존 세션을 사용하여 Bob에게 요청을 보냅니다. Bob이 IPv4를 통해 Alice로부터 요청을 받으면, Bob은 IPv4 주소를 광고하는 Charlie를 선택해야 합니다. Bob이 IPv6를 통해 Alice로부터 요청을 받으면, Bob은 IPv6 주소를 광고하는 Charlie를 선택해야 합니다. 실제 Bob-Charlie 통신은 IPv4 또는 IPv6를 통해 이루어질 수 있습니다(즉, Alice의 주소 유형과는 독립적입니다).
메시지 1-4는 기존 세션의 Data 메시지에 포함되어야 합니다.
Bob은 메시지 2를 보내기 전에 Alice의 RI를 Charlie에게 먼저 보내야 합니다.
Bob은 메시지 4를 보내기 전에 Charlie의 RI를 Alice에게 보내야 하며, 이는 승인된 경우(이유 코드 0)에만 해당한다.
메시지 5-7은 세션 외부의 Peer Test 메시지에 포함되어야 합니다.
메시지 5와 7은 메시지 3과 4에서 전송된 것과 동일한 서명된 데이터를 포함할 수도 있고, 새로운 타임스탬프로 재생성될 수도 있습니다. 서명은 선택사항입니다.
메시지 6은 메시지 1과 2에서 전송된 것과 동일한 서명된 데이터를 포함하거나, 새로운 타임스탬프로 재생성될 수 있습니다. 서명은 선택 사항입니다.
서명:
Alice는 요청에 서명하고 이를 메시지 1에 포함시킵니다; Bob은 이를 메시지 2에서 Charlie에게 전달합니다. Charlie는 응답에 서명하고 이를 메시지 3에 포함시킵니다; Bob은 이를 메시지 4에서 Alice에게 전달합니다. 서명 알고리즘: Alice 또는 Charlie의 서명 키로 다음 데이터를 서명하거나 검증합니다:
- prologue: 16바이트 “PeerTestValidate”, null로 종료되지 않음 (메시지에 포함되지 않음)
- bhash: Bob의 32바이트 라우터 해시 (메시지에 포함되지 않음)
- ahash: Alice의 32바이트 라우터 해시 (메시지 3과 4의 서명에서만 사용됨; 메시지 3 또는 4에는 포함되지 않음)
- ver: 1바이트 SSU 버전
- nonce: 4바이트 테스트 nonce
- timestamp: 4바이트 타임스탬프 (초)
- asz: 1바이트 엔드포인트 (포트 + IP) 크기 (6 또는 18)
- AlicePort: 2바이트 Alice의 포트 번호
- Alice IP: (asz - 2)바이트 Alice IP 주소
페이로드
TODO 키를 순환할 때만
+----+----+----+----+----+----+----+----+
| 11 | size | TBD |
+----+----+----+ +
| |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
blk :: 11
size :: 2 bytes, big endian, size of data to follow
참고사항
4바이트 ack through, 그 다음에 ack count와 0개 이상의 nack/ack 범위가 따라옵니다.
이 설계는 QUIC에서 적용되고 단순화되었습니다. 설계 목표는 다음과 같습니다:
- “bitfield"를 효율적으로 인코딩하려고 합니다. 이는 확인된(acked) 패킷들을 나타내는 비트 시퀀스입니다.
- bitfield는 대부분 1로 구성됩니다. 1과 0 모두 일반적으로 연속적인 “덩어리"로 나타납니다.
- ack를 위해 패킷에서 사용 가능한 공간의 양은 가변적입니다.
- 가장 중요한 비트는 가장 높은 번호의 비트입니다. 낮은 번호의 비트들은 덜 중요합니다. 가장 높은 비트로부터 일정 거리 아래에서는 오래된 비트들이 “잊혀져서” 다시는 전송되지 않습니다.
아래에 명시된 인코딩은 1로 설정된 가장 높은 비트의 번호를 1로 설정된 그보다 낮은 추가 연속 비트들과 함께 전송함으로써 이러한 설계 목표를 달성합니다. 그 후, 공간이 있으면 그보다 낮은 연속 0 비트 수와 연속 1 비트 수를 지정하는 하나 이상의 “범위"를 포함합니다. 더 자세한 배경 정보는 QUIC RFC 9000 섹션 13.2.3을 참조하십시오.
+----+----+----+----+----+----+----+----+
| 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
예제:
패킷 10만 ACK하려고 합니다:
- Ack Through: 10
- acnt: 0
- 포함된 범위 없음
패킷 8-10만 ACK하려고 합니다:
- Ack Through: 10
- acnt: 2
- 범위가 포함되지 않음
우리는 10 9 8 6 5 2 1 0을 ACK하고 7 4 3을 NACK하려고 합니다. ACK Block의 인코딩은 다음과 같습니다:
- 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)
참고사항:
- Range는 존재하지 않을 수 있습니다. Range의 최대 개수는 지정되지 않으며, 패킷에 들어갈 수 있는 만큼 많을 수 있습니다.
- 255개 이상의 연속 패킷을 acking할 때 Range nack는 0일 수 있습니다.
- 255개 이상의 연속 패킷을 nacking할 때 Range ack는 0일 수 있습니다.
- Range nack와 ack는 둘 다 0일 수 없습니다.
- 마지막 range 이후의 패킷들은 ack되지도 nack되지도 않습니다. ack 블록의 길이와 오래된 ack/nack가 처리되는 방식은 ack 블록의 발신자에게 달려있습니다. 논의에 대해서는 아래의 ack 섹션을 참조하세요.
- ack through는 수신된 가장 높은 패킷 번호여야 하며, 더 높은 번호의 패킷들은 수신되지 않았습니다. 그러나 제한적인 상황에서는 더 낮을 수 있습니다. 예를 들어 “구멍을 메우는” 단일 패킷을 acking하거나, 모든 수신 패킷의 상태를 유지하지 않는 단순화된 구현의 경우입니다. 가장 높게 수신된 것 위의 패킷들은 ack되지도 nack되지도 않지만, 여러 ack 블록 후에는 빠른 재전송 모드로 들어가는 것이 적절할 수 있습니다.
- 이 형식은 QUIC의 단순화된 버전입니다. 많은 수의 ACK를 효율적으로 인코딩하도록 설계되었으며, NACK의 버스트와 함께 사용됩니다.
- ACK 블록은 데이터 단계 패킷을 승인하는 데 사용됩니다. 세션 내 데이터 단계 패킷에만 포함되어야 합니다.
Address
2바이트 포트와 4바이트 또는 16바이트 IP 주소. Bob이 Alice에게 보낸 Alice의 주소, 또는 Alice가 Bob에게 보낸 Bob의 주소.
+----+----+----+----+----+----+----+----+
| 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
이는 Alice가 Session Request, Session Confirmed, 또는 Data 메시지에서 전송할 수 있습니다. Session Created 메시지에서는 지원되지 않습니다. Bob이 아직 Alice의 RI를 가지고 있지 않고, Alice가 relay를 지원하는지 모르기 때문입니다. 또한 Bob이 수신 연결을 받고 있다면, introducer가 필요하지 않을 것입니다 (다른 유형인 ipv4/ipv6의 경우는 제외할 수 있음).
Session Request에서 전송될 때, Bob은 Session Created 메시지에서 Relay Tag로 응답하거나, Alice의 신원을 검증하기 위해 Session Confirmed에서 Alice의 RouterInfo를 받을 때까지 기다린 후 Data 메시지로 응답하는 것을 선택할 수 있습니다. Bob이 Alice를 위한 중계를 원하지 않는다면, Relay Tag 블록을 전송하지 않습니다.
+----+----+----+
| 15 | 0 |
+----+----+----+
blk :: 15
size :: 2 bytes, big endian, value = 0
페이로드
이는 Alice의 Relay Tag Request에 대한 응답으로 Bob이 Session Confirmed 또는 Data 메시지에서 보낼 수 있습니다.
Relay Tag Request가 Session Request에서 전송될 때, Bob은 Session Created 메시지에서 Relay Tag로 응답하거나, Data 메시지로 응답하기 전에 Alice의 신원을 검증하기 위해 Session Confirmed에서 Alice의 RouterInfo를 받을 때까지 기다리도록 선택할 수 있습니다. Bob이 Alice를 위해 릴레이하기를 원하지 않는다면, Relay Tag 블록을 전송하지 않습니다.
+----+----+----+----+----+----+----+
| 16 | 4 | relay tag |
+----+----+----+----+----+----+----+
blk :: 16
size :: 2 bytes, big endian, value = 4
relay tag :: 4 bytes, big endian, nonzero
참고사항
후속 연결을 위해 사용됩니다. 일반적으로 Session Created 및 Session Confirmed 메시지에 포함됩니다. 이전 토큰이 만료되는 경우 장기간 지속되는 세션의 Data 메시지에서 다시 전송될 수도 있습니다.
+----+----+----+----+----+----+----+----+
| 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
문제점
Path Response에서 반환될 임의의 데이터가 포함된 Ping으로, keep-alive 또는 IP/포트 변경을 검증하는 데 사용됩니다.
+----+----+----+----+----+----+----+----+
| 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
참고사항:
최소 8바이트의 데이터 크기로 랜덤 데이터를 포함하는 것이 권장되지만 필수는 아닙니다.
Path Response
Path Challenge에서 받은 데이터가 포함된 Pong으로, Path Challenge에 대한 응답으로 사용되며, keep-alive 또는 IP/Port 변경을 검증하는 데 사용됩니다.
+----+----+----+----+----+----+----+----+
| 19 | size | |
+----+----+----+ +
| Data received in Path Challenge |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
blk :: 19
size :: 2 bytes, big endian, size of data to follow
data :: As received in a Path Challenge
First Packet Number
각 방향의 handshake에 선택적으로 포함되어 전송될 첫 번째 패킷 번호를 지정합니다. 이는 TCP와 유사하게 헤더 암호화에 더 많은 보안을 제공합니다.
완전히 명시되지 않음, 현재 지원되지 않음.
+----+----+----+----+----+----+----+
| 20 | size | First pkt number |
+----+----+----+----+----+----+----+
blk :: 20
size :: 4
pkt num :: The first packet number to be sent in the data phase
Congestion
이 블록은 혼잡 제어 정보를 교환하는 확장 가능한 방법으로 설계되었습니다. 혼잡 제어는 복잡할 수 있으며, 실시간 테스트에서 프로토콜에 대한 더 많은 경험을 얻거나 완전한 배포 이후에 발전할 수 있습니다.
이는 플래그가 할당될 공간이 없는 고사용량 I2NP, First Fragment, Followon Fragment, ACK 블록에서 혼잡 정보를 배제합니다. Data 패킷 헤더에 사용되지 않는 3바이트의 플래그가 있지만, 이는 확장성을 위한 제한된 공간을 제공하며 암호화 보호가 약합니다.
2비트 정보에 4바이트 블록을 사용하는 것이 다소 낭비적이지만, 이를 별도의 블록에 넣음으로써 현재 윈도우 크기, 측정된 RTT, 또는 기타 플래그와 같은 추가 데이터로 쉽게 확장할 수 있습니다. 경험에 따르면 플래그 비트만으로는 고급 혼잡 제어 방식의 구현에 종종 불충분하고 어색합니다. 예를 들어 ACK 블록에서 가능한 모든 혼잡 제어 기능에 대한 지원을 추가하려고 하면 공간이 낭비되고 해당 블록의 파싱에 복잡성이 추가됩니다.
구현체들은 향후 버전의 이 명세에서 구현이 요구되지 않는 한, 상대방 router가 여기에 포함된 특정 플래그 비트나 기능을 지원한다고 가정해서는 안 됩니다.
이 블록은 아마도 페이로드에서 마지막 non-padding 블록이어야 합니다.
+----+----+----+----+
| 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
페이로드
이는 AEAD payload 내부의 패딩을 위한 것입니다. 모든 메시지의 패딩은 AEAD payload 내부에 있습니다.
패딩은 협상된 매개변수를 대략적으로 준수해야 합니다. Bob은 Session Created에서 요청한 tx/rx min/max 매개변수를 보냈습니다. Alice는 Session Confirmed에서 요청한 tx/rx min/max 매개변수를 보냈습니다. 업데이트된 옵션은 데이터 단계 중에 전송될 수 있습니다. 위의 옵션 블록 정보를 참조하십시오.
존재하는 경우, 이것은 payload의 마지막 블록이어야 합니다.
+----+----+----+----+----+----+----+----+
|254 | size | padding |
+----+----+----+ +
| |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
blk :: 254
size :: 2 bytes, big endian, size of padding to follow
padding :: random data
참고 사항:
Size = 0이 허용됩니다.
패딩 전략은 추후 결정 예정입니다.
최소 패딩은 추후 결정 예정입니다.
패딩만으로 구성된 페이로드가 허용됩니다.
패딩 기본값은 추후 결정 예정입니다.
패딩 매개변수 협상에 대해서는 옵션 블록을 참조하세요
최소/최대 패딩 매개변수에 대해서는 옵션 블록을 참조하세요
MTU를 초과하지 마세요. 더 많은 패딩이 필요한 경우 여러 개의 메시지를 전송하세요.
협상된 패딩 위반에 대한 router 응답은 구현에 따라 다릅니다.
패딩 길이는 메시지별로 결정되고 길이 분포를 추정하거나, 랜덤 지연이 추가되어야 한다. 이러한 대응책들은 DPI에 저항하기 위해 포함되어야 하며, 그렇지 않으면 메시지 크기가 전송 프로토콜에 의해 I2P 트래픽이 전달되고 있음을 드러낼 수 있다. 정확한 패딩 방식은 향후 연구 영역이며, NTCP2의 부록 A에서 이 주제에 대한 더 많은 정보를 제공한다.
Replay Prevention
SSU2는 공격자가 재전송하는 메시지의 영향을 최소화하도록 설계되었습니다.
Token Request, Retry, Session Request, Session Created, Hole Punch, 그리고 세션 외 Peer Test 메시지들은 DateTime 블록을 포함해야 합니다.
Alice와 Bob 모두 이러한 메시지들의 시간이 유효한 편차 범위(권장: +/- 2분) 내에 있는지 검증합니다. “probing resistance"를 위해, Bob은 편차가 유효하지 않은 경우 Token Request 또는 Session Request 메시지에 응답해서는 안 됩니다. 이러한 메시지들은 재전송 공격이나 probing 공격일 수 있기 때문입니다.
Bob은 스큐가 유효하더라도 Bloom filter나 다른 메커니즘을 통해 중복된 Token Request 및 Retry 메시지를 거부하도록 선택할 수 있습니다. 하지만 이러한 메시지에 응답하는 크기와 CPU 비용은 낮습니다. 최악의 경우, 재생된 Token Request 메시지가 이전에 전송된 토큰을 무효화할 수 있습니다.
토큰 시스템은 재전송된 Session Request 메시지의 영향을 크게 최소화합니다. 토큰은 한 번만 사용할 수 있으므로, 재전송된 Session Request 메시지는 절대 유효한 토큰을 가질 수 없습니다. Bob은 skew가 유효하더라도 Bloom filter 또는 다른 메커니즘을 통해 중복된 Session Request 메시지를 거부하도록 선택할 수 있습니다. 하지만 Retry 메시지로 응답하는 크기와 CPU 비용은 낮습니다. 최악의 경우, Retry 메시지를 전송하면 이전에 전송된 토큰이 무효화될 수 있습니다.
중복된 Session Created 및 Session Confirmed 메시지는 Noise handshake 상태가 이를 복호화할 올바른 상태에 있지 않기 때문에 검증되지 않습니다. 최악의 경우, 피어는 명백한 중복 Session Created에 대한 응답으로 Session Confirmed를 재전송할 수 있습니다.
재전송된 Hole Punch 및 Peer Test 메시지는 거의 또는 전혀 영향을 주지 않아야 합니다.
Router는 데이터 메시지 패킷 번호를 사용하여 중복된 데이터 단계 메시지를 감지하고 폐기해야 합니다. 각 패킷 번호는 한 번만 사용되어야 합니다. 재전송된 메시지는 무시되어야 합니다.
Handshake Retransmission
Session Request
Alice가 Session Created 또는 Retry를 받지 못한 경우:
동일한 소스 및 연결 ID, 임시 키, 그리고 패킷 번호 0을 유지하세요. 또는 단순히 동일한 암호화된 패킷을 보관하고 재전송하세요. 패킷 번호는 증가시키면 안 됩니다. 왜냐하면 그렇게 하면 Session Created 메시지를 암호화하는 데 사용되는 연쇄 해시 값이 변경되기 때문입니다.
권장 재전송 간격: 1.25, 2.5, 5초 (첫 전송 후 1.25, 3.75, 8.75초). 권장 타임아웃: 총 15초
Session Created
Bob이 Session Confirmed를 받지 못한 경우:
동일한 소스 및 연결 ID, ephemeral key, 그리고 패킷 번호 0을 유지하세요. 또는 암호화된 패킷을 그대로 보관하세요. 패킷 번호는 증가시키면 안 됩니다. 왜냐하면 그렇게 하면 Session Confirmed 메시지를 암호화하는 데 사용되는 연쇄 해시 값이 변경되기 때문입니다.
권장 재전송 간격: 1초, 2초, 4초 (첫 번째 전송 후 1초, 3초, 7초). 권장 타임아웃: 총 12초
Session Confirmed
SSU 1에서 Alice는 Bob으로부터 첫 번째 데이터 패킷을 받을 때까지 데이터 단계로 전환하지 않습니다. 이로 인해 SSU 1은 2라운드 트립 설정이 됩니다.
SSU 2의 경우, 권장되는 Session Confirmed 재전송 간격: 1.25, 2.5, 5초 (첫 전송 후 1.25, 3.75, 8.75초).
여러 대안이 있습니다. 모두 1 RTT입니다:
Alice는 Session Confirmed가 수신되었다고 가정하고, 즉시 데이터 메시지를 전송하며, Session Confirmed를 재전송하지 않습니다. 순서가 맞지 않게 수신된 데이터 패킷들(Session Confirmed 이전에 수신된)은 복호화할 수 없지만 재전송됩니다. Session Confirmed가 손실되면, 전송된 모든 데이터 메시지가 드롭됩니다.
1)과 같이 데이터 메시지를 즉시 전송하되, 데이터 메시지를 받을 때까지 Session Confirmed도 재전송한다.
handshake에서 단 두 개의 메시지만 사용하므로 XK 대신 IK를 사용할 수 있지만, 추가 DH를 사용합니다 (3개 대신 4개).
권장되는 구현은 옵션 2)입니다. Alice는 Session Confirmed 메시지를 재전송하는 데 필요한 정보를 보유해야 합니다. Alice는 또한 Session Confirmed 메시지가 재전송된 후 모든 Data 메시지를 재전송해야 합니다.
Session Confirmed를 재전송할 때는 동일한 소스 및 연결 ID, ephemeral key, 그리고 패킷 번호 1을 유지해야 합니다. 또는 단순히 암호화된 패킷을 보관하면 됩니다. 패킷 번호는 증가시키면 안 되는데, 이는 split() 함수의 입력값인 chained hash 값을 변경시키기 때문입니다.
Bob은 Session Confirmed 메시지를 받기 전에 수신된 데이터 메시지들을 보관(대기열에 저장)할 수 있습니다. Session Confirmed 메시지가 수신되기 전까지는 헤더 보호 키나 복호화 키를 사용할 수 없으므로, Bob은 그것들이 데이터 메시지라는 것을 알 수 없지만 그렇게 추정할 수 있습니다. Session Confirmed 메시지가 수신된 후, Bob은 대기열에 저장된 데이터 메시지들을 복호화하고 처리할 수 있습니다. 이것이 너무 복잡하다면, Alice가 재전송할 것이므로 Bob은 복호화할 수 없는 데이터 메시지들을 그냥 버려도 됩니다.
참고: 세션 확인 패킷이 손실되면, Bob은 세션 생성을 재전송할 것입니다. 세션 생성 헤더는 Bob의 intro key로 설정되어 있기 때문에 Alice의 intro key로는 복호화할 수 없습니다 (Bob의 intro key로 fallback 복호화가 수행되지 않는 한). Bob은 이전에 ack되지 않은 세션 확인 패킷을 즉시 재전송할 수 있으며, 복호화할 수 없는 패킷이 수신된 경우에도 마찬가지입니다.
Token Request
Alice가 Retry를 받지 못한 경우:
동일한 소스 및 연결 ID를 유지합니다. 구현체는 새로운 랜덤 패킷 번호를 생성하고 새 패킷을 암호화할 수 있습니다. 또는 동일한 패킷 번호를 재사용하거나 단순히 동일한 암호화된 패킷을 보존하고 재전송할 수 있습니다. 패킷 번호는 증가시켜서는 안 됩니다. 그렇게 하면 Session Created 메시지를 암호화하는 데 사용되는 체인 해시 값이 변경되기 때문입니다.
권장 재전송 간격: 3초와 6초 (첫 전송 후 3초와 9초). 권장 타임아웃: 총 15초
Retry
Bob이 Session Request를 받지 못한 경우:
Retry 메시지는 위조된 소스 주소의 영향을 줄이기 위해 타임아웃 시 재전송되지 않습니다.
그러나 Retry 메시지는 원래의 (유효하지 않은) 토큰과 함께 반복된 Session Request 메시지가 수신되거나, 반복된 Token Request 메시지에 대한 응답으로 재전송될 수 있습니다. 두 경우 모두 Retry 메시지가 손실되었음을 나타냅니다.
두 번째 Session Request 메시지가 다르지만 여전히 유효하지 않은 토큰과 함께 수신되면, 대기 중인 세션을 드롭하고 응답하지 않습니다.
Retry 메시지를 재전송하는 경우: 동일한 소스 및 연결 ID와 토큰을 유지합니다. 구현체는 새로운 랜덤 패킷 번호를 생성하고 새 패킷을 암호화할 수 있습니다. 또는 동일한 패킷 번호를 재사용하거나 동일한 암호화된 패킷을 보관하고 재전송할 수도 있습니다.
Total Timeout
핸드셰이크에 권장되는 총 타임아웃은 20초입니다.
Duplicates and Error Handling
세 개의 Noise 핸드셰이크 메시지인 Session Request, Session Created, Session Confirmed의 중복은 헤더의 MixHash() 이전에 탐지되어야 합니다. 그 이후에 Noise AEAD 처리가 실패할 것으로 예상되지만, 핸드셰이크 해시는 이미 손상되었을 것입니다.
세 개의 메시지 중 하나라도 손상되어 AEAD가 실패하면, 손상된 메시지에 대해 이미 MixHash()가 호출되었기 때문에 재전송을 하더라도 핸드셰이크를 복구할 수 없습니다.
Tokens
Session Request 헤더의 Token은 DoS 완화, 소스 주소 스푸핑 방지, 그리고 재생 공격에 대한 저항성을 위해 사용됩니다.
Bob이 Session Request 메시지에서 토큰을 수락하지 않으면, Bob은 비용이 많이 드는 DH 연산이 필요하기 때문에 메시지를 복호화하지 않습니다. Bob은 단순히 새로운 토큰과 함께 Retry 메시지를 보냅니다.
해당 토큰과 함께 후속 Session Request 메시지가 수신되면, Bob은 해당 메시지를 복호화하고 핸드셰이크를 진행합니다.
토큰은 토큰 생성기가 값과 연관된 IP 및 포트를 (메모리 내 또는 영구적으로) 저장하는 경우, 무작위로 생성된 8바이트 값이어야 합니다. 생성기는 불투명한 값을 생성해서는 안 됩니다. 예를 들어, IP, 포트, 그리고 현재 시간 또는 날짜의 SipHash(비밀 시드 K0, K1 사용)를 사용하여 메모리에 저장할 필요가 없는 토큰을 만드는 것은, 이 방법이 재사용된 토큰과 재전송 공격을 거부하는 것을 어렵게 만들기 때문입니다.
토큰은 한 번만 사용할 수 있습니다. Retry 메시지에서 Bob이 Alice에게 보낸 토큰은 즉시 사용되어야 하며, 몇 초 후에 만료됩니다. 설정된 세션에서 New Token 블록으로 전송된 토큰은 후속 연결에서 사용할 수 있으며, 해당 블록에서 지정된 시간에 만료됩니다. 만료 시간은 발신자가 지정하며, 권장 값은 최소 1시간, 최대 몇 시간입니다.
router의 IP나 포트가 변경되면, 해당 router는 이전 IP나 포트에 대한 저장된 모든 토큰(인바운드 및 아웃바운드 모두)을 삭제해야 합니다. 이는 더 이상 유효하지 않기 때문입니다. 토큰은 구현에 따라 router 재시작 시에도 선택적으로 유지될 수 있습니다. 만료되지 않은 토큰의 수락이 보장되지는 않습니다. Bob이 저장된 토큰을 잊어버렸거나 삭제했다면, Alice에게 Retry를 보낼 것입니다. Router는 토큰 저장을 제한하도록 선택할 수 있으며, 만료되지 않았더라도 가장 오래된 저장된 토큰을 제거할 수 있습니다.
새로운 Token 블록은 Alice에서 Bob으로 또는 Bob에서 Alice로 전송될 수 있습니다. 일반적으로 세션 설정 중이나 직후에 한 번 전송됩니다. 토큰은 만료 전후에 새로운 만료 시간과 함께 재전송되거나, 새로운 토큰이 전송될 수 있습니다. Router들은 마지막으로 수신된 토큰만이 유효하다고 가정해야 합니다. 동일한 IP/포트에 대해 여러 개의 인바운드 또는 아웃바운드 토큰을 저장할 필요는 없습니다.
토큰은 소스 IP/포트와 목적지 IP/포트의 조합에 바인딩됩니다. IPv4에서 수신된 토큰은 IPv6에 사용할 수 없으며, 그 반대도 마찬가지입니다.
세션 중에 어느 한 peer가 새로운 IP 또는 포트로 이전하는 경우(Connection Migration 섹션 참조), 이전에 교환된 모든 토큰은 무효화되며, 새로운 토큰을 교환해야 합니다.
구현체는 토큰을 디스크에 저장하고 재시작 시 다시 로드할 수 있지만, 반드시 그래야 하는 것은 아닙니다. 지속화되는 경우, 구현체는 토큰을 다시 로드하기 전에 종료 이후 IP와 포트가 변경되지 않았음을 보장해야 합니다.
I2NP Message Fragmentation
SSU 1과의 차이점
참고: SSU 1에서와 같이, 초기 조각(fragment)은 전체 조각 수나 전체 길이에 대한 정보를 포함하지 않습니다. 후속 조각들은 자신의 오프셋에 대한 정보를 포함하지 않습니다. 이는 송신자가 패킷의 사용 가능한 공간을 기반으로 “즉석에서” 조각화할 수 있는 유연성을 제공합니다. (Java I2P는 이렇게 하지 않으며, 첫 번째 조각이 전송되기 전에 “미리 조각화"합니다) 하지만 이는 수신자가 순서에 맞지 않게 수신된 조각들을 저장하고 모든 조각이 수신될 때까지 재조립을 지연시켜야 하는 부담을 줍니다.
SSU 1에서와 같이, 프래그먼트의 재전송은 이전 전송에서의 프래그먼트 길이(및 암시적 오프셋)를 보존해야 합니다.
SSU 2는 처리 효율성을 향상시키기 위해 세 가지 경우(전체 메시지, 초기 프래그먼트, 후속 프래그먼트)를 세 가지 다른 블록 유형으로 분리합니다.
I2NP Message Duplication
이 프로토콜은 I2NP 메시지의 중복 전달을 완전히 방지하지 않습니다. 각 패킷 번호는 한 번만 사용될 수 있기 때문에 IP 계층 중복이나 재생 공격은 SSU2 계층에서 탐지됩니다.
하지만 I2NP 메시지나 프래그먼트가 새로운 패킷으로 재전송될 때는 SSU2 계층에서 이를 감지할 수 없습니다. 라우터는 I2NP 만료를 강제해야 하며(너무 오래된 것과 너무 미래의 것 모두), I2NP 메시지 ID를 기반으로 한 블룸 필터나 다른 메커니즘을 사용해야 합니다.
router나 SSU2 구현에서 중복을 탐지하기 위해 추가적인 메커니즘이 사용될 수 있습니다. 예를 들어, SSU2는 최근에 수신된 메시지 ID의 캐시를 유지할 수 있습니다. 이는 구현에 따라 달라집니다.
Congestion Control
이 제안서는 패킷 번호 매기기 및 ACK 블록에 대한 프로토콜을 명세합니다. 이는 송신자가 효율적이고 반응성이 뛰어난 혼잡 제어 알고리즘을 구현할 수 있도록 충분한 실시간 정보를 제공하는 동시에, 해당 구현에서 유연성과 혁신을 허용합니다. 이 섹션에서는 구현 목표를 논의하고 제안사항을 제공합니다. 일반적인 지침은 RFC 9002에서 찾을 수 있습니다. 재전송 타이머에 대한 지침은 RFC 6298도 참조하십시오.
ACK 전용 데이터 패킷은 전송 중인 바이트나 패킷 수에 포함되지 않아야 하며 혼잡 제어되지 않습니다. TCP와 달리 SSU2는 이러한 패킷의 손실을 감지할 수 있으며, 이 정보는 혼잡 상태를 조정하는 데 사용될 수 있습니다. 그러나 이 문서는 이를 위한 메커니즘을 명시하지 않습니다.
원하는 경우 일부 다른 비데이터 블록을 포함하는 패킷들도 혼잡 제어에서 제외될 수 있으며, 이는 구현에 따라 달라집니다. 예를 들어:
- Peer Test
- 릴레이 요청/소개/응답
- 경로 챌린지/응답
혼잡 제어는 TCP RFC 및 QUIC RFC 9002의 지침에 따라 패킷 수가 아닌 바이트 수를 기반으로 하는 것이 권장됩니다. 커널이나 middlebox에서의 버퍼 오버플로를 방지하기 위해 추가적인 패킷 수 제한도 유용할 수 있으며, 이는 구현에 따라 달라지지만 상당한 복잡성을 추가할 수 있습니다. 세션별 및/또는 전체 패킷 출력이 대역폭 제한 및/또는 속도 제한이 적용되는 경우, 이는 패킷 수 제한의 필요성을 완화할 수 있습니다.
Packet Numbers
SSU 1에서는 ACK와 NACK가 I2NP 메시지 번호와 프래그먼트 비트마스크를 포함했습니다. 송신자들은 아웃바운드 메시지(및 해당 프래그먼트)의 ACK 상태를 추적하고 필요에 따라 프래그먼트를 재전송했습니다.
SSU 2에서 ACK와 NACK은 패킷 번호를 포함합니다. 전송자는 패킷 번호와 그 내용의 매핑을 가진 데이터 구조를 유지해야 합니다. 패킷이 ACK되거나 NACK될 때, 전송자는 해당 패킷에 어떤 I2NP 메시지와 조각들이 있었는지 확인하여 무엇을 재전송할지 결정해야 합니다.
Session Confirmed ACK
Bob은 패킷 0의 ACK를 전송하여 Session Confirmed 메시지를 확인하고 Alice가 데이터 단계로 진행할 수 있도록 하며, 재전송 가능성을 위해 저장되어 있던 큰 Session Confirmed 메시지를 폐기할 수 있게 합니다. 이것은 SSU 1에서 Bob이 전송하던 DeliveryStatusMessage를 대체합니다.
Bob은 Session Confirmed 메시지를 받은 후 가능한 한 빨리 ACK를 보내야 합니다. 작은 지연(50ms 이하)은 허용되는데, 이는 Session Confirmed 메시지 직후에 적어도 하나의 Data 메시지가 거의 즉시 도착해야 하므로 ACK가 Session Confirmed와 Data 메시지를 모두 승인할 수 있기 때문입니다. 이렇게 하면 Bob이 Session Confirmed 메시지를 재전송하지 않아도 됩니다.
Generating ACKs
정의: Ack-eliciting 패킷: ack-eliciting 블록을 포함한 패킷은 최대 승인 지연 시간 내에 수신자로부터 ACK를 유발하며, 이러한 패킷을 ack-eliciting 패킷이라고 합니다.
Router들은 수신하고 처리하는 모든 패킷을 확인응답합니다. 그러나 ack-eliciting 패킷만이 최대 ack 지연 시간 내에 ACK 블록이 전송되도록 합니다. ack-eliciting이 아닌 패킷들은 다른 이유로 ACK 블록이 전송될 때만 확인응답됩니다.
어떤 이유로든 패킷을 전송할 때, 엔드포인트는 최근에 전송되지 않았다면 ACK 블록을 포함시키려고 시도해야 합니다. 이렇게 하면 피어에서 시기적절한 손실 감지에 도움이 됩니다.
일반적으로 수신자로부터의 빈번한 피드백은 손실 및 혼잡 응답을 개선하지만, 이는 모든 ack 유발 패킷에 대해 ACK 블록을 전송하는 수신자에 의해 생성되는 과도한 부하와 균형을 맞춰야 합니다. 아래에 제공된 지침은 이러한 균형을 맞추기 위한 것입니다.
다음을 제외한 모든 블록을 포함하는 세션 내 데이터 패킷은 ack-eliciting입니다:
- ACK 블록
- Address 블록
- DateTime 블록
- Padding 블록
- Termination 블록
- Termination 블록과 동일한 패킷에 있는 모든 블록들
- 기타?
“termination received” 이외의 이유를 가진 Termination 블록을 포함하는 패킷은 “termination received"를 포함하는 Termination 블록이 담긴 패킷으로 확인응답됩니다.
세션 외부 패킷들은 핸드셰이크 메시지와 피어 테스트 메시지 5-7을 포함하여 자체적인 승인 메커니즘을 가지고 있습니다. 아래를 참조하세요.
Handshake ACKs
다음은 특별한 경우들입니다:
- 토큰 요청은 재시도에 의해 암시적으로 확인됨
- 세션 요청은 세션 생성됨 또는 재시도에 의해 암시적으로 확인됨
- 재시도는 세션 요청에 의해 암시적으로 확인됨
- 세션 생성됨은 세션 확정됨에 의해 암시적으로 확인됨
- 세션 확정됨은 즉시 확인되어야 함
Sending ACK Blocks
ACK 블록은 데이터 단계 패킷을 승인하는 데 사용됩니다. 이는 세션 내 데이터 단계 패킷에 대해서만 포함되어야 합니다.
모든 패킷은 최소한 한 번은 확인되어야 하며, ack를 유발하는 패킷은 최대 지연 시간 내에 최소한 한 번은 확인되어야 합니다.
엔드포인트는 다음 예외를 제외하고 모든 ack-eliciting 핸드셰이크 패킷을 최대 지연 시간 내에 즉시 승인해야 합니다. 핸드셰이크 확인 이전에 엔드포인트는 패킷을 수신했을 때 복호화하기 위한 패킷 헤더 암호화 키를 가지고 있지 않을 수 있습니다. 따라서 이러한 패킷들을 버퍼링하고 필요한 키를 사용할 수 있게 되었을 때 승인할 수 있습니다.
ACK 블록만 포함하는 패킷은 혼잡 제어되지 않으므로, 엔드포인트는 ack-eliciting 패킷을 수신하는 것에 대한 응답으로 그러한 패킷을 하나 이상 전송해서는 안 됩니다.
엔드포인트는 non-ack-eliciting 패킷에 대한 응답으로 non-ack-eliciting 패킷을 전송해서는 안 되며, 수신된 패킷 이전에 패킷 갭이 있더라도 마찬가지입니다. 이는 승인의 무한 피드백 루프를 방지하여 연결이 유휴 상태가 되는 것을 막을 수 있습니다. Non-ack-eliciting 패킷들은 엔드포인트가 다른 이벤트에 대한 응답으로 ACK 블록을 전송할 때 결국 승인됩니다.
ACK 블록만 전송하는 endpoint는 해당 acknowledgment가 ack-eliciting 블록을 포함하는 패킷에 포함되지 않는 한 피어로부터 acknowledgment를 받지 못합니다. endpoint는 새로운 ack-eliciting 패킷을 acknowledge해야 할 때 다른 블록과 함께 ACK 블록을 전송해야 합니다. non-ack-eliciting 패킷만 acknowledge해야 하는 경우, endpoint는 ack-eliciting 패킷을 받을 때까지 outgoing 블록과 함께 ACK 블록을 전송하지 않도록 선택할 수 있습니다.
비확인응답 유발 패킷만을 전송하는 엔드포인트는 확인응답을 수신하도록 보장하기 위해 때때로 해당 패킷에 확인응답 유발 블록을 추가하도록 선택할 수 있습니다. 이 경우, 엔드포인트는 확인응답의 무한 피드백 루프를 방지하기 위해 그렇지 않으면 비확인응답 유발이 될 모든 패킷에 확인응답 유발 블록을 전송해서는 안 됩니다.
송신자의 손실 감지를 돕기 위해, 엔드포인트는 다음 경우 중 하나에서 ACK 유도 패킷을 수신했을 때 지연 없이 ACK 블록을 생성하고 전송해야 합니다:
수신된 패킷의 패킷 번호가 이미 수신된 다른 ack-eliciting 패킷보다 작을 때
패킷이 수신된 가장 높은 번호의 ack-eliciting 패킷보다 큰 패킷 번호를 가지고 있고, 해당 패킷과 이 패킷 사이에 누락된 패킷들이 있을 때.
패킷 헤더의 ack-immediate 플래그가 설정되었을 때
알고리즘들은 위에서 제공된 지침을 따르지 않는 수신자들에 대해서도 복원력을 가질 것으로 예상됩니다. 그러나 구현체는 엔드포인트에서 만들어진 연결과 네트워크의 다른 사용자들에게 미치는 성능 영향을 신중히 고려한 후에만 이러한 요구사항에서 벗어나야 합니다.
ACK Frequency
수신자는 ack-eliciting 패킷에 대한 응답으로 확인 응답을 얼마나 자주 보낼지 결정합니다. 이 결정에는 트레이드오프가 수반됩니다.
엔드포인트는 손실을 감지하기 위해 적시 확인응답에 의존합니다. 윈도우 기반 혼잡 제어기는 혼잡 윈도우를 관리하기 위해 확인응답에 의존합니다. 두 경우 모두 확인응답 지연은 성능에 악영향을 미칠 수 있습니다.
반면에, 확인응답만을 전송하는 패킷의 빈도를 줄이면 양쪽 끝점에서 패킷 전송 및 처리 비용이 감소합니다. 이는 심각하게 비대칭인 링크에서 연결 처리량을 개선할 수 있고 복귀 경로 용량을 사용하는 확인응답 트래픽의 양을 줄일 수 있습니다. RFC 3449의 Section 3을 참조하십시오.
수신자는 최소 두 개의 ack-eliciting 패킷을 받은 후 ACK 블록을 보내야 합니다. 이 권고사항은 일반적인 성격을 가지며 TCP 엔드포인트 동작에 대한 권고사항 RFC 5681과 일치합니다. 네트워크 상태에 대한 지식, 피어의 혼잡 제어기에 대한 지식, 또는 추가적인 연구와 실험을 통해 더 나은 성능 특성을 가진 대안적인 확인응답 전략을 제안할 수 있습니다.
수신자는 응답으로 ACK 블록을 보낼지 결정하기 전에 사용 가능한 여러 패킷을 처리할 수 있습니다. 일반적으로 수신자는 RTT / 6 또는 최대 150ms 이상 ACK를 지연해서는 안 됩니다.
데이터 패킷 헤더의 ack-immediate 플래그는 수신자가 수신 후 곧바로, 아마도 몇 ms 내에 ack을 보내달라는 요청입니다. 일반적으로 수신자는 즉시 ACK를 RTT / 16 또는 최대 5ms 이상 지연시켜서는 안 됩니다.
Immediate ACK Flag
수신자는 송신자의 전송 윈도우 크기를 알지 못하므로, ACK를 보내기 전에 얼마나 지연해야 하는지 모릅니다. 데이터 패킷 헤더의 즉시 ACK 플래그는 효과적인 RTT를 최소화하여 최대 처리량을 유지하는 중요한 방법입니다. 즉시 ACK 플래그는 헤더 바이트 13, 비트 0, 즉 (header[13] & 0x01)입니다. 설정되면 즉시 ACK가 요청됩니다. 자세한 내용은 위의 짧은 헤더 섹션을 참조하십시오.
송신자가 immediate-ack 플래그를 언제 설정할지 결정하기 위해 사용할 수 있는 몇 가지 가능한 전략이 있습니다:
- 작은 N 값에 대해 N개 패킷마다 한 번씩 설정
- 패킷 버스트의 마지막에 설정
- 송신 윈도우가 거의 가득 찰 때 설정, 예를 들어 2/3 이상 가득 찰 때
- 재전송된 fragment가 포함된 모든 패킷에 설정
즉시 ACK 플래그는 I2NP 메시지 또는 메시지 조각을 포함하는 데이터 패킷에서만 필요해야 합니다.
ACK Block Size
ACK 블록이 전송될 때, 확인응답된 패킷의 하나 이상의 범위가 포함됩니다. 이전 패킷에 대한 확인응답을 포함하면 이전에 전송된 ACK 블록의 손실로 인한 의사 재전송 가능성을 줄일 수 있지만, ACK 블록이 더 커지는 비용이 발생합니다.
ACK 블록은 항상 가장 최근에 수신된 패킷들을 확인해야 하며, 패킷들이 순서에서 벗어날수록 업데이트된 ACK 블록을 빠르게 전송하는 것이 더욱 중요합니다. 이는 피어가 패킷을 손실된 것으로 선언하고 포함된 블록들을 잘못 재전송하는 것을 방지하기 위함입니다. ACK 블록은 단일 패킷 내에 맞아야 합니다. 맞지 않는 경우, 더 오래된 범위들(가장 작은 패킷 번호를 가진 것들)이 생략됩니다.
수신자는 ACK 블록의 크기를 제한하고 리소스 고갈을 방지하기 위해 기억하고 ACK 블록에서 전송하는 ACK 범위의 수를 제한합니다. ACK 블록에 대한 확인응답을 받은 후, 수신자는 해당 확인응답된 ACK 범위들을 추적하는 것을 중단해야 합니다. 송신자는 대부분의 패킷에 대한 확인응답을 기대할 수 있지만, 이 프로토콜은 수신자가 처리하는 모든 패킷에 대한 확인응답 수신을 보장하지는 않습니다.
많은 ACK 범위를 유지하는 것은 ACK 블록이 너무 커질 수 있는 원인이 될 수 있습니다. 수신자는 ACK 블록 크기를 제한하기 위해 확인되지 않은 ACK 범위를 폐기할 수 있지만, 이는 송신자로부터의 재전송 증가라는 비용을 수반합니다. 이는 ACK 블록이 패킷에 맞기에는 너무 클 경우 필요한 조치입니다. 수신자는 또한 다른 블록을 위한 공간을 확보하거나 확인응답이 소비하는 대역폭을 제한하기 위해 ACK 블록 크기를 더욱 제한할 수 있습니다.
수신자는 해당 범위의 번호를 가진 패킷을 이후에 수락하지 않을 것임을 보장할 수 있는 경우가 아니라면 ACK 범위를 유지해야 합니다. 범위가 폐기됨에 따라 증가하는 최소 패킷 번호를 유지하는 것은 최소한의 상태로 이를 달성하는 한 가지 방법입니다.
수신자는 모든 ACK 범위를 폐기할 수 있지만, 성공적으로 처리된 가장 큰 패킷 번호는 유지해야 합니다. 이는 후속 패킷에서 패킷 번호를 복구하는 데 사용되기 때문입니다.
다음 섹션에서는 각 ACK 블록에서 어떤 패킷을 승인할지 결정하는 예시적인 접근 방법을 설명합니다. 이 알고리즘의 목표는 처리되는 모든 패킷에 대해 승인을 생성하는 것이지만, 여전히 승인이 손실될 가능성이 있습니다.
Limiting Ranges by Tracking ACK Blocks
ACK 블록을 포함한 패킷이 전송될 때, 해당 블록의 Ack Through 필드를 저장할 수 있습니다. ACK 블록을 포함한 패킷이 승인되면, 수신자는 전송된 ACK 블록의 Ack Through 필드보다 작거나 같은 패킷들에 대한 승인을 중단할 수 있습니다.
ACK 블록과 같이 non-ack-eliciting 패킷만을 전송하는 수신기는 장기간 동안 확인응답을 받지 못할 수 있습니다. 이는 수신기가 많은 수의 ACK 블록에 대한 상태를 장기간 유지하게 하고, 전송하는 ACK 블록이 불필요하게 클 수 있습니다. 이러한 경우, 수신기는 피어로부터 ACK를 유도하기 위해 라운드 트립당 한 번과 같이 가끔씩 PING 또는 다른 작은 ack-eliciting 블록을 전송할 수 있습니다.
ACK 블록 손실이 없는 경우, 이 알고리즘은 최소 1 RTT의 재정렬을 허용합니다. ACK 블록 손실과 재정렬이 있는 경우, 이 접근 방식은 모든 확인응답이 ACK 블록에 더 이상 포함되지 않기 전에 송신자가 확인할 수 있음을 보장하지 않습니다. 패킷이 순서대로 수신되지 않을 수 있으며, 이를 포함하는 모든 후속 ACK 블록이 손실될 수 있습니다. 이 경우 손실 복구 알고리즘이 가짜 재전송을 유발할 수 있지만, 송신자는 계속해서 전진 진행을 할 것입니다.
Congestion
I2P 전송은 I2NP 메시지의 순서대로 전달을 보장하지 않습니다. 따라서 하나 이상의 I2NP 메시지나 조각을 포함하는 Data 메시지의 손실이 다른 I2NP 메시지의 전달을 방해하지 않습니다. 즉, head-of-line blocking이 발생하지 않습니다. 구현체는 송신 윈도우가 허용하는 경우 손실 복구 단계 중에도 새로운 메시지를 계속 전송해야 합니다.
Retransmission
발송자는 동일하게 재전송하기 위해 메시지의 전체 내용을 보관해서는 안 됩니다 (핸드셰이크 메시지는 예외, 위 참조). 발송자는 메시지를 보낼 때마다 최신 정보(ACK, NACK, 미승인 데이터)가 포함된 메시지를 조립해야 합니다. 발송자는 메시지가 승인된 후에는 해당 메시지의 정보를 재전송하지 않아야 합니다. 여기에는 손실로 선언된 후 승인되는 메시지도 포함되며, 이는 네트워크 재정렬이 있을 때 발생할 수 있습니다.
Window
TBD. 일반적인 지침은 RFC 9002에서 찾을 수 있습니다.
Connection Migration
세션의 수명 동안 peer의 IP나 포트가 변경될 수 있습니다. IP 변경은 IPv6 임시 주소 순환, ISP 주도의 주기적 IP 변경, WiFi와 셀룰러 IP 간 전환하는 모바일 클라이언트, 또는 기타 로컬 네트워크 변경으로 인해 발생할 수 있습니다. 포트 변경은 이전 바인딩이 시간 초과된 후 NAT 리바인딩으로 인해 발생할 수 있습니다.
피어의 IP 또는 포트는 패킷 수정이나 주입을 포함한 다양한 경로상 및 경로외 공격으로 인해 변경된 것처럼 보일 수 있습니다.
연결 마이그레이션은 새로운 소스 엔드포인트(IP+포트)가 검증되는 과정으로, 검증되지 않은 변경사항을 방지합니다. 이 과정은 QUIC RFC 9000에 정의된 것의 단순화된 버전입니다. 이 과정은 세션의 데이터 단계에서만 정의됩니다. 핸드셰이크 중에는 마이그레이션이 허용되지 않습니다. 모든 핸드셰이크 패킷은 이전에 송신 및 수신된 패킷과 동일한 IP와 포트에서 온 것임이 검증되어야 합니다. 다시 말해, 피어의 IP와 포트는 핸드셰이크 중에 일정해야 합니다.
Threat Model
(QUIC RFC 9000에서 각색)
참고사항
peer는 소스 주소를 스푸핑하여 endpoint가 원하지 않는 호스트에 과도한 양의 데이터를 전송하도록 할 수 있습니다. endpoint가 스푸핑하는 peer보다 훨씬 많은 데이터를 전송하는 경우, connection migration이 공격자가 피해자를 향해 생성할 수 있는 데이터 볼륨을 증폭시키는 데 사용될 수 있습니다.
세션 확인 단편화
경로상의 공격자는 스푸핑된 주소로 패킷을 복사하고 전달하여 원본 패킷보다 먼저 도착하도록 함으로써 가짜 연결 마이그레이션을 유발할 수 있습니다. 스푸핑된 주소를 가진 패킷은 마이그레이션하는 연결에서 온 것으로 보이고, 원본 패킷은 중복으로 간주되어 드롭됩니다. 가짜 마이그레이션 후에는 소스 주소의 유효성 검증이 실패하는데, 이는 소스 주소의 엔티티가 전송된 Path Challenge를 읽거나 응답하는 데 필요한 암호화 키를 가지고 있지 않기 때문입니다. 설사 응답하고 싶어도 말이죠.
Off-Path Packet Forwarding
패킷을 관찰할 수 있는 경로 외부 공격자는 진짜 패킷의 복사본을 엔드포인트로 전달할 수 있습니다. 복사된 패킷이 진짜 패킷보다 먼저 도착하면, 이는 NAT 재바인딩으로 나타날 것입니다. 진짜 패킷은 중복으로 간주되어 폐기됩니다. 공격자가 계속해서 패킷을 전달할 수 있다면, 공격자를 통한 경로로의 마이그레이션을 유발할 수 있을 것입니다. 이는 공격자를 경로상에 위치시켜 모든 후속 패킷을 관찰하거나 차단할 수 있는 능력을 제공합니다.
Privacy Implications
QUIC RFC 9000은 네트워크 경로를 변경할 때 연결 ID를 변경하도록 명시했습니다. 여러 네트워크 경로에서 안정적인 연결 ID를 사용하면 수동적 관찰자가 해당 경로들 간의 활동을 상관관계로 연결할 수 있게 됩니다. 네트워크 간을 이동하는 엔드포인트는 자신의 피어가 아닌 다른 개체에 의해 자신의 활동이 상관관계로 연결되는 것을 원하지 않을 수 있습니다. 그러나 QUIC는 헤더의 연결 ID를 암호화하지 않습니다. SSU2는 이를 암호화하므로, 프라이버시 누출이 발생하려면 수동적 관찰자가 연결 ID를 복호화하는 데 필요한 소개 키를 얻기 위해 네트워크 데이터베이스에도 접근할 수 있어야 합니다. 소개 키를 가지고 있다 하더라도 이는 강력한 공격이 아니며, SSU2에서는 마이그레이션 후 연결 ID를 변경하지 않습니다. 이는 상당한 복잡성을 야기할 수 있기 때문입니다.
Initiating Path Validation
데이터 단계에서 피어들은 수신된 각 데이터 패킷의 소스 IP와 포트를 확인해야 합니다. IP 또는 포트가 이전에 수신된 것과 다르고, 패킷이 중복 패킷 번호가 아니며, 패킷이 성공적으로 복호화되는 경우, 세션은 경로 검증 단계로 진입합니다.
또한, 피어는 새로운 IP와 포트가 로컬 검증 규칙에 따라 유효한지 확인해야 합니다(차단되지 않음, 불법 포트가 아님 등). 피어는 IPv4와 IPv6 간의 마이그레이션을 지원할 필요가 없으며, 다른 주소 패밀리의 새로운 IP를 무효한 것으로 처리할 수 있습니다. 이는 예상되지 않는 동작이며 구현 복잡성을 크게 증가시킬 수 있기 때문입니다. 무효한 IP/포트에서 패킷을 수신했을 때, 구현은 단순히 패킷을 드롭하거나 이전 IP/포트로 경로 검증을 시작할 수 있습니다.
경로 검증 단계에 진입하면 다음 단계를 수행하세요:
- 몇 초간, 또는 현재 RTO의 몇 배에 해당하는 경로 검증 타임아웃 타이머를 시작 (TBD)
- 혼잡 윈도우를 최소값으로 감소
- PMTU를 최소값(1280)으로 감소
- 새로운 IP와 포트로 Path Challenge 블록, Address 블록(새로운 IP/포트 포함), 그리고 일반적으로 ACK 블록을 포함하는 데이터 패킷을 전송. 이 패킷은 현재 세션과 동일한 connection ID와 암호화 키를 사용. Path Challenge 블록 데이터는 스푸핑될 수 없도록 충분한 엔트로피(최소 8바이트)를 포함해야 함.
- 선택적으로, 다른 블록 데이터로 기존 IP/포트에도 Path Challenge를 전송. 아래 참조.
- 현재 RTO를 기반으로 한 Path Response 타임아웃 타이머 시작 (일반적으로 RTT + RTTdev의 배수)
경로 검증 단계에서 세션은 들어오는 패킷을 계속 처리할 수 있습니다. 이전 또는 새로운 IP/포트에서 오는 패킷 모두 해당됩니다. 세션은 또한 데이터 패킷을 계속 전송하고 확인응답할 수 있습니다. 그러나 스푸핑된 주소로 대량의 트래픽을 전송하여 서비스 거부 공격에 이용되는 것을 방지하기 위해, 경로 검증 단계 동안 혼잡 윈도우와 PMTU는 최소값을 유지해야 합니다.
구현체는 여러 경로를 동시에 검증하려고 시도할 수 있지만, 반드시 그럴 필요는 없습니다. 이는 아마도 복잡성에 비해 가치가 없을 것입니다. 구현체는 이전 IP/포트가 이미 검증되었음을 기억하고, 피어가 이전 IP/포트로 돌아온다면 경로 검증을 건너뛸 수 있지만, 반드시 그럴 필요는 없습니다.
Path Challenge에서 전송된 동일한 데이터가 포함된 Path Response가 수신되면 Path Validation이 성공한 것입니다. Path Response 메시지의 소스 IP/포트는 Path Challenge가 전송된 곳과 동일할 필요가 없습니다.
Path Response timer가 만료되기 전에 Path Response를 받지 못하면, 다른 Path Challenge를 보내고 Path Response timer를 두 배로 늘립니다.
Path Validation 타이머가 만료되기 전에 Path Response가 수신되지 않으면 Path Validation이 실패한 것입니다.
Message Contents
Data 메시지는 다음 블록들을 포함해야 합니다. Padding이 마지막이어야 한다는 점을 제외하고는 순서가 지정되지 않습니다:
- Path Validation 또는 Path Response 블록. Path Validation은 불투명한 데이터를 포함하며, 최소 8바이트 권장. Path Response는 Path Validation의 데이터를 포함.
- 수신자의 apparent IP를 포함하는 Address 블록
- DateTime 블록
- ACK 블록
- Padding 블록
메시지에 다른 블록(예: I2NP)을 포함하는 것은 권장되지 않습니다.
Path Response를 포함하는 메시지에 Path Validation 블록을 포함하여 반대 방향으로 검증을 시작하는 것이 허용됩니다.
Path Challenge와 Path Response 블록은 ACK-eliciting입니다. Path Challenge는 Path Response와 ACK 블록을 포함하는 Data 메시지로 ACK됩니다. Path Response는 ACK 블록을 포함하는 Data 메시지로 ACK되어야 합니다.
Routing during Path Validation
QUIC 사양은 경로 검증 중에 데이터 패킷을 어디로 보낼지에 대해 명확하지 않습니다 - 기존 IP/포트로 보낼지 새로운 IP/포트로 보낼지 말입니다. IP/포트 변경에 신속하게 응답하는 것과 스푸핑된 주소로 트래픽을 보내지 않는 것 사이에서 균형을 맞춰야 합니다. 또한 스푸핑된 패킷이 기존 세션에 실질적인 영향을 미치도록 허용해서는 안 됩니다. 포트만 변경되는 경우는 유휴 기간 후 NAT 리바인딩으로 인해 발생할 가능성이 높으며, IP 변경은 한 방향 또는 양방향에서 고트래픽 단계 중에 발생할 수 있습니다.
전략들은 연구와 개선의 대상입니다. 가능성에는 다음이 포함됩니다:
- 새로운 IP/포트가 검증될 때까지 데이터 패킷을 전송하지 않음
- 새로운 IP/포트가 검증될 때까지 기존 IP/포트로 데이터 패킷을 계속 전송
- 기존 IP/포트를 동시에 재검증
- 기존 또는 새로운 IP/포트 중 하나가 검증될 때까지 데이터를 전송하지 않음
- IP 변경과 포트만 변경하는 경우에 대한 서로 다른 전략
- 임시 주소 순환으로 인해 발생할 가능성이 높은 동일한 /32 내에서의 IPv6 변경에 대한 서로 다른 전략
Responding to Path Challenge
Path Challenge를 수신하면, 피어는 Path Challenge의 데이터를 포함하는 Path Response가 담긴 데이터 패킷으로 응답해야 합니다. TODO 아마도???: Path Response는 Path Challenge가 수신된 IP/포트로 전송되어야 합니다. 이는 피어에 대해 이전에 설정된 IP/포트와 반드시 같을 필요는 없습니다. 이를 통해 피어의 경로 검증은 경로가 양방향으로 기능할 때만 성공하도록 보장됩니다. 아래의 로컬 변경 후 검증 섹션을 참조하세요.
peer의 이전에 알려진 IP/port와 IP/port가 다르지 않는 한, Path Challenge를 단순한 ping으로 취급하고 Path Response로 무조건적으로 응답하면 됩니다. 수신자는 수신된 Path Challenge를 기반으로 어떤 상태도 유지하거나 변경하지 않습니다. IP/port가 다른 경우, peer는 새로운 IP와 port가 로컬 검증 규칙에 따라 유효한지(차단되지 않았는지, 불법 포트가 아닌지 등) 확인해야 합니다. Peer들은 IPv4와 IPv6 간의 교차 주소 패밀리 응답을 지원할 필요가 없으며, 이는 예상되는 동작이 아니므로 다른 주소 패밀리의 새로운 IP를 무효한 것으로 취급할 수 있습니다.
혼잡 제어에 의해 제한되지 않는 한, Path Response는 즉시 전송되어야 합니다. 구현체들은 필요한 경우 Path Response의 전송률을 제한하거나 사용되는 대역폭을 제한하는 조치를 취해야 합니다.
Path Challenge 블록은 일반적으로 같은 메시지 내에서 Address 블록과 함께 제공됩니다. address 블록에 새로운 IP/포트가 포함되어 있다면, 피어는 해당 IP/포트를 검증하고 세션 피어나 다른 피어와 함께 그 새로운 IP/포트에 대한 피어 테스팅을 시작할 수 있습니다. 피어가 자신이 방화벽으로 차단되어 있다고 생각하고 포트만 변경된 경우, 이러한 변경은 아마도 NAT rebinding으로 인한 것이며, 추가적인 피어 테스팅은 아마도 필요하지 않을 것입니다.
Successful Path Validation
경로 검증이 성공하면 연결이 새로운 IP/포트로 완전히 이전됩니다. 성공 시:
- 경로 검증 단계를 종료합니다
- 모든 패킷이 새로운 IP와 포트로 전송됩니다.
- 혼잡 윈도우와 PMTU에 대한 제한이 제거되고, 증가가 허용됩니다. 새로운 경로가 다른 특성을 가질 수 있으므로 이전 값으로 단순히 복원하지 마십시오.
- IP가 변경된 경우, 계산된 RTT와 RTO를 초기값으로 설정합니다. 포트만 변경되는 경우는 일반적으로 NAT 리바인딩이나 다른 미들박스 활동의 결과이므로, 피어는 초기값으로 되돌리는 대신 이러한 경우에 혼잡 제어 상태와 왕복 시간 추정값을 유지할 수 있습니다.
- 이전 IP/포트에 대해 전송되거나 수신된 토큰을 삭제(무효화)합니다 (선택사항)
- 새로운 IP/포트에 대해 새로운 토큰 블록을 전송합니다 (선택사항)
Cancelling Path Validation
경로 검증 단계에서 이전 IP/포트로부터 수신된 유효하고 중복되지 않은 패킷이 성공적으로 복호화될 경우 경로 검증이 취소됩니다. 스푸핑된 패킷으로 인해 취소된 경로 검증이 유효한 세션을 종료시키거나 심각하게 방해하지 않도록 하는 것이 중요합니다.
취소된 경로 검증에 대해:
- 경로 검증 단계를 종료합니다
- 모든 패킷이 이전 IP와 포트로 전송됩니다.
- 혼잡 윈도우와 PMTU에 대한 제한이 제거되고, 증가가 허용되거나 선택적으로 이전 값을 복원할 수 있습니다
- 이전에 새로운 IP/포트로 전송되었던 모든 데이터 패킷을 이전 IP/포트로 재전송합니다.
Failed Path Validation
스푸핑된 패킷으로 인해 발생한 경로 검증 실패가 유효한 세션을 종료하거나 심각하게 중단시키지 않도록 하는 것이 중요합니다.
경로 검증 실패 시:
- path validation 단계를 종료
- 모든 패킷이 이전 IP와 포트로 전송됩니다.
- congestion window와 PMTU에 대한 제한이 해제되고, 증가가 허용됩니다.
- 선택적으로, 이전 IP와 포트에서 path validation을 시작합니다. 실패할 경우 세션을 종료합니다.
- 그렇지 않으면 표준 세션 타임아웃 및 종료 규칙을 따릅니다.
- 이전에 새로운 IP/포트로 전송된 모든 데이터 패킷을 이전 IP/포트로 재전송합니다.
Validation After Local Change
위의 프로세스는 변경된 IP/포트에서 패킷을 받은 peer들을 위해 정의되었습니다. 하지만 이는 자신의 IP나 포트가 변경되었음을 감지한 peer가 반대 방향으로 시작할 수도 있습니다. peer는 자신의 로컬 IP가 변경되었음을 감지할 수 있을 수도 있지만, NAT 재바인딩으로 인해 자신의 포트가 변경되었음을 감지할 가능성은 훨씬 낮습니다. 따라서 이는 선택사항입니다.
IP나 포트가 변경된 피어로부터 경로 챌린지를 수신하면, 다른 피어는 반대 방향으로 경로 챌린지를 시작해야 합니다.
릴레이 보안
Path Validation 및 Path Response 블록은 언제든지 Ping/Pong 패킷으로 사용될 수 있습니다. Path Validation 블록의 수신은 다른 IP/포트에서 수신되지 않는 한 수신자에서 어떤 상태도 변경하지 않습니다.
Multiple Sessions
피어들은 SSU 1 또는 2인지에 관계없이, 또는 동일하거나 다른 IP 주소를 사용하는지에 관계없이 동일한 피어와 다중 세션을 설정해서는 안 됩니다. 그러나 버그, 이전 세션 종료 메시지 손실, 또는 종료 메시지가 아직 도착하지 않은 경합 상황으로 인해 이러한 상황이 발생할 수 있습니다.
Bob이 Alice와 기존 세션을 가지고 있는 경우, Bob이 Alice로부터 Session Confirmed를 받아 핸드셰이크를 완료하고 새로운 세션을 설정할 때, Bob은 다음과 같이 해야 합니다:
- 이전 세션에서 전송되지 않았거나 확인되지 않은 아웃바운드 I2NP 메시지를 새 세션으로 마이그레이션
- 이전 세션에서 이유 코드 22로 종료 신호 전송
- 이전 세션을 제거하고 새 세션으로 교체
Session Termination
피어 테스트 보안
handshake 단계에 있는 세션들은 일반적으로 단순히 시간 초과되거나 더 이상 응답하지 않음으로써 종료됩니다. 선택적으로, 응답에 Termination 블록을 포함시켜 종료할 수도 있지만, 암호화 키의 부족으로 인해 대부분의 오류들은 응답할 수 없습니다. termination 블록을 포함한 응답을 위한 키가 사용 가능하더라도, 응답을 위해 DH를 수행하는 것은 보통 CPU 비용에 비해 가치가 없습니다. 예외적으로 재시도 메시지의 Termination 블록은 생성 비용이 저렴하므로 사용될 수 있습니다.
릴레이 및 피어 테스트 설계 목표
데이터 단계의 세션은 Termination 블록을 포함하는 데이터 메시지를 전송하여 종료됩니다. 이 메시지는 ACK 블록도 포함해야 합니다. 세션이 충분히 오래 지속되어 이전에 전송된 토큰이 만료되었거나 곧 만료될 예정인 경우, New Token 블록을 포함할 수 있습니다. 이 메시지는 ack-eliciting하지 않습니다. “Termination Received"를 제외한 어떤 이유로든 Termination 블록을 수신하면, 피어는 “Termination Received” 이유를 포함한 Termination 블록이 담긴 데이터 메시지로 응답합니다.
Termination 블록을 보내거나 받은 후, 세션은 TBD인 최대 기간 동안 종료 단계에 진입해야 합니다. 종료 상태는 Termination 블록을 포함한 패킷이 손실되는 것과 다른 방향으로 전송 중인 패킷들로부터 보호하기 위해 필요합니다. 종료 단계에 있는 동안, 추가로 수신된 패킷을 처리할 요구사항은 없습니다. 종료 상태에 있는 세션은 해당 세션에 귀속되는 모든 수신 패킷에 대한 응답으로 Termination 블록을 포함한 패킷을 전송합니다. 세션은 종료 상태에서 패킷을 생성하는 속도를 제한해야 합니다. 예를 들어, 세션은 수신 패킷에 응답하기 전에 점진적으로 증가하는 수의 수신 패킷 또는 시간을 기다릴 수 있습니다.
종료되는 세션에 대해 router가 유지하는 상태를 최소화하기 위해, 세션은 수신된 패킷에 대한 응답으로 동일한 패킷 번호를 가진 정확히 같은 패킷을 그대로 전송할 수 있지만, 반드시 그래야 하는 것은 아닙니다. 참고: 종료 패킷의 재전송을 허용하는 것은 각 패킷에 새로운 패킷 번호를 사용해야 한다는 요구사항의 예외입니다. 새로운 패킷 번호를 전송하는 것은 주로 손실 복구 및 혼잡 제어에 유리하며, 이는 종료된 연결에서는 관련성이 없을 것으로 예상됩니다. 최종 패킷을 재전송하는 것은 더 적은 상태를 필요로 합니다.
“Termination Received” 사유가 포함된 Termination 블록을 수신한 후, 세션은 종료 단계를 종료할 수 있습니다.
Cleanup
정상적이거나 비정상적인 종료 시, router는 핸드셰이크 임시 키, 대칭 암호화 키 및 관련 정보를 포함하여 메모리 내 모든 임시 데이터를 제로화해야 합니다.
MTU
요구사항은 게시된 주소가 SSU 1과 공유되는지 여부에 따라 달라집니다. 현재 SSU 1 IPv4 최소값은 620이며, 이는 확실히 너무 작습니다.
최소 SSU2 MTU는 IPv4와 IPv6 모두에서 1280이며, 이는 RFC 9000에서 명시된 것과 동일합니다. 아래를 참조하세요. 최소 MTU를 증가시킴으로써 1 KB tunnel 메시지와 짧은 tunnel 빌드 메시지가 하나의 데이터그램에 들어갈 수 있게 되어, 일반적인 단편화량을 크게 줄일 수 있습니다. 이는 또한 최대 I2NP 메시지 크기의 증가를 가능하게 합니다. 1820바이트 스트리밍 메시지는 두 개의 데이터그램에 들어갈 수 있을 것입니다.
router는 해당 주소의 MTU가 최소 1280이 아닌 한 SSU2를 활성화하거나 SSU2 주소를 게시해서는 안 됩니다.
router들은 각 SSU 또는 SSU2 router 주소에서 기본값이 아닌 MTU를 게시해야 합니다.
요약
SSU 1과 주소를 공유하며, SSU 1 규칙을 따라야 합니다. IPv4: 기본값 및 최대값은 1484입니다. 최소값은 1292입니다. (IPv4 MTU + 4)는 16의 배수여야 합니다. IPv6: 반드시 게시되어야 하며, 최소값은 1280, 최대값은 1488입니다. IPv6 MTU는 16의 배수여야 합니다.
전송 보장
IPv4: 기본값과 최대값은 1500입니다. 최소값은 1280입니다. IPv6: 기본값과 최대값은 1500입니다. 최소값은 1280입니다. 16의 배수 규칙은 없지만, 최소한 2의 배수여야 합니다.
Noise Protocol Framework
SSU 1의 경우, 현재 Java I2P는 작은 패킷으로 시작하여 점진적으로 크기를 늘리거나 수신된 패킷 크기를 기반으로 늘리는 방식으로 PMTU 탐지를 수행합니다. 이는 조잡하며 효율성을 크게 떨어뜨립니다. SSU 2에서 이 기능을 계속 사용할지는 미정입니다.
최근 연구 PMTU에 따르면 IPv4에서 1200 이상의 최소값이 99% 이상의 연결에서 작동할 것으로 제안됩니다. QUIC RFC 9000은 최소 IP 패킷 크기로 1280바이트를 요구합니다.
RFC 9000에서 인용:
최대 데이터그램 크기는 단일 UDP 데이터그램을 사용하여 네트워크 경로를 통해 전송할 수 있는 UDP 페이로드의 가장 큰 크기로 정의됩니다. 네트워크 경로가 최소 1200바이트의 최대 데이터그램 크기를 지원할 수 없는 경우 QUIC을 사용해서는 안 됩니다.
QUIC은 최소 1280바이트의 IP 패킷 크기를 가정합니다. 이는 IPv6 최소 크기 [IPv6]이며 대부분의 현대 IPv4 네트워크에서도 지원됩니다. IPv6의 최소 IP 헤더 크기 40바이트와 IPv4의 20바이트, 그리고 UDP 헤더 크기 8바이트를 가정하면, 이는 IPv6에서 최대 데이터그램 크기 1232바이트, IPv4에서 1252바이트가 됩니다. 따라서 현대 IPv4와 모든 IPv6 네트워크 경로는 QUIC을 지원할 수 있을 것으로 예상됩니다.
참고: UDP 페이로드 1200바이트를 지원해야 한다는 이 요구사항은 경로가 IPv6 최소 MTU인 1280바이트만 지원하는 경우 IPv6 확장 헤더에 사용 가능한 공간을 32바이트로, IPv4 옵션에 사용 가능한 공간을 52바이트로 제한합니다. 이는 Initial 패킷과 경로 검증에 영향을 줍니다.
인용 끝
프레임워크에 대한 추가 사항
QUIC는 증폭 공격을 방지하고 양방향 PMTU가 이를 지원하도록 하기 위해 양방향 Initial 데이터그램이 최소 1200바이트 이상이어야 함을 요구합니다.
Session Request와 Session Created에 대해 이를 요구할 수 있지만, 대역폭에 상당한 비용이 발생합니다. 토큰이 없거나 Retry 메시지를 받은 후에만 이를 수행하는 것을 고려할 수 있습니다. TBD
QUIC는 Bob이 클라이언트 주소가 검증될 때까지 받은 데이터량의 3배를 초과하여 전송하지 않도록 요구합니다. SSU2는 Retry 메시지가 Token Request 메시지와 거의 같은 크기이고 Session Request 메시지보다 작으며, Retry 메시지는 한 번만 전송되기 때문에 이 요구 사항을 본질적으로 충족합니다.
처리 오버헤드 추정
QUIC는 증폭 공격을 방지하고 양방향으로 PMTU가 이를 지원하도록 보장하기 위해 PATH_CHALLENGE 또는 PATH_RESPONSE 블록을 포함하는 메시지가 최소 1200바이트가 되도록 요구합니다.
우리는 이것을 요구할 수도 있지만, 대역폭에서 상당한 비용이 발생할 것입니다. 하지만 이러한 경우는 드물어야 합니다. TBD
Max I2NP Message Size
IPv4: IP 단편화는 없다고 가정합니다. IP + 데이터그램 헤더는 28바이트입니다. 이는 IPv4 옵션이 없다고 가정합니다. 최대 메시지 크기는 MTU - 28입니다. 데이터 단계 헤더는 16바이트이고 MAC은 16바이트로 총 32바이트입니다. 페이로드 크기는 MTU - 60입니다. 최대 1500 MTU에서 최대 데이터 단계 페이로드는 1440입니다. 최소 1280 MTU에서 최대 데이터 단계 페이로드는 1220입니다.
IPv6: IP 단편화는 허용되지 않습니다. IP + 데이터그램 헤더는 48바이트입니다. 이는 IPv6 확장 헤더가 없다고 가정합니다. 최대 메시지 크기는 MTU - 48입니다. 데이터 단계 헤더는 16바이트이고 MAC은 16바이트로 총 32바이트입니다. 페이로드 크기는 MTU - 80입니다. 최대 1500 MTU에 대한 최대 데이터 단계 페이로드는 1420입니다. 최소 1280 MTU에 대한 최대 데이터 단계 페이로드는 1200입니다.
SSU 1에서는 최대 64개의 fragment와 620 최소 MTU를 기준으로 I2NP 메시지에 대해 약 32KB의 엄격한 최대값이 가이드라인이었습니다. 번들된 LeaseSet과 세션 키의 오버헤드로 인해 애플리케이션 레벨에서의 실용적 한계는 약 6KB 낮아져서 약 26KB였습니다. SSU 1 프로토콜은 128개의 fragment를 허용하지만 현재 구현에서는 64개의 fragment로 제한하고 있습니다.
최소 MTU를 1280으로 높이면, 약 1200의 데이터 단계 페이로드로 약 76 KB의 SSU 2 메시지가 64개 조각으로 가능하고 152 KB가 128개 조각으로 가능합니다. 이는 최대 64 KB를 쉽게 허용합니다.
터널에서의 단편화와 SSU 2에서의 단편화로 인해, 메시지 손실 가능성이 메시지 크기에 따라 기하급수적으로 증가합니다. I2NP 데이터그램의 경우 애플리케이션 계층에서 약 10KB의 실용적인 제한을 계속 권장합니다.
Peer Test Process
위의 Peer Test Security에서 SSU1 Peer Test 분석과 SSU2 Peer Test의 목표를 참조하십시오.
Alice Bob Charlie
1. PeerTest ------------------->
Alice RI ------------------->
2. PeerTest ------------------->
3. <------------------ PeerTest
<---------------- Charlie RI
4. <------------------ PeerTest
5. <----------------------------------------- PeerTest
6. PeerTest ----------------------------------------->
7. <----------------------------------------- PeerTest
Bob에 의해 거부될 때:
Alice Bob Charlie
1. PeerTest ------------------->
4. <------------------ PeerTest (reject)
Charlie에 의해 거부되었을 때:
Alice Bob Charlie
1. PeerTest ------------------->
Alice RI ------------------->
2. PeerTest ------------------->
3. <------------------ PeerTest (reject)
(optional: Bob could try another Charlie here)
4. <------------------ PeerTest (reject)
참고: RI는 I2NP 블록 내의 I2NP Database Store 메시지로 전송되거나, (충분히 작을 경우) RI 블록으로 전송될 수 있습니다. 이들은 충분히 작을 경우 peer test 블록과 동일한 패킷에 포함될 수 있습니다.
메시지 1-4는 Data 메시지의 Peer Test 블록을 사용하여 세션 내에서 전송됩니다. 메시지 5-7은 Peer Test 메시지의 Peer Test 블록을 사용하여 세션 외부에서 전송됩니다.
참고: SSU 1에서와 같이 메시지 4와 5는 어느 순서로든 도착할 수 있습니다. Alice가 방화벽 뒤에 있는 경우 메시지 5 및/또는 7이 전혀 수신되지 않을 수 있습니다. 메시지 5가 메시지 4보다 먼저 도착하면, Alice는 헤더를 암호화할 Charlie의 intro key를 아직 갖지 못했기 때문에 즉시 메시지 6을 보낼 수 없습니다. 메시지 4가 메시지 5보다 먼저 도착하면, Alice는 메시지 6으로 방화벽을 열지 않고 메시지 5가 도착하는지 기다려야 하므로 즉시 메시지 6을 보내서는 안 됩니다.
| 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
크로스 버전 peer 테스트는 지원되지 않습니다. 허용되는 유일한 버전 조합은 모든 peer가 버전 2인 경우입니다.
| 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 |
세션 설정
메시지 1-4는 세션 내에 있으며 데이터 단계 ACK 및 재전송 프로세스에 의해 처리됩니다. Peer Test 블록은 ACK를 요구합니다.
메시지 5-7은 변경되지 않은 채로 재전송될 수 있습니다.
패킷 헤더
SSU 1에서와 같이 IPv6 주소 테스트가 지원되며, Bob과 Charlie가 게시된 IPv6 주소에서 ‘B’ capability로 지원을 표시하는 경우 Alice-Bob과 Alice-Charlie 통신이 IPv6를 통해 이루어질 수 있습니다. 자세한 내용은 Proposal 126을 참조하십시오.
0.9.50 이전 SSU 1에서와 같이, Alice는 테스트하고자 하는 전송 계층(IPv4 또는 IPv6)을 통한 기존 세션을 사용하여 Bob에게 요청을 보냅니다. Bob이 IPv4를 통해 Alice로부터 요청을 받으면, Bob은 IPv4 주소를 광고하는 Charlie를 선택해야 합니다. Bob이 IPv6을 통해 Alice로부터 요청을 받으면, Bob은 IPv6 주소를 광고하는 Charlie를 선택해야 합니다. 실제 Bob-Charlie 통신은 IPv4 또는 IPv6을 통해 이루어질 수 있습니다(즉, Alice의 주소 유형과 독립적). 이것은 혼합 IPv4/v6 요청이 허용되는 0.9.50 버전의 SSU 1 동작과는 다릅니다.
Processing by Bob
SSU 1과 달리, Alice는 메시지 1에서 요청된 테스트 IP와 포트를 지정합니다. Bob은 이 IP와 포트를 검증해야 하며, 유효하지 않은 경우 코드 5로 거부해야 합니다. 권장되는 IP 검증은 IPv4의 경우 Alice의 IP와 일치해야 하고, IPv6의 경우 IP의 최소 첫 8바이트가 일치해야 합니다. 포트 검증은 특권 포트와 잘 알려진 프로토콜의 포트를 거부해야 합니다.
Relay Process
SSU1 Relay 분석과 SSU2 Relay의 목표에 대해서는 위의 Relay Security를 참조하십시오.
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 ------------------------------------------>
Bob이 거부했을 때:
Alice Bob Charlie
lookup Bob RI
SessionRequest -------------------->
<------------ SessionCreated
SessionConfirmed ----------------->
1. RelayRequest ---------------------->
4. <-------------- RelayResponse
Charlie에 의해 거부된 경우:
Alice Bob Charlie
lookup Bob RI
SessionRequest -------------------->
<------------ SessionCreated
SessionConfirmed ----------------->
1. RelayRequest ---------------------->
Alice RI ------------>
2. RelayIntro ----------->
3. <-------------- RelayResponse
4. <-------------- RelayResponse
참고: RI는 I2NP 블록의 I2NP Database Store 메시지로 전송되거나, (충분히 작을 경우) RI 블록으로 전송될 수 있습니다. 이들은 충분히 작을 경우 relay 블록과 동일한 패킷에 포함될 수 있습니다.
SSU 1에서 Charlie의 router 정보는 각 introducer의 IP, 포트, intro key, relay tag, 그리고 만료 시간을 포함합니다.
SSU 2에서 Charlie의 router info에는 각 introducer의 router hash, relay tag, 그리고 만료 시간이 포함되어 있습니다.
Alice는 먼저 이미 연결되어 있는 introducer(Bob)를 선택하여 필요한 왕복 횟수를 줄여야 합니다. 둘째, 그런 introducer가 없다면 이미 router 정보를 가지고 있는 introducer를 선택해야 합니다.
가능하다면 교차 버전 릴레이도 지원되어야 합니다. 이는 SSU 1에서 SSU 2로의 점진적 전환을 용이하게 할 것입니다. 허용되는 버전 조합은 다음과 같습니다 (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, 그리고 Relay Response는 모두 세션 내에 있으며 데이터 단계 ACK 및 재전송 프로세스에 의해 처리됩니다. Relay Request, Relay Intro, 그리고 Relay Response 블록은 ack-eliciting입니다.
Hole punch는 SSU 1에서와 같이 재전송될 수 있습니다.
IPv4/v6
SSU 1 relay의 모든 기능이 지원되며, 여기에는 Proposal 158에 문서화되고 0.9.50부터 지원되는 기능들이 포함됩니다. IPv4 및 IPv6 소개가 지원됩니다. IPv6 소개를 위해 IPv4 세션을 통해 Relay Request를 보낼 수 있으며, IPv4 소개를 위해 IPv6 세션을 통해 Relay Request를 보낼 수 있습니다.
Processing by Alice
다음은 SSU 1과의 차이점 및 SSU 2 구현을 위한 권장사항입니다.
참고사항
SSU 1에서 소개(introduction)는 상대적으로 비용이 저렴하며, Alice는 일반적으로 모든 소개자(introducer)에게 Relay Request를 보냅니다. SSU 2에서는 소개자와 먼저 연결을 설정해야 하므로 소개가 더 비용이 많이 듭니다. 소개 지연 시간과 오버헤드를 최소화하기 위해 권장되는 처리 단계는 다음과 같습니다:
- iexp 값이 만료된 introducer들은 주소에서 무시
- 하나 이상의 introducer에 SSU2 연결이 이미 설정되어 있으면, 하나를 선택하여 해당 introducer에만 Relay Request를 전송.
- 그렇지 않으면, 하나 이상의 introducer에 대해 Router Info가 로컬에 알려져 있으면, 하나를 선택하여 해당 introducer에만 연결.
- 그렇지 않으면, 모든 introducer에 대해 Router Info를 조회하고, Router Info를 먼저 받은 introducer에 연결.
참고사항
SSU 1과 SSU 2 모두에서 Relay Response와 Hole Punch는 어떤 순서로든 수신될 수 있으며, 아예 수신되지 않을 수도 있습니다.
SSU 1에서 Alice는 보통 Hole Punch (1 1/2 RTT)보다 Relay Response (1 RTT)를 먼저 받습니다. 해당 명세서들에는 잘 문서화되어 있지 않을 수 있지만, Alice는 Charlie의 IP를 받기 위해 계속하기 전에 Bob으로부터 Relay Response를 받아야 합니다. Hole Punch가 먼저 수신되면, Alice는 이를 인식하지 못할 것입니다. 왜냐하면 데이터가 포함되어 있지 않고 소스 IP가 인식되지 않기 때문입니다. Relay Response를 받은 후, Alice는 Charlie와의 핸드셰이크를 시작하기 전에 Charlie로부터 Hole Punch를 받거나 짧은 지연 시간(권장 500ms) 중 하나를 기다려야 합니다.
SSU 2에서 Alice는 일반적으로 Relay Response(2 RTT)보다 Hole Punch(1 1/2 RTT)를 먼저 받게 됩니다. SSU 2 Hole Punch는 SSU 1보다 처리하기 쉬운데, 이는 정의된 연결 ID들(relay nonce에서 파생된)과 Charlie의 IP를 포함한 내용을 가진 완전한 메시지이기 때문입니다. Relay Response(Data 메시지)와 Hole Punch 메시지는 동일한 서명된 Relay Response 블록을 포함합니다. 따라서 Alice는 Charlie로부터 Hole Punch를 받거나 Bob으로부터 Relay Response를 받은 후에 Charlie와의 핸드셰이크를 시작할 수 있습니다.
Hole Punch의 서명 검증에는 소개자(Bob)의 router 해시가 포함됩니다. Relay Request가 둘 이상의 소개자에게 전송된 경우, 서명을 검증하기 위한 몇 가지 옵션이 있습니다:
- 요청이 전송된 각 해시를 시도
- 각 introducer마다 다른 nonce를 사용하고, 이를 통해 이 Hole Punch가 어느 introducer에 대한 응답인지 판단
- 이미 수신된 경우 Relay Response의 내용과 동일하다면 서명을 재검증하지 않음
- 서명을 전혀 검증하지 않음
Charlie가 대칭 NAT 뒤에 있는 경우, Relay Response와 Hole Punch에서 보고된 그의 포트가 정확하지 않을 수 있습니다. 따라서 Alice는 Hole Punch 메시지의 UDP 소스 포트를 확인하고, 보고된 포트와 다른 경우 해당 포트를 사용해야 합니다.
Tag Requests by Bob
SSU 1에서는 Alice만이 Session Request에서 태그를 요청할 수 있었습니다. Bob은 태그를 요청할 수 없었고, Alice는 Bob을 위해 릴레이할 수 없었습니다.
SSU2에서 Alice는 일반적으로 Session Request에서 태그를 요청하지만, 데이터 단계에서는 Alice나 Bob 모두 태그를 요청할 수 있습니다. Bob은 일반적으로 인바운드 요청을 받은 후에는 방화벽에 차단되지 않지만, 릴레이 후에 차단될 수 있거나, Bob의 상태가 변경될 수 있거나, 다른 주소 유형(IPv4/v6)에 대해 introducer를 요청할 수 있습니다. 따라서 SSU2에서는 Alice와 Bob이 동시에 서로의 릴레이가 되는 것이 가능합니다.
Published Router Info
Address Properties
다음 주소 속성들은 SSU 1에서 변경되지 않은 채로 게시될 수 있으며, API 0.9.50부터 지원되는 Proposal 158의 변경사항을 포함합니다:
caps: [B,C,4,6] 기능
host: IP (IPv4 또는 IPv6). 축약된 IPv6 주소(”::” 포함)가 허용됩니다. 방화벽이 설정된 경우 존재하지 않을 수 있습니다. 호스트명은 허용되지 않습니다.
iexp[0-2]: 이 소개자의 만료 시간. ASCII 숫자, 에포크 이후의 초 단위. 방화벽이 있고 소개자가 필요한 경우에만 존재. 선택사항 (이 소개자의 다른 속성들이 있어도).
ihost[0-2]: Introducer의 IP (IPv4 또는 IPv6). 축약된 IPv6 주소(”::” 포함)가 허용됩니다. 방화벽이 설정되어 있고 introducer가 필요한 경우에만 존재합니다. 호스트 이름은 허용되지 않습니다. SSU 주소 전용입니다.
ikey[0-2]: Introducer의 Base 64 introduction key. 방화벽이 있고 introducer가 필요한 경우에만 존재합니다. SSU 주소 전용.
iport[0-2]: Introducer의 포트 1024 - 65535. 방화벽이 있고 introducer가 필요한 경우에만 존재. SSU 주소 전용.
itag[0-2]: Introducer의 태그 1 - (2**32 - 1) ASCII 숫자. 방화벽이 설정되어 있고 introducer가 필요한 경우에만 존재함.
key: Base 64 도입 키.
mtu: 선택사항. 위의 MTU 섹션을 참조하세요.
port: 1024 - 65535 방화벽이 설정된 경우 존재할 수도 있고 존재하지 않을 수도 있습니다.
Published Addresses
게시된 RouterAddress (RouterInfo의 일부)는 “SSU” 또는 “SSU2"의 프로토콜 식별자를 갖습니다.
RouterAddress는 SSU2 지원을 나타내기 위해 세 가지 옵션을 포함해야 합니다:
s=(Base64 키) 이 RouterAddress에 대한 현재 Noise 정적 공개 키(s)입니다. 표준 I2P Base 64 알파벳을 사용하여 Base 64로 인코딩됩니다. 바이너리로 32바이트, Base 64 인코딩으로 44바이트, 리틀 엔디안 X25519 공개 키입니다.
i=(Base64 key) 이 RouterAddress의 헤더 암호화를 위한 현재 소개 키입니다. 표준 I2P Base 64 알파벳을 사용하여 Base 64로 인코딩됩니다. 바이너리로 32바이트, Base 64 인코딩으로 44바이트, 빅엔디안 ChaCha20 키입니다.
v=2 현재 버전 (2). “SSU"로 게시될 때, 버전 1에 대한 추가 지원이 암시됩니다. 향후 버전에 대한 지원은 쉼표로 구분된 값을 사용합니다, 예: v=2,3 구현체는 쉼표가 있는 경우 여러 버전을 포함하여 호환성을 확인해야 합니다. 쉼표로 구분된 버전은 반드시 숫자 순서여야 합니다.
Alice는 SSU2 프로토콜을 사용하여 연결하기 전에 세 가지 옵션이 모두 존재하고 유효한지 확인해야 합니다.
“s”, “i”, “v” 옵션과 함께 “host” 및 “port” 옵션을 가지고 “SSU"로 발행될 때, router는 해당 호스트와 포트에서 SSU 및 SSU2 프로토콜 모두에 대한 수신 연결을 허용해야 하며, 프로토콜 버전을 자동으로 감지해야 합니다.
“s”, “i”, “v” 옵션과 함께 “host” 및 “port” 옵션을 사용하여 “SSU2"로 게시될 때, router는 SSU2 프로토콜에 대해서만 해당 호스트와 포트에서 들어오는 연결을 수락합니다.
router가 SSU1과 SSU2 연결을 모두 지원하지만 들어오는 연결에 대한 자동 버전 감지를 구현하지 않는 경우, “SSU"와 “SSU2” 주소를 모두 광고해야 하며, SSU2 옵션은 “SSU2” 주소에만 포함해야 합니다. router는 “SSU2” 주소에 “SSU” 주소보다 더 낮은 비용 값(더 높은 우선순위)을 설정하여 SSU2가 선호되도록 해야 합니다.
동일한 RouterInfo에 여러 개의 SSU2 RouterAddress가 (“SSU” 또는 “SSU2"로) 게시되는 경우(추가 IP 주소나 포트용), 동일한 포트를 지정하는 모든 주소는 동일한 SSU2 옵션과 값을 포함해야 합니다. 특히, 모든 주소는 동일한 정적 키 “s"와 introduction 키 “i"를 포함해야 합니다.
Introducers
introducer와 함께 SSU 또는 SSU2로 게시될 때 다음 옵션들이 존재합니다:
ih[0-2]=(Base64 hash) introducer의 router hash입니다. 표준 I2P Base 64 알파벳을 사용하여 Base 64로 인코딩됩니다. 바이너리로 32바이트, Base 64 인코딩으로 44바이트입니다.
iexp[0-2]: 이 introducer의 만료 시간. SSU 1에서 변경되지 않음.
itag[0-2]: Introducer의 태그 1 - (2**32 - 1) SSU 1에서 변경되지 않음.
다음 옵션들은 SSU 전용이며 SSU2에서는 사용되지 않습니다. SSU2에서는 Alice가 Charlie의 RI에서 이 정보를 가져옵니다.
- ihost[0-2]
- ikey[0-2]
- itag[0-2]
router는 introducer를 게시할 때 주소에 호스트나 포트를 게시해서는 안 됩니다. router는 introducer를 게시할 때 IPv4 및/또는 IPv6 지원을 나타내기 위해 주소에 4 및/또는 6 caps를 게시해야 합니다. 이는 최근 SSU 1 주소에 대한 현재 관행과 동일합니다.
참고: SSU로 게시되고 SSU 1과 SSU2 introducer가 혼재하는 경우, 기존 router와의 호환성을 위해 SSU 1 introducer는 낮은 인덱스에, SSU2 introducer는 높은 인덱스에 배치해야 합니다.
Unpublished SSU2 Address
Alice가 들어오는 연결에 대해 자신의 SSU2 주소를(“SSU” 또는 “SSU2"로) 게시하지 않는 경우, Bob이 Session Confirmed part 2에서 Alice의 RouterInfo를 수신한 후 키를 검증할 수 있도록 정적 키와 SSU2 버전만을 포함하는 “SSU2” router 주소를 게시해야 합니다.
s=(Base64 key) 위에서 게시된 주소에 대해 정의된 대로.
i=(Base64 key) 위에서 공개된 주소에 대해 정의된 바와 같습니다.
v=2 위에서 게시된 주소에 대해 정의된 대로.
이 라우터 주소는 아웃바운드 SSU2 연결에 필요하지 않으므로 “host” 또는 “port” 옵션을 포함하지 않습니다. 이 주소에 대해 공개된 cost는 인바운드 전용이므로 엄격히 중요하지는 않지만, 다른 주소보다 높은 cost(낮은 우선순위)로 설정하면 다른 라우터에게 도움이 될 수 있습니다. 권장값은 14입니다.
Alice는 기존에 게시된 “SSU” 주소에 단순히 “i”, “s”, “v” 옵션을 추가할 수도 있습니다.
패킷 무결성
NTCP2와 SSU2에 동일한 정적 키를 사용하는 것은 허용되지만 권장되지 않습니다.
RouterInfo 캐싱으로 인해, router는 게시된 주소에 포함되었든 아니든 관계없이 router가 실행 중인 동안에는 정적 공개 키나 IV를 교체해서는 안 됩니다. Router는 즉시 재시작 후 재사용을 위해 이 키와 IV를 영구적으로 저장해야 하므로, 수신 연결이 계속 작동하고 재시작 시간이 노출되지 않습니다. Router는 시작 시 이전 다운타임을 계산할 수 있도록 마지막 종료 시간을 영구적으로 저장하거나 다른 방법으로 확인해야 합니다.
재시작 시간 노출에 대한 우려로 인해, router가 이전에 상당한 시간(최소 며칠) 동안 중단되었던 경우 시작 시 이 키 또는 IV를 회전할 수 있습니다.
router가 공개된 SSU2 RouterAddress들을 가지고 있다면 (SSU 또는 SSU2로), 로컬 IP 주소가 변경되었거나 router가 “rekeys"하지 않는 한, 순환 전 최소 다운타임은 예를 들어 한 달과 같이 훨씬 길어야 합니다.
라우터가 게시된 SSU RouterAddress를 가지고 있지만 SSU2(SSU 또는 SSU2로서)는 가지고 있지 않은 경우, 로컬 IP 주소가 변경되거나 라우터가 “rekey"하지 않는 한, 순환 전 최소 다운타임은 더 길어야 하며, 예를 들어 하루여야 합니다. 이는 게시된 SSU 주소에 introducer가 있는 경우에도 적용됩니다.
router가 게시된 RouterAddress(SSU, SSU2, 또는 SSU)를 가지고 있지 않다면, router가 “rekey"하지 않는 한 IP 주소가 변경되더라도 rotation 전 최소 다운타임은 2시간 정도로 짧을 수 있습니다.
router가 다른 Router Hash로 “재키 생성"을 하는 경우, 새로운 noise key와 intro key도 함께 생성해야 합니다.
구현체들은 정적 공개 키나 IV를 변경하면 이전 RouterInfo를 캐시한 라우터들로부터의 SSU2 연결 수신이 차단된다는 점을 인식해야 합니다. RouterInfo 게시, 터널 피어 선택(OBGW와 IB closest hop 모두 포함), zero-hop 터널 선택, 전송 선택 및 기타 구현 전략들은 이를 고려해야 합니다.
Intro 키 회전은 키 회전과 동일한 규칙을 따릅니다.
참고: 재키잉 전 최소 다운타임은 네트워크 건강을 보장하고 적당한 시간 동안 다운된 router의 재시딩을 방지하기 위해 수정될 수 있습니다.
Identity Hiding
부인 가능성(Deniability)은 목표가 아닙니다. 위의 개요를 참조하십시오.
각 패턴에는 개시자의 정적 공개 키와 응답자의 정적 공개 키에 제공되는 기밀성을 설명하는 속성이 할당됩니다. 기본 가정은 임시 개인 키가 안전하며, 당사자들이 신뢰하지 않는 상대방의 정적 공개 키를 받으면 핸드셰이크를 중단한다는 것입니다.
이 섹션은 handshake의 정적 공개 키 필드를 통한 신원 누출만을 다룹니다. 물론 Noise 참가자들의 신원은 페이로드 필드, 트래픽 분석, 또는 IP 주소와 같은 메타데이터를 포함한 다른 수단을 통해 노출될 수 있습니다.
Alice: (8) 인증된 당사자에게 전진 보안성을 갖춘 암호화.
Bob: (3) 전송되지 않지만, 수동적 공격자가 응답자의 개인 키 후보들을 확인하여 해당 후보가 올바른지 판단할 수 있습니다.
Bob은 자신의 정적 공개 키를 netDb에 게시합니다. Alice는 그렇지 않을 수도 있지만, Bob에게 보내는 RI에 반드시 포함해야 합니다.
Packet Guidelines
인증 암호화
Handshake 메시지 (Session Request/Created/Confirmed, Retry) 기본 단계, 순서대로:
- 16 또는 32 바이트 헤더 생성
- 페이로드 생성
- 헤더를 mixHash() (Retry 제외)
- Noise를 사용하여 페이로드 암호화 (Retry 제외, 헤더를 AD로 사용하는 ChaChaPoly 사용)
- 헤더 암호화, Session Request/Created의 경우 ephemeral key도 암호화
데이터 단계 메시지의 기본 단계 (순서대로):
- 16바이트 헤더 생성
- 페이로드 생성
- 헤더를 AD로 사용하여 ChaChaPoly로 페이로드 암호화
- 헤더 암호화
Inbound Packet Handling
페이로드
모든 인바운드 메시지의 초기 처리:
- intro key로 헤더의 첫 8바이트(Destination Connection ID)를 복호화
- Destination Connection ID로 연결을 조회
- 연결이 발견되고 데이터 단계에 있으면 데이터 단계 섹션으로 이동
- 연결이 발견되지 않으면 핸드셰이크 섹션으로 이동
- 참고: Peer Test 및 Hole Punch 메시지도 테스트 또는 릴레이 nonce에서 생성된 Destination Connection ID로 조회될 수 있음
Handshake 메시지 (Session Request/Created/Confirmed, Retry, Token Request)와 기타 세션 외 메시지 (Peer Test, Hole Punch) 처리:
- 헤더의 8-15 바이트를 intro key로 복호화 (패킷 타입, 버전, net ID). 유효한 Session Request, Token Request, Peer Test, 또는 Hole Punch인 경우 계속 진행
- 유효한 메시지가 아닌 경우, 패킷 소스 IP/포트로 대기 중인 아웃바운드 연결을 조회하고, 패킷을 Session Created 또는 Retry로 처리. 올바른 키로 헤더의 첫 8 바이트를 재복호화하고, 헤더의 8-15 바이트 (패킷 타입, 버전, net ID)도 재복호화. 유효한 Session Created 또는 Retry인 경우 계속 진행
- 유효한 메시지가 아닌 경우, 실패하거나 순서가 틀린 데이터 단계 패킷으로 큐에 저장
- Session Request/Created, Retry, Token Request, Peer Test, Hole Punch의 경우, 헤더의 16-31 바이트를 복호화
- Session Request/Created의 경우, ephemeral key를 복호화
- 모든 헤더 필드를 검증하고, 유효하지 않으면 중단
- 헤더를 mixHash()
- Session Request/Created/Confirmed의 경우, Noise를 사용하여 페이로드를 복호화
- Retry와 데이터 단계의 경우, ChaChaPoly를 사용하여 페이로드를 복호화
- 헤더와 페이로드를 처리
데이터 단계 메시지 처리:
- 헤더의 8-15번째 바이트를 올바른 키로 복호화 (패킷 타입, 버전, 네트워크 ID)
- 헤더를 AD로 사용하여 ChaChaPoly로 페이로드 복호화
- 헤더와 페이로드 처리
Details
SSU 1에서는 세션 번호를 나타내는 헤더가 없기 때문에 인바운드 패킷 분류가 어렵습니다. 라우터는 먼저 소스 IP와 포트를 기존 피어 상태와 매치해야 하고, 찾지 못하면 적절한 피어 상태를 찾거나 새로운 상태를 시작하기 위해 다른 키들로 여러 번의 복호화를 시도해야 합니다. NAT 동작으로 인해 기존 세션의 소스 IP나 포트가 변경되는 경우, 라우터는 패킷을 기존 세션과 매치하고 내용을 복구하기 위해 비용이 많이 드는 휴리스틱을 사용할 수 있습니다.
SSU 2는 DPI 저항성과 기타 경로상 위협을 유지하면서 인바운드 패킷 분류 작업을 최소화하도록 설계되었습니다. Connection ID 번호는 모든 메시지 유형의 헤더에 포함되며, 알려진 키와 nonce를 사용하여 ChaCha20으로 암호화(난독화)됩니다. 또한 메시지 유형도 헤더에 포함되며(알려진 키에 대한 헤더 보호로 암호화된 후 ChaCha20으로 난독화됨) 추가적인 분류에 사용될 수 있습니다. 어떤 경우에도 패킷을 분류하기 위해 시행착오 DH나 기타 비대칭 암호화 작업이 필요하지 않습니다.
거의 모든 피어의 모든 메시지에 대해, Connection ID 암호화를 위한 ChaCha20 키는 netDb에 게시된 목적지 router의 introduction key입니다.
유일한 예외는 Bob이 Alice에게 보내는 첫 번째 메시지들(Session Created 또는 Retry)로, 이 경우 Alice의 introduction key가 Bob에게 아직 알려지지 않은 상태입니다. 이러한 경우에는 Bob의 introduction key가 키로 사용됩니다.
이 프로토콜은 다중 대체 단계에서 추가적인 암호화 연산이나 복잡한 휴리스틱을 요구할 수 있는 패킷 분류 처리를 최소화하도록 설계되었습니다. 또한, 수신된 패킷의 대부분은 소스 IP/포트에 의한 (비용이 많이 들 수 있는) 대체 검색이나 두 번째 헤더 복호화를 필요로 하지 않습니다. Session Created와 Retry (그리고 향후 결정될 기타 패킷들)만이 대체 처리를 요구할 것입니다. 세션 생성 후 엔드포인트가 IP나 포트를 변경하더라도, 연결 ID는 여전히 세션을 찾는 데 사용됩니다. 예를 들어 같은 IP이지만 다른 포트를 가진 다른 세션을 찾는 것과 같이, 세션을 찾기 위해 휴리스틱을 사용할 필요는 전혀 없습니다.
따라서 수신기 루프 로직에서 권장되는 처리 단계는 다음과 같습니다:
- 로컬 introduction key를 사용하여 ChaCha20으로 처음 8바이트를 복호화하여 Destination Connection ID를 복구합니다. Connection ID가 현재 또는 대기 중인 인바운드 세션과 일치하는 경우:
a) 적절한 키를 사용하여 헤더 바이트 8-15를 복호화
to recover the version, net ID, and message type.
b) 메시지 유형이 Session Confirmed인 경우, 긴 헤더입니다.
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) 메시지 유형이 유효하지만 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) (선택사항) 연결 ID가 대기 중인 인바운드 세션인 경우
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) b) 또는 c)가 실패하면 메시지를 삭제합니다.
- 연결 ID가 현재 세션과 일치하지 않는 경우: 바이트 8-15의 평문 헤더가 유효한지 확인 (헤더 보호 작업을 수행하지 않고). 네트워크 ID와 프로토콜 버전이 유효한지 확인하고, 메시지 유형이 Session Request이거나 세션 외부에서 허용되는 다른 메시지 유형인지 확인 (미정).
a) 모든 것이 유효하고 메시지 유형이 Session Request인 경우,
decrypt bytes 16-31 of the header and the 32-byte X value
with ChaCha20 using the local intro key.
- 헤더 바이트 24-31의 토큰이 허용되면,
암호화 해제된 32바이트 헤더를 MixHash()하고
Noise로 메시지를 복호화합니다.
응답으로 Session Created를 전송합니다.
- 토큰이 허용되지 않으면, 토큰과 함께 Retry 메시지를 소스 IP/포트로 전송합니다. DDoS 공격을 방지하기 위해 Noise로 메시지 복호화를 시도하지 않습니다.
b) 메시지 유형이 유효한 다른 메시지인 경우
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) a) 또는 b)가 실패하면, 3단계로 이동
- 패킷의 소스 IP/포트로 대기 중인 아웃바운드 세션을 조회합니다.
a) 발견되면, Bob의 introduction key를 사용하여 ChaCha20으로 첫 8바이트를 재복호화
to recover the Destination Connection ID.
b) 연결 ID가 대기 중인 세션과 일치하는 경우:
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).
모든 것이 유효하고 메시지 타입이 Session Created인 경우, Bob의 intro key를 사용하여 ChaCha20으로 헤더의 다음 16바이트와 32바이트 Y 값을 복호화합니다. 그런 다음 복호화된 32바이트 헤더를 MixHash()하고 Noise로 메시지를 복호화합니다. 응답으로 Session Confirmed를 전송합니다.
- 모든 것이 유효하고 메시지 타입이 Retry인 경우, Bob의 intro key를 사용하여 ChaCha20으로 헤더의 16-31바이트를 복호화합니다. TBD를 키로, TBD를 nonce로, 복호화된 32바이트 헤더를 AD로 사용하여 ChaCha20/Poly1305를 이용해 메시지를 복호화하고 검증합니다. 응답으로 수신된 토큰과 함께 Session Request를 재전송합니다.
- 메시지 타입이 세션 외에서 유효한 다른 메시지인 경우 (presumably short header), intro key를 사용하고 복호화된 16바이트 헤더를 AD로 사용하여 ChaCha20/Poly1305로 메시지의 나머지 부분을 복호화합니다. 메시지를 처리합니다.
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.
- 동일한 포트에서 SSU 1을 실행 중인 경우, 메시지를 SSU 1 패킷으로 처리를 시도합니다.
Error Handling
일반적으로 세션(handshake 또는 데이터 단계에 있는)은 예상하지 못한 메시지 타입의 패킷을 받은 후에 절대 소멸되어서는 안 됩니다. 이는 패킷 주입 공격을 방지합니다. 이러한 패킷들은 또한 handshake 패킷의 재전송 후에 헤더 복호화 키가 더 이상 유효하지 않을 때 일반적으로 수신됩니다.
대부분의 경우 단순히 패킷을 폐기합니다. 구현체는 이에 대한 응답으로 이전에 전송된 패킷(핸드셰이크 메시지 또는 ACK 0)을 재전송할 수 있지만, 필수사항은 아닙니다.
Bob으로서 Session Created를 전송한 후, 예상치 못한 패킷들은 일반적으로 Session Confirmed 패킷들이 손실되거나 순서가 뒤바뀌어서 복호화할 수 없는 Data 패킷들입니다. 이러한 패킷들을 대기열에 넣고 Session Confirmed 패킷들을 받은 후에 복호화를 시도하세요.
Bob으로서 Session Confirmed를 수신한 후, 예상치 못한 패킷들은 일반적으로 재전송된 Session Confirmed 패킷들인데, 이는 Session Confirmed의 ACK 0이 손실되었기 때문입니다. 예상치 못한 패킷들은 버려질 수 있습니다. 구현체는 응답으로 ACK 블록을 포함하는 Data 패킷을 보낼 수 있지만, 반드시 그래야 하는 것은 아닙니다.
Notes
Session Created와 Session Confirmed의 경우, 구현체들은 헤더에 대해 mixHash()를 호출하고 Noise AEAD로 페이로드를 복호화하려고 시도하기 전에 복호화된 모든 헤더 필드들(Connection ID, 패킷 번호, 패킷 타입, 버전, id, frag, flags)을 신중하게 검증해야 합니다. Noise AEAD 복호화가 실패하면, 구현체가 해시 상태를 저장하고 “되돌리기"를 하지 않는 한 mixHash()가 핸드셰이크 상태를 손상시킬 것이므로 더 이상의 처리를 수행할 수 없습니다.
Version Detection
동일한 인바운드 포트에서 들어오는 패킷이 버전 1인지 2인지 효율적으로 감지하는 것이 불가능할 수 있습니다. 위의 단계들은 SSU 1 처리 전에 수행하는 것이 합리적일 수 있으며, 이는 두 프로토콜 버전 모두를 사용한 시행착오식 DH 연산 시도를 피하기 위함입니다.
필요시 추후 결정.
Recommended Constants
- 아웃바운드 핸드셰이크 재전송 타임아웃: 1.25초, 지수 백오프 적용 (1.25초, 3.75초, 8.75초에 재전송)
- 총 아웃바운드 핸드셰이크 타임아웃: 15초
- 인바운드 핸드셰이크 재전송 타임아웃: 1초, 지수 백오프 적용 (1초, 3초, 7초에 재전송)
- 총 인바운드 핸드셰이크 타임아웃: 12초
- 재시도 전송 후 타임아웃: 9초
- ACK 지연: max(10, min(rtt/6, 150)) ms
- 즉시 ACK 지연: min(rtt/16, 5) ms
- 최대 ACK 범위: 256?
- 최대 ACK 깊이: 512?
- 패딩 분포: 0-15바이트 또는 그 이상
Variants, Fallbacks, and General Issues
TBD
Packet Overhead Analysis
IPv4를 가정하며, 추가 패딩은 포함하지 않고, IP 및 UDP 헤더 크기도 포함하지 않습니다. 패딩은 SSU 1에서만 mod-16 패딩입니다.
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 | |||||
| Session Request와 Created에서 PMTU에 대한 최소 패킷 크기가 강제되지 않는 한 TODO. |