| 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/base/cert_verify_proc_nss.h" | 5 #include "net/base/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 10 matching lines...) Expand all Loading... |
| 21 #include "net/base/asn1_util.h" | 21 #include "net/base/asn1_util.h" |
| 22 #include "net/base/cert_status_flags.h" | 22 #include "net/base/cert_status_flags.h" |
| 23 #include "net/base/cert_verifier.h" | 23 #include "net/base/cert_verifier.h" |
| 24 #include "net/base/cert_verify_result.h" | 24 #include "net/base/cert_verify_result.h" |
| 25 #include "net/base/crl_set.h" | 25 #include "net/base/crl_set.h" |
| 26 #include "net/base/ev_root_ca_metadata.h" | 26 #include "net/base/ev_root_ca_metadata.h" |
| 27 #include "net/base/net_errors.h" | 27 #include "net/base/net_errors.h" |
| 28 #include "net/base/x509_certificate.h" | 28 #include "net/base/x509_certificate.h" |
| 29 #include "net/base/x509_util_nss.h" | 29 #include "net/base/x509_util_nss.h" |
| 30 | 30 |
| 31 #if defined(OS_IOS) |
| 32 #include <CommonCrypto/CommonDigest.h> |
| 33 #include "net/base/x509_util_ios.h" |
| 34 #endif // defined(OS_IOS) |
| 35 |
| 31 namespace net { | 36 namespace net { |
| 32 | 37 |
| 33 namespace { | 38 namespace { |
| 34 | 39 |
| 35 typedef scoped_ptr_malloc< | 40 typedef scoped_ptr_malloc< |
| 36 CERTCertificatePolicies, | 41 CERTCertificatePolicies, |
| 37 crypto::NSSDestroyer<CERTCertificatePolicies, | 42 crypto::NSSDestroyer<CERTCertificatePolicies, |
| 38 CERT_DestroyCertificatePoliciesExtension> > | 43 CERT_DestroyCertificatePoliciesExtension> > |
| 39 ScopedCERTCertificatePolicies; | 44 ScopedCERTCertificatePolicies; |
| 40 | 45 |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: | 225 case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: |
| 221 verify_result->has_md4 = true; | 226 verify_result->has_md4 = true; |
| 222 break; | 227 break; |
| 223 default: | 228 default: |
| 224 break; | 229 break; |
| 225 } | 230 } |
| 226 } | 231 } |
| 227 | 232 |
| 228 if (root_cert) | 233 if (root_cert) |
| 229 verified_chain.push_back(root_cert); | 234 verified_chain.push_back(root_cert); |
| 235 #if defined(OS_IOS) |
| 236 verify_result->verified_cert = |
| 237 x509_util_ios::CreateCertFromNSSHandles(verified_cert, verified_chain); |
| 238 #else |
| 230 verify_result->verified_cert = | 239 verify_result->verified_cert = |
| 231 X509Certificate::CreateFromHandle(verified_cert, verified_chain); | 240 X509Certificate::CreateFromHandle(verified_cert, verified_chain); |
| 241 #endif // defined(OS_IOS) |
| 232 } | 242 } |
| 233 | 243 |
| 234 // IsKnownRoot returns true if the given certificate is one that we believe | 244 // IsKnownRoot returns true if the given certificate is one that we believe |
| 235 // is a standard (as opposed to user-installed) root. | 245 // is a standard (as opposed to user-installed) root. |
| 236 bool IsKnownRoot(CERTCertificate* root) { | 246 bool IsKnownRoot(CERTCertificate* root) { |
| 237 if (!root || !root->slot) | 247 if (!root || !root->slot) |
| 238 return false; | 248 return false; |
| 239 | 249 |
| 240 // This magic name is taken from | 250 // This magic name is taken from |
| 241 // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw/b
uiltins/constants.c&rev=1.13&mark=86,89#79 | 251 // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw/b
uiltins/constants.c&rev=1.13&mark=86,89#79 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 NOTREACHED(); | 317 NOTREACHED(); |
| 308 return kCRLSetError; | 318 return kCRLSetError; |
| 309 } | 319 } |
| 310 } | 320 } |
| 311 | 321 |
| 312 return kCRLSetOk; | 322 return kCRLSetOk; |
| 313 } | 323 } |
| 314 | 324 |
| 315 // Forward declarations. | 325 // Forward declarations. |
| 316 SECStatus RetryPKIXVerifyCertWithWorkarounds( | 326 SECStatus RetryPKIXVerifyCertWithWorkarounds( |
| 317 X509Certificate::OSCertHandle cert_handle, int num_policy_oids, | 327 CERTCertificate* cert_handle, int num_policy_oids, |
| 318 bool cert_io_enabled, std::vector<CERTValInParam>* cvin, | 328 bool cert_io_enabled, std::vector<CERTValInParam>* cvin, |
| 319 CERTValOutParam* cvout); | 329 CERTValOutParam* cvout); |
| 320 SECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle); | 330 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle); |
| 321 | 331 |
| 322 // Call CERT_PKIXVerifyCert for the cert_handle. | 332 // Call CERT_PKIXVerifyCert for the cert_handle. |
| 323 // Verification results are stored in an array of CERTValOutParam. | 333 // Verification results are stored in an array of CERTValOutParam. |
| 324 // If policy_oids is not NULL and num_policy_oids is positive, policies | 334 // If policy_oids is not NULL and num_policy_oids is positive, policies |
| 325 // are also checked. | 335 // are also checked. |
| 326 // Caller must initialize cvout before calling this function. | 336 // Caller must initialize cvout before calling this function. |
| 327 SECStatus PKIXVerifyCert(X509Certificate::OSCertHandle cert_handle, | 337 SECStatus PKIXVerifyCert(CERTCertificate* cert_handle, |
| 328 bool check_revocation, | 338 bool check_revocation, |
| 329 bool cert_io_enabled, | 339 bool cert_io_enabled, |
| 330 const SECOidTag* policy_oids, | 340 const SECOidTag* policy_oids, |
| 331 int num_policy_oids, | 341 int num_policy_oids, |
| 332 CERTValOutParam* cvout) { | 342 CERTValOutParam* cvout) { |
| 333 bool use_crl = check_revocation; | 343 bool use_crl = check_revocation; |
| 334 bool use_ocsp = check_revocation; | 344 bool use_ocsp = check_revocation; |
| 335 | 345 |
| 336 // These CAs have multiple keys, which trigger two bugs in NSS's CRL code. | 346 // These CAs have multiple keys, which trigger two bugs in NSS's CRL code. |
| 337 // 1. NSS may use one key to verify a CRL signed with another key, | 347 // 1. NSS may use one key to verify a CRL signed with another key, |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 440 rv = RetryPKIXVerifyCertWithWorkarounds(cert_handle, num_policy_oids, | 450 rv = RetryPKIXVerifyCertWithWorkarounds(cert_handle, num_policy_oids, |
| 441 cert_io_enabled, &cvin, cvout); | 451 cert_io_enabled, &cvin, cvout); |
| 442 } | 452 } |
| 443 return rv; | 453 return rv; |
| 444 } | 454 } |
| 445 | 455 |
| 446 // PKIXVerifyCert calls this function to work around some bugs in | 456 // PKIXVerifyCert calls this function to work around some bugs in |
| 447 // CERT_PKIXVerifyCert. All the arguments of this function are either the | 457 // CERT_PKIXVerifyCert. All the arguments of this function are either the |
| 448 // arguments or local variables of PKIXVerifyCert. | 458 // arguments or local variables of PKIXVerifyCert. |
| 449 SECStatus RetryPKIXVerifyCertWithWorkarounds( | 459 SECStatus RetryPKIXVerifyCertWithWorkarounds( |
| 450 X509Certificate::OSCertHandle cert_handle, int num_policy_oids, | 460 CERTCertificate* cert_handle, int num_policy_oids, |
| 451 bool cert_io_enabled, std::vector<CERTValInParam>* cvin, | 461 bool cert_io_enabled, std::vector<CERTValInParam>* cvin, |
| 452 CERTValOutParam* cvout) { | 462 CERTValOutParam* cvout) { |
| 453 // We call this function when the first CERT_PKIXVerifyCert call in | 463 // We call this function when the first CERT_PKIXVerifyCert call in |
| 454 // PKIXVerifyCert failed, so we initialize |rv| to SECFailure. | 464 // PKIXVerifyCert failed, so we initialize |rv| to SECFailure. |
| 455 SECStatus rv = SECFailure; | 465 SECStatus rv = SECFailure; |
| 456 int nss_error = PORT_GetError(); | 466 int nss_error = PORT_GetError(); |
| 457 CERTValInParam in_param; | 467 CERTValInParam in_param; |
| 458 | 468 |
| 459 // If we get SEC_ERROR_UNKNOWN_ISSUER, we may be missing an intermediate | 469 // If we get SEC_ERROR_UNKNOWN_ISSUER, we may be missing an intermediate |
| 460 // CA certificate, so we retry with cert_pi_useAIACertFetch. | 470 // CA certificate, so we retry with cert_pi_useAIACertFetch. |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 521 } | 531 } |
| 522 | 532 |
| 523 return rv; | 533 return rv; |
| 524 } | 534 } |
| 525 | 535 |
| 526 // Decodes the certificatePolicies extension of the certificate. Returns | 536 // Decodes the certificatePolicies extension of the certificate. Returns |
| 527 // 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 |
| 528 // be decoded. The returned value must be freed with a | 538 // be decoded. The returned value must be freed with a |
| 529 // CERT_DestroyCertificatePoliciesExtension call. | 539 // CERT_DestroyCertificatePoliciesExtension call. |
| 530 CERTCertificatePolicies* DecodeCertPolicies( | 540 CERTCertificatePolicies* DecodeCertPolicies( |
| 531 X509Certificate::OSCertHandle cert_handle) { | 541 CERTCertificate* cert_handle) { |
| 532 SECItem policy_ext; | 542 SECItem policy_ext; |
| 533 SECStatus rv = CERT_FindCertExtension(cert_handle, | 543 SECStatus rv = CERT_FindCertExtension(cert_handle, |
| 534 SEC_OID_X509_CERTIFICATE_POLICIES, | 544 SEC_OID_X509_CERTIFICATE_POLICIES, |
| 535 &policy_ext); | 545 &policy_ext); |
| 536 if (rv != SECSuccess) | 546 if (rv != SECSuccess) |
| 537 return NULL; | 547 return NULL; |
| 538 CERTCertificatePolicies* policies = | 548 CERTCertificatePolicies* policies = |
| 539 CERT_DecodeCertificatePoliciesExtension(&policy_ext); | 549 CERT_DecodeCertificatePoliciesExtension(&policy_ext); |
| 540 SECITEM_FreeItem(&policy_ext, PR_FALSE); | 550 SECITEM_FreeItem(&policy_ext, PR_FALSE); |
| 541 return policies; | 551 return policies; |
| 542 } | 552 } |
| 543 | 553 |
| 544 // Returns the OID tag for the first certificate policy in the certificate's | 554 // Returns the OID tag for the first certificate policy in the certificate's |
| 545 // certificatePolicies extension. Returns SEC_OID_UNKNOWN if the certificate | 555 // certificatePolicies extension. Returns SEC_OID_UNKNOWN if the certificate |
| 546 // has no certificate policy. | 556 // has no certificate policy. |
| 547 SECOidTag GetFirstCertPolicy(X509Certificate::OSCertHandle cert_handle) { | 557 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle) { |
| 548 ScopedCERTCertificatePolicies policies(DecodeCertPolicies(cert_handle)); | 558 ScopedCERTCertificatePolicies policies(DecodeCertPolicies(cert_handle)); |
| 549 if (!policies.get()) | 559 if (!policies.get()) |
| 550 return SEC_OID_UNKNOWN; | 560 return SEC_OID_UNKNOWN; |
| 551 | 561 |
| 552 CERTPolicyInfo* policy_info = policies->policyInfos[0]; | 562 CERTPolicyInfo* policy_info = policies->policyInfos[0]; |
| 553 if (!policy_info) | 563 if (!policy_info) |
| 554 return SEC_OID_UNKNOWN; | 564 return SEC_OID_UNKNOWN; |
| 555 if (policy_info->oid != SEC_OID_UNKNOWN) | 565 if (policy_info->oid != SEC_OID_UNKNOWN) |
| 556 return policy_info->oid; | 566 return policy_info->oid; |
| 557 | 567 |
| 558 // The certificate policy is unknown to NSS. We need to create a dynamic | 568 // The certificate policy is unknown to NSS. We need to create a dynamic |
| 559 // OID tag for the policy. | 569 // OID tag for the policy. |
| 560 SECOidData od; | 570 SECOidData od; |
| 561 od.oid.len = policy_info->policyID.len; | 571 od.oid.len = policy_info->policyID.len; |
| 562 od.oid.data = policy_info->policyID.data; | 572 od.oid.data = policy_info->policyID.data; |
| 563 od.offset = SEC_OID_UNKNOWN; | 573 od.offset = SEC_OID_UNKNOWN; |
| 564 // NSS doesn't allow us to pass an empty description, so I use a hardcoded, | 574 // NSS doesn't allow us to pass an empty description, so I use a hardcoded, |
| 565 // default description here. The description doesn't need to be unique for | 575 // default description here. The description doesn't need to be unique for |
| 566 // each OID. | 576 // each OID. |
| 567 od.desc = "a certificate policy"; | 577 od.desc = "a certificate policy"; |
| 568 od.mechanism = CKM_INVALID_MECHANISM; | 578 od.mechanism = CKM_INVALID_MECHANISM; |
| 569 od.supportedExtension = INVALID_CERT_EXTENSION; | 579 od.supportedExtension = INVALID_CERT_EXTENSION; |
| 570 return SECOID_AddEntry(&od); | 580 return SECOID_AddEntry(&od); |
| 571 } | 581 } |
| 572 | 582 |
| 573 HashValue CertPublicKeyHashSHA1(CERTCertificate* cert) { | 583 HashValue CertPublicKeyHashSHA1(CERTCertificate* cert) { |
| 574 HashValue hash(HASH_VALUE_SHA1); | 584 HashValue hash(HASH_VALUE_SHA1); |
| 585 #if defined(OS_IOS) |
| 586 CC_SHA1(cert->derPublicKey.data, cert->derPublicKey.len, hash.data()); |
| 587 #else |
| 575 SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, hash.data(), | 588 SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, hash.data(), |
| 576 cert->derPublicKey.data, cert->derPublicKey.len); | 589 cert->derPublicKey.data, cert->derPublicKey.len); |
| 577 DCHECK_EQ(SECSuccess, rv); | 590 DCHECK_EQ(SECSuccess, rv); |
| 591 #endif |
| 578 return hash; | 592 return hash; |
| 579 } | 593 } |
| 580 | 594 |
| 581 HashValue CertPublicKeyHashSHA256(CERTCertificate* cert) { | 595 HashValue CertPublicKeyHashSHA256(CERTCertificate* cert) { |
| 582 HashValue hash(HASH_VALUE_SHA256); | 596 HashValue hash(HASH_VALUE_SHA256); |
| 597 #if defined(OS_IOS) |
| 598 CC_SHA256(cert->derPublicKey.data, cert->derPublicKey.len, hash.data()); |
| 599 #else |
| 583 SECStatus rv = HASH_HashBuf(HASH_AlgSHA256, hash.data(), | 600 SECStatus rv = HASH_HashBuf(HASH_AlgSHA256, hash.data(), |
| 584 cert->derPublicKey.data, cert->derPublicKey.len); | 601 cert->derPublicKey.data, cert->derPublicKey.len); |
| 585 DCHECK_EQ(rv, SECSuccess); | 602 DCHECK_EQ(rv, SECSuccess); |
| 603 #endif |
| 586 return hash; | 604 return hash; |
| 587 } | 605 } |
| 588 | 606 |
| 589 void AppendPublicKeyHashes(CERTCertList* cert_list, | 607 void AppendPublicKeyHashes(CERTCertList* cert_list, |
| 590 CERTCertificate* root_cert, | 608 CERTCertificate* root_cert, |
| 591 HashValueVector* hashes) { | 609 HashValueVector* hashes) { |
| 592 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); | 610 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); |
| 593 !CERT_LIST_END(node, cert_list); | 611 !CERT_LIST_END(node, cert_list); |
| 594 node = CERT_LIST_NEXT(node)) { | 612 node = CERT_LIST_NEXT(node)) { |
| 595 hashes->push_back(CertPublicKeyHashSHA1(node->cert)); | 613 hashes->push_back(CertPublicKeyHashSHA1(node->cert)); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 679 // the old path, might have been revoked. | 697 // the old path, might have been revoked. |
| 680 if (crl_set) { | 698 if (crl_set) { |
| 681 CRLSetResult crl_set_result = CheckRevocationWithCRLSet( | 699 CRLSetResult crl_set_result = CheckRevocationWithCRLSet( |
| 682 cvout[cvout_cert_list_index].value.pointer.chain, | 700 cvout[cvout_cert_list_index].value.pointer.chain, |
| 683 cvout[cvout_trust_anchor_index].value.pointer.cert, | 701 cvout[cvout_trust_anchor_index].value.pointer.cert, |
| 684 crl_set); | 702 crl_set); |
| 685 if (crl_set_result == kCRLSetRevoked) | 703 if (crl_set_result == kCRLSetRevoked) |
| 686 return false; | 704 return false; |
| 687 } | 705 } |
| 688 | 706 |
| 707 #if defined(OS_IOS) |
| 708 SHA1HashValue fingerprint = x509_util_ios::CalculateFingerprintNSS(root_ca); |
| 709 #else |
| 689 SHA1HashValue fingerprint = | 710 SHA1HashValue fingerprint = |
| 690 X509Certificate::CalculateFingerprint(root_ca); | 711 X509Certificate::CalculateFingerprint(root_ca); |
| 712 #endif |
| 691 return metadata->HasEVPolicyOID(fingerprint, ev_policy_oid); | 713 return metadata->HasEVPolicyOID(fingerprint, ev_policy_oid); |
| 692 } | 714 } |
| 693 | 715 |
| 694 } // namespace | 716 } // namespace |
| 695 | 717 |
| 696 CertVerifyProcNSS::CertVerifyProcNSS() {} | 718 CertVerifyProcNSS::CertVerifyProcNSS() {} |
| 697 | 719 |
| 698 CertVerifyProcNSS::~CertVerifyProcNSS() {} | 720 CertVerifyProcNSS::~CertVerifyProcNSS() {} |
| 699 | 721 |
| 700 int CertVerifyProcNSS::VerifyInternal(X509Certificate* cert, | 722 int CertVerifyProcNSS::VerifyInternal(X509Certificate* cert, |
| 701 const std::string& hostname, | 723 const std::string& hostname, |
| 702 int flags, | 724 int flags, |
| 703 CRLSet* crl_set, | 725 CRLSet* crl_set, |
| 704 CertVerifyResult* verify_result) { | 726 CertVerifyResult* verify_result) { |
| 727 #if defined(OS_IOS) |
| 728 // For iOS, the entire chain must be loaded into NSS's in-memory certificate |
| 729 // store. |
| 730 x509_util_ios::NSSCertChain scoped_chain(cert); |
| 731 CERTCertificate* cert_handle = scoped_chain.cert_handle(); |
| 732 #else |
| 705 CERTCertificate* cert_handle = cert->os_cert_handle(); | 733 CERTCertificate* cert_handle = cert->os_cert_handle(); |
| 734 #endif // defined(OS_IOS) |
| 735 |
| 706 // Make sure that the hostname matches with the common name of the cert. | 736 // Make sure that the hostname matches with the common name of the cert. |
| 707 SECStatus status = CERT_VerifyCertName(cert_handle, hostname.c_str()); | 737 SECStatus status = CERT_VerifyCertName(cert_handle, hostname.c_str()); |
| 708 if (status != SECSuccess) | 738 if (status != SECSuccess) |
| 709 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | 739 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; |
| 710 | 740 |
| 711 // Make sure that the cert is valid now. | 741 // Make sure that the cert is valid now. |
| 712 SECCertTimeValidity validity = CERT_CheckCertValidTimes( | 742 SECCertTimeValidity validity = CERT_CheckCertValidTimes( |
| 713 cert_handle, PR_Now(), PR_TRUE); | 743 cert_handle, PR_Now(), PR_TRUE); |
| 714 if (validity != secCertTimeValid) | 744 if (validity != secCertTimeValid) |
| 715 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; | 745 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 788 | 818 |
| 789 if ((flags & CertVerifier::VERIFY_EV_CERT) && is_ev_candidate && | 819 if ((flags & CertVerifier::VERIFY_EV_CERT) && is_ev_candidate && |
| 790 VerifyEV(cert_handle, flags, crl_set, metadata, ev_policy_oid)) { | 820 VerifyEV(cert_handle, flags, crl_set, metadata, ev_policy_oid)) { |
| 791 verify_result->cert_status |= CERT_STATUS_IS_EV; | 821 verify_result->cert_status |= CERT_STATUS_IS_EV; |
| 792 } | 822 } |
| 793 | 823 |
| 794 return OK; | 824 return OK; |
| 795 } | 825 } |
| 796 | 826 |
| 797 } // namespace net | 827 } // namespace net |
| OLD | NEW |