summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc')
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc1604
1 files changed, 0 insertions, 1604 deletions
diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc
deleted file mode 100644
index 0d828db2d2b..00000000000
--- a/chromium/net/third_party/quiche/src/quic/core/crypto/transport_parameters.cc
+++ /dev/null
@@ -1,1604 +0,0 @@
-// 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 <cstdint>
-#include <cstring>
-#include <forward_list>
-#include <memory>
-#include <utility>
-
-#include "absl/strings/escaping.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/string_view.h"
-#include "third_party/boringssl/src/include/openssl/digest.h"
-#include "third_party/boringssl/src/include/openssl/sha.h"
-#include "quic/core/quic_connection_id.h"
-#include "quic/core/quic_data_reader.h"
-#include "quic/core/quic_data_writer.h"
-#include "quic/core/quic_types.h"
-#include "quic/core/quic_utils.h"
-#include "quic/core/quic_versions.h"
-#include "quic/platform/api/quic_bug_tracker.h"
-#include "quic/platform/api/quic_flag_utils.h"
-
-namespace quic {
-
-// Values of the TransportParameterId enum as defined in the
-// "Transport Parameter Encoding" section of draft-ietf-quic-transport.
-// When parameters are encoded, one of these enum values is used to indicate
-// which parameter is encoded. The supported draft version is noted in
-// transport_parameters.h.
-enum TransportParameters::TransportParameterId : uint64_t {
- kOriginalDestinationConnectionId = 0,
- kMaxIdleTimeout = 1,
- kStatelessResetToken = 2,
- kMaxPacketSize = 3,
- kInitialMaxData = 4,
- kInitialMaxStreamDataBidiLocal = 5,
- kInitialMaxStreamDataBidiRemote = 6,
- kInitialMaxStreamDataUni = 7,
- kInitialMaxStreamsBidi = 8,
- kInitialMaxStreamsUni = 9,
- kAckDelayExponent = 0xa,
- kMaxAckDelay = 0xb,
- kDisableActiveMigration = 0xc,
- kPreferredAddress = 0xd,
- kActiveConnectionIdLimit = 0xe,
- kInitialSourceConnectionId = 0xf,
- kRetrySourceConnectionId = 0x10,
-
- kMaxDatagramFrameSize = 0x20,
-
- kInitialRoundTripTime = 0x3127,
- kGoogleConnectionOptions = 0x3128,
- // 0x3129 was used to convey the user agent string.
- // 0x312A was used only in T050 to indicate support for HANDSHAKE_DONE.
- // 0x312B was used to indicate that QUIC+TLS key updates were not supported.
- // 0x4751 was used for non-standard Google-specific parameters encoded as a
- // Google QUIC_CRYPTO CHLO, it has been replaced by individual parameters.
- kGoogleQuicVersion =
- 0x4752, // Used to transmit version and supported_versions.
-
- kMinAckDelay = 0xDE1A, // draft-iyengar-quic-delayed-ack.
- kVersionInformation = 0xFF73DB, // draft-ietf-quic-version-negotiation.
-};
-
-namespace {
-
-// The following constants define minimum and maximum allowed values for some of
-// the parameters. These come from the "Transport Parameter Definitions"
-// section of draft-ietf-quic-transport.
-constexpr uint64_t kMinMaxPacketSizeTransportParam = 1200;
-constexpr uint64_t kMaxAckDelayExponentTransportParam = 20;
-constexpr uint64_t kDefaultAckDelayExponentTransportParam = 3;
-constexpr uint64_t kMaxMaxAckDelayTransportParam = 16383;
-constexpr uint64_t kDefaultMaxAckDelayTransportParam = 25;
-constexpr uint64_t kMinActiveConnectionIdLimitTransportParam = 2;
-constexpr uint64_t kDefaultActiveConnectionIdLimitTransportParam = 2;
-
-std::string TransportParameterIdToString(
- TransportParameters::TransportParameterId param_id) {
- switch (param_id) {
- case TransportParameters::kOriginalDestinationConnectionId:
- return "original_destination_connection_id";
- case TransportParameters::kMaxIdleTimeout:
- return "max_idle_timeout";
- case TransportParameters::kStatelessResetToken:
- return "stateless_reset_token";
- case TransportParameters::kMaxPacketSize:
- return "max_udp_payload_size";
- case TransportParameters::kInitialMaxData:
- return "initial_max_data";
- case TransportParameters::kInitialMaxStreamDataBidiLocal:
- return "initial_max_stream_data_bidi_local";
- case TransportParameters::kInitialMaxStreamDataBidiRemote:
- return "initial_max_stream_data_bidi_remote";
- case TransportParameters::kInitialMaxStreamDataUni:
- return "initial_max_stream_data_uni";
- case TransportParameters::kInitialMaxStreamsBidi:
- return "initial_max_streams_bidi";
- case TransportParameters::kInitialMaxStreamsUni:
- return "initial_max_streams_uni";
- case TransportParameters::kAckDelayExponent:
- return "ack_delay_exponent";
- case TransportParameters::kMaxAckDelay:
- return "max_ack_delay";
- case TransportParameters::kDisableActiveMigration:
- return "disable_active_migration";
- case TransportParameters::kPreferredAddress:
- 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:
- return "initial_round_trip_time";
- case TransportParameters::kGoogleConnectionOptions:
- return "google_connection_options";
- case TransportParameters::kGoogleQuicVersion:
- return "google-version";
- case TransportParameters::kMinAckDelay:
- return "min_ack_delay_us";
- case TransportParameters::kVersionInformation:
- return "version_information";
- }
- return absl::StrCat("Unknown(", param_id, ")");
-}
-
-bool TransportParameterIdIsKnown(
- TransportParameters::TransportParameterId param_id) {
- switch (param_id) {
- case TransportParameters::kOriginalDestinationConnectionId:
- case TransportParameters::kMaxIdleTimeout:
- case TransportParameters::kStatelessResetToken:
- case TransportParameters::kMaxPacketSize:
- case TransportParameters::kInitialMaxData:
- case TransportParameters::kInitialMaxStreamDataBidiLocal:
- case TransportParameters::kInitialMaxStreamDataBidiRemote:
- case TransportParameters::kInitialMaxStreamDataUni:
- case TransportParameters::kInitialMaxStreamsBidi:
- case TransportParameters::kInitialMaxStreamsUni:
- case TransportParameters::kAckDelayExponent:
- case TransportParameters::kMaxAckDelay:
- case TransportParameters::kDisableActiveMigration:
- case TransportParameters::kPreferredAddress:
- case TransportParameters::kActiveConnectionIdLimit:
- case TransportParameters::kInitialSourceConnectionId:
- case TransportParameters::kRetrySourceConnectionId:
- case TransportParameters::kMaxDatagramFrameSize:
- case TransportParameters::kInitialRoundTripTime:
- case TransportParameters::kGoogleConnectionOptions:
- case TransportParameters::kGoogleQuicVersion:
- case TransportParameters::kMinAckDelay:
- return true;
- case TransportParameters::kVersionInformation:
- return GetQuicReloadableFlag(quic_version_information);
- }
- return false;
-}
-
-} // namespace
-
-TransportParameters::IntegerParameter::IntegerParameter(
- TransportParameters::TransportParameterId param_id,
- uint64_t default_value,
- uint64_t min_value,
- uint64_t max_value)
- : param_id_(param_id),
- value_(default_value),
- default_value_(default_value),
- min_value_(min_value),
- max_value_(max_value),
- has_been_read_(false) {
- QUICHE_DCHECK_LE(min_value, default_value);
- QUICHE_DCHECK_LE(default_value, max_value);
- QUICHE_DCHECK_LE(max_value, kVarInt62MaxValue);
-}
-
-TransportParameters::IntegerParameter::IntegerParameter(
- TransportParameters::TransportParameterId param_id)
- : TransportParameters::IntegerParameter::IntegerParameter(
- param_id,
- 0,
- 0,
- kVarInt62MaxValue) {}
-
-void TransportParameters::IntegerParameter::set_value(uint64_t value) {
- value_ = value;
-}
-
-uint64_t TransportParameters::IntegerParameter::value() const {
- return value_;
-}
-
-bool TransportParameters::IntegerParameter::IsValid() const {
- return min_value_ <= value_ && value_ <= max_value_;
-}
-
-bool TransportParameters::IntegerParameter::Write(
- QuicDataWriter* writer) const {
- QUICHE_DCHECK(IsValid());
- if (value_ == default_value_) {
- // Do not write if the value is default.
- return true;
- }
- if (!writer->WriteVarInt62(param_id_)) {
- QUIC_BUG(quic_bug_10743_1) << "Failed to write param_id for " << *this;
- return false;
- }
- const QuicVariableLengthIntegerLength value_length =
- QuicDataWriter::GetVarInt62Len(value_);
- if (!writer->WriteVarInt62(value_length)) {
- QUIC_BUG(quic_bug_10743_2) << "Failed to write value_length for " << *this;
- return false;
- }
- if (!writer->WriteVarInt62(value_, value_length)) {
- QUIC_BUG(quic_bug_10743_3) << "Failed to write value for " << *this;
- return false;
- }
- return true;
-}
-
-bool TransportParameters::IntegerParameter::Read(QuicDataReader* reader,
- std::string* error_details) {
- if (has_been_read_) {
- *error_details =
- "Received a second " + TransportParameterIdToString(param_id_);
- return false;
- }
- has_been_read_ = true;
-
- if (!reader->ReadVarInt62(&value_)) {
- *error_details =
- "Failed to parse value for " + TransportParameterIdToString(param_id_);
- return false;
- }
- if (!reader->IsDoneReading()) {
- *error_details =
- absl::StrCat("Received unexpected ", reader->BytesRemaining(),
- " bytes after parsing ", this->ToString(false));
- return false;
- }
- return true;
-}
-
-std::string TransportParameters::IntegerParameter::ToString(
- bool for_use_in_list) const {
- if (for_use_in_list && value_ == default_value_) {
- return "";
- }
- std::string rv = for_use_in_list ? " " : "";
- absl::StrAppend(&rv, TransportParameterIdToString(param_id_), " ", value_);
- if (!IsValid()) {
- rv += " (Invalid)";
- }
- return rv;
-}
-
-std::ostream& operator<<(std::ostream& os,
- const TransportParameters::IntegerParameter& param) {
- os << param.ToString(/*for_use_in_list=*/false);
- return os;
-}
-
-TransportParameters::PreferredAddress::PreferredAddress()
- : ipv4_socket_address(QuicIpAddress::Any4(), 0),
- ipv6_socket_address(QuicIpAddress::Any6(), 0),
- connection_id(EmptyQuicConnectionId()),
- stateless_reset_token(kStatelessResetTokenLength, 0) {}
-
-TransportParameters::PreferredAddress::~PreferredAddress() {}
-
-bool TransportParameters::PreferredAddress::operator==(
- const PreferredAddress& rhs) const {
- return ipv4_socket_address == rhs.ipv4_socket_address &&
- ipv6_socket_address == rhs.ipv6_socket_address &&
- connection_id == rhs.connection_id &&
- stateless_reset_token == rhs.stateless_reset_token;
-}
-
-bool TransportParameters::PreferredAddress::operator!=(
- const PreferredAddress& rhs) const {
- return !(*this == rhs);
-}
-
-std::ostream& operator<<(
- std::ostream& os,
- const TransportParameters::PreferredAddress& preferred_address) {
- os << preferred_address.ToString();
- return os;
-}
-
-std::string TransportParameters::PreferredAddress::ToString() const {
- return "[" + ipv4_socket_address.ToString() + " " +
- ipv6_socket_address.ToString() + " connection_id " +
- connection_id.ToString() + " stateless_reset_token " +
- absl::BytesToHexString(absl::string_view(
- reinterpret_cast<const char*>(stateless_reset_token.data()),
- stateless_reset_token.size())) +
- "]";
-}
-
-TransportParameters::LegacyVersionInformation::LegacyVersionInformation()
- : version(0) {}
-
-bool TransportParameters::LegacyVersionInformation::operator==(
- const LegacyVersionInformation& rhs) const {
- return version == rhs.version && supported_versions == rhs.supported_versions;
-}
-
-bool TransportParameters::LegacyVersionInformation::operator!=(
- const LegacyVersionInformation& rhs) const {
- return !(*this == rhs);
-}
-
-std::string TransportParameters::LegacyVersionInformation::ToString() const {
- std::string rv =
- absl::StrCat("legacy[version ", QuicVersionLabelToString(version));
- if (!supported_versions.empty()) {
- absl::StrAppend(&rv,
- " supported_versions " +
- QuicVersionLabelVectorToString(supported_versions));
- }
- absl::StrAppend(&rv, "]");
- return rv;
-}
-
-std::ostream& operator<<(std::ostream& os,
- const TransportParameters::LegacyVersionInformation&
- legacy_version_information) {
- os << legacy_version_information.ToString();
- return os;
-}
-
-TransportParameters::VersionInformation::VersionInformation()
- : chosen_version(0) {}
-
-bool TransportParameters::VersionInformation::operator==(
- const VersionInformation& rhs) const {
- return chosen_version == rhs.chosen_version &&
- other_versions == rhs.other_versions;
-}
-
-bool TransportParameters::VersionInformation::operator!=(
- const VersionInformation& rhs) const {
- return !(*this == rhs);
-}
-
-std::string TransportParameters::VersionInformation::ToString() const {
- std::string rv = absl::StrCat("[chosen_version ",
- QuicVersionLabelToString(chosen_version));
- if (!other_versions.empty()) {
- absl::StrAppend(&rv, " other_versions " +
- QuicVersionLabelVectorToString(other_versions));
- }
- absl::StrAppend(&rv, "]");
- return rv;
-}
-
-std::ostream& operator<<(
- std::ostream& os,
- const TransportParameters::VersionInformation& version_information) {
- os << version_information.ToString();
- return os;
-}
-
-std::ostream& operator<<(std::ostream& os, const TransportParameters& params) {
- os << params.ToString();
- return os;
-}
-
-std::string TransportParameters::ToString() const {
- std::string rv = "[";
- if (perspective == Perspective::IS_SERVER) {
- rv += "Server";
- } else {
- rv += "Client";
- }
- if (legacy_version_information.has_value()) {
- rv += " " + legacy_version_information.value().ToString();
- }
- if (version_information.has_value()) {
- rv += " " + version_information.value().ToString();
- }
- if (original_destination_connection_id.has_value()) {
- rv += " " + TransportParameterIdToString(kOriginalDestinationConnectionId) +
- " " + original_destination_connection_id.value().ToString();
- }
- rv += max_idle_timeout_ms.ToString(/*for_use_in_list=*/true);
- if (!stateless_reset_token.empty()) {
- rv += " " + TransportParameterIdToString(kStatelessResetToken) + " " +
- absl::BytesToHexString(absl::string_view(
- reinterpret_cast<const char*>(stateless_reset_token.data()),
- stateless_reset_token.size()));
- }
- rv += max_udp_payload_size.ToString(/*for_use_in_list=*/true);
- rv += initial_max_data.ToString(/*for_use_in_list=*/true);
- rv += initial_max_stream_data_bidi_local.ToString(/*for_use_in_list=*/true);
- rv += initial_max_stream_data_bidi_remote.ToString(/*for_use_in_list=*/true);
- rv += initial_max_stream_data_uni.ToString(/*for_use_in_list=*/true);
- rv += initial_max_streams_bidi.ToString(/*for_use_in_list=*/true);
- rv += initial_max_streams_uni.ToString(/*for_use_in_list=*/true);
- rv += ack_delay_exponent.ToString(/*for_use_in_list=*/true);
- rv += max_ack_delay.ToString(/*for_use_in_list=*/true);
- rv += min_ack_delay_us.ToString(/*for_use_in_list=*/true);
- if (disable_active_migration) {
- rv += " " + TransportParameterIdToString(kDisableActiveMigration);
- }
- if (preferred_address) {
- rv += " " + TransportParameterIdToString(kPreferredAddress) + " " +
- 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()) {
- rv += " " + TransportParameterIdToString(kGoogleConnectionOptions) + " ";
- bool first = true;
- for (const QuicTag& connection_option : google_connection_options.value()) {
- if (first) {
- first = false;
- } else {
- rv += ",";
- }
- rv += QuicTagToString(connection_option);
- }
- }
- for (const auto& kv : custom_parameters) {
- absl::StrAppend(&rv, " 0x", absl::Hex(static_cast<uint32_t>(kv.first)),
- "=");
- static constexpr size_t kMaxPrintableLength = 32;
- if (kv.second.length() <= kMaxPrintableLength) {
- rv += absl::BytesToHexString(kv.second);
- } else {
- absl::string_view truncated(kv.second.data(), kMaxPrintableLength);
- rv += absl::StrCat(absl::BytesToHexString(truncated), "...(length ",
- kv.second.length(), ")");
- }
- }
- rv += "]";
- return rv;
-}
-
-TransportParameters::TransportParameters()
- : max_idle_timeout_ms(kMaxIdleTimeout),
- max_udp_payload_size(kMaxPacketSize, kDefaultMaxPacketSizeTransportParam,
- kMinMaxPacketSizeTransportParam, kVarInt62MaxValue),
- initial_max_data(kInitialMaxData),
- initial_max_stream_data_bidi_local(kInitialMaxStreamDataBidiLocal),
- initial_max_stream_data_bidi_remote(kInitialMaxStreamDataBidiRemote),
- initial_max_stream_data_uni(kInitialMaxStreamDataUni),
- initial_max_streams_bidi(kInitialMaxStreamsBidi),
- initial_max_streams_uni(kInitialMaxStreamsUni),
- ack_delay_exponent(kAckDelayExponent,
- kDefaultAckDelayExponentTransportParam, 0,
- kMaxAckDelayExponentTransportParam),
- max_ack_delay(kMaxAckDelay, kDefaultMaxAckDelayTransportParam, 0,
- kMaxMaxAckDelayTransportParam),
- min_ack_delay_us(kMinAckDelay, 0, 0,
- kMaxMaxAckDelayTransportParam * kNumMicrosPerMilli),
- disable_active_migration(false),
- active_connection_id_limit(kActiveConnectionIdLimit,
- kDefaultActiveConnectionIdLimitTransportParam,
- kMinActiveConnectionIdLimitTransportParam,
- kVarInt62MaxValue),
- max_datagram_frame_size(kMaxDatagramFrameSize),
- initial_round_trip_time_us(kInitialRoundTripTime)
-// Important note: any new transport parameters must be added
-// to TransportParameters::AreValid, SerializeTransportParameters and
-// ParseTransportParameters, TransportParameters's custom copy constructor, the
-// operator==, and TransportParametersTest.Comparator.
-{}
-
-TransportParameters::TransportParameters(const TransportParameters& other)
- : perspective(other.perspective),
- legacy_version_information(other.legacy_version_information),
- version_information(other.version_information),
- original_destination_connection_id(
- other.original_destination_connection_id),
- max_idle_timeout_ms(other.max_idle_timeout_ms),
- stateless_reset_token(other.stateless_reset_token),
- max_udp_payload_size(other.max_udp_payload_size),
- initial_max_data(other.initial_max_data),
- initial_max_stream_data_bidi_local(
- other.initial_max_stream_data_bidi_local),
- initial_max_stream_data_bidi_remote(
- other.initial_max_stream_data_bidi_remote),
- initial_max_stream_data_uni(other.initial_max_stream_data_uni),
- initial_max_streams_bidi(other.initial_max_streams_bidi),
- initial_max_streams_uni(other.initial_max_streams_uni),
- ack_delay_exponent(other.ack_delay_exponent),
- max_ack_delay(other.max_ack_delay),
- min_ack_delay_us(other.min_ack_delay_us),
- 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),
- custom_parameters(other.custom_parameters) {
- if (other.preferred_address) {
- preferred_address = std::make_unique<TransportParameters::PreferredAddress>(
- *other.preferred_address);
- }
-}
-
-bool TransportParameters::operator==(const TransportParameters& rhs) const {
- if (!(perspective == rhs.perspective &&
- legacy_version_information == rhs.legacy_version_information &&
- version_information == rhs.version_information &&
- original_destination_connection_id ==
- rhs.original_destination_connection_id &&
- max_idle_timeout_ms.value() == rhs.max_idle_timeout_ms.value() &&
- stateless_reset_token == rhs.stateless_reset_token &&
- max_udp_payload_size.value() == rhs.max_udp_payload_size.value() &&
- initial_max_data.value() == rhs.initial_max_data.value() &&
- initial_max_stream_data_bidi_local.value() ==
- rhs.initial_max_stream_data_bidi_local.value() &&
- initial_max_stream_data_bidi_remote.value() ==
- rhs.initial_max_stream_data_bidi_remote.value() &&
- initial_max_stream_data_uni.value() ==
- rhs.initial_max_stream_data_uni.value() &&
- initial_max_streams_bidi.value() ==
- rhs.initial_max_streams_bidi.value() &&
- initial_max_streams_uni.value() ==
- rhs.initial_max_streams_uni.value() &&
- ack_delay_exponent.value() == rhs.ack_delay_exponent.value() &&
- max_ack_delay.value() == rhs.max_ack_delay.value() &&
- min_ack_delay_us.value() == rhs.min_ack_delay_us.value() &&
- 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() ==
- rhs.initial_round_trip_time_us.value() &&
- google_connection_options == rhs.google_connection_options &&
- custom_parameters == rhs.custom_parameters)) {
- return false;
- }
-
- if ((!preferred_address && rhs.preferred_address) ||
- (preferred_address && !rhs.preferred_address)) {
- return false;
- }
- if (preferred_address && rhs.preferred_address &&
- *preferred_address != *rhs.preferred_address) {
- return false;
- }
-
- return true;
-}
-
-bool TransportParameters::operator!=(const TransportParameters& rhs) const {
- return !(*this == rhs);
-}
-
-bool TransportParameters::AreValid(std::string* error_details) const {
- QUICHE_DCHECK(perspective == Perspective::IS_CLIENT ||
- perspective == Perspective::IS_SERVER);
- if (perspective == Perspective::IS_CLIENT && !stateless_reset_token.empty()) {
- *error_details = "Client cannot send stateless reset token";
- return false;
- }
- if (perspective == Perspective::IS_CLIENT &&
- original_destination_connection_id.has_value()) {
- *error_details = "Client cannot send original_destination_connection_id";
- return false;
- }
- if (!stateless_reset_token.empty() &&
- stateless_reset_token.size() != kStatelessResetTokenLength) {
- *error_details = absl::StrCat("Stateless reset token has bad length ",
- stateless_reset_token.size());
- return false;
- }
- if (perspective == Perspective::IS_CLIENT && preferred_address) {
- *error_details = "Client cannot send preferred address";
- return false;
- }
- if (preferred_address && preferred_address->stateless_reset_token.size() !=
- kStatelessResetTokenLength) {
- *error_details =
- absl::StrCat("Preferred address stateless reset token has bad length ",
- preferred_address->stateless_reset_token.size());
- return false;
- }
- if (preferred_address &&
- (!preferred_address->ipv4_socket_address.host().IsIPv4() ||
- !preferred_address->ipv6_socket_address.host().IsIPv6())) {
- QUIC_BUG(quic_bug_10743_4) << "Preferred address family failure";
- *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 = absl::StrCat("Using custom_parameters with known ID ",
- TransportParameterIdToString(kv.first),
- " is not allowed");
- return false;
- }
- }
- if (perspective == Perspective::IS_SERVER &&
- initial_round_trip_time_us.value() > 0) {
- *error_details = "Server cannot send initial round trip time";
- return false;
- }
- if (version_information.has_value()) {
- const QuicVersionLabel& chosen_version =
- version_information.value().chosen_version;
- const QuicVersionLabelVector& other_versions =
- version_information.value().other_versions;
- if (chosen_version == 0) {
- *error_details = "Invalid chosen version";
- return false;
- }
- if (perspective == Perspective::IS_CLIENT &&
- std::find(other_versions.begin(), other_versions.end(),
- chosen_version) == other_versions.end()) {
- // When sent by the client, chosen_version needs to be present in
- // other_versions because other_versions lists the compatible versions and
- // the chosen version is part of that list. When sent by the server,
- // other_version contains the list of fully-deployed versions which is
- // generally equal to the list of supported versions but can slightly
- // differ during removal of versions across a server fleet. See
- // draft-ietf-quic-version-negotiation for details.
- *error_details = "Client chosen version not in other versions";
- return false;
- }
- }
- const bool ok =
- max_idle_timeout_ms.IsValid() && max_udp_payload_size.IsValid() &&
- initial_max_data.IsValid() &&
- initial_max_stream_data_bidi_local.IsValid() &&
- initial_max_stream_data_bidi_remote.IsValid() &&
- initial_max_stream_data_uni.IsValid() &&
- initial_max_streams_bidi.IsValid() && initial_max_streams_uni.IsValid() &&
- ack_delay_exponent.IsValid() && max_ack_delay.IsValid() &&
- min_ack_delay_us.IsValid() && active_connection_id_limit.IsValid() &&
- max_datagram_frame_size.IsValid() && initial_round_trip_time_us.IsValid();
- if (!ok) {
- *error_details = "Invalid transport parameters " + this->ToString();
- }
- return ok;
-}
-
-TransportParameters::~TransportParameters() = default;
-
-bool SerializeTransportParameters(ParsedQuicVersion /*version*/,
- const TransportParameters& in,
- std::vector<uint8_t>* out) {
- std::string error_details;
- if (!in.AreValid(&error_details)) {
- QUIC_BUG(invalid transport parameters)
- << "Not serializing invalid transport parameters: " << error_details;
- return false;
- }
- if (!in.legacy_version_information.has_value() ||
- in.legacy_version_information.value().version == 0 ||
- (in.perspective == Perspective::IS_SERVER &&
- in.legacy_version_information.value().supported_versions.empty())) {
- QUIC_BUG(missing versions) << "Refusing to serialize without versions";
- return false;
- }
- TransportParameters::ParameterMap custom_parameters = in.custom_parameters;
- for (const auto& kv : custom_parameters) {
- if (kv.first % 31 == 27) {
- // See the "Reserved Transport Parameters" section of RFC 9000.
- QUIC_BUG(custom_parameters with GREASE)
- << "Serializing custom_parameters with GREASE ID " << kv.first
- << " is not allowed";
- return false;
- }
- }
-
- // Maximum length of the GREASE transport parameter (see below).
- static constexpr size_t kMaxGreaseLength = 16;
-
- // Empirically transport parameters generally fit within 128 bytes, but we
- // need to allocate the size up front. Integer transport parameters
- // have a maximum encoded length of 24 bytes (3 variable length integers),
- // other transport parameters have a length of 16 + the maximum value length.
- static constexpr size_t kTypeAndValueLength = 2 * sizeof(uint64_t);
- static constexpr size_t kIntegerParameterLength =
- kTypeAndValueLength + sizeof(uint64_t);
- static constexpr size_t kStatelessResetParameterLength =
- kTypeAndValueLength + 16 /* stateless reset token length */;
- static constexpr size_t kConnectionIdParameterLength =
- kTypeAndValueLength + 255 /* maximum connection ID length */;
- static constexpr size_t kPreferredAddressParameterLength =
- kTypeAndValueLength + 4 /*IPv4 address */ + 2 /* IPv4 port */ +
- 16 /* IPv6 address */ + 1 /* Connection ID length */ +
- 255 /* maximum connection ID length */ + 16 /* stateless reset token */;
- static constexpr size_t kKnownTransportParamLength =
- kConnectionIdParameterLength + // original_destination_connection_id
- kIntegerParameterLength + // max_idle_timeout
- kStatelessResetParameterLength + // stateless_reset_token
- kIntegerParameterLength + // max_udp_payload_size
- kIntegerParameterLength + // initial_max_data
- kIntegerParameterLength + // initial_max_stream_data_bidi_local
- kIntegerParameterLength + // initial_max_stream_data_bidi_remote
- kIntegerParameterLength + // initial_max_stream_data_uni
- kIntegerParameterLength + // initial_max_streams_bidi
- kIntegerParameterLength + // initial_max_streams_uni
- kIntegerParameterLength + // ack_delay_exponent
- kIntegerParameterLength + // max_ack_delay
- kIntegerParameterLength + // min_ack_delay_us
- 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
- kTypeAndValueLength; // google-version
-
- std::vector<TransportParameters::TransportParameterId> parameter_ids = {
- TransportParameters::kOriginalDestinationConnectionId,
- TransportParameters::kMaxIdleTimeout,
- TransportParameters::kStatelessResetToken,
- TransportParameters::kMaxPacketSize,
- TransportParameters::kInitialMaxData,
- TransportParameters::kInitialMaxStreamDataBidiLocal,
- TransportParameters::kInitialMaxStreamDataBidiRemote,
- TransportParameters::kInitialMaxStreamDataUni,
- TransportParameters::kInitialMaxStreamsBidi,
- TransportParameters::kInitialMaxStreamsUni,
- TransportParameters::kAckDelayExponent,
- TransportParameters::kMaxAckDelay,
- TransportParameters::kMinAckDelay,
- TransportParameters::kActiveConnectionIdLimit,
- TransportParameters::kMaxDatagramFrameSize,
- TransportParameters::kInitialRoundTripTime,
- TransportParameters::kDisableActiveMigration,
- TransportParameters::kPreferredAddress,
- TransportParameters::kInitialSourceConnectionId,
- TransportParameters::kRetrySourceConnectionId,
- TransportParameters::kGoogleConnectionOptions,
- TransportParameters::kGoogleQuicVersion,
- TransportParameters::kVersionInformation,
- };
-
- size_t max_transport_param_length = kKnownTransportParamLength;
- // google_connection_options.
- if (in.google_connection_options.has_value()) {
- max_transport_param_length +=
- in.google_connection_options.value().size() * sizeof(QuicTag);
- }
- // Google-specific version extension.
- if (in.legacy_version_information.has_value()) {
- max_transport_param_length +=
- sizeof(in.legacy_version_information.value().version) +
- 1 /* versions length */ +
- in.legacy_version_information.value().supported_versions.size() *
- sizeof(QuicVersionLabel);
- }
- // version_information.
- if (in.version_information.has_value()) {
- max_transport_param_length +=
- sizeof(in.version_information.value().chosen_version) +
- // Add one for the added GREASE version.
- (in.version_information.value().other_versions.size() + 1) *
- sizeof(QuicVersionLabel);
- }
-
- // Add a random GREASE transport parameter, as defined in the
- // "Reserved Transport Parameters" section of RFC 9000.
- // This forces receivers to support unexpected input.
- QuicRandom* random = QuicRandom::GetInstance();
- // Transport parameter identifiers are 62 bits long so we need to
- // ensure that the output of the computation below fits in 62 bits.
- uint64_t grease_id64 = random->RandUint64() % ((1ULL << 62) - 31);
- // Make sure grease_id % 31 == 27. Note that this is not uniformely
- // distributed but is acceptable since no security depends on this
- // randomness.
- grease_id64 = (grease_id64 / 31) * 31 + 27;
- TransportParameters::TransportParameterId grease_id =
- static_cast<TransportParameters::TransportParameterId>(grease_id64);
- const size_t grease_length = random->RandUint64() % kMaxGreaseLength;
- QUICHE_DCHECK_GE(kMaxGreaseLength, grease_length);
- char grease_contents[kMaxGreaseLength];
- random->RandBytes(grease_contents, grease_length);
- custom_parameters[grease_id] = std::string(grease_contents, grease_length);
-
- // Custom parameters.
- for (const auto& kv : custom_parameters) {
- max_transport_param_length += kTypeAndValueLength + kv.second.length();
- parameter_ids.push_back(kv.first);
- }
-
- // Randomize order of sent transport parameters by walking the array
- // backwards and swapping each element with a random earlier one.
- for (size_t i = parameter_ids.size() - 1; i > 0; i--) {
- std::swap(parameter_ids[i],
- parameter_ids[random->InsecureRandUint64() % (i + 1)]);
- }
-
- out->resize(max_transport_param_length);
- QuicDataWriter writer(out->size(), reinterpret_cast<char*>(out->data()));
-
- for (TransportParameters::TransportParameterId parameter_id : parameter_ids) {
- switch (parameter_id) {
- // original_destination_connection_id
- case TransportParameters::kOriginalDestinationConnectionId: {
- if (in.original_destination_connection_id.has_value()) {
- QUICHE_DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
- QuicConnectionId original_destination_connection_id =
- in.original_destination_connection_id.value();
- if (!writer.WriteVarInt62(
- TransportParameters::kOriginalDestinationConnectionId) ||
- !writer.WriteStringPieceVarInt62(absl::string_view(
- original_destination_connection_id.data(),
- original_destination_connection_id.length()))) {
- QUIC_BUG(Failed to write original_destination_connection_id)
- << "Failed to write original_destination_connection_id "
- << original_destination_connection_id << " for " << in;
- return false;
- }
- }
- } break;
- // max_idle_timeout
- case TransportParameters::kMaxIdleTimeout: {
- if (!in.max_idle_timeout_ms.Write(&writer)) {
- QUIC_BUG(Failed to write idle_timeout)
- << "Failed to write idle_timeout for " << in;
- return false;
- }
- } break;
- // stateless_reset_token
- case TransportParameters::kStatelessResetToken: {
- if (!in.stateless_reset_token.empty()) {
- QUICHE_DCHECK_EQ(kStatelessResetTokenLength,
- in.stateless_reset_token.size());
- QUICHE_DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
- if (!writer.WriteVarInt62(
- TransportParameters::kStatelessResetToken) ||
- !writer.WriteStringPieceVarInt62(
- absl::string_view(reinterpret_cast<const char*>(
- in.stateless_reset_token.data()),
- in.stateless_reset_token.size()))) {
- QUIC_BUG(Failed to write stateless_reset_token)
- << "Failed to write stateless_reset_token of length "
- << in.stateless_reset_token.size() << " for " << in;
- return false;
- }
- }
- } break;
- // max_udp_payload_size
- case TransportParameters::kMaxPacketSize: {
- if (!in.max_udp_payload_size.Write(&writer)) {
- QUIC_BUG(Failed to write max_udp_payload_size)
- << "Failed to write max_udp_payload_size for " << in;
- return false;
- }
- } break;
- // initial_max_data
- case TransportParameters::kInitialMaxData: {
- if (!in.initial_max_data.Write(&writer)) {
- QUIC_BUG(Failed to write initial_max_data)
- << "Failed to write initial_max_data for " << in;
- return false;
- }
- } break;
- // initial_max_stream_data_bidi_local
- case TransportParameters::kInitialMaxStreamDataBidiLocal: {
- if (!in.initial_max_stream_data_bidi_local.Write(&writer)) {
- QUIC_BUG(Failed to write initial_max_stream_data_bidi_local)
- << "Failed to write initial_max_stream_data_bidi_local for "
- << in;
- return false;
- }
- } break;
- // initial_max_stream_data_bidi_remote
- case TransportParameters::kInitialMaxStreamDataBidiRemote: {
- if (!in.initial_max_stream_data_bidi_remote.Write(&writer)) {
- QUIC_BUG(Failed to write initial_max_stream_data_bidi_remote)
- << "Failed to write initial_max_stream_data_bidi_remote for "
- << in;
- return false;
- }
- } break;
- // initial_max_stream_data_uni
- case TransportParameters::kInitialMaxStreamDataUni: {
- if (!in.initial_max_stream_data_uni.Write(&writer)) {
- QUIC_BUG(Failed to write initial_max_stream_data_uni)
- << "Failed to write initial_max_stream_data_uni for " << in;
- return false;
- }
- } break;
- // initial_max_streams_bidi
- case TransportParameters::kInitialMaxStreamsBidi: {
- if (!in.initial_max_streams_bidi.Write(&writer)) {
- QUIC_BUG(Failed to write initial_max_streams_bidi)
- << "Failed to write initial_max_streams_bidi for " << in;
- return false;
- }
- } break;
- // initial_max_streams_uni
- case TransportParameters::kInitialMaxStreamsUni: {
- if (!in.initial_max_streams_uni.Write(&writer)) {
- QUIC_BUG(Failed to write initial_max_streams_uni)
- << "Failed to write initial_max_streams_uni for " << in;
- return false;
- }
- } break;
- // ack_delay_exponent
- case TransportParameters::kAckDelayExponent: {
- if (!in.ack_delay_exponent.Write(&writer)) {
- QUIC_BUG(Failed to write ack_delay_exponent)
- << "Failed to write ack_delay_exponent for " << in;
- return false;
- }
- } break;
- // max_ack_delay
- case TransportParameters::kMaxAckDelay: {
- if (!in.max_ack_delay.Write(&writer)) {
- QUIC_BUG(Failed to write max_ack_delay)
- << "Failed to write max_ack_delay for " << in;
- return false;
- }
- } break;
- // min_ack_delay_us
- case TransportParameters::kMinAckDelay: {
- if (!in.min_ack_delay_us.Write(&writer)) {
- QUIC_BUG(Failed to write min_ack_delay_us)
- << "Failed to write min_ack_delay_us for " << in;
- return false;
- }
- } break;
- // active_connection_id_limit
- case TransportParameters::kActiveConnectionIdLimit: {
- if (!in.active_connection_id_limit.Write(&writer)) {
- QUIC_BUG(Failed to write active_connection_id_limit)
- << "Failed to write active_connection_id_limit for " << in;
- return false;
- }
- } break;
- // max_datagram_frame_size
- case TransportParameters::kMaxDatagramFrameSize: {
- if (!in.max_datagram_frame_size.Write(&writer)) {
- QUIC_BUG(Failed to write max_datagram_frame_size)
- << "Failed to write max_datagram_frame_size for " << in;
- return false;
- }
- } break;
- // initial_round_trip_time_us
- case TransportParameters::kInitialRoundTripTime: {
- if (!in.initial_round_trip_time_us.Write(&writer)) {
- QUIC_BUG(Failed to write initial_round_trip_time_us)
- << "Failed to write initial_round_trip_time_us for " << in;
- return false;
- }
- } break;
- // disable_active_migration
- case TransportParameters::kDisableActiveMigration: {
- if (in.disable_active_migration) {
- if (!writer.WriteVarInt62(
- TransportParameters::kDisableActiveMigration) ||
- !writer.WriteVarInt62(/* transport parameter length */ 0)) {
- QUIC_BUG(Failed to write disable_active_migration)
- << "Failed to write disable_active_migration for " << in;
- return false;
- }
- }
- } break;
- // preferred_address
- case TransportParameters::kPreferredAddress: {
- if (in.preferred_address) {
- std::string v4_address_bytes =
- in.preferred_address->ipv4_socket_address.host().ToPackedString();
- std::string v6_address_bytes =
- in.preferred_address->ipv6_socket_address.host().ToPackedString();
- if (v4_address_bytes.length() != 4 ||
- v6_address_bytes.length() != 16 ||
- in.preferred_address->stateless_reset_token.size() !=
- kStatelessResetTokenLength) {
- QUIC_BUG(quic_bug_10743_12)
- << "Bad lengths " << *in.preferred_address;
- return false;
- }
- const uint64_t preferred_address_length =
- v4_address_bytes.length() + /* IPv4 port */ sizeof(uint16_t) +
- v6_address_bytes.length() + /* IPv6 port */ sizeof(uint16_t) +
- /* connection ID length byte */ sizeof(uint8_t) +
- in.preferred_address->connection_id.length() +
- in.preferred_address->stateless_reset_token.size();
- if (!writer.WriteVarInt62(TransportParameters::kPreferredAddress) ||
- !writer.WriteVarInt62(
- /* transport parameter length */ preferred_address_length) ||
- !writer.WriteStringPiece(v4_address_bytes) ||
- !writer.WriteUInt16(
- in.preferred_address->ipv4_socket_address.port()) ||
- !writer.WriteStringPiece(v6_address_bytes) ||
- !writer.WriteUInt16(
- in.preferred_address->ipv6_socket_address.port()) ||
- !writer.WriteUInt8(
- in.preferred_address->connection_id.length()) ||
- !writer.WriteBytes(
- in.preferred_address->connection_id.data(),
- in.preferred_address->connection_id.length()) ||
- !writer.WriteBytes(
- in.preferred_address->stateless_reset_token.data(),
- in.preferred_address->stateless_reset_token.size())) {
- QUIC_BUG(Failed to write preferred_address)
- << "Failed to write preferred_address for " << in;
- return false;
- }
- }
- } break;
- // initial_source_connection_id
- case TransportParameters::kInitialSourceConnectionId: {
- if (in.initial_source_connection_id.has_value()) {
- QuicConnectionId initial_source_connection_id =
- in.initial_source_connection_id.value();
- if (!writer.WriteVarInt62(
- TransportParameters::kInitialSourceConnectionId) ||
- !writer.WriteStringPieceVarInt62(
- absl::string_view(initial_source_connection_id.data(),
- initial_source_connection_id.length()))) {
- QUIC_BUG(Failed to write initial_source_connection_id)
- << "Failed to write initial_source_connection_id "
- << initial_source_connection_id << " for " << in;
- return false;
- }
- }
- } break;
- // retry_source_connection_id
- case TransportParameters::kRetrySourceConnectionId: {
- if (in.retry_source_connection_id.has_value()) {
- QUICHE_DCHECK_EQ(Perspective::IS_SERVER, in.perspective);
- QuicConnectionId retry_source_connection_id =
- in.retry_source_connection_id.value();
- if (!writer.WriteVarInt62(
- TransportParameters::kRetrySourceConnectionId) ||
- !writer.WriteStringPieceVarInt62(
- absl::string_view(retry_source_connection_id.data(),
- retry_source_connection_id.length()))) {
- QUIC_BUG(Failed to write retry_source_connection_id)
- << "Failed to write retry_source_connection_id "
- << retry_source_connection_id << " for " << in;
- return false;
- }
- }
- } break;
- // Google-specific connection options.
- case TransportParameters::kGoogleConnectionOptions: {
- if (in.google_connection_options.has_value()) {
- static_assert(
- sizeof(in.google_connection_options.value().front()) == 4,
- "bad size");
- uint64_t connection_options_length =
- in.google_connection_options.value().size() * 4;
- if (!writer.WriteVarInt62(
- TransportParameters::kGoogleConnectionOptions) ||
- !writer.WriteVarInt62(
- /* transport parameter length */ connection_options_length)) {
- QUIC_BUG(Failed to write google_connection_options)
- << "Failed to write google_connection_options of length "
- << connection_options_length << " for " << in;
- return false;
- }
- for (const QuicTag& connection_option :
- in.google_connection_options.value()) {
- if (!writer.WriteTag(connection_option)) {
- QUIC_BUG(Failed to write google_connection_option)
- << "Failed to write google_connection_option "
- << QuicTagToString(connection_option) << " for " << in;
- return false;
- }
- }
- }
- } break;
- // Google-specific version extension.
- case TransportParameters::kGoogleQuicVersion: {
- if (!in.legacy_version_information.has_value()) {
- break;
- }
- static_assert(sizeof(QuicVersionLabel) == sizeof(uint32_t),
- "bad length");
- uint64_t google_version_length =
- sizeof(in.legacy_version_information.value().version);
- if (in.perspective == Perspective::IS_SERVER) {
- google_version_length +=
- /* versions length */ sizeof(uint8_t) +
- sizeof(QuicVersionLabel) * in.legacy_version_information.value()
- .supported_versions.size();
- }
- if (!writer.WriteVarInt62(TransportParameters::kGoogleQuicVersion) ||
- !writer.WriteVarInt62(
- /* transport parameter length */ google_version_length) ||
- !writer.WriteUInt32(
- in.legacy_version_information.value().version)) {
- QUIC_BUG(Failed to write Google version extension)
- << "Failed to write Google version extension for " << in;
- return false;
- }
- if (in.perspective == Perspective::IS_SERVER) {
- if (!writer.WriteUInt8(sizeof(QuicVersionLabel) *
- in.legacy_version_information.value()
- .supported_versions.size())) {
- QUIC_BUG(Failed to write versions length)
- << "Failed to write versions length for " << in;
- return false;
- }
- for (QuicVersionLabel version_label :
- in.legacy_version_information.value().supported_versions) {
- if (!writer.WriteUInt32(version_label)) {
- QUIC_BUG(Failed to write supported version)
- << "Failed to write supported version for " << in;
- return false;
- }
- }
- }
- } break;
- // version_information.
- case TransportParameters::kVersionInformation: {
- if (!in.version_information.has_value()) {
- break;
- }
- static_assert(sizeof(QuicVersionLabel) == sizeof(uint32_t),
- "bad length");
- QuicVersionLabelVector other_versions =
- in.version_information.value().other_versions;
- // Insert one GREASE version at a random index.
- const size_t grease_index =
- random->InsecureRandUint64() % (other_versions.size() + 1);
- other_versions.insert(
- other_versions.begin() + grease_index,
- CreateQuicVersionLabel(QuicVersionReservedForNegotiation()));
- const uint64_t version_information_length =
- sizeof(in.version_information.value().chosen_version) +
- sizeof(QuicVersionLabel) * other_versions.size();
- if (!writer.WriteVarInt62(TransportParameters::kVersionInformation) ||
- !writer.WriteVarInt62(
- /* transport parameter length */ version_information_length) ||
- !writer.WriteUInt32(
- in.version_information.value().chosen_version)) {
- QUIC_BUG(Failed to write chosen version)
- << "Failed to write chosen version for " << in;
- return false;
- }
- for (QuicVersionLabel version_label : other_versions) {
- if (!writer.WriteUInt32(version_label)) {
- QUIC_BUG(Failed to write other version)
- << "Failed to write other version for " << in;
- return false;
- }
- }
- } break;
- // Custom parameters and GREASE.
- default: {
- auto it = custom_parameters.find(parameter_id);
- if (it == custom_parameters.end()) {
- QUIC_BUG(Unknown parameter) << "Unknown parameter " << parameter_id;
- return false;
- }
- if (!writer.WriteVarInt62(parameter_id) ||
- !writer.WriteStringPieceVarInt62(it->second)) {
- QUIC_BUG(Failed to write custom parameter)
- << "Failed to write custom parameter " << parameter_id;
- return false;
- }
- } break;
- }
- }
-
- out->resize(writer.length());
-
- QUIC_DLOG(INFO) << "Serialized " << in << " as " << writer.length()
- << " bytes";
-
- return true;
-}
-
-bool ParseTransportParameters(ParsedQuicVersion version,
- Perspective perspective,
- const uint8_t* in,
- size_t in_len,
- TransportParameters* out,
- std::string* error_details) {
- out->perspective = perspective;
- QuicDataReader reader(reinterpret_cast<const char*>(in), in_len);
-
- while (!reader.IsDoneReading()) {
- uint64_t param_id64;
- if (!reader.ReadVarInt62(&param_id64)) {
- *error_details = "Failed to parse transport parameter ID";
- return false;
- }
- TransportParameters::TransportParameterId param_id =
- static_cast<TransportParameters::TransportParameterId>(param_id64);
- absl::string_view value;
- if (!reader.ReadStringPieceVarInt62(&value)) {
- *error_details =
- "Failed to read length and value of transport parameter " +
- TransportParameterIdToString(param_id);
- return false;
- }
- QuicDataReader value_reader(value);
- bool parse_success = true;
- switch (param_id) {
- case TransportParameters::kOriginalDestinationConnectionId: {
- if (out->original_destination_connection_id.has_value()) {
- *error_details =
- "Received a second original_destination_connection_id";
- return false;
- }
- const size_t connection_id_length = value_reader.BytesRemaining();
- if (!QuicUtils::IsConnectionIdLengthValidForVersion(
- connection_id_length, version.transport_version)) {
- *error_details = absl::StrCat(
- "Received original_destination_connection_id of invalid length ",
- connection_id_length);
- return false;
- }
- QuicConnectionId original_destination_connection_id;
- if (!value_reader.ReadConnectionId(&original_destination_connection_id,
- connection_id_length)) {
- *error_details = "Failed to read original_destination_connection_id";
- return false;
- }
- out->original_destination_connection_id =
- original_destination_connection_id;
- } break;
- case TransportParameters::kMaxIdleTimeout:
- parse_success =
- out->max_idle_timeout_ms.Read(&value_reader, error_details);
- break;
- case TransportParameters::kStatelessResetToken: {
- if (!out->stateless_reset_token.empty()) {
- *error_details = "Received a second stateless_reset_token";
- return false;
- }
- absl::string_view stateless_reset_token =
- value_reader.ReadRemainingPayload();
- if (stateless_reset_token.length() != kStatelessResetTokenLength) {
- *error_details =
- absl::StrCat("Received stateless_reset_token of invalid length ",
- stateless_reset_token.length());
- return false;
- }
- out->stateless_reset_token.assign(
- stateless_reset_token.data(),
- stateless_reset_token.data() + stateless_reset_token.length());
- } break;
- case TransportParameters::kMaxPacketSize:
- parse_success =
- out->max_udp_payload_size.Read(&value_reader, error_details);
- break;
- case TransportParameters::kInitialMaxData:
- parse_success =
- out->initial_max_data.Read(&value_reader, error_details);
- break;
- case TransportParameters::kInitialMaxStreamDataBidiLocal:
- parse_success = out->initial_max_stream_data_bidi_local.Read(
- &value_reader, error_details);
- break;
- case TransportParameters::kInitialMaxStreamDataBidiRemote:
- parse_success = out->initial_max_stream_data_bidi_remote.Read(
- &value_reader, error_details);
- break;
- case TransportParameters::kInitialMaxStreamDataUni:
- parse_success =
- out->initial_max_stream_data_uni.Read(&value_reader, error_details);
- break;
- case TransportParameters::kInitialMaxStreamsBidi:
- parse_success =
- out->initial_max_streams_bidi.Read(&value_reader, error_details);
- break;
- case TransportParameters::kInitialMaxStreamsUni:
- parse_success =
- out->initial_max_streams_uni.Read(&value_reader, error_details);
- break;
- case TransportParameters::kAckDelayExponent:
- parse_success =
- out->ack_delay_exponent.Read(&value_reader, error_details);
- break;
- case TransportParameters::kMaxAckDelay:
- parse_success = out->max_ack_delay.Read(&value_reader, error_details);
- break;
- case TransportParameters::kDisableActiveMigration:
- if (out->disable_active_migration) {
- *error_details = "Received a second disable_active_migration";
- return false;
- }
- out->disable_active_migration = true;
- break;
- case TransportParameters::kPreferredAddress: {
- TransportParameters::PreferredAddress preferred_address;
- uint16_t ipv4_port, ipv6_port;
- in_addr ipv4_address;
- in6_addr ipv6_address;
- preferred_address.stateless_reset_token.resize(
- kStatelessResetTokenLength);
- if (!value_reader.ReadBytes(&ipv4_address, sizeof(ipv4_address)) ||
- !value_reader.ReadUInt16(&ipv4_port) ||
- !value_reader.ReadBytes(&ipv6_address, sizeof(ipv6_address)) ||
- !value_reader.ReadUInt16(&ipv6_port) ||
- !value_reader.ReadLengthPrefixedConnectionId(
- &preferred_address.connection_id) ||
- !value_reader.ReadBytes(&preferred_address.stateless_reset_token[0],
- kStatelessResetTokenLength)) {
- *error_details = "Failed to read preferred_address";
- return false;
- }
- preferred_address.ipv4_socket_address =
- QuicSocketAddress(QuicIpAddress(ipv4_address), ipv4_port);
- preferred_address.ipv6_socket_address =
- QuicSocketAddress(QuicIpAddress(ipv6_address), ipv6_port);
- if (!preferred_address.ipv4_socket_address.host().IsIPv4() ||
- !preferred_address.ipv6_socket_address.host().IsIPv6()) {
- *error_details = "Received preferred_address of bad families " +
- preferred_address.ToString();
- return false;
- }
- if (!QuicUtils::IsConnectionIdValidForVersion(
- preferred_address.connection_id, version.transport_version)) {
- *error_details = "Received invalid preferred_address connection ID " +
- preferred_address.ToString();
- return false;
- }
- out->preferred_address =
- std::make_unique<TransportParameters::PreferredAddress>(
- preferred_address);
- } break;
- case TransportParameters::kActiveConnectionIdLimit:
- 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 = absl::StrCat(
- "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 = absl::StrCat(
- "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);
- break;
- case TransportParameters::kInitialRoundTripTime:
- parse_success =
- out->initial_round_trip_time_us.Read(&value_reader, error_details);
- break;
- case TransportParameters::kGoogleConnectionOptions: {
- if (out->google_connection_options.has_value()) {
- *error_details = "Received a second google_connection_options";
- return false;
- }
- out->google_connection_options = QuicTagVector{};
- while (!value_reader.IsDoneReading()) {
- QuicTag connection_option;
- if (!value_reader.ReadTag(&connection_option)) {
- *error_details = "Failed to read a google_connection_options";
- return false;
- }
- out->google_connection_options.value().push_back(connection_option);
- }
- } break;
- case TransportParameters::kGoogleQuicVersion: {
- if (!out->legacy_version_information.has_value()) {
- out->legacy_version_information =
- TransportParameters::LegacyVersionInformation();
- }
- if (!value_reader.ReadUInt32(
- &out->legacy_version_information.value().version)) {
- *error_details = "Failed to read Google version extension version";
- return false;
- }
- if (perspective == Perspective::IS_SERVER) {
- uint8_t versions_length;
- if (!value_reader.ReadUInt8(&versions_length)) {
- *error_details = "Failed to parse Google supported versions length";
- return false;
- }
- const uint8_t num_versions = versions_length / sizeof(uint32_t);
- for (uint8_t i = 0; i < num_versions; ++i) {
- QuicVersionLabel version;
- if (!value_reader.ReadUInt32(&version)) {
- *error_details = "Failed to parse Google supported version";
- return false;
- }
- out->legacy_version_information.value()
- .supported_versions.push_back(version);
- }
- }
- } break;
- case TransportParameters::kVersionInformation: {
- if (!GetQuicReloadableFlag(quic_version_information)) {
- // This duplicates the default case and will be removed when this flag
- // is deprecated.
- if (out->custom_parameters.find(param_id) !=
- out->custom_parameters.end()) {
- *error_details = "Received a second unknown parameter" +
- TransportParameterIdToString(param_id);
- return false;
- }
- out->custom_parameters[param_id] =
- std::string(value_reader.ReadRemainingPayload());
- break;
- }
- QUIC_RELOADABLE_FLAG_COUNT_N(quic_version_information, 2, 2);
- if (out->version_information.has_value()) {
- *error_details = "Received a second version_information";
- return false;
- }
- out->version_information = TransportParameters::VersionInformation();
- if (!value_reader.ReadUInt32(
- &out->version_information.value().chosen_version)) {
- *error_details = "Failed to read chosen version";
- return false;
- }
- while (!value_reader.IsDoneReading()) {
- QuicVersionLabel other_version;
- if (!value_reader.ReadUInt32(&other_version)) {
- *error_details = "Failed to parse other version";
- return false;
- }
- out->version_information.value().other_versions.push_back(
- other_version);
- }
- } break;
- case TransportParameters::kMinAckDelay:
- parse_success =
- out->min_ack_delay_us.Read(&value_reader, error_details);
- break;
- default:
- if (out->custom_parameters.find(param_id) !=
- out->custom_parameters.end()) {
- *error_details = "Received a second unknown parameter" +
- TransportParameterIdToString(param_id);
- return false;
- }
- out->custom_parameters[param_id] =
- std::string(value_reader.ReadRemainingPayload());
- break;
- }
- if (!parse_success) {
- QUICHE_DCHECK(!error_details->empty());
- return false;
- }
- if (!value_reader.IsDoneReading()) {
- *error_details = absl::StrCat(
- "Received unexpected ", value_reader.BytesRemaining(),
- " bytes after parsing ", TransportParameterIdToString(param_id));
- return false;
- }
- }
-
- if (!out->AreValid(error_details)) {
- QUICHE_DCHECK(!error_details->empty());
- return false;
- }
-
- QUIC_DLOG(INFO) << "Parsed transport parameters " << *out << " from "
- << in_len << " bytes";
-
- return true;
-}
-
-namespace {
-
-bool DigestUpdateIntegerParam(
- EVP_MD_CTX* hash_ctx,
- const TransportParameters::IntegerParameter& param) {
- uint64_t value = param.value();
- return EVP_DigestUpdate(hash_ctx, &value, sizeof(value));
-}
-
-} // namespace
-
-bool SerializeTransportParametersForTicket(
- const TransportParameters& in,
- const std::vector<uint8_t>& application_data,
- std::vector<uint8_t>* out) {
- std::string error_details;
- if (!in.AreValid(&error_details)) {
- QUIC_BUG(quic_bug_10743_26)
- << "Not serializing invalid transport parameters: " << error_details;
- return false;
- }
-
- out->resize(SHA256_DIGEST_LENGTH + 1);
- const uint8_t serialization_version = 0;
- (*out)[0] = serialization_version;
-
- bssl::ScopedEVP_MD_CTX hash_ctx;
- // Write application data:
- uint64_t app_data_len = application_data.size();
- const uint64_t parameter_version = 0;
- // The format of the input to the hash function is as follows:
- // - The application data, prefixed with a 64-bit length field.
- // - Transport parameters:
- // - A 64-bit version field indicating which version of encoding is used
- // for transport parameters.
- // - A list of 64-bit integers representing the relevant parameters.
- //
- // When changing which parameters are included, additional parameters can be
- // added to the end of the list without changing the version field. New
- // parameters that are variable length must be length prefixed. If
- // parameters are removed from the list, the version field must be
- // incremented.
- //
- // Integers happen to be written in host byte order, not network byte order.
- if (!EVP_DigestInit(hash_ctx.get(), EVP_sha256()) ||
- !EVP_DigestUpdate(hash_ctx.get(), &app_data_len, sizeof(app_data_len)) ||
- !EVP_DigestUpdate(hash_ctx.get(), application_data.data(),
- application_data.size()) ||
- !EVP_DigestUpdate(hash_ctx.get(), &parameter_version,
- sizeof(parameter_version))) {
- QUIC_BUG(quic_bug_10743_27)
- << "Unexpected failure of EVP_Digest functions when hashing "
- "Transport Parameters for ticket";
- return false;
- }
-
- // Write transport parameters specified by draft-ietf-quic-transport-28,
- // section 7.4.1, that are remembered for 0-RTT.
- if (!DigestUpdateIntegerParam(hash_ctx.get(), in.initial_max_data) ||
- !DigestUpdateIntegerParam(hash_ctx.get(),
- in.initial_max_stream_data_bidi_local) ||
- !DigestUpdateIntegerParam(hash_ctx.get(),
- in.initial_max_stream_data_bidi_remote) ||
- !DigestUpdateIntegerParam(hash_ctx.get(),
- in.initial_max_stream_data_uni) ||
- !DigestUpdateIntegerParam(hash_ctx.get(), in.initial_max_streams_bidi) ||
- !DigestUpdateIntegerParam(hash_ctx.get(), in.initial_max_streams_uni) ||
- !DigestUpdateIntegerParam(hash_ctx.get(),
- in.active_connection_id_limit)) {
- QUIC_BUG(quic_bug_10743_28)
- << "Unexpected failure of EVP_Digest functions when hashing "
- "Transport Parameters for ticket";
- return false;
- }
- uint8_t disable_active_migration = in.disable_active_migration ? 1 : 0;
- if (!EVP_DigestUpdate(hash_ctx.get(), &disable_active_migration,
- sizeof(disable_active_migration)) ||
- !EVP_DigestFinal(hash_ctx.get(), out->data() + 1, nullptr)) {
- QUIC_BUG(quic_bug_10743_29)
- << "Unexpected failure of EVP_Digest functions when hashing "
- "Transport Parameters for ticket";
- return false;
- }
- return true;
-}
-
-} // namespace quic