Fix gQUIC remote handshake by postpone certificate validation to after GetProof is done.
Also modify standalone_handshaker_end_to_end_test to verify the HTTP response content, instead of response_complete(), which is implemented incorrectly in quic client.
Protected by FLAGS_quic_reloadable_flag_quic_crypto_postpone_cert_validate_for_server.
PiperOrigin-RevId: 360229986
Change-Id: I1d7afa111daec727901c1e6a8c1c95ca4c76e731
diff --git a/quic/core/crypto/quic_crypto_server_config.cc b/quic/core/crypto/quic_crypto_server_config.cc
index da04f4f..1406829 100644
--- a/quic/core/crypto/quic_crypto_server_config.cc
+++ b/quic/core/crypto/quic_crypto_server_config.cc
@@ -743,6 +743,22 @@
<< context->connection_id() << " which is invalid with version "
<< context->version();
+ if (context->validate_chlo_result()->postpone_cert_validate_for_server &&
+ context->info().reject_reasons.empty()) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_crypto_postpone_cert_validate_for_server);
+ if (!context->signed_config() || !context->signed_config()->chain) {
+ // No chain.
+ context->validate_chlo_result()->info.reject_reasons.push_back(
+ SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
+ } else if (!ValidateExpectedLeafCertificate(
+ context->client_hello(),
+ context->signed_config()->chain->certs)) {
+ // Has chain but leaf is invalid.
+ context->validate_chlo_result()->info.reject_reasons.push_back(
+ INVALID_EXPECTED_LEAF_CERTIFICATE);
+ }
+ }
+
if (found_error) {
context->Fail(QUIC_HANDSHAKE_FAILED, "Failed to get proof");
return;
@@ -1276,13 +1292,15 @@
// No valid source address token.
}
- QuicReferenceCountedPointer<ProofSource::Chain> chain =
- proof_source_->GetCertChain(server_address, client_address,
- std::string(info->sni));
- if (!chain) {
- info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
- } else if (!ValidateExpectedLeafCertificate(client_hello, chain->certs)) {
- info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE);
+ if (!client_hello_state->postpone_cert_validate_for_server) {
+ QuicReferenceCountedPointer<ProofSource::Chain> chain =
+ proof_source_->GetCertChain(server_address, client_address,
+ std::string(info->sni));
+ if (!chain) {
+ info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
+ } else if (!ValidateExpectedLeafCertificate(client_hello, chain->certs)) {
+ info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE);
+ }
}
if (info->client_nonce.size() != kNonceSize) {
diff --git a/quic/core/crypto/quic_crypto_server_config.h b/quic/core/crypto/quic_crypto_server_config.h
index 4f3ad08..464f2bb 100644
--- a/quic/core/crypto/quic_crypto_server_config.h
+++ b/quic/core/crypto/quic_crypto_server_config.h
@@ -98,6 +98,9 @@
// Populated if the CHLO STK contained a CachedNetworkParameters proto.
CachedNetworkParameters cached_network_params;
+ const bool postpone_cert_validate_for_server =
+ GetQuicReloadableFlag(quic_crypto_postpone_cert_validate_for_server);
+
protected:
~Result() override;
};
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h
index 92780bd..f37ccbc 100644
--- a/quic/core/quic_flags_list.h
+++ b/quic/core/quic_flags_list.h
@@ -20,6 +20,7 @@
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_conservative_bursts, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_conservative_cwnd_and_pacing_gains, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_count_bytes_on_alternative_path_seperately, false)
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_crypto_postpone_cert_validate_for_server, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_enable_5rto_blackhole_detection2, true)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_on_pto, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_to_bbr, false)
diff --git a/quic/test_tools/quic_test_client.cc b/quic/test_tools/quic_test_client.cc
index 4133950..d1c1272 100644
--- a/quic/test_tools/quic_test_client.cc
+++ b/quic/test_tools/quic_test_client.cc
@@ -796,7 +796,8 @@
closed_stream_states_.insert(std::make_pair(
id,
PerStreamState(
- client_stream->stream_error(), true,
+ // Set response_complete to true iff stream is closed while connected.
+ client_stream->stream_error(), connected(),
client_stream->headers_decompressed(),
client_stream->response_headers(),
client_stream->preliminary_headers(),