blob: c9df18a3d8afa12154e81f468c71e2fac3e96c65 [file] [log] [blame]
// 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 <cstring>
#include <utility>
#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<TransportParameters::TransportParameterId>(0xffcd);
const char* kCustomParameter1Value = "foo";
const auto kCustomParameter2 =
static_cast<TransportParameters::TransportParameterId>(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<uint8_t> CreateFakePreferredStatelessResetToken() {
return std::vector<uint8_t>(
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<TransportParameters::PreferredAddress>
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<TransportParameters::PreferredAddress>(
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<TransportParameters::TransportParameterId> 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<ParsedQuicVersion> {
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<uint8_t> 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<uint8_t> 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<uint8_t> 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<const uint8_t*>(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<const uint8_t*>(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<const uint8_t*>(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<const uint8_t*>(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<const uint8_t*>(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<const uint8_t*>(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<const uint8_t*>(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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> application_state_ = {0, 1};
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> new_application_state = {0};
EXPECT_NE(new_application_state, application_state_);
std::vector<uint8_t> serialized;
ASSERT_TRUE(SerializeTransportParametersForTicket(
original_params_, new_application_state, &serialized));
EXPECT_NE(original_serialized_params_, serialized);
}
} // namespace test
} // namespace quic