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 |