Chromium Code Reviews| 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 // * Sets |*has_mismatched_signature_algorithms| to true if |
|
mattm
2017/03/04 02:34:26
note that the has_mismatched_signature_algorithms
eroman
2017/03/07 23:43:00
N/A -- I removed these out-parameters and combined
| |
| 402 // certificate in the chain (either the final intermediate, or the leaf | 405 // Certificate.signatureAlgorithm is not consistent with |
| 403 // certificate). | 406 // TBSCertificate.algorithm |
| 404 // | 407 // |
| 405 // Whereas if verification was uncessful, the chain may be partial, and the | 408 // * Sets |*has_unknown_signature_algorithms| to true if one or both of the |
| 406 // final certificate may not be a trust anchor. This heuristic is used | 409 // signature algorithms could not be parsed or matched against a known |
| 407 // in both successful and failed verifications, despite this ambiguity (failure | 410 // whitelist. |
|
mattm
2017/03/04 02:34:26
Maybe just me, but I was a bit confused by the com
eroman
2017/03/07 23:43:00
N/A -- replaced this with a hopefully clearer com
| |
| 408 // to tag one of the signature algorithms should only affect the final error). | 411 void InspectSignatureAlgorithmForCert(X509Certificate::OSCertHandle cert, |
| 409 void ComputeSignatureHashAlgorithms(CertVerifyResult* verify_result) { | 412 CertVerifyResult* verify_result, |
| 413 bool* has_mismatched_signature_algorithms, | |
| 414 bool* has_unknown_signature_algorithms) { | |
| 415 std::string cert_der; | |
| 416 base::StringPiece cert_algorithm_sequence; | |
| 417 base::StringPiece tbs_algorithm_sequence; | |
| 418 | |
| 419 // Extract the AlgorithmIdentifier SEQUENCEs | |
| 420 if (!X509Certificate::GetDEREncoded(cert, &cert_der) || | |
| 421 !asn1::ExtractSignatureAlgorithmsFromDERCert( | |
| 422 cert_der, &cert_algorithm_sequence, &tbs_algorithm_sequence)) { | |
| 423 *has_unknown_signature_algorithms = true; | |
| 424 return; | |
| 425 } | |
| 426 | |
| 427 if (!SignatureAlgorithm::IsEquivalent(der::Input(cert_algorithm_sequence), | |
| 428 der::Input(tbs_algorithm_sequence))) { | |
| 429 *has_mismatched_signature_algorithms = true; | |
| 430 } | |
| 431 | |
| 432 auto algorithm = | |
| 433 SignatureAlgorithm::Create(der::Input(cert_algorithm_sequence), nullptr); | |
| 434 | |
| 435 if (!algorithm) { | |
| 436 // Couldn't parse the signature algorithm (either malformed, or an unknown | |
| 437 // OID). | |
| 438 *has_unknown_signature_algorithms = true; | |
| 439 return; | |
|
mattm
2017/03/04 02:34:26
I guess it doesn't matter with the current usage,
eroman
2017/03/07 23:43:00
N/A -- I no longer distinguish between the two, an
| |
| 440 } | |
| 441 | |
| 442 MapAlgorithmToBool(algorithm->digest(), verify_result); | |
| 443 | |
| 444 // Check the MGF1 digest for RSASSA-PSS if applicable. | |
| 445 if (algorithm->has_params()) { | |
| 446 switch (algorithm->algorithm()) { | |
| 447 case SignatureAlgorithmId::Ecdsa: | |
| 448 case SignatureAlgorithmId::RsaPkcs1: | |
| 449 NOTREACHED(); | |
|
mattm
2017/03/04 02:34:26
Is this reachable with malformed input data? Or do
eroman
2017/03/07 23:43:00
I restructured this code so there is no longer a N
| |
| 450 break; | |
| 451 case SignatureAlgorithmId::RsaPss: | |
| 452 MapAlgorithmToBool(algorithm->ParamsForRsaPss()->mgf1_hash(), | |
| 453 verify_result); | |
| 454 break; | |
| 455 } | |
| 456 } | |
| 457 } | |
| 458 | |
| 459 // InspectSignatureAlgorithms() calls InspectSignatureAlgorithmForCert() for | |
| 460 // each certificate in the chain. | |
| 461 void InspectSignatureAlgorithms(CertVerifyResult* verify_result, | |
| 462 bool* has_mismatched_signature_algorithms, | |
| 463 bool* has_unknown_signature_algorithms) { | |
| 464 *has_mismatched_signature_algorithms = false; | |
| 465 *has_unknown_signature_algorithms = false; | |
| 466 | |
| 410 const X509Certificate::OSCertHandles& intermediates = | 467 const X509Certificate::OSCertHandles& intermediates = |
| 411 verify_result->verified_cert->GetIntermediateCertificates(); | 468 verify_result->verified_cert->GetIntermediateCertificates(); |
| 412 | 469 |
| 413 // If there are no intermediates, then the leaf is trusted or verification | 470 // If there are no intermediates, then the leaf is trusted or verification |
| 414 // failed. | 471 // failed. |
| 415 if (intermediates.empty()) | 472 if (intermediates.empty()) |
| 416 return; | 473 return; |
| 417 | 474 |
| 418 DCHECK(!verify_result->has_sha1); | 475 DCHECK(!verify_result->has_sha1); |
| 419 | 476 |
| 420 // Fill in hash algorithms for the leaf certificate. | 477 // Fill in hash algorithms for the leaf certificate. |
| 421 MapHashAlgorithmToBool(X509Certificate::GetSignatureHashAlgorithm( | 478 InspectSignatureAlgorithmForCert( |
| 422 verify_result->verified_cert->os_cert_handle()), | 479 verify_result->verified_cert->os_cert_handle(), verify_result, |
| 423 verify_result); | 480 has_mismatched_signature_algorithms, has_unknown_signature_algorithms); |
| 424 verify_result->has_sha1_leaf = verify_result->has_sha1; | 481 verify_result->has_sha1_leaf = verify_result->has_sha1; |
| 425 | 482 |
| 426 // Fill in hash algorithms for the intermediate cerificates, excluding the | 483 // Fill in hash algorithms for the intermediate cerificates, excluding the |
| 427 // final one (which is the trust anchor). | 484 // final one (which is presumably the trust anchor; may be incorrect for |
| 485 // partial chains). | |
| 428 for (size_t i = 0; i + 1 < intermediates.size(); ++i) { | 486 for (size_t i = 0; i + 1 < intermediates.size(); ++i) { |
| 429 MapHashAlgorithmToBool( | 487 InspectSignatureAlgorithmForCert(intermediates[i], verify_result, |
| 430 X509Certificate::GetSignatureHashAlgorithm(intermediates[i]), | 488 has_mismatched_signature_algorithms, |
| 431 verify_result); | 489 has_unknown_signature_algorithms); |
| 432 } | 490 } |
| 433 } | 491 } |
| 434 | 492 |
| 435 } // namespace | 493 } // namespace |
| 436 | 494 |
| 437 // static | 495 // static |
| 438 CertVerifyProc* CertVerifyProc::CreateDefault() { | 496 CertVerifyProc* CertVerifyProc::CreateDefault() { |
| 439 #if defined(USE_NSS_CERTS) | 497 #if defined(USE_NSS_CERTS) |
| 440 return new CertVerifyProcNSS(); | 498 return new CertVerifyProcNSS(); |
| 441 #elif defined(USE_OPENSSL_CERTS) && !defined(OS_ANDROID) | 499 #elif defined(USE_OPENSSL_CERTS) && !defined(OS_ANDROID) |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 476 // We do online revocation checking for EV certificates that aren't covered | 534 // We do online revocation checking for EV certificates that aren't covered |
| 477 // by a fresh CRLSet. | 535 // by a fresh CRLSet. |
| 478 // TODO(rsleevi): http://crbug.com/142974 - Allow preferences to fully | 536 // TODO(rsleevi): http://crbug.com/142974 - Allow preferences to fully |
| 479 // disable revocation checking. | 537 // disable revocation checking. |
| 480 if (flags & CertVerifier::VERIFY_EV_CERT) | 538 if (flags & CertVerifier::VERIFY_EV_CERT) |
| 481 flags |= CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY; | 539 flags |= CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY; |
| 482 | 540 |
| 483 int rv = VerifyInternal(cert, hostname, ocsp_response, flags, crl_set, | 541 int rv = VerifyInternal(cert, hostname, ocsp_response, flags, crl_set, |
| 484 additional_trust_anchors, verify_result); | 542 additional_trust_anchors, verify_result); |
| 485 | 543 |
| 486 ComputeSignatureHashAlgorithms(verify_result); | 544 // Look through all the signature algorithms in the chain. |
| 545 bool has_mismatched_signature_algorithms = false; | |
| 546 bool has_unknown_signature_algorithms = false; | |
| 547 InspectSignatureAlgorithms(verify_result, | |
| 548 &has_mismatched_signature_algorithms, | |
| 549 &has_unknown_signature_algorithms); | |
| 550 if (has_mismatched_signature_algorithms || has_unknown_signature_algorithms) { | |
| 551 verify_result->cert_status |= CERT_STATUS_INVALID; | |
| 552 rv = MapCertStatusToNetError(verify_result->cert_status); | |
| 553 } | |
| 487 | 554 |
| 488 if (!cert->VerifyNameMatch(hostname, | 555 if (!cert->VerifyNameMatch(hostname, |
| 489 &verify_result->common_name_fallback_used)) { | 556 &verify_result->common_name_fallback_used)) { |
| 490 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | 557 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; |
| 491 rv = MapCertStatusToNetError(verify_result->cert_status); | 558 rv = MapCertStatusToNetError(verify_result->cert_status); |
| 492 } | 559 } |
| 493 | 560 |
| 494 UMA_HISTOGRAM_BOOLEAN("Net.CertCommonNameFallback", | 561 UMA_HISTOGRAM_BOOLEAN("Net.CertCommonNameFallback", |
| 495 verify_result->common_name_fallback_used); | 562 verify_result->common_name_fallback_used); |
| 496 if (!verify_result->is_issued_by_known_root) { | 563 if (!verify_result->is_issued_by_known_root) { |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 839 return true; | 906 return true; |
| 840 | 907 |
| 841 return false; | 908 return false; |
| 842 } | 909 } |
| 843 | 910 |
| 844 // static | 911 // static |
| 845 const base::Feature CertVerifyProc::kSHA1LegacyMode{ | 912 const base::Feature CertVerifyProc::kSHA1LegacyMode{ |
| 846 "SHA1LegacyMode", base::FEATURE_DISABLED_BY_DEFAULT}; | 913 "SHA1LegacyMode", base::FEATURE_DISABLED_BY_DEFAULT}; |
| 847 | 914 |
| 848 } // namespace net | 915 } // namespace net |
| OLD | NEW |