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