Add out_alert to ProofVerifier::VerifyCertChain
This change will allow a ProofVerifier in the future to provide more detail
to the server when closing a connection due to a certificate verification
failure. Right now, this CL only plumbs through a new (currently unused)
argument to ProofVerifier::VerifyCertChain.
PiperOrigin-RevId: 342087110
Change-Id: I4d04b61d8c89b18556a7a6ef08289081087f694b
diff --git a/quic/core/crypto/proof_verifier.h b/quic/core/crypto/proof_verifier.h
index 7576620..ab09811 100644
--- a/quic/core/crypto/proof_verifier.h
+++ b/quic/core/crypto/proof_verifier.h
@@ -97,6 +97,11 @@
// for some implementations) that provides useful information for the
// verifier, e.g. logging handles.
//
+ // If certificate verification fails, a TLS alert will be sent when closing
+ // the connection. This alert defaults to certificate_unknown. By setting
+ // |*out_alert|, a different alert can be sent to provide a more specific
+ // reason why verification failed.
+ //
// This function may also return QUIC_PENDING, in which case the ProofVerifier
// will call back, on the original thread, via |callback| when complete.
// In this case, the ProofVerifier will take ownership of |callback|.
@@ -109,6 +114,7 @@
const ProofVerifyContext* context,
std::string* error_details,
std::unique_ptr<ProofVerifyDetails>* details,
+ uint8_t* out_alert,
std::unique_ptr<ProofVerifierCallback> callback) = 0;
// Returns a ProofVerifyContext instance which can be use for subsequent
diff --git a/quic/core/quic_crypto_client_handshaker_test.cc b/quic/core/quic_crypto_client_handshaker_test.cc
index cfae506..2d6db7f 100644
--- a/quic/core/quic_crypto_client_handshaker_test.cc
+++ b/quic/core/quic_crypto_client_handshaker_test.cc
@@ -54,6 +54,7 @@
const ProofVerifyContext* /*context*/,
std::string* /*error_details*/,
std::unique_ptr<ProofVerifyDetails>* /*details*/,
+ uint8_t* /*out_alert*/,
std::unique_ptr<ProofVerifierCallback> /*callback*/) override {
return QUIC_SUCCESS;
}
diff --git a/quic/core/tls_client_handshaker.cc b/quic/core/tls_client_handshaker.cc
index fc69ad6..6ea06b8 100644
--- a/quic/core/tls_client_handshaker.cc
+++ b/quic/core/tls_client_handshaker.cc
@@ -376,6 +376,7 @@
const std::vector<std::string>& certs,
std::string* error_details,
std::unique_ptr<ProofVerifyDetails>* details,
+ uint8_t* out_alert,
std::unique_ptr<ProofVerifierCallback> callback) {
const uint8_t* ocsp_response_raw;
size_t ocsp_response_len;
@@ -390,7 +391,8 @@
return proof_verifier_->VerifyCertChain(
server_id_.host(), server_id_.port(), certs, ocsp_response, sct_list,
- verify_context_.get(), error_details, details, std::move(callback));
+ verify_context_.get(), error_details, details, out_alert,
+ std::move(callback));
}
void TlsClientHandshaker::OnProofVerifyDetailsAvailable(
diff --git a/quic/core/tls_client_handshaker.h b/quic/core/tls_client_handshaker.h
index c2707c7..aadfa0b 100644
--- a/quic/core/tls_client_handshaker.h
+++ b/quic/core/tls_client_handshaker.h
@@ -92,6 +92,7 @@
const std::vector<std::string>& certs,
std::string* error_details,
std::unique_ptr<ProofVerifyDetails>* details,
+ uint8_t* out_alert,
std::unique_ptr<ProofVerifierCallback> callback) override;
void OnProofVerifyDetailsAvailable(
const ProofVerifyDetails& verify_details) override;
diff --git a/quic/core/tls_client_handshaker_test.cc b/quic/core/tls_client_handshaker_test.cc
index 7cd7d45..2488426 100644
--- a/quic/core/tls_client_handshaker_test.cc
+++ b/quic/core/tls_client_handshaker_test.cc
@@ -74,15 +74,16 @@
const ProofVerifyContext* context,
std::string* error_details,
std::unique_ptr<ProofVerifyDetails>* details,
+ uint8_t* out_alert,
std::unique_ptr<ProofVerifierCallback> callback) override {
if (!active_) {
- return verifier_->VerifyCertChain(hostname, port, certs, ocsp_response,
- cert_sct, context, error_details,
- details, std::move(callback));
+ return verifier_->VerifyCertChain(
+ hostname, port, certs, ocsp_response, cert_sct, context,
+ error_details, details, out_alert, std::move(callback));
}
pending_ops_.push_back(std::make_unique<VerifyChainPendingOp>(
hostname, port, certs, ocsp_response, cert_sct, context, error_details,
- details, std::move(callback), verifier_.get()));
+ details, out_alert, std::move(callback), verifier_.get()));
return QUIC_PENDING;
}
@@ -123,6 +124,7 @@
const ProofVerifyContext* context,
std::string* error_details,
std::unique_ptr<ProofVerifyDetails>* details,
+ uint8_t* out_alert,
std::unique_ptr<ProofVerifierCallback> callback,
ProofVerifier* delegate)
: hostname_(hostname),
@@ -133,6 +135,7 @@
context_(context),
error_details_(error_details),
details_(details),
+ out_alert_(out_alert),
callback_(std::move(callback)),
delegate_(delegate) {}
@@ -143,7 +146,7 @@
// synchronously.
QuicAsyncStatus status = delegate_->VerifyCertChain(
hostname_, port_, certs_, ocsp_response_, cert_sct_, context_,
- error_details_, details_,
+ error_details_, details_, out_alert_,
std::make_unique<FailingProofVerifierCallback>());
ASSERT_NE(status, QUIC_PENDING);
callback_->Run(status == QUIC_SUCCESS, *error_details_, details_);
@@ -158,6 +161,7 @@
const ProofVerifyContext* context_;
std::string* error_details_;
std::unique_ptr<ProofVerifyDetails>* details_;
+ uint8_t* out_alert_;
std::unique_ptr<ProofVerifierCallback> callback_;
ProofVerifier* delegate_;
};
diff --git a/quic/core/tls_handshaker.cc b/quic/core/tls_handshaker.cc
index 495312d..bfe3545 100644
--- a/quic/core/tls_handshaker.cc
+++ b/quic/core/tls_handshaker.cc
@@ -146,6 +146,7 @@
expected_ssl_error() == SSL_ERROR_WANT_CERTIFICATE_VERIFY) {
enum ssl_verify_result_t result = verify_result_;
verify_result_ = ssl_verify_retry;
+ *out_alert = cert_verify_tls_alert_;
return result;
}
const STACK_OF(CRYPTO_BUFFER)* cert_chain = SSL_get0_peer_certificates(ssl());
@@ -164,8 +165,10 @@
ProofVerifierCallbackImpl* proof_verify_callback =
new ProofVerifierCallbackImpl(this);
+ cert_verify_tls_alert_ = *out_alert;
QuicAsyncStatus verify_result = VerifyCertChain(
certs, &cert_verify_error_details_, &verify_details_,
+ &cert_verify_tls_alert_,
std::unique_ptr<ProofVerifierCallback>(proof_verify_callback));
switch (verify_result) {
case QUIC_SUCCESS:
@@ -179,6 +182,7 @@
return ssl_verify_retry;
case QUIC_FAILURE:
default:
+ *out_alert = cert_verify_tls_alert_;
QUIC_LOG(INFO) << "Cert chain verification failed: "
<< cert_verify_error_details_;
return ssl_verify_invalid;
diff --git a/quic/core/tls_handshaker.h b/quic/core/tls_handshaker.h
index 657c9c7..12b27f1 100644
--- a/quic/core/tls_handshaker.h
+++ b/quic/core/tls_handshaker.h
@@ -90,10 +90,16 @@
// non-owning pointer to |callback|; the callback must live until this
// function returns QUIC_SUCCESS or QUIC_FAILURE, or until the callback is
// run.
+ //
+ // If certificate verification fails, |*out_alert| may be set to a TLS alert
+ // that will be sent when closing the connection; it defaults to
+ // certificate_unknown. Implementations of VerifyCertChain may retain the
+ // |out_alert| pointer while performing an async operation.
virtual QuicAsyncStatus VerifyCertChain(
const std::vector<std::string>& certs,
std::string* error_details,
std::unique_ptr<ProofVerifyDetails>* details,
+ uint8_t* out_alert,
std::unique_ptr<ProofVerifierCallback> callback) = 0;
// Called when certificate verification is completed.
virtual void OnProofVerifyDetailsAvailable(
@@ -173,6 +179,7 @@
ProofVerifierCallbackImpl* proof_verify_callback_ = nullptr;
std::unique_ptr<ProofVerifyDetails> verify_details_;
enum ssl_verify_result_t verify_result_ = ssl_verify_retry;
+ uint8_t cert_verify_tls_alert_ = SSL_AD_CERTIFICATE_UNKNOWN;
std::string cert_verify_error_details_;
int expected_ssl_error_ = SSL_ERROR_WANT_READ;
diff --git a/quic/core/tls_server_handshaker.cc b/quic/core/tls_server_handshaker.cc
index aa49597..e0fe84d 100644
--- a/quic/core/tls_server_handshaker.cc
+++ b/quic/core/tls_server_handshaker.cc
@@ -397,6 +397,7 @@
const std::vector<std::string>& /*certs*/,
std::string* /*error_details*/,
std::unique_ptr<ProofVerifyDetails>* /*details*/,
+ uint8_t* /*out_alert*/,
std::unique_ptr<ProofVerifierCallback> /*callback*/) {
QUIC_BUG << "Client certificates are not yet supported on the server";
return QUIC_FAILURE;
diff --git a/quic/core/tls_server_handshaker.h b/quic/core/tls_server_handshaker.h
index 2fba611..4d12bf3 100644
--- a/quic/core/tls_server_handshaker.h
+++ b/quic/core/tls_server_handshaker.h
@@ -97,6 +97,7 @@
const std::vector<std::string>& certs,
std::string* error_details,
std::unique_ptr<ProofVerifyDetails>* details,
+ uint8_t* out_alert,
std::unique_ptr<ProofVerifierCallback> callback) override;
void OnProofVerifyDetailsAvailable(
const ProofVerifyDetails& verify_details) override;
diff --git a/quic/qbone/qbone_session_test.cc b/quic/qbone/qbone_session_test.cc
index 92f8fa7..5059274 100644
--- a/quic/qbone/qbone_session_test.cc
+++ b/quic/qbone/qbone_session_test.cc
@@ -167,13 +167,14 @@
const ProofVerifyContext* context,
std::string* error_details,
std::unique_ptr<ProofVerifyDetails>* details,
+ uint8_t* out_alert,
std::unique_ptr<ProofVerifierCallback> callback) override {
if (!proof_verifier_) {
return QUIC_FAILURE;
}
return proof_verifier_->VerifyCertChain(
hostname, port, certs, ocsp_response, cert_sct, context, error_details,
- details, std::move(callback));
+ details, out_alert, std::move(callback));
}
std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override {
diff --git a/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc b/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc
index 2ea1e44..5932b9c 100644
--- a/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc
+++ b/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc
@@ -139,6 +139,7 @@
const ProofVerifyContext* /*context*/,
std::string* error_details,
std::unique_ptr<ProofVerifyDetails>* details,
+ uint8_t* /*out_alert*/,
std::unique_ptr<ProofVerifierCallback> /*callback*/) {
if (certs.empty()) {
*details = std::make_unique<Details>(Status::kInternalError);
diff --git a/quic/quic_transport/web_transport_fingerprint_proof_verifier.h b/quic/quic_transport/web_transport_fingerprint_proof_verifier.h
index fba1f83..ad83788 100644
--- a/quic/quic_transport/web_transport_fingerprint_proof_verifier.h
+++ b/quic/quic_transport/web_transport_fingerprint_proof_verifier.h
@@ -100,6 +100,7 @@
const ProofVerifyContext* context,
std::string* error_details,
std::unique_ptr<ProofVerifyDetails>* details,
+ uint8_t* out_alert,
std::unique_ptr<ProofVerifierCallback> callback) override;
std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override;
diff --git a/quic/quic_transport/web_transport_fingerprint_proof_verifier_test.cc b/quic/quic_transport/web_transport_fingerprint_proof_verifier_test.cc
index b527ae6..a84a8a5 100644
--- a/quic/quic_transport/web_transport_fingerprint_proof_verifier_test.cc
+++ b/quic/quic_transport/web_transport_fingerprint_proof_verifier_test.cc
@@ -40,12 +40,13 @@
VerifyResult Verify(absl::string_view certificate) {
VerifyResult result;
std::unique_ptr<ProofVerifyDetails> details;
+ uint8_t tls_alert;
result.status = verifier_->VerifyCertChain(
/*hostname=*/"", /*port=*/0,
std::vector<std::string>{std::string(certificate)},
/*ocsp_response=*/"",
/*cert_sct=*/"",
- /*context=*/nullptr, &result.error, &details,
+ /*context=*/nullptr, &result.error, &details, &tls_alert,
/*callback=*/nullptr);
result.detailed_status =
static_cast<WebTransportFingerprintProofVerifier::Details*>(
diff --git a/quic/test_tools/quic_test_client.cc b/quic/test_tools/quic_test_client.cc
index d7f2033..5b93de5 100644
--- a/quic/test_tools/quic_test_client.cc
+++ b/quic/test_tools/quic_test_client.cc
@@ -82,6 +82,7 @@
const ProofVerifyContext* /*context*/,
std::string* /*error_details*/,
std::unique_ptr<ProofVerifyDetails>* /*details*/,
+ uint8_t* /*out_alert*/,
std::unique_ptr<ProofVerifierCallback> /*callback*/) override {
return ProcessCerts(certs, cert_sct);
}
diff --git a/quic/tools/fake_proof_verifier.h b/quic/tools/fake_proof_verifier.h
index 2d7d7f4..8707879 100644
--- a/quic/tools/fake_proof_verifier.h
+++ b/quic/tools/fake_proof_verifier.h
@@ -38,6 +38,7 @@
const ProofVerifyContext* /*context*/,
std::string* /*error_details*/,
std::unique_ptr<ProofVerifyDetails>* /*details*/,
+ uint8_t* /*out_alert*/,
std::unique_ptr<ProofVerifierCallback> /*callback*/) override {
return QUIC_SUCCESS;
}