OLD | NEW |
| (Empty) |
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/base/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. | |
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 | |
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 | |
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 | |
72 OSStatus CreateBasicX509Policy(SecPolicyRef* policy) { | |
73 return CreatePolicy(&CSSMOID_APPLE_X509_BASIC, NULL, 0, policy); | |
74 } | |
75 | |
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 | |
151 CSSMFieldValue::CSSMFieldValue() | |
152 : cl_handle_(CSSM_INVALID_HANDLE), | |
153 oid_(NULL), | |
154 field_(NULL) { | |
155 } | |
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 | |
164 CSSMFieldValue::~CSSMFieldValue() { | |
165 Reset(CSSM_INVALID_HANDLE, NULL, NULL); | |
166 } | |
167 | |
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 | |
178 CSSMCachedCertificate::CSSMCachedCertificate() | |
179 : cl_handle_(CSSM_INVALID_HANDLE), | |
180 cached_cert_handle_(CSSM_INVALID_HANDLE) { | |
181 } | |
182 CSSMCachedCertificate::~CSSMCachedCertificate() { | |
183 if (cl_handle_ && cached_cert_handle_) | |
184 CSSM_CL_CertAbortCache(cl_handle_, cached_cert_handle_); | |
185 } | |
186 | |
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 | |
206 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 | |
OLD | NEW |