OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/cert/cert_verify_proc.h" | 5 #include "net/cert/cert_verify_proc.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 | 10 |
11 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
12 #include "base/metrics/histogram_macros.h" | 12 #include "base/metrics/histogram_macros.h" |
13 #include "base/sha1.h" | 13 #include "base/sha1.h" |
14 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
15 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
16 #include "base/time/time.h" | 16 #include "base/time/time.h" |
17 #include "build/build_config.h" | 17 #include "build/build_config.h" |
18 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
19 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 19 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
20 #include "net/base/url_util.h" | 20 #include "net/base/url_util.h" |
21 #include "net/cert/asn1_util.h" | 21 #include "net/cert/asn1_util.h" |
22 #include "net/cert/cert_status_flags.h" | 22 #include "net/cert/cert_status_flags.h" |
23 #include "net/cert/cert_verifier.h" | 23 #include "net/cert/cert_verifier.h" |
24 #include "net/cert/cert_verify_proc_whitelist.h" | 24 #include "net/cert/cert_verify_proc_whitelist.h" |
25 #include "net/cert/cert_verify_result.h" | 25 #include "net/cert/cert_verify_result.h" |
26 #include "net/cert/crl_set.h" | 26 #include "net/cert/crl_set.h" |
27 #include "net/cert/internal/parse_ocsp.h" | 27 #include "net/cert/internal/parse_ocsp.h" |
28 #include "net/cert/internal/signature_algorithm.h" | |
28 #include "net/cert/ocsp_revocation_status.h" | 29 #include "net/cert/ocsp_revocation_status.h" |
29 #include "net/cert/x509_certificate.h" | 30 #include "net/cert/x509_certificate.h" |
30 #include "net/der/encode_values.h" | 31 #include "net/der/encode_values.h" |
31 #include "url/url_canon.h" | 32 #include "url/url_canon.h" |
32 | 33 |
33 #if defined(USE_NSS_CERTS) | 34 #if defined(USE_NSS_CERTS) |
34 #include "net/cert/cert_verify_proc_nss.h" | 35 #include "net/cert/cert_verify_proc_nss.h" |
35 #elif defined(USE_OPENSSL_CERTS) && !defined(OS_ANDROID) | 36 #elif defined(USE_OPENSSL_CERTS) && !defined(OS_ANDROID) |
36 #include "net/cert/cert_verify_proc_openssl.h" | 37 #include "net/cert/cert_verify_proc_openssl.h" |
37 #elif defined(OS_ANDROID) | 38 #elif defined(OS_ANDROID) |
(...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
365 // Note: This must be kept in sync with cert_verify_proc_unittest.cc | 366 // Note: This must be kept in sync with cert_verify_proc_unittest.cc |
366 return base::win::GetVersion() < base::win::VERSION_WIN8; | 367 return base::win::GetVersion() < base::win::VERSION_WIN8; |
367 #else | 368 #else |
368 return false; | 369 return false; |
369 #endif | 370 #endif |
370 }; | 371 }; |
371 | 372 |
372 // Sets the "has_*" boolean members in |verify_result| that correspond with | 373 // Sets the "has_*" boolean members in |verify_result| that correspond with |
373 // the the presence of |hash| somewhere in the certificate chain (excluding the | 374 // the the presence of |hash| somewhere in the certificate chain (excluding the |
374 // trust anchor). | 375 // trust anchor). |
375 void MapHashAlgorithmToBool(X509Certificate::SignatureHashAlgorithm hash, | 376 void MapAlgorithmToBool(DigestAlgorithm hash, CertVerifyResult* verify_result) { |
376 CertVerifyResult* verify_result) { | |
377 switch (hash) { | 377 switch (hash) { |
378 case X509Certificate::kSignatureHashAlgorithmMd2: | 378 case DigestAlgorithm::Md2: |
379 verify_result->has_md2 = true; | 379 verify_result->has_md2 = true; |
380 break; | 380 break; |
381 case X509Certificate::kSignatureHashAlgorithmMd4: | 381 case DigestAlgorithm::Md4: |
382 verify_result->has_md4 = true; | 382 verify_result->has_md4 = true; |
383 break; | 383 break; |
384 case X509Certificate::kSignatureHashAlgorithmMd5: | 384 case DigestAlgorithm::Md5: |
385 verify_result->has_md5 = true; | 385 verify_result->has_md5 = true; |
386 break; | 386 break; |
387 case X509Certificate::kSignatureHashAlgorithmSha1: | 387 case DigestAlgorithm::Sha1: |
388 verify_result->has_sha1 = true; | 388 verify_result->has_sha1 = true; |
389 break; | 389 break; |
390 case X509Certificate::kSignatureHashAlgorithmOther: | 390 case DigestAlgorithm::Sha256: |
391 case DigestAlgorithm::Sha384: | |
392 case DigestAlgorithm::Sha512: | |
391 break; | 393 break; |
392 } | 394 } |
393 } | 395 } |
394 | 396 |
395 // Sets to true the |verify_result->has_*| boolean members for the hash | 397 // Inspects the signature algorithms in a single certificate |cert|. |
396 // algorithms present in the certificate chain. | |
397 // | 398 // |
398 // This considers the hash algorithms in all certificates except trusted | 399 // * Sets |verify_result->has_md2| to true if the certificate uses MD2. |
399 // certificates. | 400 // * Sets |verify_result->has_md4| to true if the certificate uses MD4. |
401 // * Sets |verify_result->has_md5| to true if the certificate uses MD5. | |
402 // * Sets |verify_result->has_sha1| to true if the certificate uses SHA1. | |
400 // | 403 // |
401 // In the case of a successful verification the trust anchor is the final | 404 // Returns false if the signature algorithm was invalid (unknown algorithm). |
mattm
2017/03/08 01:41:35
mention "unknown or mismatched"?
eroman
2017/03/08 17:09:24
Done.
| |
402 // certificate in the chain (either the final intermediate, or the leaf | 405 WARN_UNUSED_RESULT bool InspectSignatureAlgorithmForCert( |
403 // certificate). | 406 X509Certificate::OSCertHandle cert, |
407 CertVerifyResult* verify_result) { | |
408 std::string cert_der; | |
409 base::StringPiece cert_algorithm_sequence; | |
410 base::StringPiece tbs_algorithm_sequence; | |
411 | |
412 // Extract the AlgorithmIdentifier SEQUENCEs | |
413 if (!X509Certificate::GetDEREncoded(cert, &cert_der) || | |
414 !asn1::ExtractSignatureAlgorithmsFromDERCert( | |
415 cert_der, &cert_algorithm_sequence, &tbs_algorithm_sequence)) { | |
416 return false; | |
417 } | |
418 | |
419 if (!SignatureAlgorithm::IsEquivalent(der::Input(cert_algorithm_sequence), | |
420 der::Input(tbs_algorithm_sequence))) { | |
421 return false; | |
422 } | |
423 | |
424 auto algorithm = | |
425 SignatureAlgorithm::Create(der::Input(cert_algorithm_sequence), nullptr); | |
426 if (!algorithm) | |
427 return false; | |
428 | |
429 MapAlgorithmToBool(algorithm->digest(), verify_result); | |
430 | |
431 // Check algorithm-specific parameters. | |
432 switch (algorithm->algorithm()) { | |
433 case SignatureAlgorithmId::RsaPkcs1: | |
434 case SignatureAlgorithmId::Ecdsa: | |
435 DCHECK(!algorithm->has_params()); | |
436 break; | |
437 case SignatureAlgorithmId::RsaPss: | |
438 MapAlgorithmToBool(algorithm->ParamsForRsaPss()->mgf1_hash(), | |
439 verify_result); | |
440 break; | |
441 } | |
442 | |
443 return true; | |
444 } | |
445 | |
446 // InspectSignatureAlgorithmsInChain() calls InspectSignatureAlgorithmForCert() | |
447 // for each certificate in the chain (refer to its documentation). | |
404 // | 448 // |
405 // Whereas if verification was uncessful, the chain may be partial, and the | 449 // Returns false if any signature algorithm in the chain was invalid. |
406 // final certificate may not be a trust anchor. This heuristic is used | 450 WARN_UNUSED_RESULT bool InspectSignatureAlgorithmsInChain( |
407 // in both successful and failed verifications, despite this ambiguity (failure | 451 CertVerifyResult* verify_result) { |
408 // to tag one of the signature algorithms should only affect the final error). | |
409 void ComputeSignatureHashAlgorithms(CertVerifyResult* verify_result) { | |
410 const X509Certificate::OSCertHandles& intermediates = | 452 const X509Certificate::OSCertHandles& intermediates = |
411 verify_result->verified_cert->GetIntermediateCertificates(); | 453 verify_result->verified_cert->GetIntermediateCertificates(); |
412 | 454 |
413 // If there are no intermediates, then the leaf is trusted or verification | 455 // If there are no intermediates, then the leaf is trusted or verification |
414 // failed. | 456 // failed. |
415 if (intermediates.empty()) | 457 if (intermediates.empty()) |
416 return; | 458 return true; |
417 | 459 |
418 DCHECK(!verify_result->has_sha1); | 460 DCHECK(!verify_result->has_sha1); |
419 | 461 |
420 // Fill in hash algorithms for the leaf certificate. | 462 // Fill in hash algorithms for the leaf certificate. |
421 MapHashAlgorithmToBool(X509Certificate::GetSignatureHashAlgorithm( | 463 if (!InspectSignatureAlgorithmForCert( |
422 verify_result->verified_cert->os_cert_handle()), | 464 verify_result->verified_cert->os_cert_handle(), verify_result)) { |
423 verify_result); | 465 return false; |
466 } | |
467 | |
424 verify_result->has_sha1_leaf = verify_result->has_sha1; | 468 verify_result->has_sha1_leaf = verify_result->has_sha1; |
425 | 469 |
426 // Fill in hash algorithms for the intermediate cerificates, excluding the | 470 // Fill in hash algorithms for the intermediate cerificates, excluding the |
427 // final one (which is the trust anchor). | 471 // final one (which is presumably the trust anchor; may be incorrect for |
472 // partial chains). | |
428 for (size_t i = 0; i + 1 < intermediates.size(); ++i) { | 473 for (size_t i = 0; i + 1 < intermediates.size(); ++i) { |
429 MapHashAlgorithmToBool( | 474 if (!InspectSignatureAlgorithmForCert(intermediates[i], verify_result)) |
430 X509Certificate::GetSignatureHashAlgorithm(intermediates[i]), | 475 return false; |
431 verify_result); | |
432 } | 476 } |
477 | |
478 return true; | |
433 } | 479 } |
434 | 480 |
435 } // namespace | 481 } // namespace |
436 | 482 |
437 // static | 483 // static |
438 CertVerifyProc* CertVerifyProc::CreateDefault() { | 484 CertVerifyProc* CertVerifyProc::CreateDefault() { |
439 #if defined(USE_NSS_CERTS) | 485 #if defined(USE_NSS_CERTS) |
440 return new CertVerifyProcNSS(); | 486 return new CertVerifyProcNSS(); |
441 #elif defined(USE_OPENSSL_CERTS) && !defined(OS_ANDROID) | 487 #elif defined(USE_OPENSSL_CERTS) && !defined(OS_ANDROID) |
442 return new CertVerifyProcOpenSSL(); | 488 return new CertVerifyProcOpenSSL(); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
476 // We do online revocation checking for EV certificates that aren't covered | 522 // We do online revocation checking for EV certificates that aren't covered |
477 // by a fresh CRLSet. | 523 // by a fresh CRLSet. |
478 // TODO(rsleevi): http://crbug.com/142974 - Allow preferences to fully | 524 // TODO(rsleevi): http://crbug.com/142974 - Allow preferences to fully |
479 // disable revocation checking. | 525 // disable revocation checking. |
480 if (flags & CertVerifier::VERIFY_EV_CERT) | 526 if (flags & CertVerifier::VERIFY_EV_CERT) |
481 flags |= CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY; | 527 flags |= CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY; |
482 | 528 |
483 int rv = VerifyInternal(cert, hostname, ocsp_response, flags, crl_set, | 529 int rv = VerifyInternal(cert, hostname, ocsp_response, flags, crl_set, |
484 additional_trust_anchors, verify_result); | 530 additional_trust_anchors, verify_result); |
485 | 531 |
486 ComputeSignatureHashAlgorithms(verify_result); | 532 // Check for mismatched signature algorithms and unknown signature algorithms |
533 // in the chain. Also fills in the has_* booleans for the digest algorithms | |
534 // present in the chain. | |
535 if (!InspectSignatureAlgorithmsInChain(verify_result)) { | |
536 verify_result->cert_status |= CERT_STATUS_INVALID; | |
537 rv = MapCertStatusToNetError(verify_result->cert_status); | |
538 } | |
487 | 539 |
488 if (!cert->VerifyNameMatch(hostname, | 540 if (!cert->VerifyNameMatch(hostname, |
489 &verify_result->common_name_fallback_used)) { | 541 &verify_result->common_name_fallback_used)) { |
490 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | 542 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; |
491 rv = MapCertStatusToNetError(verify_result->cert_status); | 543 rv = MapCertStatusToNetError(verify_result->cert_status); |
492 } | 544 } |
493 | 545 |
494 UMA_HISTOGRAM_BOOLEAN("Net.CertCommonNameFallback", | 546 UMA_HISTOGRAM_BOOLEAN("Net.CertCommonNameFallback", |
495 verify_result->common_name_fallback_used); | 547 verify_result->common_name_fallback_used); |
496 if (!verify_result->is_issued_by_known_root) { | 548 if (!verify_result->is_issued_by_known_root) { |
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
839 return true; | 891 return true; |
840 | 892 |
841 return false; | 893 return false; |
842 } | 894 } |
843 | 895 |
844 // static | 896 // static |
845 const base::Feature CertVerifyProc::kSHA1LegacyMode{ | 897 const base::Feature CertVerifyProc::kSHA1LegacyMode{ |
846 "SHA1LegacyMode", base::FEATURE_DISABLED_BY_DEFAULT}; | 898 "SHA1LegacyMode", base::FEATURE_DISABLED_BY_DEFAULT}; |
847 | 899 |
848 } // namespace net | 900 } // namespace net |
OLD | NEW |