0

Add netlogs for 1-QWAC verification

Bug: 392931068
Change-Id: I5b77727e7b4b8f638c5f4814085557a4d9edd26e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6330879
Reviewed-by: Nick Harper <nharper@chromium.org>
Commit-Queue: Matt Mueller <mattm@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1431682}
This commit is contained in:
Matt Mueller
2025-03-12 12:13:52 -07:00
committed by Chromium LUCI CQ
parent 1063f78a04
commit 3d56577f8a
3 changed files with 142 additions and 10 deletions

@ -734,19 +734,34 @@ class PathBuilderDelegateImpl : public bssl::SimplePathBuilderDelegate {
class QwacPathBuilderDelegateImpl : public bssl::SimplePathBuilderDelegate {
public:
// TODO(crbug.com/392931068): netlogs
QwacPathBuilderDelegateImpl()
explicit QwacPathBuilderDelegateImpl(const NetLogWithSource& net_log)
: bssl::SimplePathBuilderDelegate(
kMinRsaModulusLengthBits,
bssl::SimplePathBuilderDelegate::DigestPolicy::kStrong) {}
bssl::SimplePathBuilderDelegate::DigestPolicy::kStrong),
net_log_(net_log) {}
void CheckPathAfterVerification(
const bssl::CertPathBuilder& path_builder,
bssl::CertPathBuilderResultPath* path) override {
net_log_->BeginEvent(NetLogEventType::CERT_VERIFY_PROC_PATH_BUILT);
if (!Has1QwacPolicies(path->user_constrained_policy_set)) {
path->errors.GetErrorsForCert(0)->AddError(kPathLacksQwacPolicy);
}
net_log_->EndEvent(NetLogEventType::CERT_VERIFY_PROC_PATH_BUILT,
[&] { return NetLogPathBuilderResultPath(*path); });
}
bool IsDebugLogEnabled() override { return net_log_->IsCapturing(); }
void DebugLog(std::string_view msg) override {
net_log_->AddEventWithStringParams(
NetLogEventType::CERT_VERIFY_PROC_PATH_BUILDER_DEBUG, "debug", msg);
}
private:
raw_ref<const NetLogWithSource> net_log_;
};
std::shared_ptr<const bssl::ParsedCertificate> ParseCertificateFromBuffer(
@ -782,7 +797,8 @@ class CertVerifyProcBuiltin : public CertVerifyProc {
#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
void MaybeVerify1QWAC(const bssl::CertPathBuilderResultPath* verified_path,
const bssl::der::GeneralizedTime& der_verification_time,
CertVerifyResult* verify_result);
CertVerifyResult* verify_result,
const NetLogWithSource& net_log);
#endif
const scoped_refptr<CertNetFetcher> net_fetcher_;
@ -1444,7 +1460,7 @@ int CertVerifyProcBuiltin::VerifyInternal(X509Certificate* input_cert,
cur_attempt.use_system_time
? der_verification_system_time
: der_verification_custom_time,
verify_result);
verify_result, net_log);
}
#endif
}
@ -1455,10 +1471,10 @@ int CertVerifyProcBuiltin::VerifyInternal(X509Certificate* input_cert,
void CertVerifyProcBuiltin::MaybeVerify1QWAC(
const bssl::CertPathBuilderResultPath* verified_path,
const bssl::der::GeneralizedTime& der_verification_time,
CertVerifyResult* verify_result) {
CertVerifyResult* verify_result,
const NetLogWithSource& net_log) {
CHECK(verified_path);
CHECK(verified_path->IsValid());
// TODO(crbug.com/392931068): netlogs
// TODO(crbug.com/392931068): histograms
const std::shared_ptr<const bssl::ParsedCertificate>& target =
@ -1505,7 +1521,13 @@ void CertVerifyProcBuiltin::MaybeVerify1QWAC(
bssl::der::Input(bssl::kAnyPolicyOid)};
// TODO(crbug.com/392931068): does not implement deadlines (right now there is
// no OS or network interaction, so this should be fine.)
QwacPathBuilderDelegateImpl path_builder_delegate;
QwacPathBuilderDelegateImpl path_builder_delegate(net_log);
net_log.BeginEvent(NetLogEventType::CERT_VERIFY_PROC_PATH_BUILD_ATTEMPT, [&] {
base::Value::Dict results;
results.Set("is_qwac_attempt", true);
return results;
});
// Initialize the path builder.
bssl::CertPathBuilder path_builder(
@ -1520,6 +1542,9 @@ void CertVerifyProcBuiltin::MaybeVerify1QWAC(
path_builder.SetIterationLimit(kPathBuilderIterationLimit);
qwac_result = path_builder.Run();
net_log.EndEvent(NetLogEventType::CERT_VERIFY_PROC_PATH_BUILD_ATTEMPT,
[&] { return NetLogPathBuilderResult(qwac_result); });
if (!qwac_result.HasValidPath()) {
return;
}

@ -110,6 +110,32 @@ static std::string MakeRandomPath(std::string_view suffix) {
return "/" + MakeRandomHexString(12) + std::string(suffix);
}
#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
std::vector<std::string> ParseNetLogCertificatesList(
const base::Value::List& list) {
std::vector<std::string> result;
for (const auto& pem_value : list) {
if (!pem_value.is_string()) {
result.push_back("Value is not a string");
continue;
}
CertificateList certs = X509Certificate::CreateCertificateListFromBytes(
base::as_byte_span(pem_value.GetString()),
X509Certificate::Format::FORMAT_PEM_CERT_SEQUENCE);
if (certs.empty()) {
result.push_back("error decoding pem");
continue;
}
if (certs.size() > 1) {
result.push_back("multiple certs in pem");
continue;
}
result.emplace_back(base::as_string_view(certs[0]->cert_span()));
}
return result;
}
#endif // BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
int VerifyOnWorkerThread(const scoped_refptr<CertVerifyProc>& verify_proc,
scoped_refptr<X509Certificate> cert,
const std::string& hostname,
@ -1887,7 +1913,7 @@ class CertVerifyProcBuiltin1QwacTest
};
TEST_P(CertVerifyProcBuiltin1QwacTest, OneQwacRequiresEutl) {
// TODO(crbug.com/392931068): test netlogs, histograms
// TODO(crbug.com/392931068): test histograms
auto [leaf, intermediate, root] = CertBuilder::CreateSimpleChain3();
// intermediate->SetCertificatePolicies({"2.5.29.32.0"}); // anyPolicy
@ -2054,6 +2080,7 @@ TEST_P(CertVerifyProcBuiltin1QwacTest, OneQwacCanBuildAlternatePath) {
intermediate->GetSubjectKeyIdentifier());
AddMockEutlRoot(eutl_intermediate.GetCertBuffer());
RecordingNetLogObserver net_log_observer(NetLogCaptureMode::kDefault);
CertVerifyResult verify_result;
NetLogSource verify_net_log_source;
TestCompletionCallback callback;
@ -2072,7 +2099,86 @@ TEST_P(CertVerifyProcBuiltin1QwacTest, OneQwacCanBuildAlternatePath) {
verify_result.verified_cert->intermediate_buffers()[0].get());
EXPECT_EQ(root->GetCertBuffer(),
verify_result.verified_cert->intermediate_buffers()[1].get());
// TODO(crbug.com/392931068): test that the eutl chain was netlogged
auto events = net_log_observer.GetEntriesForSource(verify_net_log_source);
auto event = std::ranges::find(
events, NetLogEventType::CERT_VERIFY_PROC_PATH_BUILD_ATTEMPT,
&NetLogEntry::type);
ASSERT_NE(event, events.end());
EXPECT_EQ(net::NetLogEventPhase::BEGIN, event->phase);
EXPECT_EQ(std::nullopt, event->params.FindBool("is_qwac_attempt"));
event = std::ranges::find(++event, events.end(),
NetLogEventType::CERT_VERIFY_PROC_PATH_BUILT,
&NetLogEntry::type);
ASSERT_NE(event, events.end());
EXPECT_EQ(net::NetLogEventPhase::BEGIN, event->phase);
event = std::ranges::find(++event, events.end(),
NetLogEventType::CERT_VERIFY_PROC_PATH_BUILT,
&NetLogEntry::type);
ASSERT_NE(event, events.end());
EXPECT_EQ(net::NetLogEventPhase::END, event->phase);
EXPECT_EQ(true, event->params.FindBool("is_valid"));
base::Value::List* pem_certs = event->params.FindList("certificates");
ASSERT_TRUE(pem_certs);
// The CERT_VERIFY_PROC_PATH_BUILT netlog for the main verification should
// contain the TLS cert chain.
EXPECT_THAT(ParseNetLogCertificatesList(*pem_certs),
testing::ElementsAre(leaf->GetDER(), intermediate->GetDER(),
root->GetDER()));
event = std::ranges::find(
++event, events.end(),
NetLogEventType::CERT_VERIFY_PROC_PATH_BUILD_ATTEMPT, &NetLogEntry::type);
ASSERT_NE(event, events.end());
EXPECT_EQ(net::NetLogEventPhase::END, event->phase);
EXPECT_EQ(true, event->params.FindBool("has_valid_path"));
event = std::ranges::find(
++event, events.end(),
NetLogEventType::CERT_VERIFY_PROC_PATH_BUILD_ATTEMPT, &NetLogEntry::type);
if (!GetParam()) {
// If the feature flag wasn't enabled, there should only be one
// CERT_VERIFY_PROC_PATH_BUILD_ATTEMPT.
ASSERT_EQ(event, events.end());
return;
}
ASSERT_NE(event, events.end());
EXPECT_EQ(net::NetLogEventPhase::BEGIN, event->phase);
EXPECT_EQ(true, event->params.FindBool("is_qwac_attempt"));
event = std::ranges::find(++event, events.end(),
NetLogEventType::CERT_VERIFY_PROC_PATH_BUILT,
&NetLogEntry::type);
ASSERT_NE(event, events.end());
EXPECT_EQ(net::NetLogEventPhase::BEGIN, event->phase);
event = std::ranges::find(++event, events.end(),
NetLogEventType::CERT_VERIFY_PROC_PATH_BUILT,
&NetLogEntry::type);
ASSERT_NE(event, events.end());
EXPECT_EQ(net::NetLogEventPhase::END, event->phase);
EXPECT_EQ(true, event->params.FindBool("is_valid"));
pem_certs = event->params.FindList("certificates");
ASSERT_TRUE(pem_certs);
// The CERT_VERIFY_PROC_PATH_BUILT netlog for the 1-QWAC verification should
// contain the QWAC cert chain.
EXPECT_THAT(ParseNetLogCertificatesList(*pem_certs),
testing::ElementsAre(leaf->GetDER(), eutl_intermediate.GetDER()));
event = std::ranges::find(
++event, events.end(),
NetLogEventType::CERT_VERIFY_PROC_PATH_BUILD_ATTEMPT, &NetLogEntry::type);
ASSERT_NE(event, events.end());
EXPECT_EQ(net::NetLogEventPhase::END, event->phase);
EXPECT_EQ(true, event->params.FindBool("has_valid_path"));
event = std::ranges::find(
++event, events.end(),
NetLogEventType::CERT_VERIFY_PROC_PATH_BUILD_ATTEMPT, &NetLogEntry::type);
ASSERT_EQ(event, events.end());
}
INSTANTIATE_TEST_SUITE_P(, CertVerifyProcBuiltin1QwacTest, testing::Bool());

@ -3873,6 +3873,7 @@ EVENT_TYPE(CERT_VERIFY_PROC_ADDITIONAL_CERT)
// "digest_policy": <Specifies which digest methods are accepted in this
// attempt.>
// "is_ev_attempt": <True if this is an EV verification attempt.>
// "is_qwac_attempt": <True if this is a QWAC verification attempt.>
// "is_network_time_attempt": <True if this attempt used the network time.>
// "network_time_value": <Int - time in milliseconds since the unix epoch,
// only populated if is_network_time_attempt is