No public description

PiperOrigin-RevId: 897681079
diff --git a/quiche/quic/core/crypto/proof_source.h b/quiche/quic/core/crypto/proof_source.h
index 698ca36..645e611 100644
--- a/quiche/quic/core/crypto/proof_source.h
+++ b/quiche/quic/core/crypto/proof_source.h
@@ -76,6 +76,7 @@
     bool chains_match_sni = false;
     std::vector<quiche::QuicheReferenceCountedPointer<Chain> absl_nonnull>
         chains;
+    std::optional<ssl_compliance_policy_t> ssl_compliance_policy = std::nullopt;
   };
 
   // Details is an abstract class which acts as a container for any
diff --git a/quiche/quic/core/crypto/proof_source_x509_test.cc b/quiche/quic/core/crypto/proof_source_x509_test.cc
index c9b5cb9..64d26b5 100644
--- a/quiche/quic/core/crypto/proof_source_x509_test.cc
+++ b/quiche/quic/core/crypto/proof_source_x509_test.cc
@@ -131,9 +131,11 @@
                                            QuicSocketAddress(), "unknown.test"),
               FieldsAre(
                   /*chains_match_sni=*/IsFalse(),
-                  /*chains=*/ElementsAre(ReferenceCountedChainIs(
+                  /*chains=*/
+                  ElementsAre(ReferenceCountedChainIs(
                       /*certs*/ ElementsAre(kTestCertificate),
-                      /*trust_anchor_id*/ IsEmpty()))));
+                      /*trust_anchor_id*/ IsEmpty())),
+                  /*ssl_compliance_policy=*/std::nullopt));
 }
 
 // mail.example.org is explicitly a SubjectAltName in `kTestCertificate`.
@@ -150,9 +152,11 @@
                   QuicSocketAddress(), QuicSocketAddress(), "mail.example.org"),
               FieldsAre(
                   /*chains_match_sni=*/IsTrue(),
-                  /*chains=*/ElementsAre(ReferenceCountedChainIs(
+                  /*chains=*/
+                  ElementsAre(ReferenceCountedChainIs(
                       /*certs*/ ElementsAre(kTestCertificate),
-                      /*trust_anchor_id*/ IsEmpty()))));
+                      /*trust_anchor_id*/ IsEmpty())),
+                  /*ssl_compliance_policy=*/std::nullopt));
 }
 
 // www.foo.test is in `kWildcardCertificate`.
@@ -169,9 +173,11 @@
                                            QuicSocketAddress(), "www.foo.test"),
               FieldsAre(
                   /*chains_match_sni=*/IsTrue(),
-                  /*chains=*/ElementsAre(ReferenceCountedChainIs(
+                  /*chains=*/
+                  ElementsAre(ReferenceCountedChainIs(
                       /*certs*/ ElementsAre(kWildcardCertificate),
-                      /*trust_anchor_id*/ IsEmpty()))));
+                      /*trust_anchor_id*/ IsEmpty())),
+                  /*ssl_compliance_policy=*/std::nullopt));
 }
 
 // *.wildcard.test is in `kWildcardCertificate`.
@@ -190,9 +196,11 @@
                                    "www.wildcard.test"),
       FieldsAre(
           /*chains_match_sni=*/IsTrue(),
-          /*chains=*/ElementsAre(ReferenceCountedChainIs(
+          /*chains=*/
+          ElementsAre(ReferenceCountedChainIs(
               /*certs*/ ElementsAre(kWildcardCertificate),
-              /*trust_anchor_id*/ IsEmpty()))));
+              /*trust_anchor_id*/ IsEmpty())),
+          /*ssl_compliance_policy=*/std::nullopt));
 
   EXPECT_THAT(proof_source_
                   ->GetCertChain(QuicSocketAddress(), QuicSocketAddress(),
@@ -206,9 +214,11 @@
                                    "etc.wildcard.test"),
       FieldsAre(
           /*chains_match_sni=*/IsTrue(),
-          /*chains=*/ElementsAre(ReferenceCountedChainIs(
+          /*chains=*/
+          ElementsAre(ReferenceCountedChainIs(
               /*certs*/ ElementsAre(kWildcardCertificate),
-              /*trust_anchor_id*/ IsEmpty()))));
+              /*trust_anchor_id*/ IsEmpty())),
+          /*ssl_compliance_policy=*/std::nullopt));
 }
 
 // wildcard.test itself is not in `kWildcardCertificate`.
@@ -225,9 +235,11 @@
                   QuicSocketAddress(), QuicSocketAddress(), "wildcard.test"),
               FieldsAre(
                   /*chains_match_sni=*/IsFalse(),
-                  /*chains=*/ElementsAre(ReferenceCountedChainIs(
+                  /*chains=*/
+                  ElementsAre(ReferenceCountedChainIs(
                       /*certs*/ ElementsAre(kTestCertificate),
-                      /*trust_anchor_id*/ IsEmpty()))));
+                      /*trust_anchor_id*/ IsEmpty())),
+                  /*ssl_compliance_policy=*/std::nullopt));
 }
 
 }  // namespace
diff --git a/quiche/quic/core/quic_types.h b/quiche/quic/core/quic_types.h
index dcf16b5..5be2c05 100644
--- a/quiche/quic/core/quic_types.h
+++ b/quiche/quic/core/quic_types.h
@@ -18,6 +18,7 @@
 #include "absl/container/inlined_vector.h"
 #include "absl/strings/str_format.h"
 #include "absl/strings/string_view.h"
+#include "openssl/ssl.h"
 #include "quiche/quic/core/quic_connection_id.h"
 #include "quiche/quic/core/quic_error_codes.h"
 #include "quiche/quic/core/quic_packet_number.h"
@@ -901,9 +902,13 @@
 struct QUICHE_EXPORT QuicDelayedSSLConfig {
   // Client certificate mode for mTLS support. Only used at server side.
   // std::nullopt means do not change client certificate mode.
-  std::optional<ClientCertMode> client_cert_mode;
+  std::optional<ClientCertMode> client_cert_mode = std::nullopt;
   // QUIC transport parameters as serialized by ProofSourceHandle.
-  std::optional<std::vector<uint8_t>> quic_transport_parameters;
+  std::optional<std::vector<uint8_t>> quic_transport_parameters = std::nullopt;
+  // If not nullopt, the SSL compliance policy to use. See documentation for
+  // ssl_compliance_policy_t values in BoringSSL:
+  // https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#Compliance-policy-configurations
+  std::optional<ssl_compliance_policy_t> ssl_compliance_policy = std::nullopt;
 
   bool operator==(const QuicDelayedSSLConfig& other) const = default;
 };
diff --git a/quiche/quic/core/tls_server_handshaker.cc b/quiche/quic/core/tls_server_handshaker.cc
index b22d855..13cfb9c 100644
--- a/quiche/quic/core/tls_server_handshaker.cc
+++ b/quiche/quic/core/tls_server_handshaker.cc
@@ -120,8 +120,10 @@
 
   handshaker_->OnSelectCertificateDone(
       /*ok=*/true, /*is_sync=*/true,
-      ProofSourceHandleCallback::LocalSSLConfig(cert_chains_result.chains,
-                                                QuicDelayedSSLConfig()),
+      ProofSourceHandleCallback::LocalSSLConfig(
+          cert_chains_result.chains,
+          QuicDelayedSSLConfig{.ssl_compliance_policy =
+                                   cert_chains_result.ssl_compliance_policy}),
       /*ticket_encryption_key=*/absl::string_view(),
       /*cert_matched_sni=*/cert_chains_result.chains_match_sni);
   if (!handshaker_->select_cert_status().has_value()) {
@@ -1129,6 +1131,10 @@
                   << client_cert_mode();
   }
 
+  if (delayed_ssl_config.ssl_compliance_policy.has_value()) {
+    SSL_set_compliance_policy(ssl(), *delayed_ssl_config.ssl_compliance_policy);
+  }
+
   if (ok) {
     if (auto* local_config = std::get_if<LocalSSLConfig>(&ssl_config);
         local_config != nullptr) {
diff --git a/quiche/quic/core/tls_server_handshaker_test.cc b/quiche/quic/core/tls_server_handshaker_test.cc
index fa33070..993c54a 100644
--- a/quiche/quic/core/tls_server_handshaker_test.cc
+++ b/quiche/quic/core/tls_server_handshaker_test.cc
@@ -8,6 +8,7 @@
 #include <cstddef>
 #include <cstdint>
 #include <memory>
+#include <optional>
 #include <string>
 #include <utility>
 #include <vector>
@@ -372,6 +373,8 @@
     return client_session_->GetMutableCryptoStream();
   }
 
+  SSL* server_ssl() { return server_stream()->GetSsl(); }
+
   // Initializes a fake client, and all its associated state, for
   // testing.  May be called multiple times.
   void InitializeFakeClient() {
@@ -1645,6 +1648,73 @@
   }
 }
 
+TEST_P(TlsServerHandshakerTest, NoCompliancePolicy) {
+  quiche::QuicheReferenceCountedPointer<ProofSource::Chain> chain(
+      new ProofSource::Chain({std::string(quic::test::kTestCertificate)}));
+
+  // Arrange GetCertChains to return no compliance policy.
+  EXPECT_CALL(*proof_source_, GetCertChains(_, _, kServerHostname))
+      .WillOnce(Return(ProofSource::CertChainsResult{
+          .chains_match_sni = true,
+          .chains = {chain},
+          .ssl_compliance_policy = std::nullopt,
+      }));
+
+  CompleteCryptoHandshake();
+  ExpectHandshakeSuccessful();
+
+  EXPECT_NE(SSL_CIPHER_get_id(SSL_get_current_cipher(server_ssl())),
+            TLS1_3_CK_AES_256_GCM_SHA384);
+}
+
+TEST_P(TlsServerHandshakerTest, CompliancePolicyWithSynchronousSelectCert) {
+  quiche::QuicheReferenceCountedPointer<ProofSource::Chain> chain(
+      new ProofSource::Chain({std::string(quic::test::kTestCertificate)}));
+
+  // Arrange GetCertChains to return the compliance policy.
+  EXPECT_CALL(*proof_source_, GetCertChains(_, _, kServerHostname))
+      .WillOnce(Return(ProofSource::CertChainsResult{
+          .chains_match_sni = true,
+          .chains = {chain},
+          .ssl_compliance_policy = ssl_compliance_policy_cnsa_202407,
+      }));
+
+  CompleteCryptoHandshake();
+  ExpectHandshakeSuccessful();
+
+  // See why AES_256 is preferred when using cnsa_202407 at:
+  // https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#Compliance-policy-configurations
+  EXPECT_EQ(SSL_CIPHER_get_id(SSL_get_current_cipher(server_ssl())),
+            TLS1_3_CK_AES_256_GCM_SHA384);
+}
+
+TEST_P(TlsServerHandshakerTest, CompliancePolicyWithAsynchronousSelectCert) {
+  InitializeServerWithFakeProofSourceHandle();
+
+  // Configure the handshaker to perform async cert selection with the policy.
+  server_handshaker_->SetupProofSourceHandle(
+      /*select_cert_action=*/FakeProofSourceHandle::Action::DELEGATE_ASYNC,
+      /*compute_signature_action=*/FakeProofSourceHandle::Action::DELEGATE_SYNC,
+      QuicDelayedSSLConfig{.ssl_compliance_policy =
+                               ssl_compliance_policy_cnsa_202407});
+
+  // Start handshake.
+  AdvanceHandshakeWithFakeClient();
+
+  // Complete the async select_certificate operation.
+  ASSERT_TRUE(
+      server_handshaker_->fake_proof_source_handle()->HasPendingOperation());
+  server_handshaker_->fake_proof_source_handle()->CompletePendingOperation();
+
+  CompleteCryptoHandshake();
+  ExpectHandshakeSuccessful();
+
+  // See why AES_256 is preferred when using cnsa_202407 at:
+  // https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#Compliance-policy-configurations
+  EXPECT_EQ(SSL_CIPHER_get_id(SSL_get_current_cipher(server_ssl())),
+            TLS1_3_CK_AES_256_GCM_SHA384);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic