Home | History | Annotate | Download | only in cert
      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
      3 // found in the LICENSE file.
      4 
      5 #include "net/cert/cert_verify_proc_nss.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include <cert.h>
     11 #include <nss.h>
     12 #include <prerror.h>
     13 #include <secerr.h>
     14 #include <sechash.h>
     15 #include <sslerr.h>
     16 
     17 #include "base/logging.h"
     18 #include "crypto/nss_util.h"
     19 #include "crypto/scoped_nss_types.h"
     20 #include "crypto/sha2.h"
     21 #include "net/base/net_errors.h"
     22 #include "net/cert/asn1_util.h"
     23 #include "net/cert/cert_status_flags.h"
     24 #include "net/cert/cert_verifier.h"
     25 #include "net/cert/cert_verify_result.h"
     26 #include "net/cert/crl_set.h"
     27 #include "net/cert/ev_root_ca_metadata.h"
     28 #include "net/cert/x509_certificate.h"
     29 #include "net/cert/x509_util_nss.h"
     30 
     31 #if defined(OS_IOS)
     32 #include <CommonCrypto/CommonDigest.h>
     33 #include "net/cert/x509_util_ios.h"
     34 #endif  // defined(OS_IOS)
     35 
     36 #define NSS_VERSION_NUM (NSS_VMAJOR * 10000 + NSS_VMINOR * 100 + NSS_VPATCH)
     37 #if NSS_VERSION_NUM < 31305
     38 // Added in NSS 3.13.5.
     39 #define SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED -8016
     40 #endif
     41 
     42 #if NSS_VERSION_NUM < 31402
     43 // Added in NSS 3.14.2.
     44 #define cert_pi_useOnlyTrustAnchors static_cast<CERTValParamInType>(14)
     45 #endif
     46 
     47 namespace net {
     48 
     49 namespace {
     50 
     51 typedef scoped_ptr_malloc<
     52     CERTCertificatePolicies,
     53     crypto::NSSDestroyer<CERTCertificatePolicies,
     54                          CERT_DestroyCertificatePoliciesExtension> >
     55     ScopedCERTCertificatePolicies;
     56 
     57 typedef scoped_ptr_malloc<
     58     CERTCertList,
     59     crypto::NSSDestroyer<CERTCertList, CERT_DestroyCertList> >
     60     ScopedCERTCertList;
     61 
     62 // ScopedCERTValOutParam manages destruction of values in the CERTValOutParam
     63 // array that cvout points to.  cvout must be initialized as passed to
     64 // CERT_PKIXVerifyCert, so that the array must be terminated with
     65 // cert_po_end type.
     66 // When it goes out of scope, it destroys values of cert_po_trustAnchor
     67 // and cert_po_certList types, but doesn't release the array itself.
     68 class ScopedCERTValOutParam {
     69  public:
     70   explicit ScopedCERTValOutParam(CERTValOutParam* cvout) : cvout_(cvout) {}
     71 
     72   ~ScopedCERTValOutParam() {
     73     Clear();
     74   }
     75 
     76   // Free the internal resources, but do not release the array itself.
     77   void Clear() {
     78     if (cvout_ == NULL)
     79       return;
     80     for (CERTValOutParam *p = cvout_; p->type != cert_po_end; p++) {
     81       switch (p->type) {
     82         case cert_po_trustAnchor:
     83           if (p->value.pointer.cert) {
     84             CERT_DestroyCertificate(p->value.pointer.cert);
     85             p->value.pointer.cert = NULL;
     86           }
     87           break;
     88         case cert_po_certList:
     89           if (p->value.pointer.chain) {
     90             CERT_DestroyCertList(p->value.pointer.chain);
     91             p->value.pointer.chain = NULL;
     92           }
     93           break;
     94         default:
     95           break;
     96       }
     97     }
     98   }
     99 
    100  private:
    101   CERTValOutParam* cvout_;
    102 
    103   DISALLOW_COPY_AND_ASSIGN(ScopedCERTValOutParam);
    104 };
    105 
    106 // Map PORT_GetError() return values to our network error codes.
    107 int MapSecurityError(int err) {
    108   switch (err) {
    109     case PR_DIRECTORY_LOOKUP_ERROR:  // DNS lookup error.
    110       return ERR_NAME_NOT_RESOLVED;
    111     case SEC_ERROR_INVALID_ARGS:
    112       return ERR_INVALID_ARGUMENT;
    113     case SSL_ERROR_BAD_CERT_DOMAIN:
    114       return ERR_CERT_COMMON_NAME_INVALID;
    115     case SEC_ERROR_INVALID_TIME:
    116     case SEC_ERROR_EXPIRED_CERTIFICATE:
    117     case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
    118       return ERR_CERT_DATE_INVALID;
    119     case SEC_ERROR_UNKNOWN_ISSUER:
    120     case SEC_ERROR_UNTRUSTED_ISSUER:
    121     case SEC_ERROR_CA_CERT_INVALID:
    122       return ERR_CERT_AUTHORITY_INVALID;
    123     // TODO(port): map ERR_CERT_NO_REVOCATION_MECHANISM.
    124     case SEC_ERROR_OCSP_BAD_HTTP_RESPONSE:
    125     case SEC_ERROR_OCSP_SERVER_ERROR:
    126       return ERR_CERT_UNABLE_TO_CHECK_REVOCATION;
    127     case SEC_ERROR_REVOKED_CERTIFICATE:
    128     case SEC_ERROR_UNTRUSTED_CERT:  // Treat as revoked.
    129       return ERR_CERT_REVOKED;
    130     case SEC_ERROR_BAD_DER:
    131     case SEC_ERROR_BAD_SIGNATURE:
    132     case SEC_ERROR_CERT_NOT_VALID:
    133     // TODO(port): add an ERR_CERT_WRONG_USAGE error code.
    134     case SEC_ERROR_CERT_USAGES_INVALID:
    135     case SEC_ERROR_INADEQUATE_KEY_USAGE:  // Key usage.
    136     case SEC_ERROR_INADEQUATE_CERT_TYPE:  // Extended key usage and whether
    137                                           // the certificate is a CA.
    138     case SEC_ERROR_POLICY_VALIDATION_FAILED:
    139     case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:
    140     case SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID:
    141     case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
    142     case SEC_ERROR_EXTENSION_VALUE_INVALID:
    143       return ERR_CERT_INVALID;
    144     case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
    145       return ERR_CERT_WEAK_SIGNATURE_ALGORITHM;
    146     default:
    147       LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
    148       return ERR_FAILED;
    149   }
    150 }
    151 
    152 // Map PORT_GetError() return values to our cert status flags.
    153 CertStatus MapCertErrorToCertStatus(int err) {
    154   int net_error = MapSecurityError(err);
    155   return MapNetErrorToCertStatus(net_error);
    156 }
    157 
    158 // Saves some information about the certificate chain cert_list in
    159 // *verify_result.  The caller MUST initialize *verify_result before calling
    160 // this function.
    161 // Note that cert_list[0] is the end entity certificate.
    162 void GetCertChainInfo(CERTCertList* cert_list,
    163                       CERTCertificate* root_cert,
    164                       CertVerifyResult* verify_result) {
    165   DCHECK(cert_list);
    166 
    167   CERTCertificate* verified_cert = NULL;
    168   std::vector<CERTCertificate*> verified_chain;
    169   int i = 0;
    170   for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
    171        !CERT_LIST_END(node, cert_list);
    172        node = CERT_LIST_NEXT(node), ++i) {
    173     if (i == 0) {
    174       verified_cert = node->cert;
    175     } else {
    176       // Because of an NSS bug, CERT_PKIXVerifyCert may chain a self-signed
    177       // certificate of a root CA to another certificate of the same root CA
    178       // key.  Detect that error and ignore the root CA certificate.
    179       // See https://bugzilla.mozilla.org/show_bug.cgi?id=721288.
    180       if (node->cert->isRoot) {
    181         // NOTE: isRoot doesn't mean the certificate is a trust anchor.  It
    182         // means the certificate is self-signed.  Here we assume isRoot only
    183         // implies the certificate is self-issued.
    184         CERTCertListNode* next_node = CERT_LIST_NEXT(node);
    185         CERTCertificate* next_cert;
    186         if (!CERT_LIST_END(next_node, cert_list)) {
    187           next_cert = next_node->cert;
    188         } else {
    189           next_cert = root_cert;
    190         }
    191         // Test that |node->cert| is actually a self-signed certificate
    192         // whose key is equal to |next_cert|, and not a self-issued
    193         // certificate signed by another key of the same CA.
    194         if (next_cert && SECITEM_ItemsAreEqual(&node->cert->derPublicKey,
    195                                                &next_cert->derPublicKey)) {
    196           continue;
    197         }
    198       }
    199       verified_chain.push_back(node->cert);
    200     }
    201 
    202     SECAlgorithmID& signature = node->cert->signature;
    203     SECOidTag oid_tag = SECOID_FindOIDTag(&signature.algorithm);
    204     switch (oid_tag) {
    205       case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
    206         verify_result->has_md5 = true;
    207         break;
    208       case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
    209         verify_result->has_md2 = true;
    210         break;
    211       case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
    212         verify_result->has_md4 = true;
    213         break;
    214       default:
    215         break;
    216     }
    217   }
    218 
    219   if (root_cert)
    220     verified_chain.push_back(root_cert);
    221 #if defined(OS_IOS)
    222   verify_result->verified_cert =
    223       x509_util_ios::CreateCertFromNSSHandles(verified_cert, verified_chain);
    224 #else
    225   verify_result->verified_cert =
    226       X509Certificate::CreateFromHandle(verified_cert, verified_chain);
    227 #endif  // defined(OS_IOS)
    228 }
    229 
    230 // IsKnownRoot returns true if the given certificate is one that we believe
    231 // is a standard (as opposed to user-installed) root.
    232 bool IsKnownRoot(CERTCertificate* root) {
    233   if (!root || !root->slot)
    234     return false;
    235 
    236   // This magic name is taken from
    237   // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw/builtins/constants.c&rev=1.13&mark=86,89#79
    238   return 0 == strcmp(PK11_GetSlotName(root->slot),
    239                      "NSS Builtin Objects");
    240 }
    241 
    242 // Returns true if the given certificate is one of the additional trust anchors.
    243 bool IsAdditionalTrustAnchor(CERTCertList* additional_trust_anchors,
    244                              CERTCertificate* root) {
    245   if (!additional_trust_anchors || !root)
    246     return false;
    247   for (CERTCertListNode* node = CERT_LIST_HEAD(additional_trust_anchors);
    248        !CERT_LIST_END(node, additional_trust_anchors);
    249        node = CERT_LIST_NEXT(node)) {
    250     if (CERT_CompareCerts(node->cert, root))
    251       return true;
    252   }
    253   return false;
    254 }
    255 
    256 enum CRLSetResult {
    257   kCRLSetOk,
    258   kCRLSetRevoked,
    259   kCRLSetUnknown,
    260 };
    261 
    262 // CheckRevocationWithCRLSet attempts to check each element of |cert_list|
    263 // against |crl_set|. It returns:
    264 //   kCRLSetRevoked: if any element of the chain is known to have been revoked.
    265 //   kCRLSetUnknown: if there is no fresh information about some element in
    266 //       the chain.
    267 //   kCRLSetOk: if every element in the chain is covered by a fresh CRLSet and
    268 //       is unrevoked.
    269 CRLSetResult CheckRevocationWithCRLSet(CERTCertList* cert_list,
    270                                        CERTCertificate* root,
    271                                        CRLSet* crl_set) {
    272   std::vector<CERTCertificate*> certs;
    273 
    274   if (cert_list) {
    275     for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
    276          !CERT_LIST_END(node, cert_list);
    277          node = CERT_LIST_NEXT(node)) {
    278       certs.push_back(node->cert);
    279     }
    280   }
    281   if (root)
    282     certs.push_back(root);
    283 
    284   bool covered = true;
    285 
    286   // We iterate from the root certificate down to the leaf, keeping track of
    287   // the issuer's SPKI at each step.
    288   std::string issuer_spki_hash;
    289   for (std::vector<CERTCertificate*>::reverse_iterator i = certs.rbegin();
    290        i != certs.rend(); ++i) {
    291     CERTCertificate* cert = *i;
    292 
    293     base::StringPiece der(reinterpret_cast<char*>(cert->derCert.data),
    294                           cert->derCert.len);
    295 
    296     base::StringPiece spki;
    297     if (!asn1::ExtractSPKIFromDERCert(der, &spki)) {
    298       NOTREACHED();
    299       covered = false;
    300       continue;
    301     }
    302     const std::string spki_hash = crypto::SHA256HashString(spki);
    303 
    304     base::StringPiece serial_number = base::StringPiece(
    305         reinterpret_cast<char*>(cert->serialNumber.data),
    306         cert->serialNumber.len);
    307 
    308     CRLSet::Result result = crl_set->CheckSPKI(spki_hash);
    309 
    310     if (result != CRLSet::REVOKED && !issuer_spki_hash.empty())
    311       result = crl_set->CheckSerial(serial_number, issuer_spki_hash);
    312 
    313     issuer_spki_hash = spki_hash;
    314 
    315     switch (result) {
    316       case CRLSet::REVOKED:
    317         return kCRLSetRevoked;
    318       case CRLSet::UNKNOWN:
    319         covered = false;
    320         continue;
    321       case CRLSet::GOOD:
    322         continue;
    323       default:
    324         NOTREACHED();
    325         covered = false;
    326         continue;
    327     }
    328   }
    329 
    330   if (!covered || crl_set->IsExpired())
    331     return kCRLSetUnknown;
    332   return kCRLSetOk;
    333 }
    334 
    335 // Forward declarations.
    336 SECStatus RetryPKIXVerifyCertWithWorkarounds(
    337     CERTCertificate* cert_handle, int num_policy_oids,
    338     bool cert_io_enabled, std::vector<CERTValInParam>* cvin,
    339     CERTValOutParam* cvout);
    340 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle);
    341 
    342 // Call CERT_PKIXVerifyCert for the cert_handle.
    343 // Verification results are stored in an array of CERTValOutParam.
    344 // If |hard_fail| is true, and no policy_oids are supplied (eg: EV is NOT being
    345 // checked), then the failure to obtain valid CRL/OCSP information for all
    346 // certificates that contain CRL/OCSP URLs will cause the certificate to be
    347 // treated as if it was revoked. Since failures may be caused by transient
    348 // network failures or by malicious attackers, in general, hard_fail should be
    349 // false.
    350 // If policy_oids is not NULL and num_policy_oids is positive, policies
    351 // are also checked.
    352 // additional_trust_anchors is an optional list of certificates that can be
    353 // trusted as anchors when building a certificate chain.
    354 // Caller must initialize cvout before calling this function.
    355 SECStatus PKIXVerifyCert(CERTCertificate* cert_handle,
    356                          bool check_revocation,
    357                          bool hard_fail,
    358                          bool cert_io_enabled,
    359                          const SECOidTag* policy_oids,
    360                          int num_policy_oids,
    361                          CERTCertList* additional_trust_anchors,
    362                          CERTValOutParam* cvout) {
    363   bool use_crl = check_revocation;
    364   bool use_ocsp = check_revocation;
    365 
    366   PRUint64 revocation_method_flags =
    367       CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD |
    368       CERT_REV_M_ALLOW_NETWORK_FETCHING |
    369       CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE |
    370       CERT_REV_M_IGNORE_MISSING_FRESH_INFO |
    371       CERT_REV_M_STOP_TESTING_ON_FRESH_INFO;
    372   PRUint64 revocation_method_independent_flags =
    373       CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST;
    374   if (check_revocation && policy_oids && num_policy_oids > 0) {
    375     // EV verification requires revocation checking.  Consider the certificate
    376     // revoked if we don't have revocation info.
    377     // TODO(wtc): Add a bool parameter to expressly specify we're doing EV
    378     // verification or we want strict revocation flags.
    379     revocation_method_flags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE;
    380     revocation_method_independent_flags |=
    381         CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;
    382   } else if (check_revocation && hard_fail) {
    383     revocation_method_flags |= CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO;
    384     revocation_method_independent_flags |=
    385         CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;
    386   } else {
    387     revocation_method_flags |= CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE;
    388     revocation_method_independent_flags |=
    389         CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT;
    390   }
    391   PRUint64 method_flags[2];
    392   method_flags[cert_revocation_method_crl] = revocation_method_flags;
    393   method_flags[cert_revocation_method_ocsp] = revocation_method_flags;
    394 
    395   if (use_crl) {
    396     method_flags[cert_revocation_method_crl] |=
    397         CERT_REV_M_TEST_USING_THIS_METHOD;
    398   }
    399   if (use_ocsp) {
    400     method_flags[cert_revocation_method_ocsp] |=
    401         CERT_REV_M_TEST_USING_THIS_METHOD;
    402   }
    403 
    404   CERTRevocationMethodIndex preferred_revocation_methods[1];
    405   if (use_ocsp) {
    406     preferred_revocation_methods[0] = cert_revocation_method_ocsp;
    407   } else {
    408     preferred_revocation_methods[0] = cert_revocation_method_crl;
    409   }
    410 
    411   CERTRevocationFlags revocation_flags;
    412   revocation_flags.leafTests.number_of_defined_methods =
    413       arraysize(method_flags);
    414   revocation_flags.leafTests.cert_rev_flags_per_method = method_flags;
    415   revocation_flags.leafTests.number_of_preferred_methods =
    416       arraysize(preferred_revocation_methods);
    417   revocation_flags.leafTests.preferred_methods = preferred_revocation_methods;
    418   revocation_flags.leafTests.cert_rev_method_independent_flags =
    419       revocation_method_independent_flags;
    420 
    421   revocation_flags.chainTests.number_of_defined_methods =
    422       arraysize(method_flags);
    423   revocation_flags.chainTests.cert_rev_flags_per_method = method_flags;
    424   revocation_flags.chainTests.number_of_preferred_methods =
    425       arraysize(preferred_revocation_methods);
    426   revocation_flags.chainTests.preferred_methods = preferred_revocation_methods;
    427   revocation_flags.chainTests.cert_rev_method_independent_flags =
    428       revocation_method_independent_flags;
    429 
    430 
    431   std::vector<CERTValInParam> cvin;
    432   cvin.reserve(7);
    433   CERTValInParam in_param;
    434   in_param.type = cert_pi_revocationFlags;
    435   in_param.value.pointer.revocation = &revocation_flags;
    436   cvin.push_back(in_param);
    437   if (policy_oids && num_policy_oids > 0) {
    438     in_param.type = cert_pi_policyOID;
    439     in_param.value.arraySize = num_policy_oids;
    440     in_param.value.array.oids = policy_oids;
    441     cvin.push_back(in_param);
    442   }
    443   if (additional_trust_anchors) {
    444     in_param.type = cert_pi_trustAnchors;
    445     in_param.value.pointer.chain = additional_trust_anchors;
    446     cvin.push_back(in_param);
    447     in_param.type = cert_pi_useOnlyTrustAnchors;
    448     in_param.value.scalar.b = PR_FALSE;
    449     cvin.push_back(in_param);
    450   }
    451   in_param.type = cert_pi_end;
    452   cvin.push_back(in_param);
    453 
    454   SECStatus rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
    455                                      &cvin[0], cvout, NULL);
    456   if (rv != SECSuccess) {
    457     rv = RetryPKIXVerifyCertWithWorkarounds(cert_handle, num_policy_oids,
    458                                             cert_io_enabled, &cvin, cvout);
    459   }
    460   return rv;
    461 }
    462 
    463 // PKIXVerifyCert calls this function to work around some bugs in
    464 // CERT_PKIXVerifyCert.  All the arguments of this function are either the
    465 // arguments or local variables of PKIXVerifyCert.
    466 SECStatus RetryPKIXVerifyCertWithWorkarounds(
    467     CERTCertificate* cert_handle, int num_policy_oids,
    468     bool cert_io_enabled, std::vector<CERTValInParam>* cvin,
    469     CERTValOutParam* cvout) {
    470   // We call this function when the first CERT_PKIXVerifyCert call in
    471   // PKIXVerifyCert failed,  so we initialize |rv| to SECFailure.
    472   SECStatus rv = SECFailure;
    473   int nss_error = PORT_GetError();
    474   CERTValInParam in_param;
    475 
    476   // If we get SEC_ERROR_UNKNOWN_ISSUER, we may be missing an intermediate
    477   // CA certificate, so we retry with cert_pi_useAIACertFetch.
    478   // cert_pi_useAIACertFetch has several bugs in its error handling and
    479   // error reporting (NSS bug 528743), so we don't use it by default.
    480   // Note: When building a certificate chain, CERT_PKIXVerifyCert may
    481   // incorrectly pick a CA certificate with the same subject name as the
    482   // missing intermediate CA certificate, and  fail with the
    483   // SEC_ERROR_BAD_SIGNATURE error (NSS bug 524013), so we also retry with
    484   // cert_pi_useAIACertFetch on SEC_ERROR_BAD_SIGNATURE.
    485   if (cert_io_enabled &&
    486       (nss_error == SEC_ERROR_UNKNOWN_ISSUER ||
    487        nss_error == SEC_ERROR_BAD_SIGNATURE)) {
    488     DCHECK_EQ(cvin->back().type,  cert_pi_end);
    489     cvin->pop_back();
    490     in_param.type = cert_pi_useAIACertFetch;
    491     in_param.value.scalar.b = PR_TRUE;
    492     cvin->push_back(in_param);
    493     in_param.type = cert_pi_end;
    494     cvin->push_back(in_param);
    495     rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
    496                              &(*cvin)[0], cvout, NULL);
    497     if (rv == SECSuccess)
    498       return rv;
    499     int new_nss_error = PORT_GetError();
    500     if (new_nss_error == SEC_ERROR_INVALID_ARGS ||
    501         new_nss_error == SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE ||
    502         new_nss_error == SEC_ERROR_BAD_INFO_ACCESS_LOCATION ||
    503         new_nss_error == SEC_ERROR_BAD_HTTP_RESPONSE ||
    504         new_nss_error == SEC_ERROR_BAD_LDAP_RESPONSE ||
    505         !IS_SEC_ERROR(new_nss_error)) {
    506       // Use the original error code because of cert_pi_useAIACertFetch's
    507       // bad error reporting.
    508       PORT_SetError(nss_error);
    509       return rv;
    510     }
    511     nss_error = new_nss_error;
    512   }
    513 
    514   // If an intermediate CA certificate has requireExplicitPolicy in its
    515   // policyConstraints extension, CERT_PKIXVerifyCert fails with
    516   // SEC_ERROR_POLICY_VALIDATION_FAILED because we didn't specify any
    517   // certificate policy (NSS bug 552775).  So we retry with the certificate
    518   // policy found in the server certificate.
    519   if (nss_error == SEC_ERROR_POLICY_VALIDATION_FAILED &&
    520       num_policy_oids == 0) {
    521     SECOidTag policy = GetFirstCertPolicy(cert_handle);
    522     if (policy != SEC_OID_UNKNOWN) {
    523       DCHECK_EQ(cvin->back().type,  cert_pi_end);
    524       cvin->pop_back();
    525       in_param.type = cert_pi_policyOID;
    526       in_param.value.arraySize = 1;
    527       in_param.value.array.oids = &policy;
    528       cvin->push_back(in_param);
    529       in_param.type = cert_pi_end;
    530       cvin->push_back(in_param);
    531       rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
    532                                &(*cvin)[0], cvout, NULL);
    533       if (rv != SECSuccess) {
    534         // Use the original error code.
    535         PORT_SetError(nss_error);
    536       }
    537     }
    538   }
    539 
    540   return rv;
    541 }
    542 
    543 // Decodes the certificatePolicies extension of the certificate.  Returns
    544 // NULL if the certificate doesn't have the extension or the extension can't
    545 // be decoded.  The returned value must be freed with a
    546 // CERT_DestroyCertificatePoliciesExtension call.
    547 CERTCertificatePolicies* DecodeCertPolicies(
    548     CERTCertificate* cert_handle) {
    549   SECItem policy_ext;
    550   SECStatus rv = CERT_FindCertExtension(cert_handle,
    551                                         SEC_OID_X509_CERTIFICATE_POLICIES,
    552                                         &policy_ext);
    553   if (rv != SECSuccess)
    554     return NULL;
    555   CERTCertificatePolicies* policies =
    556       CERT_DecodeCertificatePoliciesExtension(&policy_ext);
    557   SECITEM_FreeItem(&policy_ext, PR_FALSE);
    558   return policies;
    559 }
    560 
    561 // Returns the OID tag for the first certificate policy in the certificate's
    562 // certificatePolicies extension.  Returns SEC_OID_UNKNOWN if the certificate
    563 // has no certificate policy.
    564 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle) {
    565   ScopedCERTCertificatePolicies policies(DecodeCertPolicies(cert_handle));
    566   if (!policies.get())
    567     return SEC_OID_UNKNOWN;
    568 
    569   CERTPolicyInfo* policy_info = policies->policyInfos[0];
    570   if (!policy_info)
    571     return SEC_OID_UNKNOWN;
    572   if (policy_info->oid != SEC_OID_UNKNOWN)
    573     return policy_info->oid;
    574 
    575   // The certificate policy is unknown to NSS.  We need to create a dynamic
    576   // OID tag for the policy.
    577   SECOidData od;
    578   od.oid.len = policy_info->policyID.len;
    579   od.oid.data = policy_info->policyID.data;
    580   od.offset = SEC_OID_UNKNOWN;
    581   // NSS doesn't allow us to pass an empty description, so I use a hardcoded,
    582   // default description here.  The description doesn't need to be unique for
    583   // each OID.
    584   od.desc = "a certificate policy";
    585   od.mechanism = CKM_INVALID_MECHANISM;
    586   od.supportedExtension = INVALID_CERT_EXTENSION;
    587   return SECOID_AddEntry(&od);
    588 }
    589 
    590 HashValue CertPublicKeyHashSHA1(CERTCertificate* cert) {
    591   HashValue hash(HASH_VALUE_SHA1);
    592 #if defined(OS_IOS)
    593   CC_SHA1(cert->derPublicKey.data, cert->derPublicKey.len, hash.data());
    594 #else
    595   SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, hash.data(),
    596                               cert->derPublicKey.data, cert->derPublicKey.len);
    597   DCHECK_EQ(SECSuccess, rv);
    598 #endif
    599   return hash;
    600 }
    601 
    602 HashValue CertPublicKeyHashSHA256(CERTCertificate* cert) {
    603   HashValue hash(HASH_VALUE_SHA256);
    604 #if defined(OS_IOS)
    605   CC_SHA256(cert->derPublicKey.data, cert->derPublicKey.len, hash.data());
    606 #else
    607   SECStatus rv = HASH_HashBuf(HASH_AlgSHA256, hash.data(),
    608                               cert->derPublicKey.data, cert->derPublicKey.len);
    609   DCHECK_EQ(rv, SECSuccess);
    610 #endif
    611   return hash;
    612 }
    613 
    614 void AppendPublicKeyHashes(CERTCertList* cert_list,
    615                            CERTCertificate* root_cert,
    616                            HashValueVector* hashes) {
    617   for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
    618        !CERT_LIST_END(node, cert_list);
    619        node = CERT_LIST_NEXT(node)) {
    620     hashes->push_back(CertPublicKeyHashSHA1(node->cert));
    621     hashes->push_back(CertPublicKeyHashSHA256(node->cert));
    622   }
    623   if (root_cert) {
    624     hashes->push_back(CertPublicKeyHashSHA1(root_cert));
    625     hashes->push_back(CertPublicKeyHashSHA256(root_cert));
    626   }
    627 }
    628 
    629 // Returns true if |cert_handle| contains a policy OID that is an EV policy
    630 // OID according to |metadata|, storing the resulting policy OID in
    631 // |*ev_policy_oid|. A true return is not sufficient to establish that a
    632 // certificate is EV, but a false return is sufficient to establish the
    633 // certificate cannot be EV.
    634 bool IsEVCandidate(EVRootCAMetadata* metadata,
    635                    CERTCertificate* cert_handle,
    636                    SECOidTag* ev_policy_oid) {
    637   DCHECK(cert_handle);
    638   ScopedCERTCertificatePolicies policies(DecodeCertPolicies(cert_handle));
    639   if (!policies.get())
    640     return false;
    641 
    642   CERTPolicyInfo** policy_infos = policies->policyInfos;
    643   while (*policy_infos != NULL) {
    644     CERTPolicyInfo* policy_info = *policy_infos++;
    645     // If the Policy OID is unknown, that implicitly means it has not been
    646     // registered as an EV policy.
    647     if (policy_info->oid == SEC_OID_UNKNOWN)
    648       continue;
    649     if (metadata->IsEVPolicyOID(policy_info->oid)) {
    650       *ev_policy_oid = policy_info->oid;
    651       return true;
    652     }
    653   }
    654 
    655   return false;
    656 }
    657 
    658 // Studied Mozilla's code (esp. security/manager/ssl/src/nsIdentityChecking.cpp
    659 // and nsNSSCertHelper.cpp) to learn how to verify EV certificate.
    660 // TODO(wtc): A possible optimization is that we get the trust anchor from
    661 // the first PKIXVerifyCert call.  We look up the EV policy for the trust
    662 // anchor.  If the trust anchor has no EV policy, we know the cert isn't EV.
    663 // Otherwise, we pass just that EV policy (as opposed to all the EV policies)
    664 // to the second PKIXVerifyCert call.
    665 bool VerifyEV(CERTCertificate* cert_handle,
    666               int flags,
    667               CRLSet* crl_set,
    668               bool rev_checking_enabled,
    669               EVRootCAMetadata* metadata,
    670               SECOidTag ev_policy_oid,
    671               CERTCertList* additional_trust_anchors) {
    672   CERTValOutParam cvout[3];
    673   int cvout_index = 0;
    674   cvout[cvout_index].type = cert_po_certList;
    675   cvout[cvout_index].value.pointer.chain = NULL;
    676   int cvout_cert_list_index = cvout_index;
    677   cvout_index++;
    678   cvout[cvout_index].type = cert_po_trustAnchor;
    679   cvout[cvout_index].value.pointer.cert = NULL;
    680   int cvout_trust_anchor_index = cvout_index;
    681   cvout_index++;
    682   cvout[cvout_index].type = cert_po_end;
    683   ScopedCERTValOutParam scoped_cvout(cvout);
    684 
    685   SECStatus status = PKIXVerifyCert(
    686       cert_handle,
    687       rev_checking_enabled,
    688       true, /* hard fail is implied in EV. */
    689       flags & CertVerifier::VERIFY_CERT_IO_ENABLED,
    690       &ev_policy_oid,
    691       1,
    692       additional_trust_anchors,
    693       cvout);
    694   if (status != SECSuccess)
    695     return false;
    696 
    697   CERTCertificate* root_ca =
    698       cvout[cvout_trust_anchor_index].value.pointer.cert;
    699   if (root_ca == NULL)
    700     return false;
    701 
    702   // This second PKIXVerifyCert call could have found a different certification
    703   // path and one or more of the certificates on this new path, that weren't on
    704   // the old path, might have been revoked.
    705   if (crl_set) {
    706     CRLSetResult crl_set_result = CheckRevocationWithCRLSet(
    707         cvout[cvout_cert_list_index].value.pointer.chain,
    708         cvout[cvout_trust_anchor_index].value.pointer.cert,
    709         crl_set);
    710     if (crl_set_result == kCRLSetRevoked)
    711       return false;
    712   }
    713 
    714 #if defined(OS_IOS)
    715   SHA1HashValue fingerprint = x509_util_ios::CalculateFingerprintNSS(root_ca);
    716 #else
    717   SHA1HashValue fingerprint =
    718       X509Certificate::CalculateFingerprint(root_ca);
    719 #endif
    720   return metadata->HasEVPolicyOID(fingerprint, ev_policy_oid);
    721 }
    722 
    723 CERTCertList* CertificateListToCERTCertList(const CertificateList& list) {
    724   CERTCertList* result = CERT_NewCertList();
    725   for (size_t i = 0; i < list.size(); ++i) {
    726 #if defined(OS_IOS)
    727     // X509Certificate::os_cert_handle() on iOS is a SecCertificateRef; convert
    728     // it to an NSS CERTCertificate.
    729     CERTCertificate* cert = x509_util_ios::CreateNSSCertHandleFromOSHandle(
    730         list[i]->os_cert_handle());
    731 #else
    732     CERTCertificate* cert = list[i]->os_cert_handle();
    733 #endif
    734     CERT_AddCertToListTail(result, CERT_DupCertificate(cert));
    735   }
    736   return result;
    737 }
    738 
    739 }  // namespace
    740 
    741 CertVerifyProcNSS::CertVerifyProcNSS() {}
    742 
    743 CertVerifyProcNSS::~CertVerifyProcNSS() {}
    744 
    745 bool CertVerifyProcNSS::SupportsAdditionalTrustAnchors() const {
    746   // This requires APIs introduced in 3.14.2.
    747   return NSS_VersionCheck("3.14.2");
    748 }
    749 
    750 int CertVerifyProcNSS::VerifyInternal(
    751     X509Certificate* cert,
    752     const std::string& hostname,
    753     int flags,
    754     CRLSet* crl_set,
    755     const CertificateList& additional_trust_anchors,
    756     CertVerifyResult* verify_result) {
    757 #if defined(OS_IOS)
    758   // For iOS, the entire chain must be loaded into NSS's in-memory certificate
    759   // store.
    760   x509_util_ios::NSSCertChain scoped_chain(cert);
    761   CERTCertificate* cert_handle = scoped_chain.cert_handle();
    762 #else
    763   CERTCertificate* cert_handle = cert->os_cert_handle();
    764 #endif  // defined(OS_IOS)
    765 
    766   // Make sure that the hostname matches with the common name of the cert.
    767   SECStatus status = CERT_VerifyCertName(cert_handle, hostname.c_str());
    768   if (status != SECSuccess)
    769     verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
    770 
    771   // Make sure that the cert is valid now.
    772   SECCertTimeValidity validity = CERT_CheckCertValidTimes(
    773       cert_handle, PR_Now(), PR_TRUE);
    774   if (validity != secCertTimeValid)
    775     verify_result->cert_status |= CERT_STATUS_DATE_INVALID;
    776 
    777   CERTValOutParam cvout[3];
    778   int cvout_index = 0;
    779   cvout[cvout_index].type = cert_po_certList;
    780   cvout[cvout_index].value.pointer.chain = NULL;
    781   int cvout_cert_list_index = cvout_index;
    782   cvout_index++;
    783   cvout[cvout_index].type = cert_po_trustAnchor;
    784   cvout[cvout_index].value.pointer.cert = NULL;
    785   int cvout_trust_anchor_index = cvout_index;
    786   cvout_index++;
    787   cvout[cvout_index].type = cert_po_end;
    788   ScopedCERTValOutParam scoped_cvout(cvout);
    789 
    790   EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
    791   SECOidTag ev_policy_oid = SEC_OID_UNKNOWN;
    792   bool is_ev_candidate =
    793       (flags & CertVerifier::VERIFY_EV_CERT) &&
    794       IsEVCandidate(metadata, cert_handle, &ev_policy_oid);
    795   bool cert_io_enabled = flags & CertVerifier::VERIFY_CERT_IO_ENABLED;
    796   bool check_revocation =
    797       cert_io_enabled &&
    798       (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED);
    799   if (check_revocation)
    800     verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
    801 
    802   ScopedCERTCertList trust_anchors;
    803   if (SupportsAdditionalTrustAnchors() && !additional_trust_anchors.empty()) {
    804     trust_anchors.reset(
    805         CertificateListToCERTCertList(additional_trust_anchors));
    806   }
    807 
    808   status = PKIXVerifyCert(cert_handle, check_revocation, false,
    809                           cert_io_enabled, NULL, 0, trust_anchors.get(),
    810                           cvout);
    811 
    812   if (status == SECSuccess &&
    813       (flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) &&
    814       !IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert)) {
    815     // TODO(rsleevi): Optimize this by supplying the constructed chain to
    816     // libpkix via cvin. Omitting for now, due to lack of coverage in upstream
    817     // NSS tests for that feature.
    818     scoped_cvout.Clear();
    819     verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
    820     status = PKIXVerifyCert(cert_handle, true, true,
    821                             cert_io_enabled, NULL, 0, trust_anchors.get(),
    822                             cvout);
    823   }
    824 
    825   if (status == SECSuccess) {
    826     AppendPublicKeyHashes(cvout[cvout_cert_list_index].value.pointer.chain,
    827                           cvout[cvout_trust_anchor_index].value.pointer.cert,
    828                           &verify_result->public_key_hashes);
    829 
    830     verify_result->is_issued_by_known_root =
    831         IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert);
    832     verify_result->is_issued_by_additional_trust_anchor =
    833         IsAdditionalTrustAnchor(
    834             trust_anchors.get(),
    835             cvout[cvout_trust_anchor_index].value.pointer.cert);
    836 
    837     GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain,
    838                      cvout[cvout_trust_anchor_index].value.pointer.cert,
    839                      verify_result);
    840   }
    841 
    842   CRLSetResult crl_set_result = kCRLSetUnknown;
    843   if (crl_set) {
    844     crl_set_result = CheckRevocationWithCRLSet(
    845         cvout[cvout_cert_list_index].value.pointer.chain,
    846         cvout[cvout_trust_anchor_index].value.pointer.cert,
    847         crl_set);
    848     if (crl_set_result == kCRLSetRevoked) {
    849       PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
    850       status = SECFailure;
    851     }
    852   }
    853 
    854   if (status != SECSuccess) {
    855     int err = PORT_GetError();
    856     LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname
    857                << " failed err=" << err;
    858     // CERT_PKIXVerifyCert rerports the wrong error code for
    859     // expired certificates (NSS bug 491174)
    860     if (err == SEC_ERROR_CERT_NOT_VALID &&
    861         (verify_result->cert_status & CERT_STATUS_DATE_INVALID))
    862       err = SEC_ERROR_EXPIRED_CERTIFICATE;
    863     CertStatus cert_status = MapCertErrorToCertStatus(err);
    864     if (cert_status) {
    865       verify_result->cert_status |= cert_status;
    866       return MapCertStatusToNetError(verify_result->cert_status);
    867     }
    868     // |err| is not a certificate error.
    869     return MapSecurityError(err);
    870   }
    871 
    872   if (IsCertStatusError(verify_result->cert_status))
    873     return MapCertStatusToNetError(verify_result->cert_status);
    874 
    875   if ((flags & CertVerifier::VERIFY_EV_CERT) && is_ev_candidate) {
    876     check_revocation |=
    877         crl_set_result != kCRLSetOk &&
    878         cert_io_enabled &&
    879         (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY);
    880     if (check_revocation)
    881       verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
    882 
    883     if (VerifyEV(cert_handle, flags, crl_set, check_revocation, metadata,
    884                  ev_policy_oid, trust_anchors.get())) {
    885       verify_result->cert_status |= CERT_STATUS_IS_EV;
    886     }
    887   }
    888 
    889   return OK;
    890 }
    891 
    892 }  // namespace net
    893