gfe-relnote: Enable initial obfuscators in QUIC_VERSION_99. Protected by quic_enable_version_99 PiperOrigin-RevId: 270834093 Change-Id: Ieee9980f6facc222ee700961a4a36791cf28ab39
diff --git a/quic/core/crypto/aead_base_decrypter.cc b/quic/core/crypto/aead_base_decrypter.cc index 8fec273..b5db0db 100644 --- a/quic/core/crypto/aead_base_decrypter.cc +++ b/quic/core/crypto/aead_base_decrypter.cc
@@ -186,6 +186,10 @@ return key_size_; } +size_t AeadBaseDecrypter::GetNoncePrefixSize() const { + return nonce_size_ - sizeof(QuicPacketNumber); +} + size_t AeadBaseDecrypter::GetIVSize() const { return nonce_size_; }
diff --git a/quic/core/crypto/aead_base_decrypter.h b/quic/core/crypto/aead_base_decrypter.h index 8c7fa15..f0c5b01 100644 --- a/quic/core/crypto/aead_base_decrypter.h +++ b/quic/core/crypto/aead_base_decrypter.h
@@ -41,6 +41,7 @@ size_t* output_length, size_t max_output_length) override; size_t GetKeySize() const override; + size_t GetNoncePrefixSize() const override; size_t GetIVSize() const override; QuicStringPiece GetKey() const override; QuicStringPiece GetNoncePrefix() const override;
diff --git a/quic/core/crypto/crypto_utils.cc b/quic/core/crypto/crypto_utils.cc index 2889098..4851748 100644 --- a/quic/core/crypto/crypto_utils.cc +++ b/quic/core/crypto/crypto_utils.cc
@@ -10,6 +10,8 @@ #include "third_party/boringssl/src/include/openssl/bytestring.h" #include "third_party/boringssl/src/include/openssl/hkdf.h" #include "third_party/boringssl/src/include/openssl/sha.h" +#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_encrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" @@ -31,16 +33,31 @@ namespace quic { +namespace { + +// Implements the HKDF-Expand-Label function as defined in section 7.1 of RFC +// 8446, except that it uses "quic " as the prefix instead of "tls13 ", as +// specified by draft-ietf-quic-tls-14. The HKDF-Expand-Label function takes 4 +// explicit arguments (Secret, Label, Context, and Length), as well as +// implicit PRF which is the hash function negotiated by TLS. Its use in QUIC +// (as needed by the QUIC stack, instead of as used internally by the TLS +// stack) is only for deriving initial secrets for obfuscation and for +// calculating packet protection keys and IVs from the corresponding packet +// protection secret. Neither of these uses need a Context (a zero-length +// context is provided), so this argument is omitted here. +// +// The implicit PRF is explicitly passed into HkdfExpandLabel as |prf|; the +// Secret, Label, and Length are passed in as |secret|, |label|, and +// |out_len|, respectively. The resulting expanded secret is returned. +// // TODO(nharper): HkdfExpandLabel and SetKeyAndIV (below) implement what is // specified in draft-ietf-quic-tls-16. The latest editors' draft has changed // derivation again, and this will need to be updated to reflect those (and any // other future) changes. -// static -std::vector<uint8_t> CryptoUtils::HkdfExpandLabel( - const EVP_MD* prf, - const std::vector<uint8_t>& secret, - const std::string& label, - size_t out_len) { +std::vector<uint8_t> HkdfExpandLabel(const EVP_MD* prf, + const std::vector<uint8_t>& secret, + const std::string& label, + size_t out_len) { bssl::ScopedCBB quic_hkdf_label; CBB inner_label; const char label_prefix[] = "tls13 "; @@ -71,15 +88,17 @@ return out; } +} // namespace + void CryptoUtils::SetKeyAndIV(const EVP_MD* prf, const std::vector<uint8_t>& pp_secret, QuicCrypter* crypter) { - std::vector<uint8_t> key = CryptoUtils::HkdfExpandLabel( - prf, pp_secret, "quic key", crypter->GetKeySize()); - std::vector<uint8_t> iv = CryptoUtils::HkdfExpandLabel( - prf, pp_secret, "quic iv", crypter->GetIVSize()); - std::vector<uint8_t> pn = CryptoUtils::HkdfExpandLabel( - prf, pp_secret, "quic hp", crypter->GetKeySize()); + 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()); + std::vector<uint8_t> pn = + HkdfExpandLabel(prf, pp_secret, "quic hp", crypter->GetKeySize()); crypter->SetKey( QuicStringPiece(reinterpret_cast<char*>(key.data()), key.size())); crypter->SetIV( @@ -91,13 +110,35 @@ namespace { static_assert(kQuicIetfDraftVersion == 23, "Salts do not match draft version"); -// Salt from https://tools.ietf.org/html/draft-ietf-quic-tls-24#section-5.2 +// Salt from https://tools.ietf.org/html/draft-ietf-quic-tls-23#section-5.2 const uint8_t kInitialSalt[] = {0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7, 0xd2, 0x43, 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02}; const char kPreSharedKeyLabel[] = "QUIC PSK"; +// This is the same as SetKeyAndIV, except it is for use with Google QUIC crypto +// style crypters (which have a different nonce construction and auth tag +// length). The labels for HkdfExpandLabel have also been changed to be prefixed +// with "gquic" instead of "quic". +void SetKeyAndNonceForGoogleQuicInitialCrypter( + const EVP_MD* prf, + const std::vector<uint8_t>& pp_secret, + QuicCrypter* crypter) { + std::vector<uint8_t> key = + HkdfExpandLabel(prf, pp_secret, "gquic key", crypter->GetKeySize()); + std::vector<uint8_t> iv = HkdfExpandLabel(prf, pp_secret, "gquic iv", + crypter->GetNoncePrefixSize()); + std::vector<uint8_t> pn = + HkdfExpandLabel(prf, pp_secret, "gquic hp", crypter->GetKeySize()); + crypter->SetKey( + QuicStringPiece(reinterpret_cast<char*>(key.data()), key.size())); + crypter->SetNoncePrefix( + QuicStringPiece(reinterpret_cast<char*>(iv.data()), iv.size())); + crypter->SetHeaderProtectionKey( + QuicStringPiece(reinterpret_cast<char*>(pn.data()), pn.size())); +} + } // namespace // static @@ -142,15 +183,27 @@ encryption_label = server_label; decryption_label = client_label; } - crypters->encrypter = std::make_unique<Aes128GcmEncrypter>(); std::vector<uint8_t> encryption_secret = HkdfExpandLabel( hash, handshake_secret, encryption_label, EVP_MD_size(hash)); - SetKeyAndIV(hash, encryption_secret, crypters->encrypter.get()); - - crypters->decrypter = std::make_unique<Aes128GcmDecrypter>(); std::vector<uint8_t> decryption_secret = HkdfExpandLabel( hash, handshake_secret, decryption_label, EVP_MD_size(hash)); - SetKeyAndIV(hash, decryption_secret, crypters->decrypter.get()); + + // Create an encrypter and decrypter that have an auth tag of the same length + // as the encrypters/decrypters used with the handshake protocol for this + // version. + if (version.handshake_protocol == PROTOCOL_TLS1_3) { + crypters->encrypter = std::make_unique<Aes128GcmEncrypter>(); + SetKeyAndIV(hash, encryption_secret, crypters->encrypter.get()); + crypters->decrypter = std::make_unique<Aes128GcmDecrypter>(); + SetKeyAndIV(hash, decryption_secret, crypters->decrypter.get()); + } else { + crypters->encrypter = std::make_unique<Aes128Gcm12Encrypter>(); + SetKeyAndNonceForGoogleQuicInitialCrypter(hash, encryption_secret, + crypters->encrypter.get()); + crypters->decrypter = std::make_unique<Aes128Gcm12Decrypter>(); + SetKeyAndNonceForGoogleQuicInitialCrypter(hash, decryption_secret, + crypters->decrypter.get()); + } } // static
diff --git a/quic/core/crypto/crypto_utils.h b/quic/core/crypto/crypto_utils.h index 0eae972..6f198d6 100644 --- a/quic/core/crypto/crypto_utils.h +++ b/quic/core/crypto/crypto_utils.h
@@ -202,27 +202,6 @@ // Returns a hash of the serialized |message|. static std::string HashHandshakeMessage(const CryptoHandshakeMessage& message, Perspective perspective); - - private: - // Implements the HKDF-Expand-Label function as defined in section 7.1 of RFC - // 8446, except that it uses "quic " as the prefix instead of "tls13 ", as - // specified by draft-ietf-quic-tls-14. The HKDF-Expand-Label function takes 4 - // explicit arguments (Secret, Label, Context, and Length), as well as - // implicit PRF which is the hash function negotiated by TLS. Its use in QUIC - // (as needed by the QUIC stack, instead of as used internally by the TLS - // stack) is only for deriving initial secrets for obfuscation and for - // calculating packet protection keys and IVs from the corresponding packet - // protection secret. Neither of these uses need a Context (a zero-length - // context is provided), so this argument is omitted here. - // - // The implicit PRF is explicitly passed into HkdfExpandLabel as |prf|; the - // Secret, Label, and Length are passed in as |secret|, |label|, and - // |out_len|, respectively. The resulting expanded secret is returned. - static std::vector<uint8_t> HkdfExpandLabel( - const EVP_MD* prf, - const std::vector<uint8_t>& secret, - const std::string& label, - size_t out_len); }; } // namespace quic
diff --git a/quic/core/crypto/null_decrypter.cc b/quic/core/crypto/null_decrypter.cc index e89fecc..af0a886 100644 --- a/quic/core/crypto/null_decrypter.cc +++ b/quic/core/crypto/null_decrypter.cc
@@ -80,6 +80,10 @@ return 0; } +size_t NullDecrypter::GetNoncePrefixSize() const { + return 0; +} + size_t NullDecrypter::GetIVSize() const { return 0; }
diff --git a/quic/core/crypto/null_decrypter.h b/quic/core/crypto/null_decrypter.h index 06c361d..aac25bb 100644 --- a/quic/core/crypto/null_decrypter.h +++ b/quic/core/crypto/null_decrypter.h
@@ -44,6 +44,7 @@ std::string GenerateHeaderProtectionMask( QuicDataReader* sample_reader) override; size_t GetKeySize() const override; + size_t GetNoncePrefixSize() const override; size_t GetIVSize() const override; QuicStringPiece GetKey() const override; QuicStringPiece GetNoncePrefix() const override;
diff --git a/quic/core/crypto/quic_crypter.h b/quic/core/crypto/quic_crypter.h index c698dfb..5f07836 100644 --- a/quic/core/crypto/quic_crypter.h +++ b/quic/core/crypto/quic_crypter.h
@@ -72,10 +72,15 @@ // Sets the key to use for header protection. virtual bool SetHeaderProtectionKey(QuicStringPiece key) = 0; + // GetKeySize, GetIVSize, and GetNoncePrefixSize are used to know how many + // bytes of key material needs to be derived from the master secret. + // Returns the size in bytes of a key for the algorithm. virtual size_t GetKeySize() const = 0; // Returns the size in bytes of an IV to use with the algorithm. virtual size_t GetIVSize() const = 0; + // Returns the size in bytes of the fixed initial part of the nonce. + virtual size_t GetNoncePrefixSize() const = 0; }; } // namespace quic
diff --git a/quic/core/crypto/quic_encrypter.h b/quic/core/crypto/quic_encrypter.h index 6a69fcc..15acd02 100644 --- a/quic/core/crypto/quic_encrypter.h +++ b/quic/core/crypto/quic_encrypter.h
@@ -47,14 +47,6 @@ // be empty. virtual std::string GenerateHeaderProtectionMask(QuicStringPiece sample) = 0; - // GetKeySize() and GetNoncePrefixSize() tell the HKDF class how many bytes - // of key material needs to be derived from the master secret. - // NOTE: the sizes returned by GetKeySize() and GetNoncePrefixSize() are - // also correct for the QuicDecrypter of the same algorithm. - - // Returns the size in bytes of the fixed initial part of the nonce. - virtual size_t GetNoncePrefixSize() const = 0; - // Returns the maximum length of plaintext that can be encrypted // to ciphertext no larger than |ciphertext_size|. virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) const = 0;
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index c3ba88b..c260e81 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -362,6 +362,7 @@ void QuicConnection::InstallInitialCrypters(QuicConnectionId connection_id) { if (!framer_.framer_doesnt_create_initial_encrypter() && + !version().UsesInitialObfuscators() && version().handshake_protocol != PROTOCOL_TLS1_3) { // Initial crypters are currently only supported with TLS. return;
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index 3d59d14..2f8f6a7 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -225,6 +225,7 @@ } size_t GetKeySize() const override { return 0; } + size_t GetNoncePrefixSize() const override { return 0; } size_t GetIVSize() const override { return 0; } QuicStringPiece GetKey() const override { return QuicStringPiece(); } QuicStringPiece GetNoncePrefix() const override { return QuicStringPiece(); }
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc index 3187c78..4d7a2d7 100644 --- a/quic/core/quic_dispatcher.cc +++ b/quic/core/quic_dispatcher.cc
@@ -135,7 +135,8 @@ creator_(server_connection_id, &framer_, &collector_), time_wait_list_manager_(time_wait_list_manager) { framer_.set_data_producer(&collector_); - if (framer_.framer_doesnt_create_initial_encrypter()) { + if (framer_.framer_doesnt_create_initial_encrypter() || + version.UsesInitialObfuscators()) { framer_.SetInitialObfuscators(server_connection_id); } }
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc index fd8d287..d343c0d 100644 --- a/quic/core/quic_framer_test.cc +++ b/quic/core/quic_framer_test.cc
@@ -164,6 +164,7 @@ return std::string(5, 0); } size_t GetKeySize() const override { return 0; } + size_t GetNoncePrefixSize() const override { return 0; } size_t GetIVSize() const override { return 0; } QuicStringPiece GetKey() const override { return QuicStringPiece(); } QuicStringPiece GetNoncePrefix() const override { return QuicStringPiece(); } @@ -13035,7 +13036,8 @@ header.long_packet_type = INITIAL; header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; - QuicFrames frames = {QuicFrame(QuicPingFrame())}; + QuicFrames frames = {QuicFrame(QuicPingFrame()), + QuicFrame(QuicPaddingFrame(3))}; std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_NE(nullptr, data);
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc index 64cfcca..223780b 100644 --- a/quic/core/quic_versions.cc +++ b/quic/core/quic_versions.cc
@@ -55,7 +55,8 @@ } bool ParsedQuicVersion::UsesInitialObfuscators() const { - return handshake_protocol == PROTOCOL_TLS1_3; + return transport_version == QUIC_VERSION_99 || + handshake_protocol == PROTOCOL_TLS1_3; } bool ParsedQuicVersion::AllowsLowFlowControlLimits() const {
diff --git a/quic/test_tools/quic_test_utils.cc b/quic/test_tools/quic_test_utils.cc index 2637702..dae5857 100644 --- a/quic/test_tools/quic_test_utils.cc +++ b/quic/test_tools/quic_test_utils.cc
@@ -107,6 +107,19 @@ return ack; } +EncryptionLevel HeaderToEncryptionLevel(const QuicPacketHeader& header) { + if (header.form == IETF_QUIC_SHORT_HEADER_PACKET) { + return ENCRYPTION_FORWARD_SECURE; + } else if (header.form == IETF_QUIC_LONG_HEADER_PACKET) { + if (header.long_packet_type == HANDSHAKE) { + return ENCRYPTION_HANDSHAKE; + } else if (header.long_packet_type == ZERO_RTT_PROTECTED) { + return ENCRYPTION_ZERO_RTT; + } + } + return ENCRYPTION_INITIAL; +} + std::unique_ptr<QuicPacket> BuildUnsizedDataPacket( QuicFramer* framer, const QuicPacketHeader& header, @@ -133,16 +146,7 @@ const QuicFrames& frames, size_t packet_size) { char* buffer = new char[packet_size]; - EncryptionLevel level = ENCRYPTION_INITIAL; - if (header.form == IETF_QUIC_SHORT_HEADER_PACKET) { - level = ENCRYPTION_FORWARD_SECURE; - } else if (header.form == IETF_QUIC_LONG_HEADER_PACKET) { - if (header.long_packet_type == HANDSHAKE) { - level = ENCRYPTION_HANDSHAKE; - } else if (header.long_packet_type == ZERO_RTT_PROTECTED) { - level = ENCRYPTION_ZERO_RTT; - } - } + EncryptionLevel level = HeaderToEncryptionLevel(header); size_t length = framer->BuildDataPacket(header, frames, buffer, packet_size, level); DCHECK_NE(0u, length);
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h index 94f25fc..c12587d 100644 --- a/quic/test_tools/quic_test_utils.h +++ b/quic/test_tools/quic_test_utils.h
@@ -205,6 +205,11 @@ QuicAckFrame MakeAckFrameWithAckBlocks(size_t num_ack_blocks, uint64_t least_unacked); +// Returns the encryption level that corresponds to the header type in +// |header|. If the header is for GOOGLE_QUIC_PACKET instead of an +// IETF-invariants packet, this function returns ENCRYPTION_INITIAL. +EncryptionLevel HeaderToEncryptionLevel(const QuicPacketHeader& header); + // Returns a QuicPacket that is owned by the caller, and // is populated with the fields in |header| and |frames|, or is nullptr if the // packet could not be created.