Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2006-2008 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/base/x509_certificate.h"
      6 
      7 #include <cert.h>
      8 #include <pk11pub.h>
      9 #include <prerror.h>
     10 #include <prtime.h>
     11 #include <secder.h>
     12 #include <secerr.h>
     13 #include <sechash.h>
     14 #include <sslerr.h>
     15 
     16 #include "base/logging.h"
     17 #include "base/pickle.h"
     18 #include "base/time.h"
     19 #include "base/nss_util.h"
     20 #include "net/base/cert_status_flags.h"
     21 #include "net/base/cert_verify_result.h"
     22 #include "net/base/ev_root_ca_metadata.h"
     23 #include "net/base/net_errors.h"
     24 
     25 namespace net {
     26 
     27 namespace {
     28 
     29 class ScopedCERTCertificate {
     30  public:
     31   explicit ScopedCERTCertificate(CERTCertificate* cert)
     32       : cert_(cert) {}
     33 
     34   ~ScopedCERTCertificate() {
     35     if (cert_)
     36       CERT_DestroyCertificate(cert_);
     37   }
     38 
     39  private:
     40   CERTCertificate* cert_;
     41 
     42   DISALLOW_COPY_AND_ASSIGN(ScopedCERTCertificate);
     43 };
     44 
     45 class ScopedCERTCertList {
     46  public:
     47   explicit ScopedCERTCertList(CERTCertList* cert_list)
     48       : cert_list_(cert_list) {}
     49 
     50   ~ScopedCERTCertList() {
     51     if (cert_list_)
     52       CERT_DestroyCertList(cert_list_);
     53   }
     54 
     55  private:
     56   CERTCertList* cert_list_;
     57 
     58   DISALLOW_COPY_AND_ASSIGN(ScopedCERTCertList);
     59 };
     60 
     61 class ScopedCERTCertificatePolicies {
     62  public:
     63   explicit ScopedCERTCertificatePolicies(CERTCertificatePolicies* policies)
     64       : policies_(policies) {}
     65 
     66   ~ScopedCERTCertificatePolicies() {
     67     if (policies_)
     68       CERT_DestroyCertificatePoliciesExtension(policies_);
     69   }
     70 
     71  private:
     72   CERTCertificatePolicies* policies_;
     73 
     74   DISALLOW_COPY_AND_ASSIGN(ScopedCERTCertificatePolicies);
     75 };
     76 
     77 // ScopedCERTValOutParam manages destruction of values in the CERTValOutParam
     78 // array that cvout points to.  cvout must be initialized as passed to
     79 // CERT_PKIXVerifyCert, so that the array must be terminated with
     80 // cert_po_end type.
     81 // When it goes out of scope, it destroys values of cert_po_trustAnchor
     82 // and cert_po_certList types, but doesn't release the array itself.
     83 class ScopedCERTValOutParam {
     84  public:
     85   explicit ScopedCERTValOutParam(CERTValOutParam* cvout)
     86       : cvout_(cvout) {}
     87 
     88   ~ScopedCERTValOutParam() {
     89     if (cvout_ == NULL)
     90       return;
     91     for (CERTValOutParam *p = cvout_; p->type != cert_po_end; p++) {
     92       switch (p->type) {
     93         case cert_po_trustAnchor:
     94           if (p->value.pointer.cert) {
     95             CERT_DestroyCertificate(p->value.pointer.cert);
     96             p->value.pointer.cert = NULL;
     97           }
     98           break;
     99         case cert_po_certList:
    100           if (p->value.pointer.chain) {
    101             CERT_DestroyCertList(p->value.pointer.chain);
    102             p->value.pointer.chain = NULL;
    103           }
    104           break;
    105         default:
    106           break;
    107       }
    108     }
    109   }
    110 
    111  private:
    112   CERTValOutParam* cvout_;
    113 
    114   DISALLOW_COPY_AND_ASSIGN(ScopedCERTValOutParam);
    115 };
    116 
    117 // Map PORT_GetError() return values to our network error codes.
    118 int MapSecurityError(int err) {
    119   switch (err) {
    120     case PR_DIRECTORY_LOOKUP_ERROR:  // DNS lookup error.
    121       return ERR_NAME_NOT_RESOLVED;
    122     case SEC_ERROR_INVALID_ARGS:
    123       return ERR_INVALID_ARGUMENT;
    124     case SSL_ERROR_BAD_CERT_DOMAIN:
    125       return ERR_CERT_COMMON_NAME_INVALID;
    126     case SEC_ERROR_INVALID_TIME:
    127     case SEC_ERROR_EXPIRED_CERTIFICATE:
    128       return ERR_CERT_DATE_INVALID;
    129     case SEC_ERROR_UNKNOWN_ISSUER:
    130     case SEC_ERROR_UNTRUSTED_ISSUER:
    131     case SEC_ERROR_CA_CERT_INVALID:
    132     case SEC_ERROR_UNTRUSTED_CERT:
    133       return ERR_CERT_AUTHORITY_INVALID;
    134     case SEC_ERROR_REVOKED_CERTIFICATE:
    135       return ERR_CERT_REVOKED;
    136     case SEC_ERROR_BAD_DER:
    137     case SEC_ERROR_BAD_SIGNATURE:
    138     case SEC_ERROR_CERT_NOT_VALID:
    139     // TODO(port): add an ERR_CERT_WRONG_USAGE error code.
    140     case SEC_ERROR_CERT_USAGES_INVALID:
    141       return ERR_CERT_INVALID;
    142     default:
    143       LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
    144       return ERR_FAILED;
    145   }
    146 }
    147 
    148 // Map PORT_GetError() return values to our cert status flags.
    149 int MapCertErrorToCertStatus(int err) {
    150   switch (err) {
    151     case SSL_ERROR_BAD_CERT_DOMAIN:
    152       return CERT_STATUS_COMMON_NAME_INVALID;
    153     case SEC_ERROR_INVALID_TIME:
    154     case SEC_ERROR_EXPIRED_CERTIFICATE:
    155       return CERT_STATUS_DATE_INVALID;
    156     case SEC_ERROR_UNTRUSTED_CERT:
    157     case SEC_ERROR_UNKNOWN_ISSUER:
    158     case SEC_ERROR_UNTRUSTED_ISSUER:
    159     case SEC_ERROR_CA_CERT_INVALID:
    160       return CERT_STATUS_AUTHORITY_INVALID;
    161     // TODO(port): map CERT_STATUS_NO_REVOCATION_MECHANISM.
    162     case SEC_ERROR_OCSP_BAD_HTTP_RESPONSE:
    163     case SEC_ERROR_OCSP_SERVER_ERROR:
    164       return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
    165     case SEC_ERROR_REVOKED_CERTIFICATE:
    166       return CERT_STATUS_REVOKED;
    167     case SEC_ERROR_BAD_DER:
    168     case SEC_ERROR_BAD_SIGNATURE:
    169     case SEC_ERROR_CERT_NOT_VALID:
    170     // TODO(port): add a CERT_STATUS_WRONG_USAGE error code.
    171     case SEC_ERROR_CERT_USAGES_INVALID:
    172       return CERT_STATUS_INVALID;
    173     default:
    174       return 0;
    175   }
    176 }
    177 
    178 // Saves some information about the certificate chain cert_list in
    179 // *verify_result.  The caller MUST initialize *verify_result before calling
    180 // this function.
    181 // Note that cert_list[0] is the end entity certificate and cert_list doesn't
    182 // contain the root CA certificate.
    183 void GetCertChainInfo(CERTCertList* cert_list,
    184                       CertVerifyResult* verify_result) {
    185   // NOTE: Using a NSS library before 3.12.3.1 will crash below.  To see the
    186   // NSS version currently in use:
    187   // 1. use ldd on the chrome executable for NSS's location (ie. libnss3.so*)
    188   // 2. use ident libnss3.so* for the library's version
    189   DCHECK(cert_list);
    190   int i = 0;
    191   for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
    192        !CERT_LIST_END(node, cert_list);
    193        node = CERT_LIST_NEXT(node), i++) {
    194     SECAlgorithmID& signature = node->cert->signature;
    195     SECOidTag oid_tag = SECOID_FindOIDTag(&signature.algorithm);
    196     switch (oid_tag) {
    197       case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
    198         verify_result->has_md5 = true;
    199         if (i != 0)
    200           verify_result->has_md5_ca = true;
    201         break;
    202       case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
    203         verify_result->has_md2 = true;
    204         if (i != 0)
    205           verify_result->has_md2_ca = true;
    206         break;
    207       case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
    208         verify_result->has_md4 = true;
    209         break;
    210       default:
    211         break;
    212     }
    213   }
    214 }
    215 
    216 typedef char* (*CERTGetNameFunc)(CERTName* name);
    217 
    218 void ParsePrincipal(CERTName* name,
    219                     X509Certificate::Principal* principal) {
    220   // TODO(jcampan): add business_category and serial_number.
    221   // TODO(wtc): NSS has the CERT_GetOrgName, CERT_GetOrgUnitName, and
    222   // CERT_GetDomainComponentName functions, but they return only the most
    223   // general (the first) RDN.  NSS doesn't have a function for the street
    224   // address.
    225   static const SECOidTag kOIDs[] = {
    226       SEC_OID_AVA_STREET_ADDRESS,
    227       SEC_OID_AVA_ORGANIZATION_NAME,
    228       SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME,
    229       SEC_OID_AVA_DC };
    230 
    231   std::vector<std::string>* values[] = {
    232       &principal->street_addresses,
    233       &principal->organization_names,
    234       &principal->organization_unit_names,
    235       &principal->domain_components };
    236   DCHECK(arraysize(kOIDs) == arraysize(values));
    237 
    238   CERTRDN** rdns = name->rdns;
    239   for (size_t rdn = 0; rdns[rdn]; ++rdn) {
    240     CERTAVA** avas = rdns[rdn]->avas;
    241     for (size_t pair = 0; avas[pair] != 0; ++pair) {
    242       SECOidTag tag = CERT_GetAVATag(avas[pair]);
    243       for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) {
    244         if (kOIDs[oid] == tag) {
    245           SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value);
    246           if (!decode_item)
    247             break;
    248           // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote.
    249           std::string value(reinterpret_cast<char*>(decode_item->data),
    250                             decode_item->len);
    251           values[oid]->push_back(value);
    252           SECITEM_FreeItem(decode_item, PR_TRUE);
    253           break;
    254         }
    255       }
    256     }
    257   }
    258 
    259   // Get CN, L, S, and C.
    260   CERTGetNameFunc get_name_funcs[4] = {
    261       CERT_GetCommonName, CERT_GetLocalityName,
    262       CERT_GetStateName, CERT_GetCountryName };
    263   std::string* single_values[4] = {
    264       &principal->common_name, &principal->locality_name,
    265       &principal->state_or_province_name, &principal->country_name };
    266   for (size_t i = 0; i < arraysize(get_name_funcs); ++i) {
    267     char* value = get_name_funcs[i](name);
    268     if (value) {
    269       single_values[i]->assign(value);
    270       PORT_Free(value);
    271     }
    272   }
    273 }
    274 
    275 void ParseDate(SECItem* der_date, base::Time* result) {
    276   PRTime prtime;
    277   SECStatus rv = DER_DecodeTimeChoice(&prtime, der_date);
    278   DCHECK(rv == SECSuccess);
    279   *result = base::PRTimeToBaseTime(prtime);
    280 }
    281 
    282 void GetCertSubjectAltNamesOfType(X509Certificate::OSCertHandle cert_handle,
    283                                   CERTGeneralNameType name_type,
    284                                   std::vector<std::string>* result) {
    285   // For future extension: We only support general names of types
    286   // RFC822Name, DNSName or URI.
    287   DCHECK(name_type == certRFC822Name ||
    288          name_type == certDNSName ||
    289          name_type == certURI);
    290 
    291   SECItem alt_name;
    292   SECStatus rv = CERT_FindCertExtension(cert_handle,
    293       SEC_OID_X509_SUBJECT_ALT_NAME, &alt_name);
    294   if (rv != SECSuccess)
    295     return;
    296 
    297   PRArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    298   DCHECK(arena != NULL);
    299 
    300   CERTGeneralName* alt_name_list;
    301   alt_name_list = CERT_DecodeAltNameExtension(arena, &alt_name);
    302   SECITEM_FreeItem(&alt_name, PR_FALSE);
    303 
    304   CERTGeneralName* name = alt_name_list;
    305   while (name) {
    306     // All of the general name types we support are encoded as
    307     // IA5String. In general, we should be switching off
    308     // |name->type| and doing type-appropriate conversions.
    309     if (name->type == name_type) {
    310       unsigned char* p = name->name.other.data;
    311       int len = name->name.other.len;
    312       std::string value = std::string(reinterpret_cast<char*>(p), len);
    313       result->push_back(value);
    314     }
    315     name = CERT_GetNextGeneralName(name);
    316     if (name == alt_name_list)
    317       break;
    318   }
    319   PORT_FreeArena(arena, PR_FALSE);
    320 }
    321 
    322 // Call CERT_PKIXVerifyCert for the cert_handle.
    323 // Verification results are stored in an array of CERTValOutParam.
    324 // If policy_oids is not NULL and num_policy_oids is positive, policies
    325 // are also checked.
    326 // Caller must initialize cvout before calling this function.
    327 SECStatus PKIXVerifyCert(X509Certificate::OSCertHandle cert_handle,
    328                          bool check_revocation,
    329                          const SECOidTag* policy_oids,
    330                          int num_policy_oids,
    331                          CERTValOutParam* cvout) {
    332   bool use_crl = check_revocation;
    333   bool use_ocsp = check_revocation;
    334 
    335   PRUint64 revocation_method_flags =
    336       CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD |
    337       CERT_REV_M_ALLOW_NETWORK_FETCHING |
    338       CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE |
    339       CERT_REV_M_IGNORE_MISSING_FRESH_INFO |
    340       CERT_REV_M_STOP_TESTING_ON_FRESH_INFO;
    341   PRUint64 revocation_method_independent_flags =
    342       CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST;
    343   if (policy_oids && num_policy_oids > 0) {
    344     // EV verification requires revocation checking.  Consider the certificate
    345     // revoked if we don't have revocation info.
    346     // TODO(wtc): Add a bool parameter to expressly specify we're doing EV
    347     // verification or we want strict revocation flags.
    348     revocation_method_flags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE;
    349     revocation_method_independent_flags |=
    350         CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;
    351   } else {
    352     revocation_method_flags |= CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE;
    353     revocation_method_independent_flags |=
    354         CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT;
    355   }
    356   PRUint64 method_flags[2];
    357   method_flags[cert_revocation_method_crl] = revocation_method_flags;
    358   method_flags[cert_revocation_method_ocsp] = revocation_method_flags;
    359 
    360   if (use_crl) {
    361     method_flags[cert_revocation_method_crl] |=
    362         CERT_REV_M_TEST_USING_THIS_METHOD;
    363   }
    364   if (use_ocsp) {
    365     method_flags[cert_revocation_method_ocsp] |=
    366         CERT_REV_M_TEST_USING_THIS_METHOD;
    367   }
    368 
    369   CERTRevocationMethodIndex preferred_revocation_methods[1];
    370   if (use_ocsp) {
    371     preferred_revocation_methods[0] = cert_revocation_method_ocsp;
    372   } else {
    373     preferred_revocation_methods[0] = cert_revocation_method_crl;
    374   }
    375 
    376   CERTRevocationFlags revocation_flags;
    377   revocation_flags.leafTests.number_of_defined_methods =
    378       arraysize(method_flags);
    379   revocation_flags.leafTests.cert_rev_flags_per_method = method_flags;
    380   revocation_flags.leafTests.number_of_preferred_methods =
    381       arraysize(preferred_revocation_methods);
    382   revocation_flags.leafTests.preferred_methods = preferred_revocation_methods;
    383   revocation_flags.leafTests.cert_rev_method_independent_flags =
    384       revocation_method_independent_flags;
    385 
    386   revocation_flags.chainTests.number_of_defined_methods =
    387       arraysize(method_flags);
    388   revocation_flags.chainTests.cert_rev_flags_per_method = method_flags;
    389   revocation_flags.chainTests.number_of_preferred_methods =
    390       arraysize(preferred_revocation_methods);
    391   revocation_flags.chainTests.preferred_methods = preferred_revocation_methods;
    392   revocation_flags.chainTests.cert_rev_method_independent_flags =
    393       revocation_method_independent_flags;
    394 
    395   CERTValInParam cvin[4];
    396   int cvin_index = 0;
    397   // No need to set cert_pi_trustAnchors here.
    398   cvin[cvin_index].type = cert_pi_revocationFlags;
    399   cvin[cvin_index].value.pointer.revocation = &revocation_flags;
    400   cvin_index++;
    401   std::vector<SECOidTag> policies;
    402   if (policy_oids && num_policy_oids > 0) {
    403     cvin[cvin_index].type = cert_pi_policyOID;
    404     cvin[cvin_index].value.arraySize = num_policy_oids;
    405     cvin[cvin_index].value.array.oids = policy_oids;
    406     cvin_index++;
    407   }
    408   // Add cert_pi_useAIACertFetch last so we can easily remove it from the
    409   // cvin array in the workaround below.
    410   cvin[cvin_index].type = cert_pi_useAIACertFetch;
    411   cvin[cvin_index].value.scalar.b = PR_TRUE;
    412   cvin_index++;
    413   cvin[cvin_index].type = cert_pi_end;
    414 
    415   SECStatus rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
    416                                      cvin, cvout, NULL);
    417   if (rv != SECSuccess) {
    418     // cert_pi_useAIACertFetch can't handle a CA issuers access location that
    419     // is an LDAP URL with an empty host name (NSS bug 528741).  If cert fetch
    420     // fails because of a network error, it also causes CERT_PKIXVerifyCert
    421     // to report the network error rather than SEC_ERROR_UNKNOWN_ISSUER.  To
    422     // work around these NSS bugs, we retry without cert_pi_useAIACertFetch.
    423     int nss_error = PORT_GetError();
    424     if (nss_error == SEC_ERROR_INVALID_ARGS || !IS_SEC_ERROR(nss_error)) {
    425       cvin_index--;
    426       DCHECK_EQ(cvin[cvin_index].type, cert_pi_useAIACertFetch);
    427       cvin[cvin_index].type = cert_pi_end;
    428       rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
    429                                cvin, cvout, NULL);
    430     }
    431   }
    432   return rv;
    433 }
    434 
    435 bool CheckCertPolicies(X509Certificate::OSCertHandle cert_handle,
    436                        SECOidTag ev_policy_tag) {
    437   SECItem policy_ext;
    438   SECStatus rv = CERT_FindCertExtension(
    439       cert_handle, SEC_OID_X509_CERTIFICATE_POLICIES, &policy_ext);
    440   if (rv != SECSuccess) {
    441     LOG(ERROR) << "Cert has no policies extension.";
    442     return false;
    443   }
    444   CERTCertificatePolicies* policies =
    445       CERT_DecodeCertificatePoliciesExtension(&policy_ext);
    446   SECITEM_FreeItem(&policy_ext, PR_FALSE);
    447   if (!policies) {
    448     LOG(ERROR) << "Failed to decode certificate policy.";
    449     return false;
    450   }
    451   ScopedCERTCertificatePolicies scoped_policies(policies);
    452   CERTPolicyInfo** policy_infos = policies->policyInfos;
    453   while (*policy_infos != NULL) {
    454     CERTPolicyInfo* policy_info = *policy_infos++;
    455     SECOidTag oid_tag = policy_info->oid;
    456     if (oid_tag == SEC_OID_UNKNOWN)
    457       continue;
    458     if (oid_tag == ev_policy_tag)
    459       return true;
    460   }
    461   LOG(ERROR) << "No EV Policy Tag";
    462   return false;
    463 }
    464 
    465 }  // namespace
    466 
    467 void X509Certificate::Initialize() {
    468   ParsePrincipal(&cert_handle_->subject, &subject_);
    469   ParsePrincipal(&cert_handle_->issuer, &issuer_);
    470 
    471   ParseDate(&cert_handle_->validity.notBefore, &valid_start_);
    472   ParseDate(&cert_handle_->validity.notAfter, &valid_expiry_);
    473 
    474   fingerprint_ = CalculateFingerprint(cert_handle_);
    475 
    476   // Store the certificate in the cache in case we need it later.
    477   X509Certificate::Cache::GetInstance()->Insert(this);
    478 }
    479 
    480 // static
    481 X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle,
    482                                                    void** pickle_iter) {
    483   const char* data;
    484   int length;
    485   if (!pickle.ReadData(pickle_iter, &data, &length))
    486     return NULL;
    487 
    488   return CreateFromBytes(data, length);
    489 }
    490 
    491 void X509Certificate::Persist(Pickle* pickle) {
    492   pickle->WriteData(reinterpret_cast<const char*>(cert_handle_->derCert.data),
    493                     cert_handle_->derCert.len);
    494 }
    495 
    496 void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const {
    497   dns_names->clear();
    498 
    499   // Compare with CERT_VerifyCertName().
    500   GetCertSubjectAltNamesOfType(cert_handle_, certDNSName, dns_names);
    501 
    502   // TODO(port): suppress nss's support of the obsolete extension
    503   //  SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME
    504   // by providing our own authCertificate callback.
    505 
    506   if (dns_names->empty())
    507     dns_names->push_back(subject_.common_name);
    508 }
    509 
    510 int X509Certificate::Verify(const std::string& hostname,
    511                             int flags,
    512                             CertVerifyResult* verify_result) const {
    513   verify_result->Reset();
    514 
    515   // Make sure that the hostname matches with the common name of the cert.
    516   SECStatus status = CERT_VerifyCertName(cert_handle_, hostname.c_str());
    517   if (status != SECSuccess)
    518     verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
    519 
    520   // Make sure that the cert is valid now.
    521   SECCertTimeValidity validity = CERT_CheckCertValidTimes(
    522       cert_handle_, PR_Now(), PR_TRUE);
    523   if (validity != secCertTimeValid)
    524     verify_result->cert_status |= CERT_STATUS_DATE_INVALID;
    525 
    526   CERTValOutParam cvout[3];
    527   int cvout_index = 0;
    528   // We don't need the trust anchor for the first PKIXVerifyCert call.
    529   cvout[cvout_index].type = cert_po_certList;
    530   cvout[cvout_index].value.pointer.chain = NULL;
    531   int cvout_cert_list_index = cvout_index;
    532   cvout_index++;
    533   cvout[cvout_index].type = cert_po_end;
    534   ScopedCERTValOutParam scoped_cvout(cvout);
    535 
    536   bool check_revocation = (flags & VERIFY_REV_CHECKING_ENABLED);
    537   if (check_revocation) {
    538     verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
    539   } else {
    540     // EV requires revocation checking.
    541     flags &= ~VERIFY_EV_CERT;
    542   }
    543   status = PKIXVerifyCert(cert_handle_, check_revocation, NULL, 0, cvout);
    544   if (status != SECSuccess) {
    545     int err = PORT_GetError();
    546     LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname
    547                << " failed err=" << err;
    548     // CERT_PKIXVerifyCert rerports the wrong error code for
    549     // expired certificates (NSS bug 491174)
    550     if (err == SEC_ERROR_CERT_NOT_VALID &&
    551         (verify_result->cert_status & CERT_STATUS_DATE_INVALID) != 0)
    552       err = SEC_ERROR_EXPIRED_CERTIFICATE;
    553     int cert_status = MapCertErrorToCertStatus(err);
    554     if (cert_status) {
    555       verify_result->cert_status |= cert_status;
    556       return MapCertStatusToNetError(verify_result->cert_status);
    557     }
    558     // |err| is not a certificate error.
    559     return MapSecurityError(err);
    560   }
    561 
    562   GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain,
    563                    verify_result);
    564   if (IsCertStatusError(verify_result->cert_status))
    565     return MapCertStatusToNetError(verify_result->cert_status);
    566 
    567   if ((flags & VERIFY_EV_CERT) && VerifyEV())
    568     verify_result->cert_status |= CERT_STATUS_IS_EV;
    569   return OK;
    570 }
    571 
    572 // Studied Mozilla's code (esp. security/manager/ssl/src/nsIdentityChecking.cpp
    573 // and nsNSSCertHelper.cpp) to learn how to verify EV certificate.
    574 // TODO(wtc): A possible optimization is that we get the trust anchor from
    575 // the first PKIXVerifyCert call.  We look up the EV policy for the trust
    576 // anchor.  If the trust anchor has no EV policy, we know the cert isn't EV.
    577 // Otherwise, we pass just that EV policy (as opposed to all the EV policies)
    578 // to the second PKIXVerifyCert call.
    579 bool X509Certificate::VerifyEV() const {
    580   net::EVRootCAMetadata* metadata = net::EVRootCAMetadata::GetInstance();
    581 
    582   CERTValOutParam cvout[3];
    583   int cvout_index = 0;
    584   cvout[cvout_index].type = cert_po_trustAnchor;
    585   cvout[cvout_index].value.pointer.cert = NULL;
    586   int cvout_trust_anchor_index = cvout_index;
    587   cvout_index++;
    588   cvout[cvout_index].type = cert_po_end;
    589   ScopedCERTValOutParam scoped_cvout(cvout);
    590 
    591   SECStatus status = PKIXVerifyCert(cert_handle_,
    592                                     true,
    593                                     metadata->GetPolicyOIDs(),
    594                                     metadata->NumPolicyOIDs(),
    595                                     cvout);
    596   if (status != SECSuccess)
    597     return false;
    598 
    599   CERTCertificate* root_ca =
    600       cvout[cvout_trust_anchor_index].value.pointer.cert;
    601   if (root_ca == NULL)
    602     return false;
    603   X509Certificate::Fingerprint fingerprint =
    604       X509Certificate::CalculateFingerprint(root_ca);
    605   SECOidTag ev_policy_tag = SEC_OID_UNKNOWN;
    606   if (!metadata->GetPolicyOID(fingerprint, &ev_policy_tag))
    607     return false;
    608 
    609   if (!CheckCertPolicies(cert_handle_, ev_policy_tag))
    610     return false;
    611 
    612   return true;
    613 }
    614 
    615 // static
    616 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
    617     const char* data, int length) {
    618   base::EnsureNSSInit();
    619 
    620   SECItem der_cert;
    621   der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data));
    622   der_cert.len = length;
    623   return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert,
    624                                  NULL, PR_FALSE, PR_TRUE);
    625 }
    626 
    627 // static
    628 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
    629   CERT_DestroyCertificate(cert_handle);
    630 }
    631 
    632 // static
    633 X509Certificate::Fingerprint X509Certificate::CalculateFingerprint(
    634     OSCertHandle cert) {
    635   Fingerprint sha1;
    636   memset(sha1.data, 0, sizeof(sha1.data));
    637 
    638   DCHECK(NULL != cert->derCert.data);
    639   DCHECK(0 != cert->derCert.len);
    640 
    641   SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, sha1.data,
    642                               cert->derCert.data, cert->derCert.len);
    643   DCHECK(rv == SECSuccess);
    644 
    645   return sha1;
    646 }
    647 
    648 }  // namespace net
    649