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

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: list datafiles for ios (needed following the rebase) 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 <memory> 7 #include <memory>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "net/cert/internal/name_constraints.h" 10 #include "net/cert/internal/name_constraints.h"
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 // to the rules specified in Section 7.1). In general, the issuer and 191 // to the rules specified in Section 7.1). In general, the issuer and
192 // subject of the certificates that make up a path are different for 192 // subject of the certificates that make up a path are different for
193 // each certificate. However, a CA may issue a certificate to itself to 193 // each certificate. However, a CA may issue a certificate to itself to
194 // support key rollover or changes in certificate policies. These 194 // support key rollover or changes in certificate policies. These
195 // self-issued certificates are not counted when evaluating path length 195 // self-issued certificates are not counted when evaluating path length
196 // or name constraints. 196 // or name constraints.
197 WARN_UNUSED_RESULT bool IsSelfIssued(const FullyParsedCert& cert) { 197 WARN_UNUSED_RESULT bool IsSelfIssued(const FullyParsedCert& cert) {
198 return NameMatches(cert.tbs.subject_tlv, cert.tbs.issuer_tlv); 198 return NameMatches(cert.tbs.subject_tlv, cert.tbs.issuer_tlv);
199 } 199 }
200 200
201 // Finds a trust anchor that matches |name| in |trust_store| or returns
202 // nullptr. The returned pointer references data in |trust_store|.
203 //
204 // TODO(eroman): This implementation is linear in the size of the trust store,
205 // and also presumes that all names are unique. In practice it is possible to
206 // have multiple SPKIs with the same name. Also this mechanism of
207 // searching is fairly primitive, and does not take advantage of other
208 // properties like the authority key id.
209 WARN_UNUSED_RESULT const TrustAnchor* FindTrustAnchorByName(
210 const TrustStore& trust_store,
211 const der::Input& name) {
212 for (const auto& anchor : trust_store.anchors) {
213 if (NameMatches(name, der::Input(&anchor.name)))
214 return &anchor;
215 }
216 return nullptr;
217 }
218
219 // Returns true if |cert| is valid at time |time|. 201 // Returns true if |cert| is valid at time |time|.
220 // 202 //
221 // The certificate's validity requirements are described by RFC 5280 section 203 // The certificate's validity requirements are described by RFC 5280 section
222 // 4.1.2.5: 204 // 4.1.2.5:
223 // 205 //
224 // The validity period for a certificate is the period of time from 206 // The validity period for a certificate is the period of time from
225 // notBefore through notAfter, inclusive. 207 // notBefore through notAfter, inclusive.
226 WARN_UNUSED_RESULT bool VerifyTimeValidity(const FullyParsedCert& cert, 208 WARN_UNUSED_RESULT bool VerifyTimeValidity(const FullyParsedCert& cert,
227 const der::GeneralizedTime time) { 209 const der::GeneralizedTime time) {
228 return !(time < cert.tbs.validity_not_before) && 210 return !(time < cert.tbs.validity_not_before) &&
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 const der::Input& alg2_tlv = cert.tbs.signature_algorithm_tlv; 248 const der::Input& alg2_tlv = cert.tbs.signature_algorithm_tlv;
267 249
268 // Ensure that the two DER-encoded signature algorithms are byte-for-byte 250 // Ensure that the two DER-encoded signature algorithms are byte-for-byte
269 // equal, but make a compatibility concession for RSA with SHA1. 251 // equal, but make a compatibility concession for RSA with SHA1.
270 return alg1_tlv == alg2_tlv || (IsRsaWithSha1SignatureAlgorithm(alg1_tlv) && 252 return alg1_tlv == alg2_tlv || (IsRsaWithSha1SignatureAlgorithm(alg1_tlv) &&
271 IsRsaWithSha1SignatureAlgorithm(alg2_tlv)); 253 IsRsaWithSha1SignatureAlgorithm(alg2_tlv));
272 } 254 }
273 255
274 // This function corresponds to RFC 5280 section 6.1.3's "Basic Certificate 256 // This function corresponds to RFC 5280 section 6.1.3's "Basic Certificate
275 // Processing" procedure. 257 // Processing" procedure.
258 //
259 // |skip_issuer_checks| controls whether the function will skip:
260 // - Checking that |cert|'s signature using |working_spki|
261 // - Checkinging that |cert|'s issuer matches |working_issuer_name|
262 // This should be set to true only when verifying a trusted root certificate.
276 WARN_UNUSED_RESULT bool BasicCertificateProcessing( 263 WARN_UNUSED_RESULT bool BasicCertificateProcessing(
277 const FullyParsedCert& cert, 264 const FullyParsedCert& cert,
278 bool is_target_cert, 265 bool is_target_cert,
266 bool skip_issuer_checks,
279 const SignaturePolicy* signature_policy, 267 const SignaturePolicy* signature_policy,
280 const der::GeneralizedTime& time, 268 const der::GeneralizedTime& time,
281 const der::Input& working_spki, 269 const der::Input& working_spki,
282 const der::Input& working_issuer_name, 270 const der::Input& working_issuer_name,
283 const std::vector<std::unique_ptr<NameConstraints>>& 271 const std::vector<std::unique_ptr<NameConstraints>>&
284 name_constraints_list) { 272 name_constraints_list) {
285 // Check that the signature algorithms in Certificate vs TBSCertificate 273 // Check that the signature algorithms in Certificate vs TBSCertificate
286 // match. This isn't part of RFC 5280 section 6.1.3, but is mandated by 274 // match. This isn't part of RFC 5280 section 6.1.3, but is mandated by
287 // sections 4.1.1.2 and 4.1.2.3. 275 // sections 4.1.1.2 and 4.1.2.3.
288 if (!VerifySignatureAlgorithmsMatch(cert)) 276 if (!VerifySignatureAlgorithmsMatch(cert))
289 return false; 277 return false;
290 278
291 // Verify the digital signature using the previous certificate's (or trust 279 // Verify the digital signature using the previous certificate's key (RFC
292 // anchor's) key (RFC 5280 section 6.1.3 step a.1). 280 // 5280 section 6.1.3 step a.1).
293 if (!VerifySignedData( 281 if (!skip_issuer_checks) {
294 *cert.signature_algorithm, cert.cert.tbs_certificate_tlv, 282 if (!VerifySignedData(
295 cert.cert.signature_value, working_spki, signature_policy)) { 283 *cert.signature_algorithm, cert.cert.tbs_certificate_tlv,
296 return false; 284 cert.cert.signature_value, working_spki, signature_policy)) {
285 return false;
286 }
297 } 287 }
298 288
299 // Check the time range for the certificate's validity, ensuring it is valid 289 // Check the time range for the certificate's validity, ensuring it is valid
300 // at |time|. 290 // at |time|.
301 // (RFC 5280 section 6.1.3 step a.2) 291 // (RFC 5280 section 6.1.3 step a.2)
302 if (!VerifyTimeValidity(cert, time)) 292 if (!VerifyTimeValidity(cert, time))
303 return false; 293 return false;
304 294
305 // TODO(eroman): Check revocation (RFC 5280 section 6.1.3 step a.3) 295 // TODO(eroman): Check revocation (RFC 5280 section 6.1.3 step a.3)
306 296
307 // Verify the certificate's issuer name matches the issuing certificate's (or 297 // Verify the certificate's issuer name matches the issuing certificate's
308 // trust anchor's) subject name. (RFC 5280 section 6.1.3 step a.4) 298 // subject name. (RFC 5280 section 6.1.3 step a.4)
309 if (!NameMatches(cert.tbs.issuer_tlv, working_issuer_name)) 299 if (!skip_issuer_checks) {
310 return false; 300 if (!NameMatches(cert.tbs.issuer_tlv, working_issuer_name))
301 return false;
302 }
311 303
312 // Name constraints (RFC 5280 section 6.1.3 step b & c) 304 // Name constraints (RFC 5280 section 6.1.3 step b & c)
313 // If certificate i is self-issued and it is not the final certificate in the 305 // If certificate i is self-issued and it is not the final certificate in the
314 // path, skip this step for certificate i. 306 // path, skip this step for certificate i.
315 if (!name_constraints_list.empty() && 307 if (!name_constraints_list.empty() &&
316 (!IsSelfIssued(cert) || is_target_cert)) { 308 (!IsSelfIssued(cert) || is_target_cert)) {
317 der::Input subject_value; 309 der::Input subject_value;
318 if (!GetSequenceValue(cert.tbs.subject_tlv, &subject_value)) 310 if (!GetSequenceValue(cert.tbs.subject_tlv, &subject_value))
319 return false; 311 return false;
320 for (const auto& nc : name_constraints_list) { 312 for (const auto& nc : name_constraints_list) {
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
495 // The following check is NOT part of RFC 5280 6.1.5's "Wrap-Up Procedure", 487 // The following check is NOT part of RFC 5280 6.1.5's "Wrap-Up Procedure",
496 // however is implied by RFC 5280 section 4.2.1.9. 488 // however is implied by RFC 5280 section 4.2.1.9.
497 if (!VerifyTargetCertHasConsistentCaBits(cert)) 489 if (!VerifyTargetCertHasConsistentCaBits(cert))
498 return false; 490 return false;
499 491
500 return true; 492 return true;
501 } 493 }
502 494
503 } // namespace 495 } // namespace
504 496
497 TrustAnchor::TrustAnchor() {}
505 TrustAnchor::~TrustAnchor() {} 498 TrustAnchor::~TrustAnchor() {}
506 499
500 std::unique_ptr<TrustAnchor> TrustAnchor::CreateFromCertificateData(
501 const uint8_t* data,
502 size_t length,
503 DataSource source) {
504 std::unique_ptr<TrustAnchor> result(new TrustAnchor);
505
506 switch (source) {
507 case DataSource::INTERNAL_COPY:
508 result->cert_data_.assign(data, data + length);
509 result->cert_ =
510 der::Input(result->cert_data_.data(), result->cert_data_.size());
511 break;
512 case DataSource::EXTERNAL_REFERENCE:
513 result->cert_ = der::Input(data, length);
514 break;
515 }
516
517 // Parse the certificate to get its name.
518 ParsedCertificate cert;
519 if (!ParseCertificate(result->cert(), &cert))
520 return nullptr;
521
522 ParsedTbsCertificate tbs;
523 if (!ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs))
524 return nullptr;
525
526 result->name_ = tbs.subject_tlv;
527
528 // TODO(eroman): If adding a self-signed certificate, check that its
529 // signature is correct? This check will not otherwise be done during
530 // verification.
531
532 return result;
533 }
534
535 bool TrustAnchor::MatchesName(const der::Input& name) const {
536 return NameMatches(name, name_);
537 }
538
507 TrustStore::TrustStore() {} 539 TrustStore::TrustStore() {}
508 TrustStore::TrustStore(const TrustStore& other) = default;
509 TrustStore::~TrustStore() {} 540 TrustStore::~TrustStore() {}
510 541
542 void TrustStore::Clear() {
543 anchors_.clear();
544 }
545
546 bool TrustStore::AddTrustedCertificate(const uint8_t* data, size_t length) {
547 return AddTrustedCertificate(data, length,
548 TrustAnchor::DataSource::INTERNAL_COPY);
549 }
550
551 bool TrustStore::AddTrustedCertificate(const base::StringPiece& data) {
552 return AddTrustedCertificate(reinterpret_cast<const uint8_t*>(data.data()),
553 data.size());
554 }
555
556 bool TrustStore::AddTrustedCertificateWithoutCopying(const uint8_t* data,
557 size_t length) {
558 return AddTrustedCertificate(data, length,
559 TrustAnchor::DataSource::EXTERNAL_REFERENCE);
560 }
561
562 const TrustAnchor* TrustStore::FindTrustAnchorByName(
563 const der::Input& name) const {
564 for (const auto& anchor : anchors_) {
565 if (anchor->MatchesName(name)) {
566 return anchor.get();
567 }
568 }
569 return nullptr;
570 }
571
572 bool TrustStore::IsTrustedCertificate(const der::Input& cert_der) const {
573 for (const auto& anchor : anchors_) {
574 if (anchor->cert() == cert_der)
575 return true;
576 }
577 return false;
578 }
579
580 bool TrustStore::AddTrustedCertificate(const uint8_t* data,
581 size_t length,
582 TrustAnchor::DataSource source) {
583 auto anchor = TrustAnchor::CreateFromCertificateData(data, length, source);
584 if (!anchor)
585 return false;
586 anchors_.push_back(std::move(anchor));
587 return true;
588 }
589
590 // TODO(eroman): Move this into existing anonymous namespace.
591 namespace {
592
511 // This implementation is structured to mimic the description of certificate 593 // This implementation is structured to mimic the description of certificate
512 // path verification given by RFC 5280 section 6.1. 594 // path verification given by RFC 5280 section 6.1.
513 bool VerifyCertificateChain(const std::vector<der::Input>& certs_der, 595 //
514 const TrustStore& trust_store, 596 // Unlike RFC 5280, the trust anchor is specified as the root certificate in
515 const SignaturePolicy* signature_policy, 597 // the chain. This root certificate is assumed to be trusted, and neither its
516 const der::GeneralizedTime& time) { 598 // signature nor issuer name are verified. (It needn't be self-signed).
599 bool VerifyCertificateChainAssumingTrustedRoot(
600 const std::vector<der::Input>& certs_der,
601 // The trust store is only used for assertions.
602 const TrustStore& trust_store,
603 const SignaturePolicy* signature_policy,
604 const der::GeneralizedTime& time) {
517 // An empty chain is necessarily invalid. 605 // An empty chain is necessarily invalid.
518 if (certs_der.empty()) 606 if (certs_der.empty())
519 return false; 607 return false;
520 608
609 // IMPORTANT: the assumption being made is that the root certificate in
610 // the given path is the trust anchor (and has already been verified as
611 // such).
612 DCHECK(trust_store.IsTrustedCertificate(certs_der.back()));
613
521 // Will contain a NameConstraints for each previous cert in the chain which 614 // Will contain a NameConstraints for each previous cert in the chain which
522 // had nameConstraints. This corresponds to the permitted_subtrees and 615 // had nameConstraints. This corresponds to the permitted_subtrees and
523 // excluded_subtrees state variables from RFC 5280. 616 // excluded_subtrees state variables from RFC 5280.
524 std::vector<std::unique_ptr<NameConstraints>> name_constraints_list; 617 std::vector<std::unique_ptr<NameConstraints>> name_constraints_list;
525 618
526 // |working_spki| is an amalgamation of 3 separate variables from RFC 5280: 619 // |working_spki| is an amalgamation of 3 separate variables from RFC 5280:
527 // * working_public_key 620 // * working_public_key
528 // * working_public_key_algorithm 621 // * working_public_key_algorithm
529 // * working_public_key_parameters 622 // * working_public_key_parameters
530 // 623 //
531 // They are combined for simplicity since the signature verification takes an 624 // They are combined for simplicity since the signature verification takes an
532 // SPKI, and the parameter inheritence is not applicable for the supported 625 // SPKI, and the parameter inheritence is not applicable for the supported
533 // key types. 626 // key types.
534 // 627 //
535 // An approximate explanation of |working_spki| is this description from RFC 628 // An approximate explanation of |working_spki| is this description from RFC
536 // 5280 section 6.1.2: 629 // 5280 section 6.1.2:
537 // 630 //
538 // working_public_key: the public key used to verify the 631 // working_public_key: the public key used to verify the
539 // signature of a certificate. The working_public_key is 632 // signature of a certificate.
540 // initialized from the trusted public key provided in the trust
541 // anchor information.
542 der::Input working_spki; 633 der::Input working_spki;
543 634
544 // |working_issuer_name| corresponds with the same named variable in RFC 5280 635 // |working_issuer_name| corresponds with the same named variable in RFC 5280
545 // section 6.1.2: 636 // section 6.1.2:
546 // 637 //
547 // working_issuer_name: the issuer distinguished name expected 638 // working_issuer_name: the issuer distinguished name expected
548 // in the next certificate in the chain. The 639 // in the next certificate in the chain.
549 // working_issuer_name is initialized to the trusted issuer name
550 // provided in the trust anchor information.
551 der::Input working_issuer_name; 640 der::Input working_issuer_name;
552 641
553 // |max_path_length| corresponds with the same named variable in RFC 5280 642 // |max_path_length| corresponds with the same named variable in RFC 5280
554 // section 6.1.2: 643 // section 6.1.2:
555 // 644 //
556 // max_path_length: this integer is initialized to n, is 645 // max_path_length: this integer is initialized to n, is
557 // decremented for each non-self-issued certificate in the path, 646 // decremented for each non-self-issued certificate in the path,
558 // and may be reduced to the value in the path length constraint 647 // and may be reduced to the value in the path length constraint
559 // field within the basic constraints extension of a CA 648 // field within the basic constraints extension of a CA
560 // certificate. 649 // certificate.
561 size_t max_path_length = certs_der.size(); 650 size_t max_path_length = certs_der.size();
562 651
563 // Iterate over all the certificates in the reverse direction: starting from 652 // Iterate over all the certificates in the reverse direction: starting from
564 // the trust anchor and progressing towards the target certificate. 653 // the trust anchor and progressing towards the target certificate.
565 // 654 //
566 // Note that |i| uses 0-based indexing whereas in RFC 5280 it is 1-based. 655 // Note that |i| uses 0-based indexing whereas in RFC 5280 it is 1-based.
567 // 656 //
568 // * i=0 : Certificate signed by a trust anchor. 657 // * i=0 : Trust anchor.
569 // * i=N-1 : Target certificate. 658 // * i=N-1 : Target certificate.
570 for (size_t i = 0; i < certs_der.size(); ++i) { 659 for (size_t i = 0; i < certs_der.size(); ++i) {
571 const size_t index_into_certs_der = certs_der.size() - i - 1; 660 const size_t index_into_certs_der = certs_der.size() - i - 1;
661
662 // |is_target_cert| is true if the current certificate is the target
663 // certificate being verified. The target certificate isn't necessarily an
664 // end-entity certificate.
572 const bool is_target_cert = index_into_certs_der == 0; 665 const bool is_target_cert = index_into_certs_der == 0;
573 666
667 // |is_trust_anchor| is true if the current certificate is the trust
668 // anchor. This certificate is implicitly trusted.
669 const bool is_trust_anchor = i == 0;
670
574 // Parse the current certificate into |cert|. 671 // Parse the current certificate into |cert|.
575 FullyParsedCert cert; 672 FullyParsedCert cert;
576 const der::Input& cert_der = certs_der[index_into_certs_der]; 673 const der::Input& cert_der = certs_der[index_into_certs_der];
577 if (!FullyParseCertificate(cert_der, &cert)) 674 if (!FullyParseCertificate(cert_der, &cert))
578 return false; 675 return false;
579 676
580 // When processing the first certificate, initialize |working_spki|
581 // and |working_issuer_name| to the trust anchor per RFC 5280 section 6.1.2.
582 // This is done inside the loop in order to have access to the parsed
583 // certificate.
584 if (i == 0) {
585 const TrustAnchor* trust_anchor =
586 FindTrustAnchorByName(trust_store, cert.tbs.issuer_tlv);
587 if (!trust_anchor)
588 return false;
589 working_spki = der::Input(&trust_anchor->spki);
590 working_issuer_name = der::Input(&trust_anchor->name);
591 }
592
593 // Per RFC 5280 section 6.1: 677 // Per RFC 5280 section 6.1:
594 // * Do basic processing for each certificate 678 // * Do basic processing for each certificate
595 // * If it is the last certificate in the path (target certificate) 679 // * If it is the last certificate in the path (target certificate)
596 // - Then run "Wrap up" 680 // - Then run "Wrap up"
597 // - Otherwise run "Prepare for Next cert" 681 // - Otherwise run "Prepare for Next cert"
598 if (!BasicCertificateProcessing(cert, is_target_cert, signature_policy, 682 if (!BasicCertificateProcessing(
599 time, working_spki, working_issuer_name, 683 cert, is_target_cert, is_trust_anchor, signature_policy, time,
600 name_constraints_list)) { 684 working_spki, working_issuer_name, name_constraints_list)) {
601 return false; 685 return false;
602 } 686 }
603 if (!is_target_cert) { 687 if (!is_target_cert) {
604 if (!PrepareForNextCertificate(cert, &max_path_length, &working_spki, 688 if (!PrepareForNextCertificate(cert, &max_path_length, &working_spki,
605 &working_issuer_name, 689 &working_issuer_name,
606 &name_constraints_list)) { 690 &name_constraints_list)) {
607 return false; 691 return false;
608 } 692 }
609 } else { 693 } else {
610 if (!WrapUp(cert)) 694 if (!WrapUp(cert))
611 return false; 695 return false;
612 } 696 }
613 } 697 }
614 698
615 // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1: 699 // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1:
616 // 700 //
617 // A certificate MUST NOT appear more than once in a prospective 701 // A certificate MUST NOT appear more than once in a prospective
618 // certification path. 702 // certification path.
619 703
620 return true; 704 return true;
621 } 705 }
622 706
707 // TODO(eroman): This function is a temporary hack in the absence of full
708 // path building. It may insert 1 certificate at the root of the
709 // chain to ensure that the path's root certificate is a trust anchor.
710 //
711 // Beyond this no other verification is done on the chain. The caller is
712 // responsible for verifying the subsequent chain's correctness.
713 WARN_UNUSED_RESULT bool BuildSimplePathToTrustAnchor(
714 const std::vector<der::Input>& certs_der,
715 const TrustStore& trust_store,
716 std::vector<der::Input>* certs_der_trusted_root) {
717 // Copy the input chain.
718 *certs_der_trusted_root = certs_der;
719
720 if (certs_der.empty())
721 return false;
722
723 // Check if the current root certificate is trusted. If it is then no
724 // extra work is needed.
725 if (trust_store.IsTrustedCertificate(certs_der_trusted_root->back()))
726 return true;
727
728 // Otherwise if it is not trusted, check whether its issuer is trusted. If
729 // so, make *that* trusted certificate the root. If the issuer is not in
730 // the trust store then give up and fail (this is not full path building).
731 ParsedCertificate cert;
732 ParsedTbsCertificate tbs;
733 if (!ParseCertificate(certs_der.back(), &cert) ||
734 !ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs)) {
735 return false;
736 }
737
738 auto trust_anchor = trust_store.FindTrustAnchorByName(tbs.issuer_tlv);
739 if (!trust_anchor)
740 return false;
741 certs_der_trusted_root->push_back(trust_anchor->cert());
742 return true;
743 }
744
745 } // namespace
746
747 bool VerifyCertificateChain(const std::vector<der::Input>& certs_der,
748 const TrustStore& trust_store,
749 const SignaturePolicy* signature_policy,
750 const der::GeneralizedTime& time) {
751 // Modify the certificate chain so that its root is a trusted certificate.
752 std::vector<der::Input> certs_der_trusted_root;
753 if (!BuildSimplePathToTrustAnchor(certs_der, trust_store,
754 &certs_der_trusted_root)) {
755 return false;
756 }
757
758 // Verify the chain.
759 return VerifyCertificateChainAssumingTrustedRoot(
760 certs_der_trusted_root, trust_store, signature_policy, time);
761 }
762
623 } // namespace net 763 } // namespace net
OLDNEW
« no previous file with comments | « net/cert/internal/verify_certificate_chain.h ('k') | net/cert/internal/verify_certificate_chain_pkits_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698