OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |