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 |