gfe-relnote: Use HandshakerDelegateInterface in QUIC handshakers. Abstract keys installation, keys discarding, default encryption level change and mark handshake complete to HandshakerDelegateInterface. Protected by gfe2_reloadable_flag_quic_use_handshaker_delegate. The final goal is remove session pointer from handshakers. PiperOrigin-RevId: 282826263 Change-Id: I9b379ccfcebd174df1850f7df45069d388460173
diff --git a/quic/core/handshaker_delegate_interface.h b/quic/core/handshaker_delegate_interface.h new file mode 100644 index 0000000..9eae32a --- /dev/null +++ b/quic/core/handshaker_delegate_interface.h
@@ -0,0 +1,53 @@ +// Copyright (c) 2019 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. + +#ifndef QUICHE_QUIC_CORE_HANDSHAKER_DELEGATE_INTERFACE_H_ +#define QUICHE_QUIC_CORE_HANDSHAKER_DELEGATE_INTERFACE_H_ + +#include "net/third_party/quiche/src/quic/core/quic_types.h" + +namespace quic { + +class QuicDecrypter; +class QuicEncrypter; + +// Pure virtual class to get notified when particular handshake events occurred. +class QUIC_EXPORT_PRIVATE HandshakerDelegateInterface { + public: + virtual ~HandshakerDelegateInterface() {} + + // Called when new keys are available. + virtual void OnNewKeysAvailable(EncryptionLevel level, + std::unique_ptr<QuicDecrypter> decrypter, + bool set_alternative_decrypter, + bool latch_once_used, + std::unique_ptr<QuicEncrypter> encrypter) = 0; + + // Called to set default encryption level to |level|. + virtual void SetDefaultEncryptionLevel(EncryptionLevel level) = 0; + + // Called to discard old decryption keys to stop processing packets of + // encryption |level|. + virtual void DiscardOldDecryptionKey(EncryptionLevel level) = 0; + + // Called to discard old encryption keys (and neuter obsolete data). + // TODO(fayang): consider to combine this with DiscardOldDecryptionKey. + virtual void DiscardOldEncryptionKey(EncryptionLevel level) = 0; + + // Called to neuter ENCRYPTION_INITIAL data (without discarding initial keys). + virtual void NeuterUnencryptedData() = 0; + + // Called to neuter data of HANDSHAKE_DATA packet number space. In QUIC + // crypto, this is called 1) when a client switches to forward secure + // encryption level and 2) a server successfully processes a forward secure + // packet. Temporarily use this method in TLS handshake when both endpoints + // switch to forward secure encryption level. + // TODO(fayang): use DiscardOldEncryptionKey instead of this method in TLS + // handshake when handshake key discarding settles down. + virtual void NeuterHandshakeData() = 0; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_HANDSHAKER_DELEGATE_INTERFACE_H_
diff --git a/quic/core/http/quic_spdy_client_session_base.cc b/quic/core/http/quic_spdy_client_session_base.cc index aef68c8..0150be8 100644 --- a/quic/core/http/quic_spdy_client_session_base.cc +++ b/quic/core/http/quic_spdy_client_session_base.cc
@@ -48,6 +48,15 @@ } } +void QuicSpdyClientSessionBase::SetDefaultEncryptionLevel( + quic::EncryptionLevel level) { + QuicSpdySession::SetDefaultEncryptionLevel(level); + if (level == ENCRYPTION_FORWARD_SECURE && max_allowed_push_id() > 0 && + VersionUsesHttp3(transport_version())) { + SendMaxPushId(); + } +} + void QuicSpdyClientSessionBase::OnInitialHeadersComplete( QuicStreamId stream_id, const SpdyHeaderBlock& response_headers) {
diff --git a/quic/core/http/quic_spdy_client_session_base.h b/quic/core/http/quic_spdy_client_session_base.h index aec5e75..b208abd 100644 --- a/quic/core/http/quic_spdy_client_session_base.h +++ b/quic/core/http/quic_spdy_client_session_base.h
@@ -52,6 +52,7 @@ // Override base class to set FEC policy before any data is sent by client. void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override; + void SetDefaultEncryptionLevel(quic::EncryptionLevel level) override; // Called by |headers_stream_| when push promise headers have been // completely received.
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc index dfb8028..6bf2f1d 100644 --- a/quic/core/http/quic_spdy_session.cc +++ b/quic/core/http/quic_spdy_session.cc
@@ -630,6 +630,11 @@ SendInitialData(); } +void QuicSpdySession::SetDefaultEncryptionLevel(quic::EncryptionLevel level) { + QuicSession::SetDefaultEncryptionLevel(level); + SendInitialData(); +} + // True if there are open HTTP requests. bool QuicSpdySession::ShouldKeepConnectionAlive() const { if (!VersionUsesHttp3(transport_version())) {
diff --git a/quic/core/http/quic_spdy_session.h b/quic/core/http/quic_spdy_session.h index 6bbf2ed..50ec602 100644 --- a/quic/core/http/quic_spdy_session.h +++ b/quic/core/http/quic_spdy_session.h
@@ -313,6 +313,7 @@ QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override; + void SetDefaultEncryptionLevel(quic::EncryptionLevel level) override; bool supports_push_promise() { return supports_push_promise_; }
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc index 3178beb..27717ab 100644 --- a/quic/core/http/quic_spdy_session_test.cc +++ b/quic/core/http/quic_spdy_session_test.cc
@@ -99,9 +99,14 @@ } EXPECT_THAT(error, IsQuicNoError()); session()->OnConfigNegotiated(); - session()->connection()->SetDefaultEncryptionLevel( - ENCRYPTION_FORWARD_SECURE); - session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); + if (session()->use_handshake_delegate()) { + session()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + session()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); + } else { + session()->connection()->SetDefaultEncryptionLevel( + ENCRYPTION_FORWARD_SECURE); + session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); + } } // QuicCryptoStream implementation @@ -116,6 +121,7 @@ CryptoMessageParser* crypto_message_parser() override { return QuicCryptoHandshaker::crypto_message_parser(); } + void OnPacketDecrypted(EncryptionLevel /*level*/) override {} MOCK_METHOD0(OnCanWrite, void());
diff --git a/quic/core/http/quic_spdy_stream_test.cc b/quic/core/http/quic_spdy_stream_test.cc index 74ad6ef..73177dc 100644 --- a/quic/core/http/quic_spdy_stream_test.cc +++ b/quic/core/http/quic_spdy_stream_test.cc
@@ -245,8 +245,13 @@ EXPECT_CALL(*session_, WritevData(qpack_encoder_stream, qpack_encoder_stream->id(), 1, 0, _)); } - static_cast<QuicSession*>(session_.get()) - ->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_ESTABLISHED); + if (session_->use_handshake_delegate()) { + static_cast<QuicSession*>(session_.get()) + ->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + } else { + static_cast<QuicSession*>(session_.get()) + ->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_ESTABLISHED); + } } QuicHeaderList ProcessHeaders(bool fin, const SpdyHeaderBlock& headers) {
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index 43e7b85..d4ba114 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -338,7 +338,10 @@ version().CanSendCoalescedPackets()), mtu_discovery_v2_(GetQuicReloadableFlag(quic_mtu_discovery_v2)), quic_version_negotiated_by_default_at_server_( - GetQuicReloadableFlag(quic_version_negotiated_by_default_at_server)) { + GetQuicReloadableFlag(quic_version_negotiated_by_default_at_server)), + use_handshake_delegate_( + GetQuicReloadableFlag(quic_use_handshaker_delegate) || + version().handshake_protocol == PROTOCOL_TLS1_3) { QUIC_DLOG(INFO) << ENDPOINT << "Created connection with server connection ID " << server_connection_id << " and version: " << ParsedQuicVersionToString(version()); @@ -348,6 +351,9 @@ << "QuicConnection: attempted to use server connection ID " << server_connection_id << " which is invalid with version " << QuicVersionToString(transport_version()); + if (use_handshake_delegate_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_use_handshaker_delegate); + } framer_.set_visitor(this); stats_.connection_creation_time = clock_->ApproximateNow(); @@ -812,6 +818,11 @@ address_validated_ = true; } + if (use_handshake_delegate_) { + visitor_->OnPacketDecrypted(level); + return; + } + // Once the server receives a forward secure packet, the handshake is // confirmed. if (level == ENCRYPTION_FORWARD_SECURE &&
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h index 55173cc..a99f401 100644 --- a/quic/core/quic_connection.h +++ b/quic/core/quic_connection.h
@@ -165,6 +165,9 @@ // Called when a STOP_SENDING frame has been received. virtual void OnStopSendingFrame(const QuicStopSendingFrame& frame) = 0; + + // Called when a packet of encryption |level| has been successfully decrypted. + virtual void OnPacketDecrypted(EncryptionLevel level) = 0; }; // Interface which gets callbacks from the QuicConnection at interesting @@ -902,6 +905,8 @@ return quic_version_negotiated_by_default_at_server_; } + bool use_handshake_delegate() const { return use_handshake_delegate_; } + protected: // Calls cancel() on all the alarms owned by this connection. void CancelAllAlarms(); @@ -1535,6 +1540,9 @@ // Latched value of quic_version_negotiated_by_default_at_server. const bool quic_version_negotiated_by_default_at_server_; + + // Latched value of quic_use_handshaker_delegate. + const bool use_handshake_delegate_; }; } // namespace quic
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index 8aa33a5..e1a304b 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -1041,6 +1041,7 @@ EXPECT_CALL(*send_algorithm_, InRecovery()).Times(AnyNumber()); EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(AnyNumber()); EXPECT_CALL(visitor_, WillingAndAbleToWrite()).Times(AnyNumber()); + EXPECT_CALL(visitor_, OnPacketDecrypted(_)).Times(AnyNumber()); EXPECT_CALL(visitor_, HasPendingHandshake()).Times(AnyNumber()); EXPECT_CALL(visitor_, OnCanWrite()) .WillRepeatedly(Invoke(¬ifier_, &SimpleSessionNotifier::OnCanWrite));
diff --git a/quic/core/quic_crypto_client_handshaker.cc b/quic/core/quic_crypto_client_handshaker.cc index a6f531a..eaeabfe 100644 --- a/quic/core/quic_crypto_client_handshaker.cc +++ b/quic/core/quic_crypto_client_handshaker.cc
@@ -56,6 +56,7 @@ : QuicCryptoHandshaker(stream, session), stream_(stream), session_(session), + delegate_(session), next_state_(STATE_IDLE), num_client_hellos_(0), crypto_config_(crypto_config), @@ -317,6 +318,17 @@ crypto_config_->pad_full_hello()); SendHandshakeMessage(out); // Be prepared to decrypt with the new server write key. + if (session()->use_handshake_delegate()) { + delegate_->OnNewKeysAvailable( + ENCRYPTION_ZERO_RTT, + std::move(crypto_negotiated_params_->initial_crypters.decrypter), + /*set_alternative_decrypter=*/true, + /*latch_once_used=*/true, + std::move(crypto_negotiated_params_->initial_crypters.encrypter)); + encryption_established_ = true; + delegate_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + return; + } if (session()->connection()->version().KnowsWhichDecrypterToUse()) { session()->connection()->InstallDecrypter( ENCRYPTION_ZERO_RTT, @@ -376,7 +388,11 @@ // Receipt of a REJ message means that the server received the CHLO // so we can cancel and retransmissions. - session()->NeuterUnencryptedData(); + if (session()->use_handshake_delegate()) { + delegate_->NeuterUnencryptedData(); + } else { + session()->NeuterUnencryptedData(); + } std::string error_details; QuicErrorCode error = crypto_config_->ProcessRejection( @@ -536,6 +552,18 @@ // has been floated that the server shouldn't send packets encrypted // with the FORWARD_SECURE key until it receives a FORWARD_SECURE // packet from the client. + if (session()->use_handshake_delegate()) { + delegate_->OnNewKeysAvailable( + ENCRYPTION_FORWARD_SECURE, std::move(crypters->decrypter), + /*set_alternative_decrypter=*/true, + /*latch_once_used=*/false, std::move(crypters->encrypter)); + handshake_confirmed_ = true; + delegate_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + delegate_->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); + delegate_->NeuterHandshakeData(); + return; + } + if (session()->connection()->version().KnowsWhichDecrypterToUse()) { session()->connection()->InstallDecrypter(ENCRYPTION_FORWARD_SECURE, std::move(crypters->decrypter));
diff --git a/quic/core/quic_crypto_client_handshaker.h b/quic/core/quic_crypto_client_handshaker.h index bce4ab3..467e5c8 100644 --- a/quic/core/quic_crypto_client_handshaker.h +++ b/quic/core/quic_crypto_client_handshaker.h
@@ -132,6 +132,7 @@ QuicCryptoClientStream* stream_; QuicSession* session_; + HandshakerDelegateInterface* delegate_; State next_state_; // num_client_hellos_ contains the number of client hello messages that this
diff --git a/quic/core/quic_crypto_client_stream.h b/quic/core/quic_crypto_client_stream.h index d175ece..3f9b0af 100644 --- a/quic/core/quic_crypto_client_stream.h +++ b/quic/core/quic_crypto_client_stream.h
@@ -161,6 +161,7 @@ const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override; CryptoMessageParser* crypto_message_parser() override; + void OnPacketDecrypted(EncryptionLevel /*level*/) override {} size_t BufferSizeLimitForLevel(EncryptionLevel level) const override; std::string chlo_hash() const;
diff --git a/quic/core/quic_crypto_server_handshaker.cc b/quic/core/quic_crypto_server_handshaker.cc index 964c8ac..755e35e 100644 --- a/quic/core/quic_crypto_server_handshaker.cc +++ b/quic/core/quic_crypto_server_handshaker.cc
@@ -54,6 +54,7 @@ : QuicCryptoHandshaker(stream, session), stream_(stream), session_(session), + delegate_(session), crypto_config_(crypto_config), compressed_certs_cache_(compressed_certs_cache), signed_config_(new QuicSignedServerConfig), @@ -197,27 +198,52 @@ // write key. // // NOTE: the SHLO will be encrypted with the new server write key. - session()->connection()->SetEncrypter( - ENCRYPTION_ZERO_RTT, - std::move(crypto_negotiated_params_->initial_crypters.encrypter)); - session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); - // Set the decrypter immediately so that we no longer accept unencrypted - // packets. - if (session()->connection()->version().KnowsWhichDecrypterToUse()) { - session()->connection()->InstallDecrypter( + if (session()->use_handshake_delegate()) { + delegate_->OnNewKeysAvailable( ENCRYPTION_ZERO_RTT, - std::move(crypto_negotiated_params_->initial_crypters.decrypter)); - session()->connection()->RemoveDecrypter(ENCRYPTION_INITIAL); + std::move(crypto_negotiated_params_->initial_crypters.decrypter), + /*set_alternative_decrypter=*/false, + /*latch_once_used=*/false, + std::move(crypto_negotiated_params_->initial_crypters.encrypter)); + delegate_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + delegate_->DiscardOldDecryptionKey(ENCRYPTION_INITIAL); } else { - session()->connection()->SetDecrypter( + session()->connection()->SetEncrypter( ENCRYPTION_ZERO_RTT, - std::move(crypto_negotiated_params_->initial_crypters.decrypter)); + std::move(crypto_negotiated_params_->initial_crypters.encrypter)); + session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + // Set the decrypter immediately so that we no longer accept unencrypted + // packets. + if (session()->connection()->version().KnowsWhichDecrypterToUse()) { + session()->connection()->InstallDecrypter( + ENCRYPTION_ZERO_RTT, + std::move(crypto_negotiated_params_->initial_crypters.decrypter)); + session()->connection()->RemoveDecrypter(ENCRYPTION_INITIAL); + } else { + session()->connection()->SetDecrypter( + ENCRYPTION_ZERO_RTT, + std::move(crypto_negotiated_params_->initial_crypters.decrypter)); + } } session()->connection()->SetDiversificationNonce(*diversification_nonce); session()->connection()->set_fully_pad_crypto_handshake_packets( crypto_config_->pad_shlo()); SendHandshakeMessage(*reply); + if (session()->use_handshake_delegate()) { + delegate_->OnNewKeysAvailable( + ENCRYPTION_FORWARD_SECURE, + std::move(crypto_negotiated_params_->forward_secure_crypters.decrypter), + /*set_alternative_decrypter=*/true, + /*latch_once_used=*/false, + std::move( + crypto_negotiated_params_->forward_secure_crypters.encrypter)); + encryption_established_ = true; + handshake_confirmed_ = true; + delegate_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + delegate_->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); + return; + } session()->connection()->SetEncrypter( ENCRYPTION_FORWARD_SECURE, @@ -336,6 +362,12 @@ new CachedNetworkParameters(cached_network_params)); } +void QuicCryptoServerHandshaker::OnPacketDecrypted(EncryptionLevel level) { + if (level == ENCRYPTION_FORWARD_SECURE) { + delegate_->NeuterHandshakeData(); + } +} + bool QuicCryptoServerHandshaker::ShouldSendExpectCTHeader() const { return signed_config_->proof.send_expect_ct_header; }
diff --git a/quic/core/quic_crypto_server_handshaker.h b/quic/core/quic_crypto_server_handshaker.h index a67ea5e..4e1a1b8 100644 --- a/quic/core/quic_crypto_server_handshaker.h +++ b/quic/core/quic_crypto_server_handshaker.h
@@ -50,6 +50,7 @@ bool ZeroRttAttempted() const override; void SetPreviousCachedNetworkParams( CachedNetworkParameters cached_network_params) override; + void OnPacketDecrypted(EncryptionLevel level) override; bool ShouldSendExpectCTHeader() const override; // From QuicCryptoStream @@ -162,6 +163,7 @@ QuicCryptoServerStream* stream_; QuicSession* session_; + HandshakerDelegateInterface* delegate_; // crypto_config_ contains crypto parameters for the handshake. const QuicCryptoServerConfig* crypto_config_;
diff --git a/quic/core/quic_crypto_server_stream.cc b/quic/core/quic_crypto_server_stream.cc index 170e53b..bbc3b09 100644 --- a/quic/core/quic_crypto_server_stream.cc +++ b/quic/core/quic_crypto_server_stream.cc
@@ -111,6 +111,10 @@ return handshaker()->crypto_message_parser(); } +void QuicCryptoServerStream::OnPacketDecrypted(EncryptionLevel level) { + handshaker()->OnPacketDecrypted(level); +} + size_t QuicCryptoServerStream::BufferSizeLimitForLevel( EncryptionLevel level) const { return handshaker()->BufferSizeLimitForLevel(level);
diff --git a/quic/core/quic_crypto_server_stream.h b/quic/core/quic_crypto_server_stream.h index e66e55b..d80c495 100644 --- a/quic/core/quic_crypto_server_stream.h +++ b/quic/core/quic_crypto_server_stream.h
@@ -98,6 +98,7 @@ virtual bool ZeroRttAttempted() const = 0; virtual void SetPreviousCachedNetworkParams( CachedNetworkParameters cached_network_params) = 0; + virtual void OnPacketDecrypted(EncryptionLevel level) = 0; // NOTE: Indicating that the Expect-CT header should be sent here presents a // layering violation to some extent. The Expect-CT header only applies to @@ -176,6 +177,7 @@ const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override; CryptoMessageParser* crypto_message_parser() override; + void OnPacketDecrypted(EncryptionLevel level) override; size_t BufferSizeLimitForLevel(EncryptionLevel level) const override; void OnSuccessfulVersionNegotiation( const ParsedQuicVersion& version) override;
diff --git a/quic/core/quic_crypto_stream.h b/quic/core/quic_crypto_stream.h index e38b3f8..357303a 100644 --- a/quic/core/quic_crypto_stream.h +++ b/quic/core/quic_crypto_stream.h
@@ -80,6 +80,9 @@ // Provides the message parser to use when data is received on this stream. virtual CryptoMessageParser* crypto_message_parser() = 0; + // Called when a packet of encryption |level| has been successfully decrypted. + virtual void OnPacketDecrypted(EncryptionLevel level) = 0; + // Returns the maximum number of bytes that can be buffered at a particular // encryption level |level|. virtual size_t BufferSizeLimitForLevel(EncryptionLevel level) const;
diff --git a/quic/core/quic_crypto_stream_test.cc b/quic/core/quic_crypto_stream_test.cc index f5933d2..25d9cc1 100644 --- a/quic/core/quic_crypto_stream_test.cc +++ b/quic/core/quic_crypto_stream_test.cc
@@ -56,6 +56,7 @@ CryptoMessageParser* crypto_message_parser() override { return QuicCryptoHandshaker::crypto_message_parser(); } + void OnPacketDecrypted(EncryptionLevel /*level*/) override {} private: QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc index 9b53845..ada8bf4 100644 --- a/quic/core/quic_session.cc +++ b/quic/core/quic_session.cc
@@ -283,6 +283,10 @@ stream->CloseWriteSide(); } +void QuicSession::OnPacketDecrypted(EncryptionLevel level) { + GetMutableCryptoStream()->OnPacketDecrypted(level); +} + void QuicSession::PendingStreamOnRstStream(const QuicRstStreamFrame& frame) { DCHECK(VersionUsesHttp3(transport_version())); QuicStreamId stream_id = frame.stream_id; @@ -1269,6 +1273,7 @@ } void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { + DCHECK(!use_handshake_delegate()); switch (event) { case ENCRYPTION_ESTABLISHED: // Retransmit originally packets that were sent, since they can't be @@ -1291,6 +1296,93 @@ } } +void QuicSession::OnNewKeysAvailable(EncryptionLevel level, + std::unique_ptr<QuicDecrypter> decrypter, + bool set_alternative_decrypter, + bool latch_once_used, + std::unique_ptr<QuicEncrypter> encrypter) { + DCHECK(use_handshake_delegate()); + // Install new keys. + connection()->SetEncrypter(level, std::move(encrypter)); + if (connection()->version().KnowsWhichDecrypterToUse()) { + connection()->InstallDecrypter(level, std::move(decrypter)); + return; + } + if (set_alternative_decrypter) { + connection()->SetAlternativeDecrypter(level, std::move(decrypter), + latch_once_used); + return; + } + connection()->SetDecrypter(level, std::move(decrypter)); +} + +void QuicSession::SetDefaultEncryptionLevel(EncryptionLevel level) { + DCHECK(use_handshake_delegate()); + QUIC_DVLOG(1) << ENDPOINT << "Set default encryption level to " + << EncryptionLevelToString(level); + connection()->SetDefaultEncryptionLevel(level); + + switch (level) { + case ENCRYPTION_INITIAL: + break; + case ENCRYPTION_ZERO_RTT: + // Retransmit old 0-RTT data (if any) with the new 0-RTT keys, since they + // can't be decrypted by the peer. + connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION); + // Given any streams blocked by encryption a chance to write. + OnCanWrite(); + break; + case ENCRYPTION_HANDSHAKE: + break; + case ENCRYPTION_FORWARD_SECURE: + QUIC_BUG_IF(!config_.negotiated()) + << ENDPOINT << "Handshake confirmed without parameter negotiation."; + break; + default: + QUIC_BUG << "Unknown encryption level: " + << EncryptionLevelToString(level); + } +} + +void QuicSession::DiscardOldDecryptionKey(EncryptionLevel level) { + DCHECK(use_handshake_delegate()); + if (!connection()->version().KnowsWhichDecrypterToUse()) { + // TODO(fayang): actually discard keys. + return; + } + connection()->RemoveDecrypter(level); +} + +void QuicSession::DiscardOldEncryptionKey(EncryptionLevel level) { + DCHECK(use_handshake_delegate()); + QUIC_DVLOG(1) << ENDPOINT << "Discard keys of " + << EncryptionLevelToString(level); + // TODO(fayang): actually discard keys. + switch (level) { + case ENCRYPTION_INITIAL: + NeuterUnencryptedData(); + break; + case ENCRYPTION_HANDSHAKE: + DCHECK(false); + // TODO(fayang): implement this when handshake keys discarding settles + // down. + break; + case ENCRYPTION_ZERO_RTT: + break; + case ENCRYPTION_FORWARD_SECURE: + QUIC_BUG << "Tries to drop 1-RTT keys"; + break; + default: + QUIC_BUG << "Unknown encryption level: " + << EncryptionLevelToString(level); + } +} + +void QuicSession::NeuterHandshakeData() { + DCHECK(use_handshake_delegate()); + connection()->OnHandshakeComplete(); +} + void QuicSession::OnCryptoHandshakeMessageSent( const CryptoHandshakeMessage& /*message*/) {}
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h index 8ceba0f..c6861f9 100644 --- a/quic/core/quic_session.h +++ b/quic/core/quic_session.h
@@ -14,6 +14,7 @@ #include <string> #include <vector> +#include "net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h" #include "net/third_party/quiche/src/quic/core/legacy_quic_stream_id_manager.h" #include "net/third_party/quiche/src/quic/core/quic_connection.h" #include "net/third_party/quiche/src/quic/core/quic_control_frame_manager.h" @@ -46,7 +47,8 @@ : public QuicConnectionVisitorInterface, public SessionNotifierInterface, public QuicStreamFrameDataProducer, - public QuicStreamIdManager::DelegateInterface { + public QuicStreamIdManager::DelegateInterface, + public HandshakerDelegateInterface { public: // An interface from the session to the entity owning the session. // This lets the session notify its owner (the Dispatcher) when the connection @@ -128,6 +130,7 @@ bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override; bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override; void OnStopSendingFrame(const QuicStopSendingFrame& frame) override; + void OnPacketDecrypted(EncryptionLevel level) override; // QuicStreamFrameDataProducer WriteStreamDataResult WriteStreamData(QuicStreamId id, @@ -256,6 +259,18 @@ // Servers will simply call it once with HANDSHAKE_CONFIRMED. virtual void OnCryptoHandshakeEvent(CryptoHandshakeEvent event); + // From HandshakerDelegateInterface + void OnNewKeysAvailable(EncryptionLevel level, + std::unique_ptr<QuicDecrypter> decrypter, + bool set_alternative_decrypter, + bool latch_once_used, + std::unique_ptr<QuicEncrypter> encrypter) override; + void SetDefaultEncryptionLevel(EncryptionLevel level) override; + void DiscardOldDecryptionKey(EncryptionLevel level) override; + void DiscardOldEncryptionKey(EncryptionLevel level) override; + void NeuterUnencryptedData() override; + void NeuterHandshakeData() override; + // Called by the QuicCryptoStream when a handshake message is sent. virtual void OnCryptoHandshakeMessageSent( const CryptoHandshakeMessage& message); @@ -338,9 +353,6 @@ // Called when stream |id| is newly waiting for acks. void OnStreamWaitingForAcks(QuicStreamId id); - // Called to cancel retransmission of unencypted crypto stream data. - void NeuterUnencryptedData(); - // Returns true if the session has data to be sent, either queued in the // connection, or in a write-blocked stream. bool HasDataToWrite() const; @@ -453,6 +465,10 @@ return use_http2_priority_write_scheduler_; } + bool use_handshake_delegate() const { + return connection_->use_handshake_delegate(); + } + bool is_configured() const { return is_configured_; } QuicStreamCount num_expected_unidirectional_static_streams() const {
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc index 6334f66..afb5641 100644 --- a/quic/core/quic_session_test.cc +++ b/quic/core/quic_session_test.cc
@@ -87,9 +87,14 @@ } EXPECT_THAT(error, IsQuicNoError()); session()->OnConfigNegotiated(); - session()->connection()->SetDefaultEncryptionLevel( - ENCRYPTION_FORWARD_SECURE); - session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); + if (session()->use_handshake_delegate()) { + session()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + session()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); + } else { + session()->connection()->SetDefaultEncryptionLevel( + ENCRYPTION_FORWARD_SECURE); + session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); + } } // QuicCryptoStream implementation @@ -104,6 +109,7 @@ CryptoMessageParser* crypto_message_parser() override { return QuicCryptoHandshaker::crypto_message_parser(); } + void OnPacketDecrypted(EncryptionLevel /*level*/) override {} MOCK_METHOD0(OnCanWrite, void()); bool HasPendingCryptoRetransmission() const override { return false; }
diff --git a/quic/core/tls_client_handshaker.cc b/quic/core/tls_client_handshaker.cc index 85a278c..a65fefc 100644 --- a/quic/core/tls_client_handshaker.cc +++ b/quic/core/tls_client_handshaker.cc
@@ -333,9 +333,9 @@ QUIC_DLOG(INFO) << "Client: server selected ALPN: '" << received_alpn_string << "'"; - session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); encryption_established_ = true; handshake_confirmed_ = true; + delegate()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); // Fill crypto_negotiated_params_: const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl()); @@ -345,10 +345,9 @@ crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl()); crypto_negotiated_params_->peer_signature_algorithm = SSL_get_peer_signature_algorithm(ssl()); - - session()->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_ESTABLISHED); - session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); - session()->connection()->OnHandshakeComplete(); + // TODO(fayang): Replace this with DiscardOldKeys(ENCRYPTION_HANDSHAKE) when + // handshake key discarding settles down. + delegate()->NeuterHandshakeData(); } enum ssl_verify_result_t TlsClientHandshaker::VerifyCert(uint8_t* out_alert) { @@ -414,4 +413,15 @@ session_cache_->Insert(server_id_, std::move(cache_state)); } +void TlsClientHandshaker::WriteMessage(EncryptionLevel level, + QuicStringPiece data) { + if (level == ENCRYPTION_HANDSHAKE && + state_ < STATE_ENCRYPTION_HANDSHAKE_DATA_SENT) { + state_ = STATE_ENCRYPTION_HANDSHAKE_DATA_SENT; + delegate()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); + delegate()->DiscardOldDecryptionKey(ENCRYPTION_INITIAL); + } + TlsHandshaker::WriteMessage(level, data); +} + } // namespace quic
diff --git a/quic/core/tls_client_handshaker.h b/quic/core/tls_client_handshaker.h index 0b473a3..319cd17 100644 --- a/quic/core/tls_client_handshaker.h +++ b/quic/core/tls_client_handshaker.h
@@ -50,6 +50,9 @@ CryptoMessageParser* crypto_message_parser() override; size_t BufferSizeLimitForLevel(EncryptionLevel level) const override; + // Override to drop initial keys if trying to write ENCRYPTION_HANDSHAKE data. + void WriteMessage(EncryptionLevel level, QuicStringPiece data) override; + void AllowEmptyAlpnForTests() { allow_empty_alpn_for_tests_ = true; } protected: @@ -90,6 +93,7 @@ STATE_IDLE, STATE_HANDSHAKE_RUNNING, STATE_CERT_VERIFY_PENDING, + STATE_ENCRYPTION_HANDSHAKE_DATA_SENT, STATE_HANDSHAKE_COMPLETE, STATE_CONNECTION_CLOSED, } state_ = STATE_IDLE;
diff --git a/quic/core/tls_handshaker.cc b/quic/core/tls_handshaker.cc index f2089cd..08b4eb9 100644 --- a/quic/core/tls_handshaker.cc +++ b/quic/core/tls_handshaker.cc
@@ -16,7 +16,7 @@ TlsHandshaker::TlsHandshaker(QuicCryptoStream* stream, QuicSession* session, SSL_CTX* /*ssl_ctx*/) - : stream_(stream), session_(session) { + : stream_(stream), session_(session), delegate_(session) { QUIC_BUG_IF(!GetQuicReloadableFlag(quic_supports_tls_handshake)) << "Attempted to create TLS handshaker when TLS is disabled"; } @@ -64,32 +64,22 @@ SSL_CIPHER_get_prf_nid(SSL_get_pending_cipher(ssl()))); } -std::unique_ptr<QuicEncrypter> TlsHandshaker::CreateEncrypter( - const std::vector<uint8_t>& pp_secret) { - std::unique_ptr<QuicEncrypter> encrypter = - QuicEncrypter::CreateFromCipherSuite( - SSL_CIPHER_get_id(SSL_get_pending_cipher(ssl()))); - CryptoUtils::SetKeyAndIV(Prf(), pp_secret, encrypter.get()); - return encrypter; -} - -std::unique_ptr<QuicDecrypter> TlsHandshaker::CreateDecrypter( - const std::vector<uint8_t>& pp_secret) { - std::unique_ptr<QuicDecrypter> decrypter = - QuicDecrypter::CreateFromCipherSuite( - SSL_CIPHER_get_id(SSL_get_pending_cipher(ssl()))); - CryptoUtils::SetKeyAndIV(Prf(), pp_secret, decrypter.get()); - return decrypter; -} - void TlsHandshaker::SetEncryptionSecret( EncryptionLevel level, const std::vector<uint8_t>& read_secret, const std::vector<uint8_t>& write_secret) { - std::unique_ptr<QuicEncrypter> encrypter = CreateEncrypter(write_secret); - session()->connection()->SetEncrypter(level, std::move(encrypter)); - std::unique_ptr<QuicDecrypter> decrypter = CreateDecrypter(read_secret); - session()->connection()->InstallDecrypter(level, std::move(decrypter)); + std::unique_ptr<QuicEncrypter> encrypter = + QuicEncrypter::CreateFromCipherSuite( + SSL_CIPHER_get_id(SSL_get_pending_cipher(ssl()))); + CryptoUtils::SetKeyAndIV(Prf(), write_secret, encrypter.get()); + std::unique_ptr<QuicDecrypter> decrypter = + QuicDecrypter::CreateFromCipherSuite( + SSL_CIPHER_get_id(SSL_get_pending_cipher(ssl()))); + CryptoUtils::SetKeyAndIV(Prf(), read_secret, decrypter.get()); + delegate_->OnNewKeysAvailable(level, std::move(decrypter), + /*set_alternative_decrypter=*/false, + /*latch_once_used=*/false, + std::move(encrypter)); } void TlsHandshaker::WriteMessage(EncryptionLevel level, QuicStringPiece data) {
diff --git a/quic/core/tls_handshaker.h b/quic/core/tls_handshaker.h index 7d5b9bc..14503cd 100644 --- a/quic/core/tls_handshaker.h +++ b/quic/core/tls_handshaker.h
@@ -61,17 +61,13 @@ // Returns the PRF used by the cipher suite negotiated in the TLS handshake. const EVP_MD* Prf(); - std::unique_ptr<QuicEncrypter> CreateEncrypter( - const std::vector<uint8_t>& pp_secret); - std::unique_ptr<QuicDecrypter> CreateDecrypter( - const std::vector<uint8_t>& pp_secret); - virtual const TlsConnection* tls_connection() const = 0; SSL* ssl() const { return tls_connection()->ssl(); } QuicCryptoStream* stream() { return stream_; } QuicSession* session() { return session_; } + HandshakerDelegateInterface* delegate() { return delegate_; } // SetEncryptionSecret provides the encryption secret to use at a particular // encryption level. The secrets provided here are the ones from the TLS 1.3 @@ -100,6 +96,7 @@ private: QuicCryptoStream* stream_; QuicSession* session_; + HandshakerDelegateInterface* delegate_; QuicErrorCode parser_error_ = QUIC_NO_ERROR; std::string parser_error_detail_;
diff --git a/quic/core/tls_handshaker_test.cc b/quic/core/tls_handshaker_test.cc index e9dbd0d..a86b521 100644 --- a/quic/core/tls_handshaker_test.cc +++ b/quic/core/tls_handshaker_test.cc
@@ -177,6 +177,8 @@ pending_writes_.push_back(std::make_pair(std::string(data), level)); } + void OnPacketDecrypted(EncryptionLevel /*level*/) override {} + const std::vector<std::pair<std::string, EncryptionLevel>>& pending_writes() { return pending_writes_; } @@ -269,6 +271,10 @@ handshaker_->CancelOutstandingCallbacks(); } + void OnPacketDecrypted(EncryptionLevel level) override { + handshaker_->OnPacketDecrypted(level); + } + TlsHandshaker* handshaker() const override { return handshaker_.get(); } FakeProofSource* GetFakeProofSource() const { return proof_source_; } @@ -372,12 +378,6 @@ EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(client_session_, - OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_ESTABLISHED)); - EXPECT_CALL(client_session_, - OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED)); - EXPECT_CALL(server_session_, - OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED)); EXPECT_CALL(client_stream_->proof_handler(), OnProofVerifyDetailsAvailable); client_stream_->CryptoConnect(); ExchangeHandshakeMessages(client_stream_, server_stream_); @@ -558,12 +558,6 @@ TEST_F(TlsHandshakerTest, CustomALPNNegotiation) { EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(client_session_, - OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_ESTABLISHED)); - EXPECT_CALL(client_session_, - OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED)); - EXPECT_CALL(server_session_, - OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED)); const std::string kTestAlpn = "A Custom ALPN Value"; const std::vector<std::string> kTestAlpns(
diff --git a/quic/core/tls_server_handshaker.cc b/quic/core/tls_server_handshaker.cc index 76bd289..24af98d 100644 --- a/quic/core/tls_server_handshaker.cc +++ b/quic/core/tls_server_handshaker.cc
@@ -109,6 +109,15 @@ void TlsServerHandshaker::SetPreviousCachedNetworkParams( CachedNetworkParameters /*cached_network_params*/) {} +void TlsServerHandshaker::OnPacketDecrypted(EncryptionLevel level) { + if (level == ENCRYPTION_HANDSHAKE && + state_ < STATE_ENCRYPTION_HANDSHAKE_DATA_PROCESSED) { + state_ = STATE_ENCRYPTION_HANDSHAKE_DATA_PROCESSED; + delegate()->DiscardOldEncryptionKey(ENCRYPTION_INITIAL); + delegate()->DiscardOldDecryptionKey(ENCRYPTION_INITIAL); + } +} + bool TlsServerHandshaker::ShouldSendExpectCTHeader() const { return false; } @@ -252,10 +261,9 @@ QUIC_LOG(INFO) << "Server: handshake finished"; state_ = STATE_HANDSHAKE_COMPLETE; - session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); encryption_established_ = true; handshake_confirmed_ = true; - session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED); + delegate()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); // Fill crypto_negotiated_params_: const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl()); @@ -263,8 +271,9 @@ crypto_negotiated_params_->cipher_suite = SSL_CIPHER_get_value(cipher); } crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl()); - - session()->connection()->OnHandshakeComplete(); + // TODO(fayang): Replace this with DiscardOldKeys(ENCRYPTION_HANDSHAKE) when + // handshake key discarding settles down. + delegate()->NeuterHandshakeData(); } ssl_private_key_result_t TlsServerHandshaker::PrivateKeySign(
diff --git a/quic/core/tls_server_handshaker.h b/quic/core/tls_server_handshaker.h index 3001096..507324b 100644 --- a/quic/core/tls_server_handshaker.h +++ b/quic/core/tls_server_handshaker.h
@@ -46,6 +46,7 @@ bool ZeroRttAttempted() const override; void SetPreviousCachedNetworkParams( CachedNetworkParameters cached_network_params) override; + void OnPacketDecrypted(EncryptionLevel level) override; bool ShouldSendExpectCTHeader() const override; // From QuicCryptoServerStream::HandshakerDelegate and TlsHandshaker @@ -101,6 +102,7 @@ STATE_LISTENING, STATE_SIGNATURE_PENDING, STATE_SIGNATURE_COMPLETE, + STATE_ENCRYPTION_HANDSHAKE_DATA_PROCESSED, STATE_HANDSHAKE_COMPLETE, STATE_CONNECTION_CLOSED, };
diff --git a/quic/quartc/quartc_session.cc b/quic/quartc/quartc_session.cc index 0868d72..654e540 100644 --- a/quic/quartc/quartc_session.cc +++ b/quic/quartc/quartc_session.cc
@@ -175,6 +175,36 @@ } } +void QuartcSession::SetDefaultEncryptionLevel(EncryptionLevel level) { + QuicSession::SetDefaultEncryptionLevel(level); + switch (level) { + case ENCRYPTION_INITIAL: + break; + case ENCRYPTION_ZERO_RTT: + if (connection()->perspective() == Perspective::IS_CLIENT) { + DCHECK(IsEncryptionEstablished()); + DCHECK(session_delegate_); + session_delegate_->OnConnectionWritable(); + } + break; + case ENCRYPTION_HANDSHAKE: + break; + case ENCRYPTION_FORWARD_SECURE: + // On the server, handshake confirmed is the first time when you can start + // writing packets. + DCHECK(IsEncryptionEstablished()); + DCHECK(IsCryptoHandshakeConfirmed()); + + DCHECK(session_delegate_); + session_delegate_->OnConnectionWritable(); + session_delegate_->OnCryptoHandshakeComplete(); + break; + default: + QUIC_BUG << "Unknown encryption level: " + << EncryptionLevelToString(level); + } +} + void QuartcSession::CancelStream(QuicStreamId stream_id) { ResetStream(stream_id, QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED); }
diff --git a/quic/quartc/quartc_session.h b/quic/quartc/quartc_session.h index e9001d6..1c0fd31 100644 --- a/quic/quartc/quartc_session.h +++ b/quic/quartc/quartc_session.h
@@ -74,6 +74,7 @@ } void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override; + void SetDefaultEncryptionLevel(EncryptionLevel level) override; // QuicConnectionVisitorInterface overrides. void OnCongestionWindowChange(QuicTime now) override;
diff --git a/quic/quic_transport/quic_transport_client_session.cc b/quic/quic_transport/quic_transport_client_session.cc index 72ed9c5..f0110b7 100644 --- a/quic/quic_transport/quic_transport_client_session.cc +++ b/quic/quic_transport/quic_transport_client_session.cc
@@ -88,6 +88,14 @@ SendClientIndication(); } +void QuicTransportClientSession::SetDefaultEncryptionLevel( + EncryptionLevel level) { + QuicSession::SetDefaultEncryptionLevel(level); + if (level == ENCRYPTION_FORWARD_SECURE) { + SendClientIndication(); + } +} + QuicTransportStream* QuicTransportClientSession::AcceptIncomingBidirectionalStream() { if (incoming_bidirectional_streams_.empty()) {
diff --git a/quic/quic_transport/quic_transport_client_session.h b/quic/quic_transport/quic_transport_client_session.h index 4df008c..5872bf1 100644 --- a/quic/quic_transport/quic_transport_client_session.h +++ b/quic/quic_transport/quic_transport_client_session.h
@@ -81,6 +81,7 @@ } void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override; + void SetDefaultEncryptionLevel(EncryptionLevel level) override; // Return the earliest incoming stream that has been received by the session // but has not been accepted. Returns nullptr if there are no incoming
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h index 89dc2dc..7919ef3 100644 --- a/quic/test_tools/quic_test_utils.h +++ b/quic/test_tools/quic_test_utils.h
@@ -414,6 +414,7 @@ MOCK_METHOD1(OnStreamsBlockedFrame, bool(const QuicStreamsBlockedFrame& frame)); MOCK_METHOD1(OnStopSendingFrame, void(const QuicStopSendingFrame& frame)); + MOCK_METHOD1(OnPacketDecrypted, void(EncryptionLevel)); }; class MockQuicConnectionHelper : public QuicConnectionHelperInterface { @@ -689,6 +690,7 @@ const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override; CryptoMessageParser* crypto_message_parser() override; + void OnPacketDecrypted(EncryptionLevel /*level*/) override {} private: QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
diff --git a/quic/test_tools/simulator/quic_endpoint.h b/quic/test_tools/simulator/quic_endpoint.h index d1291f8..c2d24ac 100644 --- a/quic/test_tools/simulator/quic_endpoint.h +++ b/quic/test_tools/simulator/quic_endpoint.h
@@ -82,6 +82,7 @@ return true; } void OnStopSendingFrame(const QuicStopSendingFrame& /*frame*/) override {} + void OnPacketDecrypted(EncryptionLevel /*level*/) override {} // End QuicConnectionVisitorInterface implementation.