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