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(&notifier_, &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.