]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecTrustStore.c
Security-57740.1.18.tar.gz
[apple/security.git] / OSX / sec / Security / SecTrustStore.c
1 /*
2 * Copyright (c) 2007-2009,2012-2015 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * SecTrustStore.c - CertificateSource API to a system root certificate store
26 */
27 #include <Security/SecTrustStore.h>
28
29 #include <Security/SecCertificateInternal.h>
30 #include <Security/SecInternal.h>
31 #include <Security/SecuritydXPC.h>
32 #include <Security/SecPolicyPriv.h>
33 #include <Security/SecPolicyInternal.h>
34 #include <CoreFoundation/CFString.h>
35 #include <AssertMacros.h>
36 #include <ipc/securityd_client.h>
37 #include "SecFramework.h"
38 #include <sys/stat.h>
39 #include <stdio.h>
40 #include <os/activity.h>
41 #include <dirent.h>
42 #include "SecTrustPriv.h"
43 #include "SecTrustSettings.h"
44 #include <utilities/SecCFError.h>
45 #include <utilities/SecCFWrappers.h>
46 #include "utilities/SecDb.h"
47
48 static CFStringRef kSecTrustStoreUserName = CFSTR("user");
49
50 SecTrustStoreRef SecTrustStoreForDomain(SecTrustStoreDomain domain) {
51 CFStringRef domainName;
52 if (domain == kSecTrustStoreDomainUser) {
53 domainName = kSecTrustStoreUserName;
54 } else {
55 return NULL;
56 }
57
58 if (gSecurityd) {
59 return gSecurityd->sec_trust_store_for_domain(domainName, NULL);
60 } else {
61 return (SecTrustStoreRef)domainName;
62 }
63 }
64
65 static bool string_data_to_bool_error(enum SecXPCOperation op, SecTrustStoreRef ts, CFDataRef digest, CFErrorRef *error)
66 {
67 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
68 return SecXPCDictionarySetString(message, kSecXPCKeyDomain, (CFStringRef)ts, error) &&
69 SecXPCDictionarySetData(message, kSecXPCKeyDigest, digest, error);
70 }, NULL);
71 }
72
73 static bool string_data_to_bool_bool_error(enum SecXPCOperation op, SecTrustStoreRef ts, CFDataRef digest, bool *result, CFErrorRef *error)
74 {
75 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
76 return SecXPCDictionarySetString(message, kSecXPCKeyDomain, (CFStringRef)ts, error) &&
77 SecXPCDictionarySetData(message, kSecXPCKeyDigest, digest, error);
78 }, ^bool(xpc_object_t response, CFErrorRef *error) {
79 if (result)
80 *result = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
81 return true;
82 });
83 }
84
85 Boolean SecTrustStoreContains(SecTrustStoreRef ts,
86 SecCertificateRef certificate) {
87 CFDataRef digest;
88 bool ok = false;
89 __block bool contains = false;
90
91 os_activity_t trace_activity = os_activity_start("SecTrustStoreContains", OS_ACTIVITY_FLAG_DEFAULT);
92 require(ts, errOut);
93 require(digest = SecCertificateGetSHA1Digest(certificate), errOut);
94
95
96 ok = (SecOSStatusWith(^bool (CFErrorRef *error) {
97 return SECURITYD_XPC(sec_trust_store_contains, string_data_to_bool_bool_error, ts, digest, &contains, error);
98 }) == errSecSuccess);
99
100 errOut:
101 os_activity_end(trace_activity);
102 return ok && contains;
103 }
104
105 static bool SecXPCDictionarySetCertificate(xpc_object_t message, const char *key, SecCertificateRef certificate, CFErrorRef *error) {
106 if (certificate) {
107 xpc_dictionary_set_data(message, key, SecCertificateGetBytePtr(certificate),
108 SecCertificateGetLength(certificate));
109 return true;
110 }
111 return SecError(errSecParam, error, CFSTR("NULL certificate"));
112 }
113
114
115 static bool string_cert_cftype_to_error(enum SecXPCOperation op, SecTrustStoreRef ts, SecCertificateRef certificate, CFTypeRef trustSettingsDictOrArray, CFErrorRef *error)
116 {
117 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
118 bool ok = false;
119 ok = SecXPCDictionarySetString(message, kSecXPCKeyDomain, (CFStringRef)ts, error) &&
120 SecXPCDictionarySetCertificate(message, kSecXPCKeyCertificate, certificate, error) &&
121 (!trustSettingsDictOrArray || SecXPCDictionarySetPList(message, kSecXPCKeySettings, trustSettingsDictOrArray, error));
122 return ok;
123 }, NULL);
124 }
125
126 static OSStatus validateConstraint(Boolean isSelfSigned, CFMutableDictionaryRef trustSettingsDict) {
127 OSStatus result = errSecSuccess;
128
129 /* Check "TrustRoot"/"TrustAsRoot" */
130 CFNumberRef resultNumber = NULL;
131 resultNumber = (CFNumberRef)CFDictionaryGetValue(trustSettingsDict, kSecTrustSettingsResult);
132 uint32_t resultValue = kSecTrustSettingsResultInvalid;
133 if (!isNumber(resultNumber) && !isSelfSigned) {
134 /* only self-signed certs get default of TrustAsRoot */
135 return errSecParam;
136 }
137 if (isNumber(resultNumber) && CFNumberGetValue(resultNumber, kCFNumberSInt32Type, &resultValue)) {
138 if (isSelfSigned && resultValue == kSecTrustSettingsResultTrustAsRoot) {
139 return errSecParam;
140 }
141 if (!isSelfSigned && resultValue == kSecTrustSettingsResultTrustRoot) {
142 return errSecParam;
143 }
144 }
145
146 /* If there's a policy specified, change the contents */
147 SecPolicyRef policy = NULL;
148 policy = (SecPolicyRef)CFDictionaryGetValue(trustSettingsDict, kSecTrustSettingsPolicy);
149 if (policy) {
150 CFStringRef policyOid = NULL, policyName = NULL;
151 policyOid = SecPolicyGetOidString(policy);
152 policyName = SecPolicyGetName(policy);
153 CFDictionarySetValue(trustSettingsDict, kSecTrustSettingsPolicy, policyOid);
154 if (policyName) { CFDictionaryAddValue(trustSettingsDict, kSecTrustSettingsPolicyName, policyName); }
155 }
156
157 return result;
158 }
159
160 static OSStatus validateTrustSettings(Boolean isSelfSigned,
161 CFTypeRef trustSettingsDictOrArray,
162 CFTypeRef * CF_RETURNS_RETAINED modifiedTrustSettings) {
163 OSStatus status = errSecParam;
164 CFTypeRef result = NULL;
165
166 /* NULL is a valid input */
167 if (!trustSettingsDictOrArray && isSelfSigned) {
168 return errSecSuccess;
169 } else if (!trustSettingsDictOrArray && !isSelfSigned) {
170 return errSecParam;
171 }
172
173 if (CFDictionaryGetTypeID() == CFGetTypeID(trustSettingsDictOrArray)) {
174 result = CFDictionaryCreateMutableCopy(NULL, 0, trustSettingsDictOrArray);
175 status = validateConstraint(isSelfSigned, (CFMutableDictionaryRef)result);
176 } else if (CFArrayGetTypeID() == CFGetTypeID(trustSettingsDictOrArray)) {
177 require_action_quiet(result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks),
178 out, status = errSecAllocate);
179 CFIndex ix, count = CFArrayGetCount(trustSettingsDictOrArray);
180 for (ix = 0; ix < count; ix++) {
181 CFDictionaryRef constraint = CFArrayGetValueAtIndex(trustSettingsDictOrArray, ix);
182 CFDictionaryRef modifiedConstraint = NULL;
183 require_noerr_quiet(status = validateTrustSettings(isSelfSigned, constraint, (CFTypeRef *)&modifiedConstraint), out);
184 CFArrayAppendValue((CFMutableArrayRef)result, modifiedConstraint);
185 CFReleaseNull(modifiedConstraint); /* constraint now owned by array */
186 }
187 }
188
189 out:
190 if (errSecSuccess == status && modifiedTrustSettings) {
191 *modifiedTrustSettings = CFRetainSafe(result);
192 }
193 CFReleaseNull(result);
194 return status;
195 }
196
197 OSStatus SecTrustStoreSetTrustSettings(SecTrustStoreRef ts,
198 SecCertificateRef certificate,
199 CFTypeRef trustSettingsDictOrArray) {
200 __block OSStatus result;
201 __block CFTypeRef validatedTrustSettings = NULL;
202
203 Boolean isSelfSigned = false;
204 require_noerr_quiet(result = SecCertificateIsSelfSigned(certificate, &isSelfSigned), out);
205 require_noerr_quiet(result = validateTrustSettings(isSelfSigned, trustSettingsDictOrArray, &validatedTrustSettings), out);
206
207 os_activity_initiate("SecTrustStoreSetTrustSettings", OS_ACTIVITY_FLAG_DEFAULT, ^{
208 result = SecOSStatusWith(^bool (CFErrorRef *error) {
209 return SECURITYD_XPC(sec_trust_store_set_trust_settings, string_cert_cftype_to_error, ts, certificate, validatedTrustSettings, error);
210 });
211 });
212
213 out:
214 CFReleaseNull(validatedTrustSettings);
215 return result;
216 }
217
218 OSStatus SecTrustStoreRemoveCertificate(SecTrustStoreRef ts,
219 SecCertificateRef certificate)
220 {
221 CFDataRef digest;
222 __block OSStatus status = errSecParam;
223
224 os_activity_t trace_activity = os_activity_start("SecTrustStoreRemoveCertificate", OS_ACTIVITY_FLAG_DEFAULT);
225 require(ts, errOut);
226 require(digest = SecCertificateGetSHA1Digest(certificate), errOut);
227 require(gSecurityd || ts == (SecTrustStoreRef)kSecTrustStoreUserName, errOut);
228
229 status = SecOSStatusWith(^bool (CFErrorRef *error) {
230 return SECURITYD_XPC(sec_trust_store_remove_certificate, string_data_to_bool_error, ts, digest, error);
231 });
232
233 errOut:
234 os_activity_end(trace_activity);
235 return status;
236 }
237
238
239 static CFIndex GetOTAAssetVersionNumber()
240 {
241 CFIndex result = 0;
242 int version = 0;
243
244 if (errSecSuccess == SecTrustGetOTAPKIAssetVersionNumber(&version))
245 {
246 result = version;
247 }
248
249 return result;
250 }
251
252
253
254 OSStatus SecTrustStoreGetSettingsVersionNumber(SecTrustSettingsVersionNumber* p_settings_version_number)
255 {
256 OSStatus status = errSecParam;
257 if (NULL == p_settings_version_number)
258 {
259 return status;
260 }
261
262 CFIndex versionNumber = GetOTAAssetVersionNumber();
263 *p_settings_version_number = (SecTrustSettingsVersionNumber)versionNumber;
264
265 return errSecSuccess;
266 }
267
268 static bool string_to_array_error(enum SecXPCOperation op, SecTrustStoreRef ts, CFArrayRef *trustStoreContents, CFErrorRef *error)
269 {
270 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
271 return SecXPCDictionarySetString(message, kSecXPCKeyDomain, (CFStringRef)ts, error);
272 }, ^bool(xpc_object_t response, CFErrorRef *error) {
273 if (trustStoreContents) {
274 *trustStoreContents = SecXPCDictionaryCopyArray(response, kSecXPCKeyResult, error);
275 if (!*trustStoreContents) return false;
276 }
277 return true;
278 });
279 }
280
281 OSStatus SecTrustStoreCopyAll(SecTrustStoreRef ts, CFArrayRef *trustStoreContents)
282 {
283 __block CFArrayRef results = NULL;
284 OSStatus status = errSecParam;
285
286 os_activity_t trace_activity = os_activity_start("SecTrustStoreCopyAll", OS_ACTIVITY_FLAG_DEFAULT);
287 require(ts, errOut);
288
289 status = SecOSStatusWith(^bool (CFErrorRef *error) {
290 return SECURITYD_XPC(sec_trust_store_copy_all, string_to_array_error, ts, &results, error);
291 });
292
293 *trustStoreContents = results;
294
295 errOut:
296 os_activity_end(trace_activity);
297 return status;
298 }
299
300 static bool string_data_to_array_error(enum SecXPCOperation op, SecTrustStoreRef ts, CFDataRef digest, CFArrayRef *usageConstraints, CFErrorRef *error)
301 {
302 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
303 return SecXPCDictionarySetString(message, kSecXPCKeyDomain, (CFStringRef)ts, error) &&
304 SecXPCDictionarySetData(message, kSecXPCKeyDigest, digest, error);
305 }, ^bool(xpc_object_t response, CFErrorRef *error) {
306 return SecXPCDictionaryCopyArrayOptional(response, kSecXPCKeyResult, usageConstraints, error);
307 });
308 }
309
310 OSStatus SecTrustStoreCopyUsageConstraints(SecTrustStoreRef ts, SecCertificateRef certificate, CFArrayRef *usageConstraints)
311 {
312 CFDataRef digest;
313 __block CFArrayRef results = NULL;
314 OSStatus status = errSecParam;
315
316 os_activity_t trace_activity = os_activity_start("SecTrustStoreCopyUsageConstraints", OS_ACTIVITY_FLAG_DEFAULT);
317 require(ts, errOut);
318 require(certificate, errOut);
319 require(digest = SecCertificateGetSHA1Digest(certificate), errOut);
320 require(usageConstraints, errOut);
321
322 status = SecOSStatusWith(^bool (CFErrorRef *error) {
323 return SECURITYD_XPC(sec_trust_store_copy_usage_constraints, string_data_to_array_error, ts, digest, &results, error);
324 });
325
326 *usageConstraints = results;
327
328 errOut:
329 os_activity_end(trace_activity);
330 return status;
331 }