Roll-forward support for QUICv2 after a more thorough inventory of ALPN impacts. Automated g4 rollback of changelist 427037417. *** Reason for rollback *** Restore support for QUICv2 after a more thorough inventory of ALPN impacts. *** Original change description *** Rollback for 4 changelists related to QUICv2. *** Reason for rollback *** Rollback QUICv2 until we figure out the impact on Chrome. *** Original change descriptions *** Fix C++ defensive coding advice from the QUICv2 CL (cl/424961568). There is much more to be done, but that could get out of control fast. Let me know if you want to abandon this, push more into this CL, or commit as-is. This CL restores QUICv2 support after auditing the effects of shared ALPN. *** Fix Intermittent Contagion Test failure. Since version mismatch is known to fail ungracefully, the... *** PiperOrigin-RevId: 427504970
diff --git a/quic/core/crypto/crypto_utils.cc b/quic/core/crypto/crypto_utils.cc index 1812e73..05bbdfe 100644 --- a/quic/core/crypto/crypto_utils.cc +++ b/quic/core/crypto/crypto_utils.cc
@@ -90,12 +90,23 @@ } // namespace +const std::string getLabelForVersion(const ParsedQuicVersion& version, + const absl::string_view& predicate) { + static_assert(SupportedVersions().size() == 6u, + "Supported versions out of sync with HKDF labels"); + if (version == ParsedQuicVersion::V2Draft01()) { + return absl::StrCat("quicv2 ", predicate); + } else { + return absl::StrCat("quic ", predicate); + } +} + void CryptoUtils::InitializeCrypterSecrets( const EVP_MD* prf, const std::vector<uint8_t>& pp_secret, - QuicCrypter* crypter) { - SetKeyAndIV(prf, pp_secret, crypter); - std::vector<uint8_t> header_protection_key = - GenerateHeaderProtectionKey(prf, pp_secret, crypter->GetKeySize()); + const ParsedQuicVersion& version, QuicCrypter* crypter) { + SetKeyAndIV(prf, pp_secret, version, crypter); + std::vector<uint8_t> header_protection_key = GenerateHeaderProtectionKey( + prf, pp_secret, version, crypter->GetKeySize()); crypter->SetHeaderProtectionKey( absl::string_view(reinterpret_cast<char*>(header_protection_key.data()), header_protection_key.size())); @@ -103,11 +114,13 @@ void CryptoUtils::SetKeyAndIV(const EVP_MD* prf, const std::vector<uint8_t>& pp_secret, + const ParsedQuicVersion& version, QuicCrypter* crypter) { std::vector<uint8_t> key = - HkdfExpandLabel(prf, pp_secret, "quic key", crypter->GetKeySize()); - std::vector<uint8_t> iv = - HkdfExpandLabel(prf, pp_secret, "quic iv", crypter->GetIVSize()); + HkdfExpandLabel(prf, pp_secret, getLabelForVersion(version, "key"), + crypter->GetKeySize()); + std::vector<uint8_t> iv = HkdfExpandLabel( + prf, pp_secret, getLabelForVersion(version, "iv"), crypter->GetIVSize()); crypter->SetKey( absl::string_view(reinterpret_cast<char*>(key.data()), key.size())); crypter->SetIV( @@ -115,13 +128,17 @@ } std::vector<uint8_t> CryptoUtils::GenerateHeaderProtectionKey( - const EVP_MD* prf, const std::vector<uint8_t>& pp_secret, size_t out_len) { - return HkdfExpandLabel(prf, pp_secret, "quic hp", out_len); + const EVP_MD* prf, const std::vector<uint8_t>& pp_secret, + const ParsedQuicVersion& version, size_t out_len) { + return HkdfExpandLabel(prf, pp_secret, getLabelForVersion(version, "hp"), + out_len); } std::vector<uint8_t> CryptoUtils::GenerateNextKeyPhaseSecret( - const EVP_MD* prf, const std::vector<uint8_t>& current_secret) { - return HkdfExpandLabel(prf, current_secret, "quic ku", current_secret.size()); + const EVP_MD* prf, const ParsedQuicVersion& version, + const std::vector<uint8_t>& current_secret) { + return HkdfExpandLabel(prf, current_secret, getLabelForVersion(version, "ku"), + current_secret.size()); } namespace { @@ -133,6 +150,9 @@ const uint8_t kRFCv1InitialSalt[] = {0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a}; +const uint8_t kV2Draft01InitialSalt[] = { + 0xa7, 0x07, 0xc2, 0x03, 0xa5, 0x9b, 0x47, 0x18, 0x4a, 0x1d, + 0x62, 0xca, 0x57, 0x04, 0x06, 0xea, 0x7a, 0xe3, 0xe5, 0xd3}; // Salts used by deployed versions of QUIC. When introducing a new version, // generate a new salt by running `openssl rand -hex 20`. @@ -149,9 +169,12 @@ const uint8_t* InitialSaltForVersion(const ParsedQuicVersion& version, size_t* out_len) { - static_assert(SupportedVersions().size() == 5u, + static_assert(SupportedVersions().size() == 6u, "Supported versions out of sync with initial encryption salts"); - if (version == ParsedQuicVersion::RFCv1()) { + if (version == ParsedQuicVersion::V2Draft01()) { + *out_len = ABSL_ARRAYSIZE(kV2Draft01InitialSalt); + return kV2Draft01InitialSalt; + } else if (version == ParsedQuicVersion::RFCv1()) { *out_len = ABSL_ARRAYSIZE(kRFCv1InitialSalt); return kRFCv1InitialSalt; } else if (version == ParsedQuicVersion::Draft29()) { @@ -186,6 +209,11 @@ 0xe3, 0x68, 0xc8, 0x4e}; const uint8_t kRFCv1RetryIntegrityNonce[] = { 0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb}; +const uint8_t kV2Draft01RetryIntegrityKey[] = { + 0xba, 0x85, 0x8d, 0xc7, 0xb4, 0x3d, 0xe5, 0xdb, + 0xf8, 0x76, 0x17, 0xff, 0x4a, 0xb2, 0x53, 0xdb}; +const uint8_t kV2Draft01RetryIntegrityNonce[] = { + 0x14, 0x1b, 0x99, 0xc2, 0x39, 0xb0, 0x3e, 0x78, 0x5d, 0x6a, 0x2e, 0x9f}; // Retry integrity key used by ParsedQuicVersion::ReservedForNegotiation(). const uint8_t kReservedForNegotiationRetryIntegrityKey[] = { 0xf2, 0xcd, 0x8f, 0xe0, 0x36, 0xd0, 0x25, 0x35, @@ -199,13 +227,21 @@ bool RetryIntegrityKeysForVersion(const ParsedQuicVersion& version, absl::string_view* key, absl::string_view* nonce) { - static_assert(SupportedVersions().size() == 5u, + static_assert(SupportedVersions().size() == 6u, "Supported versions out of sync with retry integrity keys"); if (!version.UsesTls()) { QUIC_BUG(quic_bug_10699_2) << "Attempted to get retry integrity keys for invalid version " << version; return false; + } else if (version == ParsedQuicVersion::V2Draft01()) { + *key = absl::string_view( + reinterpret_cast<const char*>(kV2Draft01RetryIntegrityKey), + ABSL_ARRAYSIZE(kV2Draft01RetryIntegrityKey)); + *nonce = absl::string_view( + reinterpret_cast<const char*>(kV2Draft01RetryIntegrityNonce), + ABSL_ARRAYSIZE(kV2Draft01RetryIntegrityNonce)); + return true; } else if (version == ParsedQuicVersion::RFCv1()) { *key = absl::string_view( reinterpret_cast<const char*>(kRFCv1RetryIntegrityKey), @@ -286,12 +322,14 @@ std::vector<uint8_t> encryption_secret = HkdfExpandLabel( hash, handshake_secret, encryption_label, EVP_MD_size(hash)); crypters->encrypter = std::make_unique<Aes128GcmEncrypter>(); - InitializeCrypterSecrets(hash, encryption_secret, crypters->encrypter.get()); + InitializeCrypterSecrets(hash, encryption_secret, version, + crypters->encrypter.get()); std::vector<uint8_t> decryption_secret = HkdfExpandLabel( hash, handshake_secret, decryption_label, EVP_MD_size(hash)); crypters->decrypter = std::make_unique<Aes128GcmDecrypter>(); - InitializeCrypterSecrets(hash, decryption_secret, crypters->decrypter.get()); + InitializeCrypterSecrets(hash, decryption_secret, version, + crypters->decrypter.get()); } // static
diff --git a/quic/core/crypto/crypto_utils.h b/quic/core/crypto/crypto_utils.h index 5e603f8..fce6201 100644 --- a/quic/core/crypto/crypto_utils.h +++ b/quic/core/crypto/crypto_utils.h
@@ -79,9 +79,11 @@ // on the given QuicCrypter |*crypter|. // This follows the derivation described in section 7.3 of RFC 8446, except // with the label prefix in HKDF-Expand-Label changed from "tls13 " to "quic " - // as described in draft-ietf-quic-tls-14, section 5.1. + // as described in draft-ietf-quic-tls-14, section 5.1, or "quicv2 " as + // described in draft-ietf-quic-v2-01. static void InitializeCrypterSecrets(const EVP_MD* prf, const std::vector<uint8_t>& pp_secret, + const ParsedQuicVersion& version, QuicCrypter* crypter); // Derives the key and IV from the packet protection secret and sets those @@ -90,15 +92,18 @@ // called before using |crypter|. static void SetKeyAndIV(const EVP_MD* prf, const std::vector<uint8_t>& pp_secret, + const ParsedQuicVersion& version, QuicCrypter* crypter); // Derives the header protection key from the packet protection secret. static std::vector<uint8_t> GenerateHeaderProtectionKey( - const EVP_MD* prf, const std::vector<uint8_t>& pp_secret, size_t out_len); + const EVP_MD* prf, const std::vector<uint8_t>& pp_secret, + const ParsedQuicVersion& version, size_t out_len); // Given a secret for key phase n, return the secret for phase n+1. static std::vector<uint8_t> GenerateNextKeyPhaseSecret( - const EVP_MD* prf, const std::vector<uint8_t>& current_secret); + const EVP_MD* prf, const ParsedQuicVersion& version, + const std::vector<uint8_t>& current_secret); // IETF QUIC encrypts ENCRYPTION_INITIAL messages with a version-specific key // (to prevent network observers that are not aware of that QUIC version from
diff --git a/quic/core/crypto/crypto_utils_test.cc b/quic/core/crypto/crypto_utils_test.cc index f0706b4..f0d944b 100644 --- a/quic/core/crypto/crypto_utils_test.cc +++ b/quic/core/crypto/crypto_utils_test.cc
@@ -8,6 +8,7 @@ #include "absl/base/macros.h" #include "absl/strings/escaping.h" +#include "absl/strings/string_view.h" #include "quic/core/quic_utils.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/quic_test_utils.h" @@ -172,7 +173,7 @@ // if the number of HTTP/3 QUIC versions has changed, we need to change the // expected_keys hardcoded into this test. Regrettably, this is not a // compile-time constant. - EXPECT_EQ(AllSupportedVersionsWithTls().size(), 2u); + EXPECT_EQ(AllSupportedVersionsWithTls().size(), 3u); const char draft_29_key[] = {// test vector from draft-ietf-quic-tls-29, A.1 0x14, static_cast<char>(0x9d), @@ -207,6 +208,23 @@ 0x06, 0x7e, 0x37}; + const char v2_01_key[] = {// test vector from draft-ietf-quic-v2-01 + 0x15, + static_cast<char>(0xd5), + static_cast<char>(0xb4), + static_cast<char>(0xd9), + static_cast<char>(0xa2), + static_cast<char>(0xb8), + static_cast<char>(0x91), + 0x6a, + static_cast<char>(0xa3), + static_cast<char>(0x9b), + 0x1b, + static_cast<char>(0xfe), + 0x57, + 0x4d, + 0x2a, + static_cast<char>(0xad)}; const char connection_id[] = // test vector from both docs {static_cast<char>(0x83), static_cast<char>(0x94), @@ -226,6 +244,9 @@ } else if (version == ParsedQuicVersion::RFCv1()) { key_str = v1_key; key_size = sizeof(v1_key); + } else { // draft-ietf-quic-v2-01 + key_str = v2_01_key; + key_size = sizeof(v2_01_key); } const absl::string_view expected_key{key_str, key_size};
diff --git a/quic/core/handshaker_delegate_interface.h b/quic/core/handshaker_delegate_interface.h index fb0ad66..7fbc5ae 100644 --- a/quic/core/handshaker_delegate_interface.h +++ b/quic/core/handshaker_delegate_interface.h
@@ -7,6 +7,7 @@ #include "quic/core/crypto/transport_parameters.h" #include "quic/core/quic_types.h" +#include "quic/core/quic_versions.h" namespace quic { @@ -73,6 +74,10 @@ // Whether a packet flusher is currently attached. virtual bool PacketFlusherAttached() const = 0; + + // Get the QUIC version currently in use. tls_handshaker needs this to pass + // to crypto_utils to apply version-dependent HKDF labels. + virtual ParsedQuicVersion parsed_version() const = 0; }; } // namespace quic
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc index 04740e8..cad9cac 100644 --- a/quic/core/http/end_to_end_test.cc +++ b/quic/core/http/end_to_end_test.cc
@@ -5702,6 +5702,9 @@ } bool TypeByteIsServerHello(uint8_t type_byte) { + if (version_.UsesV2PacketTypes()) { + return ((type_byte & 0x30) >> 4) == 3; + } if (version_.UsesQuicCrypto()) { // ENCRYPTION_ZERO_RTT packet. return ((type_byte & 0x30) >> 4) == 1; @@ -5758,7 +5761,8 @@ class BadShloPacketWriter2 : public QuicPacketWriterWrapper { public: - BadShloPacketWriter2() : error_returned_(false) {} + BadShloPacketWriter2(ParsedQuicVersion version) + : error_returned_(false), version_(version) {} ~BadShloPacketWriter2() override {} WriteResult WritePacket(const char* buffer, size_t buf_len, @@ -5766,12 +5770,14 @@ const QuicSocketAddress& peer_address, quic::PerPacketOptions* options) override { const uint8_t type_byte = buffer[0]; - if ((type_byte & FLAGS_LONG_HEADER) && - (((type_byte & 0x30) >> 4) == 1 || (type_byte & 0x7F) == 0x7C)) { - QUIC_DVLOG(1) << "Dropping ZERO_RTT_PACKET packet"; - return WriteResult(WRITE_STATUS_OK, buf_len); - } - if (!error_returned_ && !(type_byte & FLAGS_LONG_HEADER)) { + + if (type_byte & FLAGS_LONG_HEADER) { + if (((type_byte & 0x30 >> 4) == (version_.UsesV2PacketTypes() ? 2 : 1)) || + ((type_byte & 0x7F) == 0x7C)) { + QUIC_DVLOG(1) << "Dropping ZERO_RTT_PACKET packet"; + return WriteResult(WRITE_STATUS_OK, buf_len); + } + } else if (!error_returned_) { QUIC_DVLOG(1) << "Return write error for short header packet"; error_returned_ = true; return WriteResult(WRITE_STATUS_ERROR, QUIC_EMSGSIZE); @@ -5782,6 +5788,7 @@ private: bool error_returned_; + ParsedQuicVersion version_; }; TEST_P(EndToEndTest, ForwardSecureConnectionClose) { @@ -5812,7 +5819,7 @@ dispatcher, // This causes the all server sent ZERO_RTT_PROTECTED packets to be // dropped, and first short header packet causes write error. - new BadShloPacketWriter2()); + new BadShloPacketWriter2(version_)); server_thread_->Resume(); client_.reset(CreateQuicClient(client_writer_)); EXPECT_EQ("", client_->SendSynchronousRequest("/foo"));
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index d9d1a34..053849f 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -10473,7 +10473,12 @@ return; } - // These values come from draft-ietf-quic-tls Appendix A.4. + // These values come from draft-ietf-quic-v2 Appendix A.4. + uint8_t retry_packet_rfcv2[] = { + 0xcf, 0x70, 0x9a, 0x50, 0xc4, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, + 0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x1d, 0xc7, 0x11, 0x30, + 0xcd, 0x1e, 0xd3, 0x9d, 0x6e, 0xfc, 0xee, 0x5c, 0x85, 0x80, 0x65, 0x01}; + // These values come from RFC9001 Appendix A.4. uint8_t retry_packet_rfcv1[] = { 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x04, 0xa2, 0x65, 0xba, @@ -10485,7 +10490,10 @@ uint8_t* retry_packet; size_t retry_packet_length; - if (version() == ParsedQuicVersion::RFCv1()) { + if (version() == ParsedQuicVersion::V2Draft01()) { + retry_packet = retry_packet_rfcv2; + retry_packet_length = ABSL_ARRAYSIZE(retry_packet_rfcv2); + } else if (version() == ParsedQuicVersion::RFCv1()) { retry_packet = retry_packet_rfcv1; retry_packet_length = ABSL_ARRAYSIZE(retry_packet_rfcv1); } else if (version() == ParsedQuicVersion::Draft29()) {
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc index ca4ae48..add5164 100644 --- a/quic/core/quic_dispatcher_test.cc +++ b/quic/core/quic_dispatcher_test.cc
@@ -1521,7 +1521,7 @@ dispatcher_->ProcessPacket(server_address_, client_address, received_packet); } -static_assert(quic::SupportedVersions().size() == 5u, +static_assert(quic::SupportedVersions().size() == 6u, "Please add new RejectDeprecatedVersion tests above this assert " "when deprecating versions");
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h index 77a53e2..b692cf5 100644 --- a/quic/core/quic_flags_list.h +++ b/quic/core/quic_flags_list.h
@@ -133,6 +133,8 @@ QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_pacing_sender_bursts, true) // When true, set the initial congestion control window from connection options in QuicSentPacketManager rather than TcpCubicSenderBytes. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_unified_iw_options, true) +// When true, support draft-ietf-quic-v2-01 +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_version_2_draft_01, false) // When true, the B203 connection option causes the Bbr2Sender to ignore inflight_hi during PROBE_UP and increase it when the bytes delivered without loss are higher. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_ignore_inflight_hi_in_probe_up, true) // When true, the B205 connection option enables extra acked in STARTUP, and B204 adds new logic to decrease it whenever max bandwidth increases.
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc index d292d84..da28e4c 100644 --- a/quic/core/quic_framer.cc +++ b/quic/core/quic_framer.cc
@@ -196,16 +196,17 @@ return static_cast<QuicPacketNumberLength>((type & 0x03) + 1); } -uint8_t LongHeaderTypeToOnWireValue(QuicLongHeaderType type) { +uint8_t LongHeaderTypeToOnWireValue(QuicLongHeaderType type, + const ParsedQuicVersion& version) { switch (type) { case INITIAL: - return 0; + return version.UsesV2PacketTypes() ? (1 << 4) : 0; case ZERO_RTT_PROTECTED: - return 1 << 4; + return version.UsesV2PacketTypes() ? (2 << 4) : (1 << 4); case HANDSHAKE: - return 2 << 4; + return version.UsesV2PacketTypes() ? (3 << 4) : (2 << 4); case RETRY: - return 3 << 4; + return version.UsesV2PacketTypes() ? 0 : (3 << 4); case VERSION_NEGOTIATION: return 0xF0; // Value does not matter default: @@ -214,27 +215,22 @@ } } -bool GetLongHeaderType(uint8_t type, QuicLongHeaderType* long_header_type) { +QuicLongHeaderType GetLongHeaderType(uint8_t type, + const ParsedQuicVersion& version) { QUICHE_DCHECK((type & FLAGS_LONG_HEADER)); switch ((type & 0x30) >> 4) { case 0: - *long_header_type = INITIAL; - break; + return version.UsesV2PacketTypes() ? RETRY : INITIAL; case 1: - *long_header_type = ZERO_RTT_PROTECTED; - break; + return version.UsesV2PacketTypes() ? INITIAL : ZERO_RTT_PROTECTED; case 2: - *long_header_type = HANDSHAKE; - break; + return version.UsesV2PacketTypes() ? ZERO_RTT_PROTECTED : HANDSHAKE; case 3: - *long_header_type = RETRY; - break; + return version.UsesV2PacketTypes() ? HANDSHAKE : RETRY; default: QUIC_BUG(quic_bug_10850_4) << "Unreachable statement"; - *long_header_type = INVALID_PACKET_TYPE; - return false; + return INVALID_PACKET_TYPE; } - return true; } QuicPacketNumberLength GetLongHeaderPacketNumberLength(uint8_t type) { @@ -2213,7 +2209,7 @@ if (header.version_flag) { type = static_cast<uint8_t>( FLAGS_LONG_HEADER | FLAGS_FIXED_BIT | - LongHeaderTypeToOnWireValue(header.long_packet_type) | + LongHeaderTypeToOnWireValue(header.long_packet_type, version_) | PacketNumberLengthToOnWireValue(header.packet_number_length)); } else { type = static_cast<uint8_t>( @@ -2623,21 +2619,27 @@ set_detailed_error("Fixed bit is 0 in long header."); return false; } - if (!GetLongHeaderType(type, &header->long_packet_type)) { - set_detailed_error("Illegal long header type value."); - return false; - } - if (header->long_packet_type == RETRY) { - if (!version().SupportsRetry()) { - set_detailed_error("RETRY not supported in this version."); + header->long_packet_type = GetLongHeaderType(type, header->version); + switch (header->long_packet_type) { + case INVALID_PACKET_TYPE: + set_detailed_error("Illegal long header type value."); return false; - } - if (perspective_ == Perspective::IS_SERVER) { - set_detailed_error("Client-initiated RETRY is invalid."); - return false; - } - } else if (!header->version.HasHeaderProtection()) { - header->packet_number_length = GetLongHeaderPacketNumberLength(type); + case RETRY: + if (!version().SupportsRetry()) { + set_detailed_error("RETRY not supported in this version."); + return false; + } + if (perspective_ == Perspective::IS_SERVER) { + set_detailed_error("Client-initiated RETRY is invalid."); + return false; + } + break; + default: + if (!header->version.HasHeaderProtection()) { + header->packet_number_length = + GetLongHeaderPacketNumberLength(type); + } + break; } } } @@ -4592,7 +4594,8 @@ QuicLongHeaderType header_type; if (IsLongHeader(type_byte)) { bitmask = 0x0f; - if (!GetLongHeaderType(type_byte, &header_type)) { + header_type = GetLongHeaderType(type_byte, version_); + if (header_type == INVALID_PACKET_TYPE) { return false; } } @@ -6889,15 +6892,15 @@ } inline bool ParseLongHeaderConnectionIds( - QuicDataReader* reader, bool has_length_prefix, - QuicVersionLabel version_label, QuicConnectionId* destination_connection_id, - QuicConnectionId* source_connection_id, std::string* detailed_error) { + QuicDataReader& reader, bool has_length_prefix, + QuicVersionLabel version_label, QuicConnectionId& destination_connection_id, + QuicConnectionId& source_connection_id, std::string& detailed_error) { if (has_length_prefix) { - if (!reader->ReadLengthPrefixedConnectionId(destination_connection_id)) { - *detailed_error = "Unable to read destination connection ID."; + if (!reader.ReadLengthPrefixedConnectionId(&destination_connection_id)) { + detailed_error = "Unable to read destination connection ID."; return false; } - if (!reader->ReadLengthPrefixedConnectionId(source_connection_id)) { + if (!reader.ReadLengthPrefixedConnectionId(&source_connection_id)) { if (version_label == kProxVersionLabel) { // The "PROX" version does not follow the length-prefixed invariants, // and can therefore attempt to read a payload byte and interpret it @@ -6906,14 +6909,14 @@ // parsing as successful. return true; } - *detailed_error = "Unable to read source connection ID."; + detailed_error = "Unable to read source connection ID."; return false; } } else { // Parse connection ID lengths. uint8_t connection_id_lengths_byte; - if (!reader->ReadUInt8(&connection_id_lengths_byte)) { - *detailed_error = "Unable to read connection ID lengths."; + if (!reader.ReadUInt8(&connection_id_lengths_byte)) { + detailed_error = "Unable to read connection ID lengths."; return false; } uint8_t destination_connection_id_length = @@ -6928,16 +6931,16 @@ } // Read destination connection ID. - if (!reader->ReadConnectionId(destination_connection_id, - destination_connection_id_length)) { - *detailed_error = "Unable to read destination connection ID."; + if (!reader.ReadConnectionId(&destination_connection_id, + destination_connection_id_length)) { + detailed_error = "Unable to read destination connection ID."; return false; } // Read source connection ID. - if (!reader->ReadConnectionId(source_connection_id, - source_connection_id_length)) { - *detailed_error = "Unable to read source connection ID."; + if (!reader.ReadConnectionId(&source_connection_id, + source_connection_id_length)) { + detailed_error = "Unable to read source connection ID."; return false; } } @@ -7010,9 +7013,9 @@ *reader, *parsed_version, *version_label, *first_byte); // Parse connection IDs. - if (!ParseLongHeaderConnectionIds(reader, *has_length_prefix, *version_label, - destination_connection_id, - source_connection_id, detailed_error)) { + if (!ParseLongHeaderConnectionIds(*reader, *has_length_prefix, *version_label, + *destination_connection_id, + *source_connection_id, *detailed_error)) { return QUIC_INVALID_PACKET_HEADER; } @@ -7022,14 +7025,20 @@ } // Parse long packet type. - if (!GetLongHeaderType(*first_byte, long_packet_type)) { - *detailed_error = "Unable to parse long packet type."; - return QUIC_INVALID_PACKET_HEADER; - } + *long_packet_type = GetLongHeaderType(*first_byte, *parsed_version); - if (!parsed_version->SupportsRetry() || *long_packet_type != INITIAL) { - // Retry token is only present on initial packets for some versions. - return QUIC_NO_ERROR; + switch (*long_packet_type) { + case INVALID_PACKET_TYPE: + *detailed_error = "Unable to parse long packet type."; + return QUIC_INVALID_PACKET_HEADER; + case INITIAL: + if (!parsed_version->SupportsRetry()) { + // Retry token is only present on initial packets for some versions. + return QUIC_NO_ERROR; + } + break; + default: + return QUIC_NO_ERROR; } *retry_token_length_length = reader->PeekVarInt62Length();
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc index d893eb9..d24664d 100644 --- a/quic/core/quic_framer_test.cc +++ b/quic/core/quic_framer_test.cc
@@ -720,6 +720,19 @@ return (CreateQuicVersionLabel(version_) >> 8 * (3 - pos)) & 0xff; } + // Helper functions to take a v1 long header packet and make it v2. These are + // not needed for short header packets, but if sent, this function will exit + // cleanly. It needs to be called twice for coalesced packets (see references + // to length_of_first_coalesced_packet below for examples of how to do this). + inline void ReviseFirstByteByVersion(unsigned char packet_ietf[]) { + if (version_.UsesV2PacketTypes() && (packet_ietf[0] >= 0x80)) { + packet_ietf[0] = (packet_ietf[0] + 0x10) | 0xc0; + } + } + inline void ReviseFirstByteByVersion(PacketFragments& packet_ietf) { + ReviseFirstByteByVersion(&packet_ietf[0].fragment[0]); + } + bool CheckEncryption(QuicPacketNumber packet_number, QuicPacket* packet) { if (packet_number != encrypter_->packet_number_) { QUIC_LOG(ERROR) << "Encrypted incorrect packet number. expected " @@ -1261,6 +1274,7 @@ unsigned char* p = packet; size_t p_length = ABSL_ARRAYSIZE(packet); if (framer_.version().HasLongHeaderLengths()) { + ReviseFirstByteByVersion(packet49); p = packet49; p_length = ABSL_ARRAYSIZE(packet49); } @@ -1367,6 +1381,7 @@ unsigned char* p = packet; size_t p_length = ABSL_ARRAYSIZE(packet); if (framer_.version().HasLongHeaderLengths()) { + ReviseFirstByteByVersion(packet49); p = packet49; p_length = ABSL_ARRAYSIZE(packet49); } else if (framer_.version().HasIetfInvariantHeader()) { @@ -1657,6 +1672,7 @@ }; // clang-format on + ReviseFirstByteByVersion(packet49); PacketFragments& fragments = framer_.version().HasLongHeaderLengths() ? packet49 @@ -2958,6 +2974,7 @@ ? VARIABLE_LENGTH_INTEGER_LENGTH_1 : VARIABLE_LENGTH_INTEGER_LENGTH_0; + ReviseFirstByteByVersion(packet_ietf); PacketFragments& fragments = VersionHasIetfQuicFrames(framer_.transport_version()) ? packet_ietf @@ -6408,6 +6425,7 @@ unsigned char* p = packet; size_t p_length = ABSL_ARRAYSIZE(packet); if (framer_.version().UsesTls()) { + ReviseFirstByteByVersion(packet_with_tag); p = packet_with_tag; p_length = ABSL_ARRAYSIZE(packet_with_tag); } else if (framer_.version().HasLongHeaderLengths()) { @@ -7103,6 +7121,7 @@ unsigned char* p = packet; size_t p_size = ABSL_ARRAYSIZE(packet); if (VersionHasIetfQuicFrames(framer_.transport_version())) { + ReviseFirstByteByVersion(packet_ietf); p = packet_ietf; p_size = ABSL_ARRAYSIZE(packet_ietf); } else if (framer_.version().HasLongHeaderLengths()) { @@ -13722,10 +13741,16 @@ 'R', 'L', 'D', '?', }; // clang-format on + const size_t first_packet_ietf_size = 46; + // If the first packet changes, the attempt to fix the first byte of the + // second packet will fail. + EXPECT_EQ(packet_ietf[first_packet_ietf_size], 0xD3); unsigned char* p = packet; size_t p_length = ABSL_ARRAYSIZE(packet); if (framer_.version().HasIetfQuicFrames()) { + ReviseFirstByteByVersion(packet_ietf); + ReviseFirstByteByVersion(&packet_ietf[first_packet_ietf_size]); p = packet_ietf; p_length = ABSL_ARRAYSIZE(packet_ietf); } @@ -13845,6 +13870,7 @@ unsigned char* p = packet; size_t p_length = ABSL_ARRAYSIZE(packet); if (framer_.version().HasIetfQuicFrames()) { + ReviseFirstByteByVersion(packet_ietf); p = packet_ietf; p_length = ABSL_ARRAYSIZE(packet_ietf); } @@ -13992,10 +14018,16 @@ 'R', 'L', 'D', '?', }; // clang-format on + const size_t first_packet_ietf_size = 46; + // If the first packet changes, the attempt to fix the first byte of the + // second packet will fail. + EXPECT_EQ(packet_ietf[first_packet_ietf_size], 0xD3); unsigned char* p = packet; size_t p_length = ABSL_ARRAYSIZE(packet); if (framer_.version().HasIetfQuicFrames()) { + ReviseFirstByteByVersion(packet_ietf); + ReviseFirstByteByVersion(&packet_ietf[first_packet_ietf_size]); p = packet_ietf; p_length = ABSL_ARRAYSIZE(packet_ietf); } @@ -14103,6 +14135,7 @@ unsigned char* p = packet; size_t p_length = ABSL_ARRAYSIZE(packet); if (framer_.version().HasLongHeaderLengths()) { + ReviseFirstByteByVersion(packet49); p = packet49; p_length = ABSL_ARRAYSIZE(packet49); } else if (framer_.version().HasIetfInvariantHeader()) { @@ -14205,6 +14238,7 @@ unsigned char* p = packet; size_t p_length = ABSL_ARRAYSIZE(packet); if (framer_.version().HasLongHeaderLengths()) { + ReviseFirstByteByVersion(packet49); p = packet49; p_length = ABSL_ARRAYSIZE(packet49); } else if (framer_.version().HasIetfInvariantHeader()) { @@ -14365,10 +14399,15 @@ }; // clang-format on const size_t length_of_first_coalesced_packet = 46; + // If the first packet changes, the attempt to fix the first byte of the + // second packet will fail. + EXPECT_EQ(packet_ietf[length_of_first_coalesced_packet], 0xD3); unsigned char* p = packet; size_t p_length = ABSL_ARRAYSIZE(packet); if (framer_.version().HasIetfQuicFrames()) { + ReviseFirstByteByVersion(packet_ietf); + ReviseFirstByteByVersion(&packet_ietf[length_of_first_coalesced_packet]); p = packet_ietf; p_length = ABSL_ARRAYSIZE(packet_ietf); } @@ -14532,10 +14571,16 @@ 'R', 'L', 'D', '?', }; // clang-format on + const size_t length_of_first_coalesced_packet = 46; + // If the first packet changes, the attempt to fix the first byte of the + // second packet will fail. + EXPECT_EQ(packet_ietf[length_of_first_coalesced_packet], 0xD3); unsigned char* p = packet; size_t p_length = ABSL_ARRAYSIZE(packet); if (framer_.version().HasIetfQuicFrames()) { + ReviseFirstByteByVersion(packet_ietf); + ReviseFirstByteByVersion(&packet_ietf[length_of_first_coalesced_packet]); p = packet_ietf; p_length = ABSL_ARRAYSIZE(packet_ietf); } @@ -14637,10 +14682,16 @@ // version would be here but we cut off the invalid coalesced header. }; // clang-format on + const size_t length_of_first_coalesced_packet = 46; + // If the first packet changes, the attempt to fix the first byte of the + // second packet will fail. + EXPECT_EQ(packet_ietf[length_of_first_coalesced_packet], 0xD3); unsigned char* p = packet; size_t p_length = ABSL_ARRAYSIZE(packet); if (framer_.version().HasIetfQuicFrames()) { + ReviseFirstByteByVersion(packet_ietf); + ReviseFirstByteByVersion(&packet_ietf[length_of_first_coalesced_packet]); p = packet_ietf; p_length = ABSL_ARRAYSIZE(packet_ietf); } @@ -14868,6 +14919,7 @@ QuicEncryptedPacket(AsChars(long_header_packet), ABSL_ARRAYSIZE(long_header_packet), false))); } else { + ReviseFirstByteByVersion(long_header_packet_ietf); EXPECT_TRUE(framer_.ProcessPacket( QuicEncryptedPacket(AsChars(long_header_packet_ietf), ABSL_ARRAYSIZE(long_header_packet_ietf), false))); @@ -15396,9 +15448,11 @@ 0x00, }; // clang-format on + unsigned char* p = packet; size_t p_length = ABSL_ARRAYSIZE(packet); if (framer_.version().HasLongHeaderLengths()) { + ReviseFirstByteByVersion(packet49); p = packet49; p_length = ABSL_ARRAYSIZE(packet49); } @@ -15464,6 +15518,7 @@ unsigned char* p = packet; size_t p_length = ABSL_ARRAYSIZE(packet); if (framer_.version().HasLongHeaderLengths()) { + ReviseFirstByteByVersion(packet49); p = packet49; p_length = ABSL_ARRAYSIZE(packet49); } @@ -16303,6 +16358,7 @@ }; // clang-format on + ReviseFirstByteByVersion(packet); QuicEncryptedPacket encrypted(AsChars(packet), ABSL_ARRAYSIZE(packet), false); EXPECT_FALSE(framer_.ProcessPacket(encrypted));
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h index d06e1fe..88ae992 100644 --- a/quic/core/quic_session.h +++ b/quic/core/quic_session.h
@@ -312,6 +312,7 @@ std::string* error_details) override; void OnHandshakeCallbackDone() override; bool PacketFlusherAttached() const override; + ParsedQuicVersion parsed_version() const override { return version(); } // Implement StreamDelegateInterface. void OnStreamError(QuicErrorCode error_code,
diff --git a/quic/core/quic_version_manager.cc b/quic/core/quic_version_manager.cc index 13e590d..1309456 100644 --- a/quic/core/quic_version_manager.cc +++ b/quic/core/quic_version_manager.cc
@@ -36,9 +36,11 @@ } void QuicVersionManager::MaybeRefilterSupportedVersions() { - static_assert(SupportedVersions().size() == 5u, + static_assert(SupportedVersions().size() == 6u, "Supported versions out of sync"); - if (disable_version_rfcv1_ != + if (enable_version_2_draft_01_ != + GetQuicReloadableFlag(quic_enable_version_2_draft_01) || + disable_version_rfcv1_ != GetQuicReloadableFlag(quic_disable_version_rfcv1) || disable_version_draft_29_ != GetQuicReloadableFlag(quic_disable_version_draft_29) || @@ -48,6 +50,8 @@ GetQuicReloadableFlag(quic_disable_version_q046) || disable_version_q043_ != GetQuicReloadableFlag(quic_disable_version_q043)) { + enable_version_2_draft_01_ = + GetQuicReloadableFlag(quic_enable_version_2_draft_01); disable_version_rfcv1_ = GetQuicReloadableFlag(quic_disable_version_rfcv1); disable_version_draft_29_ = GetQuicReloadableFlag(quic_disable_version_draft_29); @@ -75,7 +79,11 @@ if (version.UsesHttp3()) { filtered_supported_versions_with_http3_.push_back(version); } - filtered_supported_alpns_.emplace_back(AlpnForVersion(version)); + if (std::find(filtered_supported_alpns_.begin(), + filtered_supported_alpns_.end(), + AlpnForVersion(version)) == filtered_supported_alpns_.end()) { + filtered_supported_alpns_.emplace_back(AlpnForVersion(version)); + } } }
diff --git a/quic/core/quic_version_manager.h b/quic/core/quic_version_manager.h index af44d34..44e134a 100644 --- a/quic/core/quic_version_manager.h +++ b/quic/core/quic_version_manager.h
@@ -55,6 +55,8 @@ private: // Cached value of reloadable flags. + // quic_enable_version_2_draft_01 flag + bool enable_version_2_draft_01_ = false; // quic_disable_version_rfcv1 flag bool disable_version_rfcv1_ = true; // quic_disable_version_draft_29 flag
diff --git a/quic/core/quic_version_manager_test.cc b/quic/core/quic_version_manager_test.cc index 403009a..da87c4a 100644 --- a/quic/core/quic_version_manager_test.cc +++ b/quic/core/quic_version_manager_test.cc
@@ -18,11 +18,12 @@ class QuicVersionManagerTest : public QuicTest {}; TEST_F(QuicVersionManagerTest, QuicVersionManager) { - static_assert(SupportedVersions().size() == 5u, + static_assert(SupportedVersions().size() == 6u, "Supported versions out of sync"); for (const ParsedQuicVersion& version : AllSupportedVersions()) { QuicEnableVersion(version); } + QuicDisableVersion(ParsedQuicVersion::V2Draft01()); QuicDisableVersion(ParsedQuicVersion::RFCv1()); QuicDisableVersion(ParsedQuicVersion::Draft29()); QuicVersionManager manager(AllSupportedVersions()); @@ -65,6 +66,20 @@ manager.GetSupportedVersionsWithOnlyHttp3()); EXPECT_THAT(manager.GetSupportedAlpns(), ElementsAre("h3", "h3-29", "h3-Q050", "h3-Q046", "h3-Q043")); + + offset++; + QuicEnableVersion(ParsedQuicVersion::V2Draft01()); + expected_parsed_versions.insert(expected_parsed_versions.begin(), + ParsedQuicVersion::V2Draft01()); + EXPECT_EQ(expected_parsed_versions, manager.GetSupportedVersions()); + EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()), + manager.GetSupportedVersions()); + EXPECT_EQ(3u, manager.GetSupportedVersionsWithOnlyHttp3().size()); + EXPECT_EQ(CurrentSupportedHttp3Versions(), + manager.GetSupportedVersionsWithOnlyHttp3()); + EXPECT_THAT( + manager.GetSupportedAlpns(), + ElementsAre("h3", "h3-29", "h3-Q050", "h3-Q046", "h3-Q043")); } } // namespace
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc index 9dd0cc9..21ec163 100644 --- a/quic/core/quic_versions.cc +++ b/quic/core/quic_versions.cc
@@ -36,11 +36,13 @@ } void SetVersionFlag(const ParsedQuicVersion& version, bool should_enable) { - static_assert(SupportedVersions().size() == 5u, + static_assert(SupportedVersions().size() == 6u, "Supported versions out of sync"); const bool enable = should_enable; const bool disable = !should_enable; - if (version == ParsedQuicVersion::RFCv1()) { + if (version == ParsedQuicVersion::V2Draft01()) { + SetQuicReloadableFlag(quic_enable_version_2_draft_01, enable); + } else if (version == ParsedQuicVersion::RFCv1()) { SetQuicReloadableFlag(quic_disable_version_rfcv1, disable); } else if (version == ParsedQuicVersion::Draft29()) { SetQuicReloadableFlag(quic_disable_version_draft_29, disable); @@ -176,6 +178,16 @@ return handshake_protocol == PROTOCOL_QUIC_CRYPTO; } +bool ParsedQuicVersion::UsesV2PacketTypes() const { + QUICHE_DCHECK(IsKnown()); + return transport_version == QUIC_VERSION_IETF_2_DRAFT_01; +} + +bool ParsedQuicVersion::AlpnDeferToRFCv1() const { + QUICHE_DCHECK(IsKnown()); + return transport_version == QUIC_VERSION_IETF_2_DRAFT_01; +} + bool VersionHasLengthPrefixedConnectionIds( QuicTransportVersion transport_version) { QUICHE_DCHECK(transport_version != QUIC_VERSION_UNSUPPORTED); @@ -211,9 +223,11 @@ } QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) { - static_assert(SupportedVersions().size() == 5u, + static_assert(SupportedVersions().size() == 6u, "Supported versions out of sync"); - if (parsed_version == ParsedQuicVersion::RFCv1()) { + if (parsed_version == ParsedQuicVersion::V2Draft01()) { + return MakeVersionLabel(0x70, 0x9a, 0x50, 0xc4); + } else if (parsed_version == ParsedQuicVersion::RFCv1()) { return MakeVersionLabel(0x00, 0x00, 0x00, 0x01); } else if (parsed_version == ParsedQuicVersion::Draft29()) { return MakeVersionLabel(0xff, 0x00, 0x00, 29); @@ -334,7 +348,8 @@ const ParsedQuicVersionVector supported_versions = AllSupportedVersions(); for (const ParsedQuicVersion& version : supported_versions) { if (version_string == ParsedQuicVersionToString(version) || - version_string == AlpnForVersion(version) || + (version_string == AlpnForVersion(version) && + !version.AlpnDeferToRFCv1()) || (version.handshake_protocol == PROTOCOL_QUIC_CRYPTO && version_string == QuicVersionToString(version.transport_version))) { return version; @@ -409,10 +424,16 @@ ParsedQuicVersionVector FilterSupportedVersions( ParsedQuicVersionVector versions) { + static_assert(SupportedVersions().size() == 6u, + "Supported versions out of sync"); ParsedQuicVersionVector filtered_versions; filtered_versions.reserve(versions.size()); for (const ParsedQuicVersion& version : versions) { - if (version == ParsedQuicVersion::RFCv1()) { + if (version == ParsedQuicVersion::V2Draft01()) { + if (GetQuicReloadableFlag(quic_enable_version_2_draft_01)) { + filtered_versions.push_back(version); + } + } else if (version == ParsedQuicVersion::RFCv1()) { if (!GetQuicReloadableFlag(quic_disable_version_rfcv1)) { filtered_versions.push_back(version); } @@ -498,6 +519,7 @@ RETURN_STRING_LITERAL(QUIC_VERSION_50); RETURN_STRING_LITERAL(QUIC_VERSION_IETF_DRAFT_29); RETURN_STRING_LITERAL(QUIC_VERSION_IETF_RFC_V1); + RETURN_STRING_LITERAL(QUIC_VERSION_IETF_2_DRAFT_01); RETURN_STRING_LITERAL(QUIC_VERSION_UNSUPPORTED); RETURN_STRING_LITERAL(QUIC_VERSION_RESERVED_FOR_NEGOTIATION); } @@ -516,10 +538,13 @@ } std::string ParsedQuicVersionToString(ParsedQuicVersion version) { - static_assert(SupportedVersions().size() == 5u, + static_assert(SupportedVersions().size() == 6u, "Supported versions out of sync"); if (version == UnsupportedQuicVersion()) { return "0"; + } else if (version == ParsedQuicVersion::V2Draft01()) { + QUICHE_DCHECK(version.UsesHttp3()); + return "v2draft01"; } else if (version == ParsedQuicVersion::RFCv1()) { QUICHE_DCHECK(version.UsesHttp3()); return "RFCv1"; @@ -611,7 +636,9 @@ } std::string AlpnForVersion(ParsedQuicVersion parsed_version) { - if (parsed_version == ParsedQuicVersion::RFCv1()) { + if (parsed_version == ParsedQuicVersion::V2Draft01()) { + return "h3"; + } else if (parsed_version == ParsedQuicVersion::RFCv1()) { return "h3"; } else if (parsed_version == ParsedQuicVersion::Draft29()) { return "h3-29";
diff --git a/quic/core/quic_versions.h b/quic/core/quic_versions.h index 4e16fef..59bf753 100644 --- a/quic/core/quic_versions.h +++ b/quic/core/quic_versions.h
@@ -123,8 +123,9 @@ // Number 70 used to represent draft-ietf-quic-transport-25. // Number 71 used to represent draft-ietf-quic-transport-27. // Number 72 used to represent draft-ietf-quic-transport-28. - QUIC_VERSION_IETF_DRAFT_29 = 73, // draft-ietf-quic-transport-29. - QUIC_VERSION_IETF_RFC_V1 = 80, // RFC 9000. + QUIC_VERSION_IETF_DRAFT_29 = 73, // draft-ietf-quic-transport-29. + QUIC_VERSION_IETF_RFC_V1 = 80, // RFC 9000. + QUIC_VERSION_IETF_2_DRAFT_01 = 81, // draft-ietf-quic-v2-01. // Version 99 was a dumping ground for IETF QUIC changes which were not yet // ready for production between 2018-02 and 2020-02. @@ -172,9 +173,13 @@ QuicTransportVersion transport_version) { bool transport_version_is_valid = false; constexpr QuicTransportVersion valid_transport_versions[] = { - QUIC_VERSION_IETF_RFC_V1, QUIC_VERSION_IETF_DRAFT_29, - QUIC_VERSION_50, QUIC_VERSION_46, - QUIC_VERSION_43, QUIC_VERSION_RESERVED_FOR_NEGOTIATION, + QUIC_VERSION_IETF_2_DRAFT_01, + QUIC_VERSION_IETF_RFC_V1, + QUIC_VERSION_IETF_DRAFT_29, + QUIC_VERSION_50, + QUIC_VERSION_46, + QUIC_VERSION_43, + QUIC_VERSION_RESERVED_FOR_NEGOTIATION, QUIC_VERSION_UNSUPPORTED, }; for (size_t i = 0; i < ABSL_ARRAYSIZE(valid_transport_versions); ++i) { @@ -193,7 +198,8 @@ return transport_version != QUIC_VERSION_UNSUPPORTED && transport_version != QUIC_VERSION_RESERVED_FOR_NEGOTIATION && transport_version != QUIC_VERSION_IETF_DRAFT_29 && - transport_version != QUIC_VERSION_IETF_RFC_V1; + transport_version != QUIC_VERSION_IETF_RFC_V1 && + transport_version != QUIC_VERSION_IETF_2_DRAFT_01; case PROTOCOL_TLS1_3: return transport_version != QUIC_VERSION_UNSUPPORTED && transport_version != QUIC_VERSION_50 && @@ -243,6 +249,10 @@ transport_version != other.transport_version; } + static constexpr ParsedQuicVersion V2Draft01() { + return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_2_DRAFT_01); + } + static constexpr ParsedQuicVersion RFCv1() { return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_RFC_V1); } @@ -359,6 +369,14 @@ // Returns whether this version uses PROTOCOL_QUIC_CRYPTO. bool UsesQuicCrypto() const; + + // Returns whether this version uses the QUICv2 Long Header Packet Types. + bool UsesV2PacketTypes() const; + + // Returns true if this shares ALPN codes with RFCv1, and endpoints should + // choose RFCv1 when presented with a v1 ALPN. Note that this is false for + // RFCv1. + bool AlpnDeferToRFCv1() const; }; QUIC_EXPORT_PRIVATE ParsedQuicVersion UnsupportedQuicVersion(); @@ -395,11 +413,11 @@ return {PROTOCOL_TLS1_3, PROTOCOL_QUIC_CRYPTO}; } -constexpr std::array<ParsedQuicVersion, 5> SupportedVersions() { +constexpr std::array<ParsedQuicVersion, 6> SupportedVersions() { return { - ParsedQuicVersion::RFCv1(), ParsedQuicVersion::Draft29(), - ParsedQuicVersion::Q050(), ParsedQuicVersion::Q046(), - ParsedQuicVersion::Q043(), + ParsedQuicVersion::V2Draft01(), ParsedQuicVersion::RFCv1(), + ParsedQuicVersion::Draft29(), ParsedQuicVersion::Q050(), + ParsedQuicVersion::Q046(), ParsedQuicVersion::Q043(), }; }
diff --git a/quic/core/quic_versions_test.cc b/quic/core/quic_versions_test.cc index 4dcad1c..8d420ac 100644 --- a/quic/core/quic_versions_test.cc +++ b/quic/core/quic_versions_test.cc
@@ -103,7 +103,7 @@ } TEST(QuicVersionsTest, ParseQuicVersionLabel) { - static_assert(SupportedVersions().size() == 5u, + static_assert(SupportedVersions().size() == 6u, "Supported versions out of sync"); EXPECT_EQ(ParsedQuicVersion::Q043(), ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '3'))); @@ -115,9 +115,13 @@ ParseQuicVersionLabel(MakeVersionLabel(0xff, 0x00, 0x00, 0x1d))); EXPECT_EQ(ParsedQuicVersion::RFCv1(), ParseQuicVersionLabel(MakeVersionLabel(0x00, 0x00, 0x00, 0x01))); - EXPECT_EQ((ParsedQuicVersionVector{ParsedQuicVersion::RFCv1(), + EXPECT_EQ(ParsedQuicVersion::V2Draft01(), + ParseQuicVersionLabel(MakeVersionLabel(0x70, 0x9a, 0x50, 0xc4))); + EXPECT_EQ((ParsedQuicVersionVector{ParsedQuicVersion::V2Draft01(), + ParsedQuicVersion::RFCv1(), ParsedQuicVersion::Draft29()}), ParseQuicVersionLabelVector(QuicVersionLabelVector{ + MakeVersionLabel(0x70, 0x9a, 0x50, 0xc4), MakeVersionLabel(0x00, 0x00, 0x00, 0x01), MakeVersionLabel(0xaa, 0xaa, 0xaa, 0xaa), MakeVersionLabel(0xff, 0x00, 0x00, 0x1d)})); @@ -128,7 +132,7 @@ } TEST(QuicVersionsTest, ParseQuicVersionString) { - static_assert(SupportedVersions().size() == 5u, + static_assert(SupportedVersions().size() == 6u, "Supported versions out of sync"); EXPECT_EQ(ParsedQuicVersion::Q043(), ParseQuicVersionString("Q043")); EXPECT_EQ(ParsedQuicVersion::Q046(), @@ -152,13 +156,16 @@ EXPECT_EQ(ParsedQuicVersion::RFCv1(), ParseQuicVersionString("00000001")); EXPECT_EQ(ParsedQuicVersion::RFCv1(), ParseQuicVersionString("h3")); + // QUICv2 will never be the result for "h3". + for (const ParsedQuicVersion& version : AllSupportedVersions()) { EXPECT_EQ(version, ParseQuicVersionString(ParsedQuicVersionToString(version))); EXPECT_EQ(version, ParseQuicVersionString(QuicVersionLabelToString( CreateQuicVersionLabel(version)))); - - EXPECT_EQ(version, ParseQuicVersionString(AlpnForVersion(version))); + if (!version.AlpnDeferToRFCv1()) { + EXPECT_EQ(version, ParseQuicVersionString(AlpnForVersion(version))); + } } } @@ -218,13 +225,15 @@ // CreateQuicVersionLabel() uses MakeVersionLabel() internally, // in case it has a bug. TEST(QuicVersionsTest, CreateQuicVersionLabel) { - static_assert(SupportedVersions().size() == 5u, + static_assert(SupportedVersions().size() == 6u, "Supported versions out of sync"); EXPECT_EQ(0x51303433u, CreateQuicVersionLabel(ParsedQuicVersion::Q043())); EXPECT_EQ(0x51303436u, CreateQuicVersionLabel(ParsedQuicVersion::Q046())); EXPECT_EQ(0x51303530u, CreateQuicVersionLabel(ParsedQuicVersion::Q050())); EXPECT_EQ(0xff00001du, CreateQuicVersionLabel(ParsedQuicVersion::Draft29())); EXPECT_EQ(0x00000001u, CreateQuicVersionLabel(ParsedQuicVersion::RFCv1())); + EXPECT_EQ(0x709a50c4u, + CreateQuicVersionLabel(ParsedQuicVersion::V2Draft01())); // Make sure the negotiation reserved version is in the IETF reserved space. EXPECT_EQ( @@ -239,7 +248,7 @@ } TEST(QuicVersionsTest, QuicVersionLabelToString) { - static_assert(SupportedVersions().size() == 5u, + static_assert(SupportedVersions().size() == 6u, "Supported versions out of sync"); EXPECT_EQ("Q043", QuicVersionLabelToString( CreateQuicVersionLabel(ParsedQuicVersion::Q043()))); @@ -251,6 +260,8 @@ ParsedQuicVersion::Draft29()))); EXPECT_EQ("00000001", QuicVersionLabelToString(CreateQuicVersionLabel( ParsedQuicVersion::RFCv1()))); + EXPECT_EQ("709a50c4", QuicVersionLabelToString(CreateQuicVersionLabel( + ParsedQuicVersion::V2Draft01()))); QuicVersionLabelVector version_labels = { MakeVersionLabel('Q', '0', '3', '5'), @@ -275,7 +286,7 @@ } TEST(QuicVersionsTest, ParseQuicVersionLabelString) { - static_assert(SupportedVersions().size() == 5u, + static_assert(SupportedVersions().size() == 6u, "Supported versions out of sync"); // Explicitly test known QUIC version label strings. EXPECT_EQ(ParsedQuicVersion::Q043(), ParseQuicVersionLabelString("Q043")); @@ -285,6 +296,8 @@ ParseQuicVersionLabelString("ff00001d")); EXPECT_EQ(ParsedQuicVersion::RFCv1(), ParseQuicVersionLabelString("00000001")); + EXPECT_EQ(ParsedQuicVersion::V2Draft01(), + ParseQuicVersionLabelString("709a50c4")); // Sanity check that a variety of other serialization formats are ignored. EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionLabelString("1")); @@ -341,6 +354,8 @@ EXPECT_EQ("Q050", ParsedQuicVersionToString(ParsedQuicVersion::Q050())); EXPECT_EQ("draft29", ParsedQuicVersionToString(ParsedQuicVersion::Draft29())); EXPECT_EQ("RFCv1", ParsedQuicVersionToString(ParsedQuicVersion::RFCv1())); + EXPECT_EQ("v2draft01", + ParsedQuicVersionToString(ParsedQuicVersion::V2Draft01())); ParsedQuicVersionVector versions_vector = {ParsedQuicVersion::Q043()}; EXPECT_EQ("Q043", ParsedQuicVersionVectorToString(versions_vector)); @@ -407,23 +422,25 @@ // yet a typo was made in doing the #defines and it was caught // only in some test far removed from here... Better safe than sorry. TEST(QuicVersionsTest, CheckTransportVersionNumbersForTypos) { - static_assert(SupportedVersions().size() == 5u, + static_assert(SupportedVersions().size() == 6u, "Supported versions out of sync"); EXPECT_EQ(QUIC_VERSION_43, 43); EXPECT_EQ(QUIC_VERSION_46, 46); EXPECT_EQ(QUIC_VERSION_50, 50); EXPECT_EQ(QUIC_VERSION_IETF_DRAFT_29, 73); EXPECT_EQ(QUIC_VERSION_IETF_RFC_V1, 80); + EXPECT_EQ(QUIC_VERSION_IETF_2_DRAFT_01, 81); } TEST(QuicVersionsTest, AlpnForVersion) { - static_assert(SupportedVersions().size() == 5u, + static_assert(SupportedVersions().size() == 6u, "Supported versions out of sync"); EXPECT_EQ("h3-Q043", AlpnForVersion(ParsedQuicVersion::Q043())); EXPECT_EQ("h3-Q046", AlpnForVersion(ParsedQuicVersion::Q046())); EXPECT_EQ("h3-Q050", AlpnForVersion(ParsedQuicVersion::Q050())); EXPECT_EQ("h3-29", AlpnForVersion(ParsedQuicVersion::Draft29())); EXPECT_EQ("h3", AlpnForVersion(ParsedQuicVersion::RFCv1())); + EXPECT_EQ("h3", AlpnForVersion(ParsedQuicVersion::V2Draft01())); } TEST(QuicVersionsTest, QuicVersionEnabling) { @@ -473,8 +490,12 @@ EXPECT_NE(CreateQuicVersionLabel(version1), CreateQuicVersionLabel(version2)) << version1 << " " << version2; - EXPECT_NE(AlpnForVersion(version1), AlpnForVersion(version2)) - << version1 << " " << version2; + // The one pair where ALPNs are the same. + if ((version1 != ParsedQuicVersion::V2Draft01()) && + (version2 != ParsedQuicVersion::RFCv1())) { + EXPECT_NE(AlpnForVersion(version1), AlpnForVersion(version2)) + << version1 << " " << version2; + } } } }
diff --git a/quic/core/tls_handshaker.cc b/quic/core/tls_handshaker.cc index 175260b..2eee1cc 100644 --- a/quic/core/tls_handshaker.cc +++ b/quic/core/tls_handshaker.cc
@@ -240,10 +240,13 @@ std::unique_ptr<QuicEncrypter> encrypter = QuicEncrypter::CreateFromCipherSuite(SSL_CIPHER_get_id(cipher)); const EVP_MD* prf = Prf(cipher); - CryptoUtils::SetKeyAndIV(prf, write_secret, encrypter.get()); + CryptoUtils::SetKeyAndIV(prf, write_secret, + handshaker_delegate_->parsed_version(), + encrypter.get()); std::vector<uint8_t> header_protection_key = - CryptoUtils::GenerateHeaderProtectionKey(prf, write_secret, - encrypter->GetKeySize()); + CryptoUtils::GenerateHeaderProtectionKey( + prf, write_secret, handshaker_delegate_->parsed_version(), + encrypter->GetKeySize()); encrypter->SetHeaderProtectionKey( absl::string_view(reinterpret_cast<char*>(header_protection_key.data()), header_protection_key.size())); @@ -263,10 +266,13 @@ std::unique_ptr<QuicDecrypter> decrypter = QuicDecrypter::CreateFromCipherSuite(SSL_CIPHER_get_id(cipher)); const EVP_MD* prf = Prf(cipher); - CryptoUtils::SetKeyAndIV(prf, read_secret, decrypter.get()); + CryptoUtils::SetKeyAndIV(prf, read_secret, + handshaker_delegate_->parsed_version(), + decrypter.get()); std::vector<uint8_t> header_protection_key = - CryptoUtils::GenerateHeaderProtectionKey(prf, read_secret, - decrypter->GetKeySize()); + CryptoUtils::GenerateHeaderProtectionKey( + prf, read_secret, handshaker_delegate_->parsed_version(), + decrypter->GetKeySize()); decrypter->SetHeaderProtectionKey( absl::string_view(reinterpret_cast<char*>(header_protection_key.data()), header_protection_key.size())); @@ -293,14 +299,16 @@ } const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl()); const EVP_MD* prf = Prf(cipher); - latest_read_secret_ = - CryptoUtils::GenerateNextKeyPhaseSecret(prf, latest_read_secret_); - latest_write_secret_ = - CryptoUtils::GenerateNextKeyPhaseSecret(prf, latest_write_secret_); + latest_read_secret_ = CryptoUtils::GenerateNextKeyPhaseSecret( + prf, handshaker_delegate_->parsed_version(), latest_read_secret_); + latest_write_secret_ = CryptoUtils::GenerateNextKeyPhaseSecret( + prf, handshaker_delegate_->parsed_version(), latest_write_secret_); std::unique_ptr<QuicDecrypter> decrypter = QuicDecrypter::CreateFromCipherSuite(SSL_CIPHER_get_id(cipher)); - CryptoUtils::SetKeyAndIV(prf, latest_read_secret_, decrypter.get()); + CryptoUtils::SetKeyAndIV(prf, latest_read_secret_, + handshaker_delegate_->parsed_version(), + decrypter.get()); decrypter->SetHeaderProtectionKey(absl::string_view( reinterpret_cast<char*>(one_rtt_read_header_protection_key_.data()), one_rtt_read_header_protection_key_.size())); @@ -319,7 +327,9 @@ const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl()); std::unique_ptr<QuicEncrypter> encrypter = QuicEncrypter::CreateFromCipherSuite(SSL_CIPHER_get_id(cipher)); - CryptoUtils::SetKeyAndIV(Prf(cipher), latest_write_secret_, encrypter.get()); + CryptoUtils::SetKeyAndIV(Prf(cipher), latest_write_secret_, + handshaker_delegate_->parsed_version(), + encrypter.get()); encrypter->SetHeaderProtectionKey(absl::string_view( reinterpret_cast<char*>(one_rtt_write_header_protection_key_.data()), one_rtt_write_header_protection_key_.size()));