| Index: net/base/cert_verify_proc_nss.cc
|
| diff --git a/net/base/cert_verify_proc_nss.cc b/net/base/cert_verify_proc_nss.cc
|
| index 3108555455e1023d385ec0fb621b4d64c7d2f182..9edcbda082c36dd1abafb284430db25c1d2759d7 100644
|
| --- a/net/base/cert_verify_proc_nss.cc
|
| +++ b/net/base/cert_verify_proc_nss.cc
|
| @@ -28,21 +28,11 @@ namespace net {
|
|
|
| namespace {
|
|
|
| -class ScopedCERTCertificatePolicies {
|
| - public:
|
| - explicit ScopedCERTCertificatePolicies(CERTCertificatePolicies* policies)
|
| - : policies_(policies) {}
|
| -
|
| - ~ScopedCERTCertificatePolicies() {
|
| - if (policies_)
|
| - CERT_DestroyCertificatePoliciesExtension(policies_);
|
| - }
|
| -
|
| - private:
|
| - CERTCertificatePolicies* policies_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(ScopedCERTCertificatePolicies);
|
| -};
|
| +typedef scoped_ptr_malloc<
|
| + CERTCertificatePolicies,
|
| + crypto::NSSDestroyer<CERTCertificatePolicies,
|
| + CERT_DestroyCertificatePoliciesExtension> >
|
| + ScopedCERTCertificatePolicies;
|
|
|
| // ScopedCERTValOutParam manages destruction of values in the CERTValOutParam
|
| // array that cvout points to. cvout must be initialized as passed to
|
| @@ -551,10 +541,10 @@ CERTCertificatePolicies* DecodeCertPolicies(
|
| // certificatePolicies extension. Returns SEC_OID_UNKNOWN if the certificate
|
| // has no certificate policy.
|
| SECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle) {
|
| - CERTCertificatePolicies* policies = DecodeCertPolicies(cert_handle);
|
| - if (!policies)
|
| + ScopedCERTCertificatePolicies policies(DecodeCertPolicies(cert_handle));
|
| + if (!policies.get())
|
| return SEC_OID_UNKNOWN;
|
| - ScopedCERTCertificatePolicies scoped_policies(policies);
|
| +
|
| CERTPolicyInfo* policy_info = policies->policyInfos[0];
|
| if (!policy_info)
|
| return SEC_OID_UNKNOWN;
|
| @@ -576,27 +566,6 @@ SECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle) {
|
| return SECOID_AddEntry(&od);
|
| }
|
|
|
| -bool CheckCertPolicies(X509Certificate::OSCertHandle cert_handle,
|
| - SECOidTag ev_policy_tag) {
|
| - CERTCertificatePolicies* policies = DecodeCertPolicies(cert_handle);
|
| - if (!policies) {
|
| - LOG(ERROR) << "Cert has no policies extension or extension couldn't be "
|
| - "decoded.";
|
| - return false;
|
| - }
|
| - ScopedCERTCertificatePolicies scoped_policies(policies);
|
| - CERTPolicyInfo** policy_infos = policies->policyInfos;
|
| - while (*policy_infos != NULL) {
|
| - CERTPolicyInfo* policy_info = *policy_infos++;
|
| - SECOidTag oid_tag = policy_info->oid;
|
| - if (oid_tag == SEC_OID_UNKNOWN)
|
| - continue;
|
| - if (oid_tag == ev_policy_tag)
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| SHA1Fingerprint CertPublicKeyHash(CERTCertificate* cert) {
|
| SHA1Fingerprint hash;
|
| SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, hash.data,
|
| @@ -617,6 +586,35 @@ void AppendPublicKeyHashes(CERTCertList* cert_list,
|
| hashes->push_back(CertPublicKeyHash(root_cert));
|
| }
|
|
|
| +// Returns true if |cert_handle| contains a policy OID that is an EV policy
|
| +// OID according to |metadata|, storing the resulting policy OID in
|
| +// |*ev_policy_oid|. A true return is not sufficient to establish that a
|
| +// certificate is EV, but a false return is sufficient to establish the
|
| +// certificate cannot be EV.
|
| +bool IsEVCandidate(EVRootCAMetadata* metadata,
|
| + CERTCertificate* cert_handle,
|
| + SECOidTag* ev_policy_oid) {
|
| + DCHECK(cert_handle);
|
| + ScopedCERTCertificatePolicies policies(DecodeCertPolicies(cert_handle));
|
| + if (!policies.get())
|
| + return false;
|
| +
|
| + CERTPolicyInfo** policy_infos = policies->policyInfos;
|
| + while (*policy_infos != NULL) {
|
| + CERTPolicyInfo* policy_info = *policy_infos++;
|
| + // If the Policy OID is unknown, that implicitly means it has not been
|
| + // registered as an EV policy.
|
| + if (policy_info->oid == SEC_OID_UNKNOWN)
|
| + continue;
|
| + if (metadata->IsEVPolicyOID(policy_info->oid)) {
|
| + *ev_policy_oid = policy_info->oid;
|
| + return true;
|
| + }
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| // Studied Mozilla's code (esp. security/manager/ssl/src/nsIdentityChecking.cpp
|
| // and nsNSSCertHelper.cpp) to learn how to verify EV certificate.
|
| // TODO(wtc): A possible optimization is that we get the trust anchor from
|
| @@ -624,9 +622,11 @@ void AppendPublicKeyHashes(CERTCertList* cert_list,
|
| // anchor. If the trust anchor has no EV policy, we know the cert isn't EV.
|
| // Otherwise, we pass just that EV policy (as opposed to all the EV policies)
|
| // to the second PKIXVerifyCert call.
|
| -bool VerifyEV(CERTCertificate* cert_handle, int flags, CRLSet* crl_set) {
|
| - EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
|
| -
|
| +bool VerifyEV(CERTCertificate* cert_handle,
|
| + int flags,
|
| + CRLSet* crl_set,
|
| + EVRootCAMetadata* metadata,
|
| + SECOidTag ev_policy_oid) {
|
| CERTValOutParam cvout[3];
|
| int cvout_index = 0;
|
| cvout[cvout_index].type = cert_po_certList;
|
| @@ -640,12 +640,16 @@ bool VerifyEV(CERTCertificate* cert_handle, int flags, CRLSet* crl_set) {
|
| cvout[cvout_index].type = cert_po_end;
|
| ScopedCERTValOutParam scoped_cvout(cvout);
|
|
|
| + bool rev_checking_enabled =
|
| + (flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED) ||
|
| + (flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED_EV_ONLY);
|
| +
|
| SECStatus status = PKIXVerifyCert(
|
| cert_handle,
|
| - flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED,
|
| + rev_checking_enabled,
|
| flags & X509Certificate::VERIFY_CERT_IO_ENABLED,
|
| - metadata->GetPolicyOIDs(),
|
| - metadata->NumPolicyOIDs(),
|
| + &ev_policy_oid,
|
| + 1,
|
| cvout);
|
| if (status != SECSuccess)
|
| return false;
|
| @@ -669,17 +673,7 @@ bool VerifyEV(CERTCertificate* cert_handle, int flags, CRLSet* crl_set) {
|
|
|
| SHA1Fingerprint fingerprint =
|
| X509Certificate::CalculateFingerprint(root_ca);
|
| - std::vector<SECOidTag> ev_policy_tags;
|
| - if (!metadata->GetPolicyOIDsForCA(fingerprint, &ev_policy_tags))
|
| - return false;
|
| - DCHECK(!ev_policy_tags.empty());
|
| -
|
| - for (std::vector<SECOidTag>::const_iterator
|
| - i = ev_policy_tags.begin(); i != ev_policy_tags.end(); ++i) {
|
| - if (CheckCertPolicies(cert_handle, *i))
|
| - return true;
|
| - }
|
| - return false;
|
| + return metadata->HasEVPolicyOID(fingerprint, ev_policy_oid);
|
| }
|
|
|
| } // namespace
|
| @@ -718,10 +712,17 @@ int CertVerifyProcNSS::VerifyInternal(X509Certificate* cert,
|
| cvout[cvout_index].type = cert_po_end;
|
| ScopedCERTValOutParam scoped_cvout(cvout);
|
|
|
| + EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
|
| + SECOidTag ev_policy_oid = SEC_OID_UNKNOWN;
|
| + bool is_ev_candidate =
|
| + (flags & X509Certificate::VERIFY_EV_CERT) &&
|
| + IsEVCandidate(metadata, cert_handle, &ev_policy_oid);
|
| bool cert_io_enabled = flags & X509Certificate::VERIFY_CERT_IO_ENABLED;
|
| bool check_revocation =
|
| - (flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED) &&
|
| - cert_io_enabled;
|
| + cert_io_enabled &&
|
| + ((flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED) ||
|
| + ((flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED_EV_ONLY) &&
|
| + is_ev_candidate));
|
| if (check_revocation)
|
| verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
|
|
|
| @@ -770,8 +771,8 @@ int CertVerifyProcNSS::VerifyInternal(X509Certificate* cert,
|
| verify_result->is_issued_by_known_root =
|
| IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert);
|
|
|
| - if ((flags & X509Certificate::VERIFY_EV_CERT) &&
|
| - VerifyEV(cert_handle, flags, crl_set)) {
|
| + if ((flags & X509Certificate::VERIFY_EV_CERT) && is_ev_candidate &&
|
| + VerifyEV(cert_handle, flags, crl_set, metadata, ev_policy_oid)) {
|
| verify_result->cert_status |= CERT_STATUS_IS_EV;
|
| }
|
|
|
|
|