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