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/crypto/cssm_init.h" | 14 #include "base/crypto/cssm_init.h" |
14 #include "base/crypto/rsa_private_key.h" | 15 #include "base/crypto/rsa_private_key.h" |
15 #include "base/lazy_instance.h" | 16 #include "base/lazy_instance.h" |
16 #include "base/logging.h" | 17 #include "base/logging.h" |
17 #include "base/mac/scoped_cftyperef.h" | 18 #include "base/mac/scoped_cftyperef.h" |
18 #include "base/memory/singleton.h" | 19 #include "base/memory/singleton.h" |
19 #include "base/nss_util.h" | 20 #include "base/nss_util.h" |
20 #include "base/pickle.h" | 21 #include "base/pickle.h" |
21 #include "base/sha1.h" | 22 #include "base/sha1.h" |
22 #include "base/sys_string_conversions.h" | 23 #include "base/sys_string_conversions.h" |
23 #include "net/base/cert_status_flags.h" | 24 #include "net/base/cert_status_flags.h" |
24 #include "net/base/cert_verify_result.h" | 25 #include "net/base/cert_verify_result.h" |
25 #include "net/base/net_errors.h" | 26 #include "net/base/net_errors.h" |
26 #include "net/base/test_root_certs.h" | 27 #include "net/base/test_root_certs.h" |
27 #include "net/base/x509_certificate_known_roots_mac.h" | 28 #include "net/base/x509_certificate_known_roots_mac.h" |
29 #include "third_party/apple_apsl/cssmapplePriv.h" | |
28 #include "third_party/nss/mozilla/security/nss/lib/certdb/cert.h" | 30 #include "third_party/nss/mozilla/security/nss/lib/certdb/cert.h" |
29 | 31 |
30 using base::mac::ScopedCFTypeRef; | 32 using base::mac::ScopedCFTypeRef; |
31 using base::Time; | 33 using base::Time; |
32 | 34 |
33 namespace net { | 35 namespace net { |
34 | 36 |
35 namespace { | 37 namespace { |
36 | 38 |
37 typedef OSStatus (*SecTrustCopyExtendedResultFuncPtr)(SecTrustRef, | 39 typedef OSStatus (*SecTrustCopyExtendedResultFuncPtr)(SecTrustRef, |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
278 }; | 280 }; |
279 err = SecPolicySetValue(*policy, &options_data); | 281 err = SecPolicySetValue(*policy, &options_data); |
280 if (err) { | 282 if (err) { |
281 CFRelease(*policy); | 283 CFRelease(*policy); |
282 return err; | 284 return err; |
283 } | 285 } |
284 } | 286 } |
285 return noErr; | 287 return noErr; |
286 } | 288 } |
287 | 289 |
290 // Creates a series of SecPolicyRefs to be added to a SecTrustRef used to | |
291 // validate a certificate for an SSL peer. |hostname| contains the name of | |
292 // the SSL peer that the certificate should be verified against. |flags| is | |
293 // a bitwise-OR of VerifyFlags that can further alter how trust is validated, | |
294 // such as how revocation is checked. If successful, returns noErr, and | |
295 // stores the resultant array of SecPolicyRefs in |policies|. | |
296 OSStatus CreateTrustPolicies(const std::string& hostname, int flags, | |
297 ScopedCFTypeRef<CFArrayRef>* policies) { | |
298 // Create an SSL SecPolicyRef, and configure it to perform hostname | |
299 // validation. The hostname check does 99% of what we want, with the | |
300 // exception of dotted IPv4 addreses, which we handle ourselves below. | |
301 CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options = { | |
302 CSSM_APPLE_TP_SSL_OPTS_VERSION, | |
303 hostname.size(), | |
304 hostname.data(), | |
305 0 | |
306 }; | |
307 SecPolicyRef ssl_policy; | |
308 OSStatus status = CreatePolicy(&CSSMOID_APPLE_TP_SSL, &tp_ssl_options, | |
309 sizeof(tp_ssl_options), &ssl_policy); | |
310 if (status) | |
311 return status; | |
312 ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy); | |
313 | |
314 // Manually add OCSP and CRL policies. If neither an OCSP or CRL policy is | |
315 // specified, the Apple TP module will add whatever the system settings are, | |
316 // which is not desirable here. | |
317 // | |
318 // Note that this causes any locally configured OCSP responder URL to be | |
319 // ignored. | |
Ryan Sleevi
2011/04/12 07:17:29
agl: Given your experience with the unfortunate re
agl
2011/04/12 13:19:50
I've never heard of anyone deploying a custom OCSP
| |
320 CSSM_APPLE_TP_OCSP_OPTIONS tp_ocsp_options; | |
321 memset(&tp_ocsp_options, 0, sizeof(tp_ocsp_options)); | |
322 tp_ocsp_options.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION; | |
323 | |
324 CSSM_APPLE_TP_CRL_OPTIONS tp_crl_options; | |
325 memset(&tp_crl_options, 0, sizeof(tp_crl_options)); | |
326 tp_crl_options.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION; | |
327 | |
328 if (flags & X509Certificate::VERIFY_REV_CHECKING_ENABLED) { | |
329 // If an OCSP responder is available, use it, and avoid fetching any CRLs | |
330 // for that certificate, which may be much larger. | |
331 tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_SUFFICIENT; | |
Ryan Sleevi
2011/04/12 07:17:29
agl (or wtc): An alternative here would be to *req
agl
2011/04/12 13:19:50
Yes it is, absolutely.
Ryan Sleevi
2011/04/13 03:45:37
I realize the reference to "the above" was a bit a
| |
332 // Ensure that CRLs can be fetched if a crlDistributionPoint extension is | |
333 // found. Otherwise, only the local CRL cache will be consulted. | |
334 tp_crl_options.CrlFlags |= CSSM_TP_ACTION_FETCH_CRL_FROM_NET; | |
335 } else { | |
336 // Disable OCSP network fetching, but still permit cached OCSP responses | |
337 // to be used. This is equivalent to the Windows code's usage of | |
338 // CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY. | |
339 tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_DISABLE_NET; | |
340 // The default CrlFlags will ensure only cached CRLs are used. | |
341 } | |
342 | |
343 SecPolicyRef ocsp_policy; | |
344 status = CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_OCSP, &tp_ocsp_options, | |
345 sizeof(tp_ocsp_options), &ocsp_policy); | |
346 if (status) | |
347 return status; | |
348 ScopedCFTypeRef<SecPolicyRef> scoped_ocsp_policy(ocsp_policy); | |
349 | |
350 SecPolicyRef crl_policy; | |
351 status = CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_CRL, &tp_crl_options, | |
352 sizeof(tp_crl_options), &crl_policy); | |
353 if (status) | |
354 return status; | |
355 ScopedCFTypeRef<SecPolicyRef> scoped_crl_policy(crl_policy); | |
356 | |
357 CFTypeRef local_policies[] = { ssl_policy, ocsp_policy, crl_policy }; | |
358 CFArrayRef policy_array = CFArrayCreate(kCFAllocatorDefault, local_policies, | |
359 arraysize(local_policies), | |
360 &kCFTypeArrayCallBacks); | |
361 if (!policy_array) | |
362 return memFullErr; | |
363 | |
364 policies->reset(policy_array); | |
365 return noErr; | |
366 } | |
367 | |
288 // Gets the issuer for a given cert, starting with the cert itself and | 368 // Gets the issuer for a given cert, starting with the cert itself and |
289 // including the intermediate and finally root certificates (if any). | 369 // including the intermediate and finally root certificates (if any). |
290 // This function calls SecTrust but doesn't actually pay attention to the trust | 370 // This function calls SecTrust but doesn't actually pay attention to the trust |
291 // result: it shouldn't be used to determine trust, just to traverse the chain. | 371 // result: it shouldn't be used to determine trust, just to traverse the chain. |
292 // Caller is responsible for releasing the value stored into *out_cert_chain. | 372 // Caller is responsible for releasing the value stored into *out_cert_chain. |
293 OSStatus CopyCertChain(SecCertificateRef cert_handle, | 373 OSStatus CopyCertChain(SecCertificateRef cert_handle, |
294 CFArrayRef* out_cert_chain) { | 374 CFArrayRef* out_cert_chain) { |
295 DCHECK(cert_handle); | 375 DCHECK(cert_handle); |
296 DCHECK(out_cert_chain); | 376 DCHECK(out_cert_chain); |
297 // Create an SSL policy ref configured for client cert evaluation. | 377 // Create an SSL policy ref configured for client cert evaluation. |
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
704 | 784 |
705 int X509Certificate::Verify(const std::string& hostname, int flags, | 785 int X509Certificate::Verify(const std::string& hostname, int flags, |
706 CertVerifyResult* verify_result) const { | 786 CertVerifyResult* verify_result) const { |
707 verify_result->Reset(); | 787 verify_result->Reset(); |
708 | 788 |
709 if (IsBlacklisted()) { | 789 if (IsBlacklisted()) { |
710 verify_result->cert_status |= CERT_STATUS_REVOKED; | 790 verify_result->cert_status |= CERT_STATUS_REVOKED; |
711 return ERR_CERT_REVOKED; | 791 return ERR_CERT_REVOKED; |
712 } | 792 } |
713 | 793 |
714 // Create an SSL SecPolicyRef, and configure it to perform hostname | 794 ScopedCFTypeRef<CFArrayRef> trust_policies; |
715 // validation. The hostname check does 99% of what we want, with the | 795 OSStatus status = CreateTrustPolicies(hostname, flags, &trust_policies); |
716 // exception of dotted IPv4 addreses, which we handle ourselves below. | |
717 CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options = { | |
718 CSSM_APPLE_TP_SSL_OPTS_VERSION, | |
719 hostname.size(), | |
720 hostname.data(), | |
721 0 | |
722 }; | |
723 SecPolicyRef ssl_policy; | |
724 OSStatus status = CreatePolicy(&CSSMOID_APPLE_TP_SSL, | |
725 &tp_ssl_options, | |
726 sizeof(tp_ssl_options), | |
727 &ssl_policy); | |
728 if (status) | 796 if (status) |
729 return NetErrorFromOSStatus(status); | 797 return NetErrorFromOSStatus(status); |
730 ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy); | |
731 | 798 |
732 // Create and configure a SecTrustRef, which takes our certificate(s) | 799 // Create and configure a SecTrustRef, which takes our certificate(s) |
733 // and our SSL SecPolicyRef. SecTrustCreateWithCertificates() takes an | 800 // and our SSL SecPolicyRef. SecTrustCreateWithCertificates() takes an |
734 // array of certificates, the first of which is the certificate we're | 801 // array of certificates, the first of which is the certificate we're |
735 // verifying, and the subsequent (optional) certificates are used for | 802 // verifying, and the subsequent (optional) certificates are used for |
736 // chain building. | 803 // chain building. |
737 CFMutableArrayRef cert_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, | 804 CFMutableArrayRef cert_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, |
738 &kCFTypeArrayCallBacks); | 805 &kCFTypeArrayCallBacks); |
739 if (!cert_array) | 806 if (!cert_array) |
740 return ERR_OUT_OF_MEMORY; | 807 return ERR_OUT_OF_MEMORY; |
741 ScopedCFTypeRef<CFArrayRef> scoped_cert_array(cert_array); | 808 ScopedCFTypeRef<CFArrayRef> scoped_cert_array(cert_array); |
742 CFArrayAppendValue(cert_array, cert_handle_); | 809 CFArrayAppendValue(cert_array, cert_handle_); |
743 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) | 810 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) |
744 CFArrayAppendValue(cert_array, intermediate_ca_certs_[i]); | 811 CFArrayAppendValue(cert_array, intermediate_ca_certs_[i]); |
745 | 812 |
746 // From here on, only one thread can be active at a time. We have had a number | 813 // From here on, only one thread can be active at a time. We have had a number |
747 // of sporadic crashes in the SecTrustEvaluate call below, way down inside | 814 // of sporadic crashes in the SecTrustEvaluate call below, way down inside |
748 // Apple's cert code, which we suspect are caused by a thread-safety issue. | 815 // Apple's cert code, which we suspect are caused by a thread-safety issue. |
749 // So as a speculative fix allow only one thread to use SecTrust on this cert. | 816 // So as a speculative fix allow only one thread to use SecTrust on this cert. |
750 base::AutoLock lock(verification_lock_); | 817 base::AutoLock lock(verification_lock_); |
751 | 818 |
752 SecTrustRef trust_ref = NULL; | 819 SecTrustRef trust_ref = NULL; |
753 status = SecTrustCreateWithCertificates(cert_array, ssl_policy, &trust_ref); | 820 status = SecTrustCreateWithCertificates(cert_array, trust_policies, |
821 &trust_ref); | |
754 if (status) | 822 if (status) |
755 return NetErrorFromOSStatus(status); | 823 return NetErrorFromOSStatus(status); |
756 ScopedCFTypeRef<SecTrustRef> scoped_trust_ref(trust_ref); | 824 ScopedCFTypeRef<SecTrustRef> scoped_trust_ref(trust_ref); |
757 | 825 |
758 if (TestRootCerts::HasInstance()) { | 826 if (TestRootCerts::HasInstance()) { |
759 status = TestRootCerts::GetInstance()->FixupSecTrustRef(trust_ref); | 827 status = TestRootCerts::GetInstance()->FixupSecTrustRef(trust_ref); |
760 if (status) | 828 if (status) |
761 return NetErrorFromOSStatus(status); | 829 return NetErrorFromOSStatus(status); |
762 } | 830 } |
763 | 831 |
832 CSSM_APPLE_TP_ACTION_DATA tp_action_data; | |
833 memset(&tp_action_data, 0, sizeof(tp_action_data)); | |
834 tp_action_data.Version = CSSM_APPLE_TP_ACTION_VERSION; | |
835 // Allow CSSM to download any missing intermediate certificates if an | |
836 // authorityInfoAccess extension or issuerAltName extension is present. | |
837 tp_action_data.ActionFlags = CSSM_TP_ACTION_FETCH_CERT_FROM_NET; | |
838 | |
764 if (flags & VERIFY_REV_CHECKING_ENABLED) { | 839 if (flags & VERIFY_REV_CHECKING_ENABLED) { |
765 // When called with VERIFY_REV_CHECKING_ENABLED, we ask SecTrustEvaluate() | 840 // Require a positive result from an OCSP responder or a CRL (or both) |
766 // to apply OCSP and CRL checking, but we're still subject to the global | 841 // for every certificate in the chain. The Apple TP automatically excludes |
767 // settings, which are configured in the Keychain Access application (in | 842 // the self-signed root from this requirement. |
768 // the Certificates tab of the Preferences dialog). If the user has | 843 tp_action_data.ActionFlags |= CSSM_TP_ACTION_REQUIRE_REV_PER_CERT; |
agl
2011/04/12 13:19:50
What does this do if both OCSP and CRL downloading
| |
769 // revocation disabled (which is the default), then we will get | |
770 // kSecTrustResultRecoverableTrustFailure back from SecTrustEvaluate() | |
771 // with one of a number of sub error codes indicating that revocation | |
772 // checking did not occur. In that case, we'll set our own result to include | |
773 // CERT_STATUS_UNABLE_TO_CHECK_REVOCATION. | |
774 // | |
775 // NOTE: This does not apply to EV certificates, which always get | |
776 // revocation checks regardless of the global settings. | |
777 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | |
778 CSSM_APPLE_TP_ACTION_DATA tp_action_data = { CSSM_APPLE_TP_ACTION_VERSION }; | |
779 tp_action_data.ActionFlags = CSSM_TP_ACTION_REQUIRE_REV_PER_CERT; | |
780 CFDataRef action_data_ref = | |
781 CFDataCreate(NULL, reinterpret_cast<UInt8*>(&tp_action_data), | |
782 sizeof(tp_action_data)); | |
783 if (!action_data_ref) | |
784 return ERR_OUT_OF_MEMORY; | |
785 ScopedCFTypeRef<CFDataRef> scoped_action_data_ref(action_data_ref); | |
786 status = SecTrustSetParameters(trust_ref, CSSM_TP_ACTION_DEFAULT, | |
787 action_data_ref); | |
788 if (status) | |
789 return NetErrorFromOSStatus(status); | |
790 } | 844 } |
791 | 845 |
846 CFDataRef action_data_ref = | |
847 CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, | |
848 reinterpret_cast<UInt8*>(&tp_action_data), | |
849 sizeof(tp_action_data), kCFAllocatorNull); | |
850 if (!action_data_ref) | |
851 return ERR_OUT_OF_MEMORY; | |
852 ScopedCFTypeRef<CFDataRef> scoped_action_data_ref(action_data_ref); | |
853 status = SecTrustSetParameters(trust_ref, CSSM_TP_ACTION_DEFAULT, | |
854 action_data_ref); | |
855 if (status) | |
856 return NetErrorFromOSStatus(status); | |
857 | |
792 // Verify the certificate. A non-zero result from SecTrustGetResult() | 858 // Verify the certificate. A non-zero result from SecTrustGetResult() |
793 // indicates that some fatal error occurred and the chain couldn't be | 859 // indicates that some fatal error occurred and the chain couldn't be |
794 // processed, not that the chain contains no errors. We need to examine the | 860 // processed, not that the chain contains no errors. We need to examine the |
795 // output of SecTrustGetResult() to determine that. | 861 // output of SecTrustGetResult() to determine that. |
796 SecTrustResultType trust_result; | 862 SecTrustResultType trust_result; |
797 status = SecTrustEvaluate(trust_ref, &trust_result); | 863 status = SecTrustEvaluate(trust_ref, &trust_result); |
798 if (status) | 864 if (status) |
799 return NetErrorFromOSStatus(status); | 865 return NetErrorFromOSStatus(status); |
800 CFArrayRef completed_chain = NULL; | 866 CFArrayRef completed_chain = NULL; |
801 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info; | 867 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info; |
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1225 CFArrayAppendArray(chain, | 1291 CFArrayAppendArray(chain, |
1226 cert_chain, | 1292 cert_chain, |
1227 CFRangeMake(1, chain_count - 1)); | 1293 CFRangeMake(1, chain_count - 1)); |
1228 } | 1294 } |
1229 } | 1295 } |
1230 | 1296 |
1231 return chain.release(); | 1297 return chain.release(); |
1232 } | 1298 } |
1233 | 1299 |
1234 } // namespace net | 1300 } // namespace net |
OLD | NEW |