Don't create NullEncrypter/Decrypter in QuicFramer

gfe-relnote: Changes when/where ENCRYPTION_INITIAL crypters are created in QUIC, protected by reloadable flag quic_framer_doesnt_create_initial_encrypter
PiperOrigin-RevId: 270083544
Change-Id: I27db7b0f8fd094215e7385e54456c2eb807610ab
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index b9f56ee..c3ba88b 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -361,7 +361,8 @@
 }
 
 void QuicConnection::InstallInitialCrypters(QuicConnectionId connection_id) {
-  if (version().handshake_protocol != PROTOCOL_TLS1_3) {
+  if (!framer_.framer_doesnt_create_initial_encrypter() &&
+      version().handshake_protocol != PROTOCOL_TLS1_3) {
     // Initial crypters are currently only supported with TLS.
     return;
   }
@@ -369,7 +370,11 @@
   CryptoUtils::CreateInitialObfuscators(perspective_, version(), connection_id,
                                         &crypters);
   SetEncrypter(ENCRYPTION_INITIAL, std::move(crypters.encrypter));
-  InstallDecrypter(ENCRYPTION_INITIAL, std::move(crypters.decrypter));
+  if (version().KnowsWhichDecrypterToUse()) {
+    InstallDecrypter(ENCRYPTION_INITIAL, std::move(crypters.decrypter));
+  } else {
+    SetDecrypter(ENCRYPTION_INITIAL, std::move(crypters.decrypter));
+  }
 }
 
 QuicConnection::~QuicConnection() {
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 4ca06b3..3d59d14 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -344,6 +344,7 @@
         supports_release_time_(false) {
     QuicFramerPeer::SetLastSerializedServerConnectionId(framer_.framer(),
                                                         TestConnectionId());
+    framer_.framer()->SetInitialObfuscators(TestConnectionId());
   }
   TestPacketWriter(const TestPacketWriter&) = delete;
   TestPacketWriter& operator=(const TestPacketWriter&) = delete;
@@ -964,21 +965,29 @@
     SetQuicReloadableFlag(quic_supports_tls_handshake, true);
     connection_.set_defer_send_in_response_to_packets(GetParam().ack_response ==
                                                       AckResponse::kDefer);
+    framer_.SetInitialObfuscators(TestConnectionId());
+    connection_.InstallInitialCrypters(TestConnectionId());
+    CrypterPair crypters;
+    CryptoUtils::CreateInitialObfuscators(Perspective::IS_SERVER, version(),
+                                          TestConnectionId(), &crypters);
+    peer_creator_.SetEncrypter(ENCRYPTION_INITIAL,
+                               std::move(crypters.encrypter));
+    if (version().KnowsWhichDecrypterToUse()) {
+      peer_framer_.InstallDecrypter(ENCRYPTION_INITIAL,
+                                    std::move(crypters.decrypter));
+    } else {
+      peer_framer_.SetDecrypter(ENCRYPTION_INITIAL,
+                                std::move(crypters.decrypter));
+    }
     for (EncryptionLevel level :
          {ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) {
       peer_creator_.SetEncrypter(
           level, std::make_unique<NullEncrypter>(peer_framer_.perspective()));
     }
-    if (version().handshake_protocol == PROTOCOL_TLS1_3) {
-      connection_.SetEncrypter(
-          ENCRYPTION_INITIAL,
-          std::make_unique<NullEncrypter>(Perspective::IS_CLIENT));
-      connection_.InstallDecrypter(
-          ENCRYPTION_INITIAL,
-          std::make_unique<NullDecrypter>(Perspective::IS_CLIENT));
-    }
     QuicFramerPeer::SetLastSerializedServerConnectionId(
         QuicConnectionPeer::GetFramer(&connection_), connection_id_);
+    QuicFramerPeer::SetLastWrittenPacketNumberLength(
+        QuicConnectionPeer::GetFramer(&connection_), packet_number_length_);
     if (VersionHasIetfInvariantHeader(version().transport_version)) {
       EXPECT_TRUE(QuicConnectionPeer::GetNoStopWaitingFrames(&connection_));
     } else {
@@ -1269,7 +1278,7 @@
     std::unique_ptr<QuicPacket> packet(ConstructClosePacket(number));
     char buffer[kMaxOutgoingPacketSize];
     size_t encrypted_length = peer_framer_.EncryptPayload(
-        ENCRYPTION_INITIAL, QuicPacketNumber(number), *packet, buffer,
+        ENCRYPTION_FORWARD_SECURE, QuicPacketNumber(number), *packet, buffer,
         kMaxOutgoingPacketSize);
     connection_.ProcessUdpPacket(
         kSelfAddress, kPeerAddress,
@@ -1376,6 +1385,7 @@
         level < ENCRYPTION_FORWARD_SECURE) {
       // Set long header type accordingly.
       header.version_flag = true;
+      header.form = IETF_QUIC_LONG_HEADER_PACKET;
       header.long_packet_type = EncryptionlevelToLongHeaderType(level);
       if (QuicVersionHasLongHeaderLengths(
               peer_framer_.version().transport_version)) {
@@ -3737,9 +3747,9 @@
   // is returned.
   const uint64_t received_packet_num = 1;
   const bool has_stop_waiting = false;
-  const EncryptionLevel level = ENCRYPTION_INITIAL;
-  std::unique_ptr<QuicPacket> packet(ConstructDataPacket(
-      received_packet_num, has_stop_waiting, ENCRYPTION_FORWARD_SECURE));
+  const EncryptionLevel level = ENCRYPTION_FORWARD_SECURE;
+  std::unique_ptr<QuicPacket> packet(
+      ConstructDataPacket(received_packet_num, has_stop_waiting, level));
   char buffer[kMaxOutgoingPacketSize];
   size_t encrypted_length =
       peer_framer_.EncryptPayload(level, QuicPacketNumber(received_packet_num),
@@ -4831,6 +4841,18 @@
 TEST_P(QuicConnectionTest, MtuDiscoveryEnabled) {
   EXPECT_TRUE(connection_.connected());
 
+  // QuicFramer::GetMaxPlaintextSize uses the smallest max plaintext size across
+  // all encrypters. The initial encrypter used with IETF QUIC has a 16-byte
+  // overhead, while the NullEncrypter used throughout this test has a 12-byte
+  // overhead. This test tests behavior that relies on computing the packet size
+  // correctly, so by unsetting the initial encrypter, we avoid having a
+  // mismatch between the overheads for the encrypters used. In non-test
+  // scenarios all encrypters used for a given connection have the same
+  // overhead, either 12 bytes for ones using Google QUIC crypto, or 16 bytes
+  // for ones using TLS.
+  QuicConnectionPeer::GetFramer(&connection_)
+      ->SetEncrypter(ENCRYPTION_INITIAL, nullptr);
+
   connection_.EnablePathMtuDiscovery(send_algorithm_);
 
   const QuicPacketCount packets_between_probes_base = 5;
@@ -4961,6 +4983,18 @@
 TEST_P(QuicConnectionTest, MtuDiscoveryWriterLimited) {
   EXPECT_TRUE(connection_.connected());
 
+  // QuicFramer::GetMaxPlaintextSize uses the smallest max plaintext size across
+  // all encrypters. The initial encrypter used with IETF QUIC has a 16-byte
+  // overhead, while the NullEncrypter used throughout this test has a 12-byte
+  // overhead. This test tests behavior that relies on computing the packet size
+  // correctly, so by unsetting the initial encrypter, we avoid having a
+  // mismatch between the overheads for the encrypters used. In non-test
+  // scenarios all encrypters used for a given connection have the same
+  // overhead, either 12 bytes for ones using Google QUIC crypto, or 16 bytes
+  // for ones using TLS.
+  QuicConnectionPeer::GetFramer(&connection_)
+      ->SetEncrypter(ENCRYPTION_INITIAL, nullptr);
+
   const QuicByteCount mtu_limit = kMtuDiscoveryTargetPacketSizeHigh - 1;
   writer_->set_max_packet_size(mtu_limit);
   connection_.EnablePathMtuDiscovery(send_algorithm_);
@@ -7000,9 +7034,9 @@
   std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
   EXPECT_TRUE(nullptr != packet);
   char buffer[kMaxOutgoingPacketSize];
-  size_t encrypted_length =
-      peer_framer_.EncryptPayload(ENCRYPTION_INITIAL, QuicPacketNumber(1),
-                                  *packet, buffer, kMaxOutgoingPacketSize);
+  size_t encrypted_length = peer_framer_.EncryptPayload(
+      ENCRYPTION_FORWARD_SECURE, QuicPacketNumber(1), *packet, buffer,
+      kMaxOutgoingPacketSize);
 
   EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_PEER))
       .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame));
@@ -8631,9 +8665,9 @@
   std::unique_ptr<QuicPacket> packet =
       BuildUnsizedDataPacket(&framer_, header, frames);
   char buffer[kMaxOutgoingPacketSize];
-  size_t encrypted_length = peer_framer_.EncryptPayload(
-      ENCRYPTION_FORWARD_SECURE, QuicPacketNumber(1), *packet, buffer,
-      kMaxOutgoingPacketSize);
+  size_t encrypted_length =
+      peer_framer_.EncryptPayload(ENCRYPTION_INITIAL, QuicPacketNumber(1),
+                                  *packet, buffer, kMaxOutgoingPacketSize);
   QuicReceivedPacket received_packet(buffer, encrypted_length, clock_.Now(),
                                      false);
   EXPECT_EQ(0u, connection_.GetStats().packets_dropped);
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc
index bd59ce6..beb70ca 100644
--- a/quic/core/quic_dispatcher.cc
+++ b/quic/core/quic_dispatcher.cc
@@ -132,6 +132,9 @@
         creator_(server_connection_id, &framer_, &collector_),
         time_wait_list_manager_(time_wait_list_manager) {
     framer_.set_data_producer(&collector_);
+    if (framer_.framer_doesnt_create_initial_encrypter()) {
+      framer_.SetInitialObfuscators(server_connection_id);
+    }
   }
 
   ~StatelessConnectionTerminator() {
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index 010d478..e33dc00 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -424,14 +424,22 @@
           expected_server_connection_id_length),
       expected_client_connection_id_length_(0),
       supports_multiple_packet_number_spaces_(false),
+      framer_doesnt_create_initial_encrypter_(
+          GetQuicReloadableFlag(quic_framer_doesnt_create_initial_encrypter)),
       last_written_packet_number_length_(0),
       peer_ack_delay_exponent_(kDefaultAckDelayExponent),
       local_ack_delay_exponent_(kDefaultAckDelayExponent),
       current_received_frame_type_(0) {
   DCHECK(!supported_versions.empty());
   version_ = supported_versions_[0];
-  decrypter_[ENCRYPTION_INITIAL] = std::make_unique<NullDecrypter>(perspective);
-  encrypter_[ENCRYPTION_INITIAL] = std::make_unique<NullEncrypter>(perspective);
+  if (!framer_doesnt_create_initial_encrypter_) {
+    decrypter_[ENCRYPTION_INITIAL] =
+        std::make_unique<NullDecrypter>(perspective);
+    encrypter_[ENCRYPTION_INITIAL] =
+        std::make_unique<NullEncrypter>(perspective);
+  } else {
+    QUIC_RELOADABLE_FLAG_COUNT(quic_framer_doesnt_create_initial_encrypter);
+  }
 }
 
 QuicFramer::~QuicFramer() {}
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h
index de026a7..ffeeab1 100644
--- a/quic/core/quic_framer.h
+++ b/quic/core/quic_framer.h
@@ -677,6 +677,10 @@
   }
   uint32_t peer_ack_delay_exponent() const { return peer_ack_delay_exponent_; }
 
+  bool framer_doesnt_create_initial_encrypter() const {
+    return framer_doesnt_create_initial_encrypter_;
+  }
+
  private:
   friend class test::QuicFramerPeer;
 
@@ -1093,6 +1097,10 @@
   // Indicates whether this framer supports multiple packet number spaces.
   bool supports_multiple_packet_number_spaces_;
 
+  // Latched value of reloadable flag
+  // quic_framer_doesnt_create_initial_encrypter.
+  const bool framer_doesnt_create_initial_encrypter_;
+
   // The length in bytes of the last packet number written to an IETF-framed
   // packet.
   size_t last_written_packet_number_length_;
diff --git a/quic/core/quic_packet_creator_test.cc b/quic/core/quic_packet_creator_test.cc
index c2f078f..1e66667 100644
--- a/quic/core/quic_packet_creator_test.cc
+++ b/quic/core/quic_packet_creator_test.cc
@@ -155,6 +155,8 @@
         creator_(connection_id_, &client_framer_, &delegate_, &producer_),
         serialized_packet_(creator_.NoPacket()) {
     EXPECT_CALL(delegate_, GetPacketBuffer()).WillRepeatedly(Return(nullptr));
+    creator_.SetEncrypter(ENCRYPTION_INITIAL, std::make_unique<NullEncrypter>(
+                                                  Perspective::IS_CLIENT));
     creator_.SetEncrypter(ENCRYPTION_HANDSHAKE, std::make_unique<NullEncrypter>(
                                                     Perspective::IS_CLIENT));
     creator_.SetEncrypter(ENCRYPTION_ZERO_RTT, std::make_unique<NullEncrypter>(
@@ -167,6 +169,9 @@
     client_framer_.set_data_producer(&producer_);
     if (server_framer_.version().KnowsWhichDecrypterToUse()) {
       server_framer_.InstallDecrypter(
+          ENCRYPTION_INITIAL,
+          std::make_unique<NullDecrypter>(Perspective::IS_SERVER));
+      server_framer_.InstallDecrypter(
           ENCRYPTION_ZERO_RTT,
           std::make_unique<NullDecrypter>(Perspective::IS_SERVER));
       server_framer_.InstallDecrypter(
@@ -175,6 +180,10 @@
       server_framer_.InstallDecrypter(
           ENCRYPTION_FORWARD_SECURE,
           std::make_unique<NullDecrypter>(Perspective::IS_SERVER));
+    } else {
+      server_framer_.SetDecrypter(
+          ENCRYPTION_INITIAL,
+          std::make_unique<NullDecrypter>(Perspective::IS_SERVER));
     }
   }
 
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc
index 7abd24d..1f3b5b7 100644
--- a/quic/core/quic_session_test.cc
+++ b/quic/core/quic_session_test.cc
@@ -498,6 +498,7 @@
                        Perspective::IS_CLIENT,
                        kQuicDefaultConnectionIdLength) {
     client_framer_.set_visitor(&framer_visitor_);
+    client_framer_.SetInitialObfuscators(TestConnectionId());
   }
 
   QuicPathFrameBuffer path_frame_buffer1_;
diff --git a/quic/test_tools/quic_framer_peer.cc b/quic/test_tools/quic_framer_peer.cc
index eea4fd6..d686d5a 100644
--- a/quic/test_tools/quic_framer_peer.cc
+++ b/quic/test_tools/quic_framer_peer.cc
@@ -36,6 +36,13 @@
 }
 
 // static
+void QuicFramerPeer::SetLastWrittenPacketNumberLength(
+    QuicFramer* framer,
+    size_t packet_number_length) {
+  framer->last_written_packet_number_length_ = packet_number_length;
+}
+
+// static
 void QuicFramerPeer::SetLargestPacketNumber(QuicFramer* framer,
                                             QuicPacketNumber packet_number) {
   framer->largest_packet_number_ = packet_number;
diff --git a/quic/test_tools/quic_framer_peer.h b/quic/test_tools/quic_framer_peer.h
index 24b8818..661def5 100644
--- a/quic/test_tools/quic_framer_peer.h
+++ b/quic/test_tools/quic_framer_peer.h
@@ -28,6 +28,8 @@
   static void SetLastSerializedClientConnectionId(
       QuicFramer* framer,
       QuicConnectionId client_connection_id);
+  static void SetLastWrittenPacketNumberLength(QuicFramer* framer,
+                                               size_t packet_number_length);
   static void SetLargestPacketNumber(QuicFramer* framer,
                                      QuicPacketNumber packet_number);
   static void SetPerspective(QuicFramer* framer, Perspective perspective);
diff --git a/quic/test_tools/quic_test_utils.cc b/quic/test_tools/quic_test_utils.cc
index 2e6cc08..387dbe1 100644
--- a/quic/test_tools/quic_test_utils.cc
+++ b/quic/test_tools/quic_test_utils.cc
@@ -133,8 +133,18 @@
     const QuicFrames& frames,
     size_t packet_size) {
   char* buffer = new char[packet_size];
-  size_t length = framer->BuildDataPacket(header, frames, buffer, packet_size,
-                                          ENCRYPTION_INITIAL);
+  EncryptionLevel level = ENCRYPTION_INITIAL;
+  if (header.form == IETF_QUIC_SHORT_HEADER_PACKET) {
+    level = ENCRYPTION_FORWARD_SECURE;
+  } else if (header.form == IETF_QUIC_LONG_HEADER_PACKET) {
+    if (header.long_packet_type == HANDSHAKE) {
+      level = ENCRYPTION_HANDSHAKE;
+    } else if (header.long_packet_type == ZERO_RTT_PROTECTED) {
+      level = ENCRYPTION_ZERO_RTT;
+    }
+  }
+  size_t length =
+      framer->BuildDataPacket(header, frames, buffer, packet_size, level);
   DCHECK_NE(0u, length);
   // Re-construct the data packet with data ownership.
   return std::make_unique<QuicPacket>(