Stateless reset tokens are not scoped by remote address
Summary
RFC 9000 requires endpoints to remember stateless reset tokens associated with both connection IDs and remote addresses for recently sent datagrams. s2n-quic stores tokens in a global token -> InternalConnectionId map and matches a received datagram by token only. The implementation has an explicit exception file saying it intentionally does not use the remote address for this check, so this is a real RFC mismatch rather than missing static evidence.
Standard Requirement
Official standard: https://www.rfc-editor.org/rfc/rfc9000#section-10.3.1
RFC 9000 Section 10.3.1:
An endpoint remembers all stateless reset
tokens associated with the connection IDs and remote addresses for
datagrams it has recently sent.
The same paragraph later states:
The endpoint identifies a received datagram as a Stateless Reset by
comparing the last 16 bytes of the datagram with all stateless reset
tokens associated with the remote address on which the datagram was
received.
The token set is therefore scoped by the datagram's remote address.
Relevant Source Code
implementions/s2n-quic/quic/s2n-quic-transport/src/connection/connection_id_mapper.rs:53-84
pub(crate) struct StatelessResetMap {
/// Maps from a hash of peer stateless reset token to internal connection IDs
map: HashMap<stateless_reset::Token, InternalConnectionId, HashState>,
}
pub(crate) fn insert(
&mut self,
token: stateless_reset::Token,
internal_id: InternalConnectionId,
) {
self.map.insert(token, internal_id);
}
pub(crate) fn remove(
&mut self,
token: &stateless_reset::Token,
) -> Option<InternalConnectionId> {
self.map.remove(token)
}
The stored key is only the stateless reset token; no remote address is stored.
implementions/s2n-quic/quic/s2n-quic-transport/src/connection/connection_id_mapper.rs:300-319
pub fn remove_internal_connection_id_by_stateless_reset_token(
&mut self,
peer_stateless_reset_token: &stateless_reset::Token,
) -> Option<InternalConnectionId> {
let mut guard = self
.state
.lock()
.expect("should succeed unless the lock is poisoned");
guard.stateless_reset_map.remove(peer_stateless_reset_token)
}
The lookup API accepts only a token, not the datagram remote address.
implementions/s2n-quic/quic/s2n-quic-transport/src/endpoint/mod.rs:905-916
let token_index = payload.len().checked_sub(StatelessResetTokenLen)?;
let buffer = buffer.skip(token_index).ok()?;
let (token, _) = buffer.decode().ok()?;
let endpoint_context = self.config.context();
let internal_id = self
.connection_id_mapper
.remove_internal_connection_id_by_stateless_reset_token(&token)?;
The endpoint extracts the last 16 bytes and performs a global token lookup.
implementions/s2n-quic/specs/exceptions/transport/10.3.1.toml
reason = '''
s2n-quic maintains a hash map of all Stateless Reset Tokens to the connection
they are associated with.
...
In addition, validating the remote address matches the
remote address associated with the Stateless Reset Token provides minimal additional
security benefit ...
'''
The project records this as an intentional exception, not as implemented RFC behavior.
Implementation Behavior
When a peer CID becomes used, PeerIdRegistry inserts its token into stateless_reset_map. When an inbound datagram cannot be processed normally, endpoint code extracts the trailing 16-byte token and asks ConnectionIdMapper for a matching connection. Neither insertion nor lookup includes the remote address.
Inconsistency Reason
The RFC requires remembering and comparing tokens associated with the remote address on which the datagram was received. s2n-quic compares against a global token map. That means a valid token can match independently of the datagram's remote address, which is broader than the RFC-scoped comparison.
Runtime Evidence
Token lookup uses the global map:
cargo test -p s2n-quic-transport connection::connection_id_mapper::tests::remove_internal_connection_id_by_stateless_reset_token_test -- --exact --nocapture
Result: passed, exit code 0.
Token insertion occurs when a peer CID is consumed:
cargo test -p s2n-quic-transport connection::peer_id_registry::tests::consume_new_id_should_return_id -- --exact --nocapture
Result: passed, exit code 0.
opt/runs/rfc9000/rfc9000-s2nquic/501-1000/reports/runtime/0232-token-insert-on-peer-id-use.stdout.log
opt/runs/rfc9000/rfc9000-s2nquic/501-1000/reports/runtime/0232-token-insert-on-peer-id-use.stderr.log
opt/runs/rfc9000/rfc9000-s2nquic/501-1000/reports/runtime/0232-token-insert-on-peer-id-use.exitcode.txt
Impact
Stateless Reset detection is not constrained to tokens associated with the received datagram's remote address. This expands the matching scope beyond RFC 9000's address-scoped token set.
Fix Direction
Store stateless reset tokens with the relevant remote address, and pass the received datagram's remote address into Stateless Reset lookup so comparison is limited to tokens associated with that address.
Merged Redundant Reports
The following report described the same root cause and the same required fix, so it was merged into this report and removed:
0234-static unresolved requirement.md: stateless reset lookup uses the token without scoping the match to the datagram remote address.
Stateless reset tokens are not scoped by remote address
Summary
RFC 9000 requires endpoints to remember stateless reset tokens associated with both connection IDs and remote addresses for recently sent datagrams. s2n-quic stores tokens in a global
token -> InternalConnectionIdmap and matches a received datagram by token only. The implementation has an explicit exception file saying it intentionally does not use the remote address for this check, so this is a real RFC mismatch rather than missing static evidence.Standard Requirement
Official standard: https://www.rfc-editor.org/rfc/rfc9000#section-10.3.1
RFC 9000 Section 10.3.1:
The same paragraph later states:
The token set is therefore scoped by the datagram's remote address.
Relevant Source Code
implementions/s2n-quic/quic/s2n-quic-transport/src/connection/connection_id_mapper.rs:53-84The stored key is only the stateless reset token; no remote address is stored.
implementions/s2n-quic/quic/s2n-quic-transport/src/connection/connection_id_mapper.rs:300-319The lookup API accepts only a token, not the datagram remote address.
implementions/s2n-quic/quic/s2n-quic-transport/src/endpoint/mod.rs:905-916The endpoint extracts the last 16 bytes and performs a global token lookup.
implementions/s2n-quic/specs/exceptions/transport/10.3.1.tomlThe project records this as an intentional exception, not as implemented RFC behavior.
Implementation Behavior
When a peer CID becomes used,
PeerIdRegistryinserts its token intostateless_reset_map. When an inbound datagram cannot be processed normally, endpoint code extracts the trailing 16-byte token and asksConnectionIdMapperfor a matching connection. Neither insertion nor lookup includes the remote address.Inconsistency Reason
The RFC requires remembering and comparing tokens associated with the remote address on which the datagram was received. s2n-quic compares against a global token map. That means a valid token can match independently of the datagram's remote address, which is broader than the RFC-scoped comparison.
Runtime Evidence
Token lookup uses the global map:
Result: passed, exit code
0.Token insertion occurs when a peer CID is consumed:
Result: passed, exit code
0.opt/runs/rfc9000/rfc9000-s2nquic/501-1000/reports/runtime/0232-token-insert-on-peer-id-use.stdout.logopt/runs/rfc9000/rfc9000-s2nquic/501-1000/reports/runtime/0232-token-insert-on-peer-id-use.stderr.logopt/runs/rfc9000/rfc9000-s2nquic/501-1000/reports/runtime/0232-token-insert-on-peer-id-use.exitcode.txtImpact
Stateless Reset detection is not constrained to tokens associated with the received datagram's remote address. This expands the matching scope beyond RFC 9000's address-scoped token set.
Fix Direction
Store stateless reset tokens with the relevant remote address, and pass the received datagram's remote address into Stateless Reset lookup so comparison is limited to tokens associated with that address.
Merged Redundant Reports
The following report described the same root cause and the same required fix, so it was merged into this report and removed:
0234-static unresolved requirement.md: stateless reset lookup uses the token without scoping the match to the datagram remote address.