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

Side by Side Diff: net/base/cert_verify_proc_nss.cc

Issue 10857020: Do not perform online revocation checking when the user has explicitly disabled it, except for when… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Linux and Mac fixes Created 8 years, 4 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/base/cert_verify_proc_nss.h" 5 #include "net/base/cert_verify_proc_nss.h"
6 6
7 #include <cert.h> 7 #include <cert.h>
8 #include <nss.h> 8 #include <nss.h>
9 #include <prerror.h> 9 #include <prerror.h>
10 #include <secerr.h> 10 #include <secerr.h>
(...skipping 10 matching lines...) Expand all
21 #include "net/base/crl_set.h" 21 #include "net/base/crl_set.h"
22 #include "net/base/ev_root_ca_metadata.h" 22 #include "net/base/ev_root_ca_metadata.h"
23 #include "net/base/net_errors.h" 23 #include "net/base/net_errors.h"
24 #include "net/base/x509_certificate.h" 24 #include "net/base/x509_certificate.h"
25 #include "net/base/x509_util_nss.h" 25 #include "net/base/x509_util_nss.h"
26 26
27 namespace net { 27 namespace net {
28 28
29 namespace { 29 namespace {
30 30
31 class ScopedCERTCertificatePolicies { 31 typedef scoped_ptr_malloc<
32 public: 32 CERTCertificatePolicies,
33 explicit ScopedCERTCertificatePolicies(CERTCertificatePolicies* policies) 33 crypto::NSSDestroyer<CERTCertificatePolicies,
34 : policies_(policies) {} 34 CERT_DestroyCertificatePoliciesExtension> >
35 35 ScopedCERTCertificatePolicies;
36 ~ScopedCERTCertificatePolicies() {
37 if (policies_)
38 CERT_DestroyCertificatePoliciesExtension(policies_);
39 }
40
41 private:
42 CERTCertificatePolicies* policies_;
43
44 DISALLOW_COPY_AND_ASSIGN(ScopedCERTCertificatePolicies);
45 };
46 36
47 // ScopedCERTValOutParam manages destruction of values in the CERTValOutParam 37 // ScopedCERTValOutParam manages destruction of values in the CERTValOutParam
48 // array that cvout points to. cvout must be initialized as passed to 38 // array that cvout points to. cvout must be initialized as passed to
49 // CERT_PKIXVerifyCert, so that the array must be terminated with 39 // CERT_PKIXVerifyCert, so that the array must be terminated with
50 // cert_po_end type. 40 // cert_po_end type.
51 // When it goes out of scope, it destroys values of cert_po_trustAnchor 41 // When it goes out of scope, it destroys values of cert_po_trustAnchor
52 // and cert_po_certList types, but doesn't release the array itself. 42 // and cert_po_certList types, but doesn't release the array itself.
53 class ScopedCERTValOutParam { 43 class ScopedCERTValOutParam {
54 public: 44 public:
55 explicit ScopedCERTValOutParam(CERTValOutParam* cvout) 45 explicit ScopedCERTValOutParam(CERTValOutParam* cvout)
(...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 CERTCertificatePolicies* policies = 534 CERTCertificatePolicies* policies =
545 CERT_DecodeCertificatePoliciesExtension(&policy_ext); 535 CERT_DecodeCertificatePoliciesExtension(&policy_ext);
546 SECITEM_FreeItem(&policy_ext, PR_FALSE); 536 SECITEM_FreeItem(&policy_ext, PR_FALSE);
547 return policies; 537 return policies;
548 } 538 }
549 539
550 // Returns the OID tag for the first certificate policy in the certificate's 540 // Returns the OID tag for the first certificate policy in the certificate's
551 // certificatePolicies extension. Returns SEC_OID_UNKNOWN if the certificate 541 // certificatePolicies extension. Returns SEC_OID_UNKNOWN if the certificate
552 // has no certificate policy. 542 // has no certificate policy.
553 SECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle) { 543 SECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle) {
554 CERTCertificatePolicies* policies = DecodeCertPolicies(cert_handle); 544 ScopedCERTCertificatePolicies policies(DecodeCertPolicies(cert_handle));
555 if (!policies) 545 if (!policies.get())
556 return SEC_OID_UNKNOWN; 546 return SEC_OID_UNKNOWN;
557 ScopedCERTCertificatePolicies scoped_policies(policies); 547
558 CERTPolicyInfo* policy_info = policies->policyInfos[0]; 548 CERTPolicyInfo* policy_info = policies->policyInfos[0];
559 if (!policy_info) 549 if (!policy_info)
560 return SEC_OID_UNKNOWN; 550 return SEC_OID_UNKNOWN;
561 if (policy_info->oid != SEC_OID_UNKNOWN) 551 if (policy_info->oid != SEC_OID_UNKNOWN)
562 return policy_info->oid; 552 return policy_info->oid;
563 553
564 // The certificate policy is unknown to NSS. We need to create a dynamic 554 // The certificate policy is unknown to NSS. We need to create a dynamic
565 // OID tag for the policy. 555 // OID tag for the policy.
566 SECOidData od; 556 SECOidData od;
567 od.oid.len = policy_info->policyID.len; 557 od.oid.len = policy_info->policyID.len;
568 od.oid.data = policy_info->policyID.data; 558 od.oid.data = policy_info->policyID.data;
569 od.offset = SEC_OID_UNKNOWN; 559 od.offset = SEC_OID_UNKNOWN;
570 // NSS doesn't allow us to pass an empty description, so I use a hardcoded, 560 // NSS doesn't allow us to pass an empty description, so I use a hardcoded,
571 // default description here. The description doesn't need to be unique for 561 // default description here. The description doesn't need to be unique for
572 // each OID. 562 // each OID.
573 od.desc = "a certificate policy"; 563 od.desc = "a certificate policy";
574 od.mechanism = CKM_INVALID_MECHANISM; 564 od.mechanism = CKM_INVALID_MECHANISM;
575 od.supportedExtension = INVALID_CERT_EXTENSION; 565 od.supportedExtension = INVALID_CERT_EXTENSION;
576 return SECOID_AddEntry(&od); 566 return SECOID_AddEntry(&od);
577 } 567 }
578 568
579 bool CheckCertPolicies(X509Certificate::OSCertHandle cert_handle,
580 SECOidTag ev_policy_tag) {
581 CERTCertificatePolicies* policies = DecodeCertPolicies(cert_handle);
582 if (!policies) {
583 LOG(ERROR) << "Cert has no policies extension or extension couldn't be "
584 "decoded.";
585 return false;
586 }
587 ScopedCERTCertificatePolicies scoped_policies(policies);
588 CERTPolicyInfo** policy_infos = policies->policyInfos;
589 while (*policy_infos != NULL) {
590 CERTPolicyInfo* policy_info = *policy_infos++;
591 SECOidTag oid_tag = policy_info->oid;
592 if (oid_tag == SEC_OID_UNKNOWN)
593 continue;
594 if (oid_tag == ev_policy_tag)
595 return true;
596 }
597 return false;
598 }
599
600 SHA1Fingerprint CertPublicKeyHash(CERTCertificate* cert) { 569 SHA1Fingerprint CertPublicKeyHash(CERTCertificate* cert) {
601 SHA1Fingerprint hash; 570 SHA1Fingerprint hash;
602 SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, hash.data, 571 SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, hash.data,
603 cert->derPublicKey.data, cert->derPublicKey.len); 572 cert->derPublicKey.data, cert->derPublicKey.len);
604 DCHECK_EQ(rv, SECSuccess); 573 DCHECK_EQ(rv, SECSuccess);
605 return hash; 574 return hash;
606 } 575 }
607 576
608 void AppendPublicKeyHashes(CERTCertList* cert_list, 577 void AppendPublicKeyHashes(CERTCertList* cert_list,
609 CERTCertificate* root_cert, 578 CERTCertificate* root_cert,
610 std::vector<SHA1Fingerprint>* hashes) { 579 std::vector<SHA1Fingerprint>* hashes) {
611 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); 580 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
612 !CERT_LIST_END(node, cert_list); 581 !CERT_LIST_END(node, cert_list);
613 node = CERT_LIST_NEXT(node)) { 582 node = CERT_LIST_NEXT(node)) {
614 hashes->push_back(CertPublicKeyHash(node->cert)); 583 hashes->push_back(CertPublicKeyHash(node->cert));
615 } 584 }
616 if (root_cert) 585 if (root_cert)
617 hashes->push_back(CertPublicKeyHash(root_cert)); 586 hashes->push_back(CertPublicKeyHash(root_cert));
618 } 587 }
619 588
589 // Returns true if |cert_handle| contains a policy OID that is an EV policy
590 // OID according to |metadata|, storing the resulting policy OID in
591 // |*ev_policy_oid|. A true return is not sufficient to establish that a
592 // certificate is EV, but a false return is sufficient to establish the
593 // certificate cannot be EV.
594 bool IsEVCandidate(EVRootCAMetadata* metadata,
595 CERTCertificate* cert_handle,
596 SECOidTag* ev_policy_oid) {
597 DCHECK(cert_handle);
598 ScopedCERTCertificatePolicies policies(DecodeCertPolicies(cert_handle));
599 if (!policies.get())
600 return false;
601
602 CERTPolicyInfo** policy_infos = policies->policyInfos;
603 while (*policy_infos != NULL) {
604 CERTPolicyInfo* policy_info = *policy_infos++;
605 // If the Policy OID is unknown, that implicitly means it has not been
606 // registered as an EV policy.
607 if (policy_info->oid == SEC_OID_UNKNOWN)
608 continue;
609 if (metadata->IsEVPolicyOID(policy_info->oid)) {
610 *ev_policy_oid = policy_info->oid;
611 return true;
612 }
613 }
614
615 return false;
616 }
617
620 // Studied Mozilla's code (esp. security/manager/ssl/src/nsIdentityChecking.cpp 618 // Studied Mozilla's code (esp. security/manager/ssl/src/nsIdentityChecking.cpp
621 // and nsNSSCertHelper.cpp) to learn how to verify EV certificate. 619 // and nsNSSCertHelper.cpp) to learn how to verify EV certificate.
622 // TODO(wtc): A possible optimization is that we get the trust anchor from 620 // TODO(wtc): A possible optimization is that we get the trust anchor from
623 // the first PKIXVerifyCert call. We look up the EV policy for the trust 621 // the first PKIXVerifyCert call. We look up the EV policy for the trust
624 // anchor. If the trust anchor has no EV policy, we know the cert isn't EV. 622 // anchor. If the trust anchor has no EV policy, we know the cert isn't EV.
625 // Otherwise, we pass just that EV policy (as opposed to all the EV policies) 623 // Otherwise, we pass just that EV policy (as opposed to all the EV policies)
626 // to the second PKIXVerifyCert call. 624 // to the second PKIXVerifyCert call.
627 bool VerifyEV(CERTCertificate* cert_handle, int flags, CRLSet* crl_set) { 625 bool VerifyEV(CERTCertificate* cert_handle,
628 EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance(); 626 int flags,
629 627 CRLSet* crl_set,
628 EVRootCAMetadata* metadata,
629 SECOidTag ev_policy_oid) {
630 CERTValOutParam cvout[3]; 630 CERTValOutParam cvout[3];
631 int cvout_index = 0; 631 int cvout_index = 0;
632 cvout[cvout_index].type = cert_po_certList; 632 cvout[cvout_index].type = cert_po_certList;
633 cvout[cvout_index].value.pointer.chain = NULL; 633 cvout[cvout_index].value.pointer.chain = NULL;
634 int cvout_cert_list_index = cvout_index; 634 int cvout_cert_list_index = cvout_index;
635 cvout_index++; 635 cvout_index++;
636 cvout[cvout_index].type = cert_po_trustAnchor; 636 cvout[cvout_index].type = cert_po_trustAnchor;
637 cvout[cvout_index].value.pointer.cert = NULL; 637 cvout[cvout_index].value.pointer.cert = NULL;
638 int cvout_trust_anchor_index = cvout_index; 638 int cvout_trust_anchor_index = cvout_index;
639 cvout_index++; 639 cvout_index++;
640 cvout[cvout_index].type = cert_po_end; 640 cvout[cvout_index].type = cert_po_end;
641 ScopedCERTValOutParam scoped_cvout(cvout); 641 ScopedCERTValOutParam scoped_cvout(cvout);
642 642
643 bool rev_checking_enabled =
644 (flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED) ||
645 (flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED_EV_ONLY);
646
643 SECStatus status = PKIXVerifyCert( 647 SECStatus status = PKIXVerifyCert(
644 cert_handle, 648 cert_handle,
645 flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED, 649 rev_checking_enabled,
646 flags & X509Certificate::VERIFY_CERT_IO_ENABLED, 650 flags & X509Certificate::VERIFY_CERT_IO_ENABLED,
647 metadata->GetPolicyOIDs(), 651 &ev_policy_oid,
648 metadata->NumPolicyOIDs(), 652 1,
649 cvout); 653 cvout);
650 if (status != SECSuccess) 654 if (status != SECSuccess)
651 return false; 655 return false;
652 656
653 CERTCertificate* root_ca = 657 CERTCertificate* root_ca =
654 cvout[cvout_trust_anchor_index].value.pointer.cert; 658 cvout[cvout_trust_anchor_index].value.pointer.cert;
655 if (root_ca == NULL) 659 if (root_ca == NULL)
656 return false; 660 return false;
657 661
658 // This second PKIXVerifyCert call could have found a different certification 662 // This second PKIXVerifyCert call could have found a different certification
659 // path and one or more of the certificates on this new path, that weren't on 663 // path and one or more of the certificates on this new path, that weren't on
660 // the old path, might have been revoked. 664 // the old path, might have been revoked.
661 if (crl_set) { 665 if (crl_set) {
662 CRLSetResult crl_set_result = CheckRevocationWithCRLSet( 666 CRLSetResult crl_set_result = CheckRevocationWithCRLSet(
663 cvout[cvout_cert_list_index].value.pointer.chain, 667 cvout[cvout_cert_list_index].value.pointer.chain,
664 cvout[cvout_trust_anchor_index].value.pointer.cert, 668 cvout[cvout_trust_anchor_index].value.pointer.cert,
665 crl_set); 669 crl_set);
666 if (crl_set_result == kCRLSetRevoked) 670 if (crl_set_result == kCRLSetRevoked)
667 return false; 671 return false;
668 } 672 }
669 673
670 SHA1Fingerprint fingerprint = 674 SHA1Fingerprint fingerprint =
671 X509Certificate::CalculateFingerprint(root_ca); 675 X509Certificate::CalculateFingerprint(root_ca);
672 std::vector<SECOidTag> ev_policy_tags; 676 return metadata->HasEVPolicyOID(fingerprint, ev_policy_oid);
673 if (!metadata->GetPolicyOIDsForCA(fingerprint, &ev_policy_tags))
674 return false;
675 DCHECK(!ev_policy_tags.empty());
676
677 for (std::vector<SECOidTag>::const_iterator
678 i = ev_policy_tags.begin(); i != ev_policy_tags.end(); ++i) {
679 if (CheckCertPolicies(cert_handle, *i))
680 return true;
681 }
682 return false;
683 } 677 }
684 678
685 } // namespace 679 } // namespace
686 680
687 CertVerifyProcNSS::CertVerifyProcNSS() {} 681 CertVerifyProcNSS::CertVerifyProcNSS() {}
688 682
689 CertVerifyProcNSS::~CertVerifyProcNSS() {} 683 CertVerifyProcNSS::~CertVerifyProcNSS() {}
690 684
691 int CertVerifyProcNSS::VerifyInternal(X509Certificate* cert, 685 int CertVerifyProcNSS::VerifyInternal(X509Certificate* cert,
692 const std::string& hostname, 686 const std::string& hostname,
(...skipping 18 matching lines...) Expand all
711 cvout[cvout_index].value.pointer.chain = NULL; 705 cvout[cvout_index].value.pointer.chain = NULL;
712 int cvout_cert_list_index = cvout_index; 706 int cvout_cert_list_index = cvout_index;
713 cvout_index++; 707 cvout_index++;
714 cvout[cvout_index].type = cert_po_trustAnchor; 708 cvout[cvout_index].type = cert_po_trustAnchor;
715 cvout[cvout_index].value.pointer.cert = NULL; 709 cvout[cvout_index].value.pointer.cert = NULL;
716 int cvout_trust_anchor_index = cvout_index; 710 int cvout_trust_anchor_index = cvout_index;
717 cvout_index++; 711 cvout_index++;
718 cvout[cvout_index].type = cert_po_end; 712 cvout[cvout_index].type = cert_po_end;
719 ScopedCERTValOutParam scoped_cvout(cvout); 713 ScopedCERTValOutParam scoped_cvout(cvout);
720 714
715 EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
716 SECOidTag ev_policy_oid = SEC_OID_UNKNOWN;
717 bool is_ev_candidate =
718 (flags & X509Certificate::VERIFY_EV_CERT) &&
719 IsEVCandidate(metadata, cert_handle, &ev_policy_oid);
721 bool cert_io_enabled = flags & X509Certificate::VERIFY_CERT_IO_ENABLED; 720 bool cert_io_enabled = flags & X509Certificate::VERIFY_CERT_IO_ENABLED;
722 bool check_revocation = 721 bool check_revocation =
723 (flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED) && 722 cert_io_enabled &&
724 cert_io_enabled; 723 ((flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED) ||
724 ((flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED_EV_ONLY) &&
725 is_ev_candidate));
725 if (check_revocation) 726 if (check_revocation)
726 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; 727 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
727 728
728 status = PKIXVerifyCert(cert_handle, check_revocation, cert_io_enabled, 729 status = PKIXVerifyCert(cert_handle, check_revocation, cert_io_enabled,
729 NULL, 0, cvout); 730 NULL, 0, cvout);
730 731
731 if (crl_set) { 732 if (crl_set) {
732 CRLSetResult crl_set_result = CheckRevocationWithCRLSet( 733 CRLSetResult crl_set_result = CheckRevocationWithCRLSet(
733 cvout[cvout_cert_list_index].value.pointer.chain, 734 cvout[cvout_cert_list_index].value.pointer.chain,
734 cvout[cvout_trust_anchor_index].value.pointer.cert, 735 cvout[cvout_trust_anchor_index].value.pointer.cert,
(...skipping 28 matching lines...) Expand all
763 if (IsCertStatusError(verify_result->cert_status)) 764 if (IsCertStatusError(verify_result->cert_status))
764 return MapCertStatusToNetError(verify_result->cert_status); 765 return MapCertStatusToNetError(verify_result->cert_status);
765 766
766 AppendPublicKeyHashes(cvout[cvout_cert_list_index].value.pointer.chain, 767 AppendPublicKeyHashes(cvout[cvout_cert_list_index].value.pointer.chain,
767 cvout[cvout_trust_anchor_index].value.pointer.cert, 768 cvout[cvout_trust_anchor_index].value.pointer.cert,
768 &verify_result->public_key_hashes); 769 &verify_result->public_key_hashes);
769 770
770 verify_result->is_issued_by_known_root = 771 verify_result->is_issued_by_known_root =
771 IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert); 772 IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert);
772 773
773 if ((flags & X509Certificate::VERIFY_EV_CERT) && 774 if ((flags & X509Certificate::VERIFY_EV_CERT) && is_ev_candidate &&
774 VerifyEV(cert_handle, flags, crl_set)) { 775 VerifyEV(cert_handle, flags, crl_set, metadata, ev_policy_oid)) {
775 verify_result->cert_status |= CERT_STATUS_IS_EV; 776 verify_result->cert_status |= CERT_STATUS_IS_EV;
776 } 777 }
777 778
778 return OK; 779 return OK;
779 } 780 }
780 781
781 } // namespace net 782 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698