Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 #include <CommonCrypto/CommonDigest.h> | 7 #include <CommonCrypto/CommonDigest.h> |
| 8 #include <CoreServices/CoreServices.h> | |
| 8 #include <Security/Security.h> | 9 #include <Security/Security.h> |
| 9 #include <time.h> | 10 #include <time.h> |
| 10 | 11 |
| 11 #include <vector> | 12 #include <vector> |
| 12 | 13 |
| 13 #include "base/lazy_instance.h" | 14 #include "base/lazy_instance.h" |
| 14 #include "base/logging.h" | 15 #include "base/logging.h" |
| 15 #include "base/mac/scoped_cftyperef.h" | 16 #include "base/mac/scoped_cftyperef.h" |
| 16 #include "base/memory/singleton.h" | 17 #include "base/memory/singleton.h" |
| 17 #include "base/pickle.h" | 18 #include "base/pickle.h" |
| 18 #include "base/sha1.h" | 19 #include "base/sha1.h" |
| 19 #include "base/sys_string_conversions.h" | 20 #include "base/sys_string_conversions.h" |
| 20 #include "crypto/cssm_init.h" | 21 #include "crypto/cssm_init.h" |
| 21 #include "crypto/nss_util.h" | 22 #include "crypto/nss_util.h" |
| 22 #include "crypto/rsa_private_key.h" | 23 #include "crypto/rsa_private_key.h" |
| 23 #include "net/base/asn1_util.h" | 24 #include "net/base/asn1_util.h" |
| 24 #include "net/base/cert_status_flags.h" | 25 #include "net/base/cert_status_flags.h" |
| 25 #include "net/base/cert_verify_result.h" | 26 #include "net/base/cert_verify_result.h" |
| 26 #include "net/base/net_errors.h" | 27 #include "net/base/net_errors.h" |
| 27 #include "net/base/test_root_certs.h" | 28 #include "net/base/test_root_certs.h" |
| 28 #include "net/base/x509_certificate_known_roots_mac.h" | 29 #include "net/base/x509_certificate_known_roots_mac.h" |
| 30 #include "third_party/apple_apsl/cssmapplePriv.h" | |
| 29 #include "third_party/nss/mozilla/security/nss/lib/certdb/cert.h" | 31 #include "third_party/nss/mozilla/security/nss/lib/certdb/cert.h" |
| 30 | 32 |
| 31 using base::mac::ScopedCFTypeRef; | 33 using base::mac::ScopedCFTypeRef; |
| 32 using base::Time; | 34 using base::Time; |
| 33 | 35 |
| 34 namespace net { | 36 namespace net { |
| 35 | 37 |
| 36 namespace { | 38 namespace { |
| 37 | 39 |
| 38 typedef OSStatus (*SecTrustCopyExtendedResultFuncPtr)(SecTrustRef, | 40 typedef OSStatus (*SecTrustCopyExtendedResultFuncPtr)(SecTrustRef, |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 279 }; | 281 }; |
| 280 err = SecPolicySetValue(*policy, &options_data); | 282 err = SecPolicySetValue(*policy, &options_data); |
| 281 if (err) { | 283 if (err) { |
| 282 CFRelease(*policy); | 284 CFRelease(*policy); |
| 283 return err; | 285 return err; |
| 284 } | 286 } |
| 285 } | 287 } |
| 286 return noErr; | 288 return noErr; |
| 287 } | 289 } |
| 288 | 290 |
| 291 // Creates a series of SecPolicyRefs to be added to a SecTrustRef used to | |
| 292 // validate a certificate for an SSL peer. |hostname| contains the name of | |
| 293 // the SSL peer that the certificate should be verified against. |flags| is | |
|
wtc
2011/04/20 19:40:33
Nit: should we change "SSL peer" to "SSL server"?
| |
| 294 // a bitwise-OR of VerifyFlags that can further alter how trust is | |
| 295 // validated, such as how revocation is checked. If successful, returns | |
| 296 // noErr, and stores the resultant array of SecPolicyRefs in |policies|. | |
| 297 OSStatus CreateTrustPolicies(const std::string& hostname, int flags, | |
| 298 ScopedCFTypeRef<CFArrayRef>* policies) { | |
| 299 // Create an SSL SecPolicyRef, and configure it to perform hostname | |
| 300 // validation. The hostname check does 99% of what we want, with the | |
| 301 // exception of dotted IPv4 addreses, which we handle ourselves below. | |
| 302 CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options = { | |
| 303 CSSM_APPLE_TP_SSL_OPTS_VERSION, | |
| 304 hostname.size(), | |
| 305 hostname.data(), | |
| 306 0 | |
| 307 }; | |
| 308 SecPolicyRef ssl_policy; | |
| 309 OSStatus status = CreatePolicy(&CSSMOID_APPLE_TP_SSL, &tp_ssl_options, | |
| 310 sizeof(tp_ssl_options), &ssl_policy); | |
| 311 if (status) | |
| 312 return status; | |
| 313 ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy); | |
| 314 | |
| 315 // Manually add OCSP and CRL policies. If neither an OCSP or CRL policy is | |
| 316 // specified, the Apple TP module will add whatever the system settings | |
| 317 // are, which is not desirable here. | |
| 318 // | |
| 319 // Note that this causes any locally configured OCSP responder URL to be | |
| 320 // ignored. | |
|
wtc
2011/04/20 19:40:33
Is the locally configured OCSP responder URL a sys
Ryan Sleevi
2011/04/20 22:46:51
It is a system setting. I documented this because
| |
| 321 CSSM_APPLE_TP_OCSP_OPTIONS tp_ocsp_options; | |
| 322 memset(&tp_ocsp_options, 0, sizeof(tp_ocsp_options)); | |
| 323 tp_ocsp_options.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION; | |
| 324 | |
| 325 CSSM_APPLE_TP_CRL_OPTIONS tp_crl_options; | |
| 326 memset(&tp_crl_options, 0, sizeof(tp_crl_options)); | |
| 327 tp_crl_options.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION; | |
| 328 | |
| 329 if (flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED) { | |
| 330 // If an OCSP responder is available, use it, and avoid fetching any | |
| 331 // CRLs for that certificate if possible, as they may be much larger. | |
| 332 tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_SUFFICIENT; | |
| 333 // Ensure that CRLs can be fetched if a crlDistributionPoint extension | |
| 334 // is found. Otherwise, only the local CRL cache will be consulted. | |
| 335 tp_crl_options.CrlFlags |= CSSM_TP_ACTION_FETCH_CRL_FROM_NET; | |
| 336 } else { | |
| 337 // Disable OCSP network fetching, but still permit cached OCSP responses | |
| 338 // to be used. This is equivalent to the Windows code's usage of | |
| 339 // CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY. | |
|
wtc
2011/04/20 19:40:33
Ideally we want to not do any revocation checking
Ryan Sleevi
2011/04/20 22:46:51
Really? This surprises me a little. I thought the
wtc
2011/04/20 23:23:54
Yes. That's what I expect if I uncheck the "Check
| |
| 340 tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_DISABLE_NET; | |
| 341 // The default CrlFlags will ensure only cached CRLs are used. | |
| 342 } | |
| 343 | |
| 344 SecPolicyRef ocsp_policy; | |
| 345 status = CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_OCSP, &tp_ocsp_options, | |
| 346 sizeof(tp_ocsp_options), &ocsp_policy); | |
| 347 if (status) | |
| 348 return status; | |
| 349 ScopedCFTypeRef<SecPolicyRef> scoped_ocsp_policy(ocsp_policy); | |
| 350 | |
| 351 SecPolicyRef crl_policy; | |
| 352 status = CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_CRL, &tp_crl_options, | |
| 353 sizeof(tp_crl_options), &crl_policy); | |
| 354 if (status) | |
| 355 return status; | |
| 356 ScopedCFTypeRef<SecPolicyRef> scoped_crl_policy(crl_policy); | |
| 357 | |
| 358 CFTypeRef local_policies[] = { ssl_policy, ocsp_policy, crl_policy }; | |
| 359 CFArrayRef policy_array = CFArrayCreate(kCFAllocatorDefault, local_policies, | |
| 360 arraysize(local_policies), | |
| 361 &kCFTypeArrayCallBacks); | |
|
wtc
2011/04/20 19:40:33
Just wanted to confirm that CFArrayCreate will ret
Ryan Sleevi
2011/04/20 22:46:51
Yes, per the documentation for the |callBacks| par
| |
| 362 if (!policy_array) | |
| 363 return memFullErr; | |
| 364 | |
| 365 policies->reset(policy_array); | |
| 366 return noErr; | |
| 367 } | |
| 368 | |
| 289 // Gets the issuer for a given cert, starting with the cert itself and | 369 // Gets the issuer for a given cert, starting with the cert itself and |
| 290 // including the intermediate and finally root certificates (if any). | 370 // including the intermediate and finally root certificates (if any). |
| 291 // This function calls SecTrust but doesn't actually pay attention to the trust | 371 // This function calls SecTrust but doesn't actually pay attention to the trust |
| 292 // result: it shouldn't be used to determine trust, just to traverse the chain. | 372 // result: it shouldn't be used to determine trust, just to traverse the chain. |
| 293 // Caller is responsible for releasing the value stored into *out_cert_chain. | 373 // Caller is responsible for releasing the value stored into *out_cert_chain. |
| 294 OSStatus CopyCertChain(SecCertificateRef cert_handle, | 374 OSStatus CopyCertChain(SecCertificateRef cert_handle, |
| 295 CFArrayRef* out_cert_chain) { | 375 CFArrayRef* out_cert_chain) { |
| 296 DCHECK(cert_handle); | 376 DCHECK(cert_handle); |
| 297 DCHECK(out_cert_chain); | 377 DCHECK(out_cert_chain); |
| 298 // Create an SSL policy ref configured for client cert evaluation. | 378 // Create an SSL policy ref configured for client cert evaluation. |
| (...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 727 | 807 |
| 728 int X509Certificate::Verify(const std::string& hostname, int flags, | 808 int X509Certificate::Verify(const std::string& hostname, int flags, |
| 729 CertVerifyResult* verify_result) const { | 809 CertVerifyResult* verify_result) const { |
| 730 verify_result->Reset(); | 810 verify_result->Reset(); |
| 731 | 811 |
| 732 if (IsBlacklisted()) { | 812 if (IsBlacklisted()) { |
| 733 verify_result->cert_status |= CERT_STATUS_REVOKED; | 813 verify_result->cert_status |= CERT_STATUS_REVOKED; |
| 734 return ERR_CERT_REVOKED; | 814 return ERR_CERT_REVOKED; |
| 735 } | 815 } |
| 736 | 816 |
| 737 // Create an SSL SecPolicyRef, and configure it to perform hostname | 817 ScopedCFTypeRef<CFArrayRef> trust_policies; |
| 738 // validation. The hostname check does 99% of what we want, with the | 818 OSStatus status = CreateTrustPolicies(hostname, flags, &trust_policies); |
| 739 // exception of dotted IPv4 addreses, which we handle ourselves below. | |
| 740 CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options = { | |
| 741 CSSM_APPLE_TP_SSL_OPTS_VERSION, | |
| 742 hostname.size(), | |
| 743 hostname.data(), | |
| 744 0 | |
| 745 }; | |
| 746 SecPolicyRef ssl_policy; | |
| 747 OSStatus status = CreatePolicy(&CSSMOID_APPLE_TP_SSL, | |
| 748 &tp_ssl_options, | |
| 749 sizeof(tp_ssl_options), | |
| 750 &ssl_policy); | |
| 751 if (status) | 819 if (status) |
| 752 return NetErrorFromOSStatus(status); | 820 return NetErrorFromOSStatus(status); |
| 753 ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy); | |
| 754 | 821 |
| 755 // Create and configure a SecTrustRef, which takes our certificate(s) | 822 // Create and configure a SecTrustRef, which takes our certificate(s) |
| 756 // and our SSL SecPolicyRef. SecTrustCreateWithCertificates() takes an | 823 // and our SSL SecPolicyRef. SecTrustCreateWithCertificates() takes an |
| 757 // array of certificates, the first of which is the certificate we're | 824 // array of certificates, the first of which is the certificate we're |
| 758 // verifying, and the subsequent (optional) certificates are used for | 825 // verifying, and the subsequent (optional) certificates are used for |
| 759 // chain building. | 826 // chain building. |
| 760 CFMutableArrayRef cert_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, | 827 CFMutableArrayRef cert_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, |
| 761 &kCFTypeArrayCallBacks); | 828 &kCFTypeArrayCallBacks); |
| 762 if (!cert_array) | 829 if (!cert_array) |
| 763 return ERR_OUT_OF_MEMORY; | 830 return ERR_OUT_OF_MEMORY; |
| 764 ScopedCFTypeRef<CFArrayRef> scoped_cert_array(cert_array); | 831 ScopedCFTypeRef<CFArrayRef> scoped_cert_array(cert_array); |
| 765 CFArrayAppendValue(cert_array, cert_handle_); | 832 CFArrayAppendValue(cert_array, cert_handle_); |
| 766 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) | 833 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) |
| 767 CFArrayAppendValue(cert_array, intermediate_ca_certs_[i]); | 834 CFArrayAppendValue(cert_array, intermediate_ca_certs_[i]); |
| 768 | 835 |
| 769 // From here on, only one thread can be active at a time. We have had a number | 836 // From here on, only one thread can be active at a time. We have had a number |
| 770 // of sporadic crashes in the SecTrustEvaluate call below, way down inside | 837 // of sporadic crashes in the SecTrustEvaluate call below, way down inside |
| 771 // Apple's cert code, which we suspect are caused by a thread-safety issue. | 838 // Apple's cert code, which we suspect are caused by a thread-safety issue. |
| 772 // So as a speculative fix allow only one thread to use SecTrust on this cert. | 839 // So as a speculative fix allow only one thread to use SecTrust on this cert. |
| 773 base::AutoLock lock(verification_lock_); | 840 base::AutoLock lock(verification_lock_); |
| 774 | 841 |
| 775 SecTrustRef trust_ref = NULL; | 842 SecTrustRef trust_ref = NULL; |
| 776 status = SecTrustCreateWithCertificates(cert_array, ssl_policy, &trust_ref); | 843 status = SecTrustCreateWithCertificates(cert_array, trust_policies, |
| 844 &trust_ref); | |
| 777 if (status) | 845 if (status) |
| 778 return NetErrorFromOSStatus(status); | 846 return NetErrorFromOSStatus(status); |
| 779 ScopedCFTypeRef<SecTrustRef> scoped_trust_ref(trust_ref); | 847 ScopedCFTypeRef<SecTrustRef> scoped_trust_ref(trust_ref); |
| 780 | 848 |
| 781 if (TestRootCerts::HasInstance()) { | 849 if (TestRootCerts::HasInstance()) { |
| 782 status = TestRootCerts::GetInstance()->FixupSecTrustRef(trust_ref); | 850 status = TestRootCerts::GetInstance()->FixupSecTrustRef(trust_ref); |
| 783 if (status) | 851 if (status) |
| 784 return NetErrorFromOSStatus(status); | 852 return NetErrorFromOSStatus(status); |
| 785 } | 853 } |
| 786 | 854 |
| 855 CSSM_APPLE_TP_ACTION_DATA tp_action_data; | |
| 856 memset(&tp_action_data, 0, sizeof(tp_action_data)); | |
| 857 tp_action_data.Version = CSSM_APPLE_TP_ACTION_VERSION; | |
| 858 // Allow CSSM to download any missing intermediate certificates if an | |
| 859 // authorityInfoAccess extension or issuerAltName extension is present. | |
| 860 tp_action_data.ActionFlags = CSSM_TP_ACTION_FETCH_CERT_FROM_NET; | |
|
wtc
2011/04/20 19:40:33
Good change! I didn't know CSSM can do this. I w
| |
| 861 | |
| 787 if (flags & VERIFY_REV_CHECKING_ENABLED) { | 862 if (flags & VERIFY_REV_CHECKING_ENABLED) { |
| 788 // When called with VERIFY_REV_CHECKING_ENABLED, we ask SecTrustEvaluate() | 863 // Require a positive result from an OCSP responder or a CRL (or both) |
| 789 // to apply OCSP and CRL checking, but we're still subject to the global | 864 // for every certificate in the chain. The Apple TP automatically |
| 790 // settings, which are configured in the Keychain Access application (in | 865 // excludes the self-signed root from this requirement. If a certificate |
| 791 // the Certificates tab of the Preferences dialog). If the user has | 866 // is missing both a crlDistributionPoints extension and an |
| 792 // revocation disabled (which is the default), then we will get | 867 // authorityInfoAccess extension with an OCSP responder URL, then we |
| 793 // kSecTrustResultRecoverableTrustFailure back from SecTrustEvaluate() | 868 // will get a kSecTrustResultRecoverableTrustFailure back from |
| 794 // with one of a number of sub error codes indicating that revocation | 869 // SecTrustEvaluate(), with a |
| 795 // checking did not occur. In that case, we'll set our own result to include | 870 // CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK error code. In that case, |
| 871 // we'll set our own result to include | |
| 872 // CERT_STATUS_NO_REVOCATION_MECHANISM. If one or both extensions are | |
| 873 // present, and a check fails (server unavailable, OCSP retry later, | |
| 874 // signature mismatch), then we'll set our own result to include | |
| 796 // CERT_STATUS_UNABLE_TO_CHECK_REVOCATION. | 875 // CERT_STATUS_UNABLE_TO_CHECK_REVOCATION. |
| 797 // | 876 tp_action_data.ActionFlags |= CSSM_TP_ACTION_REQUIRE_REV_PER_CERT; |
| 798 // NOTE: This does not apply to EV certificates, which always get | |
| 799 // revocation checks regardless of the global settings. | |
| 800 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 877 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| 801 CSSM_APPLE_TP_ACTION_DATA tp_action_data = { CSSM_APPLE_TP_ACTION_VERSION }; | 878 } else { |
| 802 tp_action_data.ActionFlags = CSSM_TP_ACTION_REQUIRE_REV_PER_CERT; | 879 // EV requires revocation checking. |
| 803 CFDataRef action_data_ref = | 880 // Note, under the hood, SecTrustEvaluate() will modify the OCSP options |
| 804 CFDataCreate(NULL, reinterpret_cast<UInt8*>(&tp_action_data), | 881 // so as to attempt OCSP fetching if it believes a certificate may chain |
|
wtc
2011/04/20 19:40:33
Nit: OCSP fetching => OCSP checking
"fetching" im
| |
| 805 sizeof(tp_action_data)); | 882 // to an EV root. However, because network fetches are disabled in |
| 806 if (!action_data_ref) | 883 // CreateTrustPolicies() when revocation checking is disabled, these |
| 807 return ERR_OUT_OF_MEMORY; | 884 // will only go against the local cache. |
| 808 ScopedCFTypeRef<CFDataRef> scoped_action_data_ref(action_data_ref); | 885 flags &= ~VERIFY_EV_CERT; |
| 809 status = SecTrustSetParameters(trust_ref, CSSM_TP_ACTION_DEFAULT, | |
| 810 action_data_ref); | |
| 811 if (status) | |
| 812 return NetErrorFromOSStatus(status); | |
| 813 } | 886 } |
| 814 | 887 |
| 888 CFDataRef action_data_ref = | |
| 889 CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, | |
| 890 reinterpret_cast<UInt8*>(&tp_action_data), | |
| 891 sizeof(tp_action_data), kCFAllocatorNull); | |
| 892 if (!action_data_ref) | |
| 893 return ERR_OUT_OF_MEMORY; | |
| 894 ScopedCFTypeRef<CFDataRef> scoped_action_data_ref(action_data_ref); | |
| 895 status = SecTrustSetParameters(trust_ref, CSSM_TP_ACTION_DEFAULT, | |
| 896 action_data_ref); | |
| 897 if (status) | |
| 898 return NetErrorFromOSStatus(status); | |
| 899 | |
| 815 // Verify the certificate. A non-zero result from SecTrustGetResult() | 900 // Verify the certificate. A non-zero result from SecTrustGetResult() |
| 816 // indicates that some fatal error occurred and the chain couldn't be | 901 // indicates that some fatal error occurred and the chain couldn't be |
| 817 // processed, not that the chain contains no errors. We need to examine the | 902 // processed, not that the chain contains no errors. We need to examine the |
| 818 // output of SecTrustGetResult() to determine that. | 903 // output of SecTrustGetResult() to determine that. |
| 819 SecTrustResultType trust_result; | 904 SecTrustResultType trust_result; |
| 820 status = SecTrustEvaluate(trust_ref, &trust_result); | 905 status = SecTrustEvaluate(trust_ref, &trust_result); |
| 821 if (status) | 906 if (status) |
| 822 return NetErrorFromOSStatus(status); | 907 return NetErrorFromOSStatus(status); |
| 823 CFArrayRef completed_chain = NULL; | 908 CFArrayRef completed_chain = NULL; |
| 824 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info; | 909 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info; |
| (...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1249 CFArrayAppendArray(chain, | 1334 CFArrayAppendArray(chain, |
| 1250 cert_chain, | 1335 cert_chain, |
| 1251 CFRangeMake(1, chain_count - 1)); | 1336 CFRangeMake(1, chain_count - 1)); |
| 1252 } | 1337 } |
| 1253 } | 1338 } |
| 1254 | 1339 |
| 1255 return chain.release(); | 1340 return chain.release(); |
| 1256 } | 1341 } |
| 1257 | 1342 |
| 1258 } // namespace net | 1343 } // namespace net |
| OLD | NEW |