// Copyright (c) 2018 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "quic/core/crypto/transport_parameters.h" #include #include #include "absl/base/macros.h" #include "absl/strings/string_view.h" #include "quic/core/crypto/crypto_protocol.h" #include "quic/core/quic_connection_id.h" #include "quic/core/quic_tag.h" #include "quic/core/quic_types.h" #include "quic/core/quic_versions.h" #include "quic/platform/api/quic_expect_bug.h" #include "quic/platform/api/quic_ip_address.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_test_utils.h" namespace quic { namespace test { namespace { const QuicVersionLabel kFakeVersionLabel = 0x01234567; const QuicVersionLabel kFakeVersionLabel2 = 0x89ABCDEF; const uint64_t kFakeIdleTimeoutMilliseconds = 12012; const uint64_t kFakeInitialMaxData = 101; const uint64_t kFakeInitialMaxStreamDataBidiLocal = 2001; const uint64_t kFakeInitialMaxStreamDataBidiRemote = 2002; const uint64_t kFakeInitialMaxStreamDataUni = 3000; const uint64_t kFakeInitialMaxStreamsBidi = 21; const uint64_t kFakeInitialMaxStreamsUni = 22; const bool kFakeDisableMigration = true; const uint64_t kFakeInitialRoundTripTime = 53; const uint8_t kFakePreferredStatelessResetTokenData[16] = { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F}; const auto kCustomParameter1 = static_cast(0xffcd); const char* kCustomParameter1Value = "foo"; const auto kCustomParameter2 = static_cast(0xff34); const char* kCustomParameter2Value = "bar"; QuicConnectionId CreateFakeOriginalDestinationConnectionId() { return TestConnectionId(0x1337); } QuicConnectionId CreateFakeInitialSourceConnectionId() { return TestConnectionId(0x2345); } QuicConnectionId CreateFakeRetrySourceConnectionId() { return TestConnectionId(0x9876); } QuicConnectionId CreateFakePreferredConnectionId() { return TestConnectionId(0xBEEF); } std::vector CreateFakePreferredStatelessResetToken() { return std::vector( kFakePreferredStatelessResetTokenData, kFakePreferredStatelessResetTokenData + sizeof(kFakePreferredStatelessResetTokenData)); } QuicSocketAddress CreateFakeV4SocketAddress() { QuicIpAddress ipv4_address; if (!ipv4_address.FromString("65.66.67.68")) { // 0x41, 0x42, 0x43, 0x44 QUIC_LOG(FATAL) << "Failed to create IPv4 address"; return QuicSocketAddress(); } return QuicSocketAddress(ipv4_address, 0x4884); } QuicSocketAddress CreateFakeV6SocketAddress() { QuicIpAddress ipv6_address; if (!ipv6_address.FromString("6061:6263:6465:6667:6869:6A6B:6C6D:6E6F")) { QUIC_LOG(FATAL) << "Failed to create IPv6 address"; return QuicSocketAddress(); } return QuicSocketAddress(ipv6_address, 0x6336); } std::unique_ptr CreateFakePreferredAddress() { TransportParameters::PreferredAddress preferred_address; preferred_address.ipv4_socket_address = CreateFakeV4SocketAddress(); preferred_address.ipv6_socket_address = CreateFakeV6SocketAddress(); preferred_address.connection_id = CreateFakePreferredConnectionId(); preferred_address.stateless_reset_token = CreateFakePreferredStatelessResetToken(); return std::make_unique( preferred_address); } TransportParameters::LegacyVersionInformation CreateFakeLegacyVersionInformationClient() { TransportParameters::LegacyVersionInformation legacy_version_information; legacy_version_information.version = kFakeVersionLabel; return legacy_version_information; } TransportParameters::LegacyVersionInformation CreateFakeLegacyVersionInformationServer() { TransportParameters::LegacyVersionInformation legacy_version_information = CreateFakeLegacyVersionInformationClient(); legacy_version_information.supported_versions.push_back(kFakeVersionLabel); legacy_version_information.supported_versions.push_back(kFakeVersionLabel2); return legacy_version_information; } TransportParameters::VersionInformation CreateFakeVersionInformation() { TransportParameters::VersionInformation version_information; version_information.chosen_version = kFakeVersionLabel; version_information.other_versions.push_back(kFakeVersionLabel); version_information.other_versions.push_back(kFakeVersionLabel2); return version_information; } QuicTagVector CreateFakeGoogleConnectionOptions() { return {kALPN, MakeQuicTag('E', 'F', 'G', 0x00), MakeQuicTag('H', 'I', 'J', 0xff)}; } void RemoveGreaseParameters(TransportParameters* params) { std::vector grease_params; for (const auto& kv : params->custom_parameters) { if (kv.first % 31 == 27) { grease_params.push_back(kv.first); } } EXPECT_EQ(grease_params.size(), 1u); for (TransportParameters::TransportParameterId param_id : grease_params) { params->custom_parameters.erase(param_id); } // Remove all GREASE versions from version_information.other_versions. if (params->version_information.has_value()) { QuicVersionLabelVector& other_versions = params->version_information.value().other_versions; for (auto it = other_versions.begin(); it != other_versions.end();) { if ((*it & 0x0f0f0f0f) == 0x0a0a0a0a) { it = other_versions.erase(it); } else { ++it; } } } } } // namespace class TransportParametersTest : public QuicTestWithParam { protected: TransportParametersTest() : version_(GetParam()) {} ParsedQuicVersion version_; }; INSTANTIATE_TEST_SUITE_P(TransportParametersTests, TransportParametersTest, ::testing::ValuesIn(AllSupportedVersionsWithTls()), ::testing::PrintToStringParamName()); TEST_P(TransportParametersTest, Comparator) { TransportParameters orig_params; TransportParameters new_params; // Test comparison on primitive members. orig_params.perspective = Perspective::IS_CLIENT; new_params.perspective = Perspective::IS_SERVER; EXPECT_NE(orig_params, new_params); EXPECT_FALSE(orig_params == new_params); EXPECT_TRUE(orig_params != new_params); new_params.perspective = Perspective::IS_CLIENT; orig_params.legacy_version_information = CreateFakeLegacyVersionInformationClient(); new_params.legacy_version_information = CreateFakeLegacyVersionInformationClient(); orig_params.version_information = CreateFakeVersionInformation(); new_params.version_information = CreateFakeVersionInformation(); orig_params.disable_active_migration = true; new_params.disable_active_migration = true; EXPECT_EQ(orig_params, new_params); EXPECT_TRUE(orig_params == new_params); EXPECT_FALSE(orig_params != new_params); // Test comparison on vectors. orig_params.legacy_version_information.value().supported_versions.push_back( kFakeVersionLabel); new_params.legacy_version_information.value().supported_versions.push_back( kFakeVersionLabel2); EXPECT_NE(orig_params, new_params); EXPECT_FALSE(orig_params == new_params); EXPECT_TRUE(orig_params != new_params); new_params.legacy_version_information.value().supported_versions.pop_back(); new_params.legacy_version_information.value().supported_versions.push_back( kFakeVersionLabel); orig_params.stateless_reset_token = CreateStatelessResetTokenForTest(); new_params.stateless_reset_token = CreateStatelessResetTokenForTest(); EXPECT_EQ(orig_params, new_params); EXPECT_TRUE(orig_params == new_params); EXPECT_FALSE(orig_params != new_params); // Test comparison on IntegerParameters. orig_params.max_udp_payload_size.set_value(kMaxPacketSizeForTest); new_params.max_udp_payload_size.set_value(kMaxPacketSizeForTest + 1); EXPECT_NE(orig_params, new_params); EXPECT_FALSE(orig_params == new_params); EXPECT_TRUE(orig_params != new_params); new_params.max_udp_payload_size.set_value(kMaxPacketSizeForTest); EXPECT_EQ(orig_params, new_params); EXPECT_TRUE(orig_params == new_params); EXPECT_FALSE(orig_params != new_params); // Test comparison on PreferredAddress orig_params.preferred_address = CreateFakePreferredAddress(); EXPECT_NE(orig_params, new_params); EXPECT_FALSE(orig_params == new_params); EXPECT_TRUE(orig_params != new_params); new_params.preferred_address = CreateFakePreferredAddress(); EXPECT_EQ(orig_params, new_params); EXPECT_TRUE(orig_params == new_params); EXPECT_FALSE(orig_params != new_params); // Test comparison on CustomMap orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value; orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value; new_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value; new_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value; 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 = absl::nullopt; 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) { TransportParameters orig_params; orig_params.perspective = Perspective::IS_CLIENT; orig_params.legacy_version_information = CreateFakeLegacyVersionInformationClient(); orig_params.version_information = CreateFakeVersionInformation(); orig_params.original_destination_connection_id = CreateFakeOriginalDestinationConnectionId(); orig_params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds); orig_params.stateless_reset_token = CreateStatelessResetTokenForTest(); orig_params.max_udp_payload_size.set_value(kMaxPacketSizeForTest); orig_params.initial_max_data.set_value(kFakeInitialMaxData); orig_params.initial_max_stream_data_bidi_local.set_value( kFakeInitialMaxStreamDataBidiLocal); orig_params.initial_max_stream_data_bidi_remote.set_value( kFakeInitialMaxStreamDataBidiRemote); orig_params.initial_max_stream_data_uni.set_value( kFakeInitialMaxStreamDataUni); orig_params.initial_max_streams_bidi.set_value(kFakeInitialMaxStreamsBidi); orig_params.initial_max_streams_uni.set_value(kFakeInitialMaxStreamsUni); orig_params.ack_delay_exponent.set_value(kAckDelayExponentForTest); orig_params.max_ack_delay.set_value(kMaxAckDelayForTest); orig_params.min_ack_delay_us.set_value(kMinAckDelayUsForTest); orig_params.disable_active_migration = kFakeDisableMigration; orig_params.preferred_address = CreateFakePreferredAddress(); orig_params.active_connection_id_limit.set_value( kActiveConnectionIdLimitForTest); 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.custom_parameters[kCustomParameter1] = kCustomParameter1Value; orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value; TransportParameters new_params(orig_params); EXPECT_EQ(new_params, orig_params); } TEST_P(TransportParametersTest, RoundTripClient) { TransportParameters orig_params; orig_params.perspective = Perspective::IS_CLIENT; orig_params.legacy_version_information = CreateFakeLegacyVersionInformationClient(); if (GetQuicReloadableFlag(quic_version_information)) { orig_params.version_information = CreateFakeVersionInformation(); } orig_params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds); orig_params.max_udp_payload_size.set_value(kMaxPacketSizeForTest); orig_params.initial_max_data.set_value(kFakeInitialMaxData); orig_params.initial_max_stream_data_bidi_local.set_value( kFakeInitialMaxStreamDataBidiLocal); orig_params.initial_max_stream_data_bidi_remote.set_value( kFakeInitialMaxStreamDataBidiRemote); orig_params.initial_max_stream_data_uni.set_value( kFakeInitialMaxStreamDataUni); orig_params.initial_max_streams_bidi.set_value(kFakeInitialMaxStreamsBidi); orig_params.initial_max_streams_uni.set_value(kFakeInitialMaxStreamsUni); orig_params.ack_delay_exponent.set_value(kAckDelayExponentForTest); orig_params.max_ack_delay.set_value(kMaxAckDelayForTest); orig_params.min_ack_delay_us.set_value(kMinAckDelayUsForTest); orig_params.disable_active_migration = kFakeDisableMigration; orig_params.active_connection_id_limit.set_value( kActiveConnectionIdLimitForTest); 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.custom_parameters[kCustomParameter1] = kCustomParameter1Value; orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value; std::vector serialized; ASSERT_TRUE(SerializeTransportParameters(version_, orig_params, &serialized)); TransportParameters new_params; std::string error_details; ASSERT_TRUE(ParseTransportParameters(version_, Perspective::IS_CLIENT, serialized.data(), serialized.size(), &new_params, &error_details)) << error_details; EXPECT_TRUE(error_details.empty()); RemoveGreaseParameters(&new_params); EXPECT_EQ(new_params, orig_params); } TEST_P(TransportParametersTest, RoundTripServer) { TransportParameters orig_params; orig_params.perspective = Perspective::IS_SERVER; orig_params.legacy_version_information = CreateFakeLegacyVersionInformationServer(); if (GetQuicReloadableFlag(quic_version_information)) { orig_params.version_information = CreateFakeVersionInformation(); } orig_params.original_destination_connection_id = CreateFakeOriginalDestinationConnectionId(); orig_params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds); orig_params.stateless_reset_token = CreateStatelessResetTokenForTest(); orig_params.max_udp_payload_size.set_value(kMaxPacketSizeForTest); orig_params.initial_max_data.set_value(kFakeInitialMaxData); orig_params.initial_max_stream_data_bidi_local.set_value( kFakeInitialMaxStreamDataBidiLocal); orig_params.initial_max_stream_data_bidi_remote.set_value( kFakeInitialMaxStreamDataBidiRemote); orig_params.initial_max_stream_data_uni.set_value( kFakeInitialMaxStreamDataUni); orig_params.initial_max_streams_bidi.set_value(kFakeInitialMaxStreamsBidi); orig_params.initial_max_streams_uni.set_value(kFakeInitialMaxStreamsUni); orig_params.ack_delay_exponent.set_value(kAckDelayExponentForTest); orig_params.max_ack_delay.set_value(kMaxAckDelayForTest); orig_params.min_ack_delay_us.set_value(kMinAckDelayUsForTest); orig_params.disable_active_migration = kFakeDisableMigration; orig_params.preferred_address = CreateFakePreferredAddress(); orig_params.active_connection_id_limit.set_value( kActiveConnectionIdLimitForTest); orig_params.initial_source_connection_id = CreateFakeInitialSourceConnectionId(); orig_params.retry_source_connection_id = CreateFakeRetrySourceConnectionId(); orig_params.google_connection_options = CreateFakeGoogleConnectionOptions(); std::vector serialized; ASSERT_TRUE(SerializeTransportParameters(version_, orig_params, &serialized)); TransportParameters new_params; std::string error_details; ASSERT_TRUE(ParseTransportParameters(version_, Perspective::IS_SERVER, serialized.data(), serialized.size(), &new_params, &error_details)) << error_details; EXPECT_TRUE(error_details.empty()); RemoveGreaseParameters(&new_params); EXPECT_EQ(new_params, orig_params); } TEST_P(TransportParametersTest, AreValid) { { TransportParameters params; std::string error_details; params.perspective = Perspective::IS_CLIENT; EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); } { TransportParameters params; std::string error_details; params.perspective = Perspective::IS_CLIENT; EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds); EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); params.max_idle_timeout_ms.set_value(601000); EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); } { TransportParameters params; std::string error_details; params.perspective = Perspective::IS_CLIENT; EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); params.max_udp_payload_size.set_value(1200); EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); params.max_udp_payload_size.set_value(65535); EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); params.max_udp_payload_size.set_value(9999999); EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); params.max_udp_payload_size.set_value(0); error_details = ""; EXPECT_FALSE(params.AreValid(&error_details)); EXPECT_EQ(error_details, "Invalid transport parameters [Client max_udp_payload_size 0 " "(Invalid)]"); params.max_udp_payload_size.set_value(1199); error_details = ""; EXPECT_FALSE(params.AreValid(&error_details)); EXPECT_EQ(error_details, "Invalid transport parameters [Client max_udp_payload_size 1199 " "(Invalid)]"); } { TransportParameters params; std::string error_details; params.perspective = Perspective::IS_CLIENT; EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); params.ack_delay_exponent.set_value(0); EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); params.ack_delay_exponent.set_value(20); EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); params.ack_delay_exponent.set_value(21); EXPECT_FALSE(params.AreValid(&error_details)); EXPECT_EQ(error_details, "Invalid transport parameters [Client ack_delay_exponent 21 " "(Invalid)]"); } { TransportParameters params; std::string error_details; params.perspective = Perspective::IS_CLIENT; EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); params.active_connection_id_limit.set_value(2); EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); params.active_connection_id_limit.set_value(999999); EXPECT_TRUE(params.AreValid(&error_details)); EXPECT_TRUE(error_details.empty()); params.active_connection_id_limit.set_value(1); EXPECT_FALSE(params.AreValid(&error_details)); EXPECT_EQ(error_details, "Invalid transport parameters [Client active_connection_id_limit" " 1 (Invalid)]"); params.active_connection_id_limit.set_value(0); EXPECT_FALSE(params.AreValid(&error_details)); EXPECT_EQ(error_details, "Invalid transport parameters [Client active_connection_id_limit" " 0 (Invalid)]"); } } TEST_P(TransportParametersTest, NoClientParamsWithStatelessResetToken) { TransportParameters orig_params; orig_params.perspective = Perspective::IS_CLIENT; orig_params.legacy_version_information = CreateFakeLegacyVersionInformationClient(); orig_params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds); orig_params.stateless_reset_token = CreateStatelessResetTokenForTest(); orig_params.max_udp_payload_size.set_value(kMaxPacketSizeForTest); std::vector out; bool ok = true; EXPECT_QUIC_BUG( ok = SerializeTransportParameters(version_, orig_params, &out), "Not serializing invalid transport parameters: Client cannot send " "stateless reset token"); EXPECT_FALSE(ok); } TEST_P(TransportParametersTest, ParseClientParams) { // clang-format off const uint8_t kClientParams[] = { // max_idle_timeout 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value // max_udp_payload_size 0x03, // parameter id 0x02, // length 0x63, 0x29, // value // initial_max_data 0x04, // parameter id 0x02, // length 0x40, 0x65, // value // initial_max_stream_data_bidi_local 0x05, // parameter id 0x02, // length 0x47, 0xD1, // value // initial_max_stream_data_bidi_remote 0x06, // parameter id 0x02, // length 0x47, 0xD2, // value // initial_max_stream_data_uni 0x07, // parameter id 0x02, // length 0x4B, 0xB8, // value // initial_max_streams_bidi 0x08, // parameter id 0x01, // length 0x15, // value // initial_max_streams_uni 0x09, // parameter id 0x01, // length 0x16, // value // ack_delay_exponent 0x0a, // parameter id 0x01, // length 0x0a, // value // max_ack_delay 0x0b, // parameter id 0x01, // length 0x33, // value // min_ack_delay_us 0x80, 0x00, 0xde, 0x1a, // parameter id 0x02, // length 0x43, 0xe8, // value // disable_active_migration 0x0c, // parameter id 0x00, // length // active_connection_id_limit 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 0x35, // value // google_connection_options 0x71, 0x28, // parameter id 0x0c, // length 'A', 'L', 'P', 'N', // value 'E', 'F', 'G', 0x00, 'H', 'I', 'J', 0xff, // Google version extension 0x80, 0x00, 0x47, 0x52, // parameter id 0x04, // length 0x01, 0x23, 0x45, 0x67, // initial version // version_information 0x80, 0xFF, 0x73, 0xDB, // parameter id 0x0C, // length 0x01, 0x23, 0x45, 0x67, // chosen version 0x01, 0x23, 0x45, 0x67, // other version 1 0x89, 0xab, 0xcd, 0xef, // other version 2 }; // clang-format on const uint8_t* client_params = reinterpret_cast(kClientParams); size_t client_params_length = ABSL_ARRAYSIZE(kClientParams); TransportParameters new_params; std::string error_details; ASSERT_TRUE(ParseTransportParameters(version_, Perspective::IS_CLIENT, client_params, client_params_length, &new_params, &error_details)) << error_details; EXPECT_TRUE(error_details.empty()); EXPECT_EQ(Perspective::IS_CLIENT, new_params.perspective); ASSERT_TRUE(new_params.legacy_version_information.has_value()); EXPECT_EQ(kFakeVersionLabel, new_params.legacy_version_information.value().version); EXPECT_TRUE( new_params.legacy_version_information.value().supported_versions.empty()); if (GetQuicReloadableFlag(quic_version_information)) { ASSERT_TRUE(new_params.version_information.has_value()); EXPECT_EQ(new_params.version_information.value(), CreateFakeVersionInformation()); } EXPECT_FALSE(new_params.original_destination_connection_id.has_value()); EXPECT_EQ(kFakeIdleTimeoutMilliseconds, new_params.max_idle_timeout_ms.value()); EXPECT_TRUE(new_params.stateless_reset_token.empty()); EXPECT_EQ(kMaxPacketSizeForTest, new_params.max_udp_payload_size.value()); EXPECT_EQ(kFakeInitialMaxData, new_params.initial_max_data.value()); EXPECT_EQ(kFakeInitialMaxStreamDataBidiLocal, new_params.initial_max_stream_data_bidi_local.value()); EXPECT_EQ(kFakeInitialMaxStreamDataBidiRemote, new_params.initial_max_stream_data_bidi_remote.value()); EXPECT_EQ(kFakeInitialMaxStreamDataUni, new_params.initial_max_stream_data_uni.value()); EXPECT_EQ(kFakeInitialMaxStreamsBidi, new_params.initial_max_streams_bidi.value()); EXPECT_EQ(kFakeInitialMaxStreamsUni, new_params.initial_max_streams_uni.value()); EXPECT_EQ(kAckDelayExponentForTest, new_params.ack_delay_exponent.value()); EXPECT_EQ(kMaxAckDelayForTest, new_params.max_ack_delay.value()); EXPECT_EQ(kMinAckDelayUsForTest, new_params.min_ack_delay_us.value()); EXPECT_EQ(kFakeDisableMigration, new_params.disable_active_migration); EXPECT_EQ(kActiveConnectionIdLimitForTest, 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()); EXPECT_EQ(CreateFakeGoogleConnectionOptions(), new_params.google_connection_options.value()); } TEST_P(TransportParametersTest, ParseClientParamsFailsWithFullStatelessResetToken) { // clang-format off const uint8_t kClientParamsWithFullToken[] = { // max_idle_timeout 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value // stateless_reset_token 0x02, // parameter id 0x10, // length 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, // max_udp_payload_size 0x03, // parameter id 0x02, // length 0x63, 0x29, // value // initial_max_data 0x04, // parameter id 0x02, // length 0x40, 0x65, // value }; // clang-format on const uint8_t* client_params = reinterpret_cast(kClientParamsWithFullToken); size_t client_params_length = ABSL_ARRAYSIZE(kClientParamsWithFullToken); TransportParameters out_params; std::string error_details; EXPECT_FALSE(ParseTransportParameters(version_, Perspective::IS_CLIENT, client_params, client_params_length, &out_params, &error_details)); EXPECT_EQ(error_details, "Client cannot send stateless reset token"); } TEST_P(TransportParametersTest, ParseClientParamsFailsWithEmptyStatelessResetToken) { // clang-format off const uint8_t kClientParamsWithEmptyToken[] = { // max_idle_timeout 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value // stateless_reset_token 0x02, // parameter id 0x00, // length // max_udp_payload_size 0x03, // parameter id 0x02, // length 0x63, 0x29, // value // initial_max_data 0x04, // parameter id 0x02, // length 0x40, 0x65, // value }; // clang-format on const uint8_t* client_params = reinterpret_cast(kClientParamsWithEmptyToken); size_t client_params_length = ABSL_ARRAYSIZE(kClientParamsWithEmptyToken); TransportParameters out_params; std::string error_details; EXPECT_FALSE(ParseTransportParameters(version_, Perspective::IS_CLIENT, client_params, client_params_length, &out_params, &error_details)); EXPECT_EQ(error_details, "Received stateless_reset_token of invalid length 0"); } TEST_P(TransportParametersTest, ParseClientParametersRepeated) { // clang-format off const uint8_t kClientParamsRepeated[] = { // max_idle_timeout 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value // max_udp_payload_size 0x03, // parameter id 0x02, // length 0x63, 0x29, // value // max_idle_timeout (repeated) 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value }; // clang-format on const uint8_t* client_params = reinterpret_cast(kClientParamsRepeated); size_t client_params_length = ABSL_ARRAYSIZE(kClientParamsRepeated); TransportParameters out_params; std::string error_details; EXPECT_FALSE(ParseTransportParameters(version_, Perspective::IS_CLIENT, client_params, client_params_length, &out_params, &error_details)); EXPECT_EQ(error_details, "Received a second max_idle_timeout"); } TEST_P(TransportParametersTest, ParseServerParams) { // clang-format off const uint8_t kServerParams[] = { // original_destination_connection_id 0x00, // parameter id 0x08, // length 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37, // max_idle_timeout 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value // stateless_reset_token 0x02, // parameter id 0x10, // length 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, // max_udp_payload_size 0x03, // parameter id 0x02, // length 0x63, 0x29, // value // initial_max_data 0x04, // parameter id 0x02, // length 0x40, 0x65, // value // initial_max_stream_data_bidi_local 0x05, // parameter id 0x02, // length 0x47, 0xD1, // value // initial_max_stream_data_bidi_remote 0x06, // parameter id 0x02, // length 0x47, 0xD2, // value // initial_max_stream_data_uni 0x07, // parameter id 0x02, // length 0x4B, 0xB8, // value // initial_max_streams_bidi 0x08, // parameter id 0x01, // length 0x15, // value // initial_max_streams_uni 0x09, // parameter id 0x01, // length 0x16, // value // ack_delay_exponent 0x0a, // parameter id 0x01, // length 0x0a, // value // max_ack_delay 0x0b, // parameter id 0x01, // length 0x33, // value // min_ack_delay_us 0x80, 0x00, 0xde, 0x1a, // parameter id 0x02, // length 0x43, 0xe8, // value // disable_active_migration 0x0c, // parameter id 0x00, // length // preferred_address 0x0d, // parameter id 0x31, // length 0x41, 0x42, 0x43, 0x44, // IPv4 address 0x48, 0x84, // IPv4 port 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, // IPv6 address 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x63, 0x36, // IPv6 port 0x08, // connection ID length 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xEF, // connection ID 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, // stateless reset token 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, // active_connection_id_limit 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 'A', 'L', 'P', 'N', // value 'E', 'F', 'G', 0x00, 'H', 'I', 'J', 0xff, // Google version extension 0x80, 0x00, 0x47, 0x52, // parameter id 0x0d, // length 0x01, 0x23, 0x45, 0x67, // negotiated_version 0x08, // length of supported versions array 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // version_information 0x80, 0xFF, 0x73, 0xDB, // parameter id 0x0C, // length 0x01, 0x23, 0x45, 0x67, // chosen version 0x01, 0x23, 0x45, 0x67, // other version 1 0x89, 0xab, 0xcd, 0xef, // other version 2 }; // clang-format on const uint8_t* server_params = reinterpret_cast(kServerParams); size_t server_params_length = ABSL_ARRAYSIZE(kServerParams); TransportParameters new_params; std::string error_details; ASSERT_TRUE(ParseTransportParameters(version_, Perspective::IS_SERVER, server_params, server_params_length, &new_params, &error_details)) << error_details; EXPECT_TRUE(error_details.empty()); EXPECT_EQ(Perspective::IS_SERVER, new_params.perspective); ASSERT_TRUE(new_params.legacy_version_information.has_value()); EXPECT_EQ(kFakeVersionLabel, new_params.legacy_version_information.value().version); ASSERT_EQ( 2u, new_params.legacy_version_information.value().supported_versions.size()); EXPECT_EQ( kFakeVersionLabel, new_params.legacy_version_information.value().supported_versions[0]); EXPECT_EQ( kFakeVersionLabel2, new_params.legacy_version_information.value().supported_versions[1]); if (GetQuicReloadableFlag(quic_version_information)) { ASSERT_TRUE(new_params.version_information.has_value()); EXPECT_EQ(new_params.version_information.value(), CreateFakeVersionInformation()); } ASSERT_TRUE(new_params.original_destination_connection_id.has_value()); EXPECT_EQ(CreateFakeOriginalDestinationConnectionId(), new_params.original_destination_connection_id.value()); EXPECT_EQ(kFakeIdleTimeoutMilliseconds, new_params.max_idle_timeout_ms.value()); EXPECT_EQ(CreateStatelessResetTokenForTest(), new_params.stateless_reset_token); EXPECT_EQ(kMaxPacketSizeForTest, new_params.max_udp_payload_size.value()); EXPECT_EQ(kFakeInitialMaxData, new_params.initial_max_data.value()); EXPECT_EQ(kFakeInitialMaxStreamDataBidiLocal, new_params.initial_max_stream_data_bidi_local.value()); EXPECT_EQ(kFakeInitialMaxStreamDataBidiRemote, new_params.initial_max_stream_data_bidi_remote.value()); EXPECT_EQ(kFakeInitialMaxStreamDataUni, new_params.initial_max_stream_data_uni.value()); EXPECT_EQ(kFakeInitialMaxStreamsBidi, new_params.initial_max_streams_bidi.value()); EXPECT_EQ(kFakeInitialMaxStreamsUni, new_params.initial_max_streams_uni.value()); EXPECT_EQ(kAckDelayExponentForTest, new_params.ack_delay_exponent.value()); EXPECT_EQ(kMaxAckDelayForTest, new_params.max_ack_delay.value()); EXPECT_EQ(kMinAckDelayUsForTest, new_params.min_ack_delay_us.value()); EXPECT_EQ(kFakeDisableMigration, new_params.disable_active_migration); ASSERT_NE(nullptr, new_params.preferred_address.get()); EXPECT_EQ(CreateFakeV4SocketAddress(), new_params.preferred_address->ipv4_socket_address); EXPECT_EQ(CreateFakeV6SocketAddress(), new_params.preferred_address->ipv6_socket_address); EXPECT_EQ(CreateFakePreferredConnectionId(), new_params.preferred_address->connection_id); EXPECT_EQ(CreateFakePreferredStatelessResetToken(), new_params.preferred_address->stateless_reset_token); EXPECT_EQ(kActiveConnectionIdLimitForTest, 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()); } TEST_P(TransportParametersTest, ParseServerParametersRepeated) { // clang-format off const uint8_t kServerParamsRepeated[] = { // original_destination_connection_id 0x00, // parameter id 0x08, // length 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x37, // max_idle_timeout 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value // stateless_reset_token 0x02, // parameter id 0x10, // length 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, // max_idle_timeout (repeated) 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value }; // clang-format on const uint8_t* server_params = reinterpret_cast(kServerParamsRepeated); size_t server_params_length = ABSL_ARRAYSIZE(kServerParamsRepeated); TransportParameters out_params; std::string error_details; EXPECT_FALSE(ParseTransportParameters(version_, Perspective::IS_SERVER, server_params, server_params_length, &out_params, &error_details)); EXPECT_EQ(error_details, "Received a second max_idle_timeout"); } TEST_P(TransportParametersTest, ParseServerParametersEmptyOriginalConnectionId) { // clang-format off const uint8_t kServerParamsEmptyOriginalConnectionId[] = { // original_destination_connection_id 0x00, // parameter id 0x00, // length // max_idle_timeout 0x01, // parameter id 0x02, // length 0x6e, 0xec, // value // stateless_reset_token 0x02, // parameter id 0x10, // length 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, }; // clang-format on const uint8_t* server_params = reinterpret_cast(kServerParamsEmptyOriginalConnectionId); size_t server_params_length = ABSL_ARRAYSIZE(kServerParamsEmptyOriginalConnectionId); TransportParameters out_params; std::string error_details; ASSERT_TRUE(ParseTransportParameters(version_, Perspective::IS_SERVER, server_params, server_params_length, &out_params, &error_details)) << error_details; ASSERT_TRUE(out_params.original_destination_connection_id.has_value()); EXPECT_EQ(out_params.original_destination_connection_id.value(), EmptyQuicConnectionId()); } TEST_P(TransportParametersTest, VeryLongCustomParameter) { // Ensure we can handle a 70KB custom parameter on both send and receive. std::string custom_value(70000, '?'); TransportParameters orig_params; orig_params.perspective = Perspective::IS_CLIENT; orig_params.legacy_version_information = CreateFakeLegacyVersionInformationClient(); orig_params.custom_parameters[kCustomParameter1] = custom_value; std::vector serialized; ASSERT_TRUE(SerializeTransportParameters(version_, orig_params, &serialized)); TransportParameters new_params; std::string error_details; ASSERT_TRUE(ParseTransportParameters(version_, Perspective::IS_CLIENT, serialized.data(), serialized.size(), &new_params, &error_details)) << error_details; EXPECT_TRUE(error_details.empty()); RemoveGreaseParameters(&new_params); EXPECT_EQ(new_params, orig_params); } TEST_P(TransportParametersTest, SerializationOrderIsRandom) { TransportParameters orig_params; orig_params.perspective = Perspective::IS_CLIENT; orig_params.legacy_version_information = CreateFakeLegacyVersionInformationClient(); orig_params.max_idle_timeout_ms.set_value(kFakeIdleTimeoutMilliseconds); orig_params.max_udp_payload_size.set_value(kMaxPacketSizeForTest); orig_params.initial_max_data.set_value(kFakeInitialMaxData); orig_params.initial_max_stream_data_bidi_local.set_value( kFakeInitialMaxStreamDataBidiLocal); orig_params.initial_max_stream_data_bidi_remote.set_value( kFakeInitialMaxStreamDataBidiRemote); orig_params.initial_max_stream_data_uni.set_value( kFakeInitialMaxStreamDataUni); orig_params.initial_max_streams_bidi.set_value(kFakeInitialMaxStreamsBidi); orig_params.initial_max_streams_uni.set_value(kFakeInitialMaxStreamsUni); orig_params.ack_delay_exponent.set_value(kAckDelayExponentForTest); orig_params.max_ack_delay.set_value(kMaxAckDelayForTest); orig_params.min_ack_delay_us.set_value(kMinAckDelayUsForTest); orig_params.disable_active_migration = kFakeDisableMigration; orig_params.active_connection_id_limit.set_value( kActiveConnectionIdLimitForTest); 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.custom_parameters[kCustomParameter1] = kCustomParameter1Value; orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value; std::vector first_serialized; ASSERT_TRUE( SerializeTransportParameters(version_, orig_params, &first_serialized)); // Test that a subsequent serialization is different from the first. // Run in a loop to avoid a failure in the unlikely event that randomization // produces the same result multiple times. for (int i = 0; i < 1000; i++) { std::vector serialized; ASSERT_TRUE( SerializeTransportParameters(version_, orig_params, &serialized)); if (serialized != first_serialized) { return; } } } class TransportParametersTicketSerializationTest : public QuicTest { protected: void SetUp() override { original_params_.perspective = Perspective::IS_SERVER; original_params_.legacy_version_information = CreateFakeLegacyVersionInformationServer(); original_params_.original_destination_connection_id = CreateFakeOriginalDestinationConnectionId(); original_params_.max_idle_timeout_ms.set_value( kFakeIdleTimeoutMilliseconds); original_params_.stateless_reset_token = CreateStatelessResetTokenForTest(); original_params_.max_udp_payload_size.set_value(kMaxPacketSizeForTest); original_params_.initial_max_data.set_value(kFakeInitialMaxData); original_params_.initial_max_stream_data_bidi_local.set_value( kFakeInitialMaxStreamDataBidiLocal); original_params_.initial_max_stream_data_bidi_remote.set_value( kFakeInitialMaxStreamDataBidiRemote); original_params_.initial_max_stream_data_uni.set_value( kFakeInitialMaxStreamDataUni); original_params_.initial_max_streams_bidi.set_value( kFakeInitialMaxStreamsBidi); original_params_.initial_max_streams_uni.set_value( kFakeInitialMaxStreamsUni); original_params_.ack_delay_exponent.set_value(kAckDelayExponentForTest); original_params_.max_ack_delay.set_value(kMaxAckDelayForTest); original_params_.min_ack_delay_us.set_value(kMinAckDelayUsForTest); original_params_.disable_active_migration = kFakeDisableMigration; original_params_.preferred_address = CreateFakePreferredAddress(); original_params_.active_connection_id_limit.set_value( kActiveConnectionIdLimitForTest); original_params_.initial_source_connection_id = CreateFakeInitialSourceConnectionId(); original_params_.retry_source_connection_id = CreateFakeRetrySourceConnectionId(); original_params_.google_connection_options = CreateFakeGoogleConnectionOptions(); ASSERT_TRUE(SerializeTransportParametersForTicket( original_params_, application_state_, &original_serialized_params_)); } TransportParameters original_params_; std::vector application_state_ = {0, 1}; std::vector original_serialized_params_; }; TEST_F(TransportParametersTicketSerializationTest, StatelessResetTokenDoesntChangeOutput) { // Test that changing the stateless reset token doesn't change the ticket // serialization. TransportParameters new_params = original_params_; new_params.stateless_reset_token = CreateFakePreferredStatelessResetToken(); EXPECT_NE(new_params, original_params_); std::vector serialized; ASSERT_TRUE(SerializeTransportParametersForTicket( new_params, application_state_, &serialized)); EXPECT_EQ(original_serialized_params_, serialized); } TEST_F(TransportParametersTicketSerializationTest, ConnectionIDDoesntChangeOutput) { // Changing original destination CID doesn't change serialization. TransportParameters new_params = original_params_; new_params.original_destination_connection_id = TestConnectionId(0xCAFE); EXPECT_NE(new_params, original_params_); std::vector serialized; ASSERT_TRUE(SerializeTransportParametersForTicket( new_params, application_state_, &serialized)); EXPECT_EQ(original_serialized_params_, serialized); } TEST_F(TransportParametersTicketSerializationTest, StreamLimitChangesOutput) { // Changing a stream limit does change the serialization. TransportParameters new_params = original_params_; new_params.initial_max_stream_data_bidi_local.set_value( kFakeInitialMaxStreamDataBidiLocal + 1); EXPECT_NE(new_params, original_params_); std::vector serialized; ASSERT_TRUE(SerializeTransportParametersForTicket( new_params, application_state_, &serialized)); EXPECT_NE(original_serialized_params_, serialized); } TEST_F(TransportParametersTicketSerializationTest, ApplicationStateChangesOutput) { // Changing the application state changes the serialization. std::vector new_application_state = {0}; EXPECT_NE(new_application_state, application_state_); std::vector serialized; ASSERT_TRUE(SerializeTransportParametersForTicket( original_params_, new_application_state, &serialized)); EXPECT_NE(original_serialized_params_, serialized); } } // namespace test } // namespace quic