Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(248)

Side by Side Diff: net/base/x509_certificate_mac.cc

Issue 6824069: Allow revocation checking to be disabled on Mac, overriding/ignoring system settings (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: With suppressions Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698