]> git.saurik.com Git - apple/security.git/blob - Security/sec/Security/SecAccessControl.c
357c0b29f21c16a3712e16216cdaf97f24f57120
[apple/security.git] / Security / sec / Security / SecAccessControl.c
1 /*
2 * Copyright (c) 2014 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 * SecAccessControl.c - CoreFoundation based access control object
26 */
27
28 #include <AssertMacros.h>
29 #include <Security/SecAccessControl.h>
30 #include <Security/SecAccessControlPriv.h>
31 #include <Security/SecItem.h>
32 #include <utilities/SecCFWrappers.h>
33 #include <utilities/SecCFError.h>
34 #include <utilities/der_plist.h>
35
36 #if TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR)
37 #define USE_KEYSTORE 1
38 #elif TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR
39 #define USE_KEYSTORE 1
40 #else /* no keystore on this platform */
41 #define USE_KEYSTORE 0
42 #endif
43
44 #include <libaks_acl_cf_keys.h>
45
46 static CFTypeRef kSecAccessControlKeyProtection = CFSTR("prot");
47
48 // TODO: Use real name of this policy from SCred/AppleCredentialManager
49 CFTypeRef kSecAccessControlPolicyUserPresent = CFSTR("DeviceOwnerAuthenticated");
50
51 struct __SecAccessControl {
52 CFRuntimeBase _base;
53 CFMutableDictionaryRef dict;
54 };
55
56 static CFStringRef SecAccessControlCopyDescription(CFTypeRef cf) {
57 SecAccessControlRef access_control = (SecAccessControlRef)cf;
58 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<SecAccessControlRef: %p>"), access_control);
59 }
60
61 static Boolean SecAccessControlCompare(CFTypeRef lhs, CFTypeRef rhs) {
62 SecAccessControlRef laccess_control = (SecAccessControlRef)lhs;
63 SecAccessControlRef raccess_control = (SecAccessControlRef)rhs;
64 return (laccess_control == raccess_control) || CFEqual(laccess_control->dict, raccess_control->dict);
65 }
66
67 static void SecAccessControlDestroy(CFTypeRef cf) {
68 SecAccessControlRef access_control = (SecAccessControlRef)cf;
69 CFReleaseSafe(access_control->dict);
70 }
71
72 CFGiblisWithCompareFor(SecAccessControl);
73
74 SecAccessControlRef SecAccessControlCreate(CFAllocatorRef allocator, CFErrorRef *error) {
75 SecAccessControlRef access_control = CFTypeAllocate(SecAccessControl, struct __SecAccessControl, allocator);
76 if (!access_control) {
77 SecError(errSecAllocate, error, CFSTR("allocate memory for SecAccessControl"));
78 return NULL;
79 }
80
81 access_control->dict = CFDictionaryCreateMutableForCFTypes(allocator);
82 return access_control;
83 }
84
85
86 SecAccessControlRef SecAccessControlCreateWithFlags(CFAllocatorRef allocator, CFTypeRef protection,
87 SecAccessControlCreateFlags flags, CFErrorRef *error) {
88 SecAccessControlRef access_control = NULL;
89 CFTypeRef constraint = NULL;
90
91 require_quiet(access_control = SecAccessControlCreate(allocator, error), errOut);
92
93 if (!SecAccessControlSetProtection(access_control, protection, error))
94 goto errOut;
95
96 if (flags & kSecAccessControlUserPresence) {
97 require_quiet(constraint = SecAccessConstraintCreatePolicy(kSecAccessControlPolicyUserPresent, error), errOut);
98 require_quiet(SecAccessControlAddConstraintForOperation(access_control, kAKSKeyOpDecrypt,
99 constraint, error), errOut);
100 CFReleaseNull(constraint);
101 require_quiet(SecAccessControlAddConstraintForOperation(access_control, kAKSKeyOpDelete, kCFBooleanTrue, error), errOut);
102 }
103
104 return access_control;
105
106 errOut:
107 CFReleaseSafe(access_control);
108 CFReleaseSafe(constraint);
109 return NULL;
110 }
111
112 CFTypeRef SecAccessControlGetProtection(SecAccessControlRef access_control) {
113 return CFDictionaryGetValue(access_control->dict, kSecAccessControlKeyProtection);
114 }
115
116 static bool checkItemInArray(CFTypeRef item, const CFTypeRef *values, CFIndex count, CFStringRef errMessage, CFErrorRef *error) {
117 for (CFIndex i = 0; i < count; i++) {
118 if (CFEqualSafe(item, values[i])) {
119 return true;
120 }
121 }
122 return SecError(errSecParam, error, errMessage, item);
123 }
124
125 #define CheckItemInArray(item, values, msg) \
126 { \
127 const CFTypeRef vals[] = values; \
128 if (!checkItemInArray(item, vals, sizeof(vals)/sizeof(*vals), CFSTR(msg), error)) { \
129 return false; \
130 } \
131 }
132
133 #define ItemArray(...) { __VA_ARGS__ }
134
135
136 bool SecAccessControlSetProtection(SecAccessControlRef access_control, CFTypeRef protection, CFErrorRef *error) {
137 // Verify protection type.
138 CheckItemInArray(protection, ItemArray(kSecAttrAccessibleAlways, kSecAttrAccessibleAfterFirstUnlock,
139 kSecAttrAccessibleWhenUnlocked, kSecAttrAccessibleAlwaysThisDeviceOnly,
140 kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
141 kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
142 kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly),
143 "SecAccessControl: invalid protection %@");
144
145 // Protection valid, use it.
146 CFDictionarySetValue(access_control->dict, kSecAccessControlKeyProtection, protection);
147 return true;
148 }
149
150 SecAccessConstraintRef SecAccessConstraintCreatePolicy(CFTypeRef policy, CFErrorRef *error) {
151 return CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kAKSKeyAclConstraintPolicy, policy, NULL);
152 }
153
154 SecAccessConstraintRef SecAccessConstraintCreatePasscode(bool systemPasscode) {
155 return CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kAKSKeyAclConstraintUserPasscode, kCFBooleanTrue, NULL);
156 }
157
158 SecAccessConstraintRef SecAccessConstraintCreateTouchID(CFDataRef uuid, CFErrorRef *error) {
159 return CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kAKSKeyAclConstraintBio,
160 uuid ? uuid : (const void *)kCFBooleanTrue, NULL);
161 }
162
163 SecAccessConstraintRef SecAccessConstraintCreateKofN(size_t numRequired, CFArrayRef constraints, CFErrorRef *error) {
164 CFNumberRef k = CFNumberCreateWithCFIndex(kCFAllocatorDefault, numRequired);
165 CFMutableDictionaryRef kofn = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kAKSKeyAclParamKofN, k, NULL);
166 CFRelease(k);
167
168 /* Populate kofn dictionary with constraint keys from the array. note that for now we just ignore any additional
169 constraint parameters, but we might err-out if some parameter is found, since we cannot propagate parameteres
170 into k-of-n dictionary. */
171 const CFTypeRef keysToCopy[] = { kAKSKeyAclConstraintBio, kAKSKeyAclConstraintPolicy,
172 kAKSKeyAclConstraintUserPasscode };
173 SecAccessConstraintRef constraint;
174 CFArrayForEachC(constraints, constraint) {
175 require_quiet(isDictionary(constraint), errOut);
176 bool found = false;
177 for (CFIndex i = 0; i < (CFIndex)(sizeof(keysToCopy) / sizeof(keysToCopy[0])); i++) {
178 CFTypeRef value = CFDictionaryGetValue(constraint, keysToCopy[i]);
179 if (value) {
180 CFDictionarySetValue(kofn, keysToCopy[i], value);
181 found = true;
182 break;
183 }
184 }
185 require_quiet(found, errOut);
186 }
187
188 constraint = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kAKSKeyAclConstraintKofN, kofn, NULL);
189 CFRelease(kofn);
190 return constraint;
191
192 errOut:
193 SecError(errSecParam, error, CFSTR("SecAccessControl: invalid constraint for k-of-n"));
194 CFReleaseSafe(kofn);
195 return NULL;
196 }
197
198 bool SecAccessConstraintSetOption(SecAccessConstraintRef constraint, CFTypeRef option, CFTypeRef value, CFErrorRef *error) {
199 CheckItemInArray(option, ItemArray(kAKSKeyAclConstraintAccessGroups, kAKSKeyAclParamCredentialMaxAge),
200 "SecAccessControl: invalid constraint option %@");
201 CFDictionarySetValue((CFMutableDictionaryRef)constraint, option, value);
202 return true;
203 }
204
205 bool SecAccessControlAddConstraintForOperation(SecAccessControlRef access_control, CFTypeRef operation, CFTypeRef constraint, CFErrorRef *error) {
206 CheckItemInArray(operation, ItemArray(kAKSKeyOpEncrypt, kAKSKeyOpDecrypt,
207 kAKSKeyOpSync, kAKSKeyOpDefaultAcl, kAKSKeyOpDelete),
208 "SecAccessControl: invalid operation %@");
209 if (!isDictionary(constraint) && !CFEqual(constraint, kCFBooleanTrue) && !CFEqual(constraint, kCFBooleanFalse) ) {
210 return SecError(errSecParam, error, CFSTR("invalid constraint"));
211 }
212
213 CFMutableDictionaryRef ops = (CFMutableDictionaryRef)CFDictionaryGetValue(access_control->dict, kAKSKeyAcl);
214 if (!ops) {
215 ops = CFDictionaryCreateMutableForCFTypes(CFGetAllocator(access_control));
216 CFDictionarySetValue(access_control->dict, kAKSKeyAcl, ops);
217 }
218 CFDictionarySetValue(ops, operation, constraint);
219 return true;
220 }
221
222 void SecAccessControlRemoveConstraintForOperation(SecAccessControlRef access_control, CFTypeRef operation) {
223 CFMutableDictionaryRef ops = (CFMutableDictionaryRef)CFDictionaryGetValue(access_control->dict, kAKSKeyAcl);
224 if (ops)
225 CFDictionaryRemoveValue(ops, operation);
226 }
227
228 SecAccessConstraintRef SecAccessControlGetConstraint(SecAccessControlRef access_control, CFTypeRef operation) {
229 CFMutableDictionaryRef ops = (CFMutableDictionaryRef)CFDictionaryGetValue(access_control->dict, kAKSKeyAcl);
230 if (!ops || CFDictionaryGetCount(ops) == 0)
231 // No ACL is present, this means that everything is allowed.
232 return kCFBooleanTrue;
233
234 SecAccessConstraintRef constraint = CFDictionaryGetValue(ops, operation);
235 if (!constraint) {
236 constraint = CFDictionaryGetValue(ops, kAKSKeyOpDefaultAcl);
237 }
238 return constraint;
239 }
240
241 CFDictionaryRef SecAccessControlGetConstraints(SecAccessControlRef access_control) {
242 return CFDictionaryGetValue(access_control->dict, kAKSKeyAcl);
243 }
244
245 void SecAccessControlSetConstraints(SecAccessControlRef access_control, CFDictionaryRef constraints) {
246 CFMutableDictionaryRef mutableConstraints = CFDictionaryCreateMutableCopy(NULL, 0, constraints);
247 CFDictionarySetValue(access_control->dict, kAKSKeyAcl, mutableConstraints);
248 CFReleaseSafe(mutableConstraints);
249 }
250
251 void SecAccessControlSetAccessGroups(SecAccessControlRef access_control, CFArrayRef access_groups) {
252 CFMutableDictionaryRef ops = (CFMutableDictionaryRef)CFDictionaryGetValue(access_control->dict, kAKSKeyAcl);
253 if (!ops) {
254 ops = CFDictionaryCreateMutableForCFTypes(CFGetAllocator(access_control));
255 CFDictionarySetValue(access_control->dict, kAKSKeyAcl, ops);
256 }
257 CFDictionarySetValue(ops, kAKSKeyAccessGroups, access_groups);
258 }
259
260 CFArrayRef SecAccessControlGetAccessGroups(SecAccessControlRef access_control, CFTypeRef operation) {
261 CFMutableDictionaryRef ops = (CFMutableDictionaryRef)CFDictionaryGetValue(access_control->dict, kAKSKeyAcl);
262 if (!ops)
263 return NULL;
264
265 CFArrayRef access_groups = NULL;
266 SecAccessConstraintRef constraint = CFDictionaryGetValue(ops, operation);
267 if (!constraint) {
268 constraint = CFDictionaryGetValue(ops, kAKSKeyOpDefaultAcl);
269 }
270 if (constraint && isDictionary(constraint)) {
271 access_groups = CFDictionaryGetValue(constraint, kAKSKeyAclConstraintAccessGroups);
272 }
273 if (!access_groups) {
274 access_groups = CFDictionaryGetValue(ops, kAKSKeyAccessGroups);
275 }
276 return access_groups;
277 }
278
279 CFDataRef SecAccessControlCopyData(SecAccessControlRef access_control) {
280 size_t len = der_sizeof_plist(access_control->dict, NULL);
281 CFMutableDataRef encoded = CFDataCreateMutable(0, len);
282 CFDataSetLength(encoded, len);
283 uint8_t *der_end = CFDataGetMutableBytePtr(encoded);
284 const uint8_t *der = der_end;
285 der_end += len;
286 der_end = der_encode_plist(access_control->dict, NULL, der, der_end);
287 if (!der_end) {
288 CFReleaseNull(encoded);
289 }
290 return encoded;
291 }
292
293 SecAccessControlRef SecAccessControlCreateFromData(CFAllocatorRef allocator, CFDataRef data, CFErrorRef *error) {
294 SecAccessControlRef access_control;
295 require_quiet(access_control = SecAccessControlCreate(allocator, error), errOut);
296
297 CFPropertyListRef plist;
298 const uint8_t *der = CFDataGetBytePtr(data);
299 const uint8_t *der_end = der + CFDataGetLength(data);
300 require_quiet(der = der_decode_plist(0, kCFPropertyListMutableContainers, &plist, error, der, der_end), errOut);
301 if (der != der_end) {
302 SecError(errSecDecode, error, CFSTR("trailing garbage at end of SecAccessControl data"));
303 goto errOut;
304 }
305
306 CFReleaseSafe(access_control->dict);
307 access_control->dict = (CFMutableDictionaryRef)plist;
308 return access_control;
309
310 errOut:
311 CFReleaseSafe(access_control);
312 return NULL;
313 }