Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(111)

Side by Side Diff: net/cert/cert_verify_proc.cc

Issue 2731603002: Check TBSCertificate.algorithm and Certificate.signatureAlgorithm for (Closed)
Patch Set: Use rsleevi's background comment Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/cert/asn1_util.cc ('k') | net/cert/cert_verify_proc_mac.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 unknown or mismatched.
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 std::unique_ptr<SignatureAlgorithm> 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() sets |verify_result->has_*| based on
447 // the signature algorithms used in the chain, and also checks that certificates
448 // don't have contradictory signature algorithms.
404 // 449 //
405 // Whereas if verification was uncessful, the chain may be partial, and the 450 // Returns false if any signature algorithm in the chain is unknown or
406 // final certificate may not be a trust anchor. This heuristic is used 451 // mismatched.
407 // in both successful and failed verifications, despite this ambiguity (failure 452 //
408 // to tag one of the signature algorithms should only affect the final error). 453 // Background:
409 void ComputeSignatureHashAlgorithms(CertVerifyResult* verify_result) { 454 //
455 // X.509 certificates contain two redundant descriptors for the signature
456 // algorithm; one is covered by the signature, but in order to verify the
457 // signature, the other signature algorithm is untrusted.
458 //
459 // RFC 5280 states that the two should be equal, in order to mitigate risk of
460 // signature substitution attacks, but also discourages verifiers from enforcing
461 // the profile of RFC 5280.
462 //
463 // System verifiers are inconsistent - some use the unsigned signature, some use
464 // the signed signature, and they generally do not enforce that both match. This
465 // creates confusion, as it's possible that the signature itself may be checked
466 // using algorithm A, but if subsequent consumers report the certificate
467 // algorithm, they may end up reporting algorithm B, which was not used to
468 // verify the certificate. This function enforces that the two signatures match
469 // in order to prevent such confusion.
470 WARN_UNUSED_RESULT bool InspectSignatureAlgorithmsInChain(
471 CertVerifyResult* verify_result) {
410 const X509Certificate::OSCertHandles& intermediates = 472 const X509Certificate::OSCertHandles& intermediates =
411 verify_result->verified_cert->GetIntermediateCertificates(); 473 verify_result->verified_cert->GetIntermediateCertificates();
412 474
413 // If there are no intermediates, then the leaf is trusted or verification 475 // If there are no intermediates, then the leaf is trusted or verification
414 // failed. 476 // failed.
415 if (intermediates.empty()) 477 if (intermediates.empty())
416 return; 478 return true;
417 479
418 DCHECK(!verify_result->has_sha1); 480 DCHECK(!verify_result->has_sha1);
419 481
420 // Fill in hash algorithms for the leaf certificate. 482 // Fill in hash algorithms for the leaf certificate.
421 MapHashAlgorithmToBool(X509Certificate::GetSignatureHashAlgorithm( 483 if (!InspectSignatureAlgorithmForCert(
422 verify_result->verified_cert->os_cert_handle()), 484 verify_result->verified_cert->os_cert_handle(), verify_result)) {
423 verify_result); 485 return false;
486 }
487
424 verify_result->has_sha1_leaf = verify_result->has_sha1; 488 verify_result->has_sha1_leaf = verify_result->has_sha1;
425 489
426 // Fill in hash algorithms for the intermediate cerificates, excluding the 490 // Fill in hash algorithms for the intermediate cerificates, excluding the
427 // final one (which is the trust anchor). 491 // final one (which is presumably the trust anchor; may be incorrect for
492 // partial chains).
428 for (size_t i = 0; i + 1 < intermediates.size(); ++i) { 493 for (size_t i = 0; i + 1 < intermediates.size(); ++i) {
429 MapHashAlgorithmToBool( 494 if (!InspectSignatureAlgorithmForCert(intermediates[i], verify_result))
430 X509Certificate::GetSignatureHashAlgorithm(intermediates[i]), 495 return false;
431 verify_result);
432 } 496 }
497
498 return true;
433 } 499 }
434 500
435 } // namespace 501 } // namespace
436 502
437 // static 503 // static
438 CertVerifyProc* CertVerifyProc::CreateDefault() { 504 CertVerifyProc* CertVerifyProc::CreateDefault() {
439 #if defined(USE_NSS_CERTS) 505 #if defined(USE_NSS_CERTS)
440 return new CertVerifyProcNSS(); 506 return new CertVerifyProcNSS();
441 #elif defined(USE_OPENSSL_CERTS) && !defined(OS_ANDROID) 507 #elif defined(USE_OPENSSL_CERTS) && !defined(OS_ANDROID)
442 return new CertVerifyProcOpenSSL(); 508 return new CertVerifyProcOpenSSL();
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
476 // We do online revocation checking for EV certificates that aren't covered 542 // We do online revocation checking for EV certificates that aren't covered
477 // by a fresh CRLSet. 543 // by a fresh CRLSet.
478 // TODO(rsleevi): http://crbug.com/142974 - Allow preferences to fully 544 // TODO(rsleevi): http://crbug.com/142974 - Allow preferences to fully
479 // disable revocation checking. 545 // disable revocation checking.
480 if (flags & CertVerifier::VERIFY_EV_CERT) 546 if (flags & CertVerifier::VERIFY_EV_CERT)
481 flags |= CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY; 547 flags |= CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY;
482 548
483 int rv = VerifyInternal(cert, hostname, ocsp_response, flags, crl_set, 549 int rv = VerifyInternal(cert, hostname, ocsp_response, flags, crl_set,
484 additional_trust_anchors, verify_result); 550 additional_trust_anchors, verify_result);
485 551
486 ComputeSignatureHashAlgorithms(verify_result); 552 // Check for mismatched signature algorithms and unknown signature algorithms
553 // in the chain. Also fills in the has_* booleans for the digest algorithms
554 // present in the chain.
555 if (!InspectSignatureAlgorithmsInChain(verify_result)) {
556 verify_result->cert_status |= CERT_STATUS_INVALID;
557 rv = MapCertStatusToNetError(verify_result->cert_status);
558 }
487 559
488 bool allow_common_name_fallback = 560 bool allow_common_name_fallback =
489 !verify_result->is_issued_by_known_root && 561 !verify_result->is_issued_by_known_root &&
490 (flags & CertVerifier::VERIFY_ENABLE_COMMON_NAME_FALLBACK_LOCAL_ANCHORS); 562 (flags & CertVerifier::VERIFY_ENABLE_COMMON_NAME_FALLBACK_LOCAL_ANCHORS);
491 if (!cert->VerifyNameMatch(hostname, allow_common_name_fallback)) { 563 if (!cert->VerifyNameMatch(hostname, allow_common_name_fallback)) {
492 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; 564 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
493 rv = MapCertStatusToNetError(verify_result->cert_status); 565 rv = MapCertStatusToNetError(verify_result->cert_status);
494 } 566 }
495 567
496 CheckOCSP(ocsp_response, *verify_result->verified_cert, 568 CheckOCSP(ocsp_response, *verify_result->verified_cert,
(...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after
834 return true; 906 return true;
835 907
836 return false; 908 return false;
837 } 909 }
838 910
839 // static 911 // static
840 const base::Feature CertVerifyProc::kSHA1LegacyMode{ 912 const base::Feature CertVerifyProc::kSHA1LegacyMode{
841 "SHA1LegacyMode", base::FEATURE_DISABLED_BY_DEFAULT}; 913 "SHA1LegacyMode", base::FEATURE_DISABLED_BY_DEFAULT};
842 914
843 } // namespace net 915 } // namespace net
OLDNEW
« no previous file with comments | « net/cert/asn1_util.cc ('k') | net/cert/cert_verify_proc_mac.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698