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

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

Issue 1890193003: Make Cast certificate verification enforce constraints specified in the trusted root certificate. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix Created 4 years, 8 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 "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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698