gfe-relnote: In QUIC, close connection if decryption key is available before encryption key when TLS handshaker is used. Protected by disabled v99 flag.

Also route the error up to BoringSSL layer.

PiperOrigin-RevId: 294710276
Change-Id: I2af93903e76a81a0578e9791c1ccc25d35f9b5c5
diff --git a/quic/core/crypto/tls_connection.cc b/quic/core/crypto/tls_connection.cc
index 4c59d3e..ec6a226 100644
--- a/quic/core/crypto/tls_connection.cc
+++ b/quic/core/crypto/tls_connection.cc
@@ -125,8 +125,10 @@
   std::vector<uint8_t> read_secret(key_length), write_secret(key_length);
   memcpy(read_secret.data(), read_key, key_length);
   memcpy(write_secret.data(), write_key, key_length);
-  ConnectionFromSsl(ssl)->delegate_->SetEncryptionSecret(
-      QuicEncryptionLevel(level), read_secret, write_secret);
+  if (!ConnectionFromSsl(ssl)->delegate_->SetEncryptionSecret(
+          QuicEncryptionLevel(level), read_secret, write_secret)) {
+    return 0;
+  }
   return 1;
 }
 
diff --git a/quic/core/crypto/tls_connection.h b/quic/core/crypto/tls_connection.h
index cd9cec0..f037743 100644
--- a/quic/core/crypto/tls_connection.h
+++ b/quic/core/crypto/tls_connection.h
@@ -37,7 +37,7 @@
     // the handshake traffic secrets and application traffic secrets. For a
     // given level |level|, |read_secret| is the secret used for reading data,
     // and |write_secret| is the secret used for writing data.
-    virtual void SetEncryptionSecret(
+    virtual bool SetEncryptionSecret(
         EncryptionLevel level,
         const std::vector<uint8_t>& read_secret,
         const std::vector<uint8_t>& write_secret) = 0;
diff --git a/quic/core/handshaker_delegate_interface.h b/quic/core/handshaker_delegate_interface.h
index 7e4b125..03b3af9 100644
--- a/quic/core/handshaker_delegate_interface.h
+++ b/quic/core/handshaker_delegate_interface.h
@@ -17,8 +17,9 @@
  public:
   virtual ~HandshakerDelegateInterface() {}
 
-  // Called when new decryption key of |level| is available.
-  virtual void OnNewDecryptionKeyAvailable(
+  // Called when new decryption key of |level| is available. Returns true if
+  // decrypter is set successfully, otherwise, returns false.
+  virtual bool OnNewDecryptionKeyAvailable(
       EncryptionLevel level,
       std::unique_ptr<QuicDecrypter> decrypter,
       bool set_alternative_decrypter,
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 6bdb6b0..fe0ea7b 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -1465,29 +1465,13 @@
 
   current_effective_peer_migration_type_ = NO_CHANGE;
 
-  // Some encryption levels share a packet number space, it is therefore
-  // possible for us to want to ack some packets even though we do not yet
-  // have the appropriate keys to encrypt the acks. In this scenario we
-  // do not update the ACK timeout. This can happen for example with
-  // IETF QUIC on the server when we receive 0-RTT packets and do not yet
-  // have 1-RTT keys (0-RTT packets are acked at the 1-RTT level).
-  // Note that this could cause slight performance degradations in the edge
-  // case where one packet is received, then the encrypter is installed,
-  // then a second packet is received; as that could cause the ACK for the
-  // second packet to be delayed instead of immediate. This is currently
-  // considered to be small enough of an edge case to not be optimized for.
-  if (!SupportsMultiplePacketNumberSpaces() ||
-      framer_.HasEncrypterOfEncryptionLevel(QuicUtils::GetEncryptionLevel(
-          QuicUtils::GetPacketNumberSpace(last_decrypted_packet_level_)))) {
-    uber_received_packet_manager_.MaybeUpdateAckTimeout(
-        should_last_packet_instigate_acks_, last_decrypted_packet_level_,
-        last_header_.packet_number, time_of_last_received_packet_,
-        clock_->ApproximateNow(), sent_packet_manager_.GetRttStats());
-  } else {
-    QUIC_DLOG(INFO) << ENDPOINT << "Not updating ACK timeout for "
-                    << EncryptionLevelToString(last_decrypted_packet_level_)
-                    << " as we do not have the corresponding encrypter";
-  }
+  // For IETF QUIC, it is guaranteed that TLS will give connection the
+  // corresponding write key before read key. In other words, connection should
+  // never process a packet while an ACK for it cannot be encrypted.
+  uber_received_packet_manager_.MaybeUpdateAckTimeout(
+      should_last_packet_instigate_acks_, last_decrypted_packet_level_,
+      last_header_.packet_number, time_of_last_received_packet_,
+      clock_->ApproximateNow(), sent_packet_manager_.GetRttStats());
 
   ClearLastFrames();
   CloseIfTooManyOutstandingSentPackets();
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc
index f9d186d..ebd0380 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -1306,24 +1306,30 @@
   flow_controller_.UpdateSendWindowOffset(new_window);
 }
 
-void QuicSession::OnNewDecryptionKeyAvailable(
+bool QuicSession::OnNewDecryptionKeyAvailable(
     EncryptionLevel level,
     std::unique_ptr<QuicDecrypter> decrypter,
     bool set_alternative_decrypter,
     bool latch_once_used) {
-  // TODO(fayang): Close connection if corresponding encryption key is not
-  // available.
-  DCHECK(connection()->framer().HasEncrypterOfEncryptionLevel(level));
+  if (connection_->version().handshake_protocol == PROTOCOL_TLS1_3 &&
+      !connection()->framer().HasEncrypterOfEncryptionLevel(
+          QuicUtils::GetEncryptionLevel(
+              QuicUtils::GetPacketNumberSpace(level)))) {
+    // This should never happen because connection should never decrypt a packet
+    // while an ACK for it cannot be encrypted.
+    return false;
+  }
   if (connection()->version().KnowsWhichDecrypterToUse()) {
     connection()->InstallDecrypter(level, std::move(decrypter));
-    return;
+    return true;
   }
   if (set_alternative_decrypter) {
     connection()->SetAlternativeDecrypter(level, std::move(decrypter),
                                           latch_once_used);
-    return;
+    return true;
   }
   connection()->SetDecrypter(level, std::move(decrypter));
+  return true;
 }
 
 void QuicSession::OnNewEncryptionKeyAvailable(
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h
index 57d7605..138f6c1 100644
--- a/quic/core/quic_session.h
+++ b/quic/core/quic_session.h
@@ -243,7 +243,7 @@
   virtual void OnConfigNegotiated();
 
   // From HandshakerDelegateInterface
-  void OnNewDecryptionKeyAvailable(EncryptionLevel level,
+  bool OnNewDecryptionKeyAvailable(EncryptionLevel level,
                                    std::unique_ptr<QuicDecrypter> decrypter,
                                    bool set_alternative_decrypter,
                                    bool latch_once_used) override;
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc
index 153c787..e374432 100644
--- a/quic/core/quic_session_test.cc
+++ b/quic/core/quic_session_test.cc
@@ -2822,6 +2822,17 @@
   session_.SendRstStream(bidirectional, QUIC_STREAM_CANCELLED, 0);
 }
 
+TEST_P(QuicSessionTestServer, DecryptionKeyAvailableBeforeEncryptionKey) {
+  if (connection_->version().handshake_protocol != PROTOCOL_TLS1_3) {
+    return;
+  }
+  ASSERT_FALSE(connection_->framer().HasEncrypterOfEncryptionLevel(
+      ENCRYPTION_HANDSHAKE));
+  EXPECT_FALSE(session_.OnNewDecryptionKeyAvailable(
+      ENCRYPTION_HANDSHAKE, /*decrypter=*/nullptr,
+      /*set_alternative_decrypter=*/false, /*latch_once_used=*/false));
+}
+
 // A client test class that can be used when the automatic configuration is not
 // desired.
 class QuicSessionTestClientUnconfigured : public QuicSessionTestBase {
diff --git a/quic/core/tls_handshaker.cc b/quic/core/tls_handshaker.cc
index aee7133..4558928 100644
--- a/quic/core/tls_handshaker.cc
+++ b/quic/core/tls_handshaker.cc
@@ -61,7 +61,7 @@
       SSL_CIPHER_get_prf_nid(SSL_get_pending_cipher(ssl())));
 }
 
-void TlsHandshaker::SetEncryptionSecret(
+bool TlsHandshaker::SetEncryptionSecret(
     EncryptionLevel level,
     const std::vector<uint8_t>& read_secret,
     const std::vector<uint8_t>& write_secret) {
@@ -74,9 +74,10 @@
           SSL_CIPHER_get_id(SSL_get_pending_cipher(ssl())));
   CryptoUtils::SetKeyAndIV(Prf(), read_secret, decrypter.get());
   delegate_->OnNewEncryptionKeyAvailable(level, std::move(encrypter));
-  delegate_->OnNewDecryptionKeyAvailable(level, std::move(decrypter),
-                                         /*set_alternative_decrypter=*/false,
-                                         /*latch_once_used=*/false);
+  return delegate_->OnNewDecryptionKeyAvailable(
+      level, std::move(decrypter),
+      /*set_alternative_decrypter=*/false,
+      /*latch_once_used=*/false);
 }
 
 void TlsHandshaker::WriteMessage(EncryptionLevel level,
diff --git a/quic/core/tls_handshaker.h b/quic/core/tls_handshaker.h
index 6fa22d0..d6df69b 100644
--- a/quic/core/tls_handshaker.h
+++ b/quic/core/tls_handshaker.h
@@ -75,7 +75,8 @@
   // secrets and application traffic secrets. For a given secret |secret|,
   // |level| indicates which EncryptionLevel it is to be used at, and |is_write|
   // indicates whether it is used for encryption or decryption.
-  void SetEncryptionSecret(EncryptionLevel level,
+  // Returns true if secret is sucessfully set, otherwise, returns false.
+  bool SetEncryptionSecret(EncryptionLevel level,
                            const std::vector<uint8_t>& read_secret,
                            const std::vector<uint8_t>& write_secret) override;