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

Side by Side Diff: net/cert/internal/verify_certificate_chain.cc

Issue 2832703002: Allow the TrustStore interface to return matching intermediates, and identify distrusted certs. (Closed)
Patch Set: fix cert_verify_tool Created 3 years, 7 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
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/internal/verify_certificate_chain.h" 5 #include "net/cert/internal/verify_certificate_chain.h"
6 6
7 #include <memory> 7 #include <memory>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
(...skipping 19 matching lines...) Expand all
30 // ----------------------------------------------- 30 // -----------------------------------------------
31 // Errors/Warnings set by VerifyCertificateChain 31 // Errors/Warnings set by VerifyCertificateChain
32 // ----------------------------------------------- 32 // -----------------------------------------------
33 33
34 DEFINE_CERT_ERROR_ID( 34 DEFINE_CERT_ERROR_ID(
35 kSignatureAlgorithmMismatch, 35 kSignatureAlgorithmMismatch,
36 "Certificate.signatureAlgorithm != TBSCertificate.signature"); 36 "Certificate.signatureAlgorithm != TBSCertificate.signature");
37 DEFINE_CERT_ERROR_ID(kInvalidOrUnsupportedSignatureAlgorithm, 37 DEFINE_CERT_ERROR_ID(kInvalidOrUnsupportedSignatureAlgorithm,
38 "Invalid or unsupported signature algorithm"); 38 "Invalid or unsupported signature algorithm");
39 DEFINE_CERT_ERROR_ID(kChainIsEmpty, "Chain is empty"); 39 DEFINE_CERT_ERROR_ID(kChainIsEmpty, "Chain is empty");
40 DEFINE_CERT_ERROR_ID(kChainIsLength1,
41 "TODO: Cannot verify a chain of length 1");
40 DEFINE_CERT_ERROR_ID(kUnconsumedCriticalExtension, 42 DEFINE_CERT_ERROR_ID(kUnconsumedCriticalExtension,
41 "Unconsumed critical extension"); 43 "Unconsumed critical extension");
42 DEFINE_CERT_ERROR_ID( 44 DEFINE_CERT_ERROR_ID(
43 kTargetCertInconsistentCaBits, 45 kTargetCertInconsistentCaBits,
44 "Target certificate looks like a CA but does not set all CA properties"); 46 "Target certificate looks like a CA but does not set all CA properties");
45 DEFINE_CERT_ERROR_ID(kKeyCertSignBitNotSet, "keyCertSign bit is not set"); 47 DEFINE_CERT_ERROR_ID(kKeyCertSignBitNotSet, "keyCertSign bit is not set");
46 DEFINE_CERT_ERROR_ID(kMaxPathLengthViolated, "max_path_length reached"); 48 DEFINE_CERT_ERROR_ID(kMaxPathLengthViolated, "max_path_length reached");
47 DEFINE_CERT_ERROR_ID(kBasicConstraintsIndicatesNotCa, 49 DEFINE_CERT_ERROR_ID(kBasicConstraintsIndicatesNotCa,
48 "Basic Constraints indicates not a CA"); 50 "Basic Constraints indicates not a CA");
49 DEFINE_CERT_ERROR_ID(kMissingBasicConstraints, 51 DEFINE_CERT_ERROR_ID(kMissingBasicConstraints,
50 "Does not have Basic Constraints"); 52 "Does not have Basic Constraints");
51 DEFINE_CERT_ERROR_ID(kNotPermittedByNameConstraints, 53 DEFINE_CERT_ERROR_ID(kNotPermittedByNameConstraints,
52 "Not permitted by name constraints"); 54 "Not permitted by name constraints");
53 DEFINE_CERT_ERROR_ID(kSubjectDoesNotMatchIssuer, 55 DEFINE_CERT_ERROR_ID(kSubjectDoesNotMatchIssuer,
54 "subject does not match issuer"); 56 "subject does not match issuer");
55 DEFINE_CERT_ERROR_ID(kVerifySignedDataFailed, "VerifySignedData failed"); 57 DEFINE_CERT_ERROR_ID(kVerifySignedDataFailed, "VerifySignedData failed");
56 DEFINE_CERT_ERROR_ID(kSignatureAlgorithmsDifferentEncoding, 58 DEFINE_CERT_ERROR_ID(kSignatureAlgorithmsDifferentEncoding,
57 "Certificate.signatureAlgorithm is encoded differently " 59 "Certificate.signatureAlgorithm is encoded differently "
58 "than TBSCertificate.signature"); 60 "than TBSCertificate.signature");
59 DEFINE_CERT_ERROR_ID(kEkuLacksServerAuth, 61 DEFINE_CERT_ERROR_ID(kEkuLacksServerAuth,
60 "The extended key usage does not include server auth"); 62 "The extended key usage does not include server auth");
61 DEFINE_CERT_ERROR_ID(kEkuLacksClientAuth, 63 DEFINE_CERT_ERROR_ID(kEkuLacksClientAuth,
62 "The extended key usage does not include client auth"); 64 "The extended key usage does not include client auth");
65 DEFINE_CERT_ERROR_ID(kCertIsDistrusted, "Certificate is distrusted");
66 DEFINE_CERT_ERROR_ID(kCertIsNotTrustAnchor,
67 "Certificate is not a trust anchor");
63 68
64 bool IsHandledCriticalExtensionOid(const der::Input& oid) { 69 bool IsHandledCriticalExtensionOid(const der::Input& oid) {
65 if (oid == BasicConstraintsOid()) 70 if (oid == BasicConstraintsOid())
66 return true; 71 return true;
67 // Key Usage is NOT processed for end-entity certificates (this is the 72 // Key Usage is NOT processed for end-entity certificates (this is the
68 // responsibility of callers), however it is considered "handled" here in 73 // responsibility of callers), however it is considered "handled" here in
69 // order to allow being marked as critical. 74 // order to allow being marked as critical.
70 if (oid == KeyUsageOid()) 75 if (oid == KeyUsageOid())
71 return true; 76 return true;
72 if (oid == ExtKeyUsageOid()) 77 if (oid == ExtKeyUsageOid())
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 VerifyNoUnconsumedCriticalExtensions(cert, errors); 437 VerifyNoUnconsumedCriticalExtensions(cert, errors);
433 438
434 // TODO(eroman): Step g is omitted, as policy constraints are not yet 439 // TODO(eroman): Step g is omitted, as policy constraints are not yet
435 // implemented. 440 // implemented.
436 441
437 // The following check is NOT part of RFC 5280 6.1.5's "Wrap-Up Procedure", 442 // The following check is NOT part of RFC 5280 6.1.5's "Wrap-Up Procedure",
438 // however is implied by RFC 5280 section 4.2.1.9. 443 // however is implied by RFC 5280 section 4.2.1.9.
439 VerifyTargetCertHasConsistentCaBits(cert, errors); 444 VerifyTargetCertHasConsistentCaBits(cert, errors);
440 } 445 }
441 446
442 // Initializes the path validation algorithm given anchor constraints. This 447 // Enforces trust anchor constraints compatibile with RFC 5937.
443 // follows the description in RFC 5937 448 //
444 void ProcessTrustAnchorConstraints( 449 // Note that the anchor constraints are encoded via the attached certificate
445 const TrustAnchor& trust_anchor, 450 // itself.
451 void ApplyTrustAnchorConstraints(
452 const ParsedCertificate& cert,
446 KeyPurpose required_key_purpose, 453 KeyPurpose required_key_purpose,
447 size_t* max_path_length_ptr, 454 size_t* max_path_length_ptr,
448 std::vector<const NameConstraints*>* name_constraints_list, 455 std::vector<const NameConstraints*>* name_constraints_list,
449 CertErrors* errors) { 456 CertErrors* errors) {
450 // In RFC 5937 the enforcement of anchor constraints is governed by the input
451 // enforceTrustAnchorConstraints to path validation. In our implementation
452 // this is always on, and enforcement is controlled solely by whether or not
453 // the trust anchor specified constraints.
454 if (!trust_anchor.enforces_constraints())
455 return;
456
457 // Anchor constraints are encoded via the attached certificate.
458 const ParsedCertificate& cert = *trust_anchor.cert();
459
460 // This is not part of RFC 5937 nor RFC 5280, but matches the EKU handling 457 // This is not part of RFC 5937 nor RFC 5280, but matches the EKU handling
461 // done for intermediates (described in Web PKI's Baseline Requirements). 458 // done for intermediates (described in Web PKI's Baseline Requirements).
462 VerifyExtendedKeyUsage(cert, required_key_purpose, errors); 459 VerifyExtendedKeyUsage(cert, required_key_purpose, errors);
463 460
464 // The following enforcements follow from RFC 5937 (primarily section 3.2): 461 // The following enforcements follow from RFC 5937 (primarily section 3.2):
465 462
466 // Initialize name constraints initial-permitted/excluded-subtrees. 463 // Initialize name constraints initial-permitted/excluded-subtrees.
467 if (cert.has_name_constraints()) 464 if (cert.has_name_constraints())
468 name_constraints_list->push_back(&cert.name_constraints()); 465 name_constraints_list->push_back(&cert.name_constraints());
469 466
(...skipping 21 matching lines...) Expand all
491 *max_path_length_ptr = cert.basic_constraints().path_len; 488 *max_path_length_ptr = cert.basic_constraints().path_len;
492 489
493 // From RFC 5937 section 2: 490 // From RFC 5937 section 2:
494 // 491 //
495 // Extensions may be marked critical or not critical. When trust anchor 492 // Extensions may be marked critical or not critical. When trust anchor
496 // constraints are enforced, clients MUST reject certification paths 493 // constraints are enforced, clients MUST reject certification paths
497 // containing a trust anchor with unrecognized critical extensions. 494 // containing a trust anchor with unrecognized critical extensions.
498 VerifyNoUnconsumedCriticalExtensions(cert, errors); 495 VerifyNoUnconsumedCriticalExtensions(cert, errors);
499 } 496 }
500 497
498 // Initializes the path validation algorithm given anchor constraints. This
499 // follows the description in RFC 5937
500 void ProcessRootCertificate(
501 const ParsedCertificate& cert,
502 const CertificateTrust& trust,
503 KeyPurpose required_key_purpose,
504 size_t* max_path_length_ptr,
505 std::vector<const NameConstraints*>* name_constraints_list,
506 der::Input* working_spki,
507 der::Input* working_normalized_issuer_name,
508 CertErrors* errors) {
509 switch (trust.type) {
510 case CertificateTrustType::UNSPECIFIED:
511 // Doesn't chain to a trust anchor - implicitly distrusted
512 errors->AddError(kCertIsNotTrustAnchor);
513 return;
mattm 2017/04/28 20:26:47 working_spki and working_normalized_issuer_name ar
eroman 2017/04/28 21:48:04 Good point. I don't currently have tests for thos
514 case CertificateTrustType::DISTRUSTED:
515 // Chains to an actively distrusted certificate.
516 errors->AddError(kCertIsDistrusted);
517 return;
518 case CertificateTrustType::TRUSTED_ANCHOR:
519 case CertificateTrustType::TRUSTED_ANCHOR_WITH_CONSTRAINTS:
520 // Chains to a trust anchor - use its SPKI and subject when verifying the
521 // next certificate.
522 *working_spki = cert.tbs().spki_tlv;
523 *working_normalized_issuer_name = cert.normalized_subject();
524
525 // If the trust anchor has constraints, enforce them.
526 if (trust.type == CertificateTrustType::TRUSTED_ANCHOR_WITH_CONSTRAINTS) {
527 ApplyTrustAnchorConstraints(cert, required_key_purpose,
528 max_path_length_ptr, name_constraints_list,
529 errors);
530 }
531 return;
532 }
533 }
534
535 } // namespace
536
501 // This implementation is structured to mimic the description of certificate 537 // This implementation is structured to mimic the description of certificate
502 // path verification given by RFC 5280 section 6.1. 538 // path verification given by RFC 5280 section 6.1.
503 void VerifyCertificateChainNoReturnValue( 539 void VerifyCertificateChain(const ParsedCertificateList& certs,
504 const ParsedCertificateList& certs, 540 const CertificateTrust& last_cert_trust,
505 const TrustAnchor* trust_anchor, 541 const SignaturePolicy* signature_policy,
506 const SignaturePolicy* signature_policy, 542 const der::GeneralizedTime& time,
507 const der::GeneralizedTime& time, 543 KeyPurpose required_key_purpose,
508 KeyPurpose required_key_purpose, 544 CertPathErrors* errors) {
509 CertPathErrors* errors) {
510 DCHECK(trust_anchor);
511 DCHECK(signature_policy); 545 DCHECK(signature_policy);
512 DCHECK(errors); 546 DCHECK(errors);
513 547
514 // An empty chain is necessarily invalid. 548 // An empty chain is necessarily invalid.
515 if (certs.empty()) { 549 if (certs.empty()) {
516 errors->GetOtherErrors()->AddError(kChainIsEmpty); 550 errors->GetOtherErrors()->AddError(kChainIsEmpty);
517 return; 551 return;
518 } 552 }
519 553
554 // TODO(eroman): Verifying a trusted leaf certificate is not currently
555 // permitted.
556 if (certs.size() == 1) {
557 errors->GetOtherErrors()->AddError(kChainIsLength1);
558 return;
559 }
560
520 // Will contain a NameConstraints for each previous cert in the chain which 561 // Will contain a NameConstraints for each previous cert in the chain which
521 // had nameConstraints. This corresponds to the permitted_subtrees and 562 // had nameConstraints. This corresponds to the permitted_subtrees and
522 // excluded_subtrees state variables from RFC 5280. 563 // excluded_subtrees state variables from RFC 5280.
523 std::vector<const NameConstraints*> name_constraints_list; 564 std::vector<const NameConstraints*> name_constraints_list;
524 565
525 // |working_spki| is an amalgamation of 3 separate variables from RFC 5280: 566 // |working_spki| is an amalgamation of 3 separate variables from RFC 5280:
526 // * working_public_key 567 // * working_public_key
527 // * working_public_key_algorithm 568 // * working_public_key_algorithm
528 // * working_public_key_parameters 569 // * working_public_key_parameters
529 // 570 //
530 // They are combined for simplicity since the signature verification takes an 571 // They are combined for simplicity since the signature verification takes an
531 // SPKI, and the parameter inheritence is not applicable for the supported 572 // SPKI, and the parameter inheritence is not applicable for the supported
532 // key types. 573 // key types.
533 // 574 //
534 // An approximate explanation of |working_spki| is this description from RFC 575 // An approximate explanation of |working_spki| is this description from RFC
535 // 5280 section 6.1.2: 576 // 5280 section 6.1.2:
536 // 577 //
537 // working_public_key: the public key used to verify the 578 // working_public_key: the public key used to verify the
538 // signature of a certificate. 579 // signature of a certificate.
539 der::Input working_spki = trust_anchor->spki(); 580 der::Input working_spki;
540 581
541 // |working_normalized_issuer_name| is the normalized value of the 582 // |working_normalized_issuer_name| is the normalized value of the
542 // working_issuer_name variable in RFC 5280 section 6.1.2: 583 // working_issuer_name variable in RFC 5280 section 6.1.2:
543 // 584 //
544 // working_issuer_name: the issuer distinguished name expected 585 // working_issuer_name: the issuer distinguished name expected
545 // in the next certificate in the chain. 586 // in the next certificate in the chain.
546 der::Input working_normalized_issuer_name = 587 der::Input working_normalized_issuer_name;
547 trust_anchor->normalized_subject();
548 588
549 // |max_path_length| corresponds with the same named variable in RFC 5280 589 // |max_path_length| corresponds with the same named variable in RFC 5280
550 // section 6.1.2: 590 // section 6.1.2:
551 // 591 //
552 // max_path_length: this integer is initialized to n, is 592 // max_path_length: this integer is initialized to n, is
553 // decremented for each non-self-issued certificate in the path, 593 // decremented for each non-self-issued certificate in the path,
554 // and may be reduced to the value in the path length constraint 594 // and may be reduced to the value in the path length constraint
555 // field within the basic constraints extension of a CA 595 // field within the basic constraints extension of a CA
556 // certificate. 596 // certificate.
557 size_t max_path_length = certs.size(); 597 size_t max_path_length = certs.size();
558 598
559 // Apply any trust anchor constraints per RFC 5937. 599 // Iterate over all the certificates in the reverse direction: starting from
600 // the root certificate and progressing towards the target certificate.
560 // 601 //
561 // TODO(eroman): Errors on the trust anchor are put into a certificate bucket 602 // * i=0 : Root certificate (i.e. trust anchor)
562 // GetErrorsForCert(certs.size()). This is a bit magical, and 603 // * i=1 : Certificated signed by the root certificate
563 // has some integration issues. 604 // * i=certs.size()-1 : Target certificate.
564 ProcessTrustAnchorConstraints(*trust_anchor, required_key_purpose,
565 &max_path_length, &name_constraints_list,
566 errors->GetErrorsForCert(certs.size()));
567
568 // Iterate over all the certificates in the reverse direction: starting from
569 // the certificate signed by trust anchor and progressing towards the target
570 // certificate.
571 //
572 // Note that |i| uses 0-based indexing whereas in RFC 5280 it is 1-based.
573 //
574 // * i=0 : Certificated signed by trust anchor.
575 // * i=N-1 : Target certificate.
576 for (size_t i = 0; i < certs.size(); ++i) { 605 for (size_t i = 0; i < certs.size(); ++i) {
577 const size_t index_into_certs = certs.size() - i - 1; 606 const size_t index_into_certs = certs.size() - i - 1;
578 607
579 // |is_target_cert| is true if the current certificate is the target 608 // |is_target_cert| is true if the current certificate is the target
580 // certificate being verified. The target certificate isn't necessarily an 609 // certificate being verified. The target certificate isn't necessarily an
581 // end-entity certificate. 610 // end-entity certificate.
582 const bool is_target_cert = index_into_certs == 0; 611 const bool is_target_cert = index_into_certs == 0;
612 const bool is_root_cert = i == 0;
583 613
584 const ParsedCertificate& cert = *certs[index_into_certs]; 614 const ParsedCertificate& cert = *certs[index_into_certs];
585 615
586 // Output errors for the current certificate into an error bucket that is 616 // Output errors for the current certificate into an error bucket that is
587 // associated with that certificate. 617 // associated with that certificate.
588 CertErrors* cert_errors = errors->GetErrorsForCert(index_into_certs); 618 CertErrors* cert_errors = errors->GetErrorsForCert(index_into_certs);
589 619
620 if (is_root_cert) {
621 ProcessRootCertificate(cert, last_cert_trust, required_key_purpose,
622 &max_path_length, &name_constraints_list,
623 &working_spki, &working_normalized_issuer_name,
624 cert_errors);
625
626 // Don't do any other checks for root certificates.
627 continue;
628 }
629
590 // Per RFC 5280 section 6.1: 630 // Per RFC 5280 section 6.1:
591 // * Do basic processing for each certificate 631 // * Do basic processing for each certificate
592 // * If it is the last certificate in the path (target certificate) 632 // * If it is the last certificate in the path (target certificate)
593 // - Then run "Wrap up" 633 // - Then run "Wrap up"
594 // - Otherwise run "Prepare for Next cert" 634 // - Otherwise run "Prepare for Next cert"
595 BasicCertificateProcessing(cert, is_target_cert, signature_policy, time, 635 BasicCertificateProcessing(cert, is_target_cert, signature_policy, time,
596 working_spki, working_normalized_issuer_name, 636 working_spki, working_normalized_issuer_name,
597 name_constraints_list, cert_errors); 637 name_constraints_list, cert_errors);
598 638
599 // The key purpose is checked not just for the end-entity certificate, but 639 // The key purpose is checked not just for the end-entity certificate, but
(...skipping 10 matching lines...) Expand all
610 WrapUp(cert, cert_errors); 650 WrapUp(cert, cert_errors);
611 } 651 }
612 } 652 }
613 653
614 // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1: 654 // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1:
615 // 655 //
616 // A certificate MUST NOT appear more than once in a prospective 656 // A certificate MUST NOT appear more than once in a prospective
617 // certification path. 657 // certification path.
618 } 658 }
619 659
620 } // namespace
621
622 bool VerifyCertificateChain(const ParsedCertificateList& certs,
623 const TrustAnchor* trust_anchor,
624 const SignaturePolicy* signature_policy,
625 const der::GeneralizedTime& time,
626 KeyPurpose required_key_purpose,
627 CertPathErrors* errors) {
628 // TODO(eroman): This function requires that |errors| is empty upon entry,
629 // which is not part of the API contract.
630 DCHECK(!errors->ContainsHighSeverityErrors());
631 VerifyCertificateChainNoReturnValue(certs, trust_anchor, signature_policy,
632 time, required_key_purpose, errors);
633 return !errors->ContainsHighSeverityErrors();
634 }
635
636 } // namespace net 660 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698