Introduce draft-28 transport parameters This CL adds the new transport parameters to TransportParameters. They will be used in a subsequent CL. Add unused code PiperOrigin-RevId: 313678124 Change-Id: Ic04c88f8e3a7275316f67abfd8207d9d1efe15ee
diff --git a/quic/core/crypto/transport_parameters.cc b/quic/core/crypto/transport_parameters.cc index 45b284b..12c0d0d 100644 --- a/quic/core/crypto/transport_parameters.cc +++ b/quic/core/crypto/transport_parameters.cc
@@ -46,6 +46,8 @@ kDisableActiveMigration = 0xc, kPreferredAddress = 0xd, kActiveConnectionIdLimit = 0xe, + kInitialSourceConnectionId = 0xf, + kRetrySourceConnectionId = 0x10, kMaxDatagramFrameSize = 0x20, @@ -104,6 +106,10 @@ return "preferred_address"; case TransportParameters::kActiveConnectionIdLimit: return "active_connection_id_limit"; + case TransportParameters::kInitialSourceConnectionId: + return "initial_source_connection_id"; + case TransportParameters::kRetrySourceConnectionId: + return "retry_source_connection_id"; case TransportParameters::kMaxDatagramFrameSize: return "max_datagram_frame_size"; case TransportParameters::kInitialRoundTripTime: @@ -138,6 +144,8 @@ case TransportParameters::kDisableActiveMigration: case TransportParameters::kPreferredAddress: case TransportParameters::kActiveConnectionIdLimit: + case TransportParameters::kInitialSourceConnectionId: + case TransportParameters::kRetrySourceConnectionId: case TransportParameters::kMaxDatagramFrameSize: case TransportParameters::kInitialRoundTripTime: case TransportParameters::kGoogleConnectionOptions: @@ -429,6 +437,14 @@ preferred_address->ToString(); } rv += active_connection_id_limit.ToString(/*for_use_in_list=*/true); + if (initial_source_connection_id.has_value()) { + rv += " " + TransportParameterIdToString(kInitialSourceConnectionId) + " " + + initial_source_connection_id.value().ToString(); + } + if (retry_source_connection_id.has_value()) { + rv += " " + TransportParameterIdToString(kRetrySourceConnectionId) + " " + + retry_source_connection_id.value().ToString(); + } rv += max_datagram_frame_size.ToString(/*for_use_in_list=*/true); rv += initial_round_trip_time_us.ToString(/*for_use_in_list=*/true); if (google_connection_options.has_value()) { @@ -522,6 +538,8 @@ max_ack_delay(other.max_ack_delay), disable_active_migration(other.disable_active_migration), active_connection_id_limit(other.active_connection_id_limit), + initial_source_connection_id(other.initial_source_connection_id), + retry_source_connection_id(other.retry_source_connection_id), max_datagram_frame_size(other.max_datagram_frame_size), initial_round_trip_time_us(other.initial_round_trip_time_us), google_connection_options(other.google_connection_options), @@ -561,6 +579,8 @@ disable_active_migration == rhs.disable_active_migration && active_connection_id_limit.value() == rhs.active_connection_id_limit.value() && + initial_source_connection_id == rhs.initial_source_connection_id && + retry_source_connection_id == rhs.retry_source_connection_id && max_datagram_frame_size.value() == rhs.max_datagram_frame_size.value() && initial_round_trip_time_us.value() == @@ -602,7 +622,7 @@ } if (perspective == Perspective::IS_CLIENT && original_destination_connection_id.has_value()) { - *error_details = "Client cannot send original connection ID"; + *error_details = "Client cannot send original_destination_connection_id"; return false; } if (!stateless_reset_token.empty() && @@ -629,6 +649,11 @@ *error_details = "Internal preferred address family failure"; return false; } + if (perspective == Perspective::IS_CLIENT && + retry_source_connection_id.has_value()) { + *error_details = "Client cannot send retry_source_connection_id"; + return false; + } for (const auto& kv : custom_parameters) { if (TransportParameterIdIsKnown(kv.first)) { *error_details = quiche::QuicheStrCat( @@ -715,6 +740,8 @@ kTypeAndValueLength + // disable_active_migration kPreferredAddressParameterLength + // preferred_address kIntegerParameterLength + // active_connection_id_limit + kConnectionIdParameterLength + // initial_source_connection_id + kConnectionIdParameterLength + // retry_source_connection_id kIntegerParameterLength + // max_datagram_frame_size kIntegerParameterLength + // initial_round_trip_time_us kTypeAndValueLength + // google_connection_options @@ -868,6 +895,42 @@ } } + // initial_source_connection_id + if (in.initial_source_connection_id.has_value()) { + QuicConnectionId initial_source_connection_id = + in.initial_source_connection_id.value(); + if (!WriteTransportParameterId( + &writer, TransportParameters::kInitialSourceConnectionId, + version) || + !WriteTransportParameterStringPiece( + &writer, + quiche::QuicheStringPiece(initial_source_connection_id.data(), + initial_source_connection_id.length()), + version)) { + QUIC_BUG << "Failed to write initial_source_connection_id " + << initial_source_connection_id << " for " << in; + return false; + } + } + + // retry_source_connection_id + if (in.retry_source_connection_id.has_value()) { + DCHECK_EQ(Perspective::IS_SERVER, in.perspective); + QuicConnectionId retry_source_connection_id = + in.retry_source_connection_id.value(); + if (!WriteTransportParameterId( + &writer, TransportParameters::kRetrySourceConnectionId, version) || + !WriteTransportParameterStringPiece( + &writer, + quiche::QuicheStringPiece(retry_source_connection_id.data(), + retry_source_connection_id.length()), + version)) { + QUIC_BUG << "Failed to write retry_source_connection_id " + << retry_source_connection_id << " for " << in; + return false; + } + } + // Google-specific connection options. if (in.google_connection_options.has_value()) { static_assert(sizeof(in.google_connection_options.value().front()) == 4, @@ -1193,6 +1256,48 @@ parse_success = out->active_connection_id_limit.Read(&value_reader, error_details); break; + case TransportParameters::kInitialSourceConnectionId: { + if (out->initial_source_connection_id.has_value()) { + *error_details = "Received a second initial_source_connection_id"; + return false; + } + const size_t connection_id_length = value_reader.BytesRemaining(); + if (!QuicUtils::IsConnectionIdLengthValidForVersion( + connection_id_length, version.transport_version)) { + *error_details = quiche::QuicheStrCat( + "Received initial_source_connection_id of invalid length ", + connection_id_length); + return false; + } + QuicConnectionId initial_source_connection_id; + if (!value_reader.ReadConnectionId(&initial_source_connection_id, + connection_id_length)) { + *error_details = "Failed to read initial_source_connection_id"; + return false; + } + out->initial_source_connection_id = initial_source_connection_id; + } break; + case TransportParameters::kRetrySourceConnectionId: { + if (out->retry_source_connection_id.has_value()) { + *error_details = "Received a second retry_source_connection_id"; + return false; + } + const size_t connection_id_length = value_reader.BytesRemaining(); + if (!QuicUtils::IsConnectionIdLengthValidForVersion( + connection_id_length, version.transport_version)) { + *error_details = quiche::QuicheStrCat( + "Received retry_source_connection_id of invalid length ", + connection_id_length); + return false; + } + QuicConnectionId retry_source_connection_id; + if (!value_reader.ReadConnectionId(&retry_source_connection_id, + connection_id_length)) { + *error_details = "Failed to read retry_source_connection_id"; + return false; + } + out->retry_source_connection_id = retry_source_connection_id; + } break; case TransportParameters::kMaxDatagramFrameSize: parse_success = out->max_datagram_frame_size.Read(&value_reader, error_details);
diff --git a/quic/core/crypto/transport_parameters.h b/quic/core/crypto/transport_parameters.h index 1d91db3..80c905c 100644 --- a/quic/core/crypto/transport_parameters.h +++ b/quic/core/crypto/transport_parameters.h
@@ -180,6 +180,14 @@ // to store. IntegerParameter active_connection_id_limit; + // The value that the endpoint included in the Source Connection ID field of + // the first Initial packet it sent. + quiche::QuicheOptional<QuicConnectionId> initial_source_connection_id; + + // The value that the server included in the Source Connection ID field of a + // Retry packet it sent. + quiche::QuicheOptional<QuicConnectionId> retry_source_connection_id; + // Indicates support for the DATAGRAM frame and the maximum frame size that // the sender accepts. See draft-ietf-quic-datagram. IntegerParameter max_datagram_frame_size;
diff --git a/quic/core/crypto/transport_parameters_test.cc b/quic/core/crypto/transport_parameters_test.cc index 628c19f..a3fc084 100644 --- a/quic/core/crypto/transport_parameters_test.cc +++ b/quic/core/crypto/transport_parameters_test.cc
@@ -56,6 +56,14 @@ return TestConnectionId(0x1337); } +QuicConnectionId CreateFakeInitialSourceConnectionId() { + return TestConnectionId(0x2345); +} + +QuicConnectionId CreateFakeRetrySourceConnectionId() { + return TestConnectionId(0x9876); +} + QuicConnectionId CreateFakePreferredConnectionId() { return TestConnectionId(0xBEEF); } @@ -222,6 +230,23 @@ EXPECT_EQ(orig_params, new_params); EXPECT_TRUE(orig_params == new_params); EXPECT_FALSE(orig_params != new_params); + + // Test comparison on connection IDs. + orig_params.initial_source_connection_id = + CreateFakeInitialSourceConnectionId(); + new_params.initial_source_connection_id = QuicheNullOpt; + EXPECT_NE(orig_params, new_params); + EXPECT_FALSE(orig_params == new_params); + EXPECT_TRUE(orig_params != new_params); + new_params.initial_source_connection_id = TestConnectionId(0xbadbad); + EXPECT_NE(orig_params, new_params); + EXPECT_FALSE(orig_params == new_params); + EXPECT_TRUE(orig_params != new_params); + new_params.initial_source_connection_id = + CreateFakeInitialSourceConnectionId(); + EXPECT_EQ(orig_params, new_params); + EXPECT_TRUE(orig_params == new_params); + EXPECT_FALSE(orig_params != new_params); } TEST_P(TransportParametersTest, CopyConstructor) { @@ -250,6 +275,9 @@ orig_params.preferred_address = CreateFakePreferredAddress(); orig_params.active_connection_id_limit.set_value( kFakeActiveConnectionIdLimit); + orig_params.initial_source_connection_id = + CreateFakeInitialSourceConnectionId(); + orig_params.retry_source_connection_id = CreateFakeRetrySourceConnectionId(); orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime); orig_params.google_connection_options = CreateFakeGoogleConnectionOptions(); orig_params.user_agent_id = CreateFakeUserAgentId(); @@ -280,6 +308,8 @@ orig_params.disable_active_migration = kFakeDisableMigration; orig_params.active_connection_id_limit.set_value( kFakeActiveConnectionIdLimit); + orig_params.initial_source_connection_id = + CreateFakeInitialSourceConnectionId(); orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime); orig_params.google_connection_options = CreateFakeGoogleConnectionOptions(); orig_params.user_agent_id = CreateFakeUserAgentId(); @@ -326,6 +356,9 @@ orig_params.preferred_address = CreateFakePreferredAddress(); orig_params.active_connection_id_limit.set_value( kFakeActiveConnectionIdLimit); + orig_params.initial_source_connection_id = + CreateFakeInitialSourceConnectionId(); + orig_params.retry_source_connection_id = CreateFakeRetrySourceConnectionId(); orig_params.google_connection_options = CreateFakeGoogleConnectionOptions(); std::vector<uint8_t> serialized; @@ -454,7 +487,7 @@ TEST_P(TransportParametersTest, ParseClientParams) { // clang-format off const uint8_t kClientParamsOld[] = { - 0x00, 0x6a, // length of the parameters array that follows + 0x00, 0x76, // length of the parameters array that follows // max_idle_timeout 0x00, 0x01, // parameter id 0x00, 0x02, // length @@ -502,6 +535,10 @@ 0x00, 0x0e, // parameter id 0x00, 0x01, // length 0x34, // value + // initial_source_connection_id + 0x00, 0x0f, // parameter id + 0x00, 0x08, // length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45, // initial_round_trip_time_us 0x31, 0x27, // parameter id 0x00, 0x01, // length @@ -569,6 +606,10 @@ 0x0e, // parameter id 0x01, // length 0x34, // value + // initial_source_connection_id + 0x0f, // parameter id + 0x08, // length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45, // initial_round_trip_time_us 0x71, 0x27, // parameter id 0x01, // length @@ -627,6 +668,10 @@ EXPECT_EQ(kFakeDisableMigration, new_params.disable_active_migration); EXPECT_EQ(kFakeActiveConnectionIdLimit, new_params.active_connection_id_limit.value()); + ASSERT_TRUE(new_params.initial_source_connection_id.has_value()); + EXPECT_EQ(CreateFakeInitialSourceConnectionId(), + new_params.initial_source_connection_id.value()); + EXPECT_FALSE(new_params.retry_source_connection_id.has_value()); EXPECT_EQ(kFakeInitialRoundTripTime, new_params.initial_round_trip_time_us.value()); ASSERT_TRUE(new_params.google_connection_options.has_value()); @@ -801,7 +846,7 @@ TEST_P(TransportParametersTest, ParseServerParams) { // clang-format off const uint8_t kServerParamsOld[] = { - 0x00, 0xb7, // length of parameters array that follows + 0x00, 0xcf, // length of parameters array that follows // original_destination_connection_id 0x00, 0x00, // parameter id 0x00, 0x08, // length @@ -870,6 +915,14 @@ 0x00, 0x0e, // parameter id 0x00, 0x01, // length 0x34, // value + // initial_source_connection_id + 0x00, 0x0f, // parameter id + 0x00, 0x08, // length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45, + // retry_source_connection_id + 0x00, 0x10, // parameter id + 0x00, 0x08, // length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x76, // google_connection_options 0x31, 0x28, // parameter id 0x00, 0x0c, // length @@ -953,6 +1006,14 @@ 0x0e, // parameter id 0x01, // length 0x34, // value + // initial_source_connection_id + 0x0f, // parameter id + 0x08, // length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45, + // retry_source_connection_id + 0x10, // parameter id + 0x08, // length + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x76, // google_connection_options 0x71, 0x28, // parameter id 0x0c, // length @@ -1019,6 +1080,12 @@ new_params.preferred_address->stateless_reset_token); EXPECT_EQ(kFakeActiveConnectionIdLimit, new_params.active_connection_id_limit.value()); + ASSERT_TRUE(new_params.initial_source_connection_id.has_value()); + EXPECT_EQ(CreateFakeInitialSourceConnectionId(), + new_params.initial_source_connection_id.value()); + ASSERT_TRUE(new_params.retry_source_connection_id.has_value()); + EXPECT_EQ(CreateFakeRetrySourceConnectionId(), + new_params.retry_source_connection_id.value()); ASSERT_TRUE(new_params.google_connection_options.has_value()); EXPECT_EQ(CreateFakeGoogleConnectionOptions(), new_params.google_connection_options.value());