Files
i2p.www/i2p2www/spec/proposals/159-ssu2.rst
2021-10-21 10:27:14 -04:00

5602 lines
210 KiB
ReStructuredText

======
SSU2
======
.. meta::
:author: orignal, zlatinb, zzz
:created: 2021-09-12
:thread: http://zzz.i2p/topics/2612
:lastupdated: 2021-10-21
:status: Open
:target: 0.9.55
.. contents::
Overview
========
This proposal describes an authenticated key agreement protocol to improve the
resistance of [SSU]_ to various forms of automated identification and attacks.
The proposal is organized as follows: the security goals are presented,
followed by a discussion of the basic protocol. Next, a complete specification
of all protocol messages is given. Finally, router addresses and version
identification are discussed.
As with other I2P transports, SSU2 is defined
for point-to-point (router-to-router) transport of I2NP messages.
It is not a general-purpose data pipe.
Like [SSU]_, it also provides two additional services:
Relaying for NAT traversal, and Peer Testing for determination of inbound reachability.
Motivation
==========
SSU is the only remaining protocol layer that requires ElGamal, which is very slow.
The flow control for SSU is complex and does not work well.
Portions of SSU are vulnerable to address spoofing attacks.
The handshake does not use Noise.
Design Goals
============
- Reduce CPU usage by eliminating ElGamal. Use X25519 for the DH.
- Maintain the Peer Test and Relay functions, and increase security for them.
- Make implementation easier by allowing for standard flow control
algorithms.
- Increase speed and reduce latency.
Median setup time is currently about 135 ms for NTCP2 and 187 ms for SSU,
even though NTCP2 has an additional round trip; replacing ElGamal in
SSU2 should reduce it, but other changes may also help.
- (maybe) Prevent traffic amplification attacks from spoofed source addresses
via "address validation"? Is this necessary, or are there other
ways that would not require an additional round trip?
Does this conflict with the requirement to prevent traffic identification?
See below.
- Make packet identification easier, to reduce reliance on fallbacks and
heuristics that make the code overly complex.
- (maybe) Support SSU 1 and 2 on a single port, auto-detect, and published as a single
"transport" (i.e. [RouterAddress]_) in the [NetDB]_.
- Publish support for version 1 only, 2 only, or 1+2 in the NetDB in a separate
field, and default to version 1 only (don't bind version support to a
particular router version)
- Ensure that all implementations (Java/i2pd/Go) can add version 2
support (or not) on their own schedules
- Add random padding to all SSU messages including handshake and data messages.
Provide options mechanism for both sides to request min and max padding
and/or padding distribution. Specifics of the padding distribution are
implementation-dependent and may or may not be specified in the protocol
itself.
- Obfuscate the contents of messages that aren't fully encrypted (Session Created and Confirmed),
sufficiently so that DPI boxes and AV signatures can't easily classify them.
Also ensure that the messages going to a single peer or set of peers do not
have a similar pattern of bits.
- Fix loss of bits in DH due to Java format [Ticket1112]_, and speed up the DH
by switching to X25519.
- Switch to a real key derivation function (KDF) rather than using the DH
result as-is
- Add "probing resistance" (as Tor calls it); this includes replay resistance.
- Maintain 2-way authenticated key exchange (2W-AKE). 1W-AKE is not sufficient
for our application.
- Continue to use the variable-type, variable-length signatures (from the
published [RouterIdentity]_ signing key) as a part of authentication. Rely
on a static public key published in the RouterInfo as another part of
authentication.
- Add options/version in handshake for future extensibility.
- Don't add significantly to CPU required for connection setup; if possible,
reduce it significantly.
- Add message authentication (MAC) using ChaCha/Poly1305.
- Use a 3-message, one-round-trip handshake, as in [NTCP2]_.
Remove the delay waiting for data messages that makes
[SSU]_ effectively a two-round-trip handshake.
- Minimize protocol overhead before padding. While padding will be added,
overhead before padding is still overhead.
Low-bandwidth nodes must be able to use SSU2.
- All padding must be covered by the MAC, unlike the end-of-packet padding in SSU.
- Maintain timestamps for replay and skew detection.
- Avoid any year 2038 issues in timestamps, must work until at least 2106.
- Maintain a max I2NP message size of approximately 32K, as in SSU.
Increase to 64 KB? TBD
- Remove IP and port fields from the handshake, so that routers that don't know
their external IP and port will be able to connect.
- Include representatives of Java, C++, and Go router developers in the design.
Non-Goals
---------
- Bullet-proof DPI resistance... that would be pluggable transports,
[Prop109]_.
- A TLS-based (or HTTPS-lookalike) transport... that would be [Prop104]_.
- It's OK to change the symmetric stream cryptography.
- Timing-based DPI resistance (inter-message timing/delays can be
implementation-dependent; intra-message delays can be introduced at any
point, including before sending the random padding, for example). Artificial
delays (what obfs4 calls IAT or inter-arrival time) are independent of the
protocol itself.
- Deniability of participating in a session (there's signatures in there).
Non-goals that may be partially reconsidered or discussed:
- The degree of protection against Deep Packet Inspection (DPI)
- Post-Quantum (PQ) security
- Deniability
Security Goals
==============
We consider three parties:
- Alice, who wishes to establish a new session.
- Bob, with whom Alice wishes to establish a session.
- Mallory, the "man in the middle" between Alice and Bob.
At most two participants can engage in active attacks.
Alice and Bob are both in possession of a static key pair, which is contained
in their [RouterIdentity]_.
The proposed protocol attempts to allow Alice and Bob to agree on a shared
secret key (K) under the following requirements:
1) Private key security: neither Bob nor Mallory learns anything about Alice's
static private key. Symmetrically, Alice does not learn anything about Bob's
static private key.
2) The session key K is only known by Alice and Bob.
3) Perfect forward secrecy: the agreed upon session key remains secret in the
future, even when the static private keys of Alice and/or Bob are revealed
after the key has been agreed upon.
4) Two-way authentication: Alice is certain that she has established a session
with Bob, and vice versa.
5) Protection against online DPI: Ensure that it is not trivial to detect that
Alice and Bob are engaged in the protocol using only straightforward deep
packet inspection (DPI) techniques. See below.
6) Limited deniability: neither Alice nor Bob can deny participation in the
protocol, but if either leaks the shared key the other party can deny the
authenticity of the contents of the transmitted data.
The present proposal attempts to provide all five requirements based on the
Station-To-Station (STS) protocol [STS]_. Note that this protocol is also the
basis for the [SSU]_ protocol.
Additional DPI Discussion
-------------------------
We assume two DPI components:
Online DPI
`````````````
Online DPI inspecting all flows in real-time. Connections may be blocked or
otherwise tampered with. Connection data or metadata may be identified and
stored for offline analysis. The online DPI does not have access to the I2P
network database. The online DPI has only limited real-time computational
capability, including length calculation, field inspection, and simple
calculations such as XOR. The online DPI does have the capability of fast
real-time cryptographic functions such as AES, AEAD, and hashing, but these
would be too expensive to apply to most or all flows. Any application of these
cryptographic operations would apply only to flows on IP/Port combinations
previously identified by offline analysis. The online DPI does not have the
capability of high-overhead cryptographic functions such as DH or elligator2.
The online DPI is not designed specifically to detect I2P, although it may have
limited classification rules for that purpose.
It is a goal to prevent protocol identification by an online DPI.
The notion of online or "straightforward" DPI is here taken to include the
following adversary capabilities:
1) The ability to inspect all data sent or received by the target.
2) The ability to perform operations on the observed data, such as
applying block ciphers or hash functions.
3) The ability to store and compare with previously sent messages.
4) The ability to modify, delay or fragment packets.
However, the online DPI is assumed to have the following restrictions:
5) The inability to map IP addresses to router hashes. While this is trivial
with real-time access to the network database,
it would require a DPI system specifically designed to target I2P.
6) The inability to use timing information to detect the protocol.
7) Generally speaking, the online DPI toolbox does not contain any built-in
tools that are specifically designed for I2P detection. This includes
creating "honeypots", which would for example include nonrandom padding in
their messages. Note that this does not exclude machine learning systems or
highly configurable DPI tools as long as they meet the other requirements.
To counter payload analysis, it is ensured that all messages are
indistinguishable from random. This also requires their length to be random,
which is more complicated than just adding random padding. In fact, in Appendix
A, the authors argue that a naive (i.e. uniform) padding scheme does not
resolve the problem. Appendix A therefore proposes to include either random
delays or to develop an alternate padding scheme that can provide reasonable
protection for the proposed attack.
To protect against the sixth entry above, implementations should include random
delays in the protocol. Such techniques are not covered by this proposal, but
they could also resolve the padding length issues. In summary, the proposal
provides good protection against payload analysis (when the considerations in
Appendix A are taken into account), but only limited protection against flow
analysis.
Offline DPI
``````````````
Offline DPI inspecting data stored by the online DPI for later analysis.
The offline DPI may be designed specifically to detect I2P.
The offline DPI does have real-time access to the I2P network database.
The offline DPI does have access to this and other I2P specifications.
The offline DPI has unlimited computational capability, including
all cryptographic functions defined in this specification.
The offline DPI does not have the ability to block existing connections. The
offline DPI does have the capability to do near-realtime (within minutes of
setup) sending to host/port of parties by packet injection. The offline DPI
does have the capability to do near-realtime (within minutes of setup) replay
of previous messages (modified or not) for "probing" or other reasons.
It is not a goal to prevent protocol identification by an offline DPI.
All decoding of obfuscated data in the first two messages, which
is implemented by I2P routers, may also be implemented by the offline DPI.
It is a goal to reject attempted connections using replay of previous messages.
Address Validation
---------------------------
Following is copied from QUIC [RFC-9000]_.
For each section, review and edit.
Address validation ensures that an endpoint cannot be used for a
traffic amplification attack. In such an attack, a packet is sent to
a server with spoofed source address information that identifies a
victim. If a server generates more or larger packets in response to
that packet, the attacker can use the server to send more data toward
the victim than it would be able to send on its own.
The primary defense against amplification attacks is verifying that a
peer is able to receive packets at the transport address that it
claims. Therefore, after receiving packets from an address that is
not yet validated, an endpoint MUST limit the amount of data it sends
to the unvalidated address to three times the amount of data received
from that address. This limit on the size of responses is known as
the anti-amplification limit.
Address validation is performed both during connection establishment
(see Section 8.1) and during connection migration (see Section 8.2).
Address Validation during Connection Establishment
```````````````````````````````````````````````````````
Connection establishment implicitly provides address validation for
both endpoints. In particular, receipt of a packet protected with
Handshake keys confirms that the peer successfully processed an
Initial packet. Once an endpoint has successfully processed a
Handshake packet from the peer, it can consider the peer address to
have been validated.
Additionally, an endpoint MAY consider the peer address validated if
the peer uses a connection ID chosen by the endpoint and the
connection ID contains at least 64 bits of entropy.
For the client, the value of the Destination Connection ID field in
its first Initial packet allows it to validate the server address as
a part of successfully processing any packet. Initial packets from
the server are protected with keys that are derived from this value
(see Section 5.2 of [QUIC-TLS]). Alternatively, the value is echoed
by the server in Version Negotiation packets (Section 6) or included
in the Integrity Tag in Retry packets (Section 5.8 of [QUIC-TLS]).
Prior to validating the client address, servers MUST NOT send more
than three times as many bytes as the number of bytes they have
received. This limits the magnitude of any amplification attack that
can be mounted using spoofed source addresses. For the purposes of
avoiding amplification prior to address validation, servers MUST
count all of the payload bytes received in datagrams that are
uniquely attributed to a single connection. This includes datagrams
that contain packets that are successfully processed and datagrams
that contain packets that are all discarded.
Clients MUST ensure that UDP datagrams containing Initial packets
have UDP payloads of at least 1200 bytes, adding PADDING frames as
necessary. A client that sends padded datagrams allows the server to
send more data prior to completing address validation.
Loss of an Initial or Handshake packet from the server can cause a
deadlock if the client does not send additional Initial or Handshake
packets. A deadlock could occur when the server reaches its anti-
amplification limit and the client has received acknowledgments for
all the data it has sent. In this case, when the client has no
reason to send additional packets, the server will be unable to send
more data because it has not validated the client's address. To
prevent this deadlock, clients MUST send a packet on a Probe Timeout
(PTO); see Section 6.2 of [QUIC-RECOVERY]. Specifically, the client
MUST send an Initial packet in a UDP datagram that contains at least
1200 bytes if it does not have Handshake keys, and otherwise send a
Handshake packet.
A server might wish to validate the client address before starting
the cryptographic handshake. QUIC uses a token in the Initial packet
to provide address validation prior to completing the handshake.
This token is delivered to the client during connection establishment
with a Retry packet (see Section 8.1.2) or in a previous connection
using the NEW_TOKEN frame (see Section 8.1.3).
In addition to sending limits imposed prior to address validation,
servers are also constrained in what they can send by the limits set
by the congestion controller. Clients are only constrained by the
congestion controller.
Token Construction
```````````````````````````````````````````````````````
A token sent in a NEW_TOKEN frame or a Retry packet MUST be
constructed in a way that allows the server to identify how it was
provided to a client. These tokens are carried in the same field but
require different handling from servers.
Address Validation Using Retry Packets
```````````````````````````````````````````````````````
Upon receiving the client's Initial packet, the server can request
address validation by sending a Retry packet (Section 17.2.5)
containing a token. This token MUST be repeated by the client in all
Initial packets it sends for that connection after it receives the
Retry packet.
In response to processing an Initial packet containing a token that
was provided in a Retry packet, a server cannot send another Retry
packet; it can only refuse the connection or permit it to proceed.
As long as it is not possible for an attacker to generate a valid
token for its own address (see Section 8.1.4) and the client is able
to return that token, it proves to the server that it received the
token.
A server can also use a Retry packet to defer the state and
processing costs of connection establishment. Requiring the server
to provide a different connection ID, along with the
original_destination_connection_id transport parameter defined in
Section 18.2, forces the server to demonstrate that it, or an entity
it cooperates with, received the original Initial packet from the
client. Providing a different connection ID also grants a server
some control over how subsequent packets are routed. This can be
used to direct connections to a different server instance.
If a server receives a client Initial that contains an invalid Retry
token but is otherwise valid, it knows the client will not accept
another Retry token. The server can discard such a packet and allow
the client to time out to detect handshake failure, but that could
impose a significant latency penalty on the client. Instead, the
server SHOULD immediately close (Section 10.2) the connection with an
INVALID_TOKEN error. Note that a server has not established any
state for the connection at this point and so does not enter the
closing period.
A flow showing the use of a Retry packet is shown in Figure 9.
.. raw:: html
{% highlight %}
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
{% endhighlight %}
Address Validation for Future Connections
```````````````````````````````````````````````````````
A server MAY provide clients with an address validation token during
one connection that can be used on a subsequent connection. Address
validation is especially important with 0-RTT because a server
potentially sends a significant amount of data to a client in
response to 0-RTT data.
The server uses the NEW_TOKEN frame (Section 19.7) to provide the
client with an address validation token that can be used to validate
future connections. In a future connection, the client includes this
token in Initial packets to provide address validation. The client
MUST include the token in all Initial packets it sends, unless a
Retry replaces the token with a newer one. The client MUST NOT use
the token provided in a Retry for future connections. Servers MAY
discard any Initial packet that does not carry the expected token.
Unlike the token that is created for a Retry packet, which is used
immediately, the token sent in the NEW_TOKEN frame can be used after
some period of time has passed. Thus, a token SHOULD have an
expiration time, which could be either an explicit expiration time or
an issued timestamp that can be used to dynamically calculate the
expiration time. A server can store the expiration time or include
it in an encrypted form in the token.
A token issued with NEW_TOKEN MUST NOT include information that would
allow values to be linked by an observer to the connection on which
it was issued. For example, it cannot include the previous
connection ID or addressing information, unless the values are
encrypted. A server MUST ensure that every NEW_TOKEN frame it sends
is unique across all clients, with the exception of those sent to
repair losses of previously sent NEW_TOKEN frames. Information that
allows the server to distinguish between tokens from Retry and
NEW_TOKEN MAY be accessible to entities other than the server.
It is unlikely that the client port number is the same on two
different connections; validating the port is therefore unlikely to
be successful.
A token received in a NEW_TOKEN frame is applicable to any server
that the connection is considered authoritative for (e.g., server
names included in the certificate). When connecting to a server for
which the client retains an applicable and unused token, it SHOULD
include that token in the Token field of its Initial packet.
Including a token might allow the server to validate the client
address without an additional round trip. A client MUST NOT include
a token that is not applicable to the server that it is connecting
to, unless the client has the knowledge that the server that issued
the token and the server the client is connecting to are jointly
managing the tokens. A client MAY use a token from any previous
connection to that server.
A token allows a server to correlate activity between the connection
where the token was issued and any connection where it is used.
Clients that want to break continuity of identity with a server can
discard tokens provided using the NEW_TOKEN frame. In comparison, a
token obtained in a Retry packet MUST be used immediately during the
connection attempt and cannot be used in subsequent connection
attempts.
A client SHOULD NOT reuse a token from a NEW_TOKEN frame for
different connection attempts. Reusing a token allows connections to
be linked by entities on the network path; see Section 9.5.
Clients might receive multiple tokens on a single connection. Aside
from preventing linkability, any token can be used in any connection
attempt. Servers can send additional tokens to either enable address
validation for multiple connection attempts or replace older tokens
that might become invalid. For a client, this ambiguity means that
sending the most recent unused token is most likely to be effective.
Though saving and using older tokens have no negative consequences,
clients can regard older tokens as being less likely to be useful to
the server for address validation.
When a server receives an Initial packet with an address validation
token, it MUST attempt to validate the token, unless it has already
completed address validation. If the token is invalid, then the
server SHOULD proceed as if the client did not have a validated
address, including potentially sending a Retry packet. Tokens
provided with NEW_TOKEN frames and Retry packets can be distinguished
by servers (see Section 8.1.1), and the latter can be validated more
strictly. If the validation succeeds, the server SHOULD then allow
the handshake to proceed.
Note: The rationale for treating the client as unvalidated
rather than discarding the packet is that the client might have
received the token in a previous connection using the NEW_TOKEN
frame, and if the server has lost state, it might be unable to
validate the token at all, leading to connection failure if the
packet is discarded.
In a stateless design, a server can use encrypted and authenticated
tokens to pass information to clients that the server can later
recover and use to validate a client address. Tokens are not
integrated into the cryptographic handshake, and so they are not
authenticated. For instance, a client might be able to reuse a
token. To avoid attacks that exploit this property, a server can
limit its use of tokens to only the information needed to validate
client addresses.
Clients MAY use tokens obtained on one connection for any connection
attempt using the same version. When selecting a token to use,
clients do not need to consider other properties of the connection
that is being attempted, including the choice of possible application
protocols, session tickets, or other connection properties.
Address Validation Token Integrity
```````````````````````````````````````````````````````
An address validation token MUST be difficult to guess. Including a
random value with at least 128 bits of entropy in the token would be
sufficient, but this depends on the server remembering the value it
sends to clients.
A token-based scheme allows the server to offload any state
associated with validation to the client. For this design to work,
the token MUST be covered by integrity protection against
modification or falsification by clients. Without integrity
protection, malicious clients could generate or guess values for
tokens that would be accepted by the server. Only the server
requires access to the integrity protection key for tokens.
There is no need for a single well-defined format for the token
because the server that generates the token also consumes it. Tokens
sent in Retry packets SHOULD include information that allows the
server to verify that the source IP address and port in client
packets remain constant.
Tokens sent in NEW_TOKEN frames MUST include information that allows
the server to verify that the client IP address has not changed from
when the token was issued. Servers can use tokens from NEW_TOKEN
frames in deciding not to send a Retry packet, even if the client
address has changed. If the client IP address has changed, the
server MUST adhere to the anti-amplification limit; see Section 8.
Note that in the presence of NAT, this requirement might be
insufficient to protect other hosts that share the NAT from
amplification attacks.
Attackers could replay tokens to use servers as amplifiers in DDoS
attacks. To protect against such attacks, servers MUST ensure that
replay of tokens is prevented or limited. Servers SHOULD ensure that
tokens sent in Retry packets are only accepted for a short time, as
they are returned immediately by clients. Tokens that are provided
in NEW_TOKEN frames (Section 19.7) need to be valid for longer but
SHOULD NOT be accepted multiple times. Servers are encouraged to
allow tokens to be used only once, if possible; tokens MAY include
additional information about clients to further narrow applicability
or reuse.
Path Validation
```````````````````````````````````````````````````````
Path validation is used by both peers during connection migration
(see Section 9) to verify reachability after a change of address. In
path validation, endpoints test reachability between a specific local
address and a specific peer address, where an address is the 2-tuple
of IP address and port.
Path validation tests that packets sent on a path to a peer are
received by that peer. Path validation is used to ensure that
packets received from a migrating peer do not carry a spoofed source
address.
Path validation does not validate that a peer can send in the return
direction. Acknowledgments cannot be used for return path validation
because they contain insufficient entropy and might be spoofed.
Endpoints independently determine reachability on each direction of a
path, and therefore return reachability can only be established by
the peer.
Path validation can be used at any time by either endpoint. For
instance, an endpoint might check that a peer is still in possession
of its address after a period of quiescence.
Path validation is not designed as a NAT traversal mechanism. Though
the mechanism described here might be effective for the creation of
NAT bindings that support NAT traversal, the expectation is that one
endpoint is able to receive packets without first having sent a
packet on that path. Effective NAT traversal needs additional
synchronization mechanisms that are not provided here.
An endpoint MAY include other frames with the PATH_CHALLENGE and
PATH_RESPONSE frames used for path validation. In particular, an
endpoint can include PADDING frames with a PATH_CHALLENGE frame for
Path Maximum Transmission Unit Discovery (PMTUD); see Section 14.2.1.
An endpoint can also include its own PATH_CHALLENGE frame when
sending a PATH_RESPONSE frame.
An endpoint uses a new connection ID for probes sent from a new local
address; see Section 9.5. When probing a new path, an endpoint can
ensure that its peer has an unused connection ID available for
responses. Sending NEW_CONNECTION_ID and PATH_CHALLENGE frames in
the same packet, if the peer's active_connection_id_limit permits,
ensures that an unused connection ID will be available to the peer
when sending a response.
An endpoint can choose to simultaneously probe multiple paths. The
number of simultaneous paths used for probes is limited by the number
of extra connection IDs its peer has previously supplied, since each
new local address used for a probe requires a previously unused
connection ID.
Initiating Path Validation
```````````````````````````````````````````````````````
To initiate path validation, an endpoint sends a PATH_CHALLENGE frame
containing an unpredictable payload on the path to be validated.
An endpoint MAY send multiple PATH_CHALLENGE frames to guard against
packet loss. However, an endpoint SHOULD NOT send multiple
PATH_CHALLENGE frames in a single packet.
An endpoint SHOULD NOT probe a new path with packets containing a
PATH_CHALLENGE frame more frequently than it would send an Initial
packet. This ensures that connection migration is no more load on a
new path than establishing a new connection.
The endpoint MUST use unpredictable data in every PATH_CHALLENGE
frame so that it can associate the peer's response with the
corresponding PATH_CHALLENGE.
An endpoint MUST expand datagrams that contain a PATH_CHALLENGE frame
to at least the smallest allowed maximum datagram size of 1200 bytes,
unless the anti-amplification limit for the path does not permit
sending a datagram of this size. Sending UDP datagrams of this size
ensures that the network path from the endpoint to the peer can be
used for QUIC; see Section 14.
When an endpoint is unable to expand the datagram size to 1200 bytes
due to the anti-amplification limit, the path MTU will not be
validated. To ensure that the path MTU is large enough, the endpoint
MUST perform a second path validation by sending a PATH_CHALLENGE
frame in a datagram of at least 1200 bytes. This additional
validation can be performed after a PATH_RESPONSE is successfully
received or when enough bytes have been received on the path that
sending the larger datagram will not result in exceeding the anti-
amplification limit.
Unlike other cases where datagrams are expanded, endpoints MUST NOT
discard datagrams that appear to be too small when they contain
PATH_CHALLENGE or PATH_RESPONSE.
Path Validation Responses
```````````````````````````````````````````````````````
On receiving a PATH_CHALLENGE frame, an endpoint MUST respond by
echoing the data contained in the PATH_CHALLENGE frame in a
PATH_RESPONSE frame. An endpoint MUST NOT delay transmission of a
packet containing a PATH_RESPONSE frame unless constrained by
congestion control.
A PATH_RESPONSE frame MUST be sent on the network path where the
PATH_CHALLENGE frame was received. This ensures that path validation
by a peer only succeeds if the path is functional in both directions.
This requirement MUST NOT be enforced by the endpoint that initiates
path validation, as that would enable an attack on migration; see
Section 9.3.3.
An endpoint MUST expand datagrams that contain a PATH_RESPONSE frame
to at least the smallest allowed maximum datagram size of 1200 bytes.
This verifies that the path is able to carry datagrams of this size
in both directions. However, an endpoint MUST NOT expand the
datagram containing the PATH_RESPONSE if the resulting data exceeds
the anti-amplification limit. This is expected to only occur if the
received PATH_CHALLENGE was not sent in an expanded datagram.
An endpoint MUST NOT send more than one PATH_RESPONSE frame in
response to one PATH_CHALLENGE frame; see Section 13.3. The peer is
expected to send more PATH_CHALLENGE frames as necessary to evoke
additional PATH_RESPONSE frames.
Successful Path Validation
```````````````````````````````````````````````````````
Path validation succeeds when a PATH_RESPONSE frame is received that
contains the data that was sent in a previous PATH_CHALLENGE frame.
A PATH_RESPONSE frame received on any network path validates the path
on which the PATH_CHALLENGE was sent.
If an endpoint sends a PATH_CHALLENGE frame in a datagram that is not
expanded to at least 1200 bytes and if the response to it validates
the peer address, the path is validated but not the path MTU. As a
result, the endpoint can now send more than three times the amount of
data that has been received. However, the endpoint MUST initiate
another path validation with an expanded datagram to verify that the
path supports the required MTU.
Receipt of an acknowledgment for a packet containing a PATH_CHALLENGE
frame is not adequate validation, since the acknowledgment can be
spoofed by a malicious peer.
Failed Path Validation
```````````````````````````````````````````````````````
Path validation only fails when the endpoint attempting to validate
the path abandons its attempt to validate the path.
Endpoints SHOULD abandon path validation based on a timer. When
setting this timer, implementations are cautioned that the new path
could have a longer round-trip time than the original. A value of
three times the larger of the current PTO or the PTO for the new path
(using kInitialRtt, as defined in [QUIC-RECOVERY]) is RECOMMENDED.
This timeout allows for multiple PTOs to expire prior to failing path
validation, so that loss of a single PATH_CHALLENGE or PATH_RESPONSE
frame does not cause path validation failure.
Note that the endpoint might receive packets containing other frames
on the new path, but a PATH_RESPONSE frame with appropriate data is
required for path validation to succeed.
When an endpoint abandons path validation, it determines that the
path is unusable. This does not necessarily imply a failure of the
connection -- endpoints can continue sending packets over other paths
as appropriate. If no paths are available, an endpoint can wait for
a new path to become available or close the connection. An endpoint
that has no valid network path to its peer MAY signal this using the
NO_VIABLE_PATH connection error, noting that this is only possible if
the network path exists but does not support the required MTU
(Section 14).
A path validation might be abandoned for other reasons besides
failure. Primarily, this happens if a connection migration to a new
path is initiated while a path validation on the old path is in
progress.
Connection Migration
----------------------------
Following is copied from QUIC [RFC-9000]_.
For each section, review and edit.
The use of a connection ID allows connections to survive changes to
endpoint addresses (IP address and port), such as those caused by an
endpoint migrating to a new network. This section describes the
process by which an endpoint migrates to a new address.
The design of QUIC relies on endpoints retaining a stable address for
the duration of the handshake. An endpoint MUST NOT initiate
connection migration before the handshake is confirmed, as defined in
Section 4.1.2 of [QUIC-TLS].
If the peer sent the disable_active_migration transport parameter, an
endpoint also MUST NOT send packets (including probing packets; see
Section 9.1) from a different local address to the address the peer
used during the handshake, unless the endpoint has acted on a
preferred_address transport parameter from the peer. If the peer
violates this requirement, the endpoint MUST either drop the incoming
packets on that path without generating a Stateless Reset or proceed
with path validation and allow the peer to migrate. Generating a
Stateless Reset or closing the connection would allow third parties
in the network to cause connections to close by spoofing or otherwise
manipulating observed traffic.
Not all changes of peer address are intentional, or active,
migrations. The peer could experience NAT rebinding: a change of
address due to a middlebox, usually a NAT, allocating a new outgoing
port or even a new outgoing IP address for a flow. An endpoint MUST
perform path validation (Section 8.2) if it detects any change to a
peer's address, unless it has previously validated that address.
When an endpoint has no validated path on which to send packets, it
MAY discard connection state. An endpoint capable of connection
migration MAY wait for a new path to become available before
discarding connection state.
This document limits migration of connections to new client
addresses, except as described in Section 9.6. Clients are
responsible for initiating all migrations. Servers do not send non-
probing packets (see Section 9.1) toward a client address until they
see a non-probing packet from that address. If a client receives
packets from an unknown server address, the client MUST discard these
packets.
Probing a New Path
`````````````````````````
An endpoint MAY probe for peer reachability from a new local address
using path validation (Section 8.2) prior to migrating the connection
to the new local address. Failure of path validation simply means
that the new path is not usable for this connection. Failure to
validate a path does not cause the connection to end unless there are
no valid alternative paths available.
PATH_CHALLENGE, PATH_RESPONSE, NEW_CONNECTION_ID, and PADDING frames
are "probing frames", and all other frames are "non-probing frames".
A packet containing only probing frames is a "probing packet", and a
packet containing any other frame is a "non-probing packet".
Initiating Connection Migration
`````````````````````````````````````
An endpoint can migrate a connection to a new local address by
sending packets containing non-probing frames from that address.
Each endpoint validates its peer's address during connection
establishment. Therefore, a migrating endpoint can send to its peer
knowing that the peer is willing to receive at the peer's current
address. Thus, an endpoint can migrate to a new local address
without first validating the peer's address.
To establish reachability on the new path, an endpoint initiates path
validation (Section 8.2) on the new path. An endpoint MAY defer path
validation until after a peer sends the next non-probing frame to its
new address.
When migrating, the new path might not support the endpoint's current
sending rate. Therefore, the endpoint resets its congestion
controller and RTT estimate, as described in Section 9.4.
The new path might not have the same ECN capability. Therefore, the
endpoint validates ECN capability as described in Section 13.4.
Responding to Connection Migration
```````````````````````````````````````````
Receiving a packet from a new peer address containing a non-probing
frame indicates that the peer has migrated to that address.
If the recipient permits the migration, it MUST send subsequent
packets to the new peer address and MUST initiate path validation
(Section 8.2) to verify the peer's ownership of the address if
validation is not already underway. If the recipient has no unused
connection IDs from the peer, it will not be able to send anything on
the new path until the peer provides one; see Section 9.5.
An endpoint only changes the address to which it sends packets in
response to the highest-numbered non-probing packet. This ensures
that an endpoint does not send packets to an old peer address in the
case that it receives reordered packets.
An endpoint MAY send data to an unvalidated peer address, but it MUST
protect against potential attacks as described in Sections 9.3.1 and
9.3.2. An endpoint MAY skip validation of a peer address if that
address has been seen recently. In particular, if an endpoint
returns to a previously validated path after detecting some form of
spurious migration, skipping address validation and restoring loss
detection and congestion state can reduce the performance impact of
the attack.
After changing the address to which it sends non-probing packets, an
endpoint can abandon any path validation for other addresses.
Receiving a packet from a new peer address could be the result of a
NAT rebinding at the peer.
After verifying a new client address, the server SHOULD send new
address validation tokens (Section 8) to the client.
Peer Address Spoofing
`````````````````````````
It is possible that a peer is spoofing its source address to cause an
endpoint to send excessive amounts of data to an unwilling host. If
the endpoint sends significantly more data than the spoofing peer,
connection migration might be used to amplify the volume of data that
an attacker can generate toward a victim.
As described in Section 9.3, an endpoint is required to validate a
peer's new address to confirm the peer's possession of the new
address. Until a peer's address is deemed valid, an endpoint limits
the amount of data it sends to that address; see Section 8. In the
absence of this limit, an endpoint risks being used for a denial-of-
service attack against an unsuspecting victim.
If an endpoint skips validation of a peer address as described above,
it does not need to limit its sending rate.
On-Path Address Spoofing
`````````````````````````
An on-path attacker could cause a spurious connection migration by
copying and forwarding a packet with a spoofed address such that it
arrives before the original packet. The packet with the spoofed
address will be seen to come from a migrating connection, and the
original packet will be seen as a duplicate and dropped. After a
spurious migration, validation of the source address will fail
because the entity at the source address does not have the necessary
cryptographic keys to read or respond to the PATH_CHALLENGE frame
that is sent to it even if it wanted to.
To protect the connection from failing due to such a spurious
migration, an endpoint MUST revert to using the last validated peer
address when validation of a new peer address fails. Additionally,
receipt of packets with higher packet numbers from the legitimate
peer address will trigger another connection migration. This will
cause the validation of the address of the spurious migration to be
abandoned, thus containing migrations initiated by the attacker
injecting a single packet.
If an endpoint has no state about the last validated peer address, it
MUST close the connection silently by discarding all connection
state. This results in new packets on the connection being handled
generically. For instance, an endpoint MAY send a Stateless Reset in
response to any further incoming packets.
Off-Path Packet Forwarding
```````````````````````````````````
An off-path attacker that can observe packets might forward copies of
genuine packets to endpoints. If the copied packet arrives before
the genuine packet, this will appear as a NAT rebinding. Any genuine
packet will be discarded as a duplicate. If the attacker is able to
continue forwarding packets, it might be able to cause migration to a
path via the attacker. This places the attacker on-path, giving it
the ability to observe or drop all subsequent packets.
This style of attack relies on the attacker using a path that has
approximately the same characteristics as the direct path between
endpoints. The attack is more reliable if relatively few packets are
sent or if packet loss coincides with the attempted attack.
A non-probing packet received on the original path that increases the
maximum received packet number will cause the endpoint to move back
to that path. Eliciting packets on this path increases the
likelihood that the attack is unsuccessful. Therefore, mitigation of
this attack relies on triggering the exchange of packets.
In response to an apparent migration, endpoints MUST validate the
previously active path using a PATH_CHALLENGE frame. This induces
the sending of new packets on that path. If the path is no longer
viable, the validation attempt will time out and fail; if the path is
viable but no longer desired, the validation will succeed but only
results in probing packets being sent on the path.
An endpoint that receives a PATH_CHALLENGE on an active path SHOULD
send a non-probing packet in response. If the non-probing packet
arrives before any copy made by an attacker, this results in the
connection being migrated back to the original path. Any subsequent
migration to another path restarts this entire process.
This defense is imperfect, but this is not considered a serious
problem. If the path via the attack is reliably faster than the
original path despite multiple attempts to use that original path, it
is not possible to distinguish between an attack and an improvement
in routing.
An endpoint could also use heuristics to improve detection of this
style of attack. For instance, NAT rebinding is improbable if
packets were recently received on the old path; similarly, rebinding
is rare on IPv6 paths. Endpoints can also look for duplicated
packets. Conversely, a change in connection ID is more likely to
indicate an intentional migration rather than an attack.
Loss Detection and Congestion Control
`````````````````````````````````````````
The capacity available on the new path might not be the same as the
old path. Packets sent on the old path MUST NOT contribute to
congestion control or RTT estimation for the new path.
On confirming a peer's ownership of its new address, an endpoint MUST
immediately reset the congestion controller and round-trip time
estimator for the new path to initial values (see Appendices A.3 and
B.3 of [QUIC-RECOVERY]) unless the only change in the peer's address
is its port number. Because port-only changes are commonly the
result of NAT rebinding or other middlebox activity, the endpoint MAY
instead retain its congestion control state and round-trip estimate
in those cases instead of reverting to initial values. In cases
where congestion control state retained from an old path is used on a
new path with substantially different characteristics, a sender could
transmit too aggressively until the congestion controller and the RTT
estimator have adapted. Generally, implementations are advised to be
cautious when using previous values on a new path.
There could be apparent reordering at the receiver when an endpoint
sends data and probes from/to multiple addresses during the migration
period, since the two resulting paths could have different round-trip
times. A receiver of packets on multiple paths will still send ACK
frames covering all received packets.
While multiple paths might be used during connection migration, a
single congestion control context and a single loss recovery context
(as described in [QUIC-RECOVERY]) could be adequate. For instance,
an endpoint might delay switching to a new congestion control context
until it is confirmed that an old path is no longer needed (such as
the case described in Section 9.3.3).
A sender can make exceptions for probe packets so that their loss
detection is independent and does not unduly cause the congestion
controller to reduce its sending rate. An endpoint might set a
separate timer when a PATH_CHALLENGE is sent, which is canceled if
the corresponding PATH_RESPONSE is received. If the timer fires
before the PATH_RESPONSE is received, the endpoint might send a new
PATH_CHALLENGE and restart the timer for a longer period of time.
This timer SHOULD be set as described in Section 6.2.1 of
[QUIC-RECOVERY] and MUST NOT be more aggressive.
Privacy Implications of Connection Migration
`````````````````````````````````````````````````
Using a stable connection ID on multiple network paths would allow a
passive observer to correlate activity between those paths. An
endpoint that moves between networks might not wish to have their
activity correlated by any entity other than their peer, so different
connection IDs are used when sending from different local addresses,
as discussed in Section 5.1. For this to be effective, endpoints
need to ensure that connection IDs they provide cannot be linked by
any other entity.
At any time, endpoints MAY change the Destination Connection ID they
transmit with to a value that has not been used on another path.
An endpoint MUST NOT reuse a connection ID when sending from more
than one local address -- for example, when initiating connection
migration as described in Section 9.2 or when probing a new network
path as described in Section 9.1.
Similarly, an endpoint MUST NOT reuse a connection ID when sending to
more than one destination address. Due to network changes outside
the control of its peer, an endpoint might receive packets from a new
source address with the same Destination Connection ID field value,
in which case it MAY continue to use the current connection ID with
the new remote address while still sending from the same local
address.
These requirements regarding connection ID reuse apply only to the
sending of packets, as unintentional changes in path without a change
in connection ID are possible. For example, after a period of
network inactivity, NAT rebinding might cause packets to be sent on a
new path when the client resumes sending. An endpoint responds to
such an event as described in Section 9.3.
Using different connection IDs for packets sent in both directions on
each new network path eliminates the use of the connection ID for
linking packets from the same connection across different network
paths. Header protection ensures that packet numbers cannot be used
to correlate activity. This does not prevent other properties of
packets, such as timing and size, from being used to correlate
activity.
An endpoint SHOULD NOT initiate migration with a peer that has
requested a zero-length connection ID, because traffic over the new
path might be trivially linkable to traffic over the old one. If the
server is able to associate packets with a zero-length connection ID
to the right connection, it means that the server is using other
information to demultiplex packets. For example, a server might
provide a unique address to every client -- for instance, using HTTP
alternative services [ALTSVC]. Information that might allow correct
routing of packets across multiple network paths will also allow
activity on those paths to be linked by entities other than the peer.
A client might wish to reduce linkability by switching to a new
connection ID, source UDP port, or IP address (see [RFC8981]) when
sending traffic after a period of inactivity. Changing the address
from which it sends packets at the same time might cause the server
to detect a connection migration. This ensures that the mechanisms
that support migration are exercised even for clients that do not
experience NAT rebindings or genuine migrations. Changing address
can cause a peer to reset its congestion control state (see
Section 9.4), so addresses SHOULD only be changed infrequently.
An endpoint that exhausts available connection IDs cannot probe new
paths or initiate migration, nor can it respond to probes or attempts
by its peer to migrate. To ensure that migration is possible and
packets sent on different paths cannot be correlated, endpoints
SHOULD provide new connection IDs before peers migrate; see
Section 5.1.1. If a peer might have exhausted available connection
IDs, a migrating endpoint could include a NEW_CONNECTION_ID frame in
all packets sent on a new network path.
Server's Preferred Address
`````````````````````````````
QUIC allows servers to accept connections on one IP address and
attempt to transfer these connections to a more preferred address
shortly after the handshake. This is particularly useful when
clients initially connect to an address shared by multiple servers
but would prefer to use a unicast address to ensure connection
stability. This section describes the protocol for migrating a
connection to a preferred server address.
Migrating a connection to a new server address mid-connection is not
supported by the version of QUIC specified in this document. If a
client receives packets from a new server address when the client has
not initiated a migration to that address, the client SHOULD discard
these packets.
Communicating a Preferred Address
``````````````````````````````````````
A server conveys a preferred address by including the
preferred_address transport parameter in the TLS handshake.
Servers MAY communicate a preferred address of each address family
(IPv4 and IPv6) to allow clients to pick the one most suited to their
network attachment.
Once the handshake is confirmed, the client SHOULD select one of the
two addresses provided by the server and initiate path validation
(see Section 8.2). A client constructs packets using any previously
unused active connection ID, taken from either the preferred_address
transport parameter or a NEW_CONNECTION_ID frame.
As soon as path validation succeeds, the client SHOULD begin sending
all future packets to the new server address using the new connection
ID and discontinue use of the old server address. If path validation
fails, the client MUST continue sending all future packets to the
server's original IP address.
Migration to a Preferred Address
````````````````````````````````````
A client that migrates to a preferred address MUST validate the
address it chooses before migrating; see Section 21.5.3.
A server might receive a packet addressed to its preferred IP address
at any time after it accepts a connection. If this packet contains a
PATH_CHALLENGE frame, the server sends a packet containing a
PATH_RESPONSE frame as per Section 8.2. The server MUST send non-
probing packets from its original address until it receives a non-
probing packet from the client at its preferred address and until the
server has validated the new path.
The server MUST probe on the path toward the client from its
preferred address. This helps to guard against spurious migration
initiated by an attacker.
Once the server has completed its path validation and has received a
non-probing packet with a new largest packet number on its preferred
address, the server begins sending non-probing packets to the client
exclusively from its preferred IP address. The server SHOULD drop
newer packets for this connection that are received on the old IP
address. The server MAY continue to process delayed packets that are
received on the old IP address.
The addresses that a server provides in the preferred_address
transport parameter are only valid for the connection in which they
are provided. A client MUST NOT use these for other connections,
including connections that are resumed from the current connection.
Interaction of Client Migration and Preferred Address
``````````````````````````````````````````````````````````
A client might need to perform a connection migration before it has
migrated to the server's preferred address. In this case, the client
SHOULD perform path validation to both the original and preferred
server address from the client's new address concurrently.
If path validation of the server's preferred address succeeds, the
client MUST abandon validation of the original address and migrate to
using the server's preferred address. If path validation of the
server's preferred address fails but validation of the server's
original address succeeds, the client MAY migrate to its new address
and continue sending to the server's original address.
If packets received at the server's preferred address have a
different source address than observed from the client during the
handshake, the server MUST protect against potential attacks as
described in Sections 9.3.1 and 9.3.2. In addition to intentional
simultaneous migration, this might also occur because the client's
access network used a different NAT binding for the server's
preferred address.
Servers SHOULD initiate path validation to the client's new address
upon receiving a probe packet from a different address; see
Section 8.
A client that migrates to a new address SHOULD use a preferred
address from the same address family for the server.
The connection ID provided in the preferred_address transport
parameter is not specific to the addresses that are provided. This
connection ID is provided to ensure that the client has a connection
ID available for migration, but the client MAY use this connection ID
on any path.
Use of IPv6 Flow Label and Migration
``````````````````````````````````````````
QUIC recommends endpoints that send data using IPv6 SHOULD apply an IPv6 flow label
in compliance with [RFC-6437]_, unless the local API does not allow
setting IPv6 flow labels.
Unfortunately, the Java API does not allow setting IPv6 flow labels.
Security Considerations
---------------------------
Following is copied from QUIC [RFC-9000]_.
For each section, review and edit.
The goal of QUIC is to provide a secure transport connection.
Section 21.1 provides an overview of those properties; subsequent
sections discuss constraints and caveats regarding these properties,
including descriptions of known attacks and countermeasures.
Overview of Security Properties
``````````````````````````````````````````````
A complete security analysis of QUIC is outside the scope of this
document. This section provides an informal description of the
desired security properties as an aid to implementers and to help
guide protocol analysis.
QUIC assumes the threat model described in [SEC-CONS] and provides
protections against many of the attacks that arise from that model.
For this purpose, attacks are divided into passive and active
attacks. Passive attackers have the ability to read packets from the
network, while active attackers also have the ability to write
packets into the network. However, a passive attack could involve an
attacker with the ability to cause a routing change or other
modification in the path taken by packets that comprise a connection.
Attackers are additionally categorized as either on-path attackers or
off-path attackers. An on-path attacker can read, modify, or remove
any packet it observes such that the packet no longer reaches its
destination, while an off-path attacker observes the packets but
cannot prevent the original packet from reaching its intended
destination. Both types of attackers can also transmit arbitrary
packets. This definition differs from that of Section 3.5 of
[SEC-CONS] in that an off-path attacker is able to observe packets.
Properties of the handshake, protected packets, and connection
migration are considered separately.
Handshake
``````````````````````````````````````````````
The QUIC handshake incorporates the TLS 1.3 handshake and inherits
the cryptographic properties described in Appendix E.1 of [TLS13].
Many of the security properties of QUIC depend on the TLS handshake
providing these properties. Any attack on the TLS handshake could
affect QUIC.
Any attack on the TLS handshake that compromises the secrecy or
uniqueness of session keys, or the authentication of the
participating peers, affects other security guarantees provided by
QUIC that depend on those keys. For instance, migration (Section 9)
depends on the efficacy of confidentiality protections, both for the
negotiation of keys using the TLS handshake and for QUIC packet
protection, to avoid linkability across network paths.
An attack on the integrity of the TLS handshake might allow an
attacker to affect the selection of application protocol or QUIC
version.
In addition to the properties provided by TLS, the QUIC handshake
provides some defense against DoS attacks on the handshake.
Anti-Amplification
``````````````````````````````````````````````
Address validation (Section 8) is used to verify that an entity that
claims a given address is able to receive packets at that address.
Address validation limits amplification attack targets to addresses
for which an attacker can observe packets.
Prior to address validation, endpoints are limited in what they are
able to send. Endpoints cannot send data toward an unvalidated
address in excess of three times the data received from that address.
Note: The anti-amplification limit only applies when an
endpoint responds to packets received from an unvalidated
address. The anti-amplification limit does not apply to
clients when establishing a new connection or when initiating
connection migration.
Server-Side DoS
``````````````````````````````````````````````
Computing the server's first flight for a full handshake is
potentially expensive, requiring both a signature and a key exchange
computation. In order to prevent computational DoS attacks, the
Retry packet provides a cheap token exchange mechanism that allows
servers to validate a client's IP address prior to doing any
expensive computations at the cost of a single round trip. After a
successful handshake, servers can issue new tokens to a client, which
will allow new connection establishment without incurring this cost.
On-Path Handshake Termination
``````````````````````````````````````````````
An on-path or off-path attacker can force a handshake to fail by
replacing or racing Initial packets. Once valid Initial packets have
been exchanged, subsequent Handshake packets are protected with the
Handshake keys, and an on-path attacker cannot force handshake
failure other than by dropping packets to cause endpoints to abandon
the attempt.
An on-path attacker can also replace the addresses of packets on
either side and therefore cause the client or server to have an
incorrect view of the remote addresses. Such an attack is
indistinguishable from the functions performed by a NAT.
Parameter Negotiation
``````````````````````````````````````````````
The entire handshake is cryptographically protected, with the Initial
packets being encrypted with per-version keys and the Handshake and
later packets being encrypted with keys derived from the TLS key
exchange. Further, parameter negotiation is folded into the TLS
transcript and thus provides the same integrity guarantees as
ordinary TLS negotiation. An attacker can observe the client's
transport parameters (as long as it knows the version-specific salt)
but cannot observe the server's transport parameters and cannot
influence parameter negotiation.
Connection IDs are unencrypted but integrity protected in all
packets.
This version of QUIC does not incorporate a version negotiation
mechanism; implementations of incompatible versions will simply fail
to establish a connection.
Protected Packets
``````````````````````````````````````````````
Packet protection (Section 12.1) applies authenticated encryption to
all packets except Version Negotiation packets, though Initial and
Retry packets have limited protection due to the use of version-
specific keying material; see [QUIC-TLS] for more details. This
section considers passive and active attacks against protected
packets.
Both on-path and off-path attackers can mount a passive attack in
which they save observed packets for an offline attack against packet
protection at a future time; this is true for any observer of any
packet on any network.
An attacker that injects packets without being able to observe valid
packets for a connection is unlikely to be successful, since packet
protection ensures that valid packets are only generated by endpoints
that possess the key material established during the handshake; see
Sections 7 and 21.1.1. Similarly, any active attacker that observes
packets and attempts to insert new data or modify existing data in
those packets should not be able to generate packets deemed valid by
the receiving endpoint, other than Initial packets.
A spoofing attack, in which an active attacker rewrites unprotected
parts of a packet that it forwards or injects, such as the source or
destination address, is only effective if the attacker can forward
packets to the original endpoint. Packet protection ensures that the
packet payloads can only be processed by the endpoints that completed
the handshake, and invalid packets are ignored by those endpoints.
An attacker can also modify the boundaries between packets and UDP
datagrams, causing multiple packets to be coalesced into a single
datagram or splitting coalesced packets into multiple datagrams.
Aside from datagrams containing Initial packets, which require
padding, modification of how packets are arranged in datagrams has no
functional effect on a connection, although it might change some
performance characteristics.
Connection Migration
``````````````````````````````````````````````
Connection migration (Section 9) provides endpoints with the ability
to transition between IP addresses and ports on multiple paths, using
one path at a time for transmission and receipt of non-probing
frames. Path validation (Section 8.2) establishes that a peer is
both willing and able to receive packets sent on a particular path.
This helps reduce the effects of address spoofing by limiting the
number of packets sent to a spoofed address.
This section describes the intended security properties of connection
migration under various types of DoS attacks.
On-Path Active Attacks
``````````````````````````````````````````````
An attacker that can cause a packet it observes to no longer reach
its intended destination is considered an on-path attacker. When an
attacker is present between a client and server, endpoints are
required to send packets through the attacker to establish
connectivity on a given path.
An on-path attacker can:
* Inspect packets
* Modify IP and UDP packet headers
* Inject new packets
* Delay packets
* Reorder packets
* Drop packets
* Split and merge datagrams along packet boundaries
An on-path attacker cannot:
* Modify an authenticated portion of a packet and cause the
recipient to accept that packet
An on-path attacker has the opportunity to modify the packets that it
observes; however, any modifications to an authenticated portion of a
packet will cause it to be dropped by the receiving endpoint as
invalid, as packet payloads are both authenticated and encrypted.
QUIC aims to constrain the capabilities of an on-path attacker as
follows:
1. An on-path attacker can prevent the use of a path for a
connection, causing the connection to fail if it cannot use a
different path that does not contain the attacker. This can be
achieved by dropping all packets, modifying them so that they
fail to decrypt, or other methods.
2. An on-path attacker can prevent migration to a new path for which
the attacker is also on-path by causing path validation to fail
on the new path.
3. An on-path attacker cannot prevent a client from migrating to a
path for which the attacker is not on-path.
4. An on-path attacker can reduce the throughput of a connection by
delaying packets or dropping them.
5. An on-path attacker cannot cause an endpoint to accept a packet
for which it has modified an authenticated portion of that
packet.
Off-Path Active Attacks
``````````````````````````````````````````````
An off-path attacker is not directly on the path between a client and
server but could be able to obtain copies of some or all packets sent
between the client and the server. It is also able to send copies of
those packets to either endpoint.
An off-path attacker can:
* Inspect packets
* Inject new packets
* Reorder injected packets
An off-path attacker cannot:
* Modify packets sent by endpoints
* Delay packets
* Drop packets
* Reorder original packets
An off-path attacker can create modified copies of packets that it
has observed and inject those copies into the network, potentially
with spoofed source and destination addresses.
For the purposes of this discussion, it is assumed that an off-path
attacker has the ability to inject a modified copy of a packet into
the network that will reach the destination endpoint prior to the
arrival of the original packet observed by the attacker. In other
words, an attacker has the ability to consistently "win" a race with
the legitimate packets between the endpoints, potentially causing the
original packet to be ignored by the recipient.
It is also assumed that an attacker has the resources necessary to
affect NAT state. In particular, an attacker can cause an endpoint
to lose its NAT binding and then obtain the same port for use with
its own traffic.
QUIC aims to constrain the capabilities of an off-path attacker as
follows:
1. An off-path attacker can race packets and attempt to become a
"limited" on-path attacker.
2. An off-path attacker can cause path validation to succeed for
forwarded packets with the source address listed as the off-path
attacker as long as it can provide improved connectivity between
the client and the server.
3. An off-path attacker cannot cause a connection to close once the
handshake has completed.
4. An off-path attacker cannot cause migration to a new path to fail
if it cannot observe the new path.
5. An off-path attacker can become a limited on-path attacker during
migration to a new path for which it is also an off-path
attacker.
6. An off-path attacker can become a limited on-path attacker by
affecting shared NAT state such that it sends packets to the
server from the same IP address and port that the client
originally used.
Limited On-Path Active Attacks
``````````````````````````````````````````````
A limited on-path attacker is an off-path attacker that has offered
improved routing of packets by duplicating and forwarding original
packets between the server and the client, causing those packets to
arrive before the original copies such that the original packets are
dropped by the destination endpoint.
A limited on-path attacker differs from an on-path attacker in that
it is not on the original path between endpoints, and therefore the
original packets sent by an endpoint are still reaching their
destination. This means that a future failure to route copied
packets to the destination faster than their original path will not
prevent the original packets from reaching the destination.
A limited on-path attacker can:
* Inspect packets
* Inject new packets
* Modify unencrypted packet headers
* Reorder packets
A limited on-path attacker cannot:
* Delay packets so that they arrive later than packets sent on the
original path
* Drop packets
* Modify the authenticated and encrypted portion of a packet and
cause the recipient to accept that packet
A limited on-path attacker can only delay packets up to the point
that the original packets arrive before the duplicate packets,
meaning that it cannot offer routing with worse latency than the
original path. If a limited on-path attacker drops packets, the
original copy will still arrive at the destination endpoint.
QUIC aims to constrain the capabilities of a limited off-path
attacker as follows:
1. A limited on-path attacker cannot cause a connection to close
once the handshake has completed.
2. A limited on-path attacker cannot cause an idle connection to
close if the client is first to resume activity.
3. A limited on-path attacker can cause an idle connection to be
deemed lost if the server is the first to resume activity.
Note that these guarantees are the same guarantees provided for any
NAT, for the same reasons.
Handshake Denial of Service
``````````````````````````````````````````````
As an encrypted and authenticated transport, QUIC provides a range of
protections against denial of service. Once the cryptographic
handshake is complete, QUIC endpoints discard most packets that are
not authenticated, greatly limiting the ability of an attacker to
interfere with existing connections.
Once a connection is established, QUIC endpoints might accept some
unauthenticated ICMP packets (see Section 14.2.1), but the use of
these packets is extremely limited. The only other type of packet
that an endpoint might accept is a stateless reset (Section 10.3),
which relies on the token being kept secret until it is used.
During the creation of a connection, QUIC only provides protection
against attacks from off the network path. All QUIC packets contain
proof that the recipient saw a preceding packet from its peer.
Addresses cannot change during the handshake, so endpoints can
discard packets that are received on a different network path.
The Source and Destination Connection ID fields are the primary means
of protection against an off-path attack during the handshake; see
Section 8.1. These are required to match those set by a peer.
Except for Initial and Stateless Resets, an endpoint only accepts
packets that include a Destination Connection ID field that matches a
value the endpoint previously chose. This is the only protection
offered for Version Negotiation packets.
The Destination Connection ID field in an Initial packet is selected
by a client to be unpredictable, which serves an additional purpose.
The packets that carry the cryptographic handshake are protected with
a key that is derived from this connection ID and a salt specific to
the QUIC version. This allows endpoints to use the same process for
authenticating packets that they receive as they use after the
cryptographic handshake completes. Packets that cannot be
authenticated are discarded. Protecting packets in this fashion
provides a strong assurance that the sender of the packet saw the
Initial packet and understood it.
These protections are not intended to be effective against an
attacker that is able to receive QUIC packets prior to the connection
being established. Such an attacker can potentially send packets
that will be accepted by QUIC endpoints. This version of QUIC
attempts to detect this sort of attack, but it expects that endpoints
will fail to establish a connection rather than recovering. For the
most part, the cryptographic handshake protocol [QUIC-TLS] is
responsible for detecting tampering during the handshake.
Endpoints are permitted to use other methods to detect and attempt to
recover from interference with the handshake. Invalid packets can be
identified and discarded using other methods, but no specific method
is mandated in this document.
Amplification Attack
``````````````````````````````````````````````
An attacker might be able to receive an address validation token
(Section 8) from a server and then release the IP address it used to
acquire that token. At a later time, the attacker can initiate a
0-RTT connection with a server by spoofing this same address, which
might now address a different (victim) endpoint. The attacker can
thus potentially cause the server to send an initial congestion
window's worth of data towards the victim.
Servers SHOULD provide mitigations for this attack by limiting the
usage and lifetime of address validation tokens; see Section 8.1.3.
Optimistic ACK Attack
``````````````````````````````````````````````
An endpoint that acknowledges packets it has not received might cause
a congestion controller to permit sending at rates beyond what the
network supports. An endpoint MAY skip packet numbers when sending
packets to detect this behavior. An endpoint can then immediately
close the connection with a connection error of type
PROTOCOL_VIOLATION; see Section 10.2.
Request Forgery Attacks
``````````````````````````````````````````````
A request forgery attack occurs where an endpoint causes its peer to
issue a request towards a victim, with the request controlled by the
endpoint. Request forgery attacks aim to provide an attacker with
access to capabilities of its peer that might otherwise be
unavailable to the attacker. For a networking protocol, a request
forgery attack is often used to exploit any implicit authorization
conferred on the peer by the victim due to the peer's location in the
network.
For request forgery to be effective, an attacker needs to be able to
influence what packets the peer sends and where these packets are
sent. If an attacker can target a vulnerable service with a
controlled payload, that service might perform actions that are
attributed to the attacker's peer but are decided by the attacker.
For example, cross-site request forgery [CSRF] exploits on the Web
cause a client to issue requests that include authorization cookies
[COOKIE], allowing one site access to information and actions that
are intended to be restricted to a different site.
As QUIC runs over UDP, the primary attack modality of concern is one
where an attacker can select the address to which its peer sends UDP
datagrams and can control some of the unprotected content of those
packets. As much of the data sent by QUIC endpoints is protected,
this includes control over ciphertext. An attack is successful if an
attacker can cause a peer to send a UDP datagram to a host that will
perform some action based on content in the datagram.
This section discusses ways in which QUIC might be used for request
forgery attacks.
This section also describes limited countermeasures that can be
implemented by QUIC endpoints. These mitigations can be employed
unilaterally by a QUIC implementation or deployment, without
potential targets for request forgery attacks taking action.
However, these countermeasures could be insufficient if UDP-based
services do not properly authorize requests.
Because the migration attack described in Section 21.5.4 is quite
powerful and does not have adequate countermeasures, QUIC server
implementations should assume that attackers can cause them to
generate arbitrary UDP payloads to arbitrary destinations. QUIC
servers SHOULD NOT be deployed in networks that do not deploy ingress
filtering [BCP38] and also have inadequately secured UDP endpoints.
Although it is not generally possible to ensure that clients are not
co-located with vulnerable endpoints, this version of QUIC does not
allow servers to migrate, thus preventing spoofed migration attacks
on clients. Any future extension that allows server migration MUST
also define countermeasures for forgery attacks.
Control Options for Endpoints
``````````````````````````````````````````````
QUIC offers some opportunities for an attacker to influence or
control where its peer sends UDP datagrams:
* initial connection establishment (Section 7), where a server is
able to choose where a client sends datagrams -- for example, by
populating DNS records;
* preferred addresses (Section 9.6), where a server is able to
choose where a client sends datagrams;
* spoofed connection migrations (Section 9.3.1), where a client is
able to use source address spoofing to select where a server sends
subsequent datagrams; and
* spoofed packets that cause a server to send a Version Negotiation
packet (Section 21.5.5).
In all cases, the attacker can cause its peer to send datagrams to a
victim that might not understand QUIC. That is, these packets are
sent by the peer prior to address validation; see Section 8.
Outside of the encrypted portion of packets, QUIC offers an endpoint
several options for controlling the content of UDP datagrams that its
peer sends. The Destination Connection ID field offers direct
control over bytes that appear early in packets sent by the peer; see
Section 5.1. The Token field in Initial packets offers a server
control over other bytes of Initial packets; see Section 17.2.2.
There are no measures in this version of QUIC to prevent indirect
control over the encrypted portions of packets. It is necessary to
assume that endpoints are able to control the contents of frames that
a peer sends, especially those frames that convey application data,
such as STREAM frames. Though this depends to some degree on details
of the application protocol, some control is possible in many
protocol usage contexts. As the attacker has access to packet
protection keys, they are likely to be capable of predicting how a
peer will encrypt future packets. Successful control over datagram
content then only requires that the attacker be able to predict the
packet number and placement of frames in packets with some amount of
reliability.
This section assumes that limiting control over datagram content is
not feasible. The focus of the mitigations in subsequent sections is
on limiting the ways in which datagrams that are sent prior to
address validation can be used for request forgery.
Request Forgery with Client Initial Packets
``````````````````````````````````````````````
An attacker acting as a server can choose the IP address and port on
which it advertises its availability, so Initial packets from clients
are assumed to be available for use in this sort of attack. The
address validation implicit in the handshake ensures that -- for a
new connection -- a client will not send other types of packets to a
destination that does not understand QUIC or is not willing to accept
a QUIC connection.
Initial packet protection (Section 5.2 of [QUIC-TLS]) makes it
difficult for servers to control the content of Initial packets sent
by clients. A client choosing an unpredictable Destination
Connection ID ensures that servers are unable to control any of the
encrypted portion of Initial packets from clients.
However, the Token field is open to server control and does allow a
server to use clients to mount request forgery attacks. The use of
tokens provided with the NEW_TOKEN frame (Section 8.1.3) offers the
only option for request forgery during connection establishment.
Clients, however, are not obligated to use the NEW_TOKEN frame.
Request forgery attacks that rely on the Token field can be avoided
if clients send an empty Token field when the server address has
changed from when the NEW_TOKEN frame was received.
Clients could avoid using NEW_TOKEN if the server address changes.
However, not including a Token field could adversely affect
performance. Servers could rely on NEW_TOKEN to enable the sending
of data in excess of the three-times limit on sending data; see
Section 8.1. In particular, this affects cases where clients use
0-RTT to request data from servers.
Sending a Retry packet (Section 17.2.5) offers a server the option to
change the Token field. After sending a Retry, the server can also
control the Destination Connection ID field of subsequent Initial
packets from the client. This also might allow indirect control over
the encrypted content of Initial packets. However, the exchange of a
Retry packet validates the server's address, thereby preventing the
use of subsequent Initial packets for request forgery.
Request Forgery with Preferred Addresses
``````````````````````````````````````````````
Servers can specify a preferred address, which clients then migrate
to after confirming the handshake; see Section 9.6. The Destination
Connection ID field of packets that the client sends to a preferred
address can be used for request forgery.
A client MUST NOT send non-probing frames to a preferred address
prior to validating that address; see Section 8. This greatly
reduces the options that a server has to control the encrypted
portion of datagrams.
This document does not offer any additional countermeasures that are
specific to the use of preferred addresses and can be implemented by
endpoints. The generic measures described in Section 21.5.6 could be
used as further mitigation.
Request Forgery with Spoofed Migration
``````````````````````````````````````````
Clients are able to present a spoofed source address as part of an
apparent connection migration to cause a server to send datagrams to
that address.
The Destination Connection ID field in any packets that a server
subsequently sends to this spoofed address can be used for request
forgery. A client might also be able to influence the ciphertext.
A server that only sends probing packets (Section 9.1) to an address
prior to address validation provides an attacker with only limited
control over the encrypted portion of datagrams. However,
particularly for NAT rebinding, this can adversely affect
performance. If the server sends frames carrying application data,
an attacker might be able to control most of the content of
datagrams.
This document does not offer specific countermeasures that can be
implemented by endpoints, aside from the generic measures described
in Section 21.5.6. However, countermeasures for address spoofing at
the network level -- in particular, ingress filtering [BCP38] -- are
especially effective against attacks that use spoofing and originate
from an external network.
Request Forgery with Version Negotiation
`````````````````````````````````````````````````````
Clients that are able to present a spoofed source address on a packet
can cause a server to send a Version Negotiation packet
(Section 17.2.1) to that address.
The absence of size restrictions on the connection ID fields for
packets of an unknown version increases the amount of data that the
client controls from the resulting datagram. The first byte of this
packet is not under client control and the next four bytes are zero,
but the client is able to control up to 512 bytes starting from the
fifth byte.
No specific countermeasures are provided for this attack, though
generic protections (Section 21.5.6) could apply. In this case,
ingress filtering [BCP38] is also effective.
Generic Request Forgery Countermeasures
`````````````````````````````````````````````````````
The most effective defense against request forgery attacks is to
modify vulnerable services to use strong authentication. However,
this is not always something that is within the control of a QUIC
deployment. This section outlines some other steps that QUIC
endpoints could take unilaterally. These additional steps are all
discretionary because, depending on circumstances, they could
interfere with or prevent legitimate uses.
Services offered over loopback interfaces often lack proper
authentication. Endpoints MAY prevent connection attempts or
migration to a loopback address. Endpoints SHOULD NOT allow
connections or migration to a loopback address if the same service
was previously available at a different interface or if the address
was provided by a service at a non-loopback address. Endpoints that
depend on these capabilities could offer an option to disable these
protections.
Similarly, endpoints could regard a change in address to a link-local
address [RFC4291] or an address in a private-use range [RFC1918] from
a global, unique-local [RFC4193], or non-private address as a
potential attempt at request forgery. Endpoints could refuse to use
these addresses entirely, but that carries a significant risk of
interfering with legitimate uses. Endpoints SHOULD NOT refuse to use
an address unless they have specific knowledge about the network
indicating that sending datagrams to unvalidated addresses in a given
range is not safe.
Endpoints MAY choose to reduce the risk of request forgery by not
including values from NEW_TOKEN frames in Initial packets or by only
sending probing frames in packets prior to completing address
validation. Note that this does not prevent an attacker from using
the Destination Connection ID field for an attack.
Endpoints are not expected to have specific information about the
location of servers that could be vulnerable targets of a request
forgery attack. However, it might be possible over time to identify
specific UDP ports that are common targets of attacks or particular
patterns in datagrams that are used for attacks. Endpoints MAY
choose to avoid sending datagrams to these ports or not send
datagrams that match these patterns prior to validating the
destination address. Endpoints MAY retire connection IDs containing
patterns known to be problematic without using them.
Note: Modifying endpoints to apply these protections is more
efficient than deploying network-based protections, as
endpoints do not need to perform any additional processing when
sending to an address that has been validated.
Slowloris Attacks
`````````````````````````````````````````````````````
The attacks commonly known as Slowloris [SLOWLORIS] try to keep many
connections to the target endpoint open and hold them open as long as
possible. These attacks can be executed against a QUIC endpoint by
generating the minimum amount of activity necessary to avoid being
closed for inactivity. This might involve sending small amounts of
data, gradually opening flow control windows in order to control the
sender rate, or manufacturing ACK frames that simulate a high loss
rate.
QUIC deployments SHOULD provide mitigations for the Slowloris
attacks, such as increasing the maximum number of clients the server
will allow, limiting the number of connections a single IP address is
allowed to make, imposing restrictions on the minimum transfer speed
a connection is allowed to have, and restricting the length of time
an endpoint is allowed to stay connected.
Stream Fragmentation and Reassembly Attacks
`````````````````````````````````````````````````````
An adversarial sender might intentionally not send portions of the
stream data, causing the receiver to commit resources for the unsent
data. This could cause a disproportionate receive buffer memory
commitment and/or the creation of a large and inefficient data
structure at the receiver.
An adversarial receiver might intentionally not acknowledge packets
containing stream data in an attempt to force the sender to store the
unacknowledged stream data for retransmission.
The attack on receivers is mitigated if flow control windows
correspond to available memory. However, some receivers will
overcommit memory and advertise flow control offsets in the aggregate
that exceed actual available memory. The overcommitment strategy can
lead to better performance when endpoints are well behaved, but
renders endpoints vulnerable to the stream fragmentation attack.
QUIC deployments SHOULD provide mitigations for stream fragmentation
attacks. Mitigations could consist of avoiding overcommitting
memory, limiting the size of tracking data structures, delaying
reassembly of STREAM frames, implementing heuristics based on the age
and duration of reassembly holes, or some combination of these.
Stream Commitment Attack
`````````````````````````````````````````````````````
An adversarial endpoint can open a large number of streams,
exhausting state on an endpoint. The adversarial endpoint could
repeat the process on a large number of connections, in a manner
similar to SYN flooding attacks in TCP.
Normally, clients will open streams sequentially, as explained in
Section 2.1. However, when several streams are initiated at short
intervals, loss or reordering can cause STREAM frames that open
streams to be received out of sequence. On receiving a higher-
numbered stream ID, a receiver is required to open all intervening
streams of the same type; see Section 3.2. Thus, on a new
connection, opening stream 4000000 opens 1 million and 1 client-
initiated bidirectional streams.
The number of active streams is limited by the
initial_max_streams_bidi and initial_max_streams_uni transport
parameters as updated by any received MAX_STREAMS frames, as
explained in Section 4.6. If chosen judiciously, these limits
mitigate the effect of the stream commitment attack. However,
setting the limit too low could affect performance when applications
expect to open a large number of streams.
Peer Denial of Service
`````````````````````````````````````````````````````
QUIC and TLS both contain frames or messages that have legitimate
uses in some contexts, but these frames or messages can be abused to
cause a peer to expend processing resources without having any
observable impact on the state of the connection.
Messages can also be used to change and revert state in small or
inconsequential ways, such as by sending small increments to flow
control limits.
If processing costs are disproportionately large in comparison to
bandwidth consumption or effect on state, then this could allow a
malicious peer to exhaust processing capacity.
While there are legitimate uses for all messages, implementations
SHOULD track cost of processing relative to progress and treat
excessive quantities of any non-productive packets as indicative of
an attack. Endpoints MAY respond to this condition with a connection
error or by dropping packets.
Explicit Congestion Notification Attacks
`````````````````````````````````````````````````````
An on-path attacker could manipulate the value of ECN fields in the
IP header to influence the sender's rate. [RFC3168] discusses
manipulations and their effects in more detail.
A limited on-path attacker can duplicate and send packets with
modified ECN fields to affect the sender's rate. If duplicate
packets are discarded by a receiver, an attacker will need to race
the duplicate packet against the original to be successful in this
attack. Therefore, QUIC endpoints ignore the ECN field in an IP
packet unless at least one QUIC packet in that IP packet is
successfully processed; see Section 13.4.
Stateless Reset Oracle
`````````````````````````````````````````````````````
Stateless resets create a possible denial-of-service attack analogous
to a TCP reset injection. This attack is possible if an attacker is
able to cause a stateless reset token to be generated for a
connection with a selected connection ID. An attacker that can cause
this token to be generated can reset an active connection with the
same connection ID.
If a packet can be routed to different instances that share a static
key -- for example, by changing an IP address or port -- then an
attacker can cause the server to send a stateless reset. To defend
against this style of denial of service, endpoints that share a
static key for stateless resets (see Section 10.3.2) MUST be arranged
so that packets with a given connection ID always arrive at an
instance that has connection state, unless that connection is no
longer active.
More generally, servers MUST NOT generate a stateless reset if a
connection with the corresponding connection ID could be active on
any endpoint using the same static key.
In the case of a cluster that uses dynamic load balancing, it is
possible that a change in load-balancer configuration could occur
while an active instance retains connection state. Even if an
instance retains connection state, the change in routing and
resulting stateless reset will result in the connection being
terminated. If there is no chance of the packet being routed to the
correct instance, it is better to send a stateless reset than wait
for the connection to time out. However, this is acceptable only if
the routing cannot be influenced by an attacker.
Version Downgrade
`````````````````````````````````````````````````````
This document defines QUIC Version Negotiation packets (Section 6),
which can be used to negotiate the QUIC version used between two
endpoints. However, this document does not specify how this
negotiation will be performed between this version and subsequent
future versions. In particular, Version Negotiation packets do not
contain any mechanism to prevent version downgrade attacks. Future
versions of QUIC that use Version Negotiation packets MUST define a
mechanism that is robust against version downgrade attacks.
Targeted Attacks by Routing
`````````````````````````````````````````````````````
Deployments should limit the ability of an attacker to target a new
connection to a particular server instance. Ideally, routing
decisions are made independently of client-selected values, including
addresses. Once an instance is selected, a connection ID can be
selected so that later packets are routed to the same instance.
Traffic Analysis
`````````````````````````````````````````````````````
The length of QUIC packets can reveal information about the length of
the content of those packets. The PADDING frame is provided so that
endpoints have some ability to obscure the length of packet content;
see Section 19.1.
Defeating traffic analysis is challenging and the subject of active
research. Length is not the only way that information might leak.
Endpoints might also reveal sensitive information through other side
channels, such as the timing of packets.
Relay Security
----------------
Following is an analysis of Relay Request, Relay Response, Relay Intro, and Hole Punch.
Constraints: It is important that Relays be fast.
Round trips should be minimized.
Bandwidth and CPU are not as important.
SSU 1:
Alice first connects to introducer Bob, who relays the request to Charlie (who is firewalled).
After the hole punch, the session is established between Alice and Charlie as in a direct establishment.
.. raw:: html
{% highlight %}
Alice Bob Charlie
1. RelayRequest ---------------------->
2. <-------------- RelayResponse RelayIntro ----------->
3. <-------------------------------------------- HolePunch
4. SessionRequest -------------------------------------------->
5. <-------------------------------------------- SessionCreated
6. SessionConfirmed ------------------------------------------>
{% endhighlight %}
Authentication: Relay Request and Relay Response are not securely unauthenticated,
as Alice and Bob usually do not have an existing session;
these messages use published intro keys.
In-session Relay Request/Response is allowed and preferred if a session does exist.
Relay Intro from Bob to Charlie is required to be in an existing session,
so it is presumed secure.
Bob may spoof Relay Intros or change IP/port from the Relay Request.
There are no mechanisms to cryptographically bind requests to intros or
otherwise prevent or detect malicious Bobs.
Bob's router hash is not currently published in Charlie's Router Info, so
that must be added if we want the Alice-Bob messages to be authenticated.
Additionally, other SSU2 parameters would have to be published in Charlie's Router Info,
or Alice would have to lookup Bob's Router Info in the network database,
adding additional delay.
Authentication would add a round-trip between Alice and Bob.
By forwarding Alice's router hash to Charlie, Charlie could more easily
determine if he wishes to receive a connection from Alice,
by checking a local ban list.
There is no mechanism for Charlie to reject the relay by sending
a rejection through Bob to Alice.
There is no mechanism for Charlie to accept the relay by sending
an acceptance through Bob to Alice. Alice must wait for the HolePunch,
or simply send the SessionRequest blindly. The HolePunch may come from
a different port than Alice was expecting, due to NAT, which
may make it harder to recognize what router the HolePunch came from.
Alice could send her full Router Info in the Relay Request to Bob,
and forwarded to Charlie in the Relay Intro.
The Relay Request does not contain a timestamp, so it has no replay prevention.
The source IP can be spoofed, to cause Charlie to send a Hole Punch to any IP/port.
The Relay Request is not signed, and even if signed and timestamped,
Charlie does not have the full Router Identity to be able to verify the signature.
The protocol defines a challenge field of variable length 0-255 bytes.
The challenge in the Relay Request is passed to Charlie in the Relay Intro.
However, the protocol does not specify how to create, use, or verify the challenge,
and it is unimplemented.
If the HolePunch contained the challenge, Alice would be able to easily
correlate the HolePunch with Charlie.
Four byte nonce may need to be replaced or supplemented by
8-byte connection ID.
Peer Test Security
---------------------
Following is an analysis of Peer Test.
Constraints: It is not particularly important that Peer Tests be fast,
or low-bandwidth, or low-CPU, except perhaps at router startup,
where we prefer that the router discovers its reachability fairly quickly.
SSU 1:
.. raw:: html
{% highlight %}
Alice Bob Charlie
1. PeerTest ------------------->
2. PeerTest-------------------->
3. <-------------------PeerTest
4. <-------------------PeerTest
5. <------------------------------------------PeerTest
6. PeerTest------------------------------------------>
7. <------------------------------------------PeerTest
{% endhighlight %}
Authentication:
As of 0.9.15, Alice will always choose a Bob with an existing session.
The protocol also permits Bob's introKey if Alice and Bob do not have an established session,
but in the current implementation Alice always selects a Bob that is established.
As of release 0.9.15, Bob will reject PeerTests from peers without an established session.
Message 1 is sent in-session. Therefore, message 1 is secure and authenticated.
Bob selects a Charlie with whom he has an existing session.
Messages 2 and 3 are sent in-session. Therefore, messages 2 and 3 are secure and authenticated.
Message 4 should be sent in-session; however, the SSU 1 specification says that it is sent
with Alice's published intro key, which means not in-session.
Java I2P does send with the intro key, matching the specification.
This is fixable and should be fixed in SSU 1.
Alice must not have an existing session with Charlie for the test to proceed;
Alice aborts the test if Bob picks a Charlie that has a sesssion with Alice.
Therefore, messages 5-7 are not secure and authenticated.
All Peer Test messages contain a 4-byte nonce that is chosen by Alice.
This nonce is not used cryptographically.
Attacks possible on messages 5-7: to be researched.
Alice's router hash is not known to Charlie.
Charlie's router hash is not known to Alice.
Those must be added to the protocol if we want thoe Alice-Charlie messages to be authenticated.
Additionally, other SSU2 parameters would have to be provided in the Peer Test messages,
or Charlie would have to lookup Alice's Router Info in the network database,
adding additional delay.
Authentication would add a round-trip between Charlie and Alice.
By forwarding Alice's router hash to Charlie, Charlie could more easily
determine if he wishes to participate in a Peer Test with Alice,
by checking a local ban list.
Four byte nonce may need to be replaced or supplemented by
8-byte connection ID.
Relay and Peer Test Design Goals
---------------------------------
Relay and Peer Test have similar constructions.
In both cases, Alice requests Bob to forward a service request to Charlie,
and Charlie then acts on that request.
We have the following goals in improving the security of Relay and Peer Test:
- Protect against address spoofing or on-path threats that may
spoof, alter, forge, or replay requests from Alice to Bob.
Bob must ensure that Alice is an actual I2P router and that the
request and test address presented are valid.
- Protect against malicious Bobs that may spoof, alter, forge, or replay
requests forwarded to Charlie.
Charlie must ensure that both Alice and Bob are actual I2P routers and that the
request and test address presented are valid.
- Bob must receive enough information from Alice to be able to validate
the request and then accept or decline it.
Bob must have a mechanism to send the acception or rejection back
to Alice.
Bob must never be required to perform the requested action.
- Charlie must receive enough information from Bob to be able to validate
the request and then accept or decline it.
Charlie must have a mechanism to send the acception or rejection back
to Bob, to be forwarded to Alice.
Charlie must never be required to perform the requested action.
- Alice must be able to validate that the response forwarded via Bob
actually originated from Charlie.
- Alice and Charlie must be able to validate that their subsequent direct
messages (not relayed via Bob) are from the expected source
and are actual I2P routers.
The following mechanisms may assist in achieving these goals:
- Timestamps
- Signatures using the router signing key
- Using challenge data included in the request
- Encryption using the router encryption key
- Sending router hashes, Router Identities, or Router Infos,
not just IPs and ports.
- Validation of router information by querying the network database
- Checking router information, IPs, and ports against banlists
- Rate limiting
- Requiring session establishment
These possible mechanisms may increase the processing time and latency of
the Relay or Peer Test functions. All effects must be evaluated.
Cross-version relaying and peer testing should also be supported if possible.
This will facilitate a gradual transition from SSU 1 to SSU 2.
The possible version combinations are:
========= =========== ============= =============
Alice/Bob Bob/Charlie Alice/Charlie Supported
========= =========== ============= =============
1 1 2 no, use 1/1/1
1 2 1 yes?
1 2 2 no, use 1/2/1
2 1 2 yes?
2 2 1 no, use 2/2/2
2 2 2 yes
========= =========== ============= =============
Design Overview
====================
Summary
--------
We rely on several existing protocols, both within I2P and outside standards,
for inspiration, guidance, and code reuse:
* Threat models: From NTCP2 [NTCP2]_, with significant additional threats
relevant to UDP transport as analyzed by QUIC [RFC-9000]_ [RFC-9001]_.
* Cryptographic choices: From [NTCP2]_.
* Handshake: Noise XK from [NTCP2]_ and [NOISE]_. Significant simplifications
to NTCP2 are possible due to the encapsulation (inherent message boundaries)
provided by UDP.
* Handshake ephemeral key obfuscation: Adapted from [NTCP2]_
* Packet headers: Adapted from WireGuard [WireGuard]_ and QUIC [RFC-9000]_ [RFC-9001]_.
* Packet header obfuscation: Adapted from [NTCP2]_
* Packet header protection: Adapted from QUIC [RFC-9001]_ and [Nonces]_
* Headers used as AEAD associated data as in [ECIES]_.
* Packet numbering: Adapted from WireGuard [WireGuard]_ and QUIC [RFC-9000]_ [RFC-9001]_.
* Messages: Adapted from [SSU]_
* I2NP Fragmentation: Adapted from [SSU]_
* Relay and Peer Testing: Adapted from [SSU]_
* Block format: From [NTCP2]_ and [ECIES]_.
* Padding and options: From [NTCP2]_ and [ECIES]_.
* Flow control, acks, nacks: TBD
Delivery Guarantees
----------------------
As with other I2P transports NTCP, NTCP2, and SSU 1, this transport is not a general-purpose
facility for delivery of an in-order stream of bytes. It is designed for
transport of I2NP messages. There is no "stream" abstraction provided.
In addition, as for SSU, it contains additional facilities for peer-facilitated NAT traversal
and testing of reachability (inbound connections).
As for SSU 1, it does NOT provide in-order delivery of I2NP messages.
Nor does it provide guaranteed delivery of I2NP messages.
For efficiency, or because of out-of order delivery of UDP datagrams
or loss of those datagrams, I2NP messages may be delivered to the
far-end out-of-order, or may not be delivered at all.
An I2NP message may be retransmitted multiple times if necessary,
but delivery may eventually fail without causing the full connection to be
disconnected. Also, new I2NP messages may continue to be sent even
while retransmission (loss recovery) is occurring for other I2NP messages.
Noise Protocol Framework
-------------------------
This proposal provides the requirements based on the Noise Protocol Framework
[NOISE]_ (Revision 33, 2017-10-04).
Noise has similar properties to the Station-To-Station protocol
[STS]_, which is the basis for the [SSU]_ protocol. In Noise parlance, Alice
is the initiator, and Bob is the responder.
SSU2 is based on the Noise protocol Noise_XK_25519_ChaChaPoly_SHA256.
(The actual identifier for the initial key derivation function
is "Noise_XKaesobfse+hs1+hs2+hs3_25519_ChaChaPoly_SHA256"
to indicate I2P extensions - see KDF 1 section below)
NOTE: This identifier is different than that used for NTCP2, because
all three handshake messages use the header as associated data.
This Noise protocol uses the following primitives:
- Handshake Pattern: XK
Alice transmits her key to Bob (X)
Alice knows Bob's static key already (K)
- DH Function: X25519
X25519 DH with a key length of 32 bytes as specified in [RFC-7748]_.
- Cipher Function: ChaChaPoly
AEAD_CHACHA20_POLY1305 as specified in [RFC-7539]_ section 2.8.
12 byte nonce, with the first 4 bytes set to zero.
- Hash Function: SHA256
Standard 32-byte hash, already used extensively in I2P.
Additions to the Framework
-------------------------------
This proposal defines the following enhancements to
Noise_XK_25519_ChaChaPoly_SHA256. These generally follow the guidelines in
[NOISE]_ section 13.
1) Cleartext ephemeral keys are obfuscated with AES encryption using a known
key and IV. This is quicker than elligator2.
New Cryptographic Primitives for I2P
---------------------------------------
None?
Investigate other hash functions to replace SHA256.
Processing overhead estimate
-----------------------------------
TBD
Definitions
===============
We define the following functions corresponding to the cryptographic building blocks used.
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]_.
|| 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]_.
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]_, using the HMAC hash function SHA-256
as specified in [RFC-2104]_. 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]_.
Use HKDF as follows::
MixKey(d) := output = HKDF(chainKey, d, "", 64)
chainKey = output[0:31]
k = output[32:63]
Messages
========
Each UDP datagram contains exactly one message.
The length of the datagram (after the IP header) is the length of the message.
Padding, if any, is contained in a padding block inside the message.
In this document, we use the terms "datagram" and "packet" mostly interchangeably.
Each datagram (or packet) contains a single message (unlike QUIC, where
a datagram may contain multiple QUIC packets).
The "packet header" is the part after the IP/UDP header.
All SSU2 messages are less than or equal to TBD bytes in length. The message
format is based on Noise messages, with modifications for framing and indistinguishability.
Implementations using standard Noise libraries may need to pre-process received
messages to/from the Noise message format. All encrypted fields are AEAD
ciphertexts.
The following messages are defined:
==== ================ =====
Type Message Notes
==== ================ =====
0 SessionRequest
1 SessionCreated
2 SessionConfirmed
3 RelayRequest TBD may be a block
4 RelayResponse TBD may be a block
5 RelayIntro NO, block only
6 Data
7 PeerTest TBD may be a block
8 SessionDestroyed NO, block only??
9 Retry
n/a HolePunch
==== ================ =====
Session Establishment
-----------------------
The standard establishment sequence is as follows:
.. raw:: html
{% highlight %}
Alice Bob
SessionRequest ------------------->
<------------------- SessionCreated
SessionConfirmed ----------------->
{% endhighlight %}
When address verification is used, the establishment sequence is as follows:
.. raw:: html
{% highlight %}
Alice Bob
SessionRequest ------------------->
<--------------------------- Retry
SessionRequest ------------------->
<------------------- SessionCreated
SessionConfirmed ----------------->
{% endhighlight %}
Using Noise terminology, the establishment and data sequence is as follows:
(Payload Security Properties)
.. raw:: html
{% highlight lang='text' %}
XK(s, rs): Authentication Confidentiality
<- s
...
-> e, es 0 2
<- e, ee 2 1
-> s, se 2 5
<- 2 5
{% endhighlight %}
Once a session has been established, Alice and Bob can exchange Data messages.
Some notations::
- RH_A = Router Hash for Alice (32 bytes)
- RH_B = Router Hash for Bob (32 bytes)
Packet Header
---------------
All packets start with an obfuscated header.
There are two header types, long and short.
Long Header
`````````````
The long header is 32 bytes. It is used before a session is created, for SessionRequest, SessionCreated, and Retry.
Note that the first 9 bytes (Destination Connection ID and type) are the same for both headers.
Before header obfuscation and protection:
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| Destination Connection ID |
+----+----+----+----+----+----+----+----+
| Packet Number |type| ver| id |flag|
+----+----+----+----+----+----+----+----+
| Source Connection ID |
+----+----+----+----+----+----+----+----+
| Token |
+----+----+----+----+----+----+----+----+
Destination Connection ID :: 8 bytes, unsigned big endian integer
type :: The message type, 0-255
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
Packet Number :: 4 bytes, unsigned big endian integer
Source Connection ID :: 8 bytes, unsigned big endian integer
Token :: 8 bytes, unsigned big endian integer
{% endhighlight %}
Short Header
`````````````
The short header is 16 bytes. It is used after a session is created, for Data messages.
or (maybe?) for unauthenticated messages.
16 bytes is required, because
the receiver must decrypt the first 16 bytes to get the message type,
and then must decrypt an additional 16 bytes if it's actually a long header,
as indicated by the message type.
Before header obfuscation and protection:
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| Destination Connection ID |
+----+----+----+----+----+----+----+----+
| Packet Number |type| flags |
+----+----+----+----+----+----+----+----+
Destination Connection ID :: 8 bytes, unsigned big endian integer
Packet Number :: 4 bytes, unsigned big endian integer
type :: The message type, 0-10
flags :: 3 bytes, unused, set to 0 for future compatibility
{% endhighlight %}
Note: If any out-of-session relay or peer test messages are defined
and used, we must also have the ver and id fields present.
Connection ID Numbering
```````````````````````````
Random numbers
TBD change during handshake like QUIC?
Packet Numbering
`````````````````
Packets are numbered within a single session, for each direction, starting from 0, to a max of (2**32 -1).
A session must be terminated, and a new session created, well before the max
number of packets is sent.
TODO key rotation, reduce max packet number?
Packets that are determined to be lost are not retransmitted
whole. The same applies to the blocks that are contained within lost
packets. Instead, the information that might be carried in blocks is
sent again in new packets as needed.
New packets are used to carry information that is
determined to have been lost. In general, information is sent again
when a packet containing that information is determined to be lost,
and sending ceases when a packet containing that information is remain the same)
acknowledged.
Packets are never retransmitted with the same packet number.
Any retransmission of packet contents (whether or not the contents remain the same)
must use the next unused packet number.
Packet numbering starts with Session Request. Assuming no retransmissions
in the handshake, and no Retry reply from Bob, the packet numbers
in an example standard handshake will be:
.. raw:: html
{% highlight %}
Alice Bob
SessionRequest (0) ------------>
<------------- SessionCreated (0)
SessionConfirmed (1) ------------>
Data (2) ------------>
<------------- Data (1)
Data (3) ------------>
Data (4) ------------>
Data (5) ------------>
<------------- Data (2)
{% endhighlight %}
Any retransmission of handshake messages
(SessionRequest, SessionCreated, or SessionConfirmed)
must be resent unchanged, except for incrementing the packet number.
Do not use different ephemeral keys or change the payload
when retransmitting these messages.
Header Binding
````````````````
The header (before obfuscation and protection) is always included in the associated
data for the AEAD function, to cryptographically bind the header to the data.
Header Obfuscation
```````````````````
Both the long and short headers are always obfuscated with AES-CBC using
(generally) the destination router hash and IV.
For SessionCreated, where the destination router hash and IV are not yet known,
the source router hash and IV are used.
TODO ChaCha20 instead?
Header Protection
```````````````````
In addition to obfuscation, bytes 8-15 of the long header and bytes 8-12 of the short header
are encrypted by XORing with a known key, as in QUIC [RFC-9001]_ and [Nonces]_.
For SessionCreated, where the destination router hash and IV are not yet known,
the source router hash and IV are used.
There are four header protection key phases:
- Session Request
- Session Created and Retry
- Session Confirmed
- Data Phase
See the individual KDF sections below for the derivation of the header protection key for that phase.
Header Protection KDF:
.. raw:: html
{% highlight lang='dataspec' %}
// incoming encrypted packet
len = packet.length
// take the last 16 bytes before the MAC
sample = packet[len-32:len-17]
n = sample[4:15]
key = header protection key
data = {0, 0, 0, 0, 0, 0, 0, 0}
mask = ChaCha20.encrypt(key, n, data)
// encrypt the header by XORing with the mask
// short header
header[8:12] ^= mask[0:4]
// long header
header[8:15] ^= mask[0:7]
{% endhighlight %}
Header Validation
```````````````````
After decrypting the first 16 bytes of the header,
the receiver will know the Destination Session ID. From there,
the receiver knows what header protection keys to use based on the key phase of the session.
Removing the header protection will then reveal the message type and be able to determine
if it is a short or long header.
If it is a long header, the receiver must validate the version and netid fields.
If the version is != 2, or the netid is != the expected value (generally 2, except in test networks),
the receiver should drop the message.
In limited situations (after sending a Session Request but before receiving a Session Created),
the receiver should retry header protection with a different key, to check for a Retry message.
Authenticated Encryption
------------------------
There are three separate authenticated encryption instances (CipherStates).
One during the handshake phase, and two (transmit and receive) for the data phase.
Each has its own key from a KDF.
Encrypted/authenticated data will be represented as
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| |
+ +
| Encrypted and authenticated data |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
{% endhighlight %}
ChaCha20/Poly1305
`````````````````
Encrypted and authenticated data format.
Inputs to the encryption/decryption functions:
.. raw:: html
{% highlight lang='dataspec' %}
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
data :: Plaintext data, 0 or more bytes
{% endhighlight %}
Output of the encryption function, input to the decryption function:
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| |
+ +
| 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
{% endhighlight %}
For ChaCha20, what is described here corresponds to [RFC-7539]_, which is also
used similarly in TLS [RFC-7905]_.
Notes
`````
- Since ChaCha20 is a stream cipher, plaintexts need not be padded.
Additional keystream bytes are discarded.
- The key for the cipher (256 bits) is agreed upon by means of the SHA256 KDF.
The details of the KDF for each message are in separate sections below.
AEAD Error Handling
```````````````````
- In all messages, the AEAD message size is known in advance.
On an AEAD authentication failure, recipient must halt further message processing and
discard the message.
- Bob should maintain a blacklist of IPs with
repeated failures.
KDF for Session Request
-------------------------------------------------------
The Key Derivation Function (KDF) generates a handshake phase cipher key k from the DH result,
using HMAC-SHA256(key, data) as defined in [RFC-2104]_.
These are the InitializeSymmetric(), MixHash(), and MixKey() functions,
exactly as defined in the Noise spec.
KDF for Initial ChainKey
````````````````````````
.. raw:: html
{% highlight lang='text' %}
// Define protocol_name.
Set protocol_name = "Noise_XKaesobfse+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
Define rs = Bob's 32-byte static key as published in the RouterInfo
// 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);
// up until here, can all be precalculated by Bob for all incoming connections
{% endhighlight %}
KDF for Session Request
`````````````````````````
.. raw:: html
{% highlight lang='text' %}
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:64]
n = 0
ad = h
ciphertext = ENCRYPT(k, n, payload, ad)
// retain the chainKey for Session Created KDF
End of "es" message pattern.
// Header protection key
TBD
{% endhighlight %}
SessionRequest (Type 0)
------------------------
Alice sends to Bob.
Long header.
Noise content: Alice's ephemeral key X
Noise payload: datetime and padding blocks
Max payload size: MTU - 108 (IPv4) or MTU - 128 (IPv6)
For 1280 MTU: Max payload is 1172 (IPv4) or 1152 (IPv6)
For 1500 MTU: Max payload is 1392 (IPv4) or 1372 (IPv6)
Payload Security Properties:
.. raw:: html
{% highlight lang='text' %}
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.
{% endhighlight %}
The X value is encrypted to ensure payload indistinguishably
and uniqueness, which are necessary DPI countermeasures.
We use AES encryption to achieve this,
rather than more complex and slower alternatives such as elligator2.
Asymmetric encryption to Bob's router public key would be far too slow.
AES encryption uses Bob's router hash as the key and Bob's IV as published
in the network database.
AES encryption is for DPI resistance only.
Any party knowing Bob's router hash, and IV, which are published in the network database,
may decrypt the X value in this message.
Raw contents:
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| |
+ obfuscated with RH_B +
| AES-CBC-256 encrypted |
+ bytes 8-15 header protected +
| Long Header |
+ (32 bytes) +
| |
+----+----+----+----+----+----+----+----+
| |
+ obfuscated with RH_B +
| AES-CBC-256 encrypted X |
+ (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, AES-256-CBC encrypted X25519 ephemeral key, little endian
key: RH_B
iv: As published in Bobs network database entry
{% endhighlight %}
Unencrypted data (Poly1305 authentication tag not shown):
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| Destination Connection ID |
+----+----+----+----+----+----+----+----+
| Packet Number |type| ver| id |flag|
+----+----+----+----+----+----+----+----+
| Source Connection ID |
+----+----+----+----+----+----+----+----+
| Token |
+----+----+----+----+----+----+----+----+
| |
+ +
| X |
+ (32 bytes) +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| Noise payload (block data) |
+ (length varies) +
| |
+----+----+----+----+----+----+----+----+
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 :: 0 unless retransmitted or resent after Retry
Source Connection ID :: Randomly generated by Alice
Token :: 0 if not previously received from Bob
X :: 32 bytes, X25519 ephemeral key, little endian
{% endhighlight %}
Notes
`````
- When the published address is "NTCP", Bob supports both NTCP and SSU2 on the
same port. For compatibility, when initiating a connection to an address
published as "NTCP", Alice must limit the maximum size of this message,
including padding, to 287 bytes or less. This facilitates automatic protocol
identification by Bob. When published as "SSU2", there is no size
restriction. See the Published Addresses and Version Detection sections
below.
- The unique X value in the initial AES block ensure that the ciphertext is
different for every session.
- Bob must reject connections where the timestamp value is too far off from the
current time. Call the maximum delta time "D". Bob must maintain a local
cache of previously-used handshake values and reject duplicates, to prevent
replay attacks. Values in the cache must have a lifetime of at least 2*D.
The cache values are implementation-dependent, however the 32-byte X value
(or its encrypted equivalent) may be used.
- Diffie-Hellman ephemeral keys may never be reused, to prevent cryptographic attacks,
and reuse will be rejected as a replay attack.
- The "KE" and "auth" options must be compatible, i.e. the shared secret K must
be of the appropriate size. If more "auth" options are added, this could
implicitly change the meaning of the "KE" flag to use a different KDF or a
different truncation size.
- Bob must validate that Alice's ephemeral key is a valid point on the curve
here.
- Padding should be limited to a reasonable amount. Bob may reject connections
with excessive padding. Bob will specify his padding options in Session Created.
Min/max guidelines TBD. Random size from 0 to 31 bytes minimum?
(Distribution to be determined, see Appendix A.)
TODO UNLESS minimum packet size is enforced for PMTU.
- On any error, including AEAD, DH, timestamp, apparent replay, or key
validation failure, Bob must halt further message processing and
drop the message without responding.
- DoS Mitigation: DH is a relatively expensive operation. As with the previous NTCP protocol,
routers should take all necessary measures to prevent CPU or connection exhaustion.
Place limits on maximum active connections and maximum connection setups in progress.
Enforce read timeouts (both per-read and total for "slowloris").
Limit repeated or simultaneous connections from the same source.
Maintain blacklists for sources that repeatedly fail.
Do not respond to AEAD failure.
- "ver" field: The overall Noise protocol, extensions, and SSU2 protocol
including payload specifications, indicating SSU2.
This field may be used to indicate support for future changes.
- Bob must fail the connection if any incoming data remains after validating
Session Request and reading in the padding. There should be no extra data from Alice,
as Bob has not responded with Session Created yet.
- The network ID field is used to quickly identify cross-network connections.
If this field is nonzero, and does not match Bob's network ID,
Bob should disconnect and block future connections.
KDF for Session Created and Session Confirmed part 1
----------------------------------------------------------------------------------
.. raw:: html
{% highlight lang='text' %}
// take h saved from Session Request KDF
// MixHash(ciphertext)
h = SHA256(h || 32 byte encrypted 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:64]
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 protection key
TBD
{% endhighlight %}
SessionCreated (Type 1)
------------------------
Bob sends to Alice.
Noise content: Bob's ephemeral key Y
Noise payload: datetime, options, and padding blocks
Max payload size: MTU - 108 (IPv4) or MTU - 128 (IPv6)
For 1280 MTU: Max payload is 1172 (IPv4) or 1152 (IPv6)
For 1500 MTU: Max payload is 1392 (IPv4) or 1372 (IPv6)
Payload Security Properties:
.. raw:: html
{% highlight lang='text' %}
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.
{% endhighlight %}
The Y value is encrypted to ensure payload indistinguishably and uniqueness,
which are necessary DPI countermeasures. We use AES encryption to achieve
this, rather than more complex and slower alternatives such as elligator2.
Asymmetric encryption to Alice's router public key would be far too slow. AES
encryption uses Bob's router hash as the key and the AES state from Session Request
(which was initialized with Bob's IV as published in the network database).
AES encryption is for DPI resistance only. Any party knowing Bob's router hash
and IV, which are published in the network database, and captured the first 32
bytes of Session Request, may decrypt the Y value in this message.
Raw contents:
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| |
+ obfuscated with RH_B +
| AES-CBC-256 encrypted |
+ bytes 8-15 header protected +
| Long Header |
+ (32 bytes) +
| |
+----+----+----+----+----+----+----+----+
| |
+ obfuscated with RH_B +
| AES-CBC-256 encrypted Y |
+ (32 bytes) +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| 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, AES-256-CBC encrypted X25519 ephemeral key, little endian
key: RH_B
iv: Using AES state from Session Request
{% endhighlight %}
Unencrypted data (Poly1305 auth tag not shown):
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| Destination Connection ID |
+----+----+----+----+----+----+----+----+
| Packet Number |type| ver| id |flag|
+----+----+----+----+----+----+----+----+
| Source Connection ID |
+----+----+----+----+----+----+----+----+
| Token |
+----+----+----+----+----+----+----+----+
| |
+ +
| Y |
+ (32 bytes) +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| Noise payload (block data) |
+ (length varies) +
| |
+----+----+----+----+----+----+----+----+
Destination Connection ID :: As sent 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 :: 0 unless retransmitted or resent after Retry
Source Connection ID :: Randomly generated by Alice
Token :: 0 (unused)
Y :: 32 bytes, X25519 ephemeral key, little endian
{% endhighlight %}
Notes
`````
- Alice must validate that Bob's ephemeral key is a valid point on the curve
here.
- Padding should be limited to a reasonable amount.
Alice may reject connections with excessive padding.
Alice will specify her padding options in Session Confirmed.
Min/max guidelines TBD. Random size from 0 to 31 bytes minimum?
(Distribution to be determined, see Appendix A.)
TODO UNLESS minimum packet size is enforced for PMTU.
- On any error, including AEAD, DH, timestamp, apparent replay, or key
validation failure, Alice must halt further message processing and close the
connection without responding.
- Alice must fail the connection if any incoming data remains after validating
Session Created and reading in the padding. There should be no extra data from Bob,
as Alice has not responded with Session Confirmed yet.
- Alice must reject connections where the timestamp value is too far off from
the current time. Call the maximum delta time "D". Alice must maintain a
local cache of previously-used handshake values and reject duplicates, to
prevent replay attacks. Values in the cache must have a lifetime of at least
2*D. The cache values are implementation-dependent, however the 32-byte Y
value (or its encrypted equivalent) may be used.
Issues
``````
- Include min/max padding options here?
KDF for Session Confirmed part 1, using Session Created KDF
---------------------------------------------------------------------------
.. raw:: html
{% highlight lang='text' %}
// take h saved from Session Created KDF
// MixHash(ciphertext)
h = SHA256(h || 24 byte encrypted 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 protection key
TBD
{% endhighlight %}
KDF for Session Confirmed part 2
--------------------------------------------------------------
.. raw:: html
{% highlight lang='text' %}
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:64]
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 Additional Symmetric Key (SipHash) KDF
End of "se" message pattern.
{% endhighlight %}
SessionConfirmed (Type 2)
-----------------------------
Alice sends to Bob.
Noise content: Alice's static key
Noise payload part 1: None
Noise payload part 2: Alice's RouterInfo, options, data, and padding blocks
Max payload size: MTU - 108 (IPv4) or MTU - 128 (IPv6)
For 1280 MTU: Max payload is 1172 (IPv4) or 1152 (IPv6)
For 1500 MTU: Max payload is 1392 (IPv4) or 1372 (IPv6)
Payload Security Properties:
.. raw:: html
{% highlight lang='text' %}
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.
{% endhighlight %}
This contains two ChaChaPoly frames.
The first is Alice's encrypted static public key.
The second is the Noise payload: Alice's encrypted RouterInfo, optional
options, and optional padding. They use different keys, because the MixKey()
function is called in between.
Raw contents:
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
|Short Header obfuscated with dest hash |
+ encrypted, bytes 8-15 +
| header protected |
+----+----+----+----+----+----+----+----+
| 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 |
+ +
| Alice RouterInfo |
+ using block format 2 +
| Alice Options (optional) |
+ using block format 1 +
| Arbitrary padding |
+ using block format 254 +
| |
+ +
| 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
{% endhighlight %}
Unencrypted data (Poly1305 auth tags not shown):
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| Destination Connection ID |
+----+----+----+----+----+----+----+----+
| Packet Number |type| flags |
+----+----+----+----+----+----+----+----+
| |
+ +
| S |
+ Alice static key +
| (32 bytes) |
+ +
| |
+ +
+----+----+----+----+----+----+----+----+
| |
+ +
| Noise Payload |
+ (length varies) +
| |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
Destination Connection ID :: As sent in Session Request,
or one received in Session Confirmed?
Packet Number :: 1 unless retransmitted or resent after Retry
type :: 2
flags :: 3 bytes, unused, set to 0 for future compatibility
S :: 32 bytes, Alice's X25519 static key, little endian
{% endhighlight %}
Notes
`````
- Bob must perform the usual Router Info validation.
Ensure the signature type is supported, verify the signature,
verify the timestamp is within bounds, and any other checks necessary.
See below for notes on handling fragmented Router Infos.
- Bob must verify that Alice's static key received in the first frame matches
the static key in the Router Info. Bob must first search the Router Info for
a NTCP or SSU2 Router Address with a matching version (v) option.
See Published Router Info and Unpublished Router Info sections below.
See below for notes on handling fragmented Router Infos.
- If Bob has an older version of Alice's RouterInfo in his netdb, verify
that the static key in the router info is the same in both, if present,
and if the older version is less than XXX old (see key rotate time below)
- Bob must validate that Alice's static key is a valid point on the curve here.
- Options should be included, to specify padding parameters.
- On any error, including AEAD, RI, DH, timestamp, or key validation failure,
Bob must halt further message processing and close the connection without
responding.
- Message 3 part 2 frame content: This format of this frame is the same as the
format of data phase frames, except that the length of the frame is sent
by Alice in Session Request. See below for the data phase frame format.
The frame must contain 1 to 4 blocks in the following order:
1) Alice's Router Info block (required)
2) Options block (optional)
3) I2NP blocks (optional)
4) Padding block (optional)
This frame must never contain any other block type.
TODO: what about relay and peer test?
- Message 3 part 2 padding block is recommended.
- There may be no space, or only a small amount of space, available for
I2NP blocks, depending on the MTU and the Router Info size.
Do NOT include I2NP blocks if the Router Info is fragmented.
The simplest implementation may be to never include I2NP blocks in
the Session Confirmed message, and send all I2NP blocks in
subsequent Data messages.
KDF for data phase
----------------------------------------------
The data phase uses the header for associated data.
The KDF generates two cipher keys k_ab and k_ba from the chaining key ck,
using HMAC-SHA256(key, data) as defined in [RFC-2104]_.
This is the split() function, exactly as defined in the Noise spec.
.. raw:: html
{% highlight lang='text' %}
// 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
// AEAD parameters
k = k_ab or k_ba
n = packet number from header
ad = header
ciphertext = ENCRYPT(k, n, payload, ad)
// Header protection keys
TBD
{% endhighlight %}
Relay Messages (Types 3-5)
------------------------------
TBD, only required if these must be sent outside of an existing session.
Data Message (Type 6)
---------------------------
Noise payload: All block types are allowed
Max payload size: MTU - 60 (IPv4) or MTU - 80 (IPv6)
For 1500 MTU: Max payload is 1440 (IPv4) or 1420 (IPv6)
Starting with the 2nd part of Session Confirmed, all messages are inside
an authenticated and encrypted ChaChaPoly payload.
with a prepended two-byte obfuscated length.
All padding is inside the frame.
Inside the payload is a standard format with zero or more "blocks".
Each block has a one-byte type and a two-byte length.
Types include date/time, I2NP message, options, termination, and padding.
Note: Bob may, but is not required, to send his RouterInfo to Alice as
his first message to Alice in the data phase.
Payload Security Properties:
.. raw:: html
{% highlight lang='text' %}
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.
{% endhighlight %}
Notes
`````
- The router must drop a message AEAD error.
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
|Short Header obfuscated with dest hash |
+ encrypted, bytes 8-15 +
| header protected |
+----+----+----+----+----+----+----+----+
| ChaCha20 data |
+ Encrypted and authenticated data +
| length varies |
+k defined in KDF for Session Confirmed +
| n = packet number from header |
+ +
| |
+----+----+----+----+----+----+----+----+
| |
+ Poly1305 MAC (16 bytes) +
| |
+----+----+----+----+----+----+----+----+
{% endhighlight %}
Unencrypted data (Poly1305 auth tag not shown):
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 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
{% endhighlight %}
Notes
`````
Peer Test (Type 7)
------------------------
TBD, only required if these must be sent outside of an existing session.
Session Destroyed (Type 8)
-------------------------------
TBD, only required if these must be sent outside of an existing session.
Retry (Type 9)
-------------------------------
TODO encrypted? to what key?
Noise payload: Only padding block
Raw contents:
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| |
+ obfuscated with RH_B +
| AES-CBC-256 encrypted |
+ bytes 8-15 header protected +
| Long Header |
+ (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) +
| |
+----+----+----+----+----+----+----+----+
{% endhighlight %}
Unencrypted data (Poly1305 authentication tag not shown):
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| Destination Connection ID |
+----+----+----+----+----+----+----+----+
| Packet Number |type| ver| id |flag|
+----+----+----+----+----+----+----+----+
| Source Connection ID |
+----+----+----+----+----+----+----+----+
| Token |
+----+----+----+----+----+----+----+----+
| ChaCha20 payload (block data) |
+ (length varies) +
| |
+----+----+----+----+----+----+----+----+
Destination Connection ID :: As received from Alice in Session Request
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
Packet Number :: 0 unless retransmitted or resent after Retry
Source Connection ID :: As received from Alice in Session Request
Token :: 8 byte unsigned integer, nonzero
{% endhighlight %}
Notes
`````
This is NOT a standard Noise message and is not part of the handshake.
It is not bound to the Session Request message other than by connection IDs.
It is not required to decrypt the Session Request Noise message to create this
message in response.
Hole Punch Message
-------------------------------
An empty datagram. No content. Same as SSU 1.
A HolePunch is simply a UDP packet with no data. It is unauthenticated and
unencrypted. It does not contain a SSU header, so it does not have a message
type number. It is sent from Charlie to Alice as a part of the Introduction
sequence.
Noise Payload
===============
Each Noise payload contains zero or more "blocks".
This uses the same block format as defined in the [NTCP2]_ and [ECIES]_ specifications.
Individual block types are defined differently.
There are concerns that encouraging implementers to share code
may lead to parsing issues. Implementers should carefully consider
the benefits and risks of sharing code, and ensure that the
ordering and valid block rules are different for the two contexts.
Payload Format
----------------
There are zero or more blocks in the encrypted payload.
Each block contains a one-byte identifier, a two-byte length,
and zero or more bytes of data.
For extensibility, receivers must ignore blocks with unknown identifiers,
and treat them as padding.
Encrypted data is 65535 bytes max, including a 16-byte authentication header,
so the max unencrypted data is 65519 bytes.
(Poly1305 auth tag not shown):
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
|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
{% endhighlight %}
Maximum ChaChaPoly payload varies based on message type, MTU,
and IPv4 or IPv6 address type.
Upper limit is about 1440 bytes for IPv4, 1500 MTU, Data message.
Maximum total block size is the maximum payload size.
Maximum single block size is the maximum total block size.
Block type is 1 byte.
Block length is 2 bytes.
Maximum single block data size is the maximum single block size minus 3.
Note: Implementers must ensure that when reading a block,
malformed or malicious data will not cause reads to
overrun into the next block or beyond the payload boundary.
Block types:
==================================== ============= ============
Payload Block Type Type Number Block Length
==================================== ============= ============
DateTime 0 7
Options (TBD) 1 15+
Router Info 2 varies
I2NP Message 3 varies
First Fragment 4 varies
Follow-on Fragment 5 varies
Termination (TBD) 6 9 typ.
Relay Request 7 TBD
Relay Response 8 TBD
Relay Intro 9 TBD
Peer Test 10 TBD
Next Nonce 11 TBD
ACK 12 varies
Partial ACK 13 varies
NACK 14 varies
Relay Tag Request 15 3
Relay Tag 16 7
New Token 17 15
Path Challenge 18 varies
Path Response 19 varies
reserved for experimental features 255
Padding 254 varies
reserved for future extension 255
==================================== ============= ============
Block Ordering Rules
----------------------
In the Session Confirmed part 2, order must be:
RouterInfo, followed by Options if present, followed by Padding if present.
No other blocks are allowed.
In the data phase, order is unspecified, except for the
following requirements:
Padding, if present, must be the last block.
Termination, if present, must be the last block except for Padding.
There may be multiple I2NP blocks in a single payload.
Multiple Padding blocks are not allowed in a single payload.
Other block types probably won't have multiple blocks in
a single payload, but it is not prohibited.
Block Specifications
----------------------
DateTime
````````
For time synchronization:
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+
| 0 | 4 | timestamp |
+----+----+----+----+----+----+----+
blk :: 0
size :: 2 bytes, big endian, value = 4
timestamp :: Unix timestamp, unsigned seconds.
Wraps around in 2106
{% endhighlight %}
Options
```````
Pass updated options.
Options include: Min and max padding.
Options block will be variable length.
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 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
{% endhighlight %}
Options Issues
``````````````
- Options negotiation is TBD.
RouterInfo
``````````
Pass Alice's RouterInfo to Bob.
Used in Session Confirmed part 2.
Pass Alice's RouterInfo to Bob, or Bob's to Alice.
Used optionally in the data phase.
NOTE: Unlike in NTCP2, the Router Info may be fragmented.
Session setup is not complete until all fragments are received.
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 2 | size |flag|frag| |
+----+----+----+----+----+ +
| |
+ Router Info fragment +
| (Alice RI in Sessopm 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
bits 7-1: Unused, set to 0 for future compatibility
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
routerinfo :: Alice's or Bob's RouterInfo
{% endhighlight %}
Notes
`````
- When used in the data phase, receiver (Alice or Bob) shall validate that
it's the same Router Hash as originally sent (for Alice) or sent to (for Bob).
Then, treat it as a local I2NP DatabaseStore Message. Validate signature,
validate more recent timestamp, and store in the local netdb.
If the flag bit 0 is 1, and the receiving party is floodfill,
treat it as a DatabaseStore Message with a nonzero reply token,
and flood it to the nearest floodfills.
- The Router Info is NOT compressed with gzip
(unlike in a DatabaseStore Message, where it is)
- Flooding must not be requested unless there are published
RouterAddresses in the RouterInfo. The receiving router
must not flood the RouterInfo unless there are published
RouterAddresses in it.
- This protocol does not provide an acknowledgement that the RouterInfo
was received, stored, or flooded (either in the handshake or data phase).
If acknowledgement is desired, and the receiver is floodfill,
the sender should instead send a standard I2NP DatabaseStoreMessage
with a reply token.
Issues
``````
- Could also be used in data phase, instead of a I2NP DatabaseStoreMessage.
For example, Bob could use it to start off the data phase.
- Is it allowed for this to contain the RI for routers other than the
originator, as a general replacement for DatabaseStoreMessages,
e.g. for flooding by floodfills?
I2NP Message
````````````
A complete I2NP message with a modified header.
This uses the same 9 bytes for the I2NP header
as in [NTCP2]_ (type, message id, short expiration).
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 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
{% endhighlight %}
First Fragment
```````````````
The first fragment (fragment #0) of an I2NP message with a modified header.
This uses the same 9 bytes for the I2NP header
as in [NTCP2]_ (type, message id, short expiration).
Total number of fragments is not specified.
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 4 | size |type| msg id |
+----+----+----+----+----+----+----+----+
| short exp | |
+----+----+----+----+ +
| partial message |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
blk :: 4
size :: 2 bytes, big endian, size of type + msg id + exp + partial message 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 -1)
{% endhighlight %}
Follow-on Fragment
````````````````````````
An additional fragment (fragment number greater than zero) of an I2NP message.
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 5 | size |frag| msg id |
+----+----+----+----+----+----+----+----+
| |
+ +
| partial message |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
blk :: 5
size :: 2 bytes, big endian, size of frag + msg id + partial message to follow
Fragment size is (size - 5).
frag :: Fragment info:
Bit order: 76543210 (bit 7 is MSB)
bits 7-1: fragment # 1 - 127 (0 not allowed)
bit 0: isLast (1 = true)
msg id :: 4 bytes, big endian, I2NP message ID
message :: Partial I2NP message body
{% endhighlight %}
Termination
```````````
Drop the connection.
This must be the last non-padding block in the payload.
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 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
addl data :: optional, 0 or more bytes, for future expansion, debugging,
or reason text.
Format unspecified and may vary based on reason code.
{% endhighlight %}
Notes
`````
Not all reasons may actually be used, implementation dependent.
Most failures will generally result in the message being dropped, not a termination.
See notes in handshake message sections above.
Additional reasons listed are for consistency, logging, debugging, or if policy changes.
RelayRequest
``````````````
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 7 | size | relay tag | asz|
+----+----+----+----+----+----+----+----+
| Alice IP address | APort | csz| |
+----+----+----+----+----+----+----+ +
| challenge to be delivered to Charlie |
+ +
| |
+----+----+----+----+----+----+----+----+
| Alice's intro key |
+ +
| |
+ +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| nonce |
+----+----+----+----+
blk :: 7
size :: 2 bytes, big endian, size of data to follow
relay tag :: 4 byte relay (introduction) tag, nonzero, as received by
Alice in the SessionCreated message from Bob
asz :: 1 byte IP address size
Alice IP :: Alice's IP address, network byte order, asz bytes
APort :: 2 byte port number of Alice, network byte order
csz :: 1 byte challenge size
challenge :: if csz is nonzero, that many bytes to be relayed to Charlie in the intro
intro : Alice's 32-byte introduction key (so Bob can reply with
Charlie's info)
nonce :: 4 byte nonce of Alice's relay request
{% endhighlight %}
Notes
`````
* The IP address is only included if it is be different than the packet's
source address and port.
* This message may be sent via IPv4 or IPv6.
If the message is over IPv6 for an IPv4 introduction,
or (as of release 0.9.50) over IPv4 for an IPv6 introduction,
Alice must include her introduction address and port.
This is supported as of release 0.9.50.
* If Alice includes her address/port, Bob may perform additional validation
before continuing.
* Challenge is unimplemented, challenge size is always zero
* Relaying for IPv6 is supported as of release 0.9.50.
* Prior to release 0.9.12, Bob's intro key was always used. As of release
0.9.12, the session key is used if there is an established session between
Alice and Bob. In practice, there must be an established session, as Alice
will only get the nonce (introduction tag) from the session created message,
and Bob will mark the introduction tag invalid once the session is destroyed.
RelayResponse
``````````````
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 8 | size | csz| Charlie IP |
+----+----+----+----+----+----+----+----+
| CPort | asz| Alice IP |Aprt
+----+----+----+----+----+----+----+----+
Aprt| nonce |
+----+----+----+----+----+
blk :: 8
size :: 2 bytes, big endian, size of data to follow
csz :: 1 byte Charlie IP address size
Charlie IP :: Charlie's IP address, network byte order, csz bytes
CPort :: 2 byte Charlie's port number, network byte order
asz :: 1 byte Alice IP address size
Alice IP :: Alice's IP address, network byte order, asz bytes
Aprt :: 2 byte Alice's port number, network byte order
nonce :: 4 byte nonce sent by Alice
{% endhighlight %}
Notes
`````
* This message may be sent via IPv4 or IPv6.
* Alice's IP address/port are the apparent IP/port that Bob received the
RelayRequest on (not necessarily the IP Alice included in the RelayRequest),
and may be IPv4 or IPv6. Alice currently ignores these on receive.
* Charlie's IP address may be IPv4, or, as of release 0.9.50, IPv6.
as that is the address that Alice will
send the SessionRequest to after the Hole Punch.
* Relaying for IPv6 is supported as of release 0.9.50.
* Prior to release 0.9.12, Alice's intro key was always used. As of release
0.9.12, the session key is used if there is an established session between
Alice and Bob.
RelayIntro
``````````````
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 9 | size | asz| Alice IP |
+----+----+----+----+----+----+----+----+
| APort | csz| |
+----+----+----+ +
| that many bytes of challenge |
+ +
| data relayed from Alice |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
blk :: 9
size :: 2 bytes, big endian, size of data to follow
{% endhighlight %}
Notes
`````
* For IPv4, Alice's IP address is always 4 bytes, because Alice is trying to connect to Charlie via IPv4.
As of release 0.9.xx, IPv6 is supported, and Alice's IP address may be 16 bytes.
* This message must be sent via an established IPv4 connection, as that's the
only way that Bob knows Charlie's IPv4 address to return to Alice in the
RelayResponse_.
* For IPv4, this message must be sent via an established IPv4 connection,
as that's the only way that Bob knows Charlie's IPv4 address to return to Alice in the RelayResponse_.
As of release 0.9.50, IPv6 is supported, and this message may be sent via an established IPv6 connection.
* As of release 0.9.50, any SSU address published with introducers must contain "4" or "6" in the "caps" option.
* Challenge is unimplemented, challenge size is always zero
PeerTest
``````````````
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 10 | size | test nonce | asz|
+----+----+----+----+----+----+----+----+
| Alice IP address |AlicePort| |
+----+----+----+----+----+----+ +
| Alice or Charlie's |
+ introduction key (Alice's is sent to +
| Bob and Charlie, while Charlie's is |
+ sent to Alice) (32 bytes) +
| |
+ +----+----+
| |
+----+----+----+----+----+----+
blk :: 10
size :: 2 bytes, big endian, size of data to follow
test nonce :: 4 byte nonce, big endian integer
asz :: 1 byte IP address size (may be 0, 4, or 16)
Alice IP :: asz byte representation of Alice's IP address,
network byte order, if size is greater than zero
AlicePort :: 2 byte Alice's port number, big endian
intro :: Alice's or Charlie's 32-byte introduction key, big endian
{% endhighlight %}
Notes
`````
* When sent by Alice, IP address size is 0, IP address is not present, and port
is 0, as Bob and Charlie do not use the data; the point is to determine
Alice's true IP address/port and tell Alice; Bob and Charlie don't care what
Alice thinks her address is.
* When sent by Bob or Charlie, IP and port are present, and IP address is
4 or 16 bytes. IPv6 testing is supported as of release 0.9.27.
* IPv6 Notes: Through release 0.9.26, only testing of IPv4 addresses is supported. Therefore, all
Alice-Bob and Alice-Charlie communication must be via IPv4. Bob-Charlie
communication, however, may be via IPv4 or IPv6. Alice's address, when
specified in the PeerTest message, must be 4 bytes.
As of release 0.9.27, testing of IPv6 addresses is supported,
and Alice-Bob and Alice-Charlie communication may be via IPv6,
if Bob and Charlie indicate support with a 'B' capability in their published IPv6 address.
See Proposal 126 for details.
Alice sends the request to Bob using an existing session over the transport (IPv4 or IPv6) that she wishes to test.
When Bob receives a request from Alice via IPv4, Bob must select a Charlie that advertises an IPv4 address.
When Bob receives a request from Alice via IPv6, Bob must select a Charlie that advertises an IPv6 address.
The actual Bob-Charlie communication may be via IPv4 or IPv6 (i.e., independent of Alice's address type).
* A peer must maintain a table of active test states (nonces). On reception of
a PeerTest message, look up the nonce in the table. If found, it's an
existing test and you know your role (Alice, Bob, or Charlie). Otherwise, if
the IP is not present and the port is 0, this is a new test and you are Bob.
Otherwise, this is a new test and you are Charlie.
* Alice must have an established session with Bob and use
the session key.
NextNonce
``````````````
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 11 | size | TBD |
+----+----+----+ +
| |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
blk :: 11
size :: 2 bytes, big endian, size of data to follow
{% endhighlight %}
Ack
``````````````
- 4 byte ack through
- one byte negative offset from ack through
- bitfield of nacks from (ack through) - offset
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 12 | size | TBD |
+----+----+----+ +
| |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
blk :: 12
size :: 2 bytes, big endian, size of data to follow
{% endhighlight %}
Partial Ack
``````````````
TODO Not required if we're acking packets, not I2NP messages?
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 13 | size | TBD |
+----+----+----+ +
| |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
blk :: 13
size :: 2 bytes, big endian, size of data to follow
{% endhighlight %}
Nack
``````````````
TODO Not required, put in ack block?
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 14 | size | TBD |
+----+----+----+ +
| |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
blk :: 14
size :: 2 bytes, big endian, size of data to follow
{% endhighlight %}
Relay Tag Request
```````````````````````
In the Session Request message.
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+
| 15 | 0 |
+----+----+----+
blk :: 15
size :: 2 bytes, big endian, value = 0
{% endhighlight %}
Relay Tag
```````````
In the Session Created message.
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+
| 16 | 4 | relay tag |
+----+----+----+----+----+----+----+
blk :: 16
size :: 2 bytes, big endian, value = 4
relay tag :: 4 bytes, big endian
{% endhighlight %}
New Token
```````````````
For a subsequent connection:
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 17 | 4 | expires | |
+----+----+----+----+----+----+----+ +
token |
+----+----+----+----+----+----+----+
blk :: 17
size :: 2 bytes, big endian, value = 4
expires :: Unix timestamp, unsigned seconds.
Wraps around in 2106
token :: 8 bytes, big endian
{% endhighlight %}
Path Challenge
``````````````
A Ping with arbitrary data to be returned in a Path Response,
used as a keep-alive or to validate an IP/Port change.
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 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
{% endhighlight %}
Path Response
``````````````
A Pong with arbitrary data, a reply to a Path Challenge,
used as a keep-alive or to validate an IP/Port change.
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| 19 | size | Arbitrary Data |
+----+----+----+ +
| |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
blk :: 19
size :: 2 bytes, big endian, size of data to follow
data :: As received in a Path Challenge
{% endhighlight %}
Padding
```````
This is for padding inside AEAD payloads.
Padding for all messages are inside AEAD payloads.
Padding should roughly adhere to the negotiated parameters.
Bob sent his requested tx/rx min/max parameters in Session Created.
Alice sent her requested tx/rx min/max parameters in Session Confirmed.
Updated options may be sent during the data phase.
See options block information above.
If present, this must be the last block in the payload.
.. raw:: html
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
|254 | size | padding |
+----+----+----+ +
| |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
blk :: 254
size :: 2 bytes, big endian, size of padding to follow
padding :: random data
{% endhighlight %}
Notes
`````
- Padding strategies TBD.
- Minimum padding TBD.
- Padding-only blocks are allowed.
- Padding defaults TBD.
- See options block for padding parameter negotiation
- See options block for min/max padding parameters
- Noise limits messages to 64KB. If more padding is necessary, send multiple messages.
- Router response on violation of negotiated padding is implementation-dependent.
Other block types
`````````````````
Implementations should ignore unknown block types for
forward compatibility, except in Session Confirmed part 2, where
unknown blocks are not allowed.
Future work
```````````
- The padding length is either to be decided on a per-message basis and
estimates of the length distribution, or random delays should be added.
These countermeasures are to be included to resist DPI, as message sizes
would otherwise reveal that I2P traffic is being carried by the transport
protocol. The exact padding scheme is an area of future work, Appendix A
provides more information on the topic.
Replay Prevention
=====================
Both Session Request and Session Created messages must contain DateTime blocks.
Both Alice and Bob validate that the time is within a valid skew (recommended +/- 2 minutes)
and for replay prevention. Bob should reject duplicate Session Request messages
even if the skew is valid, via a Bloom filter or other mechanism.
Routers should use standard flow control and retransmission mechanisms to
detect and drop duplicate data phase messages.
Handshake Retransmission
===========================
Session Request
----------------
If no Session Created is received:
Maintain same source and connection IDs and ephemeral key. Increment packet number.
Re-encrypt Noise payload as AEAD (packet number) changed.
Re-protect header, re-obfuscate header, as packet number changed.
Recommended retransmission intervals: 3 and 6 seconds (3 and 9 seconds after first sent).
Recommended timeout: 15 seconds total
Session Created
----------------
If no Session Confirmed is received:
Maintain same source and connection IDs and ephemeral key. Increment packet number.
Re-encrypt Noise payload as AEAD (packet number) changed.
Re-protect header, re-obfuscate header, as packet number changed.
Recommended retransmission intervals: 3 and 6 seconds (3 and 9 seconds after first sent).
Recommended timeout: 15 seconds total
Session Confirmed
------------------
In SSU 1, Alice does not shift to the data phase until the first data packet is
received from Bob. This makes SSU 1 a two-round-trip setup.
Session Confirmed messages will be retransmitted
at 3 and 6 seconds (3 and 9 seconds after first sent).
There are several alternatives. All are 1 RTT:
1) Alice assumes Session Confirmed was received, sends data packets immediately,
never retransmit Session Confirmed. Data packets received out-of-order
(before Session Confirmed) will be undecryptable, but will get retransmitted.
If Session Confirmed is lost, all sent data packets will be dropped.
2) As in 1), send data packets immediately, but also retransmit Session Confirmed
until a data packet is received.
3) We could use IK instead of XK, as it has only two messages in the handshake, but
it uses an extra DH (4 instead of 3).
Retry
---------
If no Session Request is received:
Maintain same source and connection IDs. Increment packet number.
Re-protect header, re-obfuscate header, as packet number changed.
Recommended retransmission intervals: 3 and 6 seconds (3 and 9 seconds after first sent).
Recommended timeout: 15 seconds total
Total Timeout
--------------
Recommended total timeout for the handshake is 20 seconds.
Token
=============
The Token in the Session Request header is used for DoS mitigation.
If Bob does not accept the token in the Session Request message, Bob does NOT decrypt
the message, as it requires an expensive DH operation.
Bob simply sends a Retry message with a new token.
If a subsequent Session Request message then is received with that token,
Bob proceeds to decrypt that message and proceed with the handshake.
The token may be a randomly-generated 8 byte value, if the generator of the token
stores the values and associated IP and port (in-memory or persistently).
Alternatively, the generator may generate an opaque value, for example,
using the SipHash (with a secret seed K0, K1) of the IP, port, and current hour or day,
to create tokens that do not need to be saved in-memory.
Note that this method may make it difficult to reject reused tokens.
Tokens may only be used once.
A token sent from Bob to Alice in a Retry message must be used immediately, and expires
in a few seconds.
A token sent in a New Token block in an established session
may be used in a subsequent connection, and it
expires at the time specified in that block.
Expiration is specified by the sender; recommended values are
one hour minimum, several hours or days maximum.
A router should delete all its saved tokens if its IP, router hash, or keys change.
Tokens may optionally be persisted across router restarts, implementation dependent.
Acceptance of an unexpired token is not guaranteed; if Bob has forgotten or deleted
his saved tokens, he will send a Retry to Alice.
New Token blocks may be sent from Alice to Bob or Bob to Alice.
They would typically be sent once, soon after session establishment.
The token may be resent before or after expiration with a new expiration time,
or a new token may be sent.
A token is bound to the combination of source IP/port, destination IP/port,
static keys, and router hashes. A token received on IPv4 may not be used
for IPv6 or vice versa.
Router Info Fragmentation
===========================
SSU 1 contains a mechanism for Router Identity fragmentation in the Session Confirmed message
but it is unused, as the Router Identity is only 391 bytes
(387 for old DSA-SHA1 routers) and so fragmentation was never required.
The full Router Info was sent in a subsequent I2NP database store message in the data phase
and was fragmented as necessary.
In SSU2, the full Router Info is sent in the Session Confirmed message
(as in NTCP2), and validation of the signature
(and matching the static key in the Router Identity to that received in the Noise handshake)
is a vital part of the handshake.
Median Router Info sizes in the network are about 800 bytes, with a maximum size
of about 2000 bytes (uncompressed) or 1300 bytes (compressed).
Maximum Router Info sizes are expected to increase in the future,
due to additional Router Addresses.
If both SSU and SSU2 addresses are supported, or if multiple addresses for
different IPv4 or IPv6 IPs are supported (currently supported by i2pd but not Java i2p)
the sizes could increase significantly.
While a typical MTU and Router Info size would allow the Router Info to be sent
unfragmented, fragmentation will be necessary and this protocol must support it.
The Router Info block contains a fragmentation field (unlike in NTCP2 where it is not required).
If fragmentation is required, the first fragment is sent in the Session Confirmed message,
and subsequent fragments are sent in Data messages.
However, the session must be considered as in a pending state until all Router Info
fragments are received by Bob.
Alice must NOT send any I2NP blocks before all Router Info blocks are sent.
Alice MAY send I2NP blocks in the same message as the last RouterInfo fragment.
Bob MUST either queue or discard any I2NP blocks received from Alice before all Router Info blocks
are received and the signature and static key are validated.
Bob must NOT send any I2NP blocks to Alice before all Router Info blocks
are received and the signature and static key are validated.
I2NP Message Fragmentation
===========================
Differences from SSU 1
Note: As in SSU 1, the initial fragment does not contain information
on the total number of fragments or the total length.
Follow-on fragments do not contain information on their offset.
This provides the sender the flexibility of fragmenting "on the fly"
based on available space in the packet.
(Java I2P does not do this; it "pre-fragments" before the first fragment is sent)
However, it does burden the receiver to store fragments
received out-of-order and delay reassembly until all fragments are received.
As in SSU 1, any retransmission of fragments must preserve the length (and implicit offset)
of the fragment's previous tranmission.
SSU 2 does separate the three cases (full message, initial fragment, and follow-on fragment)
into three different block types, to improve processing efficiency.
Congestion Control
====================
Sequence numbers, acks, backoff, retransmission
Session Termination
=====================
Message or block? TBD
Upon any normal or abnormal termination, routers should
zero-out any in-memory ephemeral data, including handshake ephemeral keys,
symmetric crypto keys, and related information.
MTU
========
Requirements vary, based on whether the published address is shared with SSU 1.
Current SSU 1 IPv4 minimum is 620, which is probably too small.
SSU Address
------------
Shared address with SSU 1, must follow SSU 1 rules.
IPv4: Default and max is 1484. Min is 620.
(IPv4 MTU + 4) must be a multiple of 16.
IPv6: Must be published, min is 1280 and the max is 1488.
IPv6 MTU must be a multiple of 16.
SSU2 Address
------------
Must follow SSU 1 rules.
IPv4: Default and max is 1500. Min is TBD.
IPv6: Default and max is 1500. Min is 1280.
No multiple of 16 rules, but should probably be a multiple of 2 at least.
PMTU Discovery
---------------
For SSU 1, current Java I2P performs PMTU discovery by starting with small packets and
gradually increasing the size, or increasing based on received packet size.
This is crude and greatly reduces the efficiency.
Continuing this feature in SSU 2 is TBD.
Recent studies [PMTU]_ suggest that a minimum for IPv4 of 1200 or more would work
for more than 99% of connections. QUIC [RFC-9000]_ requires a minimum IP
packet size of 1280 bytes.
quote [RFC-9000]_:
The maximum datagram size is defined as the largest size of UDP
payload that can be sent across a network path using a single UDP
datagram. QUIC MUST NOT be used if the network path cannot support a
maximum datagram size of at least 1200 bytes.
QUIC assumes a minimum IP packet size of at least 1280 bytes. This
is the IPv6 minimum size [IPv6] and is also supported by most modern
IPv4 networks. Assuming the minimum IP header size of 40 bytes for
IPv6 and 20 bytes for IPv4 and a UDP header size of 8 bytes, this
results in a maximum datagram size of 1232 bytes for IPv6 and 1252
bytes for IPv4. Thus, modern IPv4 and all IPv6 network paths are
expected to be able to support QUIC.
Note: This requirement to support a UDP payload of 1200 bytes
limits the space available for IPv6 extension headers to 32
bytes or IPv4 options to 52 bytes if the path only supports the
IPv6 minimum MTU of 1280 bytes. This affects Initial packets
and path validation.
end quote
Handshake Min Size
-------------------------
QUIC requires that Initial datagrams in both directions be at least 1200 bytes,
to prevent amplification attacks. and ensure the PMTU supports it in both directions.
We could require this for Session Request and Session Created,
at substantial cost in bandwidth.
Perhaps we could do this only if we don't have a token,
or after a Retry message is received.
TBD
Path Message Min Size
-------------------------
QUIC requires that messages containing PATH_CHALLENGE or PATH_RESPONSE frames be at least 1200 bytes,
to prevent amplification attacks. and ensure the PMTU supports it in both directions.
We could require this as well, at substantial cost in bandwidth.
However, these cases should be rare.
TBD
Max Message Size
------------------
IPv4:
No IP fragmentation is assumed.
IP + datagram header is 28 bytes.
This assumes no IPv4 options.
Max message size is MTU - 28.
Data phase header is 16 bytes and MAC is 16 bytes, totalling 32 bytes.
Payload size is MTU - 60.
Max data phase payload is 1440 for a max 1500 MTU.
Max data phase payload is 1220 for a min 1280 MTU.
IPv6:
No IP fragmentation is allowed.
IP + datagram header is 48 bytes.
This assumes no IPv6 extension headers.
Max message size is MTU - 48.
Data phase header is 16 bytes and MAC is 16 bytes, totalling 32 bytes.
Payload size is MTU - 80.
Max data phase payload is 1420 for a max 1500 MTU.
Max data phase payload is 1200 for a min 1280 MTU.
Published Router Info
=====================
Address Properties
-------------------
The following address properties may be publiished, unchanged from SSU 1:
- caps: [B,C,4,6] capabilities
- host: IP (IPv4 or IPv6).
Shortened IPv6 address (with "::") is allowed.
May or may not be present if firewalled.
Host names are not allowed.
- iexp[0-2]: Expiration of this introducer.
ASCII digits, in seconds since the epoch.
Only present if firewalled, and introducers are required.
Optional (even if other properties for this introducer are present).
- ihost[0-2]: Introducer's IP (IPv4 or IPv6).
Shortened IPv6 address (with "::") is allowed.
Only present if firewalled, and introducers are required.
Host names are not allowed.
- ikey[0-2]: Introducer's Base 64 introduction key.
Only present if firewalled, and introducers are required.
- iport[0-2]: Introducer's port 1024 - 65535.
Only present if firewalled, and introducers are required.
- itag[0-2]: Introducer's tag 1 - (2**32 - 1)
ASCII digits.
Only present if firewalled, and introducers are required.
- key: Base 64 introduction key.
- mtu: Optional. See MTU section above.
- port: 1024 - 65535
May or may not be present if firewalled.
Published Addresses
-------------------
The published RouterAddress (part of the RouterInfo) will have a
protocol identifier of either "SSU" or "SSU2".
The RouterAddress must contain three options
to indicate SSU2 support:
- s=(Base64 key)
The current Noise static public key (s) for this RouterAddress.
Base 64 encoded using the standard I2P Base 64 alphabet.
32 bytes in binary, 44 bytes as Base 64 encoded,
little-endian X25519 public key.
- i=(Base64 IV)
The current IV for encrypting the headers for this RouterAddress.
Base 64 encoded using the standard I2P Base 64 alphabet.
16 bytes in binary, 24 bytes as Base 64 encoded,
big-endian.
- v=2
The current version (2).
When published as "SSU", additional support for version 1 is implied.
Support for future versions will be with comma-separated values,
e.g. v=2,3
Implementation should verify compatibility, including multiple
versions if a comma is present. Comma-separated versions must
be in numerical order.
Alice must verify that all three options are present and valid
before connecting using the SSU2 protocol.
When published as "SSU" with "s", "i", and "v" options,
the router must accept incoming connections on that host and port
for both SSU and SSU2 protocols, and automatically detect the protocol
version.
When published as "SSU2" with "s", "i", and "v" options,
the router accepts incoming connections on that host and port
for the SSU2 protocol only.
If a router supports both SSU1 and SSU2 connections but
does not implement automatic version detection for incoming connections,
it must advertise both "SSU" and "SSU2" addresses, and include
the SSU2 options in the "SSU2" address only.
The router should set a lower cost value (higher priority)
in the "SSU2" address than the "SSU" address, so SSU2 is preferred.
If multiple SSU2 RouterAddresses (either as "SSU" or "SSU2") are published
in the same RouterInfo (for additional IP addresses or ports),
all addresses specifying the same port must contain the identical SSU2 options and values.
In particular, all must contain the same static key and iv.
Unpublished SSU2 Address
-------------------------
If Alice does not publish her SSU2 address (as "SSU" or "SSU2") for incoming connections,
she must publish a "SSU2" router address containing only her static key and SSU2 version,
so that Bob may validate the key after receiving Alice's RouterInfo in Session Confirmed part 2.
- s=(Base64 key)
As defined above for published addresses.
- v=2
As defined above for published addresses.
This router address will not contain "i", "host" or "port" options,
as these are not required for outbound SSU2 connections.
The published cost for this address does not strictly matter, as it is inbound only;
however, it may be helpful to other routers if the cost is set higher (lower priority)
than other addresses. The suggested value is 14.
Alice may also simply add the "s" and "v" options to an existing published "SSU" address.
Public Key and IV Rotation
--------------------------
Using the same static keys for NTCP2 and SSU2 is allowed, but not recommended.
Due to caching of RouterInfos, routers must not rotate the static public key or IV
while the router is up, whether in a published address or not. Routers must
persistently store this key and IV for reuse after an immediate restart, so incoming
connections will continue to work, and restart times are not exposed. Routers
must persistently store, or otherwise determine, last-shutdown time, so that
the previous downtime may be calculated at startup.
Subject to concerns about exposing restart times, routers may rotate this key or IV
at startup if the router was previously down for some time (several days at
least).
If the router has any published SSU2 RouterAddresses (as SSU or SSU2), the
minimum downtime before rotation should be much longer, for example one month,
unless the local IP address has changed or the router "rekeys".
If the router has any published SSU RouterAddresses, but not SSU2 (as SSU or
SSU2) the minimum downtime before rotation should be longer, for example one
day, unless the local IP address has changed or the router "rekeys". This
applies even if the published SSU address has introducers.
If the router does not have any published RouterAddresses (SSU, SSU2, or
SSU), the minimum downtime before rotation may be as short as two hours, even
if the IP address changes, unless the router "rekeys".
If the router "rekeys" to a different Router Hash, it should generate a new
noise key and IV as well.
Implementations must be aware that changing the static public key or IV will prohibit
incoming SSU2 connections from routers that have cached an older RouterInfo.
RouterInfo publishing, tunnel peer selection (including both OBGW and IB
closest hop), zero-hop tunnel selection, transport selection, and other
implementation strategies must take this into account.
IV rotation is subject to identical rules as key rotation, except that IVs are not present
except in published RouterAddresses, so there is no IV for hidden or firewalled
routers. If anything changes (version, key, options?) it is recommended that
the IV change as well.
Note: The minimum downtime before rekeying may be modified to ensure network
health, and to prevent reseeding by a router down for a moderate amount of
time.
Identity Hiding
```````````````
Deniability is not a goal. See overview above.
Each pattern is assigned properties describing the confidentiality supplied to
the initiator's static public key, and to the responder's static public key.
The underlying assumptions are that ephemeral private keys are secure, and that
parties abort the handshake if they receive a static public key from the other
party which they don't trust.
This section only considers identity leakage through static public key fields
in handshakes. Of course, the identities of Noise participants might be
exposed through other means, including payload fields, traffic analysis, or
metadata such as IP addresses.
Alice: (8) Encrypted with forward secrecy to an authenticated party.
Bob: (3) Not transmitted, but a passive attacker can check candidates for the
responder's private key and determine whether the candidate is correct.
Bob publishes his static public key in the netdb. Alice may not, but must include it in the RI
sent to Bob.
Inbound Packet Handling
==========================
In SSU 1, inbound packet classification is difficult, because there is no
header to indicate session number. Routers must first match the source IP and port
to an existing peer state, and if not found, attempt multiple decryptions with different
keys to find the appropriate peer state or start a new one.
In the event that the source IP or port for an existing session changes,
possibly due to NAT behavior
the router may use expensive heuristics to attempt to match the packet to an existing session
and recover the contents.
SSU 2 is designed to minimize the inbound packet classification effort while maintaining
DPI resistance and other on-path threats. The session number is included in the header
for all message types, and obfuscated using AES with a known key and IV.
Additionally, the message type is also included in the header
(encrypted with header protection to a known key and then obfuscated with AES)
and may be used for additional classification.
In no case should a trial DH operation be necessary to classify a packet.
For almost all messages from all peers, the AES key and IV are the destination router's
router hash and IV as published in the netdb.
The only exceptions are the first messages sent from Bob to Alice (Session Created or Retry)
where Alice's router hash is not yet known to Bob. In these cases, Bob's router hash
and IV are used.
Therefore, the recommended processing steps are:
1) Remove the AES obfuscation to recover the session ID. If known, use that session
for further processing.
2) Remove the header protection to recover the version, net ID, message type,
and packet number fields. If all are sensible, and the message type is 0 (Session Request),
create a new session and use that session for further processing.
3) Look up a pending outbound session by the source IP/port of the packet;
if found, remove the session ID obfuscation using Bob's router hash and IV,
verify the session ID matches, and use that pending session for further processing.
Issues
--------
If Relay and Peer Test messages are allowed outside of a session, they may also require
additional processing steps to classify them.
Version Detection
--------------------
It may not be possible to efficiently detect if incoming packets are version 1 or 2 on the same inbound port.
The steps above may make sense to do before SSU 1 processing, to avoid attempting trial DH operations
using both protocol versions.
TBD if required.
Variants, Fallbacks, and General Issues
=======================================
TBD
Packet Overhead Analysis
=========================
Assumes IPv4, not including extra padding, not including IP and UDP header sizes.
Padding is mod-16 padding for SSU 1 only.
SSU 1
================== =========== ===== ====== ======= ====== =====
Message Header+MAC Keys Data Padding Total Notes
================== =========== ===== ====== ======= ====== =====
Session Request 40 256 5 3 304 Incl. extended options
Session Created 37 256 79 1 336 Incl. 64 byte Ed25519 sig
Session Confirmed 37 462 13 512 Incl. 391 byte ident and 64 byte sig
Data (RI) 37 1014 1051 Incl. 5 byte I2NP header, 1000 byte RI
Data (1 full msg) 37 14 51 Incl. 5 byte I2NP header
Total 2254
================== =========== ===== ====== ======= ====== =====
SSU 2
================== =========== ===== ====== ======= ====== =====
Message Header+MAC Keys Data Padding Total Notes
================== =========== ===== ====== ======= ====== =====
Session Request 48 32 7 87 DateTime block
Session Created 48 32 7 87 DateTime block
Session Confirmed 48 32 1003 1083 (2 macs) 1000 byte RI block
Data (1 full msg) 32 14 46
Total 1303
================== =========== ===== ====== ======= ====== =====
TODO UNLESS minimum packet size in Session Request and Created is enforced for PMTU.
References
==========
.. [ECIES]
{{ site_url('docs/spec/ecies', True) }}
.. [NetDB]
{{ site_url('docs/how/network-database', True) }}
.. [NOISE]
https://noiseprotocol.org/noise.html
.. [Nonces]
https://eprint.iacr.org/2019/624.pdf
.. [NTCP]
{{ site_url('docs/transport/ntcp', True) }}
.. [NTCP2]
{{ site_url('docs/spec/ntcp2', True) }}
.. [PMTU]
https://aura.abdn.ac.uk/bitstream/handle/2164/11693/tma2018_paper57.pdf
.. [Prop104]
{{ proposal_url('104') }}
.. [Prop109]
{{ proposal_url('109') }}
.. [RFC-2104]
https://tools.ietf.org/html/rfc2104
.. [RFC-3526]
https://tools.ietf.org/html/rfc3526
.. [RFC-5869]
https://tools.ietf.org/html/rfc5869
.. [RFC-6151]
https://tools.ietf.org/html/rfc6151
.. [RFC-6437]
https://tools.ietf.org/html/rfc6437
.. [RFC-7539]
https://tools.ietf.org/html/rfc7539
.. [RFC-7748]
https://tools.ietf.org/html/rfc7748
.. [RFC-7905]
https://tools.ietf.org/html/rfc7905
.. [RFC-9000]
https://datatracker.ietf.org/doc/html/rfc9000
.. [RFC-9001]
https://datatracker.ietf.org/doc/html/rfc9001
.. [RouterAddress]
{{ ctags_url('RouterAddress') }}
.. [RouterIdentity]
{{ ctags_url('RouterIdentity') }}
.. [SigningPublicKey]
{{ ctags_url('SigningPublicKey') }}
.. [SipHash]
https://www.131002.net/siphash/
.. [SSU]
{{ site_url('docs/transport/ssu', True) }}
.. [STS]
Diffie, W.; van Oorschot P. C.; Wiener M. J., Authentication and
Authenticated Key Exchanges
.. [Ticket1112]
https://{{ i2pconv('trac.i2p2.i2p') }}/ticket/1112
.. [Ticket1849]
https://{{ i2pconv('trac.i2p2.i2p') }}/ticket/1849
.. [WireGuard]
https://www.wireguard.com/protocol/