• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "net/cert/x509_util_mac.h"
6 
7 #include "base/logging.h"
8 #include "third_party/apple_apsl/cssmapplePriv.h"
9 
10 namespace net {
11 
12 namespace x509_util {
13 
14 namespace {
15 
16 // Creates a SecPolicyRef for the given OID, with optional value.
CreatePolicy(const CSSM_OID * policy_oid,void * option_data,size_t option_length,SecPolicyRef * policy)17 OSStatus CreatePolicy(const CSSM_OID* policy_oid,
18                       void* option_data,
19                       size_t option_length,
20                       SecPolicyRef* policy) {
21   SecPolicySearchRef search;
22   OSStatus err = SecPolicySearchCreate(CSSM_CERT_X_509v3, policy_oid, NULL,
23                                        &search);
24   if (err)
25     return err;
26   err = SecPolicySearchCopyNext(search, policy);
27   CFRelease(search);
28   if (err)
29     return err;
30 
31   if (option_data) {
32     CSSM_DATA options_data = {
33       option_length,
34       reinterpret_cast<uint8_t*>(option_data)
35     };
36     err = SecPolicySetValue(*policy, &options_data);
37     if (err) {
38       CFRelease(*policy);
39       return err;
40     }
41   }
42   return noErr;
43 }
44 
45 }  // namespace
46 
47 
CreateSSLClientPolicy(SecPolicyRef * policy)48 OSStatus CreateSSLClientPolicy(SecPolicyRef* policy) {
49   CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options;
50   memset(&tp_ssl_options, 0, sizeof(tp_ssl_options));
51   tp_ssl_options.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
52   tp_ssl_options.Flags |= CSSM_APPLE_TP_SSL_CLIENT;
53 
54   return CreatePolicy(&CSSMOID_APPLE_TP_SSL, &tp_ssl_options,
55                       sizeof(tp_ssl_options), policy);
56 }
57 
CreateSSLServerPolicy(const std::string & hostname,SecPolicyRef * policy)58 OSStatus CreateSSLServerPolicy(const std::string& hostname,
59                                SecPolicyRef* policy) {
60   CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options;
61   memset(&tp_ssl_options, 0, sizeof(tp_ssl_options));
62   tp_ssl_options.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
63   if (!hostname.empty()) {
64     tp_ssl_options.ServerName = hostname.data();
65     tp_ssl_options.ServerNameLen = hostname.size();
66   }
67 
68   return CreatePolicy(&CSSMOID_APPLE_TP_SSL, &tp_ssl_options,
69                       sizeof(tp_ssl_options), policy);
70 }
71 
CreateBasicX509Policy(SecPolicyRef * policy)72 OSStatus CreateBasicX509Policy(SecPolicyRef* policy) {
73   return CreatePolicy(&CSSMOID_APPLE_X509_BASIC, NULL, 0, policy);
74 }
75 
CreateRevocationPolicies(bool enable_revocation_checking,bool enable_ev_checking,CFMutableArrayRef policies)76 OSStatus CreateRevocationPolicies(bool enable_revocation_checking,
77                                   bool enable_ev_checking,
78                                   CFMutableArrayRef policies) {
79   OSStatus status = noErr;
80 
81   // In order to bypass the system revocation checking settings, the
82   // SecTrustRef must have at least one revocation policy associated with it.
83   // Since it is not known prior to verification whether the Apple TP will
84   // consider a certificate as an EV candidate, the default policy used is a
85   // CRL policy, since it does not communicate over the network.
86   // If the TP believes the leaf is an EV cert, it will explicitly add an
87   // OCSP policy to perform the online checking, and if it doesn't believe
88   // that the leaf is EV, then the default CRL policy will effectively no-op.
89   // This behaviour is used to implement EV-only revocation checking.
90   if (enable_ev_checking || enable_revocation_checking) {
91     CSSM_APPLE_TP_CRL_OPTIONS tp_crl_options;
92     memset(&tp_crl_options, 0, sizeof(tp_crl_options));
93     tp_crl_options.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION;
94     // Only allow network CRL fetches if the caller explicitly requests
95     // online revocation checking. Note that, as of OS X 10.7.2, the system
96     // will set force this flag on according to system policies, so
97     // online revocation checks cannot be completely disabled.
98     if (enable_revocation_checking)
99       tp_crl_options.CrlFlags = CSSM_TP_ACTION_FETCH_CRL_FROM_NET;
100 
101     SecPolicyRef crl_policy;
102     status = CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_CRL, &tp_crl_options,
103                           sizeof(tp_crl_options), &crl_policy);
104     if (status)
105       return status;
106     CFArrayAppendValue(policies, crl_policy);
107     CFRelease(crl_policy);
108   }
109 
110   // If revocation checking is explicitly enabled, then add an OCSP policy
111   // and allow network access. If both revocation checking and EV checking
112   // are disabled, then the added OCSP policy will be prevented from
113   // accessing the network. This is done because the TP will force an OCSP
114   // policy to be present when it believes the certificate is EV. If network
115   // fetching was not explicitly disabled, then it would be as if
116   // enable_ev_checking was always set to true.
117   if (enable_revocation_checking || !enable_ev_checking) {
118     CSSM_APPLE_TP_OCSP_OPTIONS tp_ocsp_options;
119     memset(&tp_ocsp_options, 0, sizeof(tp_ocsp_options));
120     tp_ocsp_options.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION;
121 
122     if (enable_revocation_checking) {
123       // The default for the OCSP policy is to fetch responses via the network,
124       // unlike the CRL policy default. The policy is further modified to
125       // prefer OCSP over CRLs, if both are specified on the certificate. This
126       // is because an OCSP response is both sufficient and typically
127       // significantly smaller than the CRL counterpart.
128       tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_SUFFICIENT;
129     } else {
130       // Effectively disable OCSP checking by making it impossible to get an
131       // OCSP response. Even if the Apple TP forces OCSP, no checking will
132       // be able to succeed. If this happens, the Apple TP will report an error
133       // that OCSP was unavailable, but this will be handled and suppressed in
134       // X509Certificate::Verify().
135       tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_DISABLE_NET |
136                               CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE;
137     }
138 
139     SecPolicyRef ocsp_policy;
140     status = CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_OCSP, &tp_ocsp_options,
141                           sizeof(tp_ocsp_options), &ocsp_policy);
142     if (status)
143       return status;
144     CFArrayAppendValue(policies, ocsp_policy);
145     CFRelease(ocsp_policy);
146   }
147 
148   return status;
149 }
150 
CSSMFieldValue()151 CSSMFieldValue::CSSMFieldValue()
152     : cl_handle_(CSSM_INVALID_HANDLE),
153       oid_(NULL),
154       field_(NULL) {
155 }
CSSMFieldValue(CSSM_CL_HANDLE cl_handle,const CSSM_OID * oid,CSSM_DATA_PTR field)156 CSSMFieldValue::CSSMFieldValue(CSSM_CL_HANDLE cl_handle,
157                                const CSSM_OID* oid,
158                                CSSM_DATA_PTR field)
159     : cl_handle_(cl_handle),
160       oid_(const_cast<CSSM_OID_PTR>(oid)),
161       field_(field) {
162 }
163 
~CSSMFieldValue()164 CSSMFieldValue::~CSSMFieldValue() {
165   Reset(CSSM_INVALID_HANDLE, NULL, NULL);
166 }
167 
Reset(CSSM_CL_HANDLE cl_handle,CSSM_OID_PTR oid,CSSM_DATA_PTR field)168 void CSSMFieldValue::Reset(CSSM_CL_HANDLE cl_handle,
169                            CSSM_OID_PTR oid,
170                            CSSM_DATA_PTR field) {
171   if (cl_handle_ && oid_ && field_)
172     CSSM_CL_FreeFieldValue(cl_handle_, oid_, field_);
173   cl_handle_ = cl_handle;
174   oid_ = oid;
175   field_ = field;
176 }
177 
CSSMCachedCertificate()178 CSSMCachedCertificate::CSSMCachedCertificate()
179     : cl_handle_(CSSM_INVALID_HANDLE),
180       cached_cert_handle_(CSSM_INVALID_HANDLE) {
181 }
~CSSMCachedCertificate()182 CSSMCachedCertificate::~CSSMCachedCertificate() {
183   if (cl_handle_ && cached_cert_handle_)
184     CSSM_CL_CertAbortCache(cl_handle_, cached_cert_handle_);
185 }
186 
Init(SecCertificateRef os_cert_handle)187 OSStatus CSSMCachedCertificate::Init(SecCertificateRef os_cert_handle) {
188   DCHECK(!cl_handle_ && !cached_cert_handle_);
189   DCHECK(os_cert_handle);
190   CSSM_DATA cert_data;
191   OSStatus status = SecCertificateGetData(os_cert_handle, &cert_data);
192   if (status)
193     return status;
194   status = SecCertificateGetCLHandle(os_cert_handle, &cl_handle_);
195   if (status) {
196     DCHECK(!cl_handle_);
197     return status;
198   }
199 
200   status = CSSM_CL_CertCache(cl_handle_, &cert_data, &cached_cert_handle_);
201   if (status)
202     DCHECK(!cached_cert_handle_);
203   return status;
204 }
205 
GetField(const CSSM_OID * field_oid,CSSMFieldValue * field) const206 OSStatus CSSMCachedCertificate::GetField(const CSSM_OID* field_oid,
207                                          CSSMFieldValue* field) const {
208   DCHECK(cl_handle_);
209   DCHECK(cached_cert_handle_);
210 
211   CSSM_OID_PTR oid = const_cast<CSSM_OID_PTR>(field_oid);
212   CSSM_DATA_PTR field_ptr = NULL;
213   CSSM_HANDLE results_handle = CSSM_INVALID_HANDLE;
214   uint32 field_value_count = 0;
215   CSSM_RETURN status = CSSM_CL_CertGetFirstCachedFieldValue(
216       cl_handle_, cached_cert_handle_, oid, &results_handle,
217       &field_value_count, &field_ptr);
218   if (status)
219     return status;
220 
221   // Note: |field_value_count| may be > 1, indicating that more than one
222   // value is present. This may happen with extensions, but for current
223   // usages, only the first value is returned.
224   CSSM_CL_CertAbortQuery(cl_handle_, results_handle);
225   field->Reset(cl_handle_, oid, field_ptr);
226   return CSSM_OK;
227 }
228 
229 }  // namespace x509_util
230 
231 }  // namespace net
232