diff options
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.cc | 1604 |
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(¶m_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(), ¶meter_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 |