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 <string>
9 #include <vector>
10
11 #include "base/logging.h"
12 #include "base/memory/raw_ptr.h"
13 #include "base/metrics/histogram_functions.h"
14 #include "base/strings/string_piece.h"
15 #include "base/values.h"
16 #include "crypto/sha2.h"
17 #include "net/base/net_errors.h"
18 #include "net/cert/cert_net_fetcher.h"
19 #include "net/cert/cert_status_flags.h"
20 #include "net/cert/cert_verifier.h"
21 #include "net/cert/cert_verify_proc.h"
22 #include "net/cert/cert_verify_result.h"
23 #include "net/cert/ev_root_ca_metadata.h"
24 #include "net/cert/internal/cert_issuer_source_aia.h"
25 #include "net/cert/internal/revocation_checker.h"
26 #include "net/cert/internal/system_trust_store.h"
27 #include "net/cert/known_roots.h"
28 #include "net/cert/pki/cert_errors.h"
29 #include "net/cert/pki/cert_issuer_source_static.h"
30 #include "net/cert/pki/common_cert_errors.h"
31 #include "net/cert/pki/parsed_certificate.h"
32 #include "net/cert/pki/path_builder.h"
33 #include "net/cert/pki/simple_path_builder_delegate.h"
34 #include "net/cert/pki/trust_store_collection.h"
35 #include "net/cert/pki/trust_store_in_memory.h"
36 #include "net/cert/test_root_certs.h"
37 #include "net/cert/x509_certificate.h"
38 #include "net/cert/x509_util.h"
39 #include "net/der/encode_values.h"
40 #include "net/log/net_log_values.h"
41 #include "net/log/net_log_with_source.h"
42 #include "third_party/abseil-cpp/absl/types/optional.h"
43
44 namespace net {
45
46 namespace {
47
48 // Very conservative iteration count limit.
49 // TODO(https://crbug.com/634470): Make this smaller.
50 constexpr uint32_t kPathBuilderIterationLimit = 25000;
51
52 constexpr base::TimeDelta kMaxVerificationTime = base::Seconds(60);
53
54 constexpr base::TimeDelta kPerAttemptMinVerificationTimeLimit =
55 base::Seconds(5);
56
57 DEFINE_CERT_ERROR_ID(kPathLacksEVPolicy, "Path does not have an EV policy");
58
59 const void* const kResultDebugDataKey = &kResultDebugDataKey;
60
NetLogCertParams(const CRYPTO_BUFFER * cert_handle,const CertErrors & errors)61 base::Value::Dict NetLogCertParams(const CRYPTO_BUFFER* cert_handle,
62 const CertErrors& errors) {
63 base::Value::Dict results;
64
65 std::string pem_encoded;
66 if (X509Certificate::GetPEMEncodedFromDER(
67 x509_util::CryptoBufferAsStringPiece(cert_handle), &pem_encoded)) {
68 results.Set("certificate", pem_encoded);
69 }
70
71 std::string errors_string = errors.ToDebugString();
72 if (!errors_string.empty())
73 results.Set("errors", errors_string);
74
75 return results;
76 }
77
78 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
NetLogChromeRootStoreVersion(int64_t chrome_root_store_version)79 base::Value::Dict NetLogChromeRootStoreVersion(
80 int64_t chrome_root_store_version) {
81 base::Value::Dict results;
82 results.Set("version_major", NetLogNumberValue(chrome_root_store_version));
83 return results;
84 }
85 #endif
86
PEMCertValueList(const ParsedCertificateList & certs)87 base::Value::List PEMCertValueList(const ParsedCertificateList& certs) {
88 base::Value::List value;
89 for (const auto& cert : certs) {
90 std::string pem;
91 X509Certificate::GetPEMEncodedFromDER(cert->der_cert().AsStringView(),
92 &pem);
93 value.Append(std::move(pem));
94 }
95 return value;
96 }
97
NetLogPathBuilderResultPath(const CertPathBuilderResultPath & result_path)98 base::Value::Dict NetLogPathBuilderResultPath(
99 const CertPathBuilderResultPath& result_path) {
100 base::Value::Dict dict;
101 dict.Set("is_valid", result_path.IsValid());
102 dict.Set("last_cert_trust", result_path.last_cert_trust.ToDebugString());
103 dict.Set("certificates", PEMCertValueList(result_path.certs));
104 // TODO(crbug.com/634484): netlog user_constrained_policy_set.
105 std::string errors_string =
106 result_path.errors.ToDebugString(result_path.certs);
107 if (!errors_string.empty())
108 dict.Set("errors", errors_string);
109 return dict;
110 }
111
NetLogPathBuilderResult(const CertPathBuilder::Result & result)112 base::Value::Dict NetLogPathBuilderResult(
113 const CertPathBuilder::Result& result) {
114 base::Value::Dict dict;
115 // TODO(crbug.com/634484): include debug data (or just have things netlog it
116 // directly).
117 dict.Set("has_valid_path", result.HasValidPath());
118 dict.Set("best_result_index", static_cast<int>(result.best_result_index));
119 if (result.exceeded_iteration_limit)
120 dict.Set("exceeded_iteration_limit", true);
121 if (result.exceeded_deadline)
122 dict.Set("exceeded_deadline", true);
123 return dict;
124 }
125
NoRevocationChecking()126 RevocationPolicy NoRevocationChecking() {
127 RevocationPolicy policy;
128 policy.check_revocation = false;
129 policy.networking_allowed = false;
130 policy.crl_allowed = false;
131 policy.allow_missing_info = true;
132 policy.allow_unable_to_check = true;
133 policy.enforce_baseline_requirements = false;
134 return policy;
135 }
136
137 // Gets the set of policy OIDs in |cert| that are recognized as EV OIDs for some
138 // root.
GetEVPolicyOids(const EVRootCAMetadata * ev_metadata,const ParsedCertificate * cert,std::set<der::Input> * oids)139 void GetEVPolicyOids(const EVRootCAMetadata* ev_metadata,
140 const ParsedCertificate* cert,
141 std::set<der::Input>* oids) {
142 oids->clear();
143
144 if (!cert->has_policy_oids())
145 return;
146
147 for (const der::Input& oid : cert->policy_oids()) {
148 if (ev_metadata->IsEVPolicyOID(oid)) {
149 oids->insert(oid);
150 }
151 }
152 }
153
154 // Returns true if |cert| could be an EV certificate, based on its policies
155 // extension. A return of false means it definitely is not an EV certificate,
156 // whereas a return of true means it could be EV.
IsEVCandidate(const EVRootCAMetadata * ev_metadata,const ParsedCertificate * cert)157 bool IsEVCandidate(const EVRootCAMetadata* ev_metadata,
158 const ParsedCertificate* cert) {
159 std::set<der::Input> oids;
160 GetEVPolicyOids(ev_metadata, cert, &oids);
161 return !oids.empty();
162 }
163
164 // CertVerifyProcTrustStore wraps a SystemTrustStore with additional trust
165 // anchors and TestRootCerts.
166 class CertVerifyProcTrustStore {
167 public:
168 // |system_trust_store| must outlive this object.
CertVerifyProcTrustStore(SystemTrustStore * system_trust_store)169 explicit CertVerifyProcTrustStore(SystemTrustStore* system_trust_store)
170 : system_trust_store_(system_trust_store) {
171 trust_store_.AddTrustStore(&additional_trust_store_);
172 trust_store_.AddTrustStore(system_trust_store_->GetTrustStore());
173 // When running in test mode, also layer in the test-only root certificates.
174 //
175 // Note that this integration requires TestRootCerts::HasInstance() to be
176 // true by the time CertVerifyProcTrustStore is created - a limitation which
177 // is acceptable for the test-only code that consumes this.
178 if (TestRootCerts::HasInstance()) {
179 trust_store_.AddTrustStore(
180 TestRootCerts::GetInstance()->test_trust_store());
181 }
182 }
183
trust_store()184 TrustStore* trust_store() { return &trust_store_; }
185
AddTrustAnchor(std::shared_ptr<const ParsedCertificate> cert)186 void AddTrustAnchor(std::shared_ptr<const ParsedCertificate> cert) {
187 additional_trust_store_.AddTrustAnchor(std::move(cert));
188 }
189
IsKnownRoot(const ParsedCertificate * trust_anchor) const190 bool IsKnownRoot(const ParsedCertificate* trust_anchor) const {
191 if (TestRootCerts::HasInstance() &&
192 TestRootCerts::GetInstance()->IsKnownRoot(
193 trust_anchor->der_cert().AsSpan())) {
194 return true;
195 }
196 return system_trust_store_->IsKnownRoot(trust_anchor);
197 }
198
IsAdditionalTrustAnchor(const ParsedCertificate * trust_anchor) const199 bool IsAdditionalTrustAnchor(const ParsedCertificate* trust_anchor) const {
200 return additional_trust_store_.Contains(trust_anchor);
201 }
202
203 private:
204 raw_ptr<SystemTrustStore> system_trust_store_;
205 TrustStoreInMemory additional_trust_store_;
206 TrustStoreCollection trust_store_;
207 };
208
209 // Enum for whether path building is attempting to verify a certificate as EV or
210 // as DV.
211 enum class VerificationType {
212 kEV, // Extended Validation
213 kDV, // Domain Validation
214 };
215
216 class PathBuilderDelegateDataImpl : public CertPathBuilderDelegateData {
217 public:
218 ~PathBuilderDelegateDataImpl() override = default;
219
Get(const CertPathBuilderResultPath & path)220 static const PathBuilderDelegateDataImpl* Get(
221 const CertPathBuilderResultPath& path) {
222 return static_cast<PathBuilderDelegateDataImpl*>(path.delegate_data.get());
223 }
224
GetOrCreate(CertPathBuilderResultPath * path)225 static PathBuilderDelegateDataImpl* GetOrCreate(
226 CertPathBuilderResultPath* path) {
227 if (!path->delegate_data)
228 path->delegate_data = std::make_unique<PathBuilderDelegateDataImpl>();
229 return static_cast<PathBuilderDelegateDataImpl*>(path->delegate_data.get());
230 }
231
232 OCSPVerifyResult stapled_ocsp_verify_result;
233 };
234
235 // TODO(eroman): The path building code in this file enforces its idea of weak
236 // keys, and signature algorithms, but separately cert_verify_proc.cc also
237 // checks the chains with its own policy. These policies must be aligned to
238 // give path building the best chance of finding a good path.
239 class PathBuilderDelegateImpl : public SimplePathBuilderDelegate {
240 public:
241 // Uses the default policy from SimplePathBuilderDelegate, which requires RSA
242 // keys to be at least 1024-bits large, and optionally accepts SHA1
243 // certificates.
PathBuilderDelegateImpl(const CRLSet * crl_set,CertNetFetcher * net_fetcher,VerificationType verification_type,SimplePathBuilderDelegate::DigestPolicy digest_policy,int flags,const CertVerifyProcTrustStore * trust_store,base::StringPiece stapled_leaf_ocsp_response,const EVRootCAMetadata * ev_metadata,bool * checked_revocation_for_some_path,base::TimeTicks deadline)244 PathBuilderDelegateImpl(const CRLSet* crl_set,
245 CertNetFetcher* net_fetcher,
246 VerificationType verification_type,
247 SimplePathBuilderDelegate::DigestPolicy digest_policy,
248 int flags,
249 const CertVerifyProcTrustStore* trust_store,
250 base::StringPiece stapled_leaf_ocsp_response,
251 const EVRootCAMetadata* ev_metadata,
252 bool* checked_revocation_for_some_path,
253 base::TimeTicks deadline)
254 : SimplePathBuilderDelegate(1024, digest_policy),
255 crl_set_(crl_set),
256 net_fetcher_(net_fetcher),
257 verification_type_(verification_type),
258 flags_(flags),
259 trust_store_(trust_store),
260 stapled_leaf_ocsp_response_(stapled_leaf_ocsp_response),
261 ev_metadata_(ev_metadata),
262 checked_revocation_for_some_path_(checked_revocation_for_some_path),
263 deadline_(deadline) {}
264
265 // This is called for each built chain, including ones which failed. It is
266 // responsible for adding errors to the built chain if it is not acceptable.
CheckPathAfterVerification(const CertPathBuilder & path_builder,CertPathBuilderResultPath * path)267 void CheckPathAfterVerification(const CertPathBuilder& path_builder,
268 CertPathBuilderResultPath* path) override {
269 // If the path is already invalid, don't check revocation status. The chain
270 // is expected to be valid when doing revocation checks (since for instance
271 // the correct issuer for a certificate may need to be known). Also if
272 // certificates are already expired, obtaining their revocation status may
273 // fail.
274 //
275 // TODO(eroman): When CertVerifyProcBuiltin fails to find a valid path,
276 // whatever (partial/incomplete) path it does return should
277 // minimally be checked with the CRLSet.
278 if (!path->IsValid())
279 return;
280
281 // If EV was requested the certificate must chain to a recognized EV root
282 // and have one of its recognized EV policy OIDs.
283 if (verification_type_ == VerificationType::kEV) {
284 if (!ConformsToEVPolicy(path)) {
285 path->errors.GetErrorsForCert(0)->AddError(kPathLacksEVPolicy);
286 return;
287 }
288 }
289
290 // Select an appropriate revocation policy for this chain based on the
291 // verifier flags and root.
292 RevocationPolicy policy = ChooseRevocationPolicy(path->certs);
293
294 // Check for revocations using the CRLSet.
295 switch (
296 CheckChainRevocationUsingCRLSet(crl_set_, path->certs, &path->errors)) {
297 case CRLSet::Result::REVOKED:
298 return;
299 case CRLSet::Result::GOOD:
300 break;
301 case CRLSet::Result::UNKNOWN:
302 // CRLSet was inconclusive.
303 break;
304 }
305
306 if (policy.check_revocation)
307 *checked_revocation_for_some_path_ = true;
308
309 // Check the revocation status for each certificate in the chain according
310 // to |policy|. Depending on the policy, errors will be added to the
311 // respective certificates, so |errors->ContainsHighSeverityErrors()| will
312 // reflect the revocation status of the chain after this call.
313 CheckValidatedChainRevocation(
314 path->certs, policy, deadline_, stapled_leaf_ocsp_response_,
315 net_fetcher_, &path->errors,
316 &PathBuilderDelegateDataImpl::GetOrCreate(path)
317 ->stapled_ocsp_verify_result);
318 }
319
320 private:
321 // Selects a revocation policy based on the CertVerifier flags and the given
322 // certificate chain.
ChooseRevocationPolicy(const ParsedCertificateList & certs)323 RevocationPolicy ChooseRevocationPolicy(const ParsedCertificateList& certs) {
324 if (flags_ & CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES) {
325 // In theory when network fetches are disabled but revocation is enabled
326 // we could continue with networking_allowed=false (and
327 // VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS would also have to change
328 // allow_missing_info and allow_unable_to_check to true).
329 // That theoretically could allow still consulting any cached CRLs/etc.
330 // However in the way things are currently implemented in the builtin
331 // verifier there really is no point to bothering, just disable
332 // revocation checking if network fetches are disabled.
333 return NoRevocationChecking();
334 }
335
336 // Use hard-fail revocation checking for local trust anchors, if requested
337 // by the load flag and the chain uses a non-public root.
338 if ((flags_ & CertVerifyProc::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) &&
339 !certs.empty() && !trust_store_->IsKnownRoot(certs.back().get())) {
340 RevocationPolicy policy;
341 policy.check_revocation = true;
342 policy.networking_allowed = true;
343 policy.crl_allowed = true;
344 policy.allow_missing_info = false;
345 policy.allow_unable_to_check = false;
346 policy.enforce_baseline_requirements = false;
347 return policy;
348 }
349
350 // Use soft-fail revocation checking for VERIFY_REV_CHECKING_ENABLED.
351 if (flags_ & CertVerifyProc::VERIFY_REV_CHECKING_ENABLED) {
352 const bool is_known_root =
353 !certs.empty() && trust_store_->IsKnownRoot(certs.back().get());
354 RevocationPolicy policy;
355 policy.check_revocation = true;
356 policy.networking_allowed = true;
357 // Publicly trusted certs are required to have OCSP by the Baseline
358 // Requirements and CRLs can be quite large, so disable the fallback to
359 // CRLs for chains to known roots.
360 policy.crl_allowed = !is_known_root;
361 policy.allow_missing_info = true;
362 policy.allow_unable_to_check = true;
363 policy.enforce_baseline_requirements = is_known_root;
364 return policy;
365 }
366
367 return NoRevocationChecking();
368 }
369
370 // Returns true if |path| chains to an EV root, and the chain conforms to one
371 // of its EV policy OIDs. When building paths all candidate EV policy OIDs
372 // were requested, so it is just a matter of testing each of the policies the
373 // chain conforms to.
ConformsToEVPolicy(const CertPathBuilderResultPath * path)374 bool ConformsToEVPolicy(const CertPathBuilderResultPath* path) {
375 const ParsedCertificate* root = path->GetTrustedCert();
376 if (!root)
377 return false;
378
379 SHA256HashValue root_fingerprint;
380 crypto::SHA256HashString(root->der_cert().AsStringView(),
381 root_fingerprint.data,
382 sizeof(root_fingerprint.data));
383
384 for (const der::Input& oid : path->user_constrained_policy_set) {
385 if (ev_metadata_->HasEVPolicyOID(root_fingerprint, oid)) {
386 return true;
387 }
388 }
389
390 return false;
391 }
392
IsDeadlineExpired()393 bool IsDeadlineExpired() override {
394 return !deadline_.is_null() && base::TimeTicks::Now() > deadline_;
395 }
396
397 raw_ptr<const CRLSet> crl_set_;
398 raw_ptr<CertNetFetcher> net_fetcher_;
399 const VerificationType verification_type_;
400 const int flags_;
401 raw_ptr<const CertVerifyProcTrustStore> trust_store_;
402 const base::StringPiece stapled_leaf_ocsp_response_;
403 raw_ptr<const EVRootCAMetadata> ev_metadata_;
404 raw_ptr<bool> checked_revocation_for_some_path_;
405 base::TimeTicks deadline_;
406 };
407
408 class CertVerifyProcBuiltin : public CertVerifyProc {
409 public:
410 CertVerifyProcBuiltin(scoped_refptr<CertNetFetcher> net_fetcher,
411 scoped_refptr<CRLSet> crl_set,
412 std::unique_ptr<SystemTrustStore> system_trust_store);
413
414 bool SupportsAdditionalTrustAnchors() const override;
415
416 protected:
417 ~CertVerifyProcBuiltin() override;
418
419 private:
420 int VerifyInternal(X509Certificate* cert,
421 const std::string& hostname,
422 const std::string& ocsp_response,
423 const std::string& sct_list,
424 int flags,
425 const CertificateList& additional_trust_anchors,
426 CertVerifyResult* verify_result,
427 const NetLogWithSource& net_log) override;
428
429 const scoped_refptr<CertNetFetcher> net_fetcher_;
430 const std::unique_ptr<SystemTrustStore> system_trust_store_;
431 };
432
CertVerifyProcBuiltin(scoped_refptr<CertNetFetcher> net_fetcher,scoped_refptr<CRLSet> crl_set,std::unique_ptr<SystemTrustStore> system_trust_store)433 CertVerifyProcBuiltin::CertVerifyProcBuiltin(
434 scoped_refptr<CertNetFetcher> net_fetcher,
435 scoped_refptr<CRLSet> crl_set,
436 std::unique_ptr<SystemTrustStore> system_trust_store)
437 : CertVerifyProc(std::move(crl_set)),
438 net_fetcher_(std::move(net_fetcher)),
439 system_trust_store_(std::move(system_trust_store)) {
440 DCHECK(system_trust_store_);
441 }
442
443 CertVerifyProcBuiltin::~CertVerifyProcBuiltin() = default;
444
SupportsAdditionalTrustAnchors() const445 bool CertVerifyProcBuiltin::SupportsAdditionalTrustAnchors() const {
446 return true;
447 }
448
ParseCertificateFromBuffer(CRYPTO_BUFFER * cert_handle,CertErrors * errors)449 std::shared_ptr<const ParsedCertificate> ParseCertificateFromBuffer(
450 CRYPTO_BUFFER* cert_handle,
451 CertErrors* errors) {
452 return ParsedCertificate::Create(bssl::UpRef(cert_handle),
453 x509_util::DefaultParseCertificateOptions(),
454 errors);
455 }
456
AddIntermediatesToIssuerSource(X509Certificate * x509_cert,CertIssuerSourceStatic * intermediates,const NetLogWithSource & net_log)457 void AddIntermediatesToIssuerSource(X509Certificate* x509_cert,
458 CertIssuerSourceStatic* intermediates,
459 const NetLogWithSource& net_log) {
460 for (const auto& intermediate : x509_cert->intermediate_buffers()) {
461 CertErrors errors;
462 std::shared_ptr<const ParsedCertificate> cert =
463 ParseCertificateFromBuffer(intermediate.get(), &errors);
464 // TODO(crbug.com/634484): this duplicates the logging of the input chain
465 // maybe should only log if there is a parse error/warning?
466 net_log.AddEvent(NetLogEventType::CERT_VERIFY_PROC_INPUT_CERT, [&] {
467 return NetLogCertParams(intermediate.get(), errors);
468 });
469 if (cert)
470 intermediates->AddCert(std::move(cert));
471 }
472 }
473
474 // Appends the SHA256 hashes of |spki_bytes| to |*hashes|.
475 // TODO(eroman): Hashes are also calculated at other times (such as when
476 // checking CRLSet). Consider caching to avoid recalculating (say
477 // in the delegate's PathInfo).
AppendPublicKeyHashes(const der::Input & spki_bytes,HashValueVector * hashes)478 void AppendPublicKeyHashes(const der::Input& spki_bytes,
479 HashValueVector* hashes) {
480 HashValue sha256(HASH_VALUE_SHA256);
481 crypto::SHA256HashString(spki_bytes.AsStringView(), sha256.data(),
482 crypto::kSHA256Length);
483 hashes->push_back(sha256);
484 }
485
486 // Appends the SubjectPublicKeyInfo hashes for all certificates in
487 // |path| to |*hashes|.
AppendPublicKeyHashes(const CertPathBuilderResultPath & path,HashValueVector * hashes)488 void AppendPublicKeyHashes(const CertPathBuilderResultPath& path,
489 HashValueVector* hashes) {
490 for (const std::shared_ptr<const ParsedCertificate>& cert : path.certs)
491 AppendPublicKeyHashes(cert->tbs().spki_tlv, hashes);
492 }
493
494 // Sets the bits on |cert_status| for all the errors present in |errors| (the
495 // errors for a particular path).
MapPathBuilderErrorsToCertStatus(const CertPathErrors & errors,CertStatus * cert_status)496 void MapPathBuilderErrorsToCertStatus(const CertPathErrors& errors,
497 CertStatus* cert_status) {
498 // If there were no errors, nothing to do.
499 if (!errors.ContainsHighSeverityErrors())
500 return;
501
502 if (errors.ContainsError(cert_errors::kCertificateRevoked))
503 *cert_status |= CERT_STATUS_REVOKED;
504
505 if (errors.ContainsError(cert_errors::kNoRevocationMechanism))
506 *cert_status |= CERT_STATUS_NO_REVOCATION_MECHANISM;
507
508 if (errors.ContainsError(cert_errors::kUnableToCheckRevocation))
509 *cert_status |= CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
510
511 if (errors.ContainsError(cert_errors::kUnacceptablePublicKey))
512 *cert_status |= CERT_STATUS_WEAK_KEY;
513
514 if (errors.ContainsError(cert_errors::kValidityFailedNotAfter) ||
515 errors.ContainsError(cert_errors::kValidityFailedNotBefore)) {
516 *cert_status |= CERT_STATUS_DATE_INVALID;
517 }
518
519 if (errors.ContainsError(cert_errors::kDistrustedByTrustStore) ||
520 errors.ContainsError(cert_errors::kVerifySignedDataFailed) ||
521 errors.ContainsError(cert_errors::kNoIssuersFound) ||
522 errors.ContainsError(cert_errors::kSubjectDoesNotMatchIssuer) ||
523 errors.ContainsError(cert_errors::kDeadlineExceeded) ||
524 errors.ContainsError(cert_errors::kIterationLimitExceeded)) {
525 *cert_status |= CERT_STATUS_AUTHORITY_INVALID;
526 }
527
528 // IMPORTANT: If the path was invalid for a reason that was not
529 // explicity checked above, set a general error. This is important as
530 // |cert_status| is what ultimately indicates whether verification was
531 // successful or not (absence of errors implies success).
532 if (!IsCertStatusError(*cert_status))
533 *cert_status |= CERT_STATUS_INVALID;
534 }
535
536 // Creates a X509Certificate (chain) to return as the verified result.
537 //
538 // * |target_cert|: The original X509Certificate that was passed in to
539 // VerifyInternal()
540 // * |path|: The result (possibly failed) from path building.
CreateVerifiedCertChain(X509Certificate * target_cert,const CertPathBuilderResultPath & path)541 scoped_refptr<X509Certificate> CreateVerifiedCertChain(
542 X509Certificate* target_cert,
543 const CertPathBuilderResultPath& path) {
544 std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
545
546 // Skip the first certificate in the path as that is the target certificate
547 for (size_t i = 1; i < path.certs.size(); ++i) {
548 intermediates.push_back(bssl::UpRef(path.certs[i]->cert_buffer()));
549 }
550
551 scoped_refptr<X509Certificate> result = X509Certificate::CreateFromBuffer(
552 bssl::UpRef(target_cert->cert_buffer()), std::move(intermediates));
553 // |target_cert| was already successfully parsed, so this should never fail.
554 DCHECK(result);
555
556 return result;
557 }
558
559 // Describes the parameters for a single path building attempt. Path building
560 // may be re-tried with different parameters for EV and for accepting SHA1
561 // certificates.
562 struct BuildPathAttempt {
BuildPathAttemptnet::__anon870afda20111::BuildPathAttempt563 BuildPathAttempt(VerificationType verification_type,
564 SimplePathBuilderDelegate::DigestPolicy digest_policy)
565 : verification_type(verification_type), digest_policy(digest_policy) {}
566
BuildPathAttemptnet::__anon870afda20111::BuildPathAttempt567 explicit BuildPathAttempt(VerificationType verification_type)
568 : BuildPathAttempt(verification_type,
569 SimplePathBuilderDelegate::DigestPolicy::kStrong) {}
570
571 VerificationType verification_type;
572 SimplePathBuilderDelegate::DigestPolicy digest_policy;
573 };
574
TryBuildPath(const std::shared_ptr<const ParsedCertificate> & target,CertIssuerSourceStatic * intermediates,CertVerifyProcTrustStore * trust_store,const der::GeneralizedTime & der_verification_time,base::TimeTicks deadline,VerificationType verification_type,SimplePathBuilderDelegate::DigestPolicy digest_policy,int flags,const std::string & ocsp_response,const CRLSet * crl_set,CertNetFetcher * net_fetcher,const EVRootCAMetadata * ev_metadata,bool * checked_revocation)575 CertPathBuilder::Result TryBuildPath(
576 const std::shared_ptr<const ParsedCertificate>& target,
577 CertIssuerSourceStatic* intermediates,
578 CertVerifyProcTrustStore* trust_store,
579 const der::GeneralizedTime& der_verification_time,
580 base::TimeTicks deadline,
581 VerificationType verification_type,
582 SimplePathBuilderDelegate::DigestPolicy digest_policy,
583 int flags,
584 const std::string& ocsp_response,
585 const CRLSet* crl_set,
586 CertNetFetcher* net_fetcher,
587 const EVRootCAMetadata* ev_metadata,
588 bool* checked_revocation) {
589 // Path building will require candidate paths to conform to at least one of
590 // the policies in |user_initial_policy_set|.
591 std::set<der::Input> user_initial_policy_set;
592
593 if (verification_type == VerificationType::kEV) {
594 GetEVPolicyOids(ev_metadata, target.get(), &user_initial_policy_set);
595 // TODO(crbug.com/634484): netlog user_initial_policy_set.
596 } else {
597 user_initial_policy_set = {der::Input(kAnyPolicyOid)};
598 }
599
600 PathBuilderDelegateImpl path_builder_delegate(
601 crl_set, net_fetcher, verification_type, digest_policy, flags,
602 trust_store, ocsp_response, ev_metadata, checked_revocation, deadline);
603
604 absl::optional<CertIssuerSourceAia> aia_cert_issuer_source;
605
606 // Initialize the path builder.
607 CertPathBuilder path_builder(
608 target, trust_store->trust_store(), &path_builder_delegate,
609 der_verification_time, KeyPurpose::SERVER_AUTH,
610 InitialExplicitPolicy::kFalse, user_initial_policy_set,
611 InitialPolicyMappingInhibit::kFalse, InitialAnyPolicyInhibit::kFalse);
612
613 // Allow the path builder to discover the explicitly provided intermediates in
614 // |input_cert|.
615 path_builder.AddCertIssuerSource(intermediates);
616
617 // Allow the path builder to discover intermediates through AIA fetching.
618 // TODO(crbug.com/634484): hook up netlog to AIA.
619 if (!(flags & CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES)) {
620 if (net_fetcher) {
621 aia_cert_issuer_source.emplace(net_fetcher);
622 path_builder.AddCertIssuerSource(&aia_cert_issuer_source.value());
623 } else {
624 LOG(ERROR) << "No net_fetcher for performing AIA chasing.";
625 }
626 }
627
628 path_builder.SetIterationLimit(kPathBuilderIterationLimit);
629
630 return path_builder.Run();
631 }
632
AssignVerifyResult(X509Certificate * input_cert,const std::string & hostname,CertPathBuilder::Result & result,VerificationType verification_type,bool checked_revocation_for_some_path,CertVerifyProcTrustStore * trust_store,CertVerifyResult * verify_result)633 int AssignVerifyResult(X509Certificate* input_cert,
634 const std::string& hostname,
635 CertPathBuilder::Result& result,
636 VerificationType verification_type,
637 bool checked_revocation_for_some_path,
638 CertVerifyProcTrustStore* trust_store,
639 CertVerifyResult* verify_result) {
640 // Clone debug data from the CertPathBuilder::Result into CertVerifyResult.
641 verify_result->CloneDataFrom(result);
642
643 const CertPathBuilderResultPath* best_path_possibly_invalid =
644 result.GetBestPathPossiblyInvalid();
645
646 if (!best_path_possibly_invalid) {
647 // TODO(crbug.com/634443): What errors to communicate? Maybe the path
648 // builder should always return some partial path (even if just containing
649 // the target), then there is a CertErrors to test.
650 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID;
651 return ERR_CERT_AUTHORITY_INVALID;
652 }
653
654 const CertPathBuilderResultPath& partial_path = *best_path_possibly_invalid;
655
656 AppendPublicKeyHashes(partial_path, &verify_result->public_key_hashes);
657
658 for (auto it = verify_result->public_key_hashes.rbegin();
659 it != verify_result->public_key_hashes.rend() &&
660 !verify_result->is_issued_by_known_root;
661 ++it) {
662 verify_result->is_issued_by_known_root =
663 GetNetTrustAnchorHistogramIdForSPKI(*it) != 0;
664 }
665
666 bool path_is_valid = partial_path.IsValid();
667
668 const ParsedCertificate* trusted_cert = partial_path.GetTrustedCert();
669 if (trusted_cert) {
670 if (!verify_result->is_issued_by_known_root) {
671 verify_result->is_issued_by_known_root =
672 trust_store->IsKnownRoot(trusted_cert);
673 }
674
675 verify_result->is_issued_by_additional_trust_anchor =
676 trust_store->IsAdditionalTrustAnchor(trusted_cert);
677 }
678
679 if (path_is_valid && (verification_type == VerificationType::kEV)) {
680 verify_result->cert_status |= CERT_STATUS_IS_EV;
681 }
682
683 // TODO(eroman): Add documentation for the meaning of
684 // CERT_STATUS_REV_CHECKING_ENABLED. Based on the current tests it appears to
685 // mean whether revocation checking was attempted during path building,
686 // although does not necessarily mean that revocation checking was done for
687 // the final returned path.
688 if (checked_revocation_for_some_path)
689 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
690
691 verify_result->verified_cert =
692 CreateVerifiedCertChain(input_cert, partial_path);
693
694 MapPathBuilderErrorsToCertStatus(partial_path.errors,
695 &verify_result->cert_status);
696
697 // TODO(eroman): Is it possible that IsValid() fails but no errors were set in
698 // partial_path.errors?
699 CHECK(path_is_valid || IsCertStatusError(verify_result->cert_status));
700
701 if (!path_is_valid) {
702 LOG(ERROR) << "CertVerifyProcBuiltin for " << hostname << " failed:\n"
703 << partial_path.errors.ToDebugString(partial_path.certs);
704 }
705
706 const PathBuilderDelegateDataImpl* delegate_data =
707 PathBuilderDelegateDataImpl::Get(partial_path);
708 if (delegate_data)
709 verify_result->ocsp_result = delegate_data->stapled_ocsp_verify_result;
710
711 return IsCertStatusError(verify_result->cert_status)
712 ? MapCertStatusToNetError(verify_result->cert_status)
713 : OK;
714 }
715
716 // Returns true if retrying path building with a less stringent signature
717 // algorithm *might* successfully build a path, based on the earlier failed
718 // |result|.
719 //
720 // This implementation is simplistic, and looks only for the presence of the
721 // kUnacceptableSignatureAlgorithm error somewhere among the built paths.
CanTryAgainWithWeakerDigestPolicy(const CertPathBuilder::Result & result)722 bool CanTryAgainWithWeakerDigestPolicy(const CertPathBuilder::Result& result) {
723 return result.AnyPathContainsError(
724 cert_errors::kUnacceptableSignatureAlgorithm);
725 }
726
VerifyInternal(X509Certificate * input_cert,const std::string & hostname,const std::string & ocsp_response,const std::string & sct_list,int flags,const CertificateList & additional_trust_anchors,CertVerifyResult * verify_result,const NetLogWithSource & net_log)727 int CertVerifyProcBuiltin::VerifyInternal(
728 X509Certificate* input_cert,
729 const std::string& hostname,
730 const std::string& ocsp_response,
731 const std::string& sct_list,
732 int flags,
733 const CertificateList& additional_trust_anchors,
734 CertVerifyResult* verify_result,
735 const NetLogWithSource& net_log) {
736 // VerifyInternal() is expected to carry out verifications using the current
737 // time stamp.
738 base::Time verification_time = base::Time::Now();
739 base::TimeTicks deadline = base::TimeTicks::Now() + kMaxVerificationTime;
740 der::GeneralizedTime der_verification_time;
741 if (!der::EncodeTimeAsGeneralizedTime(verification_time,
742 &der_verification_time)) {
743 // This shouldn't be possible.
744 // We don't really have a good error code for this type of error.
745 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID;
746 return ERR_CERT_AUTHORITY_INVALID;
747 }
748 absl::optional<int64_t> chrome_root_store_version_opt = absl::nullopt;
749 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
750 int64_t chrome_root_store_version =
751 system_trust_store_->chrome_root_store_version();
752 if (chrome_root_store_version != 0) {
753 net_log.AddEvent(
754 NetLogEventType::CERT_VERIFY_PROC_CHROME_ROOT_STORE_VERSION, [&] {
755 return NetLogChromeRootStoreVersion(chrome_root_store_version);
756 });
757 chrome_root_store_version_opt = chrome_root_store_version;
758 }
759 #endif
760
761 CertVerifyProcBuiltinResultDebugData::Create(verify_result, verification_time,
762 der_verification_time,
763 chrome_root_store_version_opt);
764
765 // Parse the target certificate.
766 std::shared_ptr<const ParsedCertificate> target;
767 {
768 CertErrors parsing_errors;
769 target =
770 ParseCertificateFromBuffer(input_cert->cert_buffer(), &parsing_errors);
771 // TODO(crbug.com/634484): this duplicates the logging of the input chain
772 // maybe should only log if there is a parse error/warning?
773 net_log.AddEvent(NetLogEventType::CERT_VERIFY_PROC_TARGET_CERT, [&] {
774 return NetLogCertParams(input_cert->cert_buffer(), parsing_errors);
775 });
776 if (!target) {
777 verify_result->cert_status |= CERT_STATUS_INVALID;
778 return ERR_CERT_INVALID;
779 }
780 }
781
782 // Parse the provided intermediates.
783 CertIssuerSourceStatic intermediates;
784 AddIntermediatesToIssuerSource(input_cert, &intermediates, net_log);
785
786 // Parse the additional trust anchors and setup trust store.
787 CertVerifyProcTrustStore trust_store(system_trust_store_.get());
788 for (const auto& x509_cert : additional_trust_anchors) {
789 CertErrors parsing_errors;
790 std::shared_ptr<const ParsedCertificate> cert =
791 ParseCertificateFromBuffer(x509_cert->cert_buffer(), &parsing_errors);
792 if (cert)
793 trust_store.AddTrustAnchor(std::move(cert));
794 // TODO(crbug.com/634484): this duplicates the logging of the
795 // additional_trust_anchors maybe should only log if there is a parse
796 // error/warning?
797 net_log.AddEvent(
798 NetLogEventType::CERT_VERIFY_PROC_ADDITIONAL_TRUST_ANCHOR, [&] {
799 return NetLogCertParams(x509_cert->cert_buffer(), parsing_errors);
800 });
801 }
802
803 // Get the global dependencies.
804 const EVRootCAMetadata* ev_metadata = EVRootCAMetadata::GetInstance();
805
806 // This boolean tracks whether online revocation checking was performed for
807 // *any* of the built paths, and not just the final path returned (used for
808 // setting output flag CERT_STATUS_REV_CHECKING_ENABLED).
809 bool checked_revocation_for_some_path = false;
810
811 // Run path building with the different parameters (attempts) until a valid
812 // path is found. Earlier successful attempts have priority over later
813 // attempts.
814 //
815 // Attempts are enqueued into |attempts| and drained in FIFO order.
816 std::vector<BuildPathAttempt> attempts;
817
818 // First try EV validation. Can skip this if the leaf certificate has no
819 // chance of verifying as EV (lacks an EV policy).
820 if (IsEVCandidate(ev_metadata, target.get()))
821 attempts.emplace_back(VerificationType::kEV);
822
823 // Next try DV validation.
824 attempts.emplace_back(VerificationType::kDV);
825
826 CertPathBuilder::Result result;
827 VerificationType verification_type = VerificationType::kDV;
828
829 // Iterate over |attempts| until there are none left to try, or an attempt
830 // succeeded.
831 for (size_t cur_attempt_index = 0; cur_attempt_index < attempts.size();
832 ++cur_attempt_index) {
833 const auto& cur_attempt = attempts[cur_attempt_index];
834 verification_type = cur_attempt.verification_type;
835 net_log.BeginEvent(
836 NetLogEventType::CERT_VERIFY_PROC_PATH_BUILD_ATTEMPT, [&] {
837 base::Value::Dict results;
838 if (verification_type == VerificationType::kEV)
839 results.Set("is_ev_attempt", true);
840 results.Set("digest_policy",
841 static_cast<int>(cur_attempt.digest_policy));
842 return results;
843 });
844
845 // If a previous attempt used up most/all of the deadline, extend the
846 // deadline a little bit to give this verification attempt a chance at
847 // success.
848 deadline = std::max(
849 deadline, base::TimeTicks::Now() + kPerAttemptMinVerificationTimeLimit);
850
851 // Run the attempt through the path builder.
852 result = TryBuildPath(
853 target, &intermediates, &trust_store, der_verification_time, deadline,
854 cur_attempt.verification_type, cur_attempt.digest_policy, flags,
855 ocsp_response, crl_set(), net_fetcher_.get(), ev_metadata,
856 &checked_revocation_for_some_path);
857
858 base::UmaHistogramCounts10000("Net.CertVerifier.PathBuilderIterationCount",
859 result.iteration_count);
860
861 // TODO(crbug.com/634484): Log these in path_builder.cc so they include
862 // correct timing information.
863 for (const auto& path : result.paths) {
864 net_log.AddEvent(NetLogEventType::CERT_VERIFY_PROC_PATH_BUILT,
865 [&] { return NetLogPathBuilderResultPath(*path); });
866 }
867
868 net_log.EndEvent(NetLogEventType::CERT_VERIFY_PROC_PATH_BUILD_ATTEMPT,
869 [&] { return NetLogPathBuilderResult(result); });
870
871 if (result.HasValidPath())
872 break;
873
874 if (result.exceeded_deadline) {
875 // Stop immediately if an attempt exceeds the deadline.
876 break;
877 }
878
879 // If this path building attempt (may have) failed due to the chain using a
880 // weak signature algorithm, enqueue a similar attempt but with weaker
881 // signature algorithms (SHA1) permitted.
882 //
883 // This fallback is necessary because the CertVerifyProc layer may decide to
884 // allow SHA1 based on its own policy, so path building should return
885 // possibly weak chains too.
886 //
887 // TODO(eroman): Would be better for the SHA1 policy to be part of the
888 // delegate instead so it can interact with path building.
889 if (cur_attempt.digest_policy ==
890 SimplePathBuilderDelegate::DigestPolicy::kStrong &&
891 CanTryAgainWithWeakerDigestPolicy(result)) {
892 BuildPathAttempt sha1_fallback_attempt = cur_attempt;
893 sha1_fallback_attempt.digest_policy =
894 SimplePathBuilderDelegate::DigestPolicy::kWeakAllowSha1;
895 attempts.push_back(sha1_fallback_attempt);
896 }
897 }
898
899 // Write the results to |*verify_result|.
900 int error = AssignVerifyResult(
901 input_cert, hostname, result, verification_type,
902 checked_revocation_for_some_path, &trust_store, verify_result);
903 if (error == OK) {
904 LogNameNormalizationMetrics(".Builtin", verify_result->verified_cert.get(),
905 verify_result->is_issued_by_known_root);
906 }
907 return error;
908 }
909
910 } // namespace
911
CertVerifyProcBuiltinResultDebugData(base::Time verification_time,const der::GeneralizedTime & der_verification_time,absl::optional<int64_t> chrome_root_store_version)912 CertVerifyProcBuiltinResultDebugData::CertVerifyProcBuiltinResultDebugData(
913 base::Time verification_time,
914 const der::GeneralizedTime& der_verification_time,
915 absl::optional<int64_t> chrome_root_store_version)
916 : verification_time_(verification_time),
917 der_verification_time_(der_verification_time),
918 chrome_root_store_version_(chrome_root_store_version) {}
919
920 // static
921 const CertVerifyProcBuiltinResultDebugData*
Get(const base::SupportsUserData * debug_data)922 CertVerifyProcBuiltinResultDebugData::Get(
923 const base::SupportsUserData* debug_data) {
924 return static_cast<CertVerifyProcBuiltinResultDebugData*>(
925 debug_data->GetUserData(kResultDebugDataKey));
926 }
927
928 // static
Create(base::SupportsUserData * debug_data,base::Time verification_time,const der::GeneralizedTime & der_verification_time,absl::optional<int64_t> chrome_root_store_version)929 void CertVerifyProcBuiltinResultDebugData::Create(
930 base::SupportsUserData* debug_data,
931 base::Time verification_time,
932 const der::GeneralizedTime& der_verification_time,
933 absl::optional<int64_t> chrome_root_store_version) {
934 debug_data->SetUserData(
935 kResultDebugDataKey,
936 std::make_unique<CertVerifyProcBuiltinResultDebugData>(
937 verification_time, der_verification_time, chrome_root_store_version));
938 }
939
940 std::unique_ptr<base::SupportsUserData::Data>
Clone()941 CertVerifyProcBuiltinResultDebugData::Clone() {
942 return std::make_unique<CertVerifyProcBuiltinResultDebugData>(*this);
943 }
944
CreateCertVerifyProcBuiltin(scoped_refptr<CertNetFetcher> net_fetcher,scoped_refptr<CRLSet> crl_set,std::unique_ptr<SystemTrustStore> system_trust_store)945 scoped_refptr<CertVerifyProc> CreateCertVerifyProcBuiltin(
946 scoped_refptr<CertNetFetcher> net_fetcher,
947 scoped_refptr<CRLSet> crl_set,
948 std::unique_ptr<SystemTrustStore> system_trust_store) {
949 return base::MakeRefCounted<CertVerifyProcBuiltin>(
950 std::move(net_fetcher), std::move(crl_set),
951 std::move(system_trust_store));
952 }
953
GetCertVerifyProcBuiltinTimeLimitForTesting()954 base::TimeDelta GetCertVerifyProcBuiltinTimeLimitForTesting() {
955 return kMaxVerificationTime;
956 }
957
958 } // namespace net
959