Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Side by Side Diff: net/base/x509_chain_nss.cc

Issue 3112013: Move chain building/verification out of X509Certificate (Closed)
Patch Set: Rebase to trunk - Without OpenSSL fixes Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/base/x509_chain.h"
6
7 #include <cert.h>
8 #include <nss.h>
9 #include <prerror.h>
10 #include <secerr.h>
11 #include <sslerr.h>
12
13 #include "base/logging.h"
14 #include "net/base/cert_status_flags.h"
15 #include "net/base/cert_verify_result.h"
16 #include "net/base/ev_root_ca_metadata.h"
17 #include "net/base/net_errors.h"
18
19 namespace net {
20
21 namespace {
22
23 class ScopedCERTCertificatePolicies {
24 public:
25 explicit ScopedCERTCertificatePolicies(CERTCertificatePolicies* policies)
26 : policies_(policies) {}
27
28 ~ScopedCERTCertificatePolicies() {
29 if (policies_)
30 CERT_DestroyCertificatePoliciesExtension(policies_);
31 }
32
33 private:
34 CERTCertificatePolicies* policies_;
35
36 DISALLOW_COPY_AND_ASSIGN(ScopedCERTCertificatePolicies);
37 };
38
39 // ScopedCERTValOutParam manages destruction of values in the CERTValOutParam
40 // array that cvout points to. cvout must be initialized as passed to
41 // CERT_PKIXVerifyCert, so that the array must be terminated with
42 // cert_po_end type.
43 // When it goes out of scope, it destroys values of cert_po_trustAnchor
44 // and cert_po_certList types, but doesn't release the array itself.
45 class ScopedCERTValOutParam {
46 public:
47 explicit ScopedCERTValOutParam(CERTValOutParam* cvout)
48 : cvout_(cvout) {}
49
50 ~ScopedCERTValOutParam() {
51 if (cvout_ == NULL)
52 return;
53 for (CERTValOutParam *p = cvout_; p->type != cert_po_end; p++) {
bulach 2010/10/21 10:21:33 nits: s/CERTValOutParam */CERTValOutParam* / s/p++
54 switch (p->type) {
55 case cert_po_trustAnchor:
56 if (p->value.pointer.cert) {
57 CERT_DestroyCertificate(p->value.pointer.cert);
58 p->value.pointer.cert = NULL;
59 }
60 break;
61 case cert_po_certList:
62 if (p->value.pointer.chain) {
63 CERT_DestroyCertList(p->value.pointer.chain);
64 p->value.pointer.chain = NULL;
65 }
66 break;
67 default:
68 break;
69 }
70 }
71 }
72
73 private:
74 CERTValOutParam* cvout_;
75
76 DISALLOW_COPY_AND_ASSIGN(ScopedCERTValOutParam);
77 };
78
79 // Map PORT_GetError() return values to our network error codes.
80 int MapSecurityError(int err) {
81 switch (err) {
82 case PR_DIRECTORY_LOOKUP_ERROR: // DNS lookup error.
83 return ERR_NAME_NOT_RESOLVED;
84 case SEC_ERROR_INVALID_ARGS:
85 return ERR_INVALID_ARGUMENT;
86 case SSL_ERROR_BAD_CERT_DOMAIN:
87 return ERR_CERT_COMMON_NAME_INVALID;
88 case SEC_ERROR_INVALID_TIME:
89 case SEC_ERROR_EXPIRED_CERTIFICATE:
90 return ERR_CERT_DATE_INVALID;
91 case SEC_ERROR_UNKNOWN_ISSUER:
92 case SEC_ERROR_UNTRUSTED_ISSUER:
93 case SEC_ERROR_CA_CERT_INVALID:
94 case SEC_ERROR_UNTRUSTED_CERT:
95 return ERR_CERT_AUTHORITY_INVALID;
96 case SEC_ERROR_REVOKED_CERTIFICATE:
97 return ERR_CERT_REVOKED;
98 case SEC_ERROR_BAD_DER:
99 case SEC_ERROR_BAD_SIGNATURE:
100 case SEC_ERROR_CERT_NOT_VALID:
101 // TODO(port): add an ERR_CERT_WRONG_USAGE error code.
102 case SEC_ERROR_CERT_USAGES_INVALID:
103 case SEC_ERROR_POLICY_VALIDATION_FAILED:
104 return ERR_CERT_INVALID;
105 default:
106 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
107 return ERR_FAILED;
108 }
109 }
110
111 // Map PORT_GetError() return values to our cert status flags.
112 int MapCertErrorToCertStatus(int err) {
113 switch (err) {
114 case SSL_ERROR_BAD_CERT_DOMAIN:
115 return CERT_STATUS_COMMON_NAME_INVALID;
116 case SEC_ERROR_INVALID_TIME:
117 case SEC_ERROR_EXPIRED_CERTIFICATE:
118 return CERT_STATUS_DATE_INVALID;
119 case SEC_ERROR_UNTRUSTED_CERT:
120 case SEC_ERROR_UNKNOWN_ISSUER:
121 case SEC_ERROR_UNTRUSTED_ISSUER:
122 case SEC_ERROR_CA_CERT_INVALID:
123 return CERT_STATUS_AUTHORITY_INVALID;
124 // TODO(port): map CERT_STATUS_NO_REVOCATION_MECHANISM.
125 case SEC_ERROR_OCSP_BAD_HTTP_RESPONSE:
126 case SEC_ERROR_OCSP_SERVER_ERROR:
127 return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
128 case SEC_ERROR_REVOKED_CERTIFICATE:
129 return CERT_STATUS_REVOKED;
130 case SEC_ERROR_BAD_DER:
131 case SEC_ERROR_BAD_SIGNATURE:
132 case SEC_ERROR_CERT_NOT_VALID:
133 // TODO(port): add a CERT_STATUS_WRONG_USAGE error code.
134 case SEC_ERROR_CERT_USAGES_INVALID:
135 case SEC_ERROR_POLICY_VALIDATION_FAILED:
136 return CERT_STATUS_INVALID;
137 default:
138 return 0;
139 }
140 }
141
142 // Saves some information about the certificate chain cert_list in
143 // *verify_result. The caller MUST initialize *verify_result before calling
144 // this function.
145 // Note that cert_list[0] is the end entity certificate and cert_list doesn't
146 // contain the root CA certificate.
147 void GetCertChainInfo(CERTCertList* cert_list,
148 CertVerifyResult* verify_result) {
149 // NOTE: Using a NSS library before 3.12.3.1 will crash below. To see the
150 // NSS version currently in use:
151 // 1. use ldd on the chrome executable for NSS's location (ie. libnss3.so*)
152 // 2. use ident libnss3.so* for the library's version
153 DCHECK(cert_list);
154 int i = 0;
155 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
156 !CERT_LIST_END(node, cert_list);
157 node = CERT_LIST_NEXT(node), i++) {
bulach 2010/10/21 10:21:33 nit: ++i
158 SECAlgorithmID& signature = node->cert->signature;
159 SECOidTag oid_tag = SECOID_FindOIDTag(&signature.algorithm);
160 switch (oid_tag) {
161 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
162 verify_result->has_md5 = true;
163 if (i != 0)
164 verify_result->has_md5_ca = true;
165 break;
166 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
167 verify_result->has_md2 = true;
168 if (i != 0)
169 verify_result->has_md2_ca = true;
170 break;
171 case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
172 verify_result->has_md4 = true;
173 break;
174 default:
175 break;
176 }
177 }
178 }
179
180 // Forward declarations.
181 SECStatus RetryPKIXVerifyCertWithWorkarounds(
182 X509Certificate::OSCertHandle cert_handle, int num_policy_oids,
183 std::vector<CERTValInParam>* cvin, CERTValOutParam* cvout);
184 SECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle);
185
186 // Call CERT_PKIXVerifyCert for the cert_handle.
187 // Verification results are stored in an array of CERTValOutParam.
188 // If policy_oids is not NULL and num_policy_oids is positive, policies
189 // are also checked.
190 // Caller must initialize cvout before calling this function.
191 SECStatus PKIXVerifyCert(X509Certificate::OSCertHandle cert_handle,
192 bool check_revocation,
193 const SECOidTag* policy_oids,
194 int num_policy_oids,
195 CERTValOutParam* cvout) {
196 bool use_crl = check_revocation;
197 bool use_ocsp = check_revocation;
198
199 // These CAs have multiple keys, which trigger two bugs in NSS's CRL code.
200 // 1. NSS may use one key to verify a CRL signed with another key,
201 // incorrectly concluding that the CRL's signature is invalid.
202 // Hopefully this bug will be fixed in NSS 3.12.9.
203 // 2. NSS considers all certificates issued by the CA as revoked when it
204 // receives a CRL with an invalid signature. This overly strict policy
205 // has been relaxed in NSS 3.12.7. See
206 // https://bugzilla.mozilla.org/show_bug.cgi?id=562542.
207 // So we have to turn off CRL checking for these CAs. See
208 // http://crbug.com/55695.
209 static const char* const kMultipleKeyCA[] = {
210 "CN=Microsoft Secure Server Authority,"
211 "DC=redmond,DC=corp,DC=microsoft,DC=com",
212 "CN=Microsoft Secure Server Authority",
213 };
214
215 if (!NSS_VersionCheck("3.12.7")) {
216 for (size_t i = 0; i < arraysize(kMultipleKeyCA); ++i) {
217 if (strcmp(cert_handle->issuerName, kMultipleKeyCA[i]) == 0) {
218 use_crl = false;
219 break;
220 }
221 }
222 }
223
224 PRUint64 revocation_method_flags =
225 CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD |
226 CERT_REV_M_ALLOW_NETWORK_FETCHING |
227 CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE |
228 CERT_REV_M_IGNORE_MISSING_FRESH_INFO |
229 CERT_REV_M_STOP_TESTING_ON_FRESH_INFO;
230 PRUint64 revocation_method_independent_flags =
231 CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST;
232 if (policy_oids && num_policy_oids > 0) {
233 // EV verification requires revocation checking. Consider the certificate
234 // revoked if we don't have revocation info.
235 // TODO(wtc): Add a bool parameter to expressly specify we're doing EV
236 // verification or we want strict revocation flags.
237 revocation_method_flags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE;
238 revocation_method_independent_flags |=
239 CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;
240 } else {
241 revocation_method_flags |= CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE;
242 revocation_method_independent_flags |=
243 CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT;
244 }
245 PRUint64 method_flags[2];
246 method_flags[cert_revocation_method_crl] = revocation_method_flags;
247 method_flags[cert_revocation_method_ocsp] = revocation_method_flags;
248
249 if (use_crl) {
250 method_flags[cert_revocation_method_crl] |=
251 CERT_REV_M_TEST_USING_THIS_METHOD;
252 }
253 if (use_ocsp) {
254 method_flags[cert_revocation_method_ocsp] |=
255 CERT_REV_M_TEST_USING_THIS_METHOD;
256 }
257
258 CERTRevocationMethodIndex preferred_revocation_methods[1];
259 if (use_ocsp) {
260 preferred_revocation_methods[0] = cert_revocation_method_ocsp;
261 } else {
262 preferred_revocation_methods[0] = cert_revocation_method_crl;
263 }
264
265 CERTRevocationFlags revocation_flags;
266 revocation_flags.leafTests.number_of_defined_methods =
267 arraysize(method_flags);
268 revocation_flags.leafTests.cert_rev_flags_per_method = method_flags;
269 revocation_flags.leafTests.number_of_preferred_methods =
270 arraysize(preferred_revocation_methods);
271 revocation_flags.leafTests.preferred_methods = preferred_revocation_methods;
272 revocation_flags.leafTests.cert_rev_method_independent_flags =
273 revocation_method_independent_flags;
274
275 revocation_flags.chainTests.number_of_defined_methods =
276 arraysize(method_flags);
277 revocation_flags.chainTests.cert_rev_flags_per_method = method_flags;
278 revocation_flags.chainTests.number_of_preferred_methods =
279 arraysize(preferred_revocation_methods);
280 revocation_flags.chainTests.preferred_methods = preferred_revocation_methods;
281 revocation_flags.chainTests.cert_rev_method_independent_flags =
282 revocation_method_independent_flags;
283
284 std::vector<CERTValInParam> cvin;
285 cvin.reserve(5);
bulach 2010/10/21 10:21:33 nit: not sure why 5 as there are three push_back b
286 CERTValInParam in_param;
287 // No need to set cert_pi_trustAnchors here.
288 in_param.type = cert_pi_revocationFlags;
289 in_param.value.pointer.revocation = &revocation_flags;
290 cvin.push_back(in_param);
291 if (policy_oids && num_policy_oids > 0) {
292 in_param.type = cert_pi_policyOID;
293 in_param.value.arraySize = num_policy_oids;
294 in_param.value.array.oids = policy_oids;
295 cvin.push_back(in_param);
296 }
297 in_param.type = cert_pi_end;
298 cvin.push_back(in_param);
299
300 SECStatus rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
301 &cvin[0], cvout, NULL);
302 if (rv != SECSuccess) {
303 rv = RetryPKIXVerifyCertWithWorkarounds(cert_handle, num_policy_oids,
304 &cvin, cvout);
305 }
306 return rv;
307 }
308
309 // PKIXVerifyCert calls this function to work around some bugs in
310 // CERT_PKIXVerifyCert. All the arguments of this function are either the
311 // arguments or local variables of PKIXVerifyCert.
312 SECStatus RetryPKIXVerifyCertWithWorkarounds(
313 X509Certificate::OSCertHandle cert_handle, int num_policy_oids,
314 std::vector<CERTValInParam>* cvin, CERTValOutParam* cvout) {
315 // We call this function when the first CERT_PKIXVerifyCert call in
316 // PKIXVerifyCert failed, so we initialize |rv| to SECFailure.
317 SECStatus rv = SECFailure;
318 int nss_error = PORT_GetError();
319 CERTValInParam in_param;
320
321 // If we get SEC_ERROR_UNKNOWN_ISSUER, we may be missing an intermediate
322 // CA certificate, so we retry with cert_pi_useAIACertFetch.
323 // cert_pi_useAIACertFetch has several bugs in its error handling and
324 // error reporting (NSS bug 528743), so we don't use it by default.
325 // Note: When building a certificate chain, CERT_PKIXVerifyCert may
326 // incorrectly pick a CA certificate with the same subject name as the
327 // missing intermediate CA certificate, and fail with the
328 // SEC_ERROR_BAD_SIGNATURE error (NSS bug 524013), so we also retry with
329 // cert_pi_useAIACertFetch on SEC_ERROR_BAD_SIGNATURE.
330 if (nss_error == SEC_ERROR_UNKNOWN_ISSUER ||
331 nss_error == SEC_ERROR_BAD_SIGNATURE) {
332 DCHECK_EQ(cvin->back().type, cert_pi_end);
333 cvin->pop_back();
334 in_param.type = cert_pi_useAIACertFetch;
335 in_param.value.scalar.b = PR_TRUE;
336 cvin->push_back(in_param);
337 in_param.type = cert_pi_end;
338 cvin->push_back(in_param);
339 rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
340 &(*cvin)[0], cvout, NULL);
341 if (rv == SECSuccess)
342 return rv;
343 int new_nss_error = PORT_GetError();
344 if (new_nss_error == SEC_ERROR_INVALID_ARGS ||
345 new_nss_error == SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE ||
346 new_nss_error == SEC_ERROR_BAD_HTTP_RESPONSE ||
347 new_nss_error == SEC_ERROR_BAD_LDAP_RESPONSE ||
348 !IS_SEC_ERROR(new_nss_error)) {
349 // Use the original error code because of cert_pi_useAIACertFetch's
350 // bad error reporting.
351 PORT_SetError(nss_error);
352 return rv;
353 }
354 nss_error = new_nss_error;
355 }
356
357 // If an intermediate CA certificate has requireExplicitPolicy in its
358 // policyConstraints extension, CERT_PKIXVerifyCert fails with
359 // SEC_ERROR_POLICY_VALIDATION_FAILED because we didn't specify any
360 // certificate policy (NSS bug 552775). So we retry with the certificate
361 // policy found in the server certificate.
362 if (nss_error == SEC_ERROR_POLICY_VALIDATION_FAILED &&
363 num_policy_oids == 0) {
364 SECOidTag policy = GetFirstCertPolicy(cert_handle);
365 if (policy != SEC_OID_UNKNOWN) {
366 DCHECK_EQ(cvin->back().type, cert_pi_end);
367 cvin->pop_back();
368 in_param.type = cert_pi_policyOID;
369 in_param.value.arraySize = 1;
370 in_param.value.array.oids = &policy;
371 cvin->push_back(in_param);
372 in_param.type = cert_pi_end;
373 cvin->push_back(in_param);
374 rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer,
375 &(*cvin)[0], cvout, NULL);
376 if (rv != SECSuccess) {
377 // Use the original error code.
378 PORT_SetError(nss_error);
379 }
380 }
381 }
382
383 return rv;
384 }
385
386 // Decodes the certificatePolicies extension of the certificate. Returns
387 // NULL if the certificate doesn't have the extension or the extension can't
388 // be decoded. The returned value must be freed with a
389 // CERT_DestroyCertificatePoliciesExtension call.
390 CERTCertificatePolicies* DecodeCertPolicies(
391 X509Certificate::OSCertHandle cert_handle) {
392 SECItem policy_ext;
393 SECStatus rv = CERT_FindCertExtension(
394 cert_handle, SEC_OID_X509_CERTIFICATE_POLICIES, &policy_ext);
395 if (rv != SECSuccess)
396 return NULL;
397 CERTCertificatePolicies* policies =
398 CERT_DecodeCertificatePoliciesExtension(&policy_ext);
399 SECITEM_FreeItem(&policy_ext, PR_FALSE);
400 return policies;
401 }
402
403 // Returns the OID tag for the first certificate policy in the certificate's
404 // certificatePolicies extension. Returns SEC_OID_UNKNOWN if the certificate
405 // has no certificate policy.
406 SECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle) {
407 CERTCertificatePolicies* policies = DecodeCertPolicies(cert_handle);
408 if (!policies)
409 return SEC_OID_UNKNOWN;
410 ScopedCERTCertificatePolicies scoped_policies(policies);
411 CERTPolicyInfo* policy_info = policies->policyInfos[0];
412 if (!policy_info)
413 return SEC_OID_UNKNOWN;
414 if (policy_info->oid != SEC_OID_UNKNOWN)
415 return policy_info->oid;
416
417 // The certificate policy is unknown to NSS. We need to create a dynamic
418 // OID tag for the policy.
419 SECOidData od;
420 od.oid.len = policy_info->policyID.len;
421 od.oid.data = policy_info->policyID.data;
422 od.offset = SEC_OID_UNKNOWN;
423 // NSS doesn't allow us to pass an empty description, so I use a hardcoded,
424 // default description here. The description doesn't need to be unique for
425 // each OID.
426 od.desc = "a certificate policy";
427 od.mechanism = CKM_INVALID_MECHANISM;
428 od.supportedExtension = INVALID_CERT_EXTENSION;
429 return SECOID_AddEntry(&od);
430 }
431
432 bool CheckCertPolicies(X509Certificate::OSCertHandle cert_handle,
433 SECOidTag ev_policy_tag) {
434 CERTCertificatePolicies* policies = DecodeCertPolicies(cert_handle);
435 if (!policies) {
436 LOG(ERROR) << "Cert has no policies extension or extension couldn't be "
437 "decoded.";
438 return false;
439 }
440 ScopedCERTCertificatePolicies scoped_policies(policies);
441 CERTPolicyInfo** policy_infos = policies->policyInfos;
442 while (*policy_infos != NULL) {
443 CERTPolicyInfo* policy_info = *policy_infos++;
444 SECOidTag oid_tag = policy_info->oid;
445 if (oid_tag == SEC_OID_UNKNOWN)
446 continue;
447 if (oid_tag == ev_policy_tag)
448 return true;
449 }
450 LOG(ERROR) << "No EV Policy Tag";
451 return false;
452 }
453
454 // Studied Mozilla's code (esp. security/manager/ssl/src/nsIdentityChecking.cpp
455 // and nsNSSCertHelper.cpp) to learn how to verify EV certificate.
456 // TODO(wtc): A possible optimization is that we get the trust anchor from
457 // the first PKIXVerifyCert call. We look up the EV policy for the trust
458 // anchor. If the trust anchor has no EV policy, we know the cert isn't EV.
459 // Otherwise, we pass just that EV policy (as opposed to all the EV policies)
460 // to the second PKIXVerifyCert call.
461 bool VerifyEV(X509Certificate* certificate) {
462 net::EVRootCAMetadata* metadata = net::EVRootCAMetadata::GetInstance();
463
464 CERTValOutParam cvout[3];
465 int cvout_index = 0;
466 cvout[cvout_index].type = cert_po_trustAnchor;
467 cvout[cvout_index].value.pointer.cert = NULL;
468 int cvout_trust_anchor_index = cvout_index;
469 cvout_index++;
bulach 2010/10/21 10:21:33 nit: ++cvout_index;
470 cvout[cvout_index].type = cert_po_end;
471 ScopedCERTValOutParam scoped_cvout(cvout);
472
473 SECStatus status = PKIXVerifyCert(certificate->os_cert_handle(),
474 true,
475 metadata->GetPolicyOIDs(),
476 metadata->NumPolicyOIDs(),
477 cvout);
478 if (status != SECSuccess)
479 return false;
480
481 CERTCertificate* root_ca =
482 cvout[cvout_trust_anchor_index].value.pointer.cert;
483 if (root_ca == NULL)
484 return false;
485 SHA1Fingerprint fingerprint =
486 X509Certificate::CalculateFingerprint(root_ca);
487 SECOidTag ev_policy_tag = SEC_OID_UNKNOWN;
488 if (!metadata->GetPolicyOID(fingerprint, &ev_policy_tag))
489 return false;
490
491 if (!CheckCertPolicies(certificate->os_cert_handle(), ev_policy_tag))
492 return false;
493
494 return true;
495 }
496
497 } // namespace
498
499 namespace x509_chain {
500
501 int VerifySSLServer(X509Certificate* certificate, const std::string& hostname,
502 int flags, CertVerifyResult* verify_result) {
503 verify_result->Reset();
504 if (!certificate || !certificate->os_cert_handle())
505 return ERR_UNEXPECTED;
506
507 // Make sure that the hostname matches with the common name of the cert.
508 SECStatus status = CERT_VerifyCertName(certificate->os_cert_handle(),
509 hostname.c_str());
510 if (status != SECSuccess)
511 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
512
513 // Make sure that the cert is valid now.
514 SECCertTimeValidity validity = CERT_CheckCertValidTimes(
515 certificate->os_cert_handle(), PR_Now(), PR_TRUE);
516 if (validity != secCertTimeValid)
517 verify_result->cert_status |= CERT_STATUS_DATE_INVALID;
518
519 CERTValOutParam cvout[3];
520 int cvout_index = 0;
521 // We don't need the trust anchor for the first PKIXVerifyCert call.
522 cvout[cvout_index].type = cert_po_certList;
523 cvout[cvout_index].value.pointer.chain = NULL;
524 int cvout_cert_list_index = cvout_index;
525 cvout_index++;
526 cvout[cvout_index].type = cert_po_end;
527 ScopedCERTValOutParam scoped_cvout(cvout);
528
529 bool check_revocation = (flags & VERIFY_REV_CHECKING_ENABLED);
530 if (check_revocation) {
531 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
532 } else {
533 // EV requires revocation checking.
534 flags &= ~VERIFY_EV_CERT;
535 }
536 status = PKIXVerifyCert(certificate->os_cert_handle(), check_revocation,
537 NULL, 0, cvout);
538 if (status != SECSuccess) {
539 int err = PORT_GetError();
540 LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname
541 << " failed err=" << err;
542 // CERT_PKIXVerifyCert rerports the wrong error code for
543 // expired certificates (NSS bug 491174)
544 if (err == SEC_ERROR_CERT_NOT_VALID &&
545 (verify_result->cert_status & CERT_STATUS_DATE_INVALID) != 0)
546 err = SEC_ERROR_EXPIRED_CERTIFICATE;
547 int cert_status = MapCertErrorToCertStatus(err);
548 if (cert_status) {
549 verify_result->cert_status |= cert_status;
550 return MapCertStatusToNetError(verify_result->cert_status);
551 }
552 // |err| is not a certificate error.
553 return MapSecurityError(err);
554 }
555
556 GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain,
557 verify_result);
558 if (IsCertStatusError(verify_result->cert_status))
559 return MapCertStatusToNetError(verify_result->cert_status);
560
561 if ((flags & VERIFY_EV_CERT) && VerifyEV(certificate))
562 verify_result->cert_status |= CERT_STATUS_IS_EV;
563 return OK;
564 }
565
566 } // namespace x509_chain
567
568 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698