]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecTrustStore.c
Security-58286.70.7.tar.gz
[apple/security.git] / OSX / sec / Security / SecTrustStore.c
1 /*
2 * Copyright (c) 2007-2018 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 <Security/SecTrustSettingsPriv.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 (gTrustd) {
59 return gTrustd->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 os_activity_t activity = os_activity_create("SecTrustStoreContains", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
76 os_activity_scope(activity);
77 bool status = securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
78 return SecXPCDictionarySetString(message, kSecXPCKeyDomain, (CFStringRef)ts, error) &&
79 SecXPCDictionarySetData(message, kSecXPCKeyDigest, digest, error);
80 }, ^bool(xpc_object_t response, CFErrorRef *error) {
81 if (result)
82 *result = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
83 return true;
84 });
85 os_release(activity);
86 return status;
87 }
88
89 Boolean SecTrustStoreContains(SecTrustStoreRef ts,
90 SecCertificateRef certificate) {
91 CFDataRef digest;
92 bool ok = false;
93 __block bool contains = false;
94
95 require(ts, errOut);
96 require(digest = SecCertificateGetSHA1Digest(certificate), errOut);
97
98
99 ok = (SecOSStatusWith(^bool (CFErrorRef *error) {
100 return TRUSTD_XPC(sec_trust_store_contains, string_data_to_bool_bool_error, ts, digest, &contains, error);
101 }) == errSecSuccess);
102
103 errOut:
104 return ok && contains;
105 }
106
107 static bool SecXPCDictionarySetCertificate(xpc_object_t message, const char *key, SecCertificateRef certificate, CFErrorRef *error) {
108 if (certificate) {
109 xpc_dictionary_set_data(message, key, SecCertificateGetBytePtr(certificate),
110 SecCertificateGetLength(certificate));
111 return true;
112 }
113 return SecError(errSecParam, error, CFSTR("NULL certificate"));
114 }
115
116
117 static bool string_cert_cftype_to_error(enum SecXPCOperation op, SecTrustStoreRef ts, SecCertificateRef certificate, CFTypeRef trustSettingsDictOrArray, CFErrorRef *error)
118 {
119 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
120 bool ok = false;
121 ok = SecXPCDictionarySetString(message, kSecXPCKeyDomain, (CFStringRef)ts, error) &&
122 SecXPCDictionarySetCertificate(message, kSecXPCKeyCertificate, certificate, error) &&
123 (!trustSettingsDictOrArray || SecXPCDictionarySetPList(message, kSecXPCKeySettings, trustSettingsDictOrArray, error));
124 return ok;
125 }, NULL);
126 }
127
128 static OSStatus validateConstraint(Boolean isSelfSigned, CFMutableDictionaryRef trustSettingsDict) {
129 OSStatus result = errSecSuccess;
130
131 /* Check "TrustRoot"/"TrustAsRoot" */
132 CFNumberRef resultNumber = NULL;
133 resultNumber = (CFNumberRef)CFDictionaryGetValue(trustSettingsDict, kSecTrustSettingsResult);
134 uint32_t resultValue = kSecTrustSettingsResultInvalid;
135 if (!isNumber(resultNumber) && !isSelfSigned) {
136 /* only self-signed certs get default of TrustAsRoot */
137 return errSecParam;
138 }
139 if (isNumber(resultNumber) && CFNumberGetValue(resultNumber, kCFNumberSInt32Type, &resultValue)) {
140 if (isSelfSigned && resultValue == kSecTrustSettingsResultTrustAsRoot) {
141 return errSecParam;
142 }
143 if (!isSelfSigned && resultValue == kSecTrustSettingsResultTrustRoot) {
144 return errSecParam;
145 }
146 }
147
148 /* If there's a policy specified, change the contents */
149 SecPolicyRef policy = NULL;
150 policy = (SecPolicyRef)CFDictionaryGetValue(trustSettingsDict, kSecTrustSettingsPolicy);
151 if (policy) {
152 CFStringRef policyOid = NULL, policyName = NULL;
153 policyOid = SecPolicyGetOidString(policy);
154 policyName = SecPolicyGetName(policy);
155 CFDictionarySetValue(trustSettingsDict, kSecTrustSettingsPolicy, policyOid);
156 if (policyName) { CFDictionaryAddValue(trustSettingsDict, kSecTrustSettingsPolicyName, policyName); }
157 }
158
159 return result;
160 }
161
162 static OSStatus validateTrustSettings(Boolean isSelfSigned,
163 CFTypeRef trustSettingsDictOrArray,
164 CFTypeRef * CF_RETURNS_RETAINED modifiedTrustSettings) {
165 OSStatus status = errSecParam;
166 CFTypeRef result = NULL;
167
168 /* NULL is a valid input */
169 if (!trustSettingsDictOrArray && isSelfSigned) {
170 return errSecSuccess;
171 } else if (!trustSettingsDictOrArray && !isSelfSigned) {
172 return errSecParam;
173 }
174
175 if (CFDictionaryGetTypeID() == CFGetTypeID(trustSettingsDictOrArray)) {
176 result = CFDictionaryCreateMutableCopy(NULL, 0, trustSettingsDictOrArray);
177 status = validateConstraint(isSelfSigned, (CFMutableDictionaryRef)result);
178 } else if (CFArrayGetTypeID() == CFGetTypeID(trustSettingsDictOrArray)) {
179 require_action_quiet(result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks),
180 out, status = errSecAllocate);
181 CFIndex ix, count = CFArrayGetCount(trustSettingsDictOrArray);
182 for (ix = 0; ix < count; ix++) {
183 CFDictionaryRef constraint = CFArrayGetValueAtIndex(trustSettingsDictOrArray, ix);
184 CFDictionaryRef modifiedConstraint = NULL;
185 require_noerr_quiet(status = validateTrustSettings(isSelfSigned, constraint, (CFTypeRef *)&modifiedConstraint), out);
186 CFArrayAppendValue((CFMutableArrayRef)result, modifiedConstraint);
187 CFReleaseNull(modifiedConstraint); /* constraint now owned by array */
188 }
189 }
190
191 out:
192 if (errSecSuccess == status && modifiedTrustSettings) {
193 *modifiedTrustSettings = CFRetainSafe(result);
194 }
195 CFReleaseNull(result);
196 return status;
197 }
198
199 OSStatus SecTrustStoreSetTrustSettings(SecTrustStoreRef ts,
200 SecCertificateRef certificate,
201 CFTypeRef trustSettingsDictOrArray) {
202 __block OSStatus result;
203 __block CFTypeRef validatedTrustSettings = NULL;
204
205 Boolean isSelfSigned = false;
206 require_noerr_quiet(result = SecCertificateIsSelfSigned(certificate, &isSelfSigned), out);
207 require_noerr_quiet(result = validateTrustSettings(isSelfSigned, trustSettingsDictOrArray, &validatedTrustSettings), out);
208
209 os_activity_initiate("SecTrustStoreSetTrustSettings", OS_ACTIVITY_FLAG_DEFAULT, ^{
210 result = SecOSStatusWith(^bool (CFErrorRef *error) {
211 return TRUSTD_XPC(sec_trust_store_set_trust_settings, string_cert_cftype_to_error, ts, certificate, validatedTrustSettings, error);
212 });
213 });
214
215 out:
216 CFReleaseNull(validatedTrustSettings);
217 return result;
218 }
219
220 OSStatus SecTrustStoreRemoveCertificate(SecTrustStoreRef ts,
221 SecCertificateRef certificate)
222 {
223 CFDataRef digest;
224 __block OSStatus status = errSecParam;
225
226 os_activity_t activity = os_activity_create("SecTrustStoreRemoveCertificate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
227 os_activity_scope(activity);
228 require(ts, errOut);
229 require(digest = SecCertificateGetSHA1Digest(certificate), errOut);
230 require(gTrustd || ts == (SecTrustStoreRef)kSecTrustStoreUserName, errOut);
231
232 status = SecOSStatusWith(^bool (CFErrorRef *error) {
233 return TRUSTD_XPC(sec_trust_store_remove_certificate, string_data_to_bool_error, ts, digest, error);
234 });
235
236 errOut:
237 os_release(activity);
238 return status;
239 }
240
241
242 OSStatus SecTrustStoreGetSettingsVersionNumber(SecTrustSettingsVersionNumber* p_settings_version_number)
243 {
244 if (NULL == p_settings_version_number) {
245 return errSecParam;
246 }
247
248 OSStatus status = errSecSuccess;
249 CFErrorRef error = nil;
250 uint64_t versionNumber = SecTrustGetTrustStoreVersionNumber(&error);
251 *p_settings_version_number = (SecTrustSettingsVersionNumber)versionNumber;
252
253 if (error) {
254 status = (OSStatus)CFErrorGetCode(error);
255 }
256 CFReleaseSafe(error);
257 return status;
258 }
259
260 static bool string_to_array_error(enum SecXPCOperation op, SecTrustStoreRef ts, CFArrayRef *trustStoreContents, CFErrorRef *error)
261 {
262 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
263 return SecXPCDictionarySetString(message, kSecXPCKeyDomain, (CFStringRef)ts, error);
264 }, ^bool(xpc_object_t response, CFErrorRef *error) {
265 if (trustStoreContents) {
266 *trustStoreContents = SecXPCDictionaryCopyArray(response, kSecXPCKeyResult, error);
267 if (!*trustStoreContents) return false;
268 }
269 return true;
270 });
271 }
272
273 OSStatus SecTrustStoreCopyAll(SecTrustStoreRef ts, CFArrayRef *trustStoreContents)
274 {
275 __block CFArrayRef results = NULL;
276 OSStatus status = errSecParam;
277
278 os_activity_t activity = os_activity_create("SecTrustStoreCopyAll", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
279 os_activity_scope(activity);
280 require(ts, errOut);
281
282 status = SecOSStatusWith(^bool (CFErrorRef *error) {
283 return TRUSTD_XPC(sec_trust_store_copy_all, string_to_array_error, ts, &results, error);
284 });
285
286 *trustStoreContents = results;
287
288 errOut:
289 os_release(activity);
290 return status;
291 }
292
293 static bool string_data_to_array_error(enum SecXPCOperation op, SecTrustStoreRef ts, CFDataRef digest, CFArrayRef *usageConstraints, CFErrorRef *error)
294 {
295 return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
296 return SecXPCDictionarySetString(message, kSecXPCKeyDomain, (CFStringRef)ts, error) &&
297 SecXPCDictionarySetData(message, kSecXPCKeyDigest, digest, error);
298 }, ^bool(xpc_object_t response, CFErrorRef *error) {
299 return SecXPCDictionaryCopyArrayOptional(response, kSecXPCKeyResult, usageConstraints, error);
300 });
301 }
302
303 OSStatus SecTrustStoreCopyUsageConstraints(SecTrustStoreRef ts, SecCertificateRef certificate, CFArrayRef *usageConstraints)
304 {
305 CFDataRef digest;
306 __block CFArrayRef results = NULL;
307 OSStatus status = errSecParam;
308
309 os_activity_t activity = os_activity_create("SecTrustStoreCopyUsageConstraints", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
310 os_activity_scope(activity);
311 require(ts, errOut);
312 require(certificate, errOut);
313 require(digest = SecCertificateGetSHA1Digest(certificate), errOut);
314 require(usageConstraints, errOut);
315
316 status = SecOSStatusWith(^bool (CFErrorRef *error) {
317 return TRUSTD_XPC(sec_trust_store_copy_usage_constraints, string_data_to_array_error, ts, digest, &results, error);
318 });
319
320 *usageConstraints = results;
321
322 errOut:
323 os_release(activity);
324 return status;
325 }