Add ability to specify preferred groups for TLS handshake.

PiperOrigin-RevId: 538556697
diff --git a/quiche/quic/core/crypto/quic_crypto_client_config.h b/quiche/quic/core/crypto/quic_crypto_client_config.h
index 546f4d1..693d0d4 100644
--- a/quiche/quic/core/crypto/quic_crypto_client_config.h
+++ b/quiche/quic/core/crypto/quic_crypto_client_config.h
@@ -354,6 +354,18 @@
   // suffix will be used to initialize the cached state for this server.
   void AddCanonicalSuffix(const std::string& suffix);
 
+  // The groups to use for key exchange in the TLS handshake.
+  const std::vector<uint16_t>& preferred_groups() const {
+    return preferred_groups_;
+  }
+
+  // Sets the preferred groups that will be used in the TLS handshake. Values
+  // in the |preferred_groups| vector are NamedGroup enum codepoints from
+  // https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.7.
+  void set_preferred_groups(const std::vector<uint16_t>& preferred_groups) {
+    preferred_groups_ = preferred_groups;
+  }
+
   // Saves the |user_agent_id| that will be passed in QUIC's CHLO message.
   void set_user_agent_id(const std::string& user_agent_id) {
     user_agent_id_ = user_agent_id;
@@ -433,6 +445,9 @@
 
   bssl::UniquePtr<SSL_CTX> ssl_ctx_;
 
+  // The groups to use for key exchange in the TLS handshake.
+  std::vector<uint16_t> preferred_groups_;
+
   // The |user_agent_id_| passed in QUIC's CHLO message.
   std::string user_agent_id_;
 
diff --git a/quiche/quic/core/crypto/quic_crypto_server_config.h b/quiche/quic/core/crypto/quic_crypto_server_config.h
index 77be1f4..5805c88 100644
--- a/quiche/quic/core/crypto/quic_crypto_server_config.h
+++ b/quiche/quic/core/crypto/quic_crypto_server_config.h
@@ -439,6 +439,18 @@
 
   SSL_CTX* ssl_ctx() const;
 
+  // The groups to use for key exchange in the TLS handshake;
+  const std::vector<uint16_t>& preferred_groups() const {
+    return preferred_groups_;
+  }
+
+  // Sets the preferred groups that will be used in the TLS handshake. Values
+  // in the |preferred_groups| vector are NamedGroup enum codepoints from
+  // https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.7.
+  void set_preferred_groups(const std::vector<uint16_t>& preferred_groups) {
+    preferred_groups_ = preferred_groups;
+  }
+
   // Pre-shared key used during the handshake.
   const std::string& pre_shared_key() const { return pre_shared_key_; }
   void set_pre_shared_key(absl::string_view psk) {
@@ -895,6 +907,9 @@
   // ssl_ctx_ contains the server configuration for doing TLS handshakes.
   bssl::UniquePtr<SSL_CTX> ssl_ctx_;
 
+  // The groups to use for key exchange in the TLS handshake;
+  std::vector<uint16_t> preferred_groups_;
+
   // These fields store configuration values. See the comments for their
   // respective setter functions.
   uint32_t source_address_token_future_secs_;
diff --git a/quiche/quic/core/tls_client_handshaker.cc b/quiche/quic/core/tls_client_handshaker.cc
index 74537f7..8ae63cc 100644
--- a/quiche/quic/core/tls_client_handshaker.cc
+++ b/quiche/quic/core/tls_client_handshaker.cc
@@ -52,6 +52,12 @@
                                    cert_and_key->private_key.private_key());
     }
   }
+#if BORINGSSL_API_VERSION >= 22
+  if (!crypto_config->preferred_groups().empty()) {
+    SSL_set1_group_ids(ssl(), crypto_config->preferred_groups().data(),
+                       crypto_config->preferred_groups().size());
+  }
+#endif  // BORINGSSL_API_VERSION
 }
 
 TlsClientHandshaker::~TlsClientHandshaker() {}
diff --git a/quiche/quic/core/tls_client_handshaker_test.cc b/quiche/quic/core/tls_client_handshaker_test.cc
index 0459de3..b11dd0c 100644
--- a/quiche/quic/core/tls_client_handshaker_test.cc
+++ b/quiche/quic/core/tls_client_handshaker_test.cc
@@ -858,6 +858,22 @@
   EXPECT_FALSE(stream()->crypto_negotiated_params().encrypted_client_hello);
 }
 
+#if BORINGSSL_API_VERSION >= 22
+TEST_P(TlsClientHandshakerTest, EnableKyber) {
+  crypto_config_->set_preferred_groups({SSL_GROUP_X25519_KYBER768_DRAFT00});
+  server_crypto_config_->set_preferred_groups(
+      {SSL_GROUP_X25519_KYBER768_DRAFT00, SSL_GROUP_X25519, SSL_GROUP_SECP256R1,
+       SSL_GROUP_SECP384R1});
+  CreateConnection();
+
+  CompleteCryptoHandshake();
+  EXPECT_TRUE(stream()->encryption_established());
+  EXPECT_TRUE(stream()->one_rtt_keys_available());
+  EXPECT_EQ(SSL_GROUP_X25519_KYBER768_DRAFT00,
+            SSL_get_group_id(stream()->GetSsl()));
+}
+#endif  // BORINGSSL_API_VERSION
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quiche/quic/core/tls_server_handshaker.cc b/quiche/quic/core/tls_server_handshaker.cc
index f4bbd3d..8407bc6 100644
--- a/quiche/quic/core/tls_server_handshaker.cc
+++ b/quiche/quic/core/tls_server_handshaker.cc
@@ -205,6 +205,12 @@
   if (session->connection()->context()->tracer) {
     tls_connection_.EnableInfoCallback();
   }
+#if BORINGSSL_API_VERSION >= 22
+  if (!crypto_config->preferred_groups().empty()) {
+    SSL_set1_group_ids(ssl(), crypto_config->preferred_groups().data(),
+                       crypto_config->preferred_groups().size());
+  }
+#endif  // BORINGSSL_API_VERSION
 }
 
 TlsServerHandshaker::~TlsServerHandshaker() { CancelOutstandingCallbacks(); }
diff --git a/quiche/quic/core/tls_server_handshaker_test.cc b/quiche/quic/core/tls_server_handshaker_test.cc
index e68ea65..39a34a5 100644
--- a/quiche/quic/core/tls_server_handshaker_test.cc
+++ b/quiche/quic/core/tls_server_handshaker_test.cc
@@ -1163,6 +1163,24 @@
                   .empty());
 }
 
+#if BORINGSSL_API_VERSION >= 22
+TEST_P(TlsServerHandshakerTest, EnableKyber) {
+  server_crypto_config_->set_preferred_groups(
+      {SSL_GROUP_X25519_KYBER768_DRAFT00});
+  client_crypto_config_->set_preferred_groups(
+      {SSL_GROUP_X25519_KYBER768_DRAFT00, SSL_GROUP_X25519, SSL_GROUP_SECP256R1,
+       SSL_GROUP_SECP384R1});
+
+  InitializeServer();
+  InitializeFakeClient();
+  CompleteCryptoHandshake();
+  ExpectHandshakeSuccessful();
+  EXPECT_EQ(PROTOCOL_TLS1_3, server_stream()->handshake_protocol());
+  EXPECT_EQ(SSL_GROUP_X25519_KYBER768_DRAFT00,
+            SSL_get_group_id(server_stream()->GetSsl()));
+}
+#endif  // BORINGSSL_API_VERSION
+
 }  // namespace
 }  // namespace test
 }  // namespace quic