| // Copyright (c) 2012 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 "net/third_party/quiche/src/quic/core/quic_versions.h" |
| |
| #include <string> |
| |
| #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" |
| #include "net/third_party/quiche/src/quic/core/quic_tag.h" |
| #include "net/third_party/quiche/src/quic/core/quic_types.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" |
| |
| namespace quic { |
| namespace { |
| |
| // Constructs a version label from the 4 bytes such that the on-the-wire |
| // order will be: d, c, b, a. |
| QuicVersionLabel MakeVersionLabel(char a, char b, char c, char d) { |
| return MakeQuicTag(d, c, b, a); |
| } |
| |
| QuicVersionLabel CreateRandomVersionLabelForNegotiation() { |
| if (!GetQuicReloadableFlag(quic_version_negotiation_grease)) { |
| return MakeVersionLabel(0xda, 0x5a, 0x3a, 0x3a); |
| } |
| QUIC_RELOADABLE_FLAG_COUNT_N(quic_version_negotiation_grease, 2, 2); |
| QuicVersionLabel result; |
| if (!GetQuicFlag(FLAGS_quic_disable_version_negotiation_grease_randomness)) { |
| QuicRandom::GetInstance()->RandBytes(&result, sizeof(result)); |
| } else { |
| result = MakeVersionLabel(0xd1, 0x57, 0x38, 0x3f); |
| } |
| result &= 0xf0f0f0f0; |
| result |= 0x0a0a0a0a; |
| return result; |
| } |
| |
| } // namespace |
| |
| ParsedQuicVersion::ParsedQuicVersion(HandshakeProtocol handshake_protocol, |
| QuicTransportVersion transport_version) |
| : handshake_protocol(handshake_protocol), |
| transport_version(transport_version) {} |
| |
| bool ParsedQuicVersion::KnowsWhichDecrypterToUse() const { |
| return transport_version > QUIC_VERSION_46 || |
| handshake_protocol == PROTOCOL_TLS1_3; |
| } |
| |
| bool ParsedQuicVersion::UsesInitialObfuscators() const { |
| return transport_version > QUIC_VERSION_49 || |
| handshake_protocol == PROTOCOL_TLS1_3; |
| } |
| |
| bool ParsedQuicVersion::AllowsLowFlowControlLimits() const { |
| return transport_version == QUIC_VERSION_99 && |
| handshake_protocol == PROTOCOL_TLS1_3; |
| } |
| |
| bool ParsedQuicVersion::HasHeaderProtection() const { |
| return transport_version > QUIC_VERSION_49; |
| } |
| |
| bool ParsedQuicVersion::SupportsRetry() const { |
| return transport_version > QUIC_VERSION_46; |
| } |
| |
| bool ParsedQuicVersion::SendsVariableLengthPacketNumberInLongHeader() const { |
| return transport_version > QUIC_VERSION_46; |
| } |
| |
| bool ParsedQuicVersion::SupportsClientConnectionIds() const { |
| return transport_version > QUIC_VERSION_48; |
| } |
| |
| bool ParsedQuicVersion::HasLengthPrefixedConnectionIds() const { |
| return VersionHasLengthPrefixedConnectionIds(transport_version); |
| } |
| |
| bool ParsedQuicVersion::SupportsAntiAmplificationLimit() const { |
| return transport_version == QUIC_VERSION_99 && |
| handshake_protocol == PROTOCOL_TLS1_3; |
| } |
| |
| bool VersionHasLengthPrefixedConnectionIds( |
| QuicTransportVersion transport_version) { |
| return transport_version > QUIC_VERSION_48; |
| } |
| |
| std::ostream& operator<<(std::ostream& os, const ParsedQuicVersion& version) { |
| os << ParsedQuicVersionToString(version); |
| return os; |
| } |
| |
| QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) { |
| char proto = 0; |
| switch (parsed_version.handshake_protocol) { |
| case PROTOCOL_QUIC_CRYPTO: |
| proto = 'Q'; |
| break; |
| case PROTOCOL_TLS1_3: |
| proto = 'T'; |
| break; |
| default: |
| QUIC_BUG << "Invalid HandshakeProtocol: " |
| << parsed_version.handshake_protocol; |
| return 0; |
| } |
| static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, |
| "Supported versions out of sync"); |
| switch (parsed_version.transport_version) { |
| case QUIC_VERSION_43: |
| return MakeVersionLabel(proto, '0', '4', '3'); |
| case QUIC_VERSION_46: |
| return MakeVersionLabel(proto, '0', '4', '6'); |
| case QUIC_VERSION_48: |
| return MakeVersionLabel(proto, '0', '4', '8'); |
| case QUIC_VERSION_49: |
| return MakeVersionLabel(proto, '0', '4', '9'); |
| case QUIC_VERSION_50: |
| return MakeVersionLabel(proto, '0', '5', '0'); |
| case QUIC_VERSION_99: |
| if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) { |
| return MakeVersionLabel(0xff, 0x00, 0x00, kQuicIetfDraftVersion); |
| } |
| return MakeVersionLabel(proto, '0', '9', '9'); |
| case QUIC_VERSION_RESERVED_FOR_NEGOTIATION: |
| return CreateRandomVersionLabelForNegotiation(); |
| default: |
| // This is a bug because we should never attempt to convert an invalid |
| // QuicTransportVersion to be written to the wire. |
| QUIC_BUG << "Unsupported QuicTransportVersion: " |
| << parsed_version.transport_version; |
| return 0; |
| } |
| } |
| |
| QuicVersionLabelVector CreateQuicVersionLabelVector( |
| const ParsedQuicVersionVector& versions) { |
| QuicVersionLabelVector out; |
| out.reserve(versions.size()); |
| for (const auto& version : versions) { |
| out.push_back(CreateQuicVersionLabel(version)); |
| } |
| return out; |
| } |
| |
| ParsedQuicVersion ParseQuicVersionLabel(QuicVersionLabel version_label) { |
| std::vector<HandshakeProtocol> protocols = {PROTOCOL_QUIC_CRYPTO, |
| PROTOCOL_TLS1_3}; |
| for (QuicTransportVersion version : kSupportedTransportVersions) { |
| for (HandshakeProtocol handshake : protocols) { |
| if (version_label == |
| CreateQuicVersionLabel(ParsedQuicVersion(handshake, version))) { |
| return ParsedQuicVersion(handshake, version); |
| } |
| } |
| } |
| // Reading from the client so this should not be considered an ERROR. |
| QUIC_DLOG(INFO) << "Unsupported QuicVersionLabel version: " |
| << QuicVersionLabelToString(version_label); |
| return UnsupportedQuicVersion(); |
| } |
| |
| ParsedQuicVersion ParseQuicVersionString(std::string version_string) { |
| if (version_string.empty()) { |
| return UnsupportedQuicVersion(); |
| } |
| int quic_version_number = 0; |
| if (QuicTextUtils::StringToInt(version_string, &quic_version_number) && |
| quic_version_number > 0) { |
| return ParsedQuicVersion( |
| PROTOCOL_QUIC_CRYPTO, |
| static_cast<QuicTransportVersion>(quic_version_number)); |
| } |
| |
| std::vector<HandshakeProtocol> protocols = {PROTOCOL_QUIC_CRYPTO}; |
| if (GetQuicReloadableFlag(quic_supports_tls_handshake)) { |
| protocols.push_back(PROTOCOL_TLS1_3); |
| } |
| for (QuicTransportVersion version : kSupportedTransportVersions) { |
| for (HandshakeProtocol handshake : protocols) { |
| const ParsedQuicVersion parsed_version = |
| ParsedQuicVersion(handshake, version); |
| if (version_string == ParsedQuicVersionToString(parsed_version)) { |
| return parsed_version; |
| } |
| } |
| } |
| // Still recognize T099 even if flag quic_ietf_draft_version has been changed. |
| if (GetQuicReloadableFlag(quic_supports_tls_handshake) && |
| version_string == "T099") { |
| return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99); |
| } |
| // Reading from the client so this should not be considered an ERROR. |
| QUIC_DLOG(INFO) << "Unsupported QUIC version string: \"" << version_string |
| << "\"."; |
| return UnsupportedQuicVersion(); |
| } |
| |
| QuicTransportVersionVector AllSupportedTransportVersions() { |
| QuicTransportVersionVector supported_versions; |
| for (QuicTransportVersion version : kSupportedTransportVersions) { |
| supported_versions.push_back(version); |
| } |
| return supported_versions; |
| } |
| |
| ParsedQuicVersionVector AllSupportedVersions() { |
| ParsedQuicVersionVector supported_versions; |
| for (HandshakeProtocol protocol : kSupportedHandshakeProtocols) { |
| for (QuicTransportVersion version : kSupportedTransportVersions) { |
| if (protocol == PROTOCOL_TLS1_3 && |
| !QuicVersionUsesCryptoFrames(version)) { |
| // The TLS handshake is only deployable if CRYPTO frames are also used. |
| continue; |
| } |
| supported_versions.push_back(ParsedQuicVersion(protocol, version)); |
| } |
| } |
| return supported_versions; |
| } |
| |
| // TODO(nharper): Remove this function when it is no longer in use. |
| QuicTransportVersionVector CurrentSupportedTransportVersions() { |
| return FilterSupportedTransportVersions(AllSupportedTransportVersions()); |
| } |
| |
| ParsedQuicVersionVector CurrentSupportedVersions() { |
| return FilterSupportedVersions(AllSupportedVersions()); |
| } |
| |
| // TODO(nharper): Remove this function when it is no longer in use. |
| QuicTransportVersionVector FilterSupportedTransportVersions( |
| QuicTransportVersionVector versions) { |
| ParsedQuicVersionVector parsed_versions; |
| for (QuicTransportVersion version : versions) { |
| parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); |
| } |
| ParsedQuicVersionVector filtered_parsed_versions = |
| FilterSupportedVersions(parsed_versions); |
| QuicTransportVersionVector filtered_versions; |
| for (ParsedQuicVersion version : filtered_parsed_versions) { |
| filtered_versions.push_back(version.transport_version); |
| } |
| return filtered_versions; |
| } |
| |
| ParsedQuicVersionVector FilterSupportedVersions( |
| ParsedQuicVersionVector versions) { |
| ParsedQuicVersionVector filtered_versions; |
| filtered_versions.reserve(versions.size()); |
| for (ParsedQuicVersion version : versions) { |
| if (version.handshake_protocol == PROTOCOL_TLS1_3 && |
| !GetQuicReloadableFlag(quic_supports_tls_handshake)) { |
| continue; |
| } |
| if (version.transport_version == QUIC_VERSION_99) { |
| if (GetQuicReloadableFlag(quic_enable_version_99)) { |
| filtered_versions.push_back(version); |
| } |
| } else if (version.transport_version == QUIC_VERSION_50) { |
| if (GetQuicReloadableFlag(quic_enable_version_50)) { |
| filtered_versions.push_back(version); |
| } |
| } else if (version.transport_version == QUIC_VERSION_49) { |
| if (GetQuicReloadableFlag(quic_enable_version_49)) { |
| filtered_versions.push_back(version); |
| } |
| } else if (version.transport_version == QUIC_VERSION_48) { |
| if (GetQuicReloadableFlag(quic_enable_version_48_2)) { |
| filtered_versions.push_back(version); |
| } |
| } else { |
| filtered_versions.push_back(version); |
| } |
| } |
| return filtered_versions; |
| } |
| |
| QuicTransportVersionVector VersionOfIndex( |
| const QuicTransportVersionVector& versions, |
| int index) { |
| QuicTransportVersionVector version; |
| int version_count = versions.size(); |
| if (index >= 0 && index < version_count) { |
| version.push_back(versions[index]); |
| } else { |
| version.push_back(QUIC_VERSION_UNSUPPORTED); |
| } |
| return version; |
| } |
| |
| ParsedQuicVersionVector ParsedVersionOfIndex( |
| const ParsedQuicVersionVector& versions, |
| int index) { |
| ParsedQuicVersionVector version; |
| int version_count = versions.size(); |
| if (index >= 0 && index < version_count) { |
| version.push_back(versions[index]); |
| } else { |
| version.push_back(UnsupportedQuicVersion()); |
| } |
| return version; |
| } |
| |
| QuicTransportVersionVector ParsedVersionsToTransportVersions( |
| const ParsedQuicVersionVector& versions) { |
| QuicTransportVersionVector transport_versions; |
| transport_versions.resize(versions.size()); |
| for (size_t i = 0; i < versions.size(); ++i) { |
| transport_versions[i] = versions[i].transport_version; |
| } |
| return transport_versions; |
| } |
| |
| QuicVersionLabel QuicVersionToQuicVersionLabel( |
| QuicTransportVersion transport_version) { |
| return CreateQuicVersionLabel( |
| ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, transport_version)); |
| } |
| |
| std::string QuicVersionLabelToString(QuicVersionLabel version_label) { |
| return QuicTagToString(QuicEndian::HostToNet32(version_label)); |
| } |
| |
| std::string QuicVersionLabelVectorToString( |
| const QuicVersionLabelVector& version_labels, |
| const std::string& separator, |
| size_t skip_after_nth_version) { |
| std::string result; |
| for (size_t i = 0; i < version_labels.size(); ++i) { |
| if (i != 0) { |
| result.append(separator); |
| } |
| |
| if (i > skip_after_nth_version) { |
| result.append("..."); |
| break; |
| } |
| result.append(QuicVersionLabelToString(version_labels[i])); |
| } |
| return result; |
| } |
| |
| QuicTransportVersion QuicVersionLabelToQuicVersion( |
| QuicVersionLabel version_label) { |
| return ParseQuicVersionLabel(version_label).transport_version; |
| } |
| |
| HandshakeProtocol QuicVersionLabelToHandshakeProtocol( |
| QuicVersionLabel version_label) { |
| return ParseQuicVersionLabel(version_label).handshake_protocol; |
| } |
| |
| #define RETURN_STRING_LITERAL(x) \ |
| case x: \ |
| return #x |
| |
| std::string QuicVersionToString(QuicTransportVersion transport_version) { |
| static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, |
| "Supported versions out of sync"); |
| switch (transport_version) { |
| RETURN_STRING_LITERAL(QUIC_VERSION_43); |
| RETURN_STRING_LITERAL(QUIC_VERSION_46); |
| RETURN_STRING_LITERAL(QUIC_VERSION_48); |
| RETURN_STRING_LITERAL(QUIC_VERSION_49); |
| RETURN_STRING_LITERAL(QUIC_VERSION_50); |
| RETURN_STRING_LITERAL(QUIC_VERSION_99); |
| default: |
| return "QUIC_VERSION_UNSUPPORTED"; |
| } |
| } |
| |
| std::string ParsedQuicVersionToString(ParsedQuicVersion version) { |
| if (version == UnsupportedQuicVersion()) { |
| return "0"; |
| } |
| return QuicVersionLabelToString(CreateQuicVersionLabel(version)); |
| } |
| |
| std::string QuicTransportVersionVectorToString( |
| const QuicTransportVersionVector& versions) { |
| std::string result = ""; |
| for (size_t i = 0; i < versions.size(); ++i) { |
| if (i != 0) { |
| result.append(","); |
| } |
| result.append(QuicVersionToString(versions[i])); |
| } |
| return result; |
| } |
| |
| std::string ParsedQuicVersionVectorToString( |
| const ParsedQuicVersionVector& versions, |
| const std::string& separator, |
| size_t skip_after_nth_version) { |
| std::string result; |
| for (size_t i = 0; i < versions.size(); ++i) { |
| if (i != 0) { |
| result.append(separator); |
| } |
| if (i > skip_after_nth_version) { |
| result.append("..."); |
| break; |
| } |
| result.append(ParsedQuicVersionToString(versions[i])); |
| } |
| return result; |
| } |
| |
| bool QuicVersionLabelUses4BitConnectionIdLength( |
| QuicVersionLabel version_label) { |
| // As we deprecate old versions, we still need the ability to send valid |
| // version negotiation packets for those versions. This function keeps track |
| // of the versions that ever supported the 4bit connection ID length encoding |
| // that we know about. Google QUIC 43 and earlier used a different encoding, |
| // and Google QUIC 49 and later use the new length prefixed encoding. |
| // Similarly, only IETF drafts 11 to 21 used this encoding. |
| |
| // Check Q044, Q045, Q046, Q047 and Q048. |
| for (uint8_t c = '4'; c <= '8'; ++c) { |
| if (version_label == MakeVersionLabel('Q', '0', '4', c)) { |
| return true; |
| } |
| } |
| // Check T048. |
| if (version_label == MakeVersionLabel('T', '0', '4', '8')) { |
| return true; |
| } |
| // Check IETF draft versions in [11,21]. |
| for (uint8_t draft_number = 11; draft_number <= 21; ++draft_number) { |
| if (version_label == MakeVersionLabel(0xff, 0x00, 0x00, draft_number)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| ParsedQuicVersion UnsupportedQuicVersion() { |
| return ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED); |
| } |
| |
| ParsedQuicVersion QuicVersionReservedForNegotiation() { |
| return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, |
| QUIC_VERSION_RESERVED_FOR_NEGOTIATION); |
| } |
| |
| std::string AlpnForVersion(ParsedQuicVersion parsed_version) { |
| if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3 && |
| parsed_version.transport_version == QUIC_VERSION_99) { |
| return "h3-" + QuicTextUtils::Uint64ToString(kQuicIetfDraftVersion); |
| } |
| return "h3-" + ParsedQuicVersionToString(parsed_version); |
| } |
| |
| void QuicVersionInitializeSupportForIetfDraft() { |
| // Enable necessary flags. |
| SetQuicReloadableFlag(quic_supports_tls_handshake, true); |
| SetQuicReloadableFlag(quic_simplify_stop_waiting, true); |
| } |
| |
| void QuicEnableVersion(ParsedQuicVersion parsed_version) { |
| if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) { |
| SetQuicReloadableFlag(quic_supports_tls_handshake, true); |
| } |
| static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, |
| "Supported versions out of sync"); |
| if (parsed_version.transport_version == QUIC_VERSION_99) { |
| SetQuicReloadableFlag(quic_enable_version_99, true); |
| } |
| if (parsed_version.transport_version == QUIC_VERSION_50) { |
| SetQuicReloadableFlag(quic_enable_version_50, true); |
| } |
| if (parsed_version.transport_version == QUIC_VERSION_49) { |
| SetQuicReloadableFlag(quic_enable_version_49, true); |
| } |
| if (parsed_version.transport_version == QUIC_VERSION_48) { |
| SetQuicReloadableFlag(quic_enable_version_48_2, true); |
| } |
| } |
| |
| #undef RETURN_STRING_LITERAL // undef for jumbo builds |
| } // namespace quic |