Chromium Code Reviews| 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 "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "net/cert/internal/name_constraints.h" | 8 #include "net/cert/internal/name_constraints.h" |
| 9 #include "net/cert/internal/parse_certificate.h" | 9 #include "net/cert/internal/parse_certificate.h" |
| 10 #include "net/cert/internal/signature_algorithm.h" | 10 #include "net/cert/internal/signature_algorithm.h" |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 189 // to the rules specified in Section 7.1). In general, the issuer and | 189 // to the rules specified in Section 7.1). In general, the issuer and |
| 190 // subject of the certificates that make up a path are different for | 190 // subject of the certificates that make up a path are different for |
| 191 // each certificate. However, a CA may issue a certificate to itself to | 191 // each certificate. However, a CA may issue a certificate to itself to |
| 192 // support key rollover or changes in certificate policies. These | 192 // support key rollover or changes in certificate policies. These |
| 193 // self-issued certificates are not counted when evaluating path length | 193 // self-issued certificates are not counted when evaluating path length |
| 194 // or name constraints. | 194 // or name constraints. |
| 195 WARN_UNUSED_RESULT bool IsSelfIssued(const FullyParsedCert& cert) { | 195 WARN_UNUSED_RESULT bool IsSelfIssued(const FullyParsedCert& cert) { |
| 196 return NameMatches(cert.tbs.subject_tlv, cert.tbs.issuer_tlv); | 196 return NameMatches(cert.tbs.subject_tlv, cert.tbs.issuer_tlv); |
| 197 } | 197 } |
| 198 | 198 |
| 199 // Finds a trust anchor that matches |name| in |trust_store| or returns | |
| 200 // nullptr. The returned pointer references data in |trust_store|. | |
| 201 // | |
| 202 // TODO(eroman): This implementation is linear in the size of the trust store, | |
| 203 // and also presumes that all names are unique. In practice it is possible to | |
| 204 // have multiple SPKIs with the same name. Also this mechanism of | |
| 205 // searching is fairly primitive, and does not take advantage of other | |
| 206 // properties like the authority key id. | |
| 207 WARN_UNUSED_RESULT const TrustAnchor* FindTrustAnchorByName( | |
| 208 const TrustStore& trust_store, | |
| 209 const der::Input& name) { | |
| 210 for (const auto& anchor : trust_store.anchors) { | |
| 211 if (NameMatches(name, der::Input(&anchor.name))) | |
| 212 return &anchor; | |
| 213 } | |
| 214 return nullptr; | |
| 215 } | |
| 216 | |
| 217 // Returns true if |cert| is valid at time |time|. | 199 // Returns true if |cert| is valid at time |time|. |
| 218 // | 200 // |
| 219 // The certificate's validity requirements are described by RFC 5280 section | 201 // The certificate's validity requirements are described by RFC 5280 section |
| 220 // 4.1.2.5: | 202 // 4.1.2.5: |
| 221 // | 203 // |
| 222 // The validity period for a certificate is the period of time from | 204 // The validity period for a certificate is the period of time from |
| 223 // notBefore through notAfter, inclusive. | 205 // notBefore through notAfter, inclusive. |
| 224 WARN_UNUSED_RESULT bool VerifyTimeValidity(const FullyParsedCert& cert, | 206 WARN_UNUSED_RESULT bool VerifyTimeValidity(const FullyParsedCert& cert, |
| 225 const der::GeneralizedTime time) { | 207 const der::GeneralizedTime time) { |
| 226 return !(time < cert.tbs.validity_not_before) && | 208 return !(time < cert.tbs.validity_not_before) && |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 493 if (!VerifyTargetCertHasConsistentCaBits(cert)) | 475 if (!VerifyTargetCertHasConsistentCaBits(cert)) |
| 494 return false; | 476 return false; |
| 495 | 477 |
| 496 return true; | 478 return true; |
| 497 } | 479 } |
| 498 | 480 |
| 499 } // namespace | 481 } // namespace |
| 500 | 482 |
| 501 TrustAnchor::~TrustAnchor() {} | 483 TrustAnchor::~TrustAnchor() {} |
| 502 | 484 |
| 485 bool TrustAnchor::AssignCertData(const uint8_t* data, | |
| 486 size_t length, | |
| 487 bool copy) { | |
| 488 // Reset all the fields. | |
| 489 *this = TrustAnchor(); | |
| 490 | |
| 491 if (copy) { | |
| 492 owned_cert_tlv.assign(data, data + length); | |
| 493 cert_tlv = der::Input(&owned_cert_tlv); | |
| 494 } else { | |
| 495 owned_cert_tlv.clear(); | |
| 496 cert_tlv = der::Input(data, length); | |
| 497 } | |
| 498 | |
| 499 if (!ParseCertificate(cert_tlv, &cert)) | |
| 500 return false; | |
| 501 | |
| 502 if (!ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs)) | |
| 503 return false; | |
| 504 | |
| 505 return true; | |
| 506 } | |
| 507 | |
| 503 TrustStore::TrustStore() {} | 508 TrustStore::TrustStore() {} |
| 504 TrustStore::TrustStore(const TrustStore& other) = default; | 509 TrustStore::TrustStore(const TrustStore& other) = default; |
| 505 TrustStore::~TrustStore() {} | 510 TrustStore::~TrustStore() {} |
| 506 | 511 |
| 512 bool TrustStore::AddTrustedCertificate(const uint8_t* data, size_t length) { | |
| 513 TrustAnchor anchor; | |
| 514 if (!anchor.AssignCertData(data, length, true)) | |
| 515 return false; | |
| 516 anchors.push_back(std::move(anchor)); | |
| 517 return true; | |
| 518 } | |
| 519 | |
| 520 bool TrustStore::AddTrustedCertificate(const base::StringPiece& data) { | |
| 521 return AddTrustedCertificate(reinterpret_cast<const uint8_t*>(data.data()), | |
| 522 data.size()); | |
| 523 } | |
| 524 | |
| 525 bool TrustStore::AddTrustedCertificateWithoutCopying(const uint8_t* data, | |
| 526 size_t length) { | |
| 527 TrustAnchor anchor; | |
| 528 if (!anchor.AssignCertData(data, length, false)) | |
| 529 return false; | |
| 530 anchors.push_back(std::move(anchor)); | |
| 531 return true; | |
| 532 } | |
| 533 | |
| 534 const der::Input* TrustStore::FindTrustedCertificateByName( | |
| 535 const der::Input& name) const { | |
| 536 for (const auto& anchor : anchors) { | |
| 537 if (NameMatches(name, anchor.tbs.subject_tlv)) | |
| 538 return &anchor.cert_tlv; | |
| 539 } | |
| 540 return nullptr; | |
| 541 } | |
| 542 | |
| 543 bool TrustStore::IsTrustedCertificate(const der::Input& cert_der) const { | |
| 544 for (const auto& anchor : anchors) { | |
| 545 if (anchor.cert_tlv == cert_der) | |
| 546 return true; | |
| 547 } | |
| 548 return false; | |
| 549 } | |
| 550 | |
| 551 // TODO(eroman): Move this into existing anonymous namespace. | |
| 552 namespace { | |
| 553 | |
| 507 // This implementation is structured to mimic the description of certificate | 554 // This implementation is structured to mimic the description of certificate |
| 508 // path verification given by RFC 5280 section 6.1. | 555 // path verification given by RFC 5280 section 6.1. |
| 509 bool VerifyCertificateChain(const std::vector<der::Input>& certs_der, | 556 // |
| 510 const TrustStore& trust_store, | 557 // Unlike RFC 5280, the trust anchor is specified as the root certificate in |
| 511 const SignaturePolicy* signature_policy, | 558 // the chain. This root certificate is assumed to be trusted -- neither its |
| 512 const der::GeneralizedTime& time) { | 559 // signature nor expiration are checked. |
| 560 bool VerifyCertificateChainAssumingTrustedRoot( | |
| 561 const std::vector<der::Input>& certs_der, | |
| 562 // The trust store is only used for assertions. | |
| 563 const TrustStore& trust_store, | |
| 564 const SignaturePolicy* signature_policy, | |
| 565 const der::GeneralizedTime& time) { | |
| 513 // An empty chain is necessarily invalid. | 566 // An empty chain is necessarily invalid. |
| 514 if (certs_der.empty()) | 567 if (certs_der.empty()) |
| 515 return false; | 568 return false; |
| 516 | 569 |
| 570 // IMPORTANT: the assumption being made is that the root certificate in | |
| 571 // the given path is trusted. | |
| 572 DCHECK(trust_store.IsTrustedCertificate(certs_der.back())); | |
| 573 | |
| 517 // Will contain a NameConstraints for each previous cert in the chain which | 574 // Will contain a NameConstraints for each previous cert in the chain which |
| 518 // had nameConstraints. This corresponds to the permitted_subtrees and | 575 // had nameConstraints. This corresponds to the permitted_subtrees and |
| 519 // excluded_subtrees state variables from RFC 5280. | 576 // excluded_subtrees state variables from RFC 5280. |
| 520 std::vector<scoped_ptr<NameConstraints>> name_constraints_list; | 577 std::vector<scoped_ptr<NameConstraints>> name_constraints_list; |
| 521 | 578 |
| 522 // |working_spki| is an amalgamation of 3 separate variables from RFC 5280: | 579 // |working_spki| is an amalgamation of 3 separate variables from RFC 5280: |
| 523 // * working_public_key | 580 // * working_public_key |
| 524 // * working_public_key_algorithm | 581 // * working_public_key_algorithm |
| 525 // * working_public_key_parameters | 582 // * working_public_key_parameters |
| 526 // | 583 // |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 547 der::Input working_issuer_name; | 604 der::Input working_issuer_name; |
| 548 | 605 |
| 549 // |max_path_length| corresponds with the same named variable in RFC 5280 | 606 // |max_path_length| corresponds with the same named variable in RFC 5280 |
| 550 // section 6.1.2: | 607 // section 6.1.2: |
| 551 // | 608 // |
| 552 // max_path_length: this integer is initialized to n, is | 609 // max_path_length: this integer is initialized to n, is |
| 553 // decremented for each non-self-issued certificate in the path, | 610 // decremented for each non-self-issued certificate in the path, |
| 554 // and may be reduced to the value in the path length constraint | 611 // and may be reduced to the value in the path length constraint |
| 555 // field within the basic constraints extension of a CA | 612 // field within the basic constraints extension of a CA |
| 556 // certificate. | 613 // certificate. |
| 557 size_t max_path_length = certs_der.size(); | 614 size_t max_path_length = certs_der.size(); |
|
mattm
2016/04/16 02:40:29
does this still work correctly now that certs_der.
eroman
2016/04/18 20:43:03
Yes I believe so, although you are correct that th
| |
| 558 | 615 |
| 559 // Iterate over all the certificates in the reverse direction: starting from | 616 // Iterate over all the certificates in the reverse direction: starting from |
| 560 // the trust anchor and progressing towards the target certificate. | 617 // the trust anchor and progressing towards the target certificate. |
| 561 // | 618 // |
| 562 // Note that |i| uses 0-based indexing whereas in RFC 5280 it is 1-based. | 619 // Note that |i| uses 0-based indexing whereas in RFC 5280 it is 1-based. |
| 563 // | 620 // |
| 564 // * i=0 : Certificate signed by a trust anchor. | 621 // * i=0 : Trust anchor. |
| 565 // * i=N-1 : Target certificate. | 622 // * i=N-1 : Target certificate. |
| 566 for (size_t i = 0; i < certs_der.size(); ++i) { | 623 for (size_t i = 0; i < certs_der.size(); ++i) { |
| 567 const size_t index_into_certs_der = certs_der.size() - i - 1; | 624 const size_t index_into_certs_der = certs_der.size() - i - 1; |
| 568 const bool is_target_cert = index_into_certs_der == 0; | 625 const bool is_target_cert = index_into_certs_der == 0; |
| 626 const bool is_trust_anchor_cert = i == 0; | |
| 569 | 627 |
| 570 // Parse the current certificate into |cert|. | 628 // Parse the current certificate into |cert|. |
| 571 FullyParsedCert cert; | 629 FullyParsedCert cert; |
| 572 const der::Input& cert_der = certs_der[index_into_certs_der]; | 630 const der::Input& cert_der = certs_der[index_into_certs_der]; |
| 573 if (!FullyParseCertificate(cert_der, &cert)) | 631 if (!FullyParseCertificate(cert_der, &cert)) |
| 574 return false; | 632 return false; |
| 575 | 633 |
| 576 // When processing the first certificate, initialize |working_spki| | |
| 577 // and |working_issuer_name| to the trust anchor per RFC 5280 section 6.1.2. | |
| 578 // This is done inside the loop in order to have access to the parsed | |
| 579 // certificate. | |
| 580 if (i == 0) { | |
| 581 const TrustAnchor* trust_anchor = | |
| 582 FindTrustAnchorByName(trust_store, cert.tbs.issuer_tlv); | |
| 583 if (!trust_anchor) | |
| 584 return false; | |
| 585 working_spki = der::Input(&trust_anchor->spki); | |
| 586 working_issuer_name = der::Input(&trust_anchor->name); | |
| 587 } | |
| 588 | |
| 589 // Per RFC 5280 section 6.1: | 634 // Per RFC 5280 section 6.1: |
| 590 // * Do basic processing for each certificate | 635 // * Do basic processing for each certificate |
| 591 // * If it is the last certificate in the path (target certificate) | 636 // * If it is the last certificate in the path (target certificate) |
| 592 // - Then run "Wrap up" | 637 // - Then run "Wrap up" |
| 593 // - Otherwise run "Prepare for Next cert" | 638 // - Otherwise run "Prepare for Next cert" |
| 594 if (!BasicCertificateProcessing(cert, is_target_cert, signature_policy, | 639 if (!is_trust_anchor_cert) { |
| 595 time, working_spki, working_issuer_name, | 640 // Note that BasicCertificateProcessing() is skipped for the root |
| 596 name_constraints_list)) { | 641 // certificate as it is implicitly trusted already. It will be |
| 597 return false; | 642 // accepted even if its signature is invalid, or it has expired. |
| 643 if (!BasicCertificateProcessing(cert, is_target_cert, signature_policy, | |
| 644 time, working_spki, working_issuer_name, | |
| 645 name_constraints_list)) { | |
| 646 return false; | |
| 647 } | |
| 598 } | 648 } |
| 599 if (!is_target_cert) { | 649 if (!is_target_cert) { |
| 600 if (!PrepareForNextCertificate(cert, &max_path_length, &working_spki, | 650 if (!PrepareForNextCertificate(cert, &max_path_length, &working_spki, |
| 601 &working_issuer_name, | 651 &working_issuer_name, |
| 602 &name_constraints_list)) { | 652 &name_constraints_list)) { |
| 603 return false; | 653 return false; |
| 604 } | 654 } |
| 605 } else { | 655 } else { |
| 606 if (!WrapUp(cert)) | 656 if (!WrapUp(cert)) |
| 607 return false; | 657 return false; |
| 608 } | 658 } |
| 609 } | 659 } |
| 610 | 660 |
| 611 // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1: | 661 // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1: |
| 612 // | 662 // |
| 613 // A certificate MUST NOT appear more than once in a prospective | 663 // A certificate MUST NOT appear more than once in a prospective |
| 614 // certification path. | 664 // certification path. |
| 615 | 665 |
| 616 return true; | 666 return true; |
| 617 } | 667 } |
| 618 | 668 |
| 669 // TODO(eroman): This function is a temporary hack in the absence of full | |
| 670 // path building. It will insert 0 or 1 certificates at the root of the | |
| 671 // chain to ensure that the path's root certificate is in the trust store. | |
| 672 // Beyond this no other verification is done on the chain. The caller is | |
| 673 // responsible for verifying the chain's correctness. | |
| 674 WARN_UNUSED_RESULT bool BuildSimplePathToTrustAnchor( | |
| 675 const std::vector<der::Input>& certs_der, | |
| 676 const TrustStore& trust_store, | |
| 677 std::vector<der::Input>* certs_der_trusted_root) { | |
| 678 // Copy the input chain. | |
| 679 *certs_der_trusted_root = certs_der; | |
| 680 | |
| 681 if (certs_der.empty()) | |
| 682 return false; | |
| 683 | |
| 684 // Check if the current root certificate is trusted. If it is then no | |
| 685 // extra work is needed. | |
| 686 if (trust_store.IsTrustedCertificate(certs_der_trusted_root->back())) | |
| 687 return true; | |
| 688 | |
| 689 // Otherwise if it is not trusted, check whether its issuer is trusted. If | |
| 690 // so, make *that* trusted certificate the root. If the issuer is not in | |
| 691 // the trust store then give up and fail (this is not full path building). | |
| 692 ParsedCertificate cert; | |
| 693 ParsedTbsCertificate tbs; | |
| 694 if (!ParseCertificate(certs_der.back(), &cert) || | |
| 695 !ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs)) { | |
| 696 return false; | |
| 697 } | |
| 698 | |
| 699 const der::Input* trusted_issuer = | |
| 700 trust_store.FindTrustedCertificateByName(tbs.issuer_tlv); | |
| 701 if (!trusted_issuer) | |
| 702 return false; | |
| 703 certs_der_trusted_root->push_back(*trusted_issuer); | |
| 704 return true; | |
| 705 } | |
| 706 | |
| 707 } // namespace | |
| 708 | |
| 709 bool VerifyCertificateChain(const std::vector<der::Input>& certs_der, | |
| 710 const TrustStore& trust_store, | |
| 711 const SignaturePolicy* signature_policy, | |
| 712 const der::GeneralizedTime& time) { | |
| 713 // Modify the certificate chain so that its root is a trusted certificate. | |
| 714 std::vector<der::Input> certs_der_trusted_root; | |
| 715 if (!BuildSimplePathToTrustAnchor(certs_der, trust_store, | |
| 716 &certs_der_trusted_root)) { | |
| 717 return false; | |
| 718 } | |
| 719 | |
| 720 // Verify the chain. | |
| 721 return VerifyCertificateChainAssumingTrustedRoot( | |
| 722 certs_der_trusted_root, trust_store, signature_policy, time); | |
| 723 } | |
| 724 | |
| 619 } // namespace net | 725 } // namespace net |
| OLD | NEW |