1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/cert/cert_verify_proc_nss.h" 6 7 #include <string> 8 #include <vector> 9 10 #include <cert.h> 11 #include <nss.h> 12 #include <prerror.h> 13 #include <secerr.h> 14 #include <sechash.h> 15 #include <sslerr.h> 16 17 #include "base/logging.h" 18 #include "crypto/nss_util.h" 19 #include "crypto/scoped_nss_types.h" 20 #include "crypto/sha2.h" 21 #include "net/base/net_errors.h" 22 #include "net/cert/asn1_util.h" 23 #include "net/cert/cert_status_flags.h" 24 #include "net/cert/cert_verifier.h" 25 #include "net/cert/cert_verify_result.h" 26 #include "net/cert/crl_set.h" 27 #include "net/cert/ev_root_ca_metadata.h" 28 #include "net/cert/x509_certificate.h" 29 #include "net/cert/x509_util_nss.h" 30 31 #if defined(OS_IOS) 32 #include <CommonCrypto/CommonDigest.h> 33 #include "net/cert/x509_util_ios.h" 34 #endif // defined(OS_IOS) 35 36 #define NSS_VERSION_NUM (NSS_VMAJOR * 10000 + NSS_VMINOR * 100 + NSS_VPATCH) 37 #if NSS_VERSION_NUM < 31305 38 // Added in NSS 3.13.5. 39 #define SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED -8016 40 #endif 41 42 #if NSS_VERSION_NUM < 31402 43 // Added in NSS 3.14.2. 44 #define cert_pi_useOnlyTrustAnchors static_cast<CERTValParamInType>(14) 45 #endif 46 47 namespace net { 48 49 namespace { 50 51 typedef scoped_ptr_malloc< 52 CERTCertificatePolicies, 53 crypto::NSSDestroyer<CERTCertificatePolicies, 54 CERT_DestroyCertificatePoliciesExtension> > 55 ScopedCERTCertificatePolicies; 56 57 typedef scoped_ptr_malloc< 58 CERTCertList, 59 crypto::NSSDestroyer<CERTCertList, CERT_DestroyCertList> > 60 ScopedCERTCertList; 61 62 // ScopedCERTValOutParam manages destruction of values in the CERTValOutParam 63 // array that cvout points to. cvout must be initialized as passed to 64 // CERT_PKIXVerifyCert, so that the array must be terminated with 65 // cert_po_end type. 66 // When it goes out of scope, it destroys values of cert_po_trustAnchor 67 // and cert_po_certList types, but doesn't release the array itself. 68 class ScopedCERTValOutParam { 69 public: 70 explicit ScopedCERTValOutParam(CERTValOutParam* cvout) : cvout_(cvout) {} 71 72 ~ScopedCERTValOutParam() { 73 Clear(); 74 } 75 76 // Free the internal resources, but do not release the array itself. 77 void Clear() { 78 if (cvout_ == NULL) 79 return; 80 for (CERTValOutParam *p = cvout_; p->type != cert_po_end; p++) { 81 switch (p->type) { 82 case cert_po_trustAnchor: 83 if (p->value.pointer.cert) { 84 CERT_DestroyCertificate(p->value.pointer.cert); 85 p->value.pointer.cert = NULL; 86 } 87 break; 88 case cert_po_certList: 89 if (p->value.pointer.chain) { 90 CERT_DestroyCertList(p->value.pointer.chain); 91 p->value.pointer.chain = NULL; 92 } 93 break; 94 default: 95 break; 96 } 97 } 98 } 99 100 private: 101 CERTValOutParam* cvout_; 102 103 DISALLOW_COPY_AND_ASSIGN(ScopedCERTValOutParam); 104 }; 105 106 // Map PORT_GetError() return values to our network error codes. 107 int MapSecurityError(int err) { 108 switch (err) { 109 case PR_DIRECTORY_LOOKUP_ERROR: // DNS lookup error. 110 return ERR_NAME_NOT_RESOLVED; 111 case SEC_ERROR_INVALID_ARGS: 112 return ERR_INVALID_ARGUMENT; 113 case SSL_ERROR_BAD_CERT_DOMAIN: 114 return ERR_CERT_COMMON_NAME_INVALID; 115 case SEC_ERROR_INVALID_TIME: 116 case SEC_ERROR_EXPIRED_CERTIFICATE: 117 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: 118 return ERR_CERT_DATE_INVALID; 119 case SEC_ERROR_UNKNOWN_ISSUER: 120 case SEC_ERROR_UNTRUSTED_ISSUER: 121 case SEC_ERROR_CA_CERT_INVALID: 122 return ERR_CERT_AUTHORITY_INVALID; 123 // TODO(port): map ERR_CERT_NO_REVOCATION_MECHANISM. 124 case SEC_ERROR_OCSP_BAD_HTTP_RESPONSE: 125 case SEC_ERROR_OCSP_SERVER_ERROR: 126 return ERR_CERT_UNABLE_TO_CHECK_REVOCATION; 127 case SEC_ERROR_REVOKED_CERTIFICATE: 128 case SEC_ERROR_UNTRUSTED_CERT: // Treat as revoked. 129 return ERR_CERT_REVOKED; 130 case SEC_ERROR_BAD_DER: 131 case SEC_ERROR_BAD_SIGNATURE: 132 case SEC_ERROR_CERT_NOT_VALID: 133 // TODO(port): add an ERR_CERT_WRONG_USAGE error code. 134 case SEC_ERROR_CERT_USAGES_INVALID: 135 case SEC_ERROR_INADEQUATE_KEY_USAGE: // Key usage. 136 case SEC_ERROR_INADEQUATE_CERT_TYPE: // Extended key usage and whether 137 // the certificate is a CA. 138 case SEC_ERROR_POLICY_VALIDATION_FAILED: 139 case SEC_ERROR_CERT_NOT_IN_NAME_SPACE: 140 case SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID: 141 case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION: 142 case SEC_ERROR_EXTENSION_VALUE_INVALID: 143 return ERR_CERT_INVALID; 144 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED: 145 return ERR_CERT_WEAK_SIGNATURE_ALGORITHM; 146 default: 147 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; 148 return ERR_FAILED; 149 } 150 } 151 152 // Map PORT_GetError() return values to our cert status flags. 153 CertStatus MapCertErrorToCertStatus(int err) { 154 int net_error = MapSecurityError(err); 155 return MapNetErrorToCertStatus(net_error); 156 } 157 158 // Saves some information about the certificate chain cert_list in 159 // *verify_result. The caller MUST initialize *verify_result before calling 160 // this function. 161 // Note that cert_list[0] is the end entity certificate. 162 void GetCertChainInfo(CERTCertList* cert_list, 163 CERTCertificate* root_cert, 164 CertVerifyResult* verify_result) { 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. 232 bool 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. 243 bool 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 256 enum CRLSetResult { 257 kCRLSetOk, 258 kCRLSetRevoked, 259 kCRLSetUnknown, 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 // kCRLSetUnknown: if there is no fresh information about some element in 266 // the chain. 267 // kCRLSetOk: if every element in the chain is covered by a fresh CRLSet and 268 // is unrevoked. 269 CRLSetResult CheckRevocationWithCRLSet(CERTCertList* cert_list, 270 CERTCertificate* root, 271 CRLSet* crl_set) { 272 std::vector<CERTCertificate*> certs; 273 274 if (cert_list) { 275 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); 276 !CERT_LIST_END(node, cert_list); 277 node = CERT_LIST_NEXT(node)) { 278 certs.push_back(node->cert); 279 } 280 } 281 if (root) 282 certs.push_back(root); 283 284 bool covered = true; 285 286 // We iterate from the root certificate down to the leaf, keeping track of 287 // the issuer's SPKI at each step. 288 std::string issuer_spki_hash; 289 for (std::vector<CERTCertificate*>::reverse_iterator i = certs.rbegin(); 290 i != certs.rend(); ++i) { 291 CERTCertificate* cert = *i; 292 293 base::StringPiece der(reinterpret_cast<char*>(cert->derCert.data), 294 cert->derCert.len); 295 296 base::StringPiece spki; 297 if (!asn1::ExtractSPKIFromDERCert(der, &spki)) { 298 NOTREACHED(); 299 covered = false; 300 continue; 301 } 302 const std::string spki_hash = crypto::SHA256HashString(spki); 303 304 base::StringPiece serial_number = base::StringPiece( 305 reinterpret_cast<char*>(cert->serialNumber.data), 306 cert->serialNumber.len); 307 308 CRLSet::Result result = crl_set->CheckSPKI(spki_hash); 309 310 if (result != CRLSet::REVOKED && !issuer_spki_hash.empty()) 311 result = crl_set->CheckSerial(serial_number, issuer_spki_hash); 312 313 issuer_spki_hash = spki_hash; 314 315 switch (result) { 316 case CRLSet::REVOKED: 317 return kCRLSetRevoked; 318 case CRLSet::UNKNOWN: 319 covered = false; 320 continue; 321 case CRLSet::GOOD: 322 continue; 323 default: 324 NOTREACHED(); 325 covered = false; 326 continue; 327 } 328 } 329 330 if (!covered || crl_set->IsExpired()) 331 return kCRLSetUnknown; 332 return kCRLSetOk; 333 } 334 335 // Forward declarations. 336 SECStatus RetryPKIXVerifyCertWithWorkarounds( 337 CERTCertificate* cert_handle, int num_policy_oids, 338 bool cert_io_enabled, std::vector<CERTValInParam>* cvin, 339 CERTValOutParam* cvout); 340 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle); 341 342 // Call CERT_PKIXVerifyCert for the cert_handle. 343 // Verification results are stored in an array of CERTValOutParam. 344 // If |hard_fail| is true, and no policy_oids are supplied (eg: EV is NOT being 345 // checked), then the failure to obtain valid CRL/OCSP information for all 346 // certificates that contain CRL/OCSP URLs will cause the certificate to be 347 // treated as if it was revoked. Since failures may be caused by transient 348 // network failures or by malicious attackers, in general, hard_fail should be 349 // false. 350 // If policy_oids is not NULL and num_policy_oids is positive, policies 351 // are also checked. 352 // additional_trust_anchors is an optional list of certificates that can be 353 // trusted as anchors when building a certificate chain. 354 // Caller must initialize cvout before calling this function. 355 SECStatus PKIXVerifyCert(CERTCertificate* cert_handle, 356 bool check_revocation, 357 bool hard_fail, 358 bool cert_io_enabled, 359 const SECOidTag* policy_oids, 360 int num_policy_oids, 361 CERTCertList* additional_trust_anchors, 362 CERTValOutParam* cvout) { 363 bool use_crl = check_revocation; 364 bool use_ocsp = check_revocation; 365 366 PRUint64 revocation_method_flags = 367 CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD | 368 CERT_REV_M_ALLOW_NETWORK_FETCHING | 369 CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE | 370 CERT_REV_M_IGNORE_MISSING_FRESH_INFO | 371 CERT_REV_M_STOP_TESTING_ON_FRESH_INFO; 372 PRUint64 revocation_method_independent_flags = 373 CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST; 374 if (check_revocation && policy_oids && num_policy_oids > 0) { 375 // EV verification requires revocation checking. Consider the certificate 376 // revoked if we don't have revocation info. 377 // TODO(wtc): Add a bool parameter to expressly specify we're doing EV 378 // verification or we want strict revocation flags. 379 revocation_method_flags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE; 380 revocation_method_independent_flags |= 381 CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE; 382 } else if (check_revocation && hard_fail) { 383 revocation_method_flags |= CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO; 384 revocation_method_independent_flags |= 385 CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE; 386 } else { 387 revocation_method_flags |= CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE; 388 revocation_method_independent_flags |= 389 CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT; 390 } 391 PRUint64 method_flags[2]; 392 method_flags[cert_revocation_method_crl] = revocation_method_flags; 393 method_flags[cert_revocation_method_ocsp] = revocation_method_flags; 394 395 if (use_crl) { 396 method_flags[cert_revocation_method_crl] |= 397 CERT_REV_M_TEST_USING_THIS_METHOD; 398 } 399 if (use_ocsp) { 400 method_flags[cert_revocation_method_ocsp] |= 401 CERT_REV_M_TEST_USING_THIS_METHOD; 402 } 403 404 CERTRevocationMethodIndex preferred_revocation_methods[1]; 405 if (use_ocsp) { 406 preferred_revocation_methods[0] = cert_revocation_method_ocsp; 407 } else { 408 preferred_revocation_methods[0] = cert_revocation_method_crl; 409 } 410 411 CERTRevocationFlags revocation_flags; 412 revocation_flags.leafTests.number_of_defined_methods = 413 arraysize(method_flags); 414 revocation_flags.leafTests.cert_rev_flags_per_method = method_flags; 415 revocation_flags.leafTests.number_of_preferred_methods = 416 arraysize(preferred_revocation_methods); 417 revocation_flags.leafTests.preferred_methods = preferred_revocation_methods; 418 revocation_flags.leafTests.cert_rev_method_independent_flags = 419 revocation_method_independent_flags; 420 421 revocation_flags.chainTests.number_of_defined_methods = 422 arraysize(method_flags); 423 revocation_flags.chainTests.cert_rev_flags_per_method = method_flags; 424 revocation_flags.chainTests.number_of_preferred_methods = 425 arraysize(preferred_revocation_methods); 426 revocation_flags.chainTests.preferred_methods = preferred_revocation_methods; 427 revocation_flags.chainTests.cert_rev_method_independent_flags = 428 revocation_method_independent_flags; 429 430 431 std::vector<CERTValInParam> cvin; 432 cvin.reserve(7); 433 CERTValInParam in_param; 434 in_param.type = cert_pi_revocationFlags; 435 in_param.value.pointer.revocation = &revocation_flags; 436 cvin.push_back(in_param); 437 if (policy_oids && num_policy_oids > 0) { 438 in_param.type = cert_pi_policyOID; 439 in_param.value.arraySize = num_policy_oids; 440 in_param.value.array.oids = policy_oids; 441 cvin.push_back(in_param); 442 } 443 if (additional_trust_anchors) { 444 in_param.type = cert_pi_trustAnchors; 445 in_param.value.pointer.chain = additional_trust_anchors; 446 cvin.push_back(in_param); 447 in_param.type = cert_pi_useOnlyTrustAnchors; 448 in_param.value.scalar.b = PR_FALSE; 449 cvin.push_back(in_param); 450 } 451 in_param.type = cert_pi_end; 452 cvin.push_back(in_param); 453 454 SECStatus rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer, 455 &cvin[0], cvout, NULL); 456 if (rv != SECSuccess) { 457 rv = RetryPKIXVerifyCertWithWorkarounds(cert_handle, num_policy_oids, 458 cert_io_enabled, &cvin, cvout); 459 } 460 return rv; 461 } 462 463 // PKIXVerifyCert calls this function to work around some bugs in 464 // CERT_PKIXVerifyCert. All the arguments of this function are either the 465 // arguments or local variables of PKIXVerifyCert. 466 SECStatus RetryPKIXVerifyCertWithWorkarounds( 467 CERTCertificate* cert_handle, int num_policy_oids, 468 bool cert_io_enabled, std::vector<CERTValInParam>* cvin, 469 CERTValOutParam* cvout) { 470 // We call this function when the first CERT_PKIXVerifyCert call in 471 // PKIXVerifyCert failed, so we initialize |rv| to SECFailure. 472 SECStatus rv = SECFailure; 473 int nss_error = PORT_GetError(); 474 CERTValInParam in_param; 475 476 // If we get SEC_ERROR_UNKNOWN_ISSUER, we may be missing an intermediate 477 // CA certificate, so we retry with cert_pi_useAIACertFetch. 478 // cert_pi_useAIACertFetch has several bugs in its error handling and 479 // error reporting (NSS bug 528743), so we don't use it by default. 480 // Note: When building a certificate chain, CERT_PKIXVerifyCert may 481 // incorrectly pick a CA certificate with the same subject name as the 482 // missing intermediate CA certificate, and fail with the 483 // SEC_ERROR_BAD_SIGNATURE error (NSS bug 524013), so we also retry with 484 // cert_pi_useAIACertFetch on SEC_ERROR_BAD_SIGNATURE. 485 if (cert_io_enabled && 486 (nss_error == SEC_ERROR_UNKNOWN_ISSUER || 487 nss_error == SEC_ERROR_BAD_SIGNATURE)) { 488 DCHECK_EQ(cvin->back().type, cert_pi_end); 489 cvin->pop_back(); 490 in_param.type = cert_pi_useAIACertFetch; 491 in_param.value.scalar.b = PR_TRUE; 492 cvin->push_back(in_param); 493 in_param.type = cert_pi_end; 494 cvin->push_back(in_param); 495 rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer, 496 &(*cvin)[0], cvout, NULL); 497 if (rv == SECSuccess) 498 return rv; 499 int new_nss_error = PORT_GetError(); 500 if (new_nss_error == SEC_ERROR_INVALID_ARGS || 501 new_nss_error == SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE || 502 new_nss_error == SEC_ERROR_BAD_INFO_ACCESS_LOCATION || 503 new_nss_error == SEC_ERROR_BAD_HTTP_RESPONSE || 504 new_nss_error == SEC_ERROR_BAD_LDAP_RESPONSE || 505 !IS_SEC_ERROR(new_nss_error)) { 506 // Use the original error code because of cert_pi_useAIACertFetch's 507 // bad error reporting. 508 PORT_SetError(nss_error); 509 return rv; 510 } 511 nss_error = new_nss_error; 512 } 513 514 // If an intermediate CA certificate has requireExplicitPolicy in its 515 // policyConstraints extension, CERT_PKIXVerifyCert fails with 516 // SEC_ERROR_POLICY_VALIDATION_FAILED because we didn't specify any 517 // certificate policy (NSS bug 552775). So we retry with the certificate 518 // policy found in the server certificate. 519 if (nss_error == SEC_ERROR_POLICY_VALIDATION_FAILED && 520 num_policy_oids == 0) { 521 SECOidTag policy = GetFirstCertPolicy(cert_handle); 522 if (policy != SEC_OID_UNKNOWN) { 523 DCHECK_EQ(cvin->back().type, cert_pi_end); 524 cvin->pop_back(); 525 in_param.type = cert_pi_policyOID; 526 in_param.value.arraySize = 1; 527 in_param.value.array.oids = &policy; 528 cvin->push_back(in_param); 529 in_param.type = cert_pi_end; 530 cvin->push_back(in_param); 531 rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer, 532 &(*cvin)[0], cvout, NULL); 533 if (rv != SECSuccess) { 534 // Use the original error code. 535 PORT_SetError(nss_error); 536 } 537 } 538 } 539 540 return rv; 541 } 542 543 // Decodes the certificatePolicies extension of the certificate. Returns 544 // NULL if the certificate doesn't have the extension or the extension can't 545 // be decoded. The returned value must be freed with a 546 // CERT_DestroyCertificatePoliciesExtension call. 547 CERTCertificatePolicies* DecodeCertPolicies( 548 CERTCertificate* cert_handle) { 549 SECItem policy_ext; 550 SECStatus rv = CERT_FindCertExtension(cert_handle, 551 SEC_OID_X509_CERTIFICATE_POLICIES, 552 &policy_ext); 553 if (rv != SECSuccess) 554 return NULL; 555 CERTCertificatePolicies* policies = 556 CERT_DecodeCertificatePoliciesExtension(&policy_ext); 557 SECITEM_FreeItem(&policy_ext, PR_FALSE); 558 return policies; 559 } 560 561 // Returns the OID tag for the first certificate policy in the certificate's 562 // certificatePolicies extension. Returns SEC_OID_UNKNOWN if the certificate 563 // has no certificate policy. 564 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle) { 565 ScopedCERTCertificatePolicies policies(DecodeCertPolicies(cert_handle)); 566 if (!policies.get()) 567 return SEC_OID_UNKNOWN; 568 569 CERTPolicyInfo* policy_info = policies->policyInfos[0]; 570 if (!policy_info) 571 return SEC_OID_UNKNOWN; 572 if (policy_info->oid != SEC_OID_UNKNOWN) 573 return policy_info->oid; 574 575 // The certificate policy is unknown to NSS. We need to create a dynamic 576 // OID tag for the policy. 577 SECOidData od; 578 od.oid.len = policy_info->policyID.len; 579 od.oid.data = policy_info->policyID.data; 580 od.offset = SEC_OID_UNKNOWN; 581 // NSS doesn't allow us to pass an empty description, so I use a hardcoded, 582 // default description here. The description doesn't need to be unique for 583 // each OID. 584 od.desc = "a certificate policy"; 585 od.mechanism = CKM_INVALID_MECHANISM; 586 od.supportedExtension = INVALID_CERT_EXTENSION; 587 return SECOID_AddEntry(&od); 588 } 589 590 HashValue CertPublicKeyHashSHA1(CERTCertificate* cert) { 591 HashValue hash(HASH_VALUE_SHA1); 592 #if defined(OS_IOS) 593 CC_SHA1(cert->derPublicKey.data, cert->derPublicKey.len, hash.data()); 594 #else 595 SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, hash.data(), 596 cert->derPublicKey.data, cert->derPublicKey.len); 597 DCHECK_EQ(SECSuccess, rv); 598 #endif 599 return hash; 600 } 601 602 HashValue CertPublicKeyHashSHA256(CERTCertificate* cert) { 603 HashValue hash(HASH_VALUE_SHA256); 604 #if defined(OS_IOS) 605 CC_SHA256(cert->derPublicKey.data, cert->derPublicKey.len, hash.data()); 606 #else 607 SECStatus rv = HASH_HashBuf(HASH_AlgSHA256, hash.data(), 608 cert->derPublicKey.data, cert->derPublicKey.len); 609 DCHECK_EQ(rv, SECSuccess); 610 #endif 611 return hash; 612 } 613 614 void AppendPublicKeyHashes(CERTCertList* cert_list, 615 CERTCertificate* root_cert, 616 HashValueVector* hashes) { 617 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); 618 !CERT_LIST_END(node, cert_list); 619 node = CERT_LIST_NEXT(node)) { 620 hashes->push_back(CertPublicKeyHashSHA1(node->cert)); 621 hashes->push_back(CertPublicKeyHashSHA256(node->cert)); 622 } 623 if (root_cert) { 624 hashes->push_back(CertPublicKeyHashSHA1(root_cert)); 625 hashes->push_back(CertPublicKeyHashSHA256(root_cert)); 626 } 627 } 628 629 // Returns true if |cert_handle| contains a policy OID that is an EV policy 630 // OID according to |metadata|, storing the resulting policy OID in 631 // |*ev_policy_oid|. A true return is not sufficient to establish that a 632 // certificate is EV, but a false return is sufficient to establish the 633 // certificate cannot be EV. 634 bool IsEVCandidate(EVRootCAMetadata* metadata, 635 CERTCertificate* cert_handle, 636 SECOidTag* ev_policy_oid) { 637 DCHECK(cert_handle); 638 ScopedCERTCertificatePolicies policies(DecodeCertPolicies(cert_handle)); 639 if (!policies.get()) 640 return false; 641 642 CERTPolicyInfo** policy_infos = policies->policyInfos; 643 while (*policy_infos != NULL) { 644 CERTPolicyInfo* policy_info = *policy_infos++; 645 // If the Policy OID is unknown, that implicitly means it has not been 646 // registered as an EV policy. 647 if (policy_info->oid == SEC_OID_UNKNOWN) 648 continue; 649 if (metadata->IsEVPolicyOID(policy_info->oid)) { 650 *ev_policy_oid = policy_info->oid; 651 return true; 652 } 653 } 654 655 return false; 656 } 657 658 // Studied Mozilla's code (esp. security/manager/ssl/src/nsIdentityChecking.cpp 659 // and nsNSSCertHelper.cpp) to learn how to verify EV certificate. 660 // TODO(wtc): A possible optimization is that we get the trust anchor from 661 // the first PKIXVerifyCert call. We look up the EV policy for the trust 662 // anchor. If the trust anchor has no EV policy, we know the cert isn't EV. 663 // Otherwise, we pass just that EV policy (as opposed to all the EV policies) 664 // to the second PKIXVerifyCert call. 665 bool VerifyEV(CERTCertificate* cert_handle, 666 int flags, 667 CRLSet* crl_set, 668 bool rev_checking_enabled, 669 EVRootCAMetadata* metadata, 670 SECOidTag ev_policy_oid, 671 CERTCertList* additional_trust_anchors) { 672 CERTValOutParam cvout[3]; 673 int cvout_index = 0; 674 cvout[cvout_index].type = cert_po_certList; 675 cvout[cvout_index].value.pointer.chain = NULL; 676 int cvout_cert_list_index = cvout_index; 677 cvout_index++; 678 cvout[cvout_index].type = cert_po_trustAnchor; 679 cvout[cvout_index].value.pointer.cert = NULL; 680 int cvout_trust_anchor_index = cvout_index; 681 cvout_index++; 682 cvout[cvout_index].type = cert_po_end; 683 ScopedCERTValOutParam scoped_cvout(cvout); 684 685 SECStatus status = PKIXVerifyCert( 686 cert_handle, 687 rev_checking_enabled, 688 true, /* hard fail is implied in EV. */ 689 flags & CertVerifier::VERIFY_CERT_IO_ENABLED, 690 &ev_policy_oid, 691 1, 692 additional_trust_anchors, 693 cvout); 694 if (status != SECSuccess) 695 return false; 696 697 CERTCertificate* root_ca = 698 cvout[cvout_trust_anchor_index].value.pointer.cert; 699 if (root_ca == NULL) 700 return false; 701 702 // This second PKIXVerifyCert call could have found a different certification 703 // path and one or more of the certificates on this new path, that weren't on 704 // the old path, might have been revoked. 705 if (crl_set) { 706 CRLSetResult crl_set_result = CheckRevocationWithCRLSet( 707 cvout[cvout_cert_list_index].value.pointer.chain, 708 cvout[cvout_trust_anchor_index].value.pointer.cert, 709 crl_set); 710 if (crl_set_result == kCRLSetRevoked) 711 return false; 712 } 713 714 #if defined(OS_IOS) 715 SHA1HashValue fingerprint = x509_util_ios::CalculateFingerprintNSS(root_ca); 716 #else 717 SHA1HashValue fingerprint = 718 X509Certificate::CalculateFingerprint(root_ca); 719 #endif 720 return metadata->HasEVPolicyOID(fingerprint, ev_policy_oid); 721 } 722 723 CERTCertList* CertificateListToCERTCertList(const CertificateList& list) { 724 CERTCertList* result = CERT_NewCertList(); 725 for (size_t i = 0; i < list.size(); ++i) { 726 #if defined(OS_IOS) 727 // X509Certificate::os_cert_handle() on iOS is a SecCertificateRef; convert 728 // it to an NSS CERTCertificate. 729 CERTCertificate* cert = x509_util_ios::CreateNSSCertHandleFromOSHandle( 730 list[i]->os_cert_handle()); 731 #else 732 CERTCertificate* cert = list[i]->os_cert_handle(); 733 #endif 734 CERT_AddCertToListTail(result, CERT_DupCertificate(cert)); 735 } 736 return result; 737 } 738 739 } // namespace 740 741 CertVerifyProcNSS::CertVerifyProcNSS() {} 742 743 CertVerifyProcNSS::~CertVerifyProcNSS() {} 744 745 bool CertVerifyProcNSS::SupportsAdditionalTrustAnchors() const { 746 // This requires APIs introduced in 3.14.2. 747 return NSS_VersionCheck("3.14.2"); 748 } 749 750 int CertVerifyProcNSS::VerifyInternal( 751 X509Certificate* cert, 752 const std::string& hostname, 753 int flags, 754 CRLSet* crl_set, 755 const CertificateList& additional_trust_anchors, 756 CertVerifyResult* verify_result) { 757 #if defined(OS_IOS) 758 // For iOS, the entire chain must be loaded into NSS's in-memory certificate 759 // store. 760 x509_util_ios::NSSCertChain scoped_chain(cert); 761 CERTCertificate* cert_handle = scoped_chain.cert_handle(); 762 #else 763 CERTCertificate* cert_handle = cert->os_cert_handle(); 764 #endif // defined(OS_IOS) 765 766 // Make sure that the hostname matches with the common name of the cert. 767 SECStatus status = CERT_VerifyCertName(cert_handle, hostname.c_str()); 768 if (status != SECSuccess) 769 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; 770 771 // Make sure that the cert is valid now. 772 SECCertTimeValidity validity = CERT_CheckCertValidTimes( 773 cert_handle, PR_Now(), PR_TRUE); 774 if (validity != secCertTimeValid) 775 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; 776 777 CERTValOutParam cvout[3]; 778 int cvout_index = 0; 779 cvout[cvout_index].type = cert_po_certList; 780 cvout[cvout_index].value.pointer.chain = NULL; 781 int cvout_cert_list_index = cvout_index; 782 cvout_index++; 783 cvout[cvout_index].type = cert_po_trustAnchor; 784 cvout[cvout_index].value.pointer.cert = NULL; 785 int cvout_trust_anchor_index = cvout_index; 786 cvout_index++; 787 cvout[cvout_index].type = cert_po_end; 788 ScopedCERTValOutParam scoped_cvout(cvout); 789 790 EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance(); 791 SECOidTag ev_policy_oid = SEC_OID_UNKNOWN; 792 bool is_ev_candidate = 793 (flags & CertVerifier::VERIFY_EV_CERT) && 794 IsEVCandidate(metadata, cert_handle, &ev_policy_oid); 795 bool cert_io_enabled = flags & CertVerifier::VERIFY_CERT_IO_ENABLED; 796 bool check_revocation = 797 cert_io_enabled && 798 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED); 799 if (check_revocation) 800 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; 801 802 ScopedCERTCertList trust_anchors; 803 if (SupportsAdditionalTrustAnchors() && !additional_trust_anchors.empty()) { 804 trust_anchors.reset( 805 CertificateListToCERTCertList(additional_trust_anchors)); 806 } 807 808 status = PKIXVerifyCert(cert_handle, check_revocation, false, 809 cert_io_enabled, NULL, 0, trust_anchors.get(), 810 cvout); 811 812 if (status == SECSuccess && 813 (flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) && 814 !IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert)) { 815 // TODO(rsleevi): Optimize this by supplying the constructed chain to 816 // libpkix via cvin. Omitting for now, due to lack of coverage in upstream 817 // NSS tests for that feature. 818 scoped_cvout.Clear(); 819 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; 820 status = PKIXVerifyCert(cert_handle, true, true, 821 cert_io_enabled, NULL, 0, trust_anchors.get(), 822 cvout); 823 } 824 825 if (status == SECSuccess) { 826 AppendPublicKeyHashes(cvout[cvout_cert_list_index].value.pointer.chain, 827 cvout[cvout_trust_anchor_index].value.pointer.cert, 828 &verify_result->public_key_hashes); 829 830 verify_result->is_issued_by_known_root = 831 IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert); 832 verify_result->is_issued_by_additional_trust_anchor = 833 IsAdditionalTrustAnchor( 834 trust_anchors.get(), 835 cvout[cvout_trust_anchor_index].value.pointer.cert); 836 837 GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain, 838 cvout[cvout_trust_anchor_index].value.pointer.cert, 839 verify_result); 840 } 841 842 CRLSetResult crl_set_result = kCRLSetUnknown; 843 if (crl_set) { 844 crl_set_result = CheckRevocationWithCRLSet( 845 cvout[cvout_cert_list_index].value.pointer.chain, 846 cvout[cvout_trust_anchor_index].value.pointer.cert, 847 crl_set); 848 if (crl_set_result == kCRLSetRevoked) { 849 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); 850 status = SECFailure; 851 } 852 } 853 854 if (status != SECSuccess) { 855 int err = PORT_GetError(); 856 LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname 857 << " failed err=" << err; 858 // CERT_PKIXVerifyCert rerports the wrong error code for 859 // expired certificates (NSS bug 491174) 860 if (err == SEC_ERROR_CERT_NOT_VALID && 861 (verify_result->cert_status & CERT_STATUS_DATE_INVALID)) 862 err = SEC_ERROR_EXPIRED_CERTIFICATE; 863 CertStatus cert_status = MapCertErrorToCertStatus(err); 864 if (cert_status) { 865 verify_result->cert_status |= cert_status; 866 return MapCertStatusToNetError(verify_result->cert_status); 867 } 868 // |err| is not a certificate error. 869 return MapSecurityError(err); 870 } 871 872 if (IsCertStatusError(verify_result->cert_status)) 873 return MapCertStatusToNetError(verify_result->cert_status); 874 875 if ((flags & CertVerifier::VERIFY_EV_CERT) && is_ev_candidate) { 876 check_revocation |= 877 crl_set_result != kCRLSetOk && 878 cert_io_enabled && 879 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY); 880 if (check_revocation) 881 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; 882 883 if (VerifyEV(cert_handle, flags, crl_set, check_revocation, metadata, 884 ev_policy_oid, trust_anchors.get())) { 885 verify_result->cert_status |= CERT_STATUS_IS_EV; 886 } 887 } 888 889 return OK; 890 } 891 892 } // namespace net 893