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 |