]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/Regressions/secitem/si_77_SecAccessControl.c
Security-57337.40.85.tar.gz
[apple/security.git] / OSX / sec / Security / Regressions / secitem / si_77_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 #include <Security/SecItem.h>
26 #include <Security/SecAccessControl.h>
27 #include <Security/SecAccessControlPriv.h>
28 #include <Security/SecInternal.h>
29 #include <utilities/SecCFWrappers.h>
30 #include <utilities/array_size.h>
31 #include <utilities/der_plist.h>
32 #include <libaks_acl_cf_keys.h>
33 #include <ACMDefs.h>
34 #include <ACMAclDefs.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 #if USE_KEYSTORE
45 #include <Security/SecRandom.h>
46 #include <securityd/SecDbItem.h>
47 #include <coreauthd_spi.h>
48 #include <corecrypto/ccder.h>
49 #endif
50
51 #include "Security_regressions.h"
52
53 static CFTypeRef kSecAccessControlKeyProtection = CFSTR("prot");
54
55 #if LA_CONTEXT_IMPLEMENTED
56 static bool aks_consistency_test(bool currentAuthDataFormat, kern_return_t expectedAksResult, SecAccessControlRef access_control, CFDataRef acm_context);
57 static CFDataRef kc_create_auth_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes);
58 static CFDataRef kc_copy_constraints_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes);
59 static int aks_crypt_acl(CFTypeRef operation, keybag_handle_t keybag,
60 keyclass_t keyclass, uint32_t textLength, const uint8_t *source,
61 CFMutableDataRef dest, CFDataRef auth_data, CFDataRef acm_context, CFDataRef caller_access_groups);
62 #endif
63
64 static void tests(void)
65 {
66 CFAllocatorRef allocator = kCFAllocatorDefault;
67 CFTypeRef protection = kSecAttrAccessibleAlways;
68 CFErrorRef error = NULL;
69
70 // Simple API tests:
71
72 // ACL with protection only
73 SecAccessControlRef acl = SecAccessControlCreateWithFlags(allocator, protection, 0, &error);
74 ok(acl != NULL, "SecAccessControlCreateWithFlags: %@", error);
75 CFReleaseNull(error);
76 CFReleaseNull(acl);
77
78 // ACL with flags only (not allowed)
79 #pragma clang diagnostic push
80 #pragma clang diagnostic ignored "-Wnonnull"
81 // NULL passed as 'protection' newly generates a warning, we need to suppress it in order to compile
82 acl = SecAccessControlCreateWithFlags(allocator, NULL, kSecAccessControlUserPresence, &error);
83 #pragma clang diagnostic pop
84 ok(acl == NULL, "SecAccessControlCreateWithFlags");
85 CFReleaseNull(error);
86 CFReleaseNull(acl);
87
88 // ACL with protection and kSecAccessControlTouchIDCurrentSet
89 acl = SecAccessControlCreateWithFlags(allocator, protection, kSecAccessControlTouchIDCurrentSet, &error);
90 ok(acl != NULL, "SecAccessControlCreateWithFlags: %@", error);
91 CFReleaseNull(error);
92 CFReleaseNull(acl);
93
94 // ACL with protection and flags
95 acl = SecAccessControlCreateWithFlags(allocator, protection, kSecAccessControlTouchIDAny | kSecAccessControlDevicePasscode | kSecAccessControlOr, &error);
96 ok(acl != NULL, "SecAccessControlCreateWithFlags: %@", error);
97 CFReleaseNull(error);
98 CFReleaseNull(acl);
99
100 // ACL with protection and flags
101 acl = SecAccessControlCreateWithFlags(allocator, protection, kSecAccessControlTouchIDAny | kSecAccessControlDevicePasscode | kSecAccessControlAnd, &error);
102 ok(acl != NULL, "SecAccessControlCreateWithFlags: %@", error);
103 CFReleaseNull(error);
104 CFReleaseNull(acl);
105
106 // ACL with protection and flags
107 acl = SecAccessControlCreateWithFlags(allocator, protection, kSecAccessControlTouchIDAny | kSecAccessControlDevicePasscode | kSecAccessControlAnd | kSecAccessControlApplicationPassword, &error);
108 ok(acl != NULL, "SecAccessControlCreateWithFlags: %@", error);
109 CFReleaseNull(error);
110 CFReleaseNull(acl);
111
112 // ACL with protection and kSecAccessControlApplicationPassword
113 acl = SecAccessControlCreateWithFlags(allocator, protection, kSecAccessControlApplicationPassword, &error);
114 ok(acl != NULL, "SecAccessControlCreateWithFlags: %@", error);
115 CFReleaseNull(error);
116 CFReleaseNull(acl);
117
118 // ACL with protection and, kSecAccessControlUserPresence can be in combination with kSecAccessControlApplicationPassword and kSecAccessControlPrivateKeyUsage
119 acl = SecAccessControlCreateWithFlags(allocator, protection, kSecAccessControlUserPresence | kSecAccessControlApplicationPassword | kSecAccessControlPrivateKeyUsage, &error);
120 ok(acl != NULL, "SecAccessControlCreateWithFlags: %@", error);
121 CFReleaseNull(error);
122 CFReleaseNull(acl);
123
124 // negative test of ACL with protection and, kSecAccessControlUserPresence can be in combination with kSecAccessControlApplicationPassword and kSecAccessControlPrivateKeyUsage
125 acl = SecAccessControlCreateWithFlags(allocator, protection, kSecAccessControlUserPresence | kSecAccessControlTouchIDAny, &error);
126 ok(acl == NULL, "SecAccessControlCreateWithFlag wrong combination of flags");
127 CFReleaseNull(error);
128 CFReleaseNull(acl);
129
130 // ACL with protection and flags
131 acl = SecAccessControlCreateWithFlags(allocator, protection, kSecAccessControlUserPresence, &error);
132 ok(acl != NULL, "SecAccessControlCreateWithFlags: %@", error);
133 CFReleaseNull(error);
134
135 // Extended API tests:
136
137 // Check created ACL
138 CFTypeRef aclProtection = SecAccessControlGetProtection(acl);
139 is(aclProtection, protection, "SecAccessControlGetProtection");
140
141 SecAccessConstraintRef aclConstraint = SecAccessControlGetConstraint(acl, kAKSKeyOpDecrypt);
142 // Check created ACL
143 ok(aclConstraint != NULL && isDictionary(aclConstraint), "SecAccessControlGetConstraint");
144 eq_cf(CFDictionaryGetValue(aclConstraint, CFSTR(kACMKeyAclConstraintPolicy)), CFSTR(kACMPolicyDeviceOwnerAuthentication), "SecAccessControlGetConstraint");
145
146 CFReleaseNull(acl);
147
148 // Simple SPI tests:
149
150 // Empty ACL
151 acl = SecAccessControlCreate(allocator, &error);
152 ok(acl != NULL, "SecAccessControlCreate: %@", error);
153 CFReleaseNull(error);
154
155 // ACL protection
156 bool result = SecAccessControlSetProtection(acl, protection, &error);
157 ok(result, "SecAccessControlSetProtection: %@", error);
158 CFReleaseNull(error);
159
160 aclProtection = SecAccessControlGetProtection(acl);
161 // ACL protection
162 is(aclProtection, protection, "SecAccessControlGetProtection");
163
164 // Policy constraint
165 SecAccessConstraintRef policy = SecAccessConstraintCreatePolicy(allocator, CFSTR(kACMPolicyDeviceOwnerAuthentication), &error);
166 ok(policy != NULL, "SecAccessConstraintCreatePolicy: %@", error);
167 ok(isDictionary(policy), "SecAccessConstraintCreatePolicy");
168 is(CFDictionaryGetValue(policy, CFSTR(kACMKeyAclConstraintPolicy)), CFSTR(kACMPolicyDeviceOwnerAuthentication), "SecAccessConstraintCreatePolicy");
169 CFReleaseNull(error);
170 CFReleaseNull(policy);
171
172 // Passcode constraint
173 SecAccessConstraintRef passcode = SecAccessConstraintCreatePasscode(allocator);
174 ok(passcode != NULL && isDictionary(passcode), "SecAccessConstraintCreatePasscode");
175 is(CFDictionaryGetValue(passcode, CFSTR(kACMKeyAclConstraintUserPasscode)), kCFBooleanTrue, "SecAccessConstraintCreatePasscode");
176 // CFReleaseNull(passcode); passcode will be used in later tests
177
178 CFUUIDRef uuid = CFUUIDCreate(allocator);
179 CFStringRef uuidString = CFUUIDCreateString(allocator, uuid);
180 CFDataRef uuidData = CFStringCreateExternalRepresentation(allocator, uuidString, kCFStringEncodingUTF8, 0);
181 SecAccessConstraintRef touchID = SecAccessConstraintCreateTouchIDCurrentSet(allocator, uuidData, uuidData);
182 // TouchID constraint
183 ok(touchID != NULL, "SecAccessConstraintCreateTouchID: %@", error);
184 ok(isDictionary(touchID), "SecAccessConstraintCreateTouchID");
185 ok(CFDictionaryGetValue(touchID, CFSTR(kACMKeyAclConstraintBio)), "SecAccessConstraintCreateTouchID");
186 CFDictionaryRef bioRef = CFDictionaryGetValue(touchID, CFSTR(kACMKeyAclConstraintBio));
187 ok(isDictionary(bioRef), "SecAccessConstraintCreateTouchID");
188 is(CFDictionaryGetValue(bioRef, CFSTR(kACMKeyAclParamBioCatacombUUID)), uuidData, "SecAccessConstraintCreateTouchID");
189 is(CFDictionaryGetValue(bioRef, CFSTR(kACMKeyAclParamBioDatabaseHash)), uuidData, "SecAccessConstraintCreateTouchID");
190 CFReleaseNull(error);
191 CFReleaseNull(touchID);
192 CFReleaseNull(uuidData);
193 CFReleaseNull(uuidString);
194 CFReleaseNull(uuid);
195
196 uuid = CFUUIDCreate(allocator);
197 uuidString = CFUUIDCreateString(allocator, uuid);
198 uuidData = CFStringCreateExternalRepresentation(allocator, uuidString, kCFStringEncodingUTF8, 0);
199 touchID = SecAccessConstraintCreateTouchIDAny(allocator, uuidData);
200 // TouchID constraint
201 ok(touchID != NULL, "SecAccessConstraintCreateTouchID: %@", error);
202 ok(isDictionary(touchID), "SecAccessConstraintCreateTouchID");
203 ok(CFDictionaryGetValue(touchID, CFSTR(kACMKeyAclConstraintBio)), "SecAccessConstraintCreateTouchID");
204 bioRef = CFDictionaryGetValue(touchID, CFSTR(kACMKeyAclConstraintBio));
205 ok(isDictionary(bioRef), "SecAccessConstraintCreateTouchID");
206 is(CFDictionaryGetValue(bioRef, CFSTR(kACMKeyAclParamBioCatacombUUID)), uuidData, "SecAccessConstraintCreateTouchID");
207 CFReleaseNull(error);
208 // CFReleaseNull(touchID); touchID will be used in later tests
209 CFReleaseNull(uuidData);
210 CFReleaseNull(uuidString);
211 CFReleaseNull(uuid);
212
213 // KofN constraint
214 CFTypeRef constraints_array[] = { passcode, touchID };
215 CFArrayRef constraintsArray = CFArrayCreate(allocator, constraints_array, array_size(constraints_array), &kCFTypeArrayCallBacks);
216 SecAccessConstraintRef kofn = SecAccessConstraintCreateKofN(allocator, 1, constraintsArray, &error);
217 ok(kofn != NULL, "SecAccessConstraintCreateKofN: %@", error);
218 ok(isDictionary(kofn), "SecAccessConstraintCreateKofN");
219 CFTypeRef kofnConstraint = CFDictionaryGetValue(kofn, CFSTR(kACMKeyAclConstraintKofN));
220 ok(kofnConstraint != NULL && isDictionary(kofnConstraint), "SecAccessConstraintCreateKofN");
221 CFNumberRef required = CFNumberCreateWithCFIndex(allocator, 1);
222 is(CFDictionaryGetValue(kofnConstraint, CFSTR(kACMKeyAclParamKofN)), required, "SecAccessConstraintCreateKofN");
223 ok(CFDictionaryGetValue(kofnConstraint, CFSTR(kACMKeyAclConstraintBio)), "SecAccessConstraintCreateKofN");
224 is(CFDictionaryGetValue(kofnConstraint, CFSTR(kACMKeyAclConstraintUserPasscode)), kCFBooleanTrue, "SecAccessConstraintCreateKofN");
225 CFReleaseNull(error);
226 CFReleaseNull(kofn);
227 CFReleaseNull(required);
228 CFReleaseNull(constraintsArray);
229 CFReleaseNull(passcode);
230
231 // Add ACL constraint for operation
232 result = SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDecrypt, touchID, &error);
233 ok(result, "SecAccessControlAddConstraintForOperation: %@", error);
234 CFReleaseNull(error);
235
236 // Get ACL operation constraint
237 SecAccessConstraintRef constraint = SecAccessControlGetConstraint(acl, kAKSKeyOpDecrypt);
238 is(constraint, touchID, "SecAccessControlGetConstraint");
239 CFReleaseNull(touchID);
240
241 // Add ACL constraint for operation (kCFBooleanTrue)
242 result = SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDecrypt, kCFBooleanTrue, &error);
243 ok(result, "SecAccessControlAddConstraintForOperation: %@", error);
244 CFReleaseNull(error);
245
246 // Get ACL operation constraint (kCFBooleanTrue)
247 constraint = SecAccessControlGetConstraint(acl, kAKSKeyOpDecrypt);
248 is(constraint, kCFBooleanTrue, "SecAccessControlGetConstraint");
249
250 // Get ACL constraints
251 CFDictionaryRef constraints = SecAccessControlGetConstraints(acl);
252 ok(constraints != NULL && isDictionary(constraints), "SecAccessControlGetConstraints");
253 // Get ACL constraints
254 is(CFDictionaryGetValue(constraints, kAKSKeyOpDecrypt), kCFBooleanTrue, "SecAccessControlGetConstraints");
255
256 // ACL export and import
257 CFDataRef aclData = SecAccessControlCopyData(acl);
258 ok(aclData != NULL, "SecAccessControlCopyData");
259 SecAccessControlRef aclCopy = SecAccessControlCreateFromData(allocator, aclData, &error);
260 ok(aclCopy != NULL, "SecAccessControlCopyData: %@", error);
261 ok(CFEqual(aclCopy, acl), "SecAccessControlCopyData");
262 CFReleaseNull(error);
263 CFReleaseNull(aclCopy);
264 CFReleaseNull(aclData);
265
266 // Extended SPI tests:
267
268 // kAKSKeyDefaultOpAcl
269 result = SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDefaultAcl, kCFBooleanTrue, &error);
270 ok(result, "SecAccessControlAddConstraintForOperation: %@", error);
271 constraint = SecAccessControlGetConstraint(acl, kAKSKeyOpDecrypt);
272 is(constraint, kCFBooleanTrue, "SecAccessControlRemoveConstraintForOperation");
273 CFReleaseNull(error);
274
275 CFReleaseNull(acl);
276
277 #if LA_CONTEXT_IMPLEMENTED
278 // AKS consistency test:
279
280 acl = SecAccessControlCreateWithFlags(allocator, protection, kSecAccessControlUserPresence, &error);
281 ok(acl != NULL, "SecAccessControlCreateWithFlags: %@", error);
282 CFReleaseNull(error);
283
284 SKIP: {
285 skip("SecAccessControlCreateWithFlags failed", 7, acl != NULL);
286
287 CFDataRef acm_context = NULL;
288 CFTypeRef auth_handle = NULL;
289
290 auth_handle = LACreateNewContextWithACMContext(NULL, &error);
291 ok(auth_handle != NULL, "LACreateNewContextWithACMContext: %@", error);
292 CFReleaseNull(error);
293
294 SKIP: {
295 skip("LACreateNewContextWithACMContext failed", 6, auth_handle != NULL);
296
297 acm_context = LACopyACMContext(auth_handle, &error);
298 ok(acm_context != NULL, "LACopyACMContext: %@", error);
299 CFReleaseNull(error);
300
301 CFReleaseNull(auth_handle);
302
303 SKIP: {
304 skip("LACopyACMContext failed", 5, acm_context != NULL);
305
306 ok(aks_consistency_test(true, kAKSReturnPolicyError, acl, acm_context), "AKS consistency negative test (current auth_data format)");
307 ok(aks_consistency_test(false, kAKSReturnPolicyError, acl, acm_context), "AKS consistency negative test (old auth_data format)");
308
309 bool decrypt_enabled = false;
310 CFDictionaryRef constraints = SecAccessControlGetConstraints(acl);
311 if (constraints) {
312 CFMutableDictionaryRef new_constraints = CFDictionaryCreateMutableCopy(NULL, 0, constraints);
313 if (new_constraints) {
314 CFDictionarySetValue(new_constraints, kAKSKeyOpDecrypt, kCFBooleanTrue);
315 SecAccessControlSetConstraints(acl, new_constraints);
316 CFReleaseSafe(new_constraints);
317 decrypt_enabled = true;
318 }
319 }
320 ok(decrypt_enabled, "Cannot enable decrypt operation for AKS consistency positive tests");
321
322 ok(aks_consistency_test(true, kAKSReturnSuccess, acl, acm_context), "AKS consistency positive test (current auth_data format)");
323 ok(aks_consistency_test(false, kAKSReturnSuccess, acl, acm_context), "AKS consistency positive test (old auth_data format)");
324
325 CFReleaseNull(acm_context);
326 }
327 }
328
329 CFReleaseNull(acl);
330 }
331 #endif
332
333 // kSecAccessControlPrivateKeyUsage
334 acl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, protection, kSecAccessControlPrivateKeyUsage | kSecAccessControlDevicePasscode, NULL);
335 ok(acl, "kSecAccessControlPrivateKeyUsage ACL create with constraint");
336 ok(!SecAccessControlGetConstraint(acl, kAKSKeyOpEncrypt), "kAKSKeyOpEncrypt constraint");
337 ok(!SecAccessControlGetConstraint(acl, kAKSKeyOpDecrypt), "kAKSKeyOpDecrypt constraint");
338 ok(constraint = SecAccessControlGetConstraint(acl, kAKSKeyOpDelete), "kAKSKeyOpDelete constraint");
339 is(constraint, kCFBooleanTrue, "kAKSKeyOpDelete constraint value");
340 ok(constraint = SecAccessControlGetConstraint(acl, kAKSKeyOpSign), "kAKSKeyOpSign constraint");
341 ok(constraint && isDictionary(constraint), "kAKSKeyOpSign constraint value");
342 CFReleaseNull(acl);
343
344 acl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, protection, kSecAccessControlPrivateKeyUsage, NULL);
345 ok(acl, "kSecAccessControlPrivateKeyUsage ACL create without constraint");
346 ok(!SecAccessControlGetConstraint(acl, kAKSKeyOpEncrypt), "kAKSKeyOpEncrypt constraint");
347 ok(!SecAccessControlGetConstraint(acl, kAKSKeyOpDecrypt), "kAKSKeyOpDecrypt constraint");
348 ok(constraint = SecAccessControlGetConstraint(acl, kAKSKeyOpDelete), "kAKSKeyOpDelete constraint");
349 is(constraint, kCFBooleanTrue, "kAKSKeyOpDelete constraint value");
350 ok(constraint = SecAccessControlGetConstraint(acl, kAKSKeyOpSign), "kAKSKeyOpSign constraint");
351 is(constraint, kCFBooleanTrue, "kAKSKeyOpSign constraint value");
352 CFReleaseNull(acl);
353 }
354
355 #if LA_CONTEXT_IMPLEMENTED
356
357 static bool aks_consistency_test(bool currentAuthDataFormat, kern_return_t expectedAksResult, SecAccessControlRef access_control, CFDataRef acm_context)
358 {
359 bool result = false;
360
361 const uint32_t bulkKeySize = 32;
362 const uint32_t maxKeyWrapOverHead = 8 + 32;
363 uint8_t bulkKey[bulkKeySize];
364 CFMutableDataRef bulkKeyWrapped = CFDataCreateMutable(NULL, 0);
365 CFDataSetLength(bulkKeyWrapped, bulkKeySize + maxKeyWrapOverHead);
366 CFMutableDataRef bulkKeyUnwrapped = CFDataCreateMutable(NULL, 0);
367 CFDataSetLength(bulkKeyUnwrapped, bulkKeySize);
368
369 CFDataRef auth_data = NULL;
370 CFMutableDictionaryRef auth_attribs = NULL;
371
372 require_noerr_string(SecRandomCopyBytes(kSecRandomDefault, bulkKeySize, bulkKey), out, "SecRandomCopyBytes failed");
373
374 auth_attribs = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
375 if (currentAuthDataFormat) {
376 auth_data = kc_create_auth_data(access_control, auth_attribs);
377 }
378 else {
379 auth_data = kc_copy_constraints_data(access_control, auth_attribs);
380 }
381
382 require_string(aks_crypt_acl(kAKSKeyOpEncrypt, KEYBAG_DEVICE, key_class_dk, bulkKeySize, bulkKey, bulkKeyWrapped,
383 auth_data, acm_context, NULL) == kAKSReturnSuccess, out, "kAKSKeyOpEncrypt failed");
384
385 uint32_t blobLenWrapped = (uint32_t)CFDataGetLength(bulkKeyWrapped);
386 const uint8_t *cursor = CFDataGetBytePtr(bulkKeyWrapped);
387
388 require_string(aks_crypt_acl(kAKSKeyOpDecrypt, KEYBAG_DEVICE, key_class_dk, blobLenWrapped, cursor, bulkKeyUnwrapped,
389 auth_data, acm_context, NULL) == expectedAksResult, out, "kAKSKeyOpDecrypt finished with unexpected result");
390
391 result = true;
392
393 out:
394 CFReleaseSafe(bulkKeyUnwrapped);
395 CFReleaseSafe(bulkKeyWrapped);
396 CFReleaseSafe(auth_data);
397 CFReleaseSafe(auth_attribs);
398
399 return result;
400 }
401
402 static bool merge_der_in_to_data(const void *der1, size_t der1_len, const void *der2, size_t der2_len, CFMutableDataRef mergedData)
403 {
404 bool result = false;
405 CFPropertyListRef dict1 = NULL;
406 CFPropertyListRef dict2 = NULL;
407
408 der_decode_plist(NULL, kCFPropertyListImmutable, &dict1, NULL, der1, der1 + der1_len);
409 der_decode_plist(NULL, kCFPropertyListImmutable, &dict2, NULL, der2, der2 + der2_len);
410 if (dict1 && dict2) {
411 CFMutableDictionaryRef result_dict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict1);
412 CFDictionaryForEach(dict2, ^(const void *key, const void *value) {
413 CFDictionaryAddValue(result_dict, key, value);
414 });
415
416 CFDataSetLength(mergedData, 0);
417 CFDataRef der_data = CFPropertyListCreateDERData(kCFAllocatorDefault, result_dict, NULL);
418 if (der_data) {
419 CFDataAppend(mergedData, der_data);
420 CFRelease(der_data);
421 result = CFDataGetLength(mergedData) > 0;
422 }
423 CFRelease(result_dict);
424 }
425
426 CFReleaseSafe(dict1);
427 CFReleaseSafe(dict2);
428 return result;
429 }
430
431 static int aks_crypt_acl(CFTypeRef operation, keybag_handle_t keybag,
432 keyclass_t keyclass, uint32_t textLength, const uint8_t *source,
433 CFMutableDataRef dest, CFDataRef auth_data, CFDataRef acm_context, CFDataRef caller_access_groups)
434 {
435 int aks_return = kAKSReturnSuccess;
436 void *params = NULL, *der = NULL;
437 const uint8_t *access_groups = caller_access_groups?CFDataGetBytePtr(caller_access_groups):NULL;
438 size_t params_len = 0, der_len = 0, access_groups_len = caller_access_groups?CFDataGetLength(caller_access_groups):0;
439 aks_ref_key_t key_handle = NULL;
440
441 if (CFEqual(operation, kAKSKeyOpEncrypt)) {
442 aks_operation_optional_params(0, 0, CFDataGetBytePtr(auth_data), CFDataGetLength(auth_data),
443 CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), &params, &params_len);
444
445 require_noerr_quiet(aks_return = aks_ref_key_create(keybag, keyclass, key_type_sym, params, params_len, &key_handle), out);
446 require_noerr_quiet(aks_return = aks_ref_key_encrypt(key_handle, params, params_len, source, textLength, &der, &der_len), out);
447 size_t key_blob_len;
448 const void *key_blob = aks_ref_key_get_blob(key_handle, &key_blob_len);
449 require_action_string(key_blob, out, aks_return = kAKSReturnError, "aks_ref_key_get_blob failed");
450 require_action_string(merge_der_in_to_data(der, der_len, key_blob, key_blob_len, dest), out, aks_return = kAKSReturnError, "merge_der_in_to_data failed");
451
452 } else if (CFEqual(operation, kAKSKeyOpDecrypt)) {
453 aks_operation_optional_params(access_groups, access_groups_len, 0, 0,
454 CFDataGetBytePtr(acm_context), (int)CFDataGetLength(acm_context), (void**)&params, &params_len);
455 require_noerr_quiet(aks_return = aks_ref_key_create_with_blob(keybag, source, textLength, &key_handle), out);
456 require_noerr_quiet(aks_return = aks_ref_key_decrypt(key_handle, params, params_len, source, textLength, &der, &der_len), out);
457 require_action_string(der, out, aks_return = kAKSReturnError, "aks_ref_key_decrypt failed");
458
459 CFPropertyListRef decoded_data = NULL;
460 der_decode_plist(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_data, NULL, der, der + der_len);
461 require_action_string(decoded_data, out, aks_return = kAKSReturnError, "der_decode_plist failed");
462 if (CFGetTypeID(decoded_data) == CFDataGetTypeID()) {
463 CFDataSetLength(dest, 0);
464 CFDataAppend(dest, decoded_data);
465 CFRelease(decoded_data);
466 }
467 else {
468 CFRelease(decoded_data);
469 require_action_string(false, out, aks_return = kAKSReturnError, "wrong decoded data type");
470 }
471 }
472
473 out:
474 if (key_handle) {
475 aks_ref_key_free(&key_handle);
476 }
477 if (params) {
478 free(params);
479 }
480 if (der) {
481 free(der);
482 }
483 return aks_return;
484 }
485
486 static CFDataRef kc_create_auth_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes)
487 {
488 CFDictionaryRef constraints = SecAccessControlGetConstraints(access_control);
489 CFMutableDictionaryRef auth_data = CFDictionaryCreateMutableCopy(NULL, 0, auth_attributes);
490 CFDictionarySetValue(auth_data, kAKSKeyAcl, constraints);
491 CFDataRef encoded = CFPropertyListCreateDERData(kCFAllocatorDefault, auth_data, NULL);
492 CFReleaseSafe(auth_data);
493 return encoded;
494 }
495
496 static CFDataRef kc_copy_constraints_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes)
497 {
498 CFDictionaryRef constraints = SecAccessControlGetConstraints(access_control);
499 CFMutableDictionaryRef auth_data = CFDictionaryCreateMutableCopy(NULL, 0, constraints);
500 if (auth_attributes) {
501 CFDictionaryForEach(auth_attributes, ^(const void *key, const void *value) {
502 CFDictionaryAddValue(auth_data, key, value);
503 });
504 }
505
506 CFDataRef encoded = CFPropertyListCreateDERData(kCFAllocatorDefault, auth_data, NULL);
507 CFReleaseSafe(auth_data);
508 return encoded;
509 }
510
511 #endif
512
513 int si_77_SecAccessControl(int argc, char *const *argv)
514 {
515 #if LA_CONTEXT_IMPLEMENTED
516 plan_tests(71);
517 #else
518 plan_tests(63);
519 #endif
520
521 tests();
522
523 return 0;
524 }