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