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