Evict resources from resource pool after timeout
[chromium-blink-merge.git] / net / cert / cert_verify_proc_nss.cc
blob9ee65ee4b3404531a07b0fdd35700575d6f2cba9
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.
5 #include "net/cert/cert_verify_proc_nss.h"
7 #include <string>
8 #include <vector>
10 #include <cert.h>
11 #include <nss.h>
12 #include <prerror.h>
13 #include <secerr.h>
14 #include <sechash.h>
15 #include <sslerr.h>
17 #include "base/logging.h"
18 #include "build/build_config.h"
19 #include "crypto/nss_util.h"
20 #include "crypto/scoped_nss_types.h"
21 #include "crypto/sha2.h"
22 #include "net/base/net_errors.h"
23 #include "net/cert/asn1_util.h"
24 #include "net/cert/cert_status_flags.h"
25 #include "net/cert/cert_verifier.h"
26 #include "net/cert/cert_verify_result.h"
27 #include "net/cert/crl_set.h"
28 #include "net/cert/ev_root_ca_metadata.h"
29 #include "net/cert/x509_certificate.h"
30 #include "net/cert/x509_util_nss.h"
32 #if defined(OS_IOS)
33 #include <CommonCrypto/CommonDigest.h>
34 #include "net/cert/x509_util_ios.h"
35 #endif // defined(OS_IOS)
37 #if defined(USE_NSS_CERTS)
38 #include <dlfcn.h>
39 #else
40 #include <ocsp.h>
41 #endif
43 namespace net {
45 namespace {
47 typedef scoped_ptr<
48 CERTCertificatePolicies,
49 crypto::NSSDestroyer<CERTCertificatePolicies,
50 CERT_DestroyCertificatePoliciesExtension> >
51 ScopedCERTCertificatePolicies;
53 typedef scoped_ptr<
54 CERTCertList,
55 crypto::NSSDestroyer<CERTCertList, CERT_DestroyCertList> >
56 ScopedCERTCertList;
58 // ScopedCERTValOutParam manages destruction of values in the CERTValOutParam
59 // array that cvout points to. cvout must be initialized as passed to
60 // CERT_PKIXVerifyCert, so that the array must be terminated with
61 // cert_po_end type.
62 // When it goes out of scope, it destroys values of cert_po_trustAnchor
63 // and cert_po_certList types, but doesn't release the array itself.
64 class ScopedCERTValOutParam {
65 public:
66 explicit ScopedCERTValOutParam(CERTValOutParam* cvout) : cvout_(cvout) {}
68 ~ScopedCERTValOutParam() {
69 Clear();
72 // Free the internal resources, but do not release the array itself.
73 void Clear() {
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;
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;
89 break;
90 default:
91 break;
96 private:
97 CERTValOutParam* cvout_;
99 DISALLOW_COPY_AND_ASSIGN(ScopedCERTValOutParam);
102 // Map PORT_GetError() return values to our network error codes.
103 int 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 case SEC_ERROR_APPLICATION_CALLBACK_ERROR: // Rejected by
119 // chain_verify_callback.
120 return ERR_CERT_AUTHORITY_INVALID;
121 // TODO(port): map ERR_CERT_NO_REVOCATION_MECHANISM.
122 case SEC_ERROR_OCSP_BAD_HTTP_RESPONSE:
123 case SEC_ERROR_OCSP_SERVER_ERROR:
124 return ERR_CERT_UNABLE_TO_CHECK_REVOCATION;
125 case SEC_ERROR_REVOKED_CERTIFICATE:
126 case SEC_ERROR_UNTRUSTED_CERT: // Treat as revoked.
127 return ERR_CERT_REVOKED;
128 case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:
129 return ERR_CERT_NAME_CONSTRAINT_VIOLATION;
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_PATH_LEN_CONSTRAINT_INVALID:
140 case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
141 case SEC_ERROR_EXTENSION_VALUE_INVALID:
142 return ERR_CERT_INVALID;
143 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
144 return ERR_CERT_WEAK_SIGNATURE_ALGORITHM;
145 default:
146 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
147 return ERR_FAILED;
151 // Map PORT_GetError() return values to our cert status flags.
152 CertStatus MapCertErrorToCertStatus(int err) {
153 int net_error = MapSecurityError(err);
154 return MapNetErrorToCertStatus(net_error);
157 // Saves some information about the certificate chain cert_list in
158 // *verify_result. The caller MUST initialize *verify_result before calling
159 // this function.
160 // Note that cert_list[0] is the end entity certificate.
161 void GetCertChainInfo(CERTCertList* cert_list,
162 CERTCertificate* root_cert,
163 CertVerifyResult* verify_result) {
164 DCHECK(cert_list);
166 CERTCertificate* verified_cert = NULL;
167 std::vector<CERTCertificate*> verified_chain;
168 int i = 0;
169 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
170 !CERT_LIST_END(node, cert_list);
171 node = CERT_LIST_NEXT(node), ++i) {
172 if (i == 0) {
173 verified_cert = node->cert;
174 } else {
175 // Because of an NSS bug, CERT_PKIXVerifyCert may chain a self-signed
176 // certificate of a root CA to another certificate of the same root CA
177 // key. Detect that error and ignore the root CA certificate.
178 // See https://bugzilla.mozilla.org/show_bug.cgi?id=721288.
179 if (node->cert->isRoot) {
180 // NOTE: isRoot doesn't mean the certificate is a trust anchor. It
181 // means the certificate is self-signed. Here we assume isRoot only
182 // implies the certificate is self-issued.
183 CERTCertListNode* next_node = CERT_LIST_NEXT(node);
184 CERTCertificate* next_cert;
185 if (!CERT_LIST_END(next_node, cert_list)) {
186 next_cert = next_node->cert;
187 } else {
188 next_cert = root_cert;
190 // Test that |node->cert| is actually a self-signed certificate
191 // whose key is equal to |next_cert|, and not a self-issued
192 // certificate signed by another key of the same CA.
193 if (next_cert && SECITEM_ItemsAreEqual(&node->cert->derPublicKey,
194 &next_cert->derPublicKey)) {
195 continue;
198 verified_chain.push_back(node->cert);
201 SECAlgorithmID& signature = node->cert->signature;
202 SECOidTag oid_tag = SECOID_FindOIDTag(&signature.algorithm);
203 switch (oid_tag) {
204 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
205 verify_result->has_md5 = true;
206 break;
207 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
208 verify_result->has_md2 = true;
209 break;
210 case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
211 verify_result->has_md4 = true;
212 break;
213 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
214 case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE:
215 case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
216 case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
217 verify_result->has_sha1 = true;
218 break;
219 default:
220 break;
224 if (root_cert)
225 verified_chain.push_back(root_cert);
226 #if defined(OS_IOS)
227 verify_result->verified_cert =
228 x509_util_ios::CreateCertFromNSSHandles(verified_cert, verified_chain);
229 #else
230 verify_result->verified_cert =
231 X509Certificate::CreateFromHandle(verified_cert, verified_chain);
232 #endif // defined(OS_IOS)
235 // IsKnownRoot returns true if the given certificate is one that we believe
236 // is a standard (as opposed to user-installed) root.
237 bool IsKnownRoot(CERTCertificate* root) {
238 if (!root || !root->slot)
239 return false;
241 // This magic name is taken from
242 // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw/builtins/constants.c&rev=1.13&mark=86,89#79
243 return 0 == strcmp(PK11_GetSlotName(root->slot),
244 "NSS Builtin Objects");
247 // Returns true if the given certificate is one of the additional trust anchors.
248 bool IsAdditionalTrustAnchor(CERTCertList* additional_trust_anchors,
249 CERTCertificate* root) {
250 if (!additional_trust_anchors || !root)
251 return false;
252 for (CERTCertListNode* node = CERT_LIST_HEAD(additional_trust_anchors);
253 !CERT_LIST_END(node, additional_trust_anchors);
254 node = CERT_LIST_NEXT(node)) {
255 if (CERT_CompareCerts(node->cert, root))
256 return true;
258 return false;
261 enum CRLSetResult {
262 kCRLSetOk,
263 kCRLSetRevoked,
264 kCRLSetUnknown,
267 // CheckRevocationWithCRLSet attempts to check each element of |cert_list|
268 // against |crl_set|. It returns:
269 // kCRLSetRevoked: if any element of the chain is known to have been revoked.
270 // kCRLSetUnknown: if there is no fresh information about the leaf
271 // certificate in the chain or if the CRLSet has expired.
273 // Only the leaf certificate is considered for coverage because some
274 // intermediates have CRLs with no revocations (after filtering) and
275 // those CRLs are pruned from the CRLSet at generation time. This means
276 // that some EV sites would otherwise take the hit of an OCSP lookup for
277 // no reason.
278 // kCRLSetOk: otherwise.
279 CRLSetResult CheckRevocationWithCRLSet(CERTCertList* cert_list,
280 CERTCertificate* root,
281 CRLSet* crl_set) {
282 std::vector<CERTCertificate*> certs;
284 if (cert_list) {
285 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
286 !CERT_LIST_END(node, cert_list);
287 node = CERT_LIST_NEXT(node)) {
288 certs.push_back(node->cert);
291 if (root)
292 certs.push_back(root);
294 // error is set to true if any errors are found. It causes such chains to be
295 // considered as not covered.
296 bool error = false;
297 // last_covered is set to the coverage state of the previous certificate. The
298 // certificates are iterated over backwards thus, after the iteration,
299 // |last_covered| contains the coverage state of the leaf certificate.
300 bool last_covered = false;
302 // We iterate from the root certificate down to the leaf, keeping track of
303 // the issuer's SPKI at each step.
304 std::string issuer_spki_hash;
305 for (std::vector<CERTCertificate*>::reverse_iterator i = certs.rbegin();
306 i != certs.rend(); ++i) {
307 CERTCertificate* cert = *i;
309 base::StringPiece der(reinterpret_cast<char*>(cert->derCert.data),
310 cert->derCert.len);
312 base::StringPiece spki;
313 if (!asn1::ExtractSPKIFromDERCert(der, &spki)) {
314 NOTREACHED();
315 error = true;
316 continue;
318 const std::string spki_hash = crypto::SHA256HashString(spki);
320 base::StringPiece serial_number = base::StringPiece(
321 reinterpret_cast<char*>(cert->serialNumber.data),
322 cert->serialNumber.len);
324 CRLSet::Result result = crl_set->CheckSPKI(spki_hash);
326 if (result != CRLSet::REVOKED && !issuer_spki_hash.empty())
327 result = crl_set->CheckSerial(serial_number, issuer_spki_hash);
329 issuer_spki_hash = spki_hash;
331 switch (result) {
332 case CRLSet::REVOKED:
333 return kCRLSetRevoked;
334 case CRLSet::UNKNOWN:
335 last_covered = false;
336 continue;
337 case CRLSet::GOOD:
338 last_covered = true;
339 continue;
340 default:
341 NOTREACHED();
342 error = true;
343 continue;
347 if (error || !last_covered || crl_set->IsExpired())
348 return kCRLSetUnknown;
349 return kCRLSetOk;
352 // Forward declarations.
353 SECStatus RetryPKIXVerifyCertWithWorkarounds(
354 CERTCertificate* cert_handle, int num_policy_oids,
355 bool cert_io_enabled, std::vector<CERTValInParam>* cvin,
356 CERTValOutParam* cvout);
357 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle);
359 // Call CERT_PKIXVerifyCert for the cert_handle.
360 // Verification results are stored in an array of CERTValOutParam.
361 // If |hard_fail| is true, and no policy_oids are supplied (eg: EV is NOT being
362 // checked), then the failure to obtain valid CRL/OCSP information for all
363 // certificates that contain CRL/OCSP URLs will cause the certificate to be
364 // treated as if it was revoked. Since failures may be caused by transient
365 // network failures or by malicious attackers, in general, hard_fail should be
366 // false.
367 // If policy_oids is not NULL and num_policy_oids is positive, policies
368 // are also checked.
369 // additional_trust_anchors is an optional list of certificates that can be
370 // trusted as anchors when building a certificate chain.
371 // Caller must initialize cvout before calling this function.
372 SECStatus PKIXVerifyCert(CERTCertificate* cert_handle,
373 bool check_revocation,
374 bool hard_fail,
375 bool cert_io_enabled,
376 const SECOidTag* policy_oids,
377 int num_policy_oids,
378 CERTCertList* additional_trust_anchors,
379 CERTChainVerifyCallback* chain_verify_callback,
380 CERTValOutParam* cvout) {
381 bool use_crl = check_revocation;
382 bool use_ocsp = check_revocation;
384 PRUint64 revocation_method_flags =
385 CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD |
386 CERT_REV_M_ALLOW_NETWORK_FETCHING |
387 CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE |
388 CERT_REV_M_IGNORE_MISSING_FRESH_INFO |
389 CERT_REV_M_STOP_TESTING_ON_FRESH_INFO;
390 PRUint64 revocation_method_independent_flags =
391 CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST;
392 if (check_revocation && policy_oids && num_policy_oids > 0) {
393 // EV verification requires revocation checking. Consider the certificate
394 // revoked if we don't have revocation info.
395 // TODO(wtc): Add a bool parameter to expressly specify we're doing EV
396 // verification or we want strict revocation flags.
397 revocation_method_flags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE;
398 revocation_method_independent_flags |=
399 CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;
400 } else if (check_revocation && hard_fail) {
401 revocation_method_flags |= CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO;
402 revocation_method_independent_flags |=
403 CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;
404 } else {
405 revocation_method_flags |= CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE;
406 revocation_method_independent_flags |=
407 CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT;
409 PRUint64 method_flags[2];
410 method_flags[cert_revocation_method_crl] = revocation_method_flags;
411 method_flags[cert_revocation_method_ocsp] = revocation_method_flags;
413 if (use_crl) {
414 method_flags[cert_revocation_method_crl] |=
415 CERT_REV_M_TEST_USING_THIS_METHOD;
417 if (use_ocsp) {
418 method_flags[cert_revocation_method_ocsp] |=
419 CERT_REV_M_TEST_USING_THIS_METHOD;
422 CERTRevocationMethodIndex preferred_revocation_methods[1];
423 if (use_ocsp) {
424 preferred_revocation_methods[0] = cert_revocation_method_ocsp;
425 } else {
426 preferred_revocation_methods[0] = cert_revocation_method_crl;
429 CERTRevocationFlags revocation_flags;
430 revocation_flags.leafTests.number_of_defined_methods =
431 arraysize(method_flags);
432 revocation_flags.leafTests.cert_rev_flags_per_method = method_flags;
433 revocation_flags.leafTests.number_of_preferred_methods =
434 arraysize(preferred_revocation_methods);
435 revocation_flags.leafTests.preferred_methods = preferred_revocation_methods;
436 revocation_flags.leafTests.cert_rev_method_independent_flags =
437 revocation_method_independent_flags;
439 revocation_flags.chainTests.number_of_defined_methods =
440 arraysize(method_flags);
441 revocation_flags.chainTests.cert_rev_flags_per_method = method_flags;
442 revocation_flags.chainTests.number_of_preferred_methods =
443 arraysize(preferred_revocation_methods);
444 revocation_flags.chainTests.preferred_methods = preferred_revocation_methods;
445 revocation_flags.chainTests.cert_rev_method_independent_flags =
446 revocation_method_independent_flags;
449 std::vector<CERTValInParam> cvin;
450 cvin.reserve(7);
451 CERTValInParam in_param;
452 in_param.type = cert_pi_revocationFlags;
453 in_param.value.pointer.revocation = &revocation_flags;
454 cvin.push_back(in_param);
455 if (policy_oids && num_policy_oids > 0) {
456 in_param.type = cert_pi_policyOID;
457 in_param.value.arraySize = num_policy_oids;
458 in_param.value.array.oids = policy_oids;
459 cvin.push_back(in_param);
461 if (additional_trust_anchors) {
462 in_param.type = cert_pi_trustAnchors;
463 in_param.value.pointer.chain = additional_trust_anchors;
464 cvin.push_back(in_param);
465 in_param.type = cert_pi_useOnlyTrustAnchors;
466 in_param.value.scalar.b = PR_FALSE;
467 cvin.push_back(in_param);
469 if (chain_verify_callback) {
470 in_param.type = cert_pi_chainVerifyCallback;
471 in_param.value.pointer.chainVerifyCallback = chain_verify_callback;
472 cvin.push_back(in_param);
474 in_param.type = cert_pi_end;
475 cvin.push_back(in_param);
477 SECStatus rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
478 &cvin[0], cvout, NULL);
479 if (rv != SECSuccess) {
480 rv = RetryPKIXVerifyCertWithWorkarounds(cert_handle, num_policy_oids,
481 cert_io_enabled, &cvin, cvout);
483 return rv;
486 // PKIXVerifyCert calls this function to work around some bugs in
487 // CERT_PKIXVerifyCert. All the arguments of this function are either the
488 // arguments or local variables of PKIXVerifyCert.
489 SECStatus RetryPKIXVerifyCertWithWorkarounds(
490 CERTCertificate* cert_handle, int num_policy_oids,
491 bool cert_io_enabled, std::vector<CERTValInParam>* cvin,
492 CERTValOutParam* cvout) {
493 // We call this function when the first CERT_PKIXVerifyCert call in
494 // PKIXVerifyCert failed, so we initialize |rv| to SECFailure.
495 SECStatus rv = SECFailure;
496 int nss_error = PORT_GetError();
497 CERTValInParam in_param;
499 // If we get SEC_ERROR_UNKNOWN_ISSUER, we may be missing an intermediate
500 // CA certificate, so we retry with cert_pi_useAIACertFetch.
501 // cert_pi_useAIACertFetch has several bugs in its error handling and
502 // error reporting (NSS bug 528743), so we don't use it by default.
503 // Note: When building a certificate chain, CERT_PKIXVerifyCert may
504 // incorrectly pick a CA certificate with the same subject name as the
505 // missing intermediate CA certificate, and fail with the
506 // SEC_ERROR_BAD_SIGNATURE error (NSS bug 524013), so we also retry with
507 // cert_pi_useAIACertFetch on SEC_ERROR_BAD_SIGNATURE.
508 if (cert_io_enabled &&
509 (nss_error == SEC_ERROR_UNKNOWN_ISSUER ||
510 nss_error == SEC_ERROR_BAD_SIGNATURE)) {
511 DCHECK_EQ(cvin->back().type, cert_pi_end);
512 cvin->pop_back();
513 in_param.type = cert_pi_useAIACertFetch;
514 in_param.value.scalar.b = PR_TRUE;
515 cvin->push_back(in_param);
516 in_param.type = cert_pi_end;
517 cvin->push_back(in_param);
518 rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
519 &(*cvin)[0], cvout, NULL);
520 if (rv == SECSuccess)
521 return rv;
522 int new_nss_error = PORT_GetError();
523 if (new_nss_error == SEC_ERROR_INVALID_ARGS ||
524 new_nss_error == SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE ||
525 new_nss_error == SEC_ERROR_BAD_INFO_ACCESS_LOCATION ||
526 new_nss_error == SEC_ERROR_BAD_HTTP_RESPONSE ||
527 new_nss_error == SEC_ERROR_BAD_LDAP_RESPONSE ||
528 !IS_SEC_ERROR(new_nss_error)) {
529 // Use the original error code because of cert_pi_useAIACertFetch's
530 // bad error reporting.
531 PORT_SetError(nss_error);
532 return rv;
534 nss_error = new_nss_error;
537 // If an intermediate CA certificate has requireExplicitPolicy in its
538 // policyConstraints extension, CERT_PKIXVerifyCert fails with
539 // SEC_ERROR_POLICY_VALIDATION_FAILED because we didn't specify any
540 // certificate policy (NSS bug 552775). So we retry with the certificate
541 // policy found in the server certificate.
542 if (nss_error == SEC_ERROR_POLICY_VALIDATION_FAILED &&
543 num_policy_oids == 0) {
544 SECOidTag policy = GetFirstCertPolicy(cert_handle);
545 if (policy != SEC_OID_UNKNOWN) {
546 DCHECK_EQ(cvin->back().type, cert_pi_end);
547 cvin->pop_back();
548 in_param.type = cert_pi_policyOID;
549 in_param.value.arraySize = 1;
550 in_param.value.array.oids = &policy;
551 cvin->push_back(in_param);
552 in_param.type = cert_pi_end;
553 cvin->push_back(in_param);
554 rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
555 &(*cvin)[0], cvout, NULL);
556 if (rv != SECSuccess) {
557 // Use the original error code.
558 PORT_SetError(nss_error);
563 return rv;
566 // Decodes the certificatePolicies extension of the certificate. Returns
567 // NULL if the certificate doesn't have the extension or the extension can't
568 // be decoded. The returned value must be freed with a
569 // CERT_DestroyCertificatePoliciesExtension call.
570 CERTCertificatePolicies* DecodeCertPolicies(
571 CERTCertificate* cert_handle) {
572 SECItem policy_ext;
573 SECStatus rv = CERT_FindCertExtension(cert_handle,
574 SEC_OID_X509_CERTIFICATE_POLICIES,
575 &policy_ext);
576 if (rv != SECSuccess)
577 return NULL;
578 CERTCertificatePolicies* policies =
579 CERT_DecodeCertificatePoliciesExtension(&policy_ext);
580 SECITEM_FreeItem(&policy_ext, PR_FALSE);
581 return policies;
584 // Returns the OID tag for the first certificate policy in the certificate's
585 // certificatePolicies extension. Returns SEC_OID_UNKNOWN if the certificate
586 // has no certificate policy.
587 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle) {
588 ScopedCERTCertificatePolicies policies(DecodeCertPolicies(cert_handle));
589 if (!policies.get())
590 return SEC_OID_UNKNOWN;
592 CERTPolicyInfo* policy_info = policies->policyInfos[0];
593 if (!policy_info)
594 return SEC_OID_UNKNOWN;
595 if (policy_info->oid != SEC_OID_UNKNOWN)
596 return policy_info->oid;
598 // The certificate policy is unknown to NSS. We need to create a dynamic
599 // OID tag for the policy.
600 SECOidData od;
601 od.oid.len = policy_info->policyID.len;
602 od.oid.data = policy_info->policyID.data;
603 od.offset = SEC_OID_UNKNOWN;
604 // NSS doesn't allow us to pass an empty description, so I use a hardcoded,
605 // default description here. The description doesn't need to be unique for
606 // each OID.
607 od.desc = "a certificate policy";
608 od.mechanism = CKM_INVALID_MECHANISM;
609 od.supportedExtension = INVALID_CERT_EXTENSION;
610 return SECOID_AddEntry(&od);
613 HashValue CertPublicKeyHashSHA1(CERTCertificate* cert) {
614 HashValue hash(HASH_VALUE_SHA1);
615 #if defined(OS_IOS)
616 CC_SHA1(cert->derPublicKey.data, cert->derPublicKey.len, hash.data());
617 #else
618 SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, hash.data(),
619 cert->derPublicKey.data, cert->derPublicKey.len);
620 DCHECK_EQ(SECSuccess, rv);
621 #endif
622 return hash;
625 HashValue CertPublicKeyHashSHA256(CERTCertificate* cert) {
626 HashValue hash(HASH_VALUE_SHA256);
627 #if defined(OS_IOS)
628 CC_SHA256(cert->derPublicKey.data, cert->derPublicKey.len, hash.data());
629 #else
630 SECStatus rv = HASH_HashBuf(HASH_AlgSHA256, hash.data(),
631 cert->derPublicKey.data, cert->derPublicKey.len);
632 DCHECK_EQ(rv, SECSuccess);
633 #endif
634 return hash;
637 void AppendPublicKeyHashes(CERTCertList* cert_list,
638 CERTCertificate* root_cert,
639 HashValueVector* hashes) {
640 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
641 !CERT_LIST_END(node, cert_list);
642 node = CERT_LIST_NEXT(node)) {
643 hashes->push_back(CertPublicKeyHashSHA1(node->cert));
644 hashes->push_back(CertPublicKeyHashSHA256(node->cert));
646 if (root_cert) {
647 hashes->push_back(CertPublicKeyHashSHA1(root_cert));
648 hashes->push_back(CertPublicKeyHashSHA256(root_cert));
652 // Returns true if |cert_handle| contains a policy OID that is an EV policy
653 // OID according to |metadata|, storing the resulting policy OID in
654 // |*ev_policy_oid|. A true return is not sufficient to establish that a
655 // certificate is EV, but a false return is sufficient to establish the
656 // certificate cannot be EV.
657 bool IsEVCandidate(EVRootCAMetadata* metadata,
658 CERTCertificate* cert_handle,
659 SECOidTag* ev_policy_oid) {
660 DCHECK(cert_handle);
661 ScopedCERTCertificatePolicies policies(DecodeCertPolicies(cert_handle));
662 if (!policies.get())
663 return false;
665 CERTPolicyInfo** policy_infos = policies->policyInfos;
666 while (*policy_infos != NULL) {
667 CERTPolicyInfo* policy_info = *policy_infos++;
668 // If the Policy OID is unknown, that implicitly means it has not been
669 // registered as an EV policy.
670 if (policy_info->oid == SEC_OID_UNKNOWN)
671 continue;
672 if (metadata->IsEVPolicyOID(policy_info->oid)) {
673 *ev_policy_oid = policy_info->oid;
674 return true;
678 return false;
681 // Studied Mozilla's code (esp. security/manager/ssl/src/nsIdentityChecking.cpp
682 // and nsNSSCertHelper.cpp) to learn how to verify EV certificate.
683 // TODO(wtc): A possible optimization is that we get the trust anchor from
684 // the first PKIXVerifyCert call. We look up the EV policy for the trust
685 // anchor. If the trust anchor has no EV policy, we know the cert isn't EV.
686 // Otherwise, we pass just that EV policy (as opposed to all the EV policies)
687 // to the second PKIXVerifyCert call.
688 bool VerifyEV(CERTCertificate* cert_handle,
689 int flags,
690 CRLSet* crl_set,
691 bool rev_checking_enabled,
692 EVRootCAMetadata* metadata,
693 SECOidTag ev_policy_oid,
694 CERTCertList* additional_trust_anchors,
695 CERTChainVerifyCallback* chain_verify_callback) {
696 CERTValOutParam cvout[3];
697 int cvout_index = 0;
698 cvout[cvout_index].type = cert_po_certList;
699 cvout[cvout_index].value.pointer.chain = NULL;
700 int cvout_cert_list_index = cvout_index;
701 cvout_index++;
702 cvout[cvout_index].type = cert_po_trustAnchor;
703 cvout[cvout_index].value.pointer.cert = NULL;
704 int cvout_trust_anchor_index = cvout_index;
705 cvout_index++;
706 cvout[cvout_index].type = cert_po_end;
707 ScopedCERTValOutParam scoped_cvout(cvout);
709 SECStatus status = PKIXVerifyCert(
710 cert_handle,
711 rev_checking_enabled,
712 true, /* hard fail is implied in EV. */
713 flags & CertVerifier::VERIFY_CERT_IO_ENABLED,
714 &ev_policy_oid,
716 additional_trust_anchors,
717 chain_verify_callback,
718 cvout);
719 if (status != SECSuccess)
720 return false;
722 CERTCertificate* root_ca =
723 cvout[cvout_trust_anchor_index].value.pointer.cert;
724 if (root_ca == NULL)
725 return false;
727 // This second PKIXVerifyCert call could have found a different certification
728 // path and one or more of the certificates on this new path, that weren't on
729 // the old path, might have been revoked.
730 if (crl_set) {
731 CRLSetResult crl_set_result = CheckRevocationWithCRLSet(
732 cvout[cvout_cert_list_index].value.pointer.chain,
733 cvout[cvout_trust_anchor_index].value.pointer.cert,
734 crl_set);
735 if (crl_set_result == kCRLSetRevoked)
736 return false;
739 #if defined(OS_IOS)
740 SHA1HashValue fingerprint = x509_util_ios::CalculateFingerprintNSS(root_ca);
741 #else
742 SHA1HashValue fingerprint =
743 X509Certificate::CalculateFingerprint(root_ca);
744 #endif
745 return metadata->HasEVPolicyOID(fingerprint, ev_policy_oid);
748 CERTCertList* CertificateListToCERTCertList(const CertificateList& list) {
749 CERTCertList* result = CERT_NewCertList();
750 for (size_t i = 0; i < list.size(); ++i) {
751 #if defined(OS_IOS)
752 // X509Certificate::os_cert_handle() on iOS is a SecCertificateRef; convert
753 // it to an NSS CERTCertificate.
754 CERTCertificate* cert = x509_util_ios::CreateNSSCertHandleFromOSHandle(
755 list[i]->os_cert_handle());
756 #else
757 CERTCertificate* cert = list[i]->os_cert_handle();
758 #endif
759 CERT_AddCertToListTail(result, CERT_DupCertificate(cert));
761 return result;
764 } // namespace
766 CertVerifyProcNSS::CertVerifyProcNSS()
767 #if defined(USE_NSS_CERTS)
768 : cache_ocsp_response_from_side_channel_(
769 reinterpret_cast<CacheOCSPResponseFromSideChannelFunction>(
770 dlsym(RTLD_DEFAULT, "CERT_CacheOCSPResponseFromSideChannel")))
771 #else
772 : cache_ocsp_response_from_side_channel_(
773 &CERT_CacheOCSPResponseFromSideChannel)
774 #endif
778 CertVerifyProcNSS::~CertVerifyProcNSS() {}
780 bool CertVerifyProcNSS::SupportsAdditionalTrustAnchors() const {
781 return true;
784 bool CertVerifyProcNSS::SupportsOCSPStapling() const {
785 return cache_ocsp_response_from_side_channel_;
788 int CertVerifyProcNSS::VerifyInternalImpl(
789 X509Certificate* cert,
790 const std::string& hostname,
791 const std::string& ocsp_response,
792 int flags,
793 CRLSet* crl_set,
794 const CertificateList& additional_trust_anchors,
795 CERTChainVerifyCallback* chain_verify_callback,
796 CertVerifyResult* verify_result) {
797 #if defined(OS_IOS)
798 // For iOS, the entire chain must be loaded into NSS's in-memory certificate
799 // store.
800 x509_util_ios::NSSCertChain scoped_chain(cert);
801 CERTCertificate* cert_handle = scoped_chain.cert_handle();
802 #else
803 CERTCertificate* cert_handle = cert->os_cert_handle();
804 #endif // defined(OS_IOS)
806 if (!ocsp_response.empty() && cache_ocsp_response_from_side_channel_) {
807 // Note: NSS uses a thread-safe global hash table, so this call will
808 // affect any concurrent verification operations on |cert| or copies of
809 // the same certificate. This is an unavoidable limitation of NSS's OCSP
810 // API.
811 SECItem ocsp_response_item;
812 ocsp_response_item.data = reinterpret_cast<unsigned char*>(
813 const_cast<char*>(ocsp_response.data()));
814 ocsp_response_item.len = ocsp_response.size();
815 cache_ocsp_response_from_side_channel_(CERT_GetDefaultCertDB(), cert_handle,
816 PR_Now(), &ocsp_response_item,
817 nullptr);
820 if (!cert->VerifyNameMatch(hostname,
821 &verify_result->common_name_fallback_used)) {
822 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
825 // Make sure that the cert is valid now.
826 SECCertTimeValidity validity = CERT_CheckCertValidTimes(
827 cert_handle, PR_Now(), PR_TRUE);
828 if (validity != secCertTimeValid)
829 verify_result->cert_status |= CERT_STATUS_DATE_INVALID;
831 CERTValOutParam cvout[3];
832 int cvout_index = 0;
833 cvout[cvout_index].type = cert_po_certList;
834 cvout[cvout_index].value.pointer.chain = NULL;
835 int cvout_cert_list_index = cvout_index;
836 cvout_index++;
837 cvout[cvout_index].type = cert_po_trustAnchor;
838 cvout[cvout_index].value.pointer.cert = NULL;
839 int cvout_trust_anchor_index = cvout_index;
840 cvout_index++;
841 cvout[cvout_index].type = cert_po_end;
842 ScopedCERTValOutParam scoped_cvout(cvout);
844 EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
845 SECOidTag ev_policy_oid = SEC_OID_UNKNOWN;
846 bool is_ev_candidate =
847 (flags & CertVerifier::VERIFY_EV_CERT) &&
848 IsEVCandidate(metadata, cert_handle, &ev_policy_oid);
849 bool cert_io_enabled = flags & CertVerifier::VERIFY_CERT_IO_ENABLED;
850 bool check_revocation =
851 cert_io_enabled &&
852 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED);
853 if (check_revocation)
854 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
856 ScopedCERTCertList trust_anchors;
857 if (!additional_trust_anchors.empty()) {
858 trust_anchors.reset(
859 CertificateListToCERTCertList(additional_trust_anchors));
862 SECStatus status = PKIXVerifyCert(cert_handle,
863 check_revocation,
864 false,
865 cert_io_enabled,
866 NULL,
868 trust_anchors.get(),
869 chain_verify_callback,
870 cvout);
872 if (status == SECSuccess &&
873 (flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) &&
874 !IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert)) {
875 // TODO(rsleevi): Optimize this by supplying the constructed chain to
876 // libpkix via cvin. Omitting for now, due to lack of coverage in upstream
877 // NSS tests for that feature.
878 scoped_cvout.Clear();
879 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
880 status = PKIXVerifyCert(cert_handle,
881 true,
882 true,
883 cert_io_enabled,
884 NULL,
886 trust_anchors.get(),
887 chain_verify_callback,
888 cvout);
891 if (status == SECSuccess) {
892 AppendPublicKeyHashes(cvout[cvout_cert_list_index].value.pointer.chain,
893 cvout[cvout_trust_anchor_index].value.pointer.cert,
894 &verify_result->public_key_hashes);
896 verify_result->is_issued_by_known_root =
897 IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert);
898 verify_result->is_issued_by_additional_trust_anchor =
899 IsAdditionalTrustAnchor(
900 trust_anchors.get(),
901 cvout[cvout_trust_anchor_index].value.pointer.cert);
903 GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain,
904 cvout[cvout_trust_anchor_index].value.pointer.cert,
905 verify_result);
908 CRLSetResult crl_set_result = kCRLSetUnknown;
909 if (crl_set) {
910 crl_set_result = CheckRevocationWithCRLSet(
911 cvout[cvout_cert_list_index].value.pointer.chain,
912 cvout[cvout_trust_anchor_index].value.pointer.cert,
913 crl_set);
914 if (crl_set_result == kCRLSetRevoked) {
915 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
916 status = SECFailure;
920 if (status != SECSuccess) {
921 int err = PORT_GetError();
922 LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname
923 << " failed err=" << err;
924 // CERT_PKIXVerifyCert rerports the wrong error code for
925 // expired certificates (NSS bug 491174)
926 if (err == SEC_ERROR_CERT_NOT_VALID &&
927 (verify_result->cert_status & CERT_STATUS_DATE_INVALID))
928 err = SEC_ERROR_EXPIRED_CERTIFICATE;
929 CertStatus cert_status = MapCertErrorToCertStatus(err);
930 if (cert_status) {
931 verify_result->cert_status |= cert_status;
932 return MapCertStatusToNetError(verify_result->cert_status);
934 // |err| is not a certificate error.
935 return MapSecurityError(err);
938 if (IsCertStatusError(verify_result->cert_status))
939 return MapCertStatusToNetError(verify_result->cert_status);
941 if ((flags & CertVerifier::VERIFY_EV_CERT) && is_ev_candidate) {
942 check_revocation |=
943 crl_set_result != kCRLSetOk &&
944 cert_io_enabled &&
945 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY);
946 if (check_revocation)
947 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
949 if (VerifyEV(cert_handle,
950 flags,
951 crl_set,
952 check_revocation,
953 metadata,
954 ev_policy_oid,
955 trust_anchors.get(),
956 chain_verify_callback)) {
957 verify_result->cert_status |= CERT_STATUS_IS_EV;
961 return OK;
964 int CertVerifyProcNSS::VerifyInternal(
965 X509Certificate* cert,
966 const std::string& hostname,
967 const std::string& ocsp_response,
968 int flags,
969 CRLSet* crl_set,
970 const CertificateList& additional_trust_anchors,
971 CertVerifyResult* verify_result) {
972 return VerifyInternalImpl(cert, hostname, ocsp_response, flags, crl_set,
973 additional_trust_anchors,
974 NULL, // chain_verify_callback
975 verify_result);
978 } // namespace net