1 // Copyright 2012 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.h"
6
7 #include <stdint.h>
8
9 #include <algorithm>
10 #include <optional>
11 #include <string_view>
12
13 #include "base/containers/flat_set.h"
14 #include "base/containers/span.h"
15 #include "base/memory/raw_span.h"
16 #include "base/metrics/histogram.h"
17 #include "base/metrics/histogram_functions.h"
18 #include "base/metrics/histogram_macros.h"
19 #include "base/notreached.h"
20 #include "base/strings/strcat.h"
21 #include "base/strings/string_util.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/threading/scoped_blocking_call.h"
24 #include "base/time/time.h"
25 #include "build/build_config.h"
26 #include "crypto/crypto_buildflags.h"
27 #include "crypto/sha2.h"
28 #include "net/base/cronet_buildflags.h"
29 #include "net/base/features.h"
30 #include "net/base/net_errors.h"
31 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
32 #include "net/base/url_util.h"
33 #include "net/cert/asn1_util.h"
34 #include "net/cert/cert_net_fetcher.h"
35 #include "net/cert/cert_status_flags.h"
36 #include "net/cert/cert_verifier.h"
37 #include "net/cert/cert_verify_result.h"
38 #include "net/cert/crl_set.h"
39 #include "net/cert/internal/revocation_checker.h"
40 #include "net/cert/internal/system_trust_store.h"
41 #include "net/cert/known_roots.h"
42 #include "net/cert/symantec_certs.h"
43 #include "net/cert/x509_certificate.h"
44 #include "net/cert/x509_certificate_net_log_param.h"
45 #include "net/cert/x509_util.h"
46 #include "net/log/net_log_event_type.h"
47 #include "net/log/net_log_values.h"
48 #include "net/log/net_log_with_source.h"
49 #include "third_party/boringssl/src/include/openssl/pool.h"
50 #include "third_party/boringssl/src/pki/encode_values.h"
51 #include "third_party/boringssl/src/pki/extended_key_usage.h"
52 #include "third_party/boringssl/src/pki/ocsp.h"
53 #include "third_party/boringssl/src/pki/ocsp_revocation_status.h"
54 #include "third_party/boringssl/src/pki/parse_certificate.h"
55 #include "third_party/boringssl/src/pki/pem.h"
56 #include "third_party/boringssl/src/pki/signature_algorithm.h"
57 #include "url/url_canon.h"
58
59 #if BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
60 #include "net/cert/cert_verify_proc_builtin.h"
61 #endif
62
63 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
64 #include "net/cert/internal/trust_store_chrome.h"
65 #endif // CHROME_ROOT_STORE_SUPPORTED
66
67 #if BUILDFLAG(IS_ANDROID)
68 #include "net/cert/cert_verify_proc_android.h"
69 #elif BUILDFLAG(IS_IOS)
70 #include "net/cert/cert_verify_proc_ios.h"
71 #endif
72
73 namespace net {
74
75 namespace {
76
77 // Constants used to build histogram names
78 const char kLeafCert[] = "Leaf";
79 const char kIntermediateCert[] = "Intermediate";
80 const char kRootCert[] = "Root";
81
82 // Histogram buckets for RSA key sizes, as well as unknown key types. RSA key
83 // sizes < 1024 bits should cause errors, while key sizes > 16K are not
84 // supported by BoringSSL.
85 const int kRsaKeySizes[] = {512, 768, 1024, 1536, 2048,
86 3072, 4096, 8192, 16384};
87 // Histogram buckets for ECDSA key sizes. The list was historically based upon
88 // FIPS 186-4 approved curves, but most are impossible. BoringSSL will only ever
89 // return P-224, P-256, P-384, or P-521, and the verifier will reject P-224.
90 const int kEcdsaKeySizes[] = {163, 192, 224, 233, 256, 283, 384, 409, 521, 571};
91
CertTypeToString(X509Certificate::PublicKeyType cert_type)92 const char* CertTypeToString(X509Certificate::PublicKeyType cert_type) {
93 switch (cert_type) {
94 case X509Certificate::kPublicKeyTypeUnknown:
95 return "Unknown";
96 case X509Certificate::kPublicKeyTypeRSA:
97 return "RSA";
98 case X509Certificate::kPublicKeyTypeECDSA:
99 return "ECDSA";
100 }
101 NOTREACHED();
102 }
103
RecordPublicKeyHistogram(const char * chain_position,bool baseline_keysize_applies,size_t size_bits,X509Certificate::PublicKeyType cert_type)104 void RecordPublicKeyHistogram(const char* chain_position,
105 bool baseline_keysize_applies,
106 size_t size_bits,
107 X509Certificate::PublicKeyType cert_type) {
108 std::string histogram_name =
109 base::StringPrintf("CertificateType2.%s.%s.%s",
110 baseline_keysize_applies ? "BR" : "NonBR",
111 chain_position,
112 CertTypeToString(cert_type));
113 // Do not use UMA_HISTOGRAM_... macros here, as it caches the Histogram
114 // instance and thus only works if |histogram_name| is constant.
115 base::HistogramBase* counter = nullptr;
116
117 // Histogram buckets are contingent upon the underlying algorithm being used.
118 switch (cert_type) {
119 case X509Certificate::kPublicKeyTypeECDSA:
120 counter = base::CustomHistogram::FactoryGet(
121 histogram_name,
122 base::CustomHistogram::ArrayToCustomEnumRanges(kEcdsaKeySizes),
123 base::HistogramBase::kUmaTargetedHistogramFlag);
124 break;
125 case X509Certificate::kPublicKeyTypeRSA:
126 case X509Certificate::kPublicKeyTypeUnknown:
127 counter = base::CustomHistogram::FactoryGet(
128 histogram_name,
129 base::CustomHistogram::ArrayToCustomEnumRanges(kRsaKeySizes),
130 base::HistogramBase::kUmaTargetedHistogramFlag);
131 break;
132 }
133 counter->Add(size_bits);
134 }
135
136 // Returns true if |type| is |kPublicKeyTypeRSA| and if |size_bits| is < 1024.
137 // Note that this means there may be false negatives: keys for other algorithms
138 // and which are weak will pass this test.
IsWeakKey(X509Certificate::PublicKeyType type,size_t size_bits)139 bool IsWeakKey(X509Certificate::PublicKeyType type, size_t size_bits) {
140 switch (type) {
141 case X509Certificate::kPublicKeyTypeRSA:
142 return size_bits < 1024;
143 default:
144 return false;
145 }
146 }
147
148 // Returns true if |cert| contains a known-weak key. Additionally, histograms
149 // the observed keys for future tightening of the definition of what
150 // constitutes a weak key.
ExaminePublicKeys(const scoped_refptr<X509Certificate> & cert,bool should_histogram)151 bool ExaminePublicKeys(const scoped_refptr<X509Certificate>& cert,
152 bool should_histogram) {
153 // The effective date of the CA/Browser Forum's Baseline Requirements -
154 // 2012-07-01 00:00:00 UTC.
155 const base::Time kBaselineEffectiveDate =
156 base::Time::FromInternalValue(INT64_C(12985574400000000));
157 // The effective date of the key size requirements from Appendix A, v1.1.5
158 // 2014-01-01 00:00:00 UTC.
159 const base::Time kBaselineKeysizeEffectiveDate =
160 base::Time::FromInternalValue(INT64_C(13033008000000000));
161
162 size_t size_bits = 0;
163 X509Certificate::PublicKeyType type = X509Certificate::kPublicKeyTypeUnknown;
164 bool weak_key = false;
165 bool baseline_keysize_applies =
166 cert->valid_start() >= kBaselineEffectiveDate &&
167 cert->valid_expiry() >= kBaselineKeysizeEffectiveDate;
168
169 X509Certificate::GetPublicKeyInfo(cert->cert_buffer(), &size_bits, &type);
170 if (should_histogram) {
171 RecordPublicKeyHistogram(kLeafCert, baseline_keysize_applies, size_bits,
172 type);
173 }
174 if (IsWeakKey(type, size_bits))
175 weak_key = true;
176
177 const std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>& intermediates =
178 cert->intermediate_buffers();
179 for (size_t i = 0; i < intermediates.size(); ++i) {
180 X509Certificate::GetPublicKeyInfo(intermediates[i].get(), &size_bits,
181 &type);
182 if (should_histogram) {
183 RecordPublicKeyHistogram(
184 (i < intermediates.size() - 1) ? kIntermediateCert : kRootCert,
185 baseline_keysize_applies,
186 size_bits,
187 type);
188 }
189 if (!weak_key && IsWeakKey(type, size_bits))
190 weak_key = true;
191 }
192
193 return weak_key;
194 }
195
BestEffortCheckOCSP(const std::string & raw_response,const X509Certificate & certificate,bssl::OCSPVerifyResult * verify_result)196 void BestEffortCheckOCSP(const std::string& raw_response,
197 const X509Certificate& certificate,
198 bssl::OCSPVerifyResult* verify_result) {
199 if (raw_response.empty()) {
200 *verify_result = bssl::OCSPVerifyResult();
201 verify_result->response_status = bssl::OCSPVerifyResult::MISSING;
202 return;
203 }
204
205 std::string_view cert_der =
206 x509_util::CryptoBufferAsStringPiece(certificate.cert_buffer());
207
208 // Try to get the certificate that signed |certificate|. This will run into
209 // problems if the CertVerifyProc implementation doesn't return the ordered
210 // certificates. If that happens the OCSP verification may be incorrect.
211 std::string_view issuer_der;
212 if (certificate.intermediate_buffers().empty()) {
213 if (X509Certificate::IsSelfSigned(certificate.cert_buffer())) {
214 issuer_der = cert_der;
215 } else {
216 // A valid cert chain wasn't provided.
217 *verify_result = bssl::OCSPVerifyResult();
218 return;
219 }
220 } else {
221 issuer_der = x509_util::CryptoBufferAsStringPiece(
222 certificate.intermediate_buffers().front().get());
223 }
224
225 verify_result->revocation_status = bssl::CheckOCSP(
226 raw_response, cert_der, issuer_der, base::Time::Now().ToTimeT(),
227 kMaxRevocationLeafUpdateAge.InSeconds(), &verify_result->response_status);
228 }
229
230 // Records details about the most-specific trust anchor in |hashes|, which is
231 // expected to be ordered with the leaf cert first and the root cert last.
232 // "Most-specific" refers to the case that it is not uncommon to have multiple
233 // potential trust anchors present in a chain, depending on the client trust
234 // store. For example, '1999-Root' cross-signing '2005-Root' cross-signing
235 // '2012-Root' cross-signing '2017-Root', then followed by intermediate and
236 // leaf. For purposes of assessing impact of, say, removing 1999-Root, while
237 // including 2017-Root as a trust anchor, then the validation should be
238 // counted as 2017-Root, rather than 1999-Root.
239 //
240 // This also accounts for situations in which a new CA is introduced, and
241 // has been cross-signed by an existing CA. Assessing impact should use the
242 // most-specific trust anchor, when possible.
243 //
244 // This also histograms for divergence between the root store and
245 // |spki_hashes| - that is, situations in which the OS methods of detecting
246 // a known root flag a certificate as known, but its hash is not known as part
247 // of the built-in list.
RecordTrustAnchorHistogram(const HashValueVector & spki_hashes,bool is_issued_by_known_root)248 void RecordTrustAnchorHistogram(const HashValueVector& spki_hashes,
249 bool is_issued_by_known_root) {
250 int32_t id = 0;
251 for (const auto& hash : spki_hashes) {
252 id = GetNetTrustAnchorHistogramIdForSPKI(hash);
253 if (id != 0)
254 break;
255 }
256 base::UmaHistogramSparse("Net.Certificate.TrustAnchor.Verify", id);
257
258 // Record when a known trust anchor is not found within the chain, but the
259 // certificate is flagged as being from a known root (meaning a fallback to
260 // OS-based methods of determination).
261 if (id == 0) {
262 UMA_HISTOGRAM_BOOLEAN("Net.Certificate.TrustAnchor.VerifyOutOfDate",
263 is_issued_by_known_root);
264 }
265 }
266
267 // Inspects the signature algorithms in a single certificate |cert|.
268 //
269 // * Sets |verify_result->has_sha1| to true if the certificate uses SHA1.
270 //
271 // Returns false if the signature algorithm was unknown or mismatched.
InspectSignatureAlgorithmForCert(const CRYPTO_BUFFER * cert,CertVerifyResult * verify_result)272 [[nodiscard]] bool InspectSignatureAlgorithmForCert(
273 const CRYPTO_BUFFER* cert,
274 CertVerifyResult* verify_result) {
275 std::string_view cert_algorithm_sequence;
276 std::string_view tbs_algorithm_sequence;
277
278 // Extract the AlgorithmIdentifier SEQUENCEs
279 if (!asn1::ExtractSignatureAlgorithmsFromDERCert(
280 x509_util::CryptoBufferAsStringPiece(cert), &cert_algorithm_sequence,
281 &tbs_algorithm_sequence)) {
282 return false;
283 }
284
285 std::optional<bssl::SignatureAlgorithm> cert_algorithm =
286 bssl::ParseSignatureAlgorithm(bssl::der::Input(cert_algorithm_sequence));
287 std::optional<bssl::SignatureAlgorithm> tbs_algorithm =
288 bssl::ParseSignatureAlgorithm(bssl::der::Input(tbs_algorithm_sequence));
289 if (!cert_algorithm || !tbs_algorithm || *cert_algorithm != *tbs_algorithm) {
290 return false;
291 }
292
293 switch (*cert_algorithm) {
294 case bssl::SignatureAlgorithm::kRsaPkcs1Sha1:
295 case bssl::SignatureAlgorithm::kEcdsaSha1:
296 verify_result->has_sha1 = true;
297 return true; // For now.
298
299 case bssl::SignatureAlgorithm::kRsaPkcs1Sha256:
300 case bssl::SignatureAlgorithm::kRsaPkcs1Sha384:
301 case bssl::SignatureAlgorithm::kRsaPkcs1Sha512:
302 case bssl::SignatureAlgorithm::kEcdsaSha256:
303 case bssl::SignatureAlgorithm::kEcdsaSha384:
304 case bssl::SignatureAlgorithm::kEcdsaSha512:
305 case bssl::SignatureAlgorithm::kRsaPssSha256:
306 case bssl::SignatureAlgorithm::kRsaPssSha384:
307 case bssl::SignatureAlgorithm::kRsaPssSha512:
308 return true;
309 }
310
311 NOTREACHED();
312 }
313
314 // InspectSignatureAlgorithmsInChain() sets |verify_result->has_*| based on
315 // the signature algorithms used in the chain, and also checks that certificates
316 // don't have contradictory signature algorithms.
317 //
318 // Returns false if any signature algorithm in the chain is unknown or
319 // mismatched.
320 //
321 // Background:
322 //
323 // X.509 certificates contain two redundant descriptors for the signature
324 // algorithm; one is covered by the signature, but in order to verify the
325 // signature, the other signature algorithm is untrusted.
326 //
327 // RFC 5280 states that the two should be equal, in order to mitigate risk of
328 // signature substitution attacks, but also discourages verifiers from enforcing
329 // the profile of RFC 5280.
330 //
331 // System verifiers are inconsistent - some use the unsigned signature, some use
332 // the signed signature, and they generally do not enforce that both match. This
333 // creates confusion, as it's possible that the signature itself may be checked
334 // using algorithm A, but if subsequent consumers report the certificate
335 // algorithm, they may end up reporting algorithm B, which was not used to
336 // verify the certificate. This function enforces that the two signatures match
337 // in order to prevent such confusion.
InspectSignatureAlgorithmsInChain(CertVerifyResult * verify_result)338 [[nodiscard]] bool InspectSignatureAlgorithmsInChain(
339 CertVerifyResult* verify_result) {
340 const std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>& intermediates =
341 verify_result->verified_cert->intermediate_buffers();
342
343 // If there are no intermediates, then the leaf is trusted or verification
344 // failed.
345 if (intermediates.empty())
346 return true;
347
348 DCHECK(!verify_result->has_sha1);
349
350 // Fill in hash algorithms for the leaf certificate.
351 if (!InspectSignatureAlgorithmForCert(
352 verify_result->verified_cert->cert_buffer(), verify_result)) {
353 return false;
354 }
355
356 // Fill in hash algorithms for the intermediate cerificates, excluding the
357 // final one (which is presumably the trust anchor; may be incorrect for
358 // partial chains).
359 for (size_t i = 0; i + 1 < intermediates.size(); ++i) {
360 if (!InspectSignatureAlgorithmForCert(intermediates[i].get(),
361 verify_result))
362 return false;
363 }
364
365 return true;
366 }
367
CertVerifyParams(X509Certificate * cert,const std::string & hostname,const std::string & ocsp_response,const std::string & sct_list,int flags,CRLSet * crl_set)368 base::Value::Dict CertVerifyParams(X509Certificate* cert,
369 const std::string& hostname,
370 const std::string& ocsp_response,
371 const std::string& sct_list,
372 int flags,
373 CRLSet* crl_set) {
374 base::Value::Dict dict;
375 dict.Set("certificates", NetLogX509CertificateList(cert));
376 if (!ocsp_response.empty()) {
377 dict.Set("ocsp_response",
378 bssl::PEMEncode(ocsp_response, "NETLOG OCSP RESPONSE"));
379 }
380 if (!sct_list.empty()) {
381 dict.Set("sct_list", bssl::PEMEncode(sct_list, "NETLOG SCT LIST"));
382 }
383 dict.Set("host", NetLogStringValue(hostname));
384 dict.Set("verify_flags", flags);
385 dict.Set("crlset_sequence", NetLogNumberValue(crl_set->sequence()));
386 if (crl_set->IsExpired())
387 dict.Set("crlset_is_expired", true);
388
389 return dict;
390 }
391
392 } // namespace
393
394 #if !(BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(CHROME_ROOT_STORE_ONLY))
395 // static
CreateSystemVerifyProc(scoped_refptr<CertNetFetcher> cert_net_fetcher,scoped_refptr<CRLSet> crl_set)396 scoped_refptr<CertVerifyProc> CertVerifyProc::CreateSystemVerifyProc(
397 scoped_refptr<CertNetFetcher> cert_net_fetcher,
398 scoped_refptr<CRLSet> crl_set) {
399 #if BUILDFLAG(IS_ANDROID)
400 return base::MakeRefCounted<CertVerifyProcAndroid>(
401 std::move(cert_net_fetcher), std::move(crl_set));
402 #elif BUILDFLAG(IS_IOS)
403 return base::MakeRefCounted<CertVerifyProcIOS>(std::move(crl_set));
404 #else
405 #error Unsupported platform
406 #endif
407 }
408 #endif
409
410 #if BUILDFLAG(IS_FUCHSIA)
411 // static
CreateBuiltinVerifyProc(scoped_refptr<CertNetFetcher> cert_net_fetcher,scoped_refptr<CRLSet> crl_set,std::unique_ptr<CTVerifier> ct_verifier,scoped_refptr<CTPolicyEnforcer> ct_policy_enforcer,const InstanceParams instance_params,std::optional<network_time::TimeTracker> time_tracker)412 scoped_refptr<CertVerifyProc> CertVerifyProc::CreateBuiltinVerifyProc(
413 scoped_refptr<CertNetFetcher> cert_net_fetcher,
414 scoped_refptr<CRLSet> crl_set,
415 std::unique_ptr<CTVerifier> ct_verifier,
416 scoped_refptr<CTPolicyEnforcer> ct_policy_enforcer,
417 const InstanceParams instance_params,
418 std::optional<network_time::TimeTracker> time_tracker) {
419 return CreateCertVerifyProcBuiltin(
420 std::move(cert_net_fetcher), std::move(crl_set), std::move(ct_verifier),
421 std::move(ct_policy_enforcer), CreateSslSystemTrustStore(),
422 instance_params, std::move(time_tracker));
423 }
424 #endif
425
426 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
427 // static
CreateBuiltinWithChromeRootStore(scoped_refptr<CertNetFetcher> cert_net_fetcher,scoped_refptr<CRLSet> crl_set,std::unique_ptr<CTVerifier> ct_verifier,scoped_refptr<CTPolicyEnforcer> ct_policy_enforcer,const ChromeRootStoreData * root_store_data,const InstanceParams instance_params,std::optional<network_time::TimeTracker> time_tracker)428 scoped_refptr<CertVerifyProc> CertVerifyProc::CreateBuiltinWithChromeRootStore(
429 scoped_refptr<CertNetFetcher> cert_net_fetcher,
430 scoped_refptr<CRLSet> crl_set,
431 std::unique_ptr<CTVerifier> ct_verifier,
432 scoped_refptr<CTPolicyEnforcer> ct_policy_enforcer,
433 const ChromeRootStoreData* root_store_data,
434 const InstanceParams instance_params,
435 std::optional<network_time::TimeTracker> time_tracker) {
436 std::unique_ptr<TrustStoreChrome> chrome_root =
437 root_store_data ? std::make_unique<TrustStoreChrome>(*root_store_data)
438 : std::make_unique<TrustStoreChrome>();
439 return CreateCertVerifyProcBuiltin(
440 std::move(cert_net_fetcher), std::move(crl_set), std::move(ct_verifier),
441 std::move(ct_policy_enforcer),
442 CreateSslSystemTrustStoreChromeRoot(std::move(chrome_root)),
443 instance_params, std::move(time_tracker));
444 }
445 #endif
446
CertVerifyProc(scoped_refptr<CRLSet> crl_set)447 CertVerifyProc::CertVerifyProc(scoped_refptr<CRLSet> crl_set)
448 : crl_set_(std::move(crl_set)) {
449 CHECK(crl_set_);
450 }
451
452 CertVerifyProc::~CertVerifyProc() = default;
453
Verify(X509Certificate * cert,const std::string & hostname,const std::string & ocsp_response,const std::string & sct_list,int flags,CertVerifyResult * verify_result,const NetLogWithSource & net_log)454 int CertVerifyProc::Verify(X509Certificate* cert,
455 const std::string& hostname,
456 const std::string& ocsp_response,
457 const std::string& sct_list,
458 int flags,
459 CertVerifyResult* verify_result,
460 const NetLogWithSource& net_log) {
461 CHECK(cert);
462 CHECK(verify_result);
463
464 net_log.BeginEvent(NetLogEventType::CERT_VERIFY_PROC, [&] {
465 return CertVerifyParams(cert, hostname, ocsp_response, sct_list, flags,
466 crl_set());
467 });
468 // CertVerifyProc's contract allows ::VerifyInternal() to wait on File I/O
469 // (such as the Windows registry or smart cards on all platforms) or may re-
470 // enter this code via extension hooks (such as smart card UI). To ensure
471 // threads are not starved or deadlocked, the base::ScopedBlockingCall below
472 // increments the thread pool capacity when this method takes too much time to
473 // run.
474 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
475 base::BlockingType::MAY_BLOCK);
476
477 verify_result->Reset();
478 verify_result->verified_cert = cert;
479
480 int rv = VerifyInternal(cert, hostname, ocsp_response, sct_list, flags,
481 verify_result, net_log);
482
483 CHECK(verify_result->verified_cert);
484
485 // Check for mismatched signature algorithms and unknown signature algorithms
486 // in the chain. Also fills in the has_* booleans for the digest algorithms
487 // present in the chain.
488 if (!InspectSignatureAlgorithmsInChain(verify_result)) {
489 verify_result->cert_status |= CERT_STATUS_INVALID;
490 rv = MapCertStatusToNetError(verify_result->cert_status);
491 }
492
493 if (!cert->VerifyNameMatch(hostname)) {
494 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
495 rv = MapCertStatusToNetError(verify_result->cert_status);
496 }
497
498 if (verify_result->ocsp_result.response_status ==
499 bssl::OCSPVerifyResult::NOT_CHECKED) {
500 // If VerifyInternal did not record the result of checking stapled OCSP,
501 // do it now.
502 BestEffortCheckOCSP(ocsp_response, *verify_result->verified_cert,
503 &verify_result->ocsp_result);
504 }
505
506 // Check to see if the connection is being intercepted.
507 for (const auto& hash : verify_result->public_key_hashes) {
508 if (hash.tag() != HASH_VALUE_SHA256) {
509 continue;
510 }
511 if (!crl_set()->IsKnownInterceptionKey(std::string_view(
512 reinterpret_cast<const char*>(hash.data()), hash.size()))) {
513 continue;
514 }
515
516 if (verify_result->cert_status & CERT_STATUS_REVOKED) {
517 // If the chain was revoked, and a known MITM was present, signal that
518 // with a more meaningful error message.
519 verify_result->cert_status |= CERT_STATUS_KNOWN_INTERCEPTION_BLOCKED;
520 rv = MapCertStatusToNetError(verify_result->cert_status);
521 } else {
522 // Otherwise, simply signal informatively. Both statuses are not set
523 // simultaneously.
524 verify_result->cert_status |= CERT_STATUS_KNOWN_INTERCEPTION_DETECTED;
525 }
526 break;
527 }
528
529 std::vector<std::string> dns_names, ip_addrs;
530 cert->GetSubjectAltName(&dns_names, &ip_addrs);
531 if (HasNameConstraintsViolation(verify_result->public_key_hashes,
532 cert->subject().common_name,
533 dns_names,
534 ip_addrs)) {
535 verify_result->cert_status |= CERT_STATUS_NAME_CONSTRAINT_VIOLATION;
536 rv = MapCertStatusToNetError(verify_result->cert_status);
537 }
538
539 // Check for weak keys in the entire verified chain.
540 bool weak_key = ExaminePublicKeys(verify_result->verified_cert,
541 verify_result->is_issued_by_known_root);
542
543 if (weak_key) {
544 verify_result->cert_status |= CERT_STATUS_WEAK_KEY;
545 // Avoid replacing a more serious error, such as an OS/library failure,
546 // by ensuring that if verification failed, it failed with a certificate
547 // error.
548 if (rv == OK || IsCertificateError(rv))
549 rv = MapCertStatusToNetError(verify_result->cert_status);
550 }
551
552 if (verify_result->has_sha1)
553 verify_result->cert_status |= CERT_STATUS_SHA1_SIGNATURE_PRESENT;
554
555 // Flag certificates using weak signature algorithms.
556 bool sha1_allowed = (flags & VERIFY_ENABLE_SHA1_LOCAL_ANCHORS) &&
557 !verify_result->is_issued_by_known_root;
558 if (!sha1_allowed && verify_result->has_sha1) {
559 verify_result->cert_status |= CERT_STATUS_WEAK_SIGNATURE_ALGORITHM;
560 // Avoid replacing a more serious error, such as an OS/library failure,
561 // by ensuring that if verification failed, it failed with a certificate
562 // error.
563 if (rv == OK || IsCertificateError(rv))
564 rv = MapCertStatusToNetError(verify_result->cert_status);
565 }
566
567 // Distrust Symantec-issued certificates, as described at
568 // https://security.googleblog.com/2017/09/chromes-plan-to-distrust-symantec.html
569 if (!(flags & VERIFY_DISABLE_SYMANTEC_ENFORCEMENT) &&
570 IsLegacySymantecCert(verify_result->public_key_hashes)) {
571 verify_result->cert_status |= CERT_STATUS_SYMANTEC_LEGACY;
572 if (rv == OK || IsCertificateError(rv))
573 rv = MapCertStatusToNetError(verify_result->cert_status);
574 }
575
576 // Flag certificates using too long validity periods.
577 if (verify_result->is_issued_by_known_root && HasTooLongValidity(*cert)) {
578 verify_result->cert_status |= CERT_STATUS_VALIDITY_TOO_LONG;
579 if (rv == OK)
580 rv = MapCertStatusToNetError(verify_result->cert_status);
581 }
582
583 // Flag certificates from publicly-trusted CAs that are issued to intranet
584 // hosts. These are not allowed per the CA/Browser Forum requirements.
585 //
586 // Validity period is checked first just for testing convenience; there's not
587 // a strong security reason to let validity period vs non-unique names take
588 // precedence.
589 if (verify_result->is_issued_by_known_root && IsHostnameNonUnique(hostname)) {
590 verify_result->cert_status |= CERT_STATUS_NON_UNIQUE_NAME;
591 // On Cronet, CERT_STATUS_NON_UNIQUE_NAME is recorded as a warning but not
592 // treated as an error, because consumers have tests that use certs with
593 // non-unique names. See b/337196170 (Google-internal).
594 #if !BUILDFLAG(CRONET_BUILD)
595 if (rv == OK) {
596 rv = MapCertStatusToNetError(verify_result->cert_status);
597 }
598 #endif // !BUILDFLAG(CRONET_BUILD)
599 }
600
601 // Record a histogram for per-verification usage of root certs.
602 if (rv == OK) {
603 RecordTrustAnchorHistogram(verify_result->public_key_hashes,
604 verify_result->is_issued_by_known_root);
605 }
606
607 net_log.EndEvent(NetLogEventType::CERT_VERIFY_PROC,
608 [&] { return verify_result->NetLogParams(rv); });
609 return rv;
610 }
611
612 // static
LogNameNormalizationResult(const std::string & histogram_suffix,NameNormalizationResult result)613 void CertVerifyProc::LogNameNormalizationResult(
614 const std::string& histogram_suffix,
615 NameNormalizationResult result) {
616 base::UmaHistogramEnumeration(
617 std::string("Net.CertVerifier.NameNormalizationPrivateRoots") +
618 histogram_suffix,
619 result);
620 }
621
622 // static
LogNameNormalizationMetrics(const std::string & histogram_suffix,X509Certificate * verified_cert,bool is_issued_by_known_root)623 void CertVerifyProc::LogNameNormalizationMetrics(
624 const std::string& histogram_suffix,
625 X509Certificate* verified_cert,
626 bool is_issued_by_known_root) {
627 if (is_issued_by_known_root)
628 return;
629
630 if (verified_cert->intermediate_buffers().empty()) {
631 LogNameNormalizationResult(histogram_suffix,
632 NameNormalizationResult::kChainLengthOne);
633 return;
634 }
635
636 std::vector<CRYPTO_BUFFER*> der_certs;
637 der_certs.push_back(verified_cert->cert_buffer());
638 for (const auto& buf : verified_cert->intermediate_buffers())
639 der_certs.push_back(buf.get());
640
641 bssl::ParseCertificateOptions options;
642 options.allow_invalid_serial_numbers = true;
643
644 std::vector<bssl::der::Input> subjects;
645 std::vector<bssl::der::Input> issuers;
646
647 for (auto* buf : der_certs) {
648 bssl::der::Input tbs_certificate_tlv;
649 bssl::der::Input signature_algorithm_tlv;
650 bssl::der::BitString signature_value;
651 bssl::ParsedTbsCertificate tbs;
652 if (!bssl::ParseCertificate(
653 bssl::der::Input(CRYPTO_BUFFER_data(buf), CRYPTO_BUFFER_len(buf)),
654 &tbs_certificate_tlv, &signature_algorithm_tlv, &signature_value,
655 nullptr /* errors*/) ||
656 !ParseTbsCertificate(tbs_certificate_tlv, options, &tbs,
657 nullptr /*errors*/)) {
658 LogNameNormalizationResult(histogram_suffix,
659 NameNormalizationResult::kError);
660 return;
661 }
662 subjects.push_back(tbs.subject_tlv);
663 issuers.push_back(tbs.issuer_tlv);
664 }
665
666 for (size_t i = 0; i < subjects.size() - 1; ++i) {
667 if (issuers[i] != subjects[i + 1]) {
668 LogNameNormalizationResult(histogram_suffix,
669 NameNormalizationResult::kNormalized);
670 return;
671 }
672 }
673
674 LogNameNormalizationResult(histogram_suffix,
675 NameNormalizationResult::kByteEqual);
676 }
677
678 // CheckNameConstraints verifies that every name in |dns_names| is in one of
679 // the domains specified by |domains|.
CheckNameConstraints(const std::vector<std::string> & dns_names,base::span<const std::string_view> domains)680 static bool CheckNameConstraints(const std::vector<std::string>& dns_names,
681 base::span<const std::string_view> domains) {
682 for (const auto& host : dns_names) {
683 bool ok = false;
684 url::CanonHostInfo host_info;
685 const std::string dns_name = CanonicalizeHost(host, &host_info);
686 if (host_info.IsIPAddress())
687 continue;
688
689 // If the name is not in a known TLD, ignore it. This permits internal
690 // server names.
691 if (!registry_controlled_domains::HostHasRegistryControlledDomain(
692 dns_name, registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
693 registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) {
694 continue;
695 }
696
697 for (const auto& domain : domains) {
698 // The |domain| must be of ".somesuffix" form, and |dns_name| must
699 // have |domain| as a suffix.
700 DCHECK_EQ('.', domain[0]);
701 if (dns_name.size() <= domain.size())
702 continue;
703 std::string_view suffix =
704 std::string_view(dns_name).substr(dns_name.size() - domain.size());
705 if (!base::EqualsCaseInsensitiveASCII(suffix, domain))
706 continue;
707 ok = true;
708 break;
709 }
710
711 if (!ok)
712 return false;
713 }
714
715 return true;
716 }
717
718 // static
HasNameConstraintsViolation(const HashValueVector & public_key_hashes,const std::string & common_name,const std::vector<std::string> & dns_names,const std::vector<std::string> & ip_addrs)719 bool CertVerifyProc::HasNameConstraintsViolation(
720 const HashValueVector& public_key_hashes,
721 const std::string& common_name,
722 const std::vector<std::string>& dns_names,
723 const std::vector<std::string>& ip_addrs) {
724 static constexpr std::string_view kDomainsANSSI[] = {
725 ".fr", // France
726 ".gp", // Guadeloupe
727 ".gf", // Guyane
728 ".mq", // Martinique
729 ".re", // Réunion
730 ".yt", // Mayotte
731 ".pm", // Saint-Pierre et Miquelon
732 ".bl", // Saint Barthélemy
733 ".mf", // Saint Martin
734 ".wf", // Wallis et Futuna
735 ".pf", // Polynésie française
736 ".nc", // Nouvelle Calédonie
737 ".tf", // Terres australes et antarctiques françaises
738 };
739
740 static constexpr std::string_view kDomainsTest[] = {
741 ".example.com",
742 };
743
744 // PublicKeyDomainLimitation contains SHA-256(SPKI) and a pointer to an array
745 // of fixed-length strings that contain the domains that the SPKI is allowed
746 // to issue for.
747 //
748 // A public key hash can be generated with the following command:
749 // openssl x509 -noout -in <cert>.pem -pubkey | \
750 // openssl asn1parse -noout -inform pem -out - | \
751 // openssl dgst -sha256 -binary | xxd -i
752 static const struct PublicKeyDomainLimitation {
753 SHA256HashValue public_key_hash;
754 base::raw_span<const std::string_view> domains;
755 } kLimits[] = {
756 // C=FR, ST=France, L=Paris, O=PM/SGDN, OU=DCSSI,
757 // CN=IGC/A/emailAddress=igca@sgdn.pm.gouv.fr
758 //
759 // net/data/ssl/name_constrained/b9bea7860a962ea3611dab97ab6da3e21c1068b97d55575ed0e11279c11c8932.pem
760 {
761 {{0x86, 0xc1, 0x3a, 0x34, 0x08, 0xdd, 0x1a, 0xa7, 0x7e, 0xe8, 0xb6,
762 0x94, 0x7c, 0x03, 0x95, 0x87, 0x72, 0xf5, 0x31, 0x24, 0x8c, 0x16,
763 0x27, 0xbe, 0xfb, 0x2c, 0x4f, 0x4b, 0x04, 0xd0, 0x44, 0x96}},
764 kDomainsANSSI,
765 },
766 // Not a real certificate - just for testing.
767 // net/data/ssl/certificates/name_constrained_key.pem
768 {
769 {{0xa2, 0x2a, 0x88, 0x82, 0xba, 0x0c, 0xae, 0x9d, 0xf2, 0xc4, 0x5b,
770 0x15, 0xa6, 0x1e, 0xfd, 0xfd, 0x19, 0x6b, 0xb1, 0x09, 0x19, 0xfd,
771 0xac, 0x77, 0x9b, 0xd6, 0x08, 0x66, 0xda, 0xa8, 0xd2, 0x88}},
772 kDomainsTest,
773 },
774 };
775
776 for (const auto& limit : kLimits) {
777 for (const auto& hash : public_key_hashes) {
778 if (hash.tag() != HASH_VALUE_SHA256)
779 continue;
780 if (memcmp(hash.data(), limit.public_key_hash.data, hash.size()) != 0)
781 continue;
782 if (dns_names.empty() && ip_addrs.empty()) {
783 std::vector<std::string> names;
784 names.push_back(common_name);
785 if (!CheckNameConstraints(names, limit.domains))
786 return true;
787 } else {
788 if (!CheckNameConstraints(dns_names, limit.domains))
789 return true;
790 }
791 }
792 }
793
794 return false;
795 }
796
797 // static
HasTooLongValidity(const X509Certificate & cert)798 bool CertVerifyProc::HasTooLongValidity(const X509Certificate& cert) {
799 const base::Time& start = cert.valid_start();
800 const base::Time& expiry = cert.valid_expiry();
801 if (start.is_max() || start.is_null() || expiry.is_max() ||
802 expiry.is_null() || start > expiry) {
803 return true;
804 }
805
806 // The maximum lifetime of publicly trusted certificates has reduced
807 // gradually over time. These dates are derived from the transitions noted in
808 // Section 1.2.2 (Relevant Dates) of the Baseline Requirements.
809 //
810 // * Certificates issued before BRs took effect, Chrome limited to max of ten
811 // years validity and a max notAfter date of 2019-07-01.
812 // * Last possible expiry: 2019-07-01.
813 //
814 // * Cerificates issued on-or-after the BR effective date of 1 July 2012: 60
815 // months.
816 // * Last possible expiry: 1 April 2015 + 60 months = 2020-04-01
817 //
818 // * Certificates issued on-or-after 1 April 2015: 39 months.
819 // * Last possible expiry: 1 March 2018 + 39 months = 2021-06-01
820 //
821 // * Certificates issued on-or-after 1 March 2018: 825 days.
822 // * Last possible expiry: 1 September 2020 + 825 days = 2022-12-05
823 //
824 // The current limit, from Chrome Root Certificate Policy:
825 // * Certificates issued on-or-after 1 September 2020: 398 days.
826
827 base::TimeDelta validity_duration = cert.valid_expiry() - cert.valid_start();
828
829 // No certificates issued before the latest lifetime requirement was enacted
830 // could possibly still be accepted, so we don't need to check the older
831 // limits explicitly.
832 return validity_duration > base::Days(398);
833 }
834
ImplParams()835 CertVerifyProc::ImplParams::ImplParams() {
836 crl_set = net::CRLSet::BuiltinCRLSet();
837 #if BUILDFLAG(CHROME_ROOT_STORE_OPTIONAL)
838 // Defaults to using Chrome Root Store, though we have to keep this option in
839 // here to allow WebView to turn this option off.
840 use_chrome_root_store = true;
841 #endif
842 }
843
844 CertVerifyProc::ImplParams::~ImplParams() = default;
845
846 CertVerifyProc::ImplParams::ImplParams(const ImplParams&) = default;
847 CertVerifyProc::ImplParams& CertVerifyProc::ImplParams::operator=(
848 const ImplParams& other) = default;
849 CertVerifyProc::ImplParams::ImplParams(ImplParams&&) = default;
850 CertVerifyProc::ImplParams& CertVerifyProc::ImplParams::operator=(
851 ImplParams&& other) = default;
852
853 CertVerifyProc::InstanceParams::InstanceParams() = default;
854 CertVerifyProc::InstanceParams::~InstanceParams() = default;
855
856 CertVerifyProc::InstanceParams::InstanceParams(const InstanceParams&) = default;
857 CertVerifyProc::InstanceParams& CertVerifyProc::InstanceParams::operator=(
858 const InstanceParams& other) = default;
859 CertVerifyProc::InstanceParams::InstanceParams(InstanceParams&&) = default;
860 CertVerifyProc::InstanceParams& CertVerifyProc::InstanceParams::operator=(
861 InstanceParams&& other) = default;
862
863 CertVerifyProc::CertificateWithConstraints::CertificateWithConstraints() =
864 default;
865 CertVerifyProc::CertificateWithConstraints::~CertificateWithConstraints() =
866 default;
867
868 CertVerifyProc::CertificateWithConstraints::CertificateWithConstraints(
869 const CertificateWithConstraints&) = default;
870 CertVerifyProc::CertificateWithConstraints&
871 CertVerifyProc::CertificateWithConstraints::operator=(
872 const CertificateWithConstraints& other) = default;
873 CertVerifyProc::CertificateWithConstraints::CertificateWithConstraints(
874 CertificateWithConstraints&&) = default;
875 CertVerifyProc::CertificateWithConstraints&
876 CertVerifyProc::CertificateWithConstraints::operator=(
877 CertificateWithConstraints&& other) = default;
878
879 } // namespace net
880