OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/cert/cert_verify_proc_nss.h" | 5 #include "net/cert/cert_verify_proc_nss.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include <cert.h> | 10 #include <cert.h> |
(...skipping 25 matching lines...) Expand all Loading... |
36 namespace net { | 36 namespace net { |
37 | 37 |
38 namespace { | 38 namespace { |
39 | 39 |
40 typedef scoped_ptr< | 40 typedef scoped_ptr< |
41 CERTCertificatePolicies, | 41 CERTCertificatePolicies, |
42 crypto::NSSDestroyer<CERTCertificatePolicies, | 42 crypto::NSSDestroyer<CERTCertificatePolicies, |
43 CERT_DestroyCertificatePoliciesExtension> > | 43 CERT_DestroyCertificatePoliciesExtension> > |
44 ScopedCERTCertificatePolicies; | 44 ScopedCERTCertificatePolicies; |
45 | 45 |
46 typedef scoped_ptr< | 46 typedef scoped_ptr<CERTCertList, |
47 CERTCertList, | 47 crypto::NSSDestroyer<CERTCertList, CERT_DestroyCertList> > |
48 crypto::NSSDestroyer<CERTCertList, CERT_DestroyCertList> > | |
49 ScopedCERTCertList; | 48 ScopedCERTCertList; |
50 | 49 |
51 // ScopedCERTValOutParam manages destruction of values in the CERTValOutParam | 50 // ScopedCERTValOutParam manages destruction of values in the CERTValOutParam |
52 // array that cvout points to. cvout must be initialized as passed to | 51 // array that cvout points to. cvout must be initialized as passed to |
53 // CERT_PKIXVerifyCert, so that the array must be terminated with | 52 // CERT_PKIXVerifyCert, so that the array must be terminated with |
54 // cert_po_end type. | 53 // cert_po_end type. |
55 // When it goes out of scope, it destroys values of cert_po_trustAnchor | 54 // When it goes out of scope, it destroys values of cert_po_trustAnchor |
56 // and cert_po_certList types, but doesn't release the array itself. | 55 // and cert_po_certList types, but doesn't release the array itself. |
57 class ScopedCERTValOutParam { | 56 class ScopedCERTValOutParam { |
58 public: | 57 public: |
59 explicit ScopedCERTValOutParam(CERTValOutParam* cvout) : cvout_(cvout) {} | 58 explicit ScopedCERTValOutParam(CERTValOutParam* cvout) : cvout_(cvout) {} |
60 | 59 |
61 ~ScopedCERTValOutParam() { | 60 ~ScopedCERTValOutParam() { Clear(); } |
62 Clear(); | |
63 } | |
64 | 61 |
65 // Free the internal resources, but do not release the array itself. | 62 // Free the internal resources, but do not release the array itself. |
66 void Clear() { | 63 void Clear() { |
67 if (cvout_ == NULL) | 64 if (cvout_ == NULL) |
68 return; | 65 return; |
69 for (CERTValOutParam *p = cvout_; p->type != cert_po_end; p++) { | 66 for (CERTValOutParam* p = cvout_; p->type != cert_po_end; p++) { |
70 switch (p->type) { | 67 switch (p->type) { |
71 case cert_po_trustAnchor: | 68 case cert_po_trustAnchor: |
72 if (p->value.pointer.cert) { | 69 if (p->value.pointer.cert) { |
73 CERT_DestroyCertificate(p->value.pointer.cert); | 70 CERT_DestroyCertificate(p->value.pointer.cert); |
74 p->value.pointer.cert = NULL; | 71 p->value.pointer.cert = NULL; |
75 } | 72 } |
76 break; | 73 break; |
77 case cert_po_certList: | 74 case cert_po_certList: |
78 if (p->value.pointer.chain) { | 75 if (p->value.pointer.chain) { |
79 CERT_DestroyCertList(p->value.pointer.chain); | 76 CERT_DestroyCertList(p->value.pointer.chain); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 } | 217 } |
221 | 218 |
222 // IsKnownRoot returns true if the given certificate is one that we believe | 219 // IsKnownRoot returns true if the given certificate is one that we believe |
223 // is a standard (as opposed to user-installed) root. | 220 // is a standard (as opposed to user-installed) root. |
224 bool IsKnownRoot(CERTCertificate* root) { | 221 bool IsKnownRoot(CERTCertificate* root) { |
225 if (!root || !root->slot) | 222 if (!root || !root->slot) |
226 return false; | 223 return false; |
227 | 224 |
228 // This magic name is taken from | 225 // This magic name is taken from |
229 // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw/b
uiltins/constants.c&rev=1.13&mark=86,89#79 | 226 // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw/b
uiltins/constants.c&rev=1.13&mark=86,89#79 |
230 return 0 == strcmp(PK11_GetSlotName(root->slot), | 227 return 0 == strcmp(PK11_GetSlotName(root->slot), "NSS Builtin Objects"); |
231 "NSS Builtin Objects"); | |
232 } | 228 } |
233 | 229 |
234 // Returns true if the given certificate is one of the additional trust anchors. | 230 // Returns true if the given certificate is one of the additional trust anchors. |
235 bool IsAdditionalTrustAnchor(CERTCertList* additional_trust_anchors, | 231 bool IsAdditionalTrustAnchor(CERTCertList* additional_trust_anchors, |
236 CERTCertificate* root) { | 232 CERTCertificate* root) { |
237 if (!additional_trust_anchors || !root) | 233 if (!additional_trust_anchors || !root) |
238 return false; | 234 return false; |
239 for (CERTCertListNode* node = CERT_LIST_HEAD(additional_trust_anchors); | 235 for (CERTCertListNode* node = CERT_LIST_HEAD(additional_trust_anchors); |
240 !CERT_LIST_END(node, additional_trust_anchors); | 236 !CERT_LIST_END(node, additional_trust_anchors); |
241 node = CERT_LIST_NEXT(node)) { | 237 node = CERT_LIST_NEXT(node)) { |
(...skipping 30 matching lines...) Expand all Loading... |
272 } | 268 } |
273 if (root) | 269 if (root) |
274 certs.push_back(root); | 270 certs.push_back(root); |
275 | 271 |
276 bool covered = true; | 272 bool covered = true; |
277 | 273 |
278 // We iterate from the root certificate down to the leaf, keeping track of | 274 // We iterate from the root certificate down to the leaf, keeping track of |
279 // the issuer's SPKI at each step. | 275 // the issuer's SPKI at each step. |
280 std::string issuer_spki_hash; | 276 std::string issuer_spki_hash; |
281 for (std::vector<CERTCertificate*>::reverse_iterator i = certs.rbegin(); | 277 for (std::vector<CERTCertificate*>::reverse_iterator i = certs.rbegin(); |
282 i != certs.rend(); ++i) { | 278 i != certs.rend(); |
| 279 ++i) { |
283 CERTCertificate* cert = *i; | 280 CERTCertificate* cert = *i; |
284 | 281 |
285 base::StringPiece der(reinterpret_cast<char*>(cert->derCert.data), | 282 base::StringPiece der(reinterpret_cast<char*>(cert->derCert.data), |
286 cert->derCert.len); | 283 cert->derCert.len); |
287 | 284 |
288 base::StringPiece spki; | 285 base::StringPiece spki; |
289 if (!asn1::ExtractSPKIFromDERCert(der, &spki)) { | 286 if (!asn1::ExtractSPKIFromDERCert(der, &spki)) { |
290 NOTREACHED(); | 287 NOTREACHED(); |
291 covered = false; | 288 covered = false; |
292 continue; | 289 continue; |
293 } | 290 } |
294 const std::string spki_hash = crypto::SHA256HashString(spki); | 291 const std::string spki_hash = crypto::SHA256HashString(spki); |
295 | 292 |
296 base::StringPiece serial_number = base::StringPiece( | 293 base::StringPiece serial_number = |
297 reinterpret_cast<char*>(cert->serialNumber.data), | 294 base::StringPiece(reinterpret_cast<char*>(cert->serialNumber.data), |
298 cert->serialNumber.len); | 295 cert->serialNumber.len); |
299 | 296 |
300 CRLSet::Result result = crl_set->CheckSPKI(spki_hash); | 297 CRLSet::Result result = crl_set->CheckSPKI(spki_hash); |
301 | 298 |
302 if (result != CRLSet::REVOKED && !issuer_spki_hash.empty()) | 299 if (result != CRLSet::REVOKED && !issuer_spki_hash.empty()) |
303 result = crl_set->CheckSerial(serial_number, issuer_spki_hash); | 300 result = crl_set->CheckSerial(serial_number, issuer_spki_hash); |
304 | 301 |
305 issuer_spki_hash = spki_hash; | 302 issuer_spki_hash = spki_hash; |
306 | 303 |
307 switch (result) { | 304 switch (result) { |
308 case CRLSet::REVOKED: | 305 case CRLSet::REVOKED: |
309 return kCRLSetRevoked; | 306 return kCRLSetRevoked; |
310 case CRLSet::UNKNOWN: | 307 case CRLSet::UNKNOWN: |
311 covered = false; | 308 covered = false; |
312 continue; | 309 continue; |
313 case CRLSet::GOOD: | 310 case CRLSet::GOOD: |
314 continue; | 311 continue; |
315 default: | 312 default: |
316 NOTREACHED(); | 313 NOTREACHED(); |
317 covered = false; | 314 covered = false; |
318 continue; | 315 continue; |
319 } | 316 } |
320 } | 317 } |
321 | 318 |
322 if (!covered || crl_set->IsExpired()) | 319 if (!covered || crl_set->IsExpired()) |
323 return kCRLSetUnknown; | 320 return kCRLSetUnknown; |
324 return kCRLSetOk; | 321 return kCRLSetOk; |
325 } | 322 } |
326 | 323 |
327 // Forward declarations. | 324 // Forward declarations. |
328 SECStatus RetryPKIXVerifyCertWithWorkarounds( | 325 SECStatus RetryPKIXVerifyCertWithWorkarounds(CERTCertificate* cert_handle, |
329 CERTCertificate* cert_handle, int num_policy_oids, | 326 int num_policy_oids, |
330 bool cert_io_enabled, std::vector<CERTValInParam>* cvin, | 327 bool cert_io_enabled, |
331 CERTValOutParam* cvout); | 328 std::vector<CERTValInParam>* cvin, |
| 329 CERTValOutParam* cvout); |
332 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle); | 330 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle); |
333 | 331 |
334 // Call CERT_PKIXVerifyCert for the cert_handle. | 332 // Call CERT_PKIXVerifyCert for the cert_handle. |
335 // Verification results are stored in an array of CERTValOutParam. | 333 // Verification results are stored in an array of CERTValOutParam. |
336 // If |hard_fail| is true, and no policy_oids are supplied (eg: EV is NOT being | 334 // If |hard_fail| is true, and no policy_oids are supplied (eg: EV is NOT being |
337 // checked), then the failure to obtain valid CRL/OCSP information for all | 335 // checked), then the failure to obtain valid CRL/OCSP information for all |
338 // certificates that contain CRL/OCSP URLs will cause the certificate to be | 336 // certificates that contain CRL/OCSP URLs will cause the certificate to be |
339 // treated as if it was revoked. Since failures may be caused by transient | 337 // treated as if it was revoked. Since failures may be caused by transient |
340 // network failures or by malicious attackers, in general, hard_fail should be | 338 // network failures or by malicious attackers, in general, hard_fail should be |
341 // false. | 339 // false. |
342 // If policy_oids is not NULL and num_policy_oids is positive, policies | 340 // If policy_oids is not NULL and num_policy_oids is positive, policies |
343 // are also checked. | 341 // are also checked. |
344 // additional_trust_anchors is an optional list of certificates that can be | 342 // additional_trust_anchors is an optional list of certificates that can be |
345 // trusted as anchors when building a certificate chain. | 343 // trusted as anchors when building a certificate chain. |
346 // Caller must initialize cvout before calling this function. | 344 // Caller must initialize cvout before calling this function. |
347 SECStatus PKIXVerifyCert(CERTCertificate* cert_handle, | 345 SECStatus PKIXVerifyCert(CERTCertificate* cert_handle, |
348 bool check_revocation, | 346 bool check_revocation, |
349 bool hard_fail, | 347 bool hard_fail, |
350 bool cert_io_enabled, | 348 bool cert_io_enabled, |
351 const SECOidTag* policy_oids, | 349 const SECOidTag* policy_oids, |
352 int num_policy_oids, | 350 int num_policy_oids, |
353 CERTCertList* additional_trust_anchors, | 351 CERTCertList* additional_trust_anchors, |
354 CERTChainVerifyCallback* chain_verify_callback, | 352 CERTChainVerifyCallback* chain_verify_callback, |
355 CERTValOutParam* cvout) { | 353 CERTValOutParam* cvout) { |
356 bool use_crl = check_revocation; | 354 bool use_crl = check_revocation; |
357 bool use_ocsp = check_revocation; | 355 bool use_ocsp = check_revocation; |
358 | 356 |
359 PRUint64 revocation_method_flags = | 357 PRUint64 revocation_method_flags = CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD | |
360 CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD | | 358 CERT_REV_M_ALLOW_NETWORK_FETCHING | |
361 CERT_REV_M_ALLOW_NETWORK_FETCHING | | 359 CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE | |
362 CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE | | 360 CERT_REV_M_IGNORE_MISSING_FRESH_INFO | |
363 CERT_REV_M_IGNORE_MISSING_FRESH_INFO | | 361 CERT_REV_M_STOP_TESTING_ON_FRESH_INFO; |
364 CERT_REV_M_STOP_TESTING_ON_FRESH_INFO; | |
365 PRUint64 revocation_method_independent_flags = | 362 PRUint64 revocation_method_independent_flags = |
366 CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST; | 363 CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST; |
367 if (check_revocation && policy_oids && num_policy_oids > 0) { | 364 if (check_revocation && policy_oids && num_policy_oids > 0) { |
368 // EV verification requires revocation checking. Consider the certificate | 365 // EV verification requires revocation checking. Consider the certificate |
369 // revoked if we don't have revocation info. | 366 // revoked if we don't have revocation info. |
370 // TODO(wtc): Add a bool parameter to expressly specify we're doing EV | 367 // TODO(wtc): Add a bool parameter to expressly specify we're doing EV |
371 // verification or we want strict revocation flags. | 368 // verification or we want strict revocation flags. |
372 revocation_method_flags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE; | 369 revocation_method_flags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE; |
373 revocation_method_independent_flags |= | 370 revocation_method_independent_flags |= |
374 CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE; | 371 CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
413 | 410 |
414 revocation_flags.chainTests.number_of_defined_methods = | 411 revocation_flags.chainTests.number_of_defined_methods = |
415 arraysize(method_flags); | 412 arraysize(method_flags); |
416 revocation_flags.chainTests.cert_rev_flags_per_method = method_flags; | 413 revocation_flags.chainTests.cert_rev_flags_per_method = method_flags; |
417 revocation_flags.chainTests.number_of_preferred_methods = | 414 revocation_flags.chainTests.number_of_preferred_methods = |
418 arraysize(preferred_revocation_methods); | 415 arraysize(preferred_revocation_methods); |
419 revocation_flags.chainTests.preferred_methods = preferred_revocation_methods; | 416 revocation_flags.chainTests.preferred_methods = preferred_revocation_methods; |
420 revocation_flags.chainTests.cert_rev_method_independent_flags = | 417 revocation_flags.chainTests.cert_rev_method_independent_flags = |
421 revocation_method_independent_flags; | 418 revocation_method_independent_flags; |
422 | 419 |
423 | |
424 std::vector<CERTValInParam> cvin; | 420 std::vector<CERTValInParam> cvin; |
425 cvin.reserve(7); | 421 cvin.reserve(7); |
426 CERTValInParam in_param; | 422 CERTValInParam in_param; |
427 in_param.type = cert_pi_revocationFlags; | 423 in_param.type = cert_pi_revocationFlags; |
428 in_param.value.pointer.revocation = &revocation_flags; | 424 in_param.value.pointer.revocation = &revocation_flags; |
429 cvin.push_back(in_param); | 425 cvin.push_back(in_param); |
430 if (policy_oids && num_policy_oids > 0) { | 426 if (policy_oids && num_policy_oids > 0) { |
431 in_param.type = cert_pi_policyOID; | 427 in_param.type = cert_pi_policyOID; |
432 in_param.value.arraySize = num_policy_oids; | 428 in_param.value.arraySize = num_policy_oids; |
433 in_param.value.array.oids = policy_oids; | 429 in_param.value.array.oids = policy_oids; |
434 cvin.push_back(in_param); | 430 cvin.push_back(in_param); |
435 } | 431 } |
436 if (additional_trust_anchors) { | 432 if (additional_trust_anchors) { |
437 in_param.type = cert_pi_trustAnchors; | 433 in_param.type = cert_pi_trustAnchors; |
438 in_param.value.pointer.chain = additional_trust_anchors; | 434 in_param.value.pointer.chain = additional_trust_anchors; |
439 cvin.push_back(in_param); | 435 cvin.push_back(in_param); |
440 in_param.type = cert_pi_useOnlyTrustAnchors; | 436 in_param.type = cert_pi_useOnlyTrustAnchors; |
441 in_param.value.scalar.b = PR_FALSE; | 437 in_param.value.scalar.b = PR_FALSE; |
442 cvin.push_back(in_param); | 438 cvin.push_back(in_param); |
443 } | 439 } |
444 if (chain_verify_callback) { | 440 if (chain_verify_callback) { |
445 in_param.type = cert_pi_chainVerifyCallback; | 441 in_param.type = cert_pi_chainVerifyCallback; |
446 in_param.value.pointer.chainVerifyCallback = chain_verify_callback; | 442 in_param.value.pointer.chainVerifyCallback = chain_verify_callback; |
447 cvin.push_back(in_param); | 443 cvin.push_back(in_param); |
448 } | 444 } |
449 in_param.type = cert_pi_end; | 445 in_param.type = cert_pi_end; |
450 cvin.push_back(in_param); | 446 cvin.push_back(in_param); |
451 | 447 |
452 SECStatus rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer, | 448 SECStatus rv = CERT_PKIXVerifyCert( |
453 &cvin[0], cvout, NULL); | 449 cert_handle, certificateUsageSSLServer, &cvin[0], cvout, NULL); |
454 if (rv != SECSuccess) { | 450 if (rv != SECSuccess) { |
455 rv = RetryPKIXVerifyCertWithWorkarounds(cert_handle, num_policy_oids, | 451 rv = RetryPKIXVerifyCertWithWorkarounds( |
456 cert_io_enabled, &cvin, cvout); | 452 cert_handle, num_policy_oids, cert_io_enabled, &cvin, cvout); |
457 } | 453 } |
458 return rv; | 454 return rv; |
459 } | 455 } |
460 | 456 |
461 // PKIXVerifyCert calls this function to work around some bugs in | 457 // PKIXVerifyCert calls this function to work around some bugs in |
462 // CERT_PKIXVerifyCert. All the arguments of this function are either the | 458 // CERT_PKIXVerifyCert. All the arguments of this function are either the |
463 // arguments or local variables of PKIXVerifyCert. | 459 // arguments or local variables of PKIXVerifyCert. |
464 SECStatus RetryPKIXVerifyCertWithWorkarounds( | 460 SECStatus RetryPKIXVerifyCertWithWorkarounds(CERTCertificate* cert_handle, |
465 CERTCertificate* cert_handle, int num_policy_oids, | 461 int num_policy_oids, |
466 bool cert_io_enabled, std::vector<CERTValInParam>* cvin, | 462 bool cert_io_enabled, |
467 CERTValOutParam* cvout) { | 463 std::vector<CERTValInParam>* cvin, |
| 464 CERTValOutParam* cvout) { |
468 // We call this function when the first CERT_PKIXVerifyCert call in | 465 // We call this function when the first CERT_PKIXVerifyCert call in |
469 // PKIXVerifyCert failed, so we initialize |rv| to SECFailure. | 466 // PKIXVerifyCert failed, so we initialize |rv| to SECFailure. |
470 SECStatus rv = SECFailure; | 467 SECStatus rv = SECFailure; |
471 int nss_error = PORT_GetError(); | 468 int nss_error = PORT_GetError(); |
472 CERTValInParam in_param; | 469 CERTValInParam in_param; |
473 | 470 |
474 // If we get SEC_ERROR_UNKNOWN_ISSUER, we may be missing an intermediate | 471 // If we get SEC_ERROR_UNKNOWN_ISSUER, we may be missing an intermediate |
475 // CA certificate, so we retry with cert_pi_useAIACertFetch. | 472 // CA certificate, so we retry with cert_pi_useAIACertFetch. |
476 // cert_pi_useAIACertFetch has several bugs in its error handling and | 473 // cert_pi_useAIACertFetch has several bugs in its error handling and |
477 // error reporting (NSS bug 528743), so we don't use it by default. | 474 // error reporting (NSS bug 528743), so we don't use it by default. |
478 // Note: When building a certificate chain, CERT_PKIXVerifyCert may | 475 // Note: When building a certificate chain, CERT_PKIXVerifyCert may |
479 // incorrectly pick a CA certificate with the same subject name as the | 476 // incorrectly pick a CA certificate with the same subject name as the |
480 // missing intermediate CA certificate, and fail with the | 477 // missing intermediate CA certificate, and fail with the |
481 // SEC_ERROR_BAD_SIGNATURE error (NSS bug 524013), so we also retry with | 478 // SEC_ERROR_BAD_SIGNATURE error (NSS bug 524013), so we also retry with |
482 // cert_pi_useAIACertFetch on SEC_ERROR_BAD_SIGNATURE. | 479 // cert_pi_useAIACertFetch on SEC_ERROR_BAD_SIGNATURE. |
483 if (cert_io_enabled && | 480 if (cert_io_enabled && (nss_error == SEC_ERROR_UNKNOWN_ISSUER || |
484 (nss_error == SEC_ERROR_UNKNOWN_ISSUER || | 481 nss_error == SEC_ERROR_BAD_SIGNATURE)) { |
485 nss_error == SEC_ERROR_BAD_SIGNATURE)) { | 482 DCHECK_EQ(cvin->back().type, cert_pi_end); |
486 DCHECK_EQ(cvin->back().type, cert_pi_end); | |
487 cvin->pop_back(); | 483 cvin->pop_back(); |
488 in_param.type = cert_pi_useAIACertFetch; | 484 in_param.type = cert_pi_useAIACertFetch; |
489 in_param.value.scalar.b = PR_TRUE; | 485 in_param.value.scalar.b = PR_TRUE; |
490 cvin->push_back(in_param); | 486 cvin->push_back(in_param); |
491 in_param.type = cert_pi_end; | 487 in_param.type = cert_pi_end; |
492 cvin->push_back(in_param); | 488 cvin->push_back(in_param); |
493 rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer, | 489 rv = CERT_PKIXVerifyCert( |
494 &(*cvin)[0], cvout, NULL); | 490 cert_handle, certificateUsageSSLServer, &(*cvin)[0], cvout, NULL); |
495 if (rv == SECSuccess) | 491 if (rv == SECSuccess) |
496 return rv; | 492 return rv; |
497 int new_nss_error = PORT_GetError(); | 493 int new_nss_error = PORT_GetError(); |
498 if (new_nss_error == SEC_ERROR_INVALID_ARGS || | 494 if (new_nss_error == SEC_ERROR_INVALID_ARGS || |
499 new_nss_error == SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE || | 495 new_nss_error == SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE || |
500 new_nss_error == SEC_ERROR_BAD_INFO_ACCESS_LOCATION || | 496 new_nss_error == SEC_ERROR_BAD_INFO_ACCESS_LOCATION || |
501 new_nss_error == SEC_ERROR_BAD_HTTP_RESPONSE || | 497 new_nss_error == SEC_ERROR_BAD_HTTP_RESPONSE || |
502 new_nss_error == SEC_ERROR_BAD_LDAP_RESPONSE || | 498 new_nss_error == SEC_ERROR_BAD_LDAP_RESPONSE || |
503 !IS_SEC_ERROR(new_nss_error)) { | 499 !IS_SEC_ERROR(new_nss_error)) { |
504 // Use the original error code because of cert_pi_useAIACertFetch's | 500 // Use the original error code because of cert_pi_useAIACertFetch's |
505 // bad error reporting. | 501 // bad error reporting. |
506 PORT_SetError(nss_error); | 502 PORT_SetError(nss_error); |
507 return rv; | 503 return rv; |
508 } | 504 } |
509 nss_error = new_nss_error; | 505 nss_error = new_nss_error; |
510 } | 506 } |
511 | 507 |
512 // If an intermediate CA certificate has requireExplicitPolicy in its | 508 // If an intermediate CA certificate has requireExplicitPolicy in its |
513 // policyConstraints extension, CERT_PKIXVerifyCert fails with | 509 // policyConstraints extension, CERT_PKIXVerifyCert fails with |
514 // SEC_ERROR_POLICY_VALIDATION_FAILED because we didn't specify any | 510 // SEC_ERROR_POLICY_VALIDATION_FAILED because we didn't specify any |
515 // certificate policy (NSS bug 552775). So we retry with the certificate | 511 // certificate policy (NSS bug 552775). So we retry with the certificate |
516 // policy found in the server certificate. | 512 // policy found in the server certificate. |
517 if (nss_error == SEC_ERROR_POLICY_VALIDATION_FAILED && | 513 if (nss_error == SEC_ERROR_POLICY_VALIDATION_FAILED && num_policy_oids == 0) { |
518 num_policy_oids == 0) { | |
519 SECOidTag policy = GetFirstCertPolicy(cert_handle); | 514 SECOidTag policy = GetFirstCertPolicy(cert_handle); |
520 if (policy != SEC_OID_UNKNOWN) { | 515 if (policy != SEC_OID_UNKNOWN) { |
521 DCHECK_EQ(cvin->back().type, cert_pi_end); | 516 DCHECK_EQ(cvin->back().type, cert_pi_end); |
522 cvin->pop_back(); | 517 cvin->pop_back(); |
523 in_param.type = cert_pi_policyOID; | 518 in_param.type = cert_pi_policyOID; |
524 in_param.value.arraySize = 1; | 519 in_param.value.arraySize = 1; |
525 in_param.value.array.oids = &policy; | 520 in_param.value.array.oids = &policy; |
526 cvin->push_back(in_param); | 521 cvin->push_back(in_param); |
527 in_param.type = cert_pi_end; | 522 in_param.type = cert_pi_end; |
528 cvin->push_back(in_param); | 523 cvin->push_back(in_param); |
529 rv = CERT_PKIXVerifyCert(cert_handle, certificateUsageSSLServer, | 524 rv = CERT_PKIXVerifyCert( |
530 &(*cvin)[0], cvout, NULL); | 525 cert_handle, certificateUsageSSLServer, &(*cvin)[0], cvout, NULL); |
531 if (rv != SECSuccess) { | 526 if (rv != SECSuccess) { |
532 // Use the original error code. | 527 // Use the original error code. |
533 PORT_SetError(nss_error); | 528 PORT_SetError(nss_error); |
534 } | 529 } |
535 } | 530 } |
536 } | 531 } |
537 | 532 |
538 return rv; | 533 return rv; |
539 } | 534 } |
540 | 535 |
541 // Decodes the certificatePolicies extension of the certificate. Returns | 536 // Decodes the certificatePolicies extension of the certificate. Returns |
542 // NULL if the certificate doesn't have the extension or the extension can't | 537 // NULL if the certificate doesn't have the extension or the extension can't |
543 // be decoded. The returned value must be freed with a | 538 // be decoded. The returned value must be freed with a |
544 // CERT_DestroyCertificatePoliciesExtension call. | 539 // CERT_DestroyCertificatePoliciesExtension call. |
545 CERTCertificatePolicies* DecodeCertPolicies( | 540 CERTCertificatePolicies* DecodeCertPolicies(CERTCertificate* cert_handle) { |
546 CERTCertificate* cert_handle) { | |
547 SECItem policy_ext; | 541 SECItem policy_ext; |
548 SECStatus rv = CERT_FindCertExtension(cert_handle, | 542 SECStatus rv = CERT_FindCertExtension( |
549 SEC_OID_X509_CERTIFICATE_POLICIES, | 543 cert_handle, SEC_OID_X509_CERTIFICATE_POLICIES, &policy_ext); |
550 &policy_ext); | |
551 if (rv != SECSuccess) | 544 if (rv != SECSuccess) |
552 return NULL; | 545 return NULL; |
553 CERTCertificatePolicies* policies = | 546 CERTCertificatePolicies* policies = |
554 CERT_DecodeCertificatePoliciesExtension(&policy_ext); | 547 CERT_DecodeCertificatePoliciesExtension(&policy_ext); |
555 SECITEM_FreeItem(&policy_ext, PR_FALSE); | 548 SECITEM_FreeItem(&policy_ext, PR_FALSE); |
556 return policies; | 549 return policies; |
557 } | 550 } |
558 | 551 |
559 // Returns the OID tag for the first certificate policy in the certificate's | 552 // Returns the OID tag for the first certificate policy in the certificate's |
560 // certificatePolicies extension. Returns SEC_OID_UNKNOWN if the certificate | 553 // certificatePolicies extension. Returns SEC_OID_UNKNOWN if the certificate |
(...skipping 22 matching lines...) Expand all Loading... |
583 od.mechanism = CKM_INVALID_MECHANISM; | 576 od.mechanism = CKM_INVALID_MECHANISM; |
584 od.supportedExtension = INVALID_CERT_EXTENSION; | 577 od.supportedExtension = INVALID_CERT_EXTENSION; |
585 return SECOID_AddEntry(&od); | 578 return SECOID_AddEntry(&od); |
586 } | 579 } |
587 | 580 |
588 HashValue CertPublicKeyHashSHA1(CERTCertificate* cert) { | 581 HashValue CertPublicKeyHashSHA1(CERTCertificate* cert) { |
589 HashValue hash(HASH_VALUE_SHA1); | 582 HashValue hash(HASH_VALUE_SHA1); |
590 #if defined(OS_IOS) | 583 #if defined(OS_IOS) |
591 CC_SHA1(cert->derPublicKey.data, cert->derPublicKey.len, hash.data()); | 584 CC_SHA1(cert->derPublicKey.data, cert->derPublicKey.len, hash.data()); |
592 #else | 585 #else |
593 SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, hash.data(), | 586 SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, |
594 cert->derPublicKey.data, cert->derPublicKey.len); | 587 hash.data(), |
| 588 cert->derPublicKey.data, |
| 589 cert->derPublicKey.len); |
595 DCHECK_EQ(SECSuccess, rv); | 590 DCHECK_EQ(SECSuccess, rv); |
596 #endif | 591 #endif |
597 return hash; | 592 return hash; |
598 } | 593 } |
599 | 594 |
600 HashValue CertPublicKeyHashSHA256(CERTCertificate* cert) { | 595 HashValue CertPublicKeyHashSHA256(CERTCertificate* cert) { |
601 HashValue hash(HASH_VALUE_SHA256); | 596 HashValue hash(HASH_VALUE_SHA256); |
602 #if defined(OS_IOS) | 597 #if defined(OS_IOS) |
603 CC_SHA256(cert->derPublicKey.data, cert->derPublicKey.len, hash.data()); | 598 CC_SHA256(cert->derPublicKey.data, cert->derPublicKey.len, hash.data()); |
604 #else | 599 #else |
605 SECStatus rv = HASH_HashBuf(HASH_AlgSHA256, hash.data(), | 600 SECStatus rv = HASH_HashBuf(HASH_AlgSHA256, |
606 cert->derPublicKey.data, cert->derPublicKey.len); | 601 hash.data(), |
| 602 cert->derPublicKey.data, |
| 603 cert->derPublicKey.len); |
607 DCHECK_EQ(rv, SECSuccess); | 604 DCHECK_EQ(rv, SECSuccess); |
608 #endif | 605 #endif |
609 return hash; | 606 return hash; |
610 } | 607 } |
611 | 608 |
612 void AppendPublicKeyHashes(CERTCertList* cert_list, | 609 void AppendPublicKeyHashes(CERTCertList* cert_list, |
613 CERTCertificate* root_cert, | 610 CERTCertificate* root_cert, |
614 HashValueVector* hashes) { | 611 HashValueVector* hashes) { |
615 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); | 612 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); |
616 !CERT_LIST_END(node, cert_list); | 613 !CERT_LIST_END(node, cert_list); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
674 cvout[cvout_index].value.pointer.chain = NULL; | 671 cvout[cvout_index].value.pointer.chain = NULL; |
675 int cvout_cert_list_index = cvout_index; | 672 int cvout_cert_list_index = cvout_index; |
676 cvout_index++; | 673 cvout_index++; |
677 cvout[cvout_index].type = cert_po_trustAnchor; | 674 cvout[cvout_index].type = cert_po_trustAnchor; |
678 cvout[cvout_index].value.pointer.cert = NULL; | 675 cvout[cvout_index].value.pointer.cert = NULL; |
679 int cvout_trust_anchor_index = cvout_index; | 676 int cvout_trust_anchor_index = cvout_index; |
680 cvout_index++; | 677 cvout_index++; |
681 cvout[cvout_index].type = cert_po_end; | 678 cvout[cvout_index].type = cert_po_end; |
682 ScopedCERTValOutParam scoped_cvout(cvout); | 679 ScopedCERTValOutParam scoped_cvout(cvout); |
683 | 680 |
684 SECStatus status = PKIXVerifyCert( | 681 SECStatus status = |
685 cert_handle, | 682 PKIXVerifyCert(cert_handle, |
686 rev_checking_enabled, | 683 rev_checking_enabled, |
687 true, /* hard fail is implied in EV. */ | 684 true, /* hard fail is implied in EV. */ |
688 flags & CertVerifier::VERIFY_CERT_IO_ENABLED, | 685 flags & CertVerifier::VERIFY_CERT_IO_ENABLED, |
689 &ev_policy_oid, | 686 &ev_policy_oid, |
690 1, | 687 1, |
691 additional_trust_anchors, | 688 additional_trust_anchors, |
692 chain_verify_callback, | 689 chain_verify_callback, |
693 cvout); | 690 cvout); |
694 if (status != SECSuccess) | 691 if (status != SECSuccess) |
695 return false; | 692 return false; |
696 | 693 |
697 CERTCertificate* root_ca = | 694 CERTCertificate* root_ca = cvout[cvout_trust_anchor_index].value.pointer.cert; |
698 cvout[cvout_trust_anchor_index].value.pointer.cert; | |
699 if (root_ca == NULL) | 695 if (root_ca == NULL) |
700 return false; | 696 return false; |
701 | 697 |
702 // This second PKIXVerifyCert call could have found a different certification | 698 // 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 | 699 // path and one or more of the certificates on this new path, that weren't on |
704 // the old path, might have been revoked. | 700 // the old path, might have been revoked. |
705 if (crl_set) { | 701 if (crl_set) { |
706 CRLSetResult crl_set_result = CheckRevocationWithCRLSet( | 702 CRLSetResult crl_set_result = CheckRevocationWithCRLSet( |
707 cvout[cvout_cert_list_index].value.pointer.chain, | 703 cvout[cvout_cert_list_index].value.pointer.chain, |
708 cvout[cvout_trust_anchor_index].value.pointer.cert, | 704 cvout[cvout_trust_anchor_index].value.pointer.cert, |
709 crl_set); | 705 crl_set); |
710 if (crl_set_result == kCRLSetRevoked) | 706 if (crl_set_result == kCRLSetRevoked) |
711 return false; | 707 return false; |
712 } | 708 } |
713 | 709 |
714 #if defined(OS_IOS) | 710 #if defined(OS_IOS) |
715 SHA1HashValue fingerprint = x509_util_ios::CalculateFingerprintNSS(root_ca); | 711 SHA1HashValue fingerprint = x509_util_ios::CalculateFingerprintNSS(root_ca); |
716 #else | 712 #else |
717 SHA1HashValue fingerprint = | 713 SHA1HashValue fingerprint = X509Certificate::CalculateFingerprint(root_ca); |
718 X509Certificate::CalculateFingerprint(root_ca); | |
719 #endif | 714 #endif |
720 return metadata->HasEVPolicyOID(fingerprint, ev_policy_oid); | 715 return metadata->HasEVPolicyOID(fingerprint, ev_policy_oid); |
721 } | 716 } |
722 | 717 |
723 CERTCertList* CertificateListToCERTCertList(const CertificateList& list) { | 718 CERTCertList* CertificateListToCERTCertList(const CertificateList& list) { |
724 CERTCertList* result = CERT_NewCertList(); | 719 CERTCertList* result = CERT_NewCertList(); |
725 for (size_t i = 0; i < list.size(); ++i) { | 720 for (size_t i = 0; i < list.size(); ++i) { |
726 #if defined(OS_IOS) | 721 #if defined(OS_IOS) |
727 // X509Certificate::os_cert_handle() on iOS is a SecCertificateRef; convert | 722 // X509Certificate::os_cert_handle() on iOS is a SecCertificateRef; convert |
728 // it to an NSS CERTCertificate. | 723 // it to an NSS CERTCertificate. |
729 CERTCertificate* cert = x509_util_ios::CreateNSSCertHandleFromOSHandle( | 724 CERTCertificate* cert = x509_util_ios::CreateNSSCertHandleFromOSHandle( |
730 list[i]->os_cert_handle()); | 725 list[i]->os_cert_handle()); |
731 #else | 726 #else |
732 CERTCertificate* cert = list[i]->os_cert_handle(); | 727 CERTCertificate* cert = list[i]->os_cert_handle(); |
733 #endif | 728 #endif |
734 CERT_AddCertToListTail(result, CERT_DupCertificate(cert)); | 729 CERT_AddCertToListTail(result, CERT_DupCertificate(cert)); |
735 } | 730 } |
736 return result; | 731 return result; |
737 } | 732 } |
738 | 733 |
739 } // namespace | 734 } // namespace |
740 | 735 |
741 CertVerifyProcNSS::CertVerifyProcNSS() {} | 736 CertVerifyProcNSS::CertVerifyProcNSS() { |
| 737 } |
742 | 738 |
743 CertVerifyProcNSS::~CertVerifyProcNSS() {} | 739 CertVerifyProcNSS::~CertVerifyProcNSS() { |
| 740 } |
744 | 741 |
745 bool CertVerifyProcNSS::SupportsAdditionalTrustAnchors() const { | 742 bool CertVerifyProcNSS::SupportsAdditionalTrustAnchors() const { |
746 return true; | 743 return true; |
747 } | 744 } |
748 | 745 |
749 int CertVerifyProcNSS::VerifyInternalImpl( | 746 int CertVerifyProcNSS::VerifyInternalImpl( |
750 X509Certificate* cert, | 747 X509Certificate* cert, |
751 const std::string& hostname, | 748 const std::string& hostname, |
752 int flags, | 749 int flags, |
753 CRLSet* crl_set, | 750 CRLSet* crl_set, |
754 const CertificateList& additional_trust_anchors, | 751 const CertificateList& additional_trust_anchors, |
755 CERTChainVerifyCallback* chain_verify_callback, | 752 CERTChainVerifyCallback* chain_verify_callback, |
756 CertVerifyResult* verify_result) { | 753 CertVerifyResult* verify_result) { |
757 #if defined(OS_IOS) | 754 #if defined(OS_IOS) |
758 // For iOS, the entire chain must be loaded into NSS's in-memory certificate | 755 // For iOS, the entire chain must be loaded into NSS's in-memory certificate |
759 // store. | 756 // store. |
760 x509_util_ios::NSSCertChain scoped_chain(cert); | 757 x509_util_ios::NSSCertChain scoped_chain(cert); |
761 CERTCertificate* cert_handle = scoped_chain.cert_handle(); | 758 CERTCertificate* cert_handle = scoped_chain.cert_handle(); |
762 #else | 759 #else |
763 CERTCertificate* cert_handle = cert->os_cert_handle(); | 760 CERTCertificate* cert_handle = cert->os_cert_handle(); |
764 #endif // defined(OS_IOS) | 761 #endif // defined(OS_IOS) |
765 | 762 |
766 if (!cert->VerifyNameMatch(hostname, | 763 if (!cert->VerifyNameMatch(hostname, |
767 &verify_result->common_name_fallback_used)) { | 764 &verify_result->common_name_fallback_used)) { |
768 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | 765 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; |
769 } | 766 } |
770 | 767 |
771 // Make sure that the cert is valid now. | 768 // Make sure that the cert is valid now. |
772 SECCertTimeValidity validity = CERT_CheckCertValidTimes( | 769 SECCertTimeValidity validity = |
773 cert_handle, PR_Now(), PR_TRUE); | 770 CERT_CheckCertValidTimes(cert_handle, PR_Now(), PR_TRUE); |
774 if (validity != secCertTimeValid) | 771 if (validity != secCertTimeValid) |
775 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; | 772 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; |
776 | 773 |
777 CERTValOutParam cvout[3]; | 774 CERTValOutParam cvout[3]; |
778 int cvout_index = 0; | 775 int cvout_index = 0; |
779 cvout[cvout_index].type = cert_po_certList; | 776 cvout[cvout_index].type = cert_po_certList; |
780 cvout[cvout_index].value.pointer.chain = NULL; | 777 cvout[cvout_index].value.pointer.chain = NULL; |
781 int cvout_cert_list_index = cvout_index; | 778 int cvout_cert_list_index = cvout_index; |
782 cvout_index++; | 779 cvout_index++; |
783 cvout[cvout_index].type = cert_po_trustAnchor; | 780 cvout[cvout_index].type = cert_po_trustAnchor; |
784 cvout[cvout_index].value.pointer.cert = NULL; | 781 cvout[cvout_index].value.pointer.cert = NULL; |
785 int cvout_trust_anchor_index = cvout_index; | 782 int cvout_trust_anchor_index = cvout_index; |
786 cvout_index++; | 783 cvout_index++; |
787 cvout[cvout_index].type = cert_po_end; | 784 cvout[cvout_index].type = cert_po_end; |
788 ScopedCERTValOutParam scoped_cvout(cvout); | 785 ScopedCERTValOutParam scoped_cvout(cvout); |
789 | 786 |
790 EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance(); | 787 EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance(); |
791 SECOidTag ev_policy_oid = SEC_OID_UNKNOWN; | 788 SECOidTag ev_policy_oid = SEC_OID_UNKNOWN; |
792 bool is_ev_candidate = | 789 bool is_ev_candidate = (flags & CertVerifier::VERIFY_EV_CERT) && |
793 (flags & CertVerifier::VERIFY_EV_CERT) && | 790 IsEVCandidate(metadata, cert_handle, &ev_policy_oid); |
794 IsEVCandidate(metadata, cert_handle, &ev_policy_oid); | |
795 bool cert_io_enabled = flags & CertVerifier::VERIFY_CERT_IO_ENABLED; | 791 bool cert_io_enabled = flags & CertVerifier::VERIFY_CERT_IO_ENABLED; |
796 bool check_revocation = | 792 bool check_revocation = |
797 cert_io_enabled && | 793 cert_io_enabled && (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED); |
798 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED); | |
799 if (check_revocation) | 794 if (check_revocation) |
800 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 795 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
801 | 796 |
802 ScopedCERTCertList trust_anchors; | 797 ScopedCERTCertList trust_anchors; |
803 if (!additional_trust_anchors.empty()) { | 798 if (!additional_trust_anchors.empty()) { |
804 trust_anchors.reset( | 799 trust_anchors.reset( |
805 CertificateListToCERTCertList(additional_trust_anchors)); | 800 CertificateListToCERTCertList(additional_trust_anchors)); |
806 } | 801 } |
807 | 802 |
808 SECStatus status = PKIXVerifyCert(cert_handle, | 803 SECStatus status = PKIXVerifyCert(cert_handle, |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
879 } | 874 } |
880 // |err| is not a certificate error. | 875 // |err| is not a certificate error. |
881 return MapSecurityError(err); | 876 return MapSecurityError(err); |
882 } | 877 } |
883 | 878 |
884 if (IsCertStatusError(verify_result->cert_status)) | 879 if (IsCertStatusError(verify_result->cert_status)) |
885 return MapCertStatusToNetError(verify_result->cert_status); | 880 return MapCertStatusToNetError(verify_result->cert_status); |
886 | 881 |
887 if ((flags & CertVerifier::VERIFY_EV_CERT) && is_ev_candidate) { | 882 if ((flags & CertVerifier::VERIFY_EV_CERT) && is_ev_candidate) { |
888 check_revocation |= | 883 check_revocation |= |
889 crl_set_result != kCRLSetOk && | 884 crl_set_result != kCRLSetOk && cert_io_enabled && |
890 cert_io_enabled && | |
891 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY); | 885 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY); |
892 if (check_revocation) | 886 if (check_revocation) |
893 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 887 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
894 | 888 |
895 if (VerifyEV(cert_handle, | 889 if (VerifyEV(cert_handle, |
896 flags, | 890 flags, |
897 crl_set, | 891 crl_set, |
898 check_revocation, | 892 check_revocation, |
899 metadata, | 893 metadata, |
900 ev_policy_oid, | 894 ev_policy_oid, |
(...skipping 16 matching lines...) Expand all Loading... |
917 return VerifyInternalImpl(cert, | 911 return VerifyInternalImpl(cert, |
918 hostname, | 912 hostname, |
919 flags, | 913 flags, |
920 crl_set, | 914 crl_set, |
921 additional_trust_anchors, | 915 additional_trust_anchors, |
922 NULL, // chain_verify_callback | 916 NULL, // chain_verify_callback |
923 verify_result); | 917 verify_result); |
924 } | 918 } |
925 | 919 |
926 } // namespace net | 920 } // namespace net |
OLD | NEW |