| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/base/x509_certificate.h" | 5 #include "net/base/x509_certificate.h" |
| 6 | 6 |
| 7 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424 | 7 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424 |
| 8 // until NSS 3.12.2 comes out and we update to it. | 8 // until NSS 3.12.2 comes out and we update to it. |
| 9 #define Lock FOO_NSS_Lock | 9 #define Lock FOO_NSS_Lock |
| 10 #include <cert.h> | 10 #include <cert.h> |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 53 if (cert_list_) | 53 if (cert_list_) |
| 54 CERT_DestroyCertList(cert_list_); | 54 CERT_DestroyCertList(cert_list_); |
| 55 } | 55 } |
| 56 | 56 |
| 57 private: | 57 private: |
| 58 CERTCertList* cert_list_; | 58 CERTCertList* cert_list_; |
| 59 | 59 |
| 60 DISALLOW_COPY_AND_ASSIGN(ScopedCERTCertList); | 60 DISALLOW_COPY_AND_ASSIGN(ScopedCERTCertList); |
| 61 }; | 61 }; |
| 62 | 62 |
| 63 class ScopedCERTCertificatePolicies { |
| 64 public: |
| 65 explicit ScopedCERTCertificatePolicies(CERTCertificatePolicies* policies) |
| 66 : policies_(policies) {} |
| 67 |
| 68 ~ScopedCERTCertificatePolicies() { |
| 69 if (policies_) |
| 70 CERT_DestroyCertificatePoliciesExtension(policies_); |
| 71 } |
| 72 |
| 73 private: |
| 74 CERTCertificatePolicies* policies_; |
| 75 |
| 76 DISALLOW_COPY_AND_ASSIGN(ScopedCERTCertificatePolicies); |
| 77 }; |
| 78 |
| 63 // ScopedCERTValOutParam manages destruction of values in the CERTValOutParam | 79 // ScopedCERTValOutParam manages destruction of values in the CERTValOutParam |
| 64 // array that cvout points to. cvout must be initialized as passed to | 80 // array that cvout points to. cvout must be initialized as passed to |
| 65 // CERT_PKIXVerifyCert, so that the array must be terminated with | 81 // CERT_PKIXVerifyCert, so that the array must be terminated with |
| 66 // cert_po_end type. | 82 // cert_po_end type. |
| 67 // When it goes out of scope, it destroys values of cert_po_trustAnchor | 83 // When it goes out of scope, it destroys values of cert_po_trustAnchor |
| 68 // and cert_po_certList types, but doesn't release the array itself. | 84 // and cert_po_certList types, but doesn't release the array itself. |
| 69 class ScopedCERTValOutParam { | 85 class ScopedCERTValOutParam { |
| 70 public: | 86 public: |
| 71 explicit ScopedCERTValOutParam(CERTValOutParam* cvout) | 87 explicit ScopedCERTValOutParam(CERTValOutParam* cvout) |
| 72 : cvout_(cvout) {} | 88 : cvout_(cvout) {} |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 324 // 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 |
| 325 // are also checked. | 341 // are also checked. |
| 326 // Caller must initialize cvout before calling this function. | 342 // Caller must initialize cvout before calling this function. |
| 327 SECStatus PKIXVerifyCert(X509Certificate::OSCertHandle cert_handle, | 343 SECStatus PKIXVerifyCert(X509Certificate::OSCertHandle cert_handle, |
| 328 const SECOidTag* policy_oids, | 344 const SECOidTag* policy_oids, |
| 329 int num_policy_oids, | 345 int num_policy_oids, |
| 330 CERTValOutParam* cvout) { | 346 CERTValOutParam* cvout) { |
| 331 PRUint64 revocation_method_flags = | 347 PRUint64 revocation_method_flags = |
| 332 CERT_REV_M_TEST_USING_THIS_METHOD | | 348 CERT_REV_M_TEST_USING_THIS_METHOD | |
| 333 CERT_REV_M_ALLOW_NETWORK_FETCHING | | 349 CERT_REV_M_ALLOW_NETWORK_FETCHING | |
| 334 CERT_REV_M_ALLOW_IMPLICIT_DEFAULT_SOURCE | | 350 CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE | |
| 351 CERT_REV_M_IGNORE_MISSING_FRESH_INFO | |
| 335 CERT_REV_M_STOP_TESTING_ON_FRESH_INFO; | 352 CERT_REV_M_STOP_TESTING_ON_FRESH_INFO; |
| 336 PRUint64 revocation_method_independent_flags = | 353 PRUint64 revocation_method_independent_flags = |
| 337 CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST; | 354 CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST; |
| 338 if (policy_oids && num_policy_oids > 0) { | 355 if (policy_oids && num_policy_oids > 0) { |
| 339 // EV verification requires revocation checking. Consider the certificate | 356 // EV verification requires revocation checking. Consider the certificate |
| 340 // revoked if we don't have revocation info. | 357 // revoked if we don't have revocation info. |
| 341 // TODO(wtc): Add a bool parameter to expressly specify we're doing EV | 358 // TODO(wtc): Add a bool parameter to expressly specify we're doing EV |
| 342 // verification or we want strict revocation flags. | 359 // verification or we want strict revocation flags. |
| 343 revocation_method_flags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE; | 360 revocation_method_flags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE; |
| 344 revocation_method_independent_flags |= | 361 revocation_method_independent_flags |= |
| 345 CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE; | 362 CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE; |
| 346 } else { | 363 } else { |
| 347 revocation_method_flags |= CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE; | 364 revocation_method_flags |= CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE; |
| 348 revocation_method_independent_flags |= | 365 revocation_method_independent_flags |= |
| 349 CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT; | 366 CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT; |
| 350 } | 367 } |
| 351 PRUint64 method_flags[2]; | 368 PRUint64 method_flags[2]; |
| 352 method_flags[cert_revocation_method_crl] = revocation_method_flags; | 369 method_flags[cert_revocation_method_crl] = revocation_method_flags; |
| 353 method_flags[cert_revocation_method_ocsp] = revocation_method_flags; | 370 method_flags[cert_revocation_method_ocsp] = revocation_method_flags; |
| 354 | 371 |
| 355 // TODO(ukai): need to find out if we need to call OCSP-related NSS functions, | |
| 356 // CERT_EnableOCSPChecking, CERT_DisableOCSPDefaultResponder and | |
| 357 // CERT_SetOCSPFailureMode. | |
| 358 CERTRevocationMethodIndex preferred_revocation_methods[1]; | 372 CERTRevocationMethodIndex preferred_revocation_methods[1]; |
| 359 preferred_revocation_methods[0] = cert_revocation_method_ocsp; | 373 preferred_revocation_methods[0] = cert_revocation_method_ocsp; |
| 360 | 374 |
| 361 CERTRevocationFlags revocation_flags; | 375 CERTRevocationFlags revocation_flags; |
| 362 revocation_flags.leafTests.number_of_defined_methods = | 376 revocation_flags.leafTests.number_of_defined_methods = |
| 363 arraysize(method_flags); | 377 arraysize(method_flags); |
| 364 revocation_flags.leafTests.cert_rev_flags_per_method = method_flags; | 378 revocation_flags.leafTests.cert_rev_flags_per_method = method_flags; |
| 365 revocation_flags.leafTests.number_of_preferred_methods = | 379 revocation_flags.leafTests.number_of_preferred_methods = |
| 366 arraysize(preferred_revocation_methods); | 380 arraysize(preferred_revocation_methods); |
| 367 revocation_flags.leafTests.preferred_methods = preferred_revocation_methods; | 381 revocation_flags.leafTests.preferred_methods = preferred_revocation_methods; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 if (rv != SECSuccess) { | 419 if (rv != SECSuccess) { |
| 406 LOG(ERROR) << "Cert has no policies extension."; | 420 LOG(ERROR) << "Cert has no policies extension."; |
| 407 return false; | 421 return false; |
| 408 } | 422 } |
| 409 CERTCertificatePolicies* policies = | 423 CERTCertificatePolicies* policies = |
| 410 CERT_DecodeCertificatePoliciesExtension(&policy_ext); | 424 CERT_DecodeCertificatePoliciesExtension(&policy_ext); |
| 411 if (!policies) { | 425 if (!policies) { |
| 412 LOG(ERROR) << "Failed to decode certificate policy."; | 426 LOG(ERROR) << "Failed to decode certificate policy."; |
| 413 return false; | 427 return false; |
| 414 } | 428 } |
| 429 ScopedCERTCertificatePolicies scoped_policies(policies); |
| 415 CERTPolicyInfo** policy_infos = policies->policyInfos; | 430 CERTPolicyInfo** policy_infos = policies->policyInfos; |
| 416 while (*policy_infos != NULL) { | 431 while (*policy_infos != NULL) { |
| 417 CERTPolicyInfo* policy_info = *policy_infos++; | 432 CERTPolicyInfo* policy_info = *policy_infos++; |
| 418 SECOidTag oid_tag = policy_info->oid; | 433 SECOidTag oid_tag = policy_info->oid; |
| 419 if (oid_tag == SEC_OID_UNKNOWN) | 434 if (oid_tag == SEC_OID_UNKNOWN) |
| 420 continue; | 435 continue; |
| 421 if (oid_tag == ev_policy_tag) | 436 if (oid_tag == ev_policy_tag) |
| 422 return true; | 437 return true; |
| 423 } | 438 } |
| 424 LOG(ERROR) << "No EV Policy Tag"; | 439 LOG(ERROR) << "No EV Policy Tag"; |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 515 if (IsCertStatusError(verify_result->cert_status)) | 530 if (IsCertStatusError(verify_result->cert_status)) |
| 516 return MapCertStatusToNetError(verify_result->cert_status); | 531 return MapCertStatusToNetError(verify_result->cert_status); |
| 517 | 532 |
| 518 if ((flags & VERIFY_EV_CERT) && VerifyEV()) | 533 if ((flags & VERIFY_EV_CERT) && VerifyEV()) |
| 519 verify_result->cert_status |= CERT_STATUS_IS_EV; | 534 verify_result->cert_status |= CERT_STATUS_IS_EV; |
| 520 return OK; | 535 return OK; |
| 521 } | 536 } |
| 522 | 537 |
| 523 // Studied Mozilla's code (esp. security/manager/ssl/src/nsIdentityChecking.cpp | 538 // Studied Mozilla's code (esp. security/manager/ssl/src/nsIdentityChecking.cpp |
| 524 // and nsNSSCertHelper.cpp) to learn how to verify EV certificate. | 539 // and nsNSSCertHelper.cpp) to learn how to verify EV certificate. |
| 525 // TODO(wtc): We may be able to request cert_po_policyOID and just | 540 // TODO(wtc): A possible optimization is that we get the trust anchor from |
| 526 // check if any of the returned policies is the EV policy of the trust anchor. | |
| 527 // Another possible optimization is that we get the trust anchor from | |
| 528 // the first PKIXVerifyCert call. We look up the EV policy for the trust | 541 // the first PKIXVerifyCert call. We look up the EV policy for the trust |
| 529 // anchor. If the trust anchor has no EV policy, we know the cert isn't EV. | 542 // anchor. If the trust anchor has no EV policy, we know the cert isn't EV. |
| 530 // Otherwise, we pass just that EV policy (as opposed to all the EV policies) | 543 // Otherwise, we pass just that EV policy (as opposed to all the EV policies) |
| 531 // to the second PKIXVerifyCert call. | 544 // to the second PKIXVerifyCert call. |
| 532 bool X509Certificate::VerifyEV() const { | 545 bool X509Certificate::VerifyEV() const { |
| 533 net::EVRootCAMetadata* metadata = net::EVRootCAMetadata::GetInstance(); | 546 net::EVRootCAMetadata* metadata = net::EVRootCAMetadata::GetInstance(); |
| 534 | 547 |
| 535 CERTValOutParam cvout[3]; | 548 CERTValOutParam cvout[3]; |
| 536 int cvout_index = 0; | 549 int cvout_index = 0; |
| 537 cvout[cvout_index].type = cert_po_trustAnchor; | 550 cvout[cvout_index].type = cert_po_trustAnchor; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 591 DCHECK(0 != cert->derCert.len); | 604 DCHECK(0 != cert->derCert.len); |
| 592 | 605 |
| 593 SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, sha1.data, | 606 SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, sha1.data, |
| 594 cert->derCert.data, cert->derCert.len); | 607 cert->derCert.data, cert->derCert.len); |
| 595 DCHECK(rv == SECSuccess); | 608 DCHECK(rv == SECSuccess); |
| 596 | 609 |
| 597 return sha1; | 610 return sha1; |
| 598 } | 611 } |
| 599 | 612 |
| 600 } // namespace net | 613 } // namespace net |
| OLD | NEW |