Generate stateless reset tokens by hashing instead of XOR.
This will allow us to support connection ID lengths greater than 24 which is required per latest IETF draft on version negotiation (QUICv1 requires the connection ID length to be <= 20 but if we receive a packet of an unknown version with connection ID lengths of up to 255 we need to properly send a version negotiation packet in response). Protected by quic_use_hashed_stateless_reset_tokens.
gfe-relnote: change stateless reset token generation, protected by disabled gfe2_restart_flag_quic_use_hashed_stateless_reset_tokens
PiperOrigin-RevId: 264287305
Change-Id: I921a1137fc1ceaa3a799ec486e0609d051feadc4
diff --git a/quic/core/quic_utils.cc b/quic/core/quic_utils.cc
index a3366da..da2cb1a 100644
--- a/quic/core/quic_utils.cc
+++ b/quic/core/quic_utils.cc
@@ -578,17 +578,22 @@
QuicUint128 QuicUtils::GenerateStatelessResetToken(
QuicConnectionId connection_id) {
- uint64_t data_bytes[3] = {0, 0, 0};
- static_assert(sizeof(data_bytes) >= kQuicMaxConnectionIdAllVersionsLength,
- "kQuicMaxConnectionIdAllVersionsLength changed");
- memcpy(data_bytes, connection_id.data(), connection_id.length());
- // This is designed so that the common case of 64bit connection IDs
- // produces a stateless reset token that is equal to the connection ID
- // interpreted as a 64bit unsigned integer, to facilitate debugging.
- return MakeQuicUint128(
- QuicEndian::NetToHost64(sizeof(uint64_t) ^ connection_id.length() ^
- data_bytes[1] ^ data_bytes[2]),
- QuicEndian::NetToHost64(data_bytes[0]));
+ if (!GetQuicRestartFlag(quic_use_hashed_stateless_reset_tokens)) {
+ uint64_t data_bytes[3] = {0, 0, 0};
+ static_assert(sizeof(data_bytes) >= kQuicMaxConnectionIdAllVersionsLength,
+ "kQuicMaxConnectionIdAllVersionsLength changed");
+ memcpy(data_bytes, connection_id.data(), connection_id.length());
+ // This is designed so that the common case of 64bit connection IDs
+ // produces a stateless reset token that is equal to the connection ID
+ // interpreted as a 64bit unsigned integer, to facilitate debugging.
+ return MakeQuicUint128(
+ QuicEndian::NetToHost64(sizeof(uint64_t) ^ connection_id.length() ^
+ data_bytes[1] ^ data_bytes[2]),
+ QuicEndian::NetToHost64(data_bytes[0]));
+ }
+ QUIC_RESTART_FLAG_COUNT(quic_use_hashed_stateless_reset_tokens);
+ return FNV1a_128_Hash(
+ QuicStringPiece(connection_id.data(), connection_id.length()));
}
// Returns the maximum value that a stream count may have, taking into account
diff --git a/quic/core/quic_utils_test.cc b/quic/core/quic_utils_test.cc
index dc46133..a2bc403 100644
--- a/quic/core/quic_utils_test.cc
+++ b/quic/core/quic_utils_test.cc
@@ -266,7 +266,9 @@
QuicUint128 token2 = QuicUtils::GenerateStatelessResetToken(connection_id2);
EXPECT_EQ(token1a, token1b);
EXPECT_NE(token1a, token2);
- EXPECT_EQ(token1a, MakeQuicUint128(0, 1));
+ if (!GetQuicRestartFlag(quic_use_hashed_stateless_reset_tokens)) {
+ EXPECT_EQ(token1a, MakeQuicUint128(0, 1));
+ }
}
} // namespace
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc
index 1292d0d..3fd870f 100644
--- a/quic/core/quic_versions.cc
+++ b/quic/core/quic_versions.cc
@@ -475,6 +475,7 @@
SetQuicReloadableFlag(quic_simplify_stop_waiting, true);
SetQuicReloadableFlag(quic_use_parse_public_header, true);
SetQuicRestartFlag(quic_dispatcher_hands_chlo_extractor_one_version, true);
+ SetQuicRestartFlag(quic_use_hashed_stateless_reset_tokens, true);
}
void QuicEnableVersion(ParsedQuicVersion parsed_version) {