1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/cert/cert_verify_proc_builtin.h"
6
7 #include <memory>
8 #include <optional>
9 #include <string>
10 #include <string_view>
11 #include <vector>
12
13 #include "base/feature_list.h"
14 #include "base/logging.h"
15 #include "base/memory/raw_ptr.h"
16 #include "base/time/time.h"
17 #include "base/values.h"
18 #include "components/network_time/time_tracker/time_tracker.h"
19 #include "crypto/sha2.h"
20 #include "net/base/features.h"
21 #include "net/base/ip_address.h"
22 #include "net/base/net_errors.h"
23 #include "net/cert/cert_net_fetcher.h"
24 #include "net/cert/cert_status_flags.h"
25 #include "net/cert/cert_verifier.h"
26 #include "net/cert/cert_verify_proc.h"
27 #include "net/cert/cert_verify_result.h"
28 #include "net/cert/ct_policy_enforcer.h"
29 #include "net/cert/ct_policy_status.h"
30 #include "net/cert/ct_verifier.h"
31 #include "net/cert/ev_root_ca_metadata.h"
32 #include "net/cert/internal/cert_issuer_source_aia.h"
33 #include "net/cert/internal/revocation_checker.h"
34 #include "net/cert/internal/system_trust_store.h"
35 #include "net/cert/signed_certificate_timestamp_and_status.h"
36 #include "net/cert/test_root_certs.h"
37 #include "net/cert/time_conversions.h"
38 #include "net/cert/x509_certificate.h"
39 #include "net/cert/x509_util.h"
40 #include "net/log/net_log_values.h"
41 #include "net/log/net_log_with_source.h"
42 #include "third_party/boringssl/src/pki/cert_errors.h"
43 #include "third_party/boringssl/src/pki/cert_issuer_source_static.h"
44 #include "third_party/boringssl/src/pki/common_cert_errors.h"
45 #include "third_party/boringssl/src/pki/name_constraints.h"
46 #include "third_party/boringssl/src/pki/parsed_certificate.h"
47 #include "third_party/boringssl/src/pki/path_builder.h"
48 #include "third_party/boringssl/src/pki/simple_path_builder_delegate.h"
49 #include "third_party/boringssl/src/pki/trust_store.h"
50 #include "third_party/boringssl/src/pki/trust_store_collection.h"
51 #include "third_party/boringssl/src/pki/trust_store_in_memory.h"
52
53 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
54 #include "base/version_info/version_info.h" // nogncheck
55 #include "net/cert/internal/trust_store_chrome.h"
56 #endif
57
58 using bssl::CertErrorId;
59
60 namespace net {
61
62 namespace {
63
64 // To avoid a denial-of-service risk, cap iterations by the path builder.
65 // Without a limit, path building is potentially exponential. This limit was
66 // set based on UMA histograms in the wild. See https://crrev.com/c/4903550.
67 //
68 // TODO(crbug.com/41267856): Move this limit into BoringSSL as a default.
69 constexpr uint32_t kPathBuilderIterationLimit = 20;
70
71 constexpr base::TimeDelta kMaxVerificationTime = base::Seconds(60);
72
73 constexpr base::TimeDelta kPerAttemptMinVerificationTimeLimit =
74 base::Seconds(5);
75
76 DEFINE_CERT_ERROR_ID(kPathLacksEVPolicy, "Path does not have an EV policy");
77 DEFINE_CERT_ERROR_ID(kChromeRootConstraintsFailed,
78 "Path does not satisfy CRS constraints");
79
NetLogCertParams(const CRYPTO_BUFFER * cert_handle,const bssl::CertErrors & errors)80 base::Value::Dict NetLogCertParams(const CRYPTO_BUFFER* cert_handle,
81 const bssl::CertErrors& errors) {
82 base::Value::Dict results;
83
84 std::string pem_encoded;
85 if (X509Certificate::GetPEMEncodedFromDER(
86 x509_util::CryptoBufferAsStringPiece(cert_handle), &pem_encoded)) {
87 results.Set("certificate", pem_encoded);
88 }
89
90 std::string errors_string = errors.ToDebugString();
91 if (!errors_string.empty())
92 results.Set("errors", errors_string);
93
94 return results;
95 }
96
NetLogAdditionalCert(const CRYPTO_BUFFER * cert_handle,const bssl::CertificateTrust & trust,const bssl::CertErrors & errors)97 base::Value::Dict NetLogAdditionalCert(const CRYPTO_BUFFER* cert_handle,
98 const bssl::CertificateTrust& trust,
99 const bssl::CertErrors& errors) {
100 base::Value::Dict results = NetLogCertParams(cert_handle, errors);
101 results.Set("trust", trust.ToDebugString());
102 return results;
103 }
104
105 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
NetLogChromeRootStoreVersion(int64_t chrome_root_store_version)106 base::Value::Dict NetLogChromeRootStoreVersion(
107 int64_t chrome_root_store_version) {
108 base::Value::Dict results;
109 results.Set("version_major", NetLogNumberValue(chrome_root_store_version));
110 return results;
111 }
112 #endif
113
PEMCertValueList(const bssl::ParsedCertificateList & certs)114 base::Value::List PEMCertValueList(const bssl::ParsedCertificateList& certs) {
115 base::Value::List value;
116 for (const auto& cert : certs) {
117 std::string pem;
118 X509Certificate::GetPEMEncodedFromDER(cert->der_cert().AsStringView(),
119 &pem);
120 value.Append(std::move(pem));
121 }
122 return value;
123 }
124
NetLogPathBuilderResultPath(const bssl::CertPathBuilderResultPath & result_path)125 base::Value::Dict NetLogPathBuilderResultPath(
126 const bssl::CertPathBuilderResultPath& result_path) {
127 base::Value::Dict dict;
128 dict.Set("is_valid", result_path.IsValid());
129 dict.Set("last_cert_trust", result_path.last_cert_trust.ToDebugString());
130 dict.Set("certificates", PEMCertValueList(result_path.certs));
131 // TODO(crbug.com/40479281): netlog user_constrained_policy_set.
132 std::string errors_string =
133 result_path.errors.ToDebugString(result_path.certs);
134 if (!errors_string.empty())
135 dict.Set("errors", errors_string);
136 return dict;
137 }
138
NetLogPathBuilderResult(const bssl::CertPathBuilder::Result & result)139 base::Value::Dict NetLogPathBuilderResult(
140 const bssl::CertPathBuilder::Result& result) {
141 base::Value::Dict dict;
142 // TODO(crbug.com/40479281): include debug data (or just have things netlog it
143 // directly).
144 dict.Set("has_valid_path", result.HasValidPath());
145 dict.Set("best_result_index", static_cast<int>(result.best_result_index));
146 if (result.exceeded_iteration_limit)
147 dict.Set("exceeded_iteration_limit", true);
148 if (result.exceeded_deadline)
149 dict.Set("exceeded_deadline", true);
150 return dict;
151 }
152
NoRevocationChecking()153 RevocationPolicy NoRevocationChecking() {
154 RevocationPolicy policy;
155 policy.check_revocation = false;
156 policy.networking_allowed = false;
157 policy.crl_allowed = false;
158 policy.allow_missing_info = true;
159 policy.allow_unable_to_check = true;
160 policy.enforce_baseline_requirements = false;
161 return policy;
162 }
163
164 // Gets the set of policy OIDs in |cert| that are recognized as EV OIDs for some
165 // root.
GetEVPolicyOids(const EVRootCAMetadata * ev_metadata,const bssl::ParsedCertificate * cert,std::set<bssl::der::Input> * oids)166 void GetEVPolicyOids(const EVRootCAMetadata* ev_metadata,
167 const bssl::ParsedCertificate* cert,
168 std::set<bssl::der::Input>* oids) {
169 oids->clear();
170
171 if (!cert->has_policy_oids())
172 return;
173
174 for (const bssl::der::Input& oid : cert->policy_oids()) {
175 if (ev_metadata->IsEVPolicyOID(oid)) {
176 oids->insert(oid);
177 }
178 }
179 }
180
181 // Returns true if |cert| could be an EV certificate, based on its policies
182 // extension. A return of false means it definitely is not an EV certificate,
183 // whereas a return of true means it could be EV.
IsEVCandidate(const EVRootCAMetadata * ev_metadata,const bssl::ParsedCertificate * cert)184 bool IsEVCandidate(const EVRootCAMetadata* ev_metadata,
185 const bssl::ParsedCertificate* cert) {
186 std::set<bssl::der::Input> oids;
187 GetEVPolicyOids(ev_metadata, cert, &oids);
188 return !oids.empty();
189 }
190
191 // CertVerifyProcTrustStore wraps a SystemTrustStore with additional trust
192 // anchors and TestRootCerts.
193 class CertVerifyProcTrustStore {
194 public:
195 // |system_trust_store| must outlive this object.
CertVerifyProcTrustStore(SystemTrustStore * system_trust_store,bssl::TrustStoreInMemory * additional_trust_store)196 explicit CertVerifyProcTrustStore(
197 SystemTrustStore* system_trust_store,
198 bssl::TrustStoreInMemory* additional_trust_store)
199 : system_trust_store_(system_trust_store),
200 additional_trust_store_(additional_trust_store) {
201 trust_store_.AddTrustStore(additional_trust_store_);
202 trust_store_.AddTrustStore(system_trust_store_->GetTrustStore());
203 // When running in test mode, also layer in the test-only root certificates.
204 //
205 // Note that this integration requires TestRootCerts::HasInstance() to be
206 // true by the time CertVerifyProcTrustStore is created - a limitation which
207 // is acceptable for the test-only code that consumes this.
208 if (TestRootCerts::HasInstance()) {
209 trust_store_.AddTrustStore(
210 TestRootCerts::GetInstance()->test_trust_store());
211 }
212 }
213
trust_store()214 bssl::TrustStore* trust_store() { return &trust_store_; }
215
IsKnownRoot(const bssl::ParsedCertificate * trust_anchor) const216 bool IsKnownRoot(const bssl::ParsedCertificate* trust_anchor) const {
217 if (TestRootCerts::HasInstance() &&
218 TestRootCerts::GetInstance()->IsKnownRoot(trust_anchor->der_cert())) {
219 return true;
220 }
221 return system_trust_store_->IsKnownRoot(trust_anchor);
222 }
223
224 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
GetChromeRootConstraints(const bssl::ParsedCertificate * cert) const225 base::span<const ChromeRootCertConstraints> GetChromeRootConstraints(
226 const bssl::ParsedCertificate* cert) const {
227 return system_trust_store_->GetChromeRootConstraints(cert);
228 }
229
IsNonChromeRootStoreTrustAnchor(const bssl::ParsedCertificate * trust_anchor) const230 bool IsNonChromeRootStoreTrustAnchor(
231 const bssl::ParsedCertificate* trust_anchor) const {
232 return IsAdditionalTrustAnchor(trust_anchor) ||
233 system_trust_store_->IsLocallyTrustedRoot(trust_anchor);
234 }
235 #endif
236
IsAdditionalTrustAnchor(const bssl::ParsedCertificate * trust_anchor) const237 bool IsAdditionalTrustAnchor(
238 const bssl::ParsedCertificate* trust_anchor) const {
239 return additional_trust_store_->GetTrust(trust_anchor).IsTrustAnchor();
240 }
241
242 private:
243 raw_ptr<SystemTrustStore> system_trust_store_;
244 raw_ptr<bssl::TrustStoreInMemory> additional_trust_store_;
245 bssl::TrustStoreCollection trust_store_;
246 };
247
248 // Enum for whether path building is attempting to verify a certificate as EV or
249 // as DV.
250 enum class VerificationType {
251 kEV, // Extended Validation
252 kDV, // Domain Validation
253 };
254
255 class PathBuilderDelegateDataImpl : public bssl::CertPathBuilderDelegateData {
256 public:
257 ~PathBuilderDelegateDataImpl() override = default;
258
Get(const bssl::CertPathBuilderResultPath & path)259 static const PathBuilderDelegateDataImpl* Get(
260 const bssl::CertPathBuilderResultPath& path) {
261 return static_cast<PathBuilderDelegateDataImpl*>(path.delegate_data.get());
262 }
263
GetOrCreate(bssl::CertPathBuilderResultPath * path)264 static PathBuilderDelegateDataImpl* GetOrCreate(
265 bssl::CertPathBuilderResultPath* path) {
266 if (!path->delegate_data)
267 path->delegate_data = std::make_unique<PathBuilderDelegateDataImpl>();
268 return static_cast<PathBuilderDelegateDataImpl*>(path->delegate_data.get());
269 }
270
271 bssl::OCSPVerifyResult stapled_ocsp_verify_result;
272 SignedCertificateTimestampAndStatusList scts;
273 ct::CTPolicyCompliance ct_policy_compliance;
274 };
275
276 // TODO(eroman): The path building code in this file enforces its idea of weak
277 // keys, and signature algorithms, but separately cert_verify_proc.cc also
278 // checks the chains with its own policy. These policies must be aligned to
279 // give path building the best chance of finding a good path.
280 class PathBuilderDelegateImpl : public bssl::SimplePathBuilderDelegate {
281 public:
282 // Uses the default policy from bssl::SimplePathBuilderDelegate, which
283 // requires RSA keys to be at least 1024-bits large, and optionally accepts
284 // SHA1 certificates.
PathBuilderDelegateImpl(const CRLSet * crl_set,CTVerifier * ct_verifier,const CTPolicyEnforcer * ct_policy_enforcer,CertNetFetcher * net_fetcher,VerificationType verification_type,bssl::SimplePathBuilderDelegate::DigestPolicy digest_policy,int flags,const CertVerifyProcTrustStore * trust_store,const std::vector<net::CertVerifyProc::CertificateWithConstraints> & additional_constraints,std::string_view stapled_leaf_ocsp_response,std::string_view sct_list_from_tls_extension,const EVRootCAMetadata * ev_metadata,base::TimeTicks deadline,base::Time current_time,bool * checked_revocation_for_some_path,const NetLogWithSource & net_log)285 PathBuilderDelegateImpl(
286 const CRLSet* crl_set,
287 CTVerifier* ct_verifier,
288 const CTPolicyEnforcer* ct_policy_enforcer,
289 CertNetFetcher* net_fetcher,
290 VerificationType verification_type,
291 bssl::SimplePathBuilderDelegate::DigestPolicy digest_policy,
292 int flags,
293 const CertVerifyProcTrustStore* trust_store,
294 const std::vector<net::CertVerifyProc::CertificateWithConstraints>&
295 additional_constraints,
296 std::string_view stapled_leaf_ocsp_response,
297 std::string_view sct_list_from_tls_extension,
298 const EVRootCAMetadata* ev_metadata,
299 base::TimeTicks deadline,
300 base::Time current_time,
301 bool* checked_revocation_for_some_path,
302 const NetLogWithSource& net_log)
303 : bssl::SimplePathBuilderDelegate(1024, digest_policy),
304 crl_set_(crl_set),
305 ct_verifier_(ct_verifier),
306 ct_policy_enforcer_(ct_policy_enforcer),
307 net_fetcher_(net_fetcher),
308 verification_type_(verification_type),
309 flags_(flags),
310 trust_store_(trust_store),
311 additional_constraints_(additional_constraints),
312 stapled_leaf_ocsp_response_(stapled_leaf_ocsp_response),
313 sct_list_from_tls_extension_(sct_list_from_tls_extension),
314 ev_metadata_(ev_metadata),
315 deadline_(deadline),
316 current_time_(current_time),
317 checked_revocation_for_some_path_(checked_revocation_for_some_path),
318 net_log_(net_log) {}
319
320 // This is called for each built chain, including ones which failed. It is
321 // responsible for adding errors to the built chain if it is not acceptable.
CheckPathAfterVerification(const bssl::CertPathBuilder & path_builder,bssl::CertPathBuilderResultPath * path)322 void CheckPathAfterVerification(
323 const bssl::CertPathBuilder& path_builder,
324 bssl::CertPathBuilderResultPath* path) override {
325 net_log_->BeginEvent(NetLogEventType::CERT_VERIFY_PROC_PATH_BUILT);
326
327 CheckPathAfterVerificationImpl(path_builder, path);
328
329 net_log_->EndEvent(NetLogEventType::CERT_VERIFY_PROC_PATH_BUILT,
330 [&] { return NetLogPathBuilderResultPath(*path); });
331 }
332
333 private:
CheckPathAfterVerificationImpl(const bssl::CertPathBuilder & path_builder,bssl::CertPathBuilderResultPath * path)334 void CheckPathAfterVerificationImpl(const bssl::CertPathBuilder& path_builder,
335 bssl::CertPathBuilderResultPath* path) {
336 PathBuilderDelegateDataImpl* delegate_data =
337 PathBuilderDelegateDataImpl::GetOrCreate(path);
338
339 // TODO(https://crbug.com/1211074, https://crbug.com/848277): making a
340 // temporary X509Certificate just to pass into CTVerifier and
341 // CTPolicyEnforcer is silly, refactor so they take CRYPTO_BUFFER or
342 // ParsedCertificate or something.
343 std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
344 if (path->certs.size() > 1) {
345 intermediates.push_back(bssl::UpRef(path->certs[1]->cert_buffer()));
346 }
347 auto cert_for_ct_verify = X509Certificate::CreateFromBuffer(
348 bssl::UpRef(path->certs[0]->cert_buffer()), std::move(intermediates));
349 ct_verifier_->Verify(cert_for_ct_verify.get(), stapled_leaf_ocsp_response_,
350 sct_list_from_tls_extension_, current_time_,
351 &delegate_data->scts, *net_log_);
352
353 // Check any extra constraints that might exist outside of the certificates.
354 CheckExtraConstraints(path->certs, &path->errors);
355 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
356 CheckChromeRootConstraints(path);
357 #endif
358
359 // If the path is already invalid, don't check revocation status. The
360 // chain is expected to be valid when doing revocation checks (since for
361 // instance the correct issuer for a certificate may need to be known).
362 // Also if certificates are already expired, obtaining their revocation
363 // status may fail.
364 //
365 // TODO(eroman): When CertVerifyProcBuiltin fails to find a valid path,
366 // whatever (partial/incomplete) path it does return should
367 // minimally be checked with the CRLSet.
368 if (!path->IsValid()) {
369 return;
370 }
371
372 // If EV was requested the certificate must chain to a recognized EV root
373 // and have one of its recognized EV policy OIDs.
374 if (verification_type_ == VerificationType::kEV) {
375 if (!ConformsToEVPolicy(path)) {
376 path->errors.GetErrorsForCert(0)->AddError(kPathLacksEVPolicy);
377 return;
378 }
379 }
380
381 // Select an appropriate revocation policy for this chain based on the
382 // verifier flags and root.
383 RevocationPolicy policy = ChooseRevocationPolicy(path->certs);
384
385 // Check for revocations using the CRLSet.
386 switch (
387 CheckChainRevocationUsingCRLSet(crl_set_, path->certs, &path->errors)) {
388 case CRLSet::Result::REVOKED:
389 return;
390 case CRLSet::Result::GOOD:
391 break;
392 case CRLSet::Result::UNKNOWN:
393 // CRLSet was inconclusive.
394 break;
395 }
396
397 if (policy.check_revocation) {
398 *checked_revocation_for_some_path_ = true;
399 }
400
401 // Check the revocation status for each certificate in the chain according
402 // to |policy|. Depending on the policy, errors will be added to the
403 // respective certificates, so |errors->ContainsHighSeverityErrors()| will
404 // reflect the revocation status of the chain after this call.
405 CheckValidatedChainRevocation(path->certs, policy, deadline_,
406 stapled_leaf_ocsp_response_, current_time_,
407 net_fetcher_, &path->errors,
408 &delegate_data->stapled_ocsp_verify_result);
409
410 ct::SCTList verified_scts;
411 for (const auto& sct_and_status : delegate_data->scts) {
412 if (sct_and_status.status == ct::SCT_STATUS_OK) {
413 verified_scts.push_back(sct_and_status.sct);
414 }
415 }
416 delegate_data->ct_policy_compliance = ct_policy_enforcer_->CheckCompliance(
417 cert_for_ct_verify.get(), verified_scts, current_time_, *net_log_);
418 }
419
420 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
421 // Returns the SCTs from `scts` that are verified successfully and signed by
422 // a log which was not disqualified.
ValidScts(const SignedCertificateTimestampAndStatusList & scts)423 ct::SCTList ValidScts(const SignedCertificateTimestampAndStatusList& scts) {
424 ct::SCTList valid_scts;
425 for (const auto& sct_and_status : scts) {
426 if (sct_and_status.status != ct::SCT_STATUS_OK) {
427 continue;
428 }
429 std::optional<base::Time> disqualification_time =
430 ct_policy_enforcer_->GetLogDisqualificationTime(
431 sct_and_status.sct->log_id);
432 // TODO(https://crbug.com/40840044): use the same time source here as for
433 // the rest of verification.
434 if (disqualification_time && base::Time::Now() >= disqualification_time) {
435 continue;
436 }
437 valid_scts.push_back(sct_and_status.sct);
438 }
439 return valid_scts;
440 }
441
CheckPathSatisfiesChromeRootConstraint(bssl::CertPathBuilderResultPath * path,const ChromeRootCertConstraints & constraint)442 bool CheckPathSatisfiesChromeRootConstraint(
443 bssl::CertPathBuilderResultPath* path,
444 const ChromeRootCertConstraints& constraint) {
445 PathBuilderDelegateDataImpl* delegate_data =
446 PathBuilderDelegateDataImpl::GetOrCreate(path);
447
448 // TODO(https://crbug.com/40941039): add more specific netlog or CertError
449 // logs about which constraint failed exactly? (Note that it could be
450 // confusing when there are multiple ChromeRootCertConstraints objects,
451 // would need to clearly distinguish which set of constraints had errors.)
452
453 if (ct_policy_enforcer_->IsCtEnabled()) {
454 if (constraint.sct_not_after.has_value()) {
455 bool found_matching_sct = false;
456 for (const auto& sct : ValidScts(delegate_data->scts)) {
457 if (sct->timestamp <= constraint.sct_not_after.value()) {
458 found_matching_sct = true;
459 break;
460 }
461 }
462 if (!found_matching_sct) {
463 return false;
464 }
465 }
466
467 if (constraint.sct_all_after.has_value()) {
468 ct::SCTList valid_scts = ValidScts(delegate_data->scts);
469 if (valid_scts.empty()) {
470 return false;
471 }
472 for (const auto& sct : ValidScts(delegate_data->scts)) {
473 if (sct->timestamp <= constraint.sct_all_after.value()) {
474 return false;
475 }
476 }
477 }
478 }
479
480 if (!constraint.permitted_dns_names.empty()) {
481 bssl::GeneralNames permitted_names;
482 for (const auto& dns_name : constraint.permitted_dns_names) {
483 permitted_names.dns_names.push_back(dns_name);
484 }
485 permitted_names.present_name_types |=
486 bssl::GeneralNameTypes::GENERAL_NAME_DNS_NAME;
487
488 std::unique_ptr<bssl::NameConstraints> nc =
489 bssl::NameConstraints::CreateFromPermittedSubtrees(
490 std::move(permitted_names));
491
492 const std::shared_ptr<const bssl::ParsedCertificate>& leaf_cert =
493 path->certs[0];
494 bssl::CertErrors name_constraint_errors;
495 nc->IsPermittedCert(leaf_cert->normalized_subject(),
496 leaf_cert->subject_alt_names(),
497 &name_constraint_errors);
498 if (name_constraint_errors.ContainsAnyErrorWithSeverity(
499 bssl::CertError::SEVERITY_HIGH)) {
500 return false;
501 }
502 }
503
504 if (constraint.min_version.has_value() &&
505 version_info::GetVersion() < constraint.min_version.value()) {
506 return false;
507 }
508
509 if (constraint.max_version_exclusive.has_value() &&
510 version_info::GetVersion() >=
511 constraint.max_version_exclusive.value()) {
512 return false;
513 }
514
515 return true;
516 }
517
CheckChromeRootConstraints(bssl::CertPathBuilderResultPath * path)518 void CheckChromeRootConstraints(bssl::CertPathBuilderResultPath* path) {
519 // If the root is trusted locally, do not enforce CRS constraints, even if
520 // some exist.
521 if (trust_store_->IsNonChromeRootStoreTrustAnchor(
522 path->certs.back().get())) {
523 return;
524 }
525
526 if (base::span<const ChromeRootCertConstraints> constraints =
527 trust_store_->GetChromeRootConstraints(path->certs.back().get());
528 !constraints.empty()) {
529 bool found_valid_constraint = false;
530 for (const ChromeRootCertConstraints& constraint : constraints) {
531 found_valid_constraint |=
532 CheckPathSatisfiesChromeRootConstraint(path, constraint);
533 }
534 if (!found_valid_constraint) {
535 path->errors.GetOtherErrors()->AddError(kChromeRootConstraintsFailed);
536 }
537 }
538 }
539 #endif
540
541 // Check extra constraints that aren't encoded in the certificates themselves.
CheckExtraConstraints(const bssl::ParsedCertificateList & certs,bssl::CertPathErrors * errors)542 void CheckExtraConstraints(const bssl::ParsedCertificateList& certs,
543 bssl::CertPathErrors* errors) {
544 const std::shared_ptr<const bssl::ParsedCertificate> root_cert =
545 certs.back();
546 // An assumption being made is that there will be at most a few (2-3) certs
547 // in here; if there are more and this ends up being a drag on performance
548 // it may be worth making additional_constraints_ into a map storing certs
549 // by hash.
550 for (const auto& cert_with_constraints : *additional_constraints_) {
551 if (!x509_util::CryptoBufferEqual(
552 root_cert->cert_buffer(),
553 cert_with_constraints.certificate->cert_buffer())) {
554 continue;
555 }
556 // Found the cert, check constraints
557 if (cert_with_constraints.permitted_dns_names.empty() &&
558 cert_with_constraints.permitted_cidrs.empty()) {
559 // No constraints to check.
560 return;
561 }
562
563 bssl::GeneralNames permitted_names;
564
565 if (!cert_with_constraints.permitted_dns_names.empty()) {
566 for (const auto& dns_name : cert_with_constraints.permitted_dns_names) {
567 permitted_names.dns_names.push_back(dns_name);
568 }
569 permitted_names.present_name_types |=
570 bssl::GeneralNameTypes::GENERAL_NAME_DNS_NAME;
571 }
572
573 if (!cert_with_constraints.permitted_cidrs.empty()) {
574 for (const auto& cidr : cert_with_constraints.permitted_cidrs) {
575 permitted_names.ip_address_ranges.emplace_back(cidr.ip.bytes(),
576 cidr.mask.bytes());
577 }
578 permitted_names.present_name_types |=
579 bssl::GeneralNameTypes::GENERAL_NAME_IP_ADDRESS;
580 }
581
582 std::unique_ptr<bssl::NameConstraints> nc =
583 bssl::NameConstraints::CreateFromPermittedSubtrees(
584 std::move(permitted_names));
585
586 const std::shared_ptr<const bssl::ParsedCertificate>& leaf_cert =
587 certs[0];
588
589 nc->IsPermittedCert(leaf_cert->normalized_subject(),
590 leaf_cert->subject_alt_names(),
591 errors->GetErrorsForCert(0));
592 return;
593 }
594 }
595
596 // Selects a revocation policy based on the CertVerifier flags and the given
597 // certificate chain.
ChooseRevocationPolicy(const bssl::ParsedCertificateList & certs)598 RevocationPolicy ChooseRevocationPolicy(
599 const bssl::ParsedCertificateList& certs) {
600 if (flags_ & CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES) {
601 // In theory when network fetches are disabled but revocation is enabled
602 // we could continue with networking_allowed=false (and
603 // VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS would also have to change
604 // allow_missing_info and allow_unable_to_check to true).
605 // That theoretically could allow still consulting any cached CRLs/etc.
606 // However in the way things are currently implemented in the builtin
607 // verifier there really is no point to bothering, just disable
608 // revocation checking if network fetches are disabled.
609 return NoRevocationChecking();
610 }
611
612 // Use hard-fail revocation checking for local trust anchors, if requested
613 // by the load flag and the chain uses a non-public root.
614 if ((flags_ & CertVerifyProc::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) &&
615 !certs.empty() && !trust_store_->IsKnownRoot(certs.back().get())) {
616 RevocationPolicy policy;
617 policy.check_revocation = true;
618 policy.networking_allowed = true;
619 policy.crl_allowed = true;
620 policy.allow_missing_info = false;
621 policy.allow_unable_to_check = false;
622 policy.enforce_baseline_requirements = false;
623 return policy;
624 }
625
626 // Use soft-fail revocation checking for VERIFY_REV_CHECKING_ENABLED.
627 if (flags_ & CertVerifyProc::VERIFY_REV_CHECKING_ENABLED) {
628 const bool is_known_root =
629 !certs.empty() && trust_store_->IsKnownRoot(certs.back().get());
630 RevocationPolicy policy;
631 policy.check_revocation = true;
632 policy.networking_allowed = true;
633 // Publicly trusted certs are required to have OCSP by the Baseline
634 // Requirements and CRLs can be quite large, so disable the fallback to
635 // CRLs for chains to known roots.
636 policy.crl_allowed = !is_known_root;
637 policy.allow_missing_info = true;
638 policy.allow_unable_to_check = true;
639 policy.enforce_baseline_requirements = is_known_root;
640 return policy;
641 }
642
643 return NoRevocationChecking();
644 }
645
646 // Returns true if |path| chains to an EV root, and the chain conforms to
647 // one of its EV policy OIDs. When building paths all candidate EV policy
648 // OIDs were requested, so it is just a matter of testing each of the
649 // policies the chain conforms to.
ConformsToEVPolicy(const bssl::CertPathBuilderResultPath * path)650 bool ConformsToEVPolicy(const bssl::CertPathBuilderResultPath* path) {
651 const bssl::ParsedCertificate* root = path->GetTrustedCert();
652 if (!root) {
653 return false;
654 }
655
656 SHA256HashValue root_fingerprint;
657 crypto::SHA256HashString(root->der_cert().AsStringView(),
658 root_fingerprint.data,
659 sizeof(root_fingerprint.data));
660
661 for (const bssl::der::Input& oid : path->user_constrained_policy_set) {
662 if (ev_metadata_->HasEVPolicyOID(root_fingerprint, oid)) {
663 return true;
664 }
665 }
666
667 return false;
668 }
669
IsDeadlineExpired()670 bool IsDeadlineExpired() override {
671 return !deadline_.is_null() && base::TimeTicks::Now() > deadline_;
672 }
673
IsDebugLogEnabled()674 bool IsDebugLogEnabled() override { return net_log_->IsCapturing(); }
675
DebugLog(std::string_view msg)676 void DebugLog(std::string_view msg) override {
677 net_log_->AddEventWithStringParams(
678 NetLogEventType::CERT_VERIFY_PROC_PATH_BUILDER_DEBUG, "debug", msg);
679 }
680
681 raw_ptr<const CRLSet> crl_set_;
682 raw_ptr<CTVerifier> ct_verifier_;
683 raw_ptr<const CTPolicyEnforcer> ct_policy_enforcer_;
684 raw_ptr<CertNetFetcher> net_fetcher_;
685 const VerificationType verification_type_;
686 const int flags_;
687 raw_ptr<const CertVerifyProcTrustStore> trust_store_;
688 raw_ref<const std::vector<net::CertVerifyProc::CertificateWithConstraints>>
689 additional_constraints_;
690 const std::string_view stapled_leaf_ocsp_response_;
691 const std::string_view sct_list_from_tls_extension_;
692 raw_ptr<const EVRootCAMetadata> ev_metadata_;
693 base::TimeTicks deadline_;
694 base::Time current_time_;
695 raw_ptr<bool> checked_revocation_for_some_path_;
696 raw_ref<const NetLogWithSource> net_log_;
697 };
698
ParseCertificateFromBuffer(CRYPTO_BUFFER * cert_handle,bssl::CertErrors * errors)699 std::shared_ptr<const bssl::ParsedCertificate> ParseCertificateFromBuffer(
700 CRYPTO_BUFFER* cert_handle,
701 bssl::CertErrors* errors) {
702 return bssl::ParsedCertificate::Create(
703 bssl::UpRef(cert_handle), x509_util::DefaultParseCertificateOptions(),
704 errors);
705 }
706
707 class CertVerifyProcBuiltin : public CertVerifyProc {
708 public:
709 CertVerifyProcBuiltin(scoped_refptr<CertNetFetcher> net_fetcher,
710 scoped_refptr<CRLSet> crl_set,
711 std::unique_ptr<CTVerifier> ct_verifier,
712 scoped_refptr<CTPolicyEnforcer> ct_policy_enforcer,
713 std::unique_ptr<SystemTrustStore> system_trust_store,
714 const CertVerifyProc::InstanceParams& instance_params,
715 std::optional<network_time::TimeTracker> time_tracker);
716
717 protected:
718 ~CertVerifyProcBuiltin() override;
719
720 private:
721 int VerifyInternal(X509Certificate* cert,
722 const std::string& hostname,
723 const std::string& ocsp_response,
724 const std::string& sct_list,
725 int flags,
726 CertVerifyResult* verify_result,
727 const NetLogWithSource& net_log) override;
728
729 const scoped_refptr<CertNetFetcher> net_fetcher_;
730 const std::unique_ptr<CTVerifier> ct_verifier_;
731 const scoped_refptr<CTPolicyEnforcer> ct_policy_enforcer_;
732 const std::unique_ptr<SystemTrustStore> system_trust_store_;
733 std::vector<net::CertVerifyProc::CertificateWithConstraints>
734 additional_constraints_;
735 bssl::TrustStoreInMemory additional_trust_store_;
736 const std::optional<network_time::TimeTracker> time_tracker_;
737 };
738
CertVerifyProcBuiltin(scoped_refptr<CertNetFetcher> net_fetcher,scoped_refptr<CRLSet> crl_set,std::unique_ptr<CTVerifier> ct_verifier,scoped_refptr<CTPolicyEnforcer> ct_policy_enforcer,std::unique_ptr<SystemTrustStore> system_trust_store,const CertVerifyProc::InstanceParams & instance_params,std::optional<network_time::TimeTracker> time_tracker)739 CertVerifyProcBuiltin::CertVerifyProcBuiltin(
740 scoped_refptr<CertNetFetcher> net_fetcher,
741 scoped_refptr<CRLSet> crl_set,
742 std::unique_ptr<CTVerifier> ct_verifier,
743 scoped_refptr<CTPolicyEnforcer> ct_policy_enforcer,
744 std::unique_ptr<SystemTrustStore> system_trust_store,
745 const CertVerifyProc::InstanceParams& instance_params,
746 std::optional<network_time::TimeTracker> time_tracker)
747 : CertVerifyProc(std::move(crl_set)),
748 net_fetcher_(std::move(net_fetcher)),
749 ct_verifier_(std::move(ct_verifier)),
750 ct_policy_enforcer_(std::move(ct_policy_enforcer)),
751 system_trust_store_(std::move(system_trust_store)),
752 time_tracker_(std::move(time_tracker)) {
753 DCHECK(system_trust_store_);
754
755 NetLogWithSource net_log =
756 NetLogWithSource::Make(net::NetLogSourceType::CERT_VERIFY_PROC_CREATED);
757 net_log.BeginEvent(NetLogEventType::CERT_VERIFY_PROC_CREATED);
758
759 // When adding additional certs from instance params, there needs to be a
760 // priority order if a cert is added with multiple different trust types.
761 //
762 // The priority is as follows:
763 //
764 // (a) Distrusted SPKIs (though we don't check for SPKI collisions in added
765 // certs; we rely on that to happen in path building).
766 // (b) Trusted certs with enforced constraints both in the cert and
767 // specified externally outside of the cert.
768 // (c) Trusted certs with enforced constraints only within the cert.
769 // (d) Trusted certs w/o enforced constraints.
770 // (e) Unspecified certs.
771 //
772 // No effort was made to categorize what applies if a cert is specified
773 // within the same category multiple times.
774
775 for (const auto& spki : instance_params.additional_distrusted_spkis) {
776 additional_trust_store_.AddDistrustedCertificateBySPKI(
777 std::string(base::as_string_view(spki)));
778 net_log.AddEvent(NetLogEventType::CERT_VERIFY_PROC_ADDITIONAL_CERT, [&] {
779 base::Value::Dict results;
780 results.Set("spki", NetLogBinaryValue(base::span(spki)));
781 results.Set("trust",
782 bssl::CertificateTrust::ForDistrusted().ToDebugString());
783 return results;
784 });
785 }
786
787 bssl::CertificateTrust anchor_trust_enforcement =
788 bssl::CertificateTrust::ForTrustAnchor()
789 .WithEnforceAnchorConstraints()
790 .WithEnforceAnchorExpiry();
791
792 for (const auto& cert_with_constraints :
793 instance_params.additional_trust_anchors_with_constraints) {
794 const std::shared_ptr<const bssl::ParsedCertificate>& cert =
795 cert_with_constraints.certificate;
796 additional_trust_store_.AddCertificate(cert, anchor_trust_enforcement);
797 additional_constraints_.push_back(cert_with_constraints);
798 bssl::CertErrors parsing_errors;
799 net_log.AddEvent(NetLogEventType::CERT_VERIFY_PROC_ADDITIONAL_CERT, [&] {
800 return NetLogAdditionalCert(cert->cert_buffer(),
801 bssl::CertificateTrust::ForTrustAnchor(),
802 parsing_errors);
803 });
804 }
805
806 bssl::CertificateTrust leaf_trust = bssl::CertificateTrust::ForTrustedLeaf();
807
808 for (const auto& cert_with_possible_constraints :
809 instance_params.additional_trust_leafs) {
810 const std::shared_ptr<const bssl::ParsedCertificate>& cert =
811 cert_with_possible_constraints.certificate;
812 if (!additional_trust_store_.Contains(cert.get())) {
813 if (!cert_with_possible_constraints.permitted_dns_names.empty() ||
814 !cert_with_possible_constraints.permitted_cidrs.empty()) {
815 additional_constraints_.push_back(cert_with_possible_constraints);
816 }
817
818 bssl::CertErrors parsing_errors;
819 additional_trust_store_.AddCertificate(cert, leaf_trust);
820 net_log.AddEvent(NetLogEventType::CERT_VERIFY_PROC_ADDITIONAL_CERT, [&] {
821 return NetLogAdditionalCert(cert->cert_buffer(), leaf_trust,
822 parsing_errors);
823 });
824 }
825 }
826
827 bssl::CertificateTrust anchor_leaf_trust =
828 bssl::CertificateTrust::ForTrustAnchorOrLeaf()
829 .WithEnforceAnchorConstraints()
830 .WithEnforceAnchorExpiry();
831
832 for (const auto& cert_with_possible_constraints :
833 instance_params.additional_trust_anchors_and_leafs) {
834 const std::shared_ptr<const bssl::ParsedCertificate>& cert =
835 cert_with_possible_constraints.certificate;
836 if (!additional_trust_store_.Contains(cert.get())) {
837 if (!cert_with_possible_constraints.permitted_dns_names.empty() ||
838 !cert_with_possible_constraints.permitted_cidrs.empty()) {
839 additional_constraints_.push_back(cert_with_possible_constraints);
840 }
841
842 bssl::CertErrors parsing_errors;
843 additional_trust_store_.AddCertificate(cert, anchor_leaf_trust);
844 net_log.AddEvent(NetLogEventType::CERT_VERIFY_PROC_ADDITIONAL_CERT, [&] {
845 return NetLogAdditionalCert(cert->cert_buffer(), anchor_leaf_trust,
846 parsing_errors);
847 });
848 }
849 }
850
851 for (const auto& cert :
852 instance_params.additional_trust_anchors_with_enforced_constraints) {
853 bssl::CertErrors parsing_errors;
854 if (!additional_trust_store_.Contains(cert.get())) {
855 additional_trust_store_.AddCertificate(cert, anchor_trust_enforcement);
856 net_log.AddEvent(NetLogEventType::CERT_VERIFY_PROC_ADDITIONAL_CERT, [&] {
857 return NetLogAdditionalCert(cert->cert_buffer(),
858 anchor_trust_enforcement, parsing_errors);
859 });
860 }
861 }
862
863 for (const auto& cert : instance_params.additional_trust_anchors) {
864 bssl::CertErrors parsing_errors;
865 // Only add if it wasn't already present in `additional_trust_store_`. This
866 // is for two reasons:
867 // (1) TrustStoreInMemory doesn't expect to contain duplicates
868 // (2) If the same anchor is added with enforced constraints, that takes
869 // precedence.
870 if (!additional_trust_store_.Contains(cert.get())) {
871 additional_trust_store_.AddTrustAnchor(cert);
872 }
873 net_log.AddEvent(NetLogEventType::CERT_VERIFY_PROC_ADDITIONAL_CERT, [&] {
874 return NetLogAdditionalCert(cert->cert_buffer(),
875 bssl::CertificateTrust::ForTrustAnchor(),
876 parsing_errors);
877 });
878 }
879
880 for (const auto& cert : instance_params.additional_untrusted_authorities) {
881 bssl::CertErrors parsing_errors;
882 // Only add the untrusted cert if it isn't already present in
883 // `additional_trust_store_`. If the same cert was already added as a
884 // trust anchor then adding it again as an untrusted cert can lead to it
885 // not being treated as a trust anchor since TrustStoreInMemory doesn't
886 // expect to contain duplicates.
887 if (!additional_trust_store_.Contains(cert.get())) {
888 additional_trust_store_.AddCertificateWithUnspecifiedTrust(cert);
889 }
890 net_log.AddEvent(NetLogEventType::CERT_VERIFY_PROC_ADDITIONAL_CERT, [&] {
891 return NetLogAdditionalCert(cert->cert_buffer(),
892 bssl::CertificateTrust::ForUnspecified(),
893 parsing_errors);
894 });
895 }
896
897 net_log.EndEvent(NetLogEventType::CERT_VERIFY_PROC_CREATED);
898 }
899
900 CertVerifyProcBuiltin::~CertVerifyProcBuiltin() = default;
901
AddIntermediatesToIssuerSource(X509Certificate * x509_cert,bssl::CertIssuerSourceStatic * intermediates,const NetLogWithSource & net_log)902 void AddIntermediatesToIssuerSource(X509Certificate* x509_cert,
903 bssl::CertIssuerSourceStatic* intermediates,
904 const NetLogWithSource& net_log) {
905 for (const auto& intermediate : x509_cert->intermediate_buffers()) {
906 bssl::CertErrors errors;
907 std::shared_ptr<const bssl::ParsedCertificate> cert =
908 ParseCertificateFromBuffer(intermediate.get(), &errors);
909 // TODO(crbug.com/40479281): this duplicates the logging of the input chain
910 // maybe should only log if there is a parse error/warning?
911 net_log.AddEvent(NetLogEventType::CERT_VERIFY_PROC_INPUT_CERT, [&] {
912 return NetLogCertParams(intermediate.get(), errors);
913 });
914 if (cert) {
915 intermediates->AddCert(std::move(cert));
916 }
917 }
918 }
919
920 // Appends the SHA256 hashes of |spki_bytes| to |*hashes|.
921 // TODO(eroman): Hashes are also calculated at other times (such as when
922 // checking CRLSet). Consider caching to avoid recalculating (say
923 // in the delegate's PathInfo).
AppendPublicKeyHashes(const bssl::der::Input & spki_bytes,HashValueVector * hashes)924 void AppendPublicKeyHashes(const bssl::der::Input& spki_bytes,
925 HashValueVector* hashes) {
926 HashValue sha256(HASH_VALUE_SHA256);
927 crypto::SHA256HashString(spki_bytes.AsStringView(), sha256.data(),
928 crypto::kSHA256Length);
929 hashes->push_back(sha256);
930 }
931
932 // Appends the SubjectPublicKeyInfo hashes for all certificates in
933 // |path| to |*hashes|.
AppendPublicKeyHashes(const bssl::CertPathBuilderResultPath & path,HashValueVector * hashes)934 void AppendPublicKeyHashes(const bssl::CertPathBuilderResultPath& path,
935 HashValueVector* hashes) {
936 for (const std::shared_ptr<const bssl::ParsedCertificate>& cert :
937 path.certs) {
938 AppendPublicKeyHashes(cert->tbs().spki_tlv, hashes);
939 }
940 }
941
942 // Sets the bits on |cert_status| for all the errors present in |errors| (the
943 // errors for a particular path).
MapPathBuilderErrorsToCertStatus(const bssl::CertPathErrors & errors,CertStatus * cert_status)944 void MapPathBuilderErrorsToCertStatus(const bssl::CertPathErrors& errors,
945 CertStatus* cert_status) {
946 // If there were no errors, nothing to do.
947 if (!errors.ContainsHighSeverityErrors())
948 return;
949
950 if (errors.ContainsError(bssl::cert_errors::kCertificateRevoked)) {
951 *cert_status |= CERT_STATUS_REVOKED;
952 }
953
954 if (errors.ContainsError(bssl::cert_errors::kNoRevocationMechanism)) {
955 *cert_status |= CERT_STATUS_NO_REVOCATION_MECHANISM;
956 }
957
958 if (errors.ContainsError(bssl::cert_errors::kUnableToCheckRevocation)) {
959 *cert_status |= CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
960 }
961
962 if (errors.ContainsError(bssl::cert_errors::kUnacceptablePublicKey)) {
963 *cert_status |= CERT_STATUS_WEAK_KEY;
964 }
965
966 if (errors.ContainsError(bssl::cert_errors::kValidityFailedNotAfter) ||
967 errors.ContainsError(bssl::cert_errors::kValidityFailedNotBefore)) {
968 *cert_status |= CERT_STATUS_DATE_INVALID;
969 }
970
971 if (errors.ContainsError(bssl::cert_errors::kDistrustedByTrustStore) ||
972 errors.ContainsError(bssl::cert_errors::kVerifySignedDataFailed) ||
973 errors.ContainsError(bssl::cert_errors::kNoIssuersFound) ||
974 errors.ContainsError(bssl::cert_errors::kSubjectDoesNotMatchIssuer) ||
975 errors.ContainsError(bssl::cert_errors::kDeadlineExceeded) ||
976 errors.ContainsError(bssl::cert_errors::kIterationLimitExceeded) ||
977 errors.ContainsError(kChromeRootConstraintsFailed)) {
978 *cert_status |= CERT_STATUS_AUTHORITY_INVALID;
979 }
980
981 // IMPORTANT: If the path was invalid for a reason that was not
982 // explicity checked above, set a general error. This is important as
983 // |cert_status| is what ultimately indicates whether verification was
984 // successful or not (absence of errors implies success).
985 if (!IsCertStatusError(*cert_status))
986 *cert_status |= CERT_STATUS_INVALID;
987 }
988
989 // Creates a X509Certificate (chain) to return as the verified result.
990 //
991 // * |target_cert|: The original X509Certificate that was passed in to
992 // VerifyInternal()
993 // * |path|: The result (possibly failed) from path building.
CreateVerifiedCertChain(X509Certificate * target_cert,const bssl::CertPathBuilderResultPath & path)994 scoped_refptr<X509Certificate> CreateVerifiedCertChain(
995 X509Certificate* target_cert,
996 const bssl::CertPathBuilderResultPath& path) {
997 std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
998
999 // Skip the first certificate in the path as that is the target certificate
1000 for (size_t i = 1; i < path.certs.size(); ++i) {
1001 intermediates.push_back(bssl::UpRef(path.certs[i]->cert_buffer()));
1002 }
1003
1004 scoped_refptr<X509Certificate> result =
1005 target_cert->CloneWithDifferentIntermediates(std::move(intermediates));
1006 DCHECK(result);
1007
1008 return result;
1009 }
1010
1011 // Describes the parameters for a single path building attempt. Path building
1012 // may be re-tried with different parameters for EV and for accepting SHA1
1013 // certificates.
1014 struct BuildPathAttempt {
BuildPathAttemptnet::__anonb619077d0111::BuildPathAttempt1015 BuildPathAttempt(VerificationType verification_type,
1016 bssl::SimplePathBuilderDelegate::DigestPolicy digest_policy,
1017 bool use_system_time)
1018 : verification_type(verification_type),
1019 digest_policy(digest_policy),
1020 use_system_time(use_system_time) {}
1021
BuildPathAttemptnet::__anonb619077d0111::BuildPathAttempt1022 BuildPathAttempt(VerificationType verification_type, bool use_system_time)
1023 : BuildPathAttempt(verification_type,
1024 bssl::SimplePathBuilderDelegate::DigestPolicy::kStrong,
1025 use_system_time) {}
1026
1027 VerificationType verification_type;
1028 bssl::SimplePathBuilderDelegate::DigestPolicy digest_policy;
1029 bool use_system_time;
1030 };
1031
TryBuildPath(const std::shared_ptr<const bssl::ParsedCertificate> & target,bssl::CertIssuerSourceStatic * intermediates,CertVerifyProcTrustStore * trust_store,const std::vector<net::CertVerifyProc::CertificateWithConstraints> & additional_constraints,const bssl::der::GeneralizedTime & der_verification_time,base::Time current_time,base::TimeTicks deadline,VerificationType verification_type,bssl::SimplePathBuilderDelegate::DigestPolicy digest_policy,int flags,std::string_view ocsp_response,std::string_view sct_list,const CRLSet * crl_set,CTVerifier * ct_verifier,const CTPolicyEnforcer * ct_policy_enforcer,CertNetFetcher * net_fetcher,const EVRootCAMetadata * ev_metadata,bool * checked_revocation,const NetLogWithSource & net_log)1032 bssl::CertPathBuilder::Result TryBuildPath(
1033 const std::shared_ptr<const bssl::ParsedCertificate>& target,
1034 bssl::CertIssuerSourceStatic* intermediates,
1035 CertVerifyProcTrustStore* trust_store,
1036 const std::vector<net::CertVerifyProc::CertificateWithConstraints>&
1037 additional_constraints,
1038 const bssl::der::GeneralizedTime& der_verification_time,
1039 base::Time current_time,
1040 base::TimeTicks deadline,
1041 VerificationType verification_type,
1042 bssl::SimplePathBuilderDelegate::DigestPolicy digest_policy,
1043 int flags,
1044 std::string_view ocsp_response,
1045 std::string_view sct_list,
1046 const CRLSet* crl_set,
1047 CTVerifier* ct_verifier,
1048 const CTPolicyEnforcer* ct_policy_enforcer,
1049 CertNetFetcher* net_fetcher,
1050 const EVRootCAMetadata* ev_metadata,
1051 bool* checked_revocation,
1052 const NetLogWithSource& net_log) {
1053 // Path building will require candidate paths to conform to at least one of
1054 // the policies in |user_initial_policy_set|.
1055 std::set<bssl::der::Input> user_initial_policy_set;
1056
1057 if (verification_type == VerificationType::kEV) {
1058 GetEVPolicyOids(ev_metadata, target.get(), &user_initial_policy_set);
1059 // TODO(crbug.com/40479281): netlog user_initial_policy_set.
1060 } else {
1061 user_initial_policy_set = {bssl::der::Input(bssl::kAnyPolicyOid)};
1062 }
1063
1064 PathBuilderDelegateImpl path_builder_delegate(
1065 crl_set, ct_verifier, ct_policy_enforcer, net_fetcher, verification_type,
1066 digest_policy, flags, trust_store, additional_constraints, ocsp_response,
1067 sct_list, ev_metadata, deadline, current_time, checked_revocation,
1068 net_log);
1069
1070 std::optional<CertIssuerSourceAia> aia_cert_issuer_source;
1071
1072 // Initialize the path builder.
1073 bssl::CertPathBuilder path_builder(
1074 target, trust_store->trust_store(), &path_builder_delegate,
1075 der_verification_time, bssl::KeyPurpose::SERVER_AUTH,
1076 bssl::InitialExplicitPolicy::kFalse, user_initial_policy_set,
1077 bssl::InitialPolicyMappingInhibit::kFalse,
1078 bssl::InitialAnyPolicyInhibit::kFalse);
1079
1080 // Allow the path builder to discover the explicitly provided intermediates in
1081 // |input_cert|.
1082 path_builder.AddCertIssuerSource(intermediates);
1083
1084 // Allow the path builder to discover intermediates through AIA fetching.
1085 // TODO(crbug.com/40479281): hook up netlog to AIA.
1086 if (!(flags & CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES)) {
1087 if (net_fetcher) {
1088 aia_cert_issuer_source.emplace(net_fetcher);
1089 path_builder.AddCertIssuerSource(&aia_cert_issuer_source.value());
1090 } else {
1091 VLOG(1) << "No net_fetcher for performing AIA chasing.";
1092 }
1093 }
1094
1095 path_builder.SetIterationLimit(kPathBuilderIterationLimit);
1096
1097 return path_builder.Run();
1098 }
1099
AssignVerifyResult(X509Certificate * input_cert,const std::string & hostname,bssl::CertPathBuilder::Result & result,VerificationType verification_type,bool checked_revocation_for_some_path,CertVerifyProcTrustStore * trust_store,CertVerifyResult * verify_result)1100 int AssignVerifyResult(X509Certificate* input_cert,
1101 const std::string& hostname,
1102 bssl::CertPathBuilder::Result& result,
1103 VerificationType verification_type,
1104 bool checked_revocation_for_some_path,
1105 CertVerifyProcTrustStore* trust_store,
1106 CertVerifyResult* verify_result) {
1107 const bssl::CertPathBuilderResultPath* best_path_possibly_invalid =
1108 result.GetBestPathPossiblyInvalid();
1109
1110 if (!best_path_possibly_invalid) {
1111 // TODO(crbug.com/41267838): What errors to communicate? Maybe the path
1112 // builder should always return some partial path (even if just containing
1113 // the target), then there is a bssl::CertErrors to test.
1114 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID;
1115 return ERR_CERT_AUTHORITY_INVALID;
1116 }
1117
1118 const bssl::CertPathBuilderResultPath& partial_path =
1119 *best_path_possibly_invalid;
1120
1121 AppendPublicKeyHashes(partial_path, &verify_result->public_key_hashes);
1122
1123 bool path_is_valid = partial_path.IsValid();
1124
1125 const bssl::ParsedCertificate* trusted_cert = partial_path.GetTrustedCert();
1126 if (trusted_cert) {
1127 verify_result->is_issued_by_known_root =
1128 trust_store->IsKnownRoot(trusted_cert);
1129
1130 verify_result->is_issued_by_additional_trust_anchor =
1131 trust_store->IsAdditionalTrustAnchor(trusted_cert);
1132 }
1133
1134 if (path_is_valid && (verification_type == VerificationType::kEV)) {
1135 verify_result->cert_status |= CERT_STATUS_IS_EV;
1136 }
1137
1138 // TODO(eroman): Add documentation for the meaning of
1139 // CERT_STATUS_REV_CHECKING_ENABLED. Based on the current tests it appears to
1140 // mean whether revocation checking was attempted during path building,
1141 // although does not necessarily mean that revocation checking was done for
1142 // the final returned path.
1143 if (checked_revocation_for_some_path)
1144 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
1145
1146 verify_result->verified_cert =
1147 CreateVerifiedCertChain(input_cert, partial_path);
1148
1149 MapPathBuilderErrorsToCertStatus(partial_path.errors,
1150 &verify_result->cert_status);
1151
1152 // TODO(eroman): Is it possible that IsValid() fails but no errors were set in
1153 // partial_path.errors?
1154 CHECK(path_is_valid || IsCertStatusError(verify_result->cert_status));
1155
1156 if (!path_is_valid) {
1157 VLOG(1) << "CertVerifyProcBuiltin for " << hostname << " failed:\n"
1158 << partial_path.errors.ToDebugString(partial_path.certs);
1159 }
1160
1161 const PathBuilderDelegateDataImpl* delegate_data =
1162 PathBuilderDelegateDataImpl::Get(partial_path);
1163 if (delegate_data) {
1164 verify_result->ocsp_result = delegate_data->stapled_ocsp_verify_result;
1165 verify_result->scts = std::move(delegate_data->scts);
1166 verify_result->policy_compliance = delegate_data->ct_policy_compliance;
1167 }
1168
1169 return IsCertStatusError(verify_result->cert_status)
1170 ? MapCertStatusToNetError(verify_result->cert_status)
1171 : OK;
1172 }
1173
1174 // Returns true if retrying path building with a less stringent signature
1175 // algorithm *might* successfully build a path, based on the earlier failed
1176 // |result|.
1177 //
1178 // This implementation is simplistic, and looks only for the presence of the
1179 // kUnacceptableSignatureAlgorithm error somewhere among the built paths.
CanTryAgainWithWeakerDigestPolicy(const bssl::CertPathBuilder::Result & result)1180 bool CanTryAgainWithWeakerDigestPolicy(
1181 const bssl::CertPathBuilder::Result& result) {
1182 return result.AnyPathContainsError(
1183 bssl::cert_errors::kUnacceptableSignatureAlgorithm);
1184 }
1185
1186 // Returns true if retrying with the system time as the verification time might
1187 // successfully build a path, based on the earlier failed |result|.
CanTryAgainWithSystemTime(const bssl::CertPathBuilder::Result & result)1188 bool CanTryAgainWithSystemTime(const bssl::CertPathBuilder::Result& result) {
1189 // TODO(crbug.com/363034686): Retries should also be triggered for CT
1190 // failures.
1191 return result.AnyPathContainsError(
1192 bssl::cert_errors::kValidityFailedNotAfter) ||
1193 result.AnyPathContainsError(
1194 bssl::cert_errors::kValidityFailedNotBefore) ||
1195 result.AnyPathContainsError(bssl::cert_errors::kCertificateRevoked) ||
1196 result.AnyPathContainsError(
1197 bssl::cert_errors::kUnableToCheckRevocation);
1198 }
1199
VerifyInternal(X509Certificate * input_cert,const std::string & hostname,const std::string & ocsp_response,const std::string & sct_list,int flags,CertVerifyResult * verify_result,const NetLogWithSource & net_log)1200 int CertVerifyProcBuiltin::VerifyInternal(X509Certificate* input_cert,
1201 const std::string& hostname,
1202 const std::string& ocsp_response,
1203 const std::string& sct_list,
1204 int flags,
1205 CertVerifyResult* verify_result,
1206 const NetLogWithSource& net_log) {
1207 base::TimeTicks deadline = base::TimeTicks::Now() + kMaxVerificationTime;
1208 bssl::der::GeneralizedTime der_verification_system_time;
1209 bssl::der::GeneralizedTime der_verification_custom_time;
1210 if (!EncodeTimeAsGeneralizedTime(base::Time::Now(),
1211 &der_verification_system_time)) {
1212 // This shouldn't be possible.
1213 // We don't really have a good error code for this type of error.
1214 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID;
1215 return ERR_CERT_AUTHORITY_INVALID;
1216 }
1217 bool custom_time_available = false;
1218 base::Time custom_time;
1219 if (time_tracker_.has_value()) {
1220 custom_time_available = time_tracker_->GetTime(
1221 base::Time::Now(), base::TimeTicks::Now(), &custom_time, nullptr);
1222 if (custom_time_available &&
1223 !EncodeTimeAsGeneralizedTime(custom_time,
1224 &der_verification_custom_time)) {
1225 // This shouldn't be possible, but if it somehow happens, just use system
1226 // time.
1227 custom_time_available = false;
1228 }
1229 }
1230 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
1231 int64_t chrome_root_store_version =
1232 system_trust_store_->chrome_root_store_version();
1233 if (chrome_root_store_version != 0) {
1234 net_log.AddEvent(
1235 NetLogEventType::CERT_VERIFY_PROC_CHROME_ROOT_STORE_VERSION, [&] {
1236 return NetLogChromeRootStoreVersion(chrome_root_store_version);
1237 });
1238 }
1239 #endif
1240
1241 // TODO(crbug.com/40928765): Netlog extra configuration information stored
1242 // inside CertVerifyProcBuiltin (e.g. certs in additional_trust_store and
1243 // system trust store)
1244
1245 // Parse the target certificate.
1246 std::shared_ptr<const bssl::ParsedCertificate> target;
1247 {
1248 bssl::CertErrors parsing_errors;
1249 target =
1250 ParseCertificateFromBuffer(input_cert->cert_buffer(), &parsing_errors);
1251 // TODO(crbug.com/40479281): this duplicates the logging of the input chain
1252 // maybe should only log if there is a parse error/warning?
1253 net_log.AddEvent(NetLogEventType::CERT_VERIFY_PROC_TARGET_CERT, [&] {
1254 return NetLogCertParams(input_cert->cert_buffer(), parsing_errors);
1255 });
1256 if (!target) {
1257 verify_result->cert_status |= CERT_STATUS_INVALID;
1258 return ERR_CERT_INVALID;
1259 }
1260 }
1261
1262 // Parse the provided intermediates.
1263 bssl::CertIssuerSourceStatic intermediates;
1264 AddIntermediatesToIssuerSource(input_cert, &intermediates, net_log);
1265
1266 CertVerifyProcTrustStore trust_store(system_trust_store_.get(),
1267 &additional_trust_store_);
1268
1269 // Get the global dependencies.
1270 const EVRootCAMetadata* ev_metadata = EVRootCAMetadata::GetInstance();
1271
1272 // This boolean tracks whether online revocation checking was performed for
1273 // *any* of the built paths, and not just the final path returned (used for
1274 // setting output flag CERT_STATUS_REV_CHECKING_ENABLED).
1275 bool checked_revocation_for_some_path = false;
1276
1277 // Run path building with the different parameters (attempts) until a valid
1278 // path is found. Earlier successful attempts have priority over later
1279 // attempts.
1280 //
1281 // Attempts are enqueued into |attempts| and drained in FIFO order.
1282 std::vector<BuildPathAttempt> attempts;
1283
1284 // First try EV validation. Can skip this if the leaf certificate has no
1285 // chance of verifying as EV (lacks an EV policy).
1286 if (IsEVCandidate(ev_metadata, target.get()))
1287 attempts.emplace_back(VerificationType::kEV, !custom_time_available);
1288
1289 // Next try DV validation.
1290 attempts.emplace_back(VerificationType::kDV, !custom_time_available);
1291
1292 bssl::CertPathBuilder::Result result;
1293 VerificationType verification_type = VerificationType::kDV;
1294
1295 // Iterate over |attempts| until there are none left to try, or an attempt
1296 // succeeded.
1297 for (size_t cur_attempt_index = 0; cur_attempt_index < attempts.size();
1298 ++cur_attempt_index) {
1299 const auto& cur_attempt = attempts[cur_attempt_index];
1300 verification_type = cur_attempt.verification_type;
1301 net_log.BeginEvent(
1302 NetLogEventType::CERT_VERIFY_PROC_PATH_BUILD_ATTEMPT, [&] {
1303 base::Value::Dict results;
1304 if (verification_type == VerificationType::kEV)
1305 results.Set("is_ev_attempt", true);
1306 results.Set("is_network_time_attempt", !cur_attempt.use_system_time);
1307 if (!cur_attempt.use_system_time) {
1308 results.Set(
1309 "network_time_value",
1310 NetLogNumberValue(custom_time.InMillisecondsSinceUnixEpoch()));
1311 }
1312 results.Set("digest_policy",
1313 static_cast<int>(cur_attempt.digest_policy));
1314 return results;
1315 });
1316
1317 // If a previous attempt used up most/all of the deadline, extend the
1318 // deadline a little bit to give this verification attempt a chance at
1319 // success.
1320 deadline = std::max(
1321 deadline, base::TimeTicks::Now() + kPerAttemptMinVerificationTimeLimit);
1322
1323 // Run the attempt through the path builder.
1324 result = TryBuildPath(
1325 target, &intermediates, &trust_store, additional_constraints_,
1326 cur_attempt.use_system_time ? der_verification_system_time
1327 : der_verification_custom_time,
1328 cur_attempt.use_system_time ? base::Time::Now() : custom_time, deadline,
1329 cur_attempt.verification_type, cur_attempt.digest_policy, flags,
1330 ocsp_response, sct_list, crl_set(), ct_verifier_.get(),
1331 ct_policy_enforcer_.get(), net_fetcher_.get(), ev_metadata,
1332 &checked_revocation_for_some_path, net_log);
1333
1334 net_log.EndEvent(NetLogEventType::CERT_VERIFY_PROC_PATH_BUILD_ATTEMPT,
1335 [&] { return NetLogPathBuilderResult(result); });
1336
1337 if (result.HasValidPath())
1338 break;
1339
1340 if (result.exceeded_deadline) {
1341 // Stop immediately if an attempt exceeds the deadline.
1342 break;
1343 }
1344
1345 if (!cur_attempt.use_system_time && CanTryAgainWithSystemTime(result)) {
1346 BuildPathAttempt system_time_attempt = cur_attempt;
1347 system_time_attempt.use_system_time = true;
1348 attempts.push_back(system_time_attempt);
1349 } else if (cur_attempt.digest_policy ==
1350 bssl::SimplePathBuilderDelegate::DigestPolicy::kStrong &&
1351 CanTryAgainWithWeakerDigestPolicy(result)) {
1352 // If this path building attempt (may have) failed due to the chain using
1353 // a
1354 // weak signature algorithm, enqueue a similar attempt but with weaker
1355 // signature algorithms (SHA1) permitted.
1356 //
1357 // This fallback is necessary because the CertVerifyProc layer may decide
1358 // to allow SHA1 based on its own policy, so path building should return
1359 // possibly weak chains too.
1360 //
1361 // TODO(eroman): Would be better for the SHA1 policy to be part of the
1362 // delegate instead so it can interact with path building.
1363 BuildPathAttempt sha1_fallback_attempt = cur_attempt;
1364 sha1_fallback_attempt.digest_policy =
1365 bssl::SimplePathBuilderDelegate::DigestPolicy::kWeakAllowSha1;
1366 attempts.push_back(sha1_fallback_attempt);
1367 }
1368 }
1369
1370 // Write the results to |*verify_result|.
1371 int error = AssignVerifyResult(
1372 input_cert, hostname, result, verification_type,
1373 checked_revocation_for_some_path, &trust_store, verify_result);
1374 if (error == OK) {
1375 LogNameNormalizationMetrics(".Builtin", verify_result->verified_cert.get(),
1376 verify_result->is_issued_by_known_root);
1377 }
1378 return error;
1379 }
1380
1381 } // namespace
1382
CreateCertVerifyProcBuiltin(scoped_refptr<CertNetFetcher> net_fetcher,scoped_refptr<CRLSet> crl_set,std::unique_ptr<CTVerifier> ct_verifier,scoped_refptr<CTPolicyEnforcer> ct_policy_enforcer,std::unique_ptr<SystemTrustStore> system_trust_store,const CertVerifyProc::InstanceParams & instance_params,std::optional<network_time::TimeTracker> time_tracker)1383 scoped_refptr<CertVerifyProc> CreateCertVerifyProcBuiltin(
1384 scoped_refptr<CertNetFetcher> net_fetcher,
1385 scoped_refptr<CRLSet> crl_set,
1386 std::unique_ptr<CTVerifier> ct_verifier,
1387 scoped_refptr<CTPolicyEnforcer> ct_policy_enforcer,
1388 std::unique_ptr<SystemTrustStore> system_trust_store,
1389 const CertVerifyProc::InstanceParams& instance_params,
1390 std::optional<network_time::TimeTracker> time_tracker) {
1391 return base::MakeRefCounted<CertVerifyProcBuiltin>(
1392 std::move(net_fetcher), std::move(crl_set), std::move(ct_verifier),
1393 std::move(ct_policy_enforcer), std::move(system_trust_store),
1394 instance_params, std::move(time_tracker));
1395 }
1396
GetCertVerifyProcBuiltinTimeLimitForTesting()1397 base::TimeDelta GetCertVerifyProcBuiltinTimeLimitForTesting() {
1398 return kMaxVerificationTime;
1399 }
1400
1401 } // namespace net
1402