Don't crash if QuicServerConfigProtobuf is invalid.

Return an error indication (false) if no keys are
passed to CryptoSecretBoxer::SetKeys, rather than corrupting
the state of the boxer, which would later result in a crash.

PiperOrigin-RevId: 416130497
diff --git a/quic/core/crypto/crypto_secret_boxer.cc b/quic/core/crypto/crypto_secret_boxer.cc
index 1826212..a4a7a2a 100644
--- a/quic/core/crypto/crypto_secret_boxer.cc
+++ b/quic/core/crypto/crypto_secret_boxer.cc
@@ -44,8 +44,11 @@
 // kAEAD is the AEAD used for boxing: AES-256-GCM-SIV.
 static const EVP_AEAD* (*const kAEAD)() = EVP_aead_aes_256_gcm_siv;
 
-void CryptoSecretBoxer::SetKeys(const std::vector<std::string>& keys) {
-  QUICHE_DCHECK(!keys.empty());
+bool CryptoSecretBoxer::SetKeys(const std::vector<std::string>& keys) {
+  if (keys.empty()) {
+    QUIC_LOG(DFATAL) << "No keys supplied!";
+    return false;
+  }
   const EVP_AEAD* const aead = kAEAD();
   std::unique_ptr<State> new_state(new State);
 
@@ -57,7 +60,7 @@
     if (!ctx) {
       ERR_clear_error();
       QUIC_LOG(DFATAL) << "EVP_AEAD_CTX_init failed";
-      return;
+      return false;
     }
 
     new_state->ctxs.push_back(std::move(ctx));
@@ -65,6 +68,7 @@
 
   QuicWriterMutexLock l(&lock_);
   state_ = std::move(new_state);
+  return true;
 }
 
 std::string CryptoSecretBoxer::Box(QuicRandom* rand,
diff --git a/quic/core/crypto/crypto_secret_boxer.h b/quic/core/crypto/crypto_secret_boxer.h
index 5dd5cb2..e2cd037 100644
--- a/quic/core/crypto/crypto_secret_boxer.h
+++ b/quic/core/crypto/crypto_secret_boxer.h
@@ -34,13 +34,15 @@
   // SetKeys sets a list of encryption keys. The first key in the list will be
   // used by |Box|, but all supplied keys will be tried by |Unbox|, to handle
   // key skew across the fleet. This must be called before |Box| or |Unbox|.
-  // Keys must be |GetKeySize()| bytes long.
-  void SetKeys(const std::vector<std::string>& keys);
+  // Keys must be |GetKeySize()| bytes long. No change is made if any key is
+  // invalid, or if there are no keys supplied.
+  bool SetKeys(const std::vector<std::string>& keys);
 
   // Box encrypts |plaintext| using a random nonce generated from |rand| and
   // returns the resulting ciphertext. Since an authenticator and nonce are
   // included, the result will be slightly larger than |plaintext|. The first
-  // key in the vector supplied to |SetKeys| will be used.
+  // key in the vector supplied to |SetKeys| will be used. |SetKeys| must be
+  // called before calling this method.
   std::string Box(QuicRandom* rand, absl::string_view plaintext) const;
 
   // Unbox takes the result of a previous call to |Box| in |ciphertext| and
diff --git a/quic/core/crypto/crypto_secret_boxer_test.cc b/quic/core/crypto/crypto_secret_boxer_test.cc
index 225bfc8..7b07d96 100644
--- a/quic/core/crypto/crypto_secret_boxer_test.cc
+++ b/quic/core/crypto/crypto_secret_boxer_test.cc
@@ -56,9 +56,9 @@
   std::string key_12(CryptoSecretBoxer::GetKeySize(), 0x12);
 
   CryptoSecretBoxer boxer_11, boxer_12, boxer;
-  boxer_11.SetKeys({key_11});
-  boxer_12.SetKeys({key_12});
-  boxer.SetKeys({key_12, key_11});
+  EXPECT_TRUE(boxer_11.SetKeys({key_11}));
+  EXPECT_TRUE(boxer_12.SetKeys({key_12}));
+  EXPECT_TRUE(boxer.SetKeys({key_12, key_11}));
 
   // Neither single-key boxer can decode the other's tokens.
   EXPECT_FALSE(CanDecode(boxer_11, boxer_12));
@@ -74,7 +74,7 @@
 
   // After we flush key_11 from |boxer|, it can no longer decode tokens from
   // |boxer_11|.
-  boxer.SetKeys({key_12});
+  EXPECT_TRUE(boxer.SetKeys({key_12}));
   EXPECT_FALSE(CanDecode(boxer, boxer_11));
 }
 
diff --git a/quic/core/crypto/quic_crypto_server_config.cc b/quic/core/crypto/quic_crypto_server_config.cc
index d6eebbb..e8ac18e 100644
--- a/quic/core/crypto/quic_crypto_server_config.cc
+++ b/quic/core/crypto/quic_crypto_server_config.cc
@@ -512,6 +512,7 @@
 
 void QuicCryptoServerConfig::SetSourceAddressTokenKeys(
     const std::vector<std::string>& keys) {
+  // TODO(b/208866709)
   source_address_token_boxer_.SetKeys(keys);
 }
 
@@ -1576,9 +1577,14 @@
   std::unique_ptr<CryptoHandshakeMessage> msg =
       CryptoFramer::ParseMessage(protobuf.config());
 
+  if (!msg) {
+    QUIC_LOG(WARNING) << "Failed to parse server config message";
+    return nullptr;
+  }
+
   if (msg->tag() != kSCFG) {
     QUIC_LOG(WARNING) << "Server config message has tag " << msg->tag()
-                      << " expected " << kSCFG;
+                      << ", but expected " << kSCFG;
     return nullptr;
   }