• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
ScopedCERTCertificate(CERTCertificate * cert)31   explicit ScopedCERTCertificate(CERTCertificate* cert)
32       : cert_(cert) {}
33 
~ScopedCERTCertificate()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:
ScopedCERTCertList(CERTCertList * cert_list)47   explicit ScopedCERTCertList(CERTCertList* cert_list)
48       : cert_list_(cert_list) {}
49 
~ScopedCERTCertList()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:
ScopedCERTCertificatePolicies(CERTCertificatePolicies * policies)63   explicit ScopedCERTCertificatePolicies(CERTCertificatePolicies* policies)
64       : policies_(policies) {}
65 
~ScopedCERTCertificatePolicies()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:
ScopedCERTValOutParam(CERTValOutParam * cvout)85   explicit ScopedCERTValOutParam(CERTValOutParam* cvout)
86       : cvout_(cvout) {}
87 
~ScopedCERTValOutParam()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.
MapSecurityError(int err)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.
MapCertErrorToCertStatus(int err)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.
GetCertChainInfo(CERTCertList * cert_list,CertVerifyResult * verify_result)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 
ParsePrincipal(CERTName * name,X509Certificate::Principal * principal)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 
ParseDate(SECItem * der_date,base::Time * result)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 
GetCertSubjectAltNamesOfType(X509Certificate::OSCertHandle cert_handle,CERTGeneralNameType name_type,std::vector<std::string> * result)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.
PKIXVerifyCert(X509Certificate::OSCertHandle cert_handle,bool check_revocation,const SECOidTag * policy_oids,int num_policy_oids,CERTValOutParam * cvout)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 
CheckCertPolicies(X509Certificate::OSCertHandle cert_handle,SECOidTag ev_policy_tag)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 
Initialize()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
CreateFromPickle(const Pickle & pickle,void ** pickle_iter)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 
Persist(Pickle * pickle)491 void X509Certificate::Persist(Pickle* pickle) {
492   pickle->WriteData(reinterpret_cast<const char*>(cert_handle_->derCert.data),
493                     cert_handle_->derCert.len);
494 }
495 
GetDNSNames(std::vector<std::string> * dns_names) const496 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 
Verify(const std::string & hostname,int flags,CertVerifyResult * verify_result) const510 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.
VerifyEV() const579 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
CreateOSCertHandleFromBytes(const char * data,int length)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
FreeOSCertHandle(OSCertHandle cert_handle)628 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
629   CERT_DestroyCertificate(cert_handle);
630 }
631 
632 // static
CalculateFingerprint(OSCertHandle cert)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