2 * Copyright (c) 2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <Security/SecItem.h>
26 #include <Security/SecItemPriv.h>
27 #include <Security/SecAccessControl.h>
28 #include <Security/SecAccessControlPriv.h>
29 #include <Security/SecInternal.h>
30 #include <utilities/SecCFWrappers.h>
31 #include <utilities/SecAKSWrappers.h>
32 #include <utilities/array_size.h>
33 #include <utilities/der_plist.h>
34 #include <libaks_acl_cf_keys.h>
36 #include <ACMAclDefs.h>
38 #if TARGET_HAS_KEYSTORE
39 #include <Security/SecRandom.h>
40 #include "keychain/securityd/SecDbItem.h"
41 #include <coreauthd_spi.h>
42 #include <corecrypto/ccder.h>
43 #endif /* TARGET_HAS_KEYSTORE */
45 #include "Security_regressions.h"
47 #if LA_CONTEXT_IMPLEMENTED && TARGET_HAS_KEYSTORE
48 static bool aks_consistency_test(bool currentAuthDataFormat
, kern_return_t expectedAksResult
, SecAccessControlRef access_control
, CFDataRef acm_context
);
49 static CFDataRef
kc_create_auth_data(SecAccessControlRef access_control
, CFDictionaryRef auth_attributes
);
50 static CFDataRef
kc_copy_constraints_data(SecAccessControlRef access_control
, CFDictionaryRef auth_attributes
);
51 static int aks_crypt_acl(CFTypeRef operation
, keybag_handle_t keybag
,
52 keyclass_t keyclass
, uint32_t textLength
, const uint8_t *source
,
53 CFMutableDataRef dest
, CFDataRef auth_data
, CFDataRef acm_context
, CFDataRef caller_access_groups
);
56 static void tests(void)
58 CFAllocatorRef allocator
= kCFAllocatorDefault
;
59 CFTypeRef protection
= kSecAttrAccessibleAlwaysPrivate
;
60 CFErrorRef error
= NULL
;
64 // ACL with protection only
65 SecAccessControlRef acl
= SecAccessControlCreateWithFlags(allocator
, protection
, 0, &error
);
66 ok(acl
!= NULL
, "SecAccessControlCreateWithFlags: %@", error
);
70 // ACL with flags only (not allowed)
71 #pragma clang diagnostic push
72 #pragma clang diagnostic ignored "-Wnonnull"
73 // NULL passed as 'protection' newly generates a warning, we need to suppress it in order to compile
74 acl
= SecAccessControlCreateWithFlags(allocator
, NULL
, kSecAccessControlUserPresence
, &error
);
75 #pragma clang diagnostic pop
76 ok(acl
== NULL
, "SecAccessControlCreateWithFlags");
80 // ACL with protection and kSecAccessControlBiometryCurrentSet
81 acl
= SecAccessControlCreateWithFlags(allocator
, protection
, kSecAccessControlBiometryCurrentSet
, &error
);
82 ok(acl
!= NULL
, "SecAccessControlCreateWithFlags: %@", error
);
86 // ACL with protection and flags
87 acl
= SecAccessControlCreateWithFlags(allocator
, protection
, kSecAccessControlBiometryAny
| kSecAccessControlDevicePasscode
| kSecAccessControlOr
, &error
);
88 ok(acl
!= NULL
, "SecAccessControlCreateWithFlags: %@", error
);
92 // ACL with protection and flags
93 acl
= SecAccessControlCreateWithFlags(allocator
, protection
, kSecAccessControlBiometryAny
| kSecAccessControlDevicePasscode
| kSecAccessControlAnd
, &error
);
94 ok(acl
!= NULL
, "SecAccessControlCreateWithFlags: %@", error
);
98 // ACL with protection and flags
100 acl
= SecAccessControlCreateWithFlags(allocator
, protection
, kSecAccessControlBiometryAny
| kSecAccessControlDevicePasscode
| kSecAccessControlWatch
| kSecAccessControlAnd
| kSecAccessControlApplicationPassword
, &error
);
102 acl
= SecAccessControlCreateWithFlags(allocator
, protection
, kSecAccessControlBiometryAny
| kSecAccessControlDevicePasscode
| kSecAccessControlAnd
| kSecAccessControlApplicationPassword
, &error
);
104 ok(acl
!= NULL
, "SecAccessControlCreateWithFlags: %@", error
);
105 CFReleaseNull(error
);
108 // ACL with protection and kSecAccessControlApplicationPassword
109 acl
= SecAccessControlCreateWithFlags(allocator
, protection
, kSecAccessControlApplicationPassword
, &error
);
110 ok(acl
!= NULL
, "SecAccessControlCreateWithFlags: %@", error
);
111 CFReleaseNull(error
);
114 // ACL with protection and, kSecAccessControlUserPresence can be in combination with kSecAccessControlApplicationPassword and kSecAccessControlPrivateKeyUsage
115 acl
= SecAccessControlCreateWithFlags(allocator
, protection
, kSecAccessControlUserPresence
| kSecAccessControlApplicationPassword
| kSecAccessControlPrivateKeyUsage
, &error
);
116 ok(acl
!= NULL
, "SecAccessControlCreateWithFlags: %@", error
);
117 CFReleaseNull(error
);
120 // negative test of ACL with protection and, kSecAccessControlUserPresence can be in combination with kSecAccessControlApplicationPassword and kSecAccessControlPrivateKeyUsage
121 acl
= SecAccessControlCreateWithFlags(allocator
, protection
, kSecAccessControlUserPresence
| kSecAccessControlBiometryAny
, &error
);
122 ok(acl
== NULL
, "SecAccessControlCreateWithFlag wrong combination of flags");
123 CFReleaseNull(error
);
126 // ACL with protection and flags
127 acl
= SecAccessControlCreateWithFlags(allocator
, protection
, kSecAccessControlUserPresence
, &error
);
128 ok(acl
!= NULL
, "SecAccessControlCreateWithFlags: %@", error
);
129 CFReleaseNull(error
);
131 // Extended API tests:
134 CFTypeRef aclProtection
= SecAccessControlGetProtection(acl
);
135 is(aclProtection
, protection
, "SecAccessControlGetProtection");
137 SecAccessConstraintRef aclConstraint
= SecAccessControlGetConstraint(acl
, kAKSKeyOpDecrypt
);
139 ok(aclConstraint
!= NULL
&& isDictionary(aclConstraint
), "SecAccessControlGetConstraint");
140 eq_cf(CFDictionaryGetValue(aclConstraint
, CFSTR(kACMKeyAclConstraintPolicy
)), CFSTR(kACMPolicyDeviceOwnerAuthentication
), "SecAccessControlGetConstraint");
147 acl
= SecAccessControlCreate(allocator
, &error
);
148 ok(acl
!= NULL
, "SecAccessControlCreate: %@", error
);
149 CFReleaseNull(error
);
152 bool result
= SecAccessControlSetProtection(acl
, protection
, &error
);
153 ok(result
, "SecAccessControlSetProtection: %@", error
);
154 CFReleaseNull(error
);
156 aclProtection
= SecAccessControlGetProtection(acl
);
158 is(aclProtection
, protection
, "SecAccessControlGetProtection");
161 SecAccessConstraintRef policy
= SecAccessConstraintCreatePolicy(allocator
, CFSTR(kACMPolicyDeviceOwnerAuthentication
), &error
);
162 ok(policy
!= NULL
, "SecAccessConstraintCreatePolicy: %@", error
);
163 ok(isDictionary(policy
), "SecAccessConstraintCreatePolicy");
164 is(CFDictionaryGetValue(policy
, CFSTR(kACMKeyAclConstraintPolicy
)), CFSTR(kACMPolicyDeviceOwnerAuthentication
), "SecAccessConstraintCreatePolicy");
165 CFReleaseNull(error
);
166 CFReleaseNull(policy
);
169 aclConstraint
= SecAccessConstraintCreateWatch(allocator
);
170 ok(aclConstraint
!= NULL
&& isDictionary(aclConstraint
), "SecAccessConstraintCreateWatch");
171 is(CFDictionaryGetValue(aclConstraint
, CFSTR(kACMKeyAclConstraintWatch
)), kCFBooleanTrue
, "SecAccessConstraintCreateWatch");
172 CFReleaseNull(aclConstraint
);
174 // Passcode constraint
175 SecAccessConstraintRef passcode
= SecAccessConstraintCreatePasscode(allocator
);
176 ok(passcode
!= NULL
&& isDictionary(passcode
), "SecAccessConstraintCreatePasscode");
177 is(CFDictionaryGetValue(passcode
, CFSTR(kACMKeyAclConstraintUserPasscode
)), kCFBooleanTrue
, "SecAccessConstraintCreatePasscode");
178 // CFReleaseNull(passcode); passcode will be used in later tests
180 CFUUIDRef uuid
= CFUUIDCreate(allocator
);
181 CFStringRef uuidString
= CFUUIDCreateString(allocator
, uuid
);
182 CFDataRef uuidData
= CFStringCreateExternalRepresentation(allocator
, uuidString
, kCFStringEncodingUTF8
, 0);
183 SecAccessConstraintRef biometry
= SecAccessConstraintCreateBiometryCurrentSet(allocator
, uuidData
, uuidData
);
184 // Biometry constraint
185 ok(biometry
!= NULL
, "SecAccessConstraintCreateBiometry: %@", error
);
186 ok(isDictionary(biometry
), "SecAccessConstraintCreateBiometry");
187 ok(CFDictionaryGetValue(biometry
, CFSTR(kACMKeyAclConstraintBio
)), "SecAccessConstraintCreateBiometry");
188 CFDictionaryRef bioRef
= CFDictionaryGetValue(biometry
, CFSTR(kACMKeyAclConstraintBio
));
189 ok(isDictionary(bioRef
), "SecAccessConstraintCreateBiometry");
190 is(CFDictionaryGetValue(bioRef
, CFSTR(kACMKeyAclParamBioCatacombUUID
)), uuidData
, "SecAccessConstraintCreateBiometry");
191 is(CFDictionaryGetValue(bioRef
, CFSTR(kACMKeyAclParamBioDatabaseHash
)), uuidData
, "SecAccessConstraintCreateBiometry");
192 CFReleaseNull(error
);
193 CFReleaseNull(biometry
);
194 CFReleaseNull(uuidData
);
195 CFReleaseNull(uuidString
);
198 uuid
= CFUUIDCreate(allocator
);
199 uuidString
= CFUUIDCreateString(allocator
, uuid
);
200 uuidData
= CFStringCreateExternalRepresentation(allocator
, uuidString
, kCFStringEncodingUTF8
, 0);
201 biometry
= SecAccessConstraintCreateBiometryAny(allocator
, uuidData
);
202 // Biometry constraint
203 ok(biometry
!= NULL
, "SecAccessConstraintCreateBiometry: %@", error
);
204 ok(isDictionary(biometry
), "SecAccessConstraintCreateBiometry");
205 ok(CFDictionaryGetValue(biometry
, CFSTR(kACMKeyAclConstraintBio
)), "SecAccessConstraintCreateBiometry");
206 bioRef
= CFDictionaryGetValue(biometry
, CFSTR(kACMKeyAclConstraintBio
));
207 ok(isDictionary(bioRef
), "SecAccessConstraintCreateBiometry");
208 is(CFDictionaryGetValue(bioRef
, CFSTR(kACMKeyAclParamBioCatacombUUID
)), uuidData
, "SecAccessConstraintCreateBiometry");
209 CFReleaseNull(error
);
210 // CFReleaseNull(biometry); biometry will be used in later tests
211 CFReleaseNull(uuidData
);
212 CFReleaseNull(uuidString
);
216 CFTypeRef constraints_array
[] = { passcode
, biometry
};
217 CFArrayRef constraintsArray
= CFArrayCreate(allocator
, constraints_array
, array_size(constraints_array
), &kCFTypeArrayCallBacks
);
218 SecAccessConstraintRef kofn
= SecAccessConstraintCreateKofN(allocator
, 1, constraintsArray
, &error
);
219 ok(kofn
!= NULL
, "SecAccessConstraintCreateKofN: %@", error
);
220 ok(isDictionary(kofn
), "SecAccessConstraintCreateKofN");
221 CFTypeRef kofnConstraint
= CFDictionaryGetValue(kofn
, CFSTR(kACMKeyAclConstraintKofN
));
222 ok(kofnConstraint
!= NULL
&& isDictionary(kofnConstraint
), "SecAccessConstraintCreateKofN");
223 CFNumberRef required
= CFNumberCreateWithCFIndex(allocator
, 1);
224 is(CFDictionaryGetValue(kofnConstraint
, CFSTR(kACMKeyAclParamKofN
)), required
, "SecAccessConstraintCreateKofN");
225 ok(CFDictionaryGetValue(kofnConstraint
, CFSTR(kACMKeyAclConstraintBio
)), "SecAccessConstraintCreateKofN");
226 is(CFDictionaryGetValue(kofnConstraint
, CFSTR(kACMKeyAclConstraintUserPasscode
)), kCFBooleanTrue
, "SecAccessConstraintCreateKofN");
227 CFReleaseNull(error
);
229 CFReleaseNull(required
);
230 CFReleaseNull(constraintsArray
);
231 CFReleaseNull(passcode
);
233 // Add ACL constraint for operation
234 result
= SecAccessControlAddConstraintForOperation(acl
, kAKSKeyOpDecrypt
, biometry
, &error
);
235 ok(result
, "SecAccessControlAddConstraintForOperation: %@", error
);
236 CFReleaseNull(error
);
238 // Get ACL operation constraint
239 SecAccessConstraintRef constraint
= SecAccessControlGetConstraint(acl
, kAKSKeyOpDecrypt
);
240 is(constraint
, biometry
, "SecAccessControlGetConstraint");
241 CFReleaseNull(biometry
);
243 // Add ACL constraint for operation (kCFBooleanTrue)
244 result
= SecAccessControlAddConstraintForOperation(acl
, kAKSKeyOpDecrypt
, kCFBooleanTrue
, &error
);
245 ok(result
, "SecAccessControlAddConstraintForOperation: %@", error
);
246 CFReleaseNull(error
);
248 // Get ACL operation constraint (kCFBooleanTrue)
249 constraint
= SecAccessControlGetConstraint(acl
, kAKSKeyOpDecrypt
);
250 is(constraint
, kCFBooleanTrue
, "SecAccessControlGetConstraint");
252 // Get ACL constraints
253 CFDictionaryRef constraints
= SecAccessControlGetConstraints(acl
);
254 ok(constraints
!= NULL
&& isDictionary(constraints
), "SecAccessControlGetConstraints");
255 // Get ACL constraints
256 is(CFDictionaryGetValue(constraints
, kAKSKeyOpDecrypt
), kCFBooleanTrue
, "SecAccessControlGetConstraints");
258 // ACL export and import
259 CFDataRef aclData
= SecAccessControlCopyData(acl
);
260 ok(aclData
!= NULL
, "SecAccessControlCopyData");
261 SecAccessControlRef aclCopy
= SecAccessControlCreateFromData(allocator
, aclData
, &error
);
262 ok(aclCopy
!= NULL
, "SecAccessControlCopyData: %@", error
);
263 ok(CFEqual(aclCopy
, acl
), "SecAccessControlCopyData");
264 CFReleaseNull(error
);
265 CFReleaseNull(aclCopy
);
266 CFReleaseNull(aclData
);
268 // Extended SPI tests:
270 // kAKSKeyDefaultOpAcl
271 result
= SecAccessControlAddConstraintForOperation(acl
, kAKSKeyOpDefaultAcl
, kCFBooleanTrue
, &error
);
272 ok(result
, "SecAccessControlAddConstraintForOperation: %@", error
);
273 constraint
= SecAccessControlGetConstraint(acl
, kAKSKeyOpDecrypt
);
274 is(constraint
, kCFBooleanTrue
, "SecAccessControlRemoveConstraintForOperation");
275 CFReleaseNull(error
);
279 #if LA_CONTEXT_IMPLEMENTED && TARGET_HAS_KEYSTORE
280 // AKS consistency test:
282 acl
= SecAccessControlCreateWithFlags(allocator
, protection
, kSecAccessControlUserPresence
, &error
);
283 ok(acl
!= NULL
, "SecAccessControlCreateWithFlags: %@", error
);
284 CFReleaseNull(error
);
287 skip("SecAccessControlCreateWithFlags failed", 7, acl
!= NULL
);
289 CFDataRef acm_context
= NULL
;
290 CFTypeRef auth_handle
= NULL
;
292 auth_handle
= LACreateNewContextWithACMContext(NULL
, &error
);
293 ok(auth_handle
!= NULL
, "LACreateNewContextWithACMContext: %@", error
);
294 CFReleaseNull(error
);
297 skip("LACreateNewContextWithACMContext failed", 6, auth_handle
!= NULL
);
299 acm_context
= LACopyACMContext(auth_handle
, &error
);
300 ok(acm_context
!= NULL
, "LACopyACMContext: %@", error
);
301 CFReleaseNull(error
);
303 CFReleaseNull(auth_handle
);
306 skip("LACopyACMContext failed", 5, acm_context
!= NULL
);
308 ok(aks_consistency_test(true, kAKSReturnPolicyError
, acl
, acm_context
), "AKS consistency negative test (current auth_data format)");
309 ok(aks_consistency_test(false, kAKSReturnPolicyError
, acl
, acm_context
), "AKS consistency negative test (old auth_data format)");
311 bool decrypt_enabled
= false;
312 CFDictionaryRef constraints
= SecAccessControlGetConstraints(acl
);
314 CFMutableDictionaryRef new_constraints
= CFDictionaryCreateMutableCopy(NULL
, 0, constraints
);
315 if (new_constraints
) {
316 CFDictionarySetValue(new_constraints
, kAKSKeyOpDecrypt
, kCFBooleanTrue
);
317 SecAccessControlSetConstraints(acl
, new_constraints
);
318 CFReleaseSafe(new_constraints
);
319 decrypt_enabled
= true;
322 ok(decrypt_enabled
, "Cannot enable decrypt operation for AKS consistency positive tests");
324 ok(aks_consistency_test(true, kAKSReturnSuccess
, acl
, acm_context
), "AKS consistency positive test (current auth_data format)");
325 ok(aks_consistency_test(false, kAKSReturnSuccess
, acl
, acm_context
), "AKS consistency positive test (old auth_data format)");
327 CFReleaseNull(acm_context
);
335 // kSecAccessControlPrivateKeyUsage
336 acl
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, protection
, kSecAccessControlPrivateKeyUsage
| kSecAccessControlDevicePasscode
, NULL
);
337 ok(acl
, "kSecAccessControlPrivateKeyUsage ACL create with constraint");
338 ok(!SecAccessControlGetConstraint(acl
, kAKSKeyOpEncrypt
), "kAKSKeyOpEncrypt constraint");
339 ok(!SecAccessControlGetConstraint(acl
, kAKSKeyOpDecrypt
), "kAKSKeyOpDecrypt constraint");
340 ok(constraint
= SecAccessControlGetConstraint(acl
, kAKSKeyOpDelete
), "kAKSKeyOpDelete constraint");
341 is(constraint
, kCFBooleanTrue
, "kAKSKeyOpDelete constraint value");
342 ok(constraint
= SecAccessControlGetConstraint(acl
, kAKSKeyOpSign
), "kAKSKeyOpSign constraint");
343 ok(constraint
&& isDictionary(constraint
), "kAKSKeyOpSign constraint value");
346 acl
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, protection
, kSecAccessControlPrivateKeyUsage
, NULL
);
347 ok(acl
, "kSecAccessControlPrivateKeyUsage ACL create without constraint");
348 ok(!SecAccessControlGetConstraint(acl
, kAKSKeyOpEncrypt
), "kAKSKeyOpEncrypt constraint");
349 ok(!SecAccessControlGetConstraint(acl
, kAKSKeyOpDecrypt
), "kAKSKeyOpDecrypt constraint");
350 ok(constraint
= SecAccessControlGetConstraint(acl
, kAKSKeyOpDelete
), "kAKSKeyOpDelete constraint");
351 is(constraint
, kCFBooleanTrue
, "kAKSKeyOpDelete constraint value");
352 ok(constraint
= SecAccessControlGetConstraint(acl
, kAKSKeyOpSign
), "kAKSKeyOpSign constraint");
353 is(constraint
, kCFBooleanTrue
, "kAKSKeyOpSign constraint value");
357 #if LA_CONTEXT_IMPLEMENTED && TARGET_HAS_KEYSTORE
359 static bool aks_consistency_test(bool currentAuthDataFormat
, kern_return_t expectedAksResult
, SecAccessControlRef access_control
, CFDataRef acm_context
)
363 const uint32_t bulkKeySize
= 32;
364 const uint32_t maxKeyWrapOverHead
= 8 + 32;
365 uint8_t bulkKey
[bulkKeySize
];
366 CFMutableDataRef bulkKeyWrapped
= CFDataCreateMutable(NULL
, 0);
367 CFDataSetLength(bulkKeyWrapped
, bulkKeySize
+ maxKeyWrapOverHead
);
368 CFMutableDataRef bulkKeyUnwrapped
= CFDataCreateMutable(NULL
, 0);
369 CFDataSetLength(bulkKeyUnwrapped
, bulkKeySize
);
371 CFDataRef auth_data
= NULL
;
372 CFMutableDictionaryRef auth_attribs
= NULL
;
374 OSStatus status
= SecRandomCopyBytes(kSecRandomDefault
, bulkKeySize
, bulkKey
);
375 ok_status(status
, "SecRandomCopyBytes failed");
376 require_noerr(status
, out
);
378 auth_attribs
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
379 if (currentAuthDataFormat
) {
380 auth_data
= kc_create_auth_data(access_control
, auth_attribs
);
383 auth_data
= kc_copy_constraints_data(access_control
, auth_attribs
);
386 status
= aks_crypt_acl(kAKSKeyOpEncrypt
, KEYBAG_DEVICE
, key_class_dk
, bulkKeySize
, bulkKey
, bulkKeyWrapped
, auth_data
, acm_context
, NULL
);
387 is_status(status
, kAKSReturnSuccess
, "kAKSKeyOpEncrypt failed");
388 require(status
== kAKSReturnSuccess
, out
);
390 uint32_t blobLenWrapped
= (uint32_t)CFDataGetLength(bulkKeyWrapped
);
391 const uint8_t *cursor
= CFDataGetBytePtr(bulkKeyWrapped
);
393 status
= aks_crypt_acl(kAKSKeyOpDecrypt
, KEYBAG_DEVICE
, key_class_dk
, blobLenWrapped
, cursor
, bulkKeyUnwrapped
, auth_data
, acm_context
, NULL
);
394 is_status(status
, expectedAksResult
, "kAKSKeyOpDecrypt finished with unexpected result");
395 require(status
== expectedAksResult
, out
);
400 CFReleaseSafe(bulkKeyUnwrapped
);
401 CFReleaseSafe(bulkKeyWrapped
);
402 CFReleaseSafe(auth_data
);
403 CFReleaseSafe(auth_attribs
);
408 static bool merge_der_in_to_data(const void *der1
, size_t der1_len
, const void *der2
, size_t der2_len
, CFMutableDataRef mergedData
)
411 CFPropertyListRef dict1
= NULL
;
412 CFPropertyListRef dict2
= NULL
;
414 der_decode_plist(NULL
, kCFPropertyListImmutable
, &dict1
, NULL
, der1
, der1
+ der1_len
);
415 der_decode_plist(NULL
, kCFPropertyListImmutable
, &dict2
, NULL
, der2
, der2
+ der2_len
);
416 if (dict1
&& dict2
) {
417 CFMutableDictionaryRef result_dict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, dict1
);
418 CFDictionaryForEach(dict2
, ^(const void *key
, const void *value
) {
419 CFDictionaryAddValue(result_dict
, key
, value
);
422 CFDataSetLength(mergedData
, 0);
423 CFDataRef der_data
= CFPropertyListCreateDERData(kCFAllocatorDefault
, result_dict
, NULL
);
425 CFDataAppend(mergedData
, der_data
);
427 result
= CFDataGetLength(mergedData
) > 0;
429 CFRelease(result_dict
);
432 CFReleaseSafe(dict1
);
433 CFReleaseSafe(dict2
);
437 static int aks_crypt_acl(CFTypeRef operation
, keybag_handle_t keybag
,
438 keyclass_t keyclass
, uint32_t textLength
, const uint8_t *source
,
439 CFMutableDataRef dest
, CFDataRef auth_data
, CFDataRef acm_context
, CFDataRef caller_access_groups
)
441 int aks_return
= kAKSReturnSuccess
;
442 void *params
= NULL
, *der
= NULL
;
443 const uint8_t *access_groups
= caller_access_groups
?CFDataGetBytePtr(caller_access_groups
):NULL
;
444 size_t params_len
= 0, der_len
= 0, access_groups_len
= caller_access_groups
?CFDataGetLength(caller_access_groups
):0;
445 aks_ref_key_t key_handle
= NULL
;
447 if (CFEqual(operation
, kAKSKeyOpEncrypt
)) {
448 aks_operation_optional_params(0, 0, CFDataGetBytePtr(auth_data
), CFDataGetLength(auth_data
),
449 CFDataGetBytePtr(acm_context
), (int)CFDataGetLength(acm_context
), ¶ms
, ¶ms_len
);
451 require_noerr_quiet(aks_return
= aks_ref_key_create(keybag
, keyclass
, key_type_sym
, params
, params_len
, &key_handle
), out
);
452 require_noerr_quiet(aks_return
= aks_ref_key_encrypt(key_handle
, params
, params_len
, source
, textLength
, &der
, &der_len
), out
);
454 const void *key_blob
= aks_ref_key_get_blob(key_handle
, &key_blob_len
);
455 require_action_string(key_blob
, out
, aks_return
= kAKSReturnError
, "aks_ref_key_get_blob failed");
456 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");
458 } else if (CFEqual(operation
, kAKSKeyOpDecrypt
)) {
459 aks_operation_optional_params(access_groups
, access_groups_len
, 0, 0,
460 CFDataGetBytePtr(acm_context
), (int)CFDataGetLength(acm_context
), (void**)¶ms
, ¶ms_len
);
461 require_noerr_quiet(aks_return
= aks_ref_key_create_with_blob(keybag
, source
, textLength
, &key_handle
), out
);
462 require_noerr_quiet(aks_return
= aks_ref_key_decrypt(key_handle
, params
, params_len
, source
, textLength
, &der
, &der_len
), out
);
463 require_action_string(der
, out
, aks_return
= kAKSReturnError
, "aks_ref_key_decrypt failed");
465 CFPropertyListRef decoded_data
= NULL
;
466 der_decode_plist(kCFAllocatorDefault
, kCFPropertyListImmutable
, &decoded_data
, NULL
, der
, der
+ der_len
);
467 require_action_string(decoded_data
, out
, aks_return
= kAKSReturnError
, "der_decode_plist failed");
468 if (CFGetTypeID(decoded_data
) == CFDataGetTypeID()) {
469 CFDataSetLength(dest
, 0);
470 CFDataAppend(dest
, decoded_data
);
471 CFRelease(decoded_data
);
474 CFRelease(decoded_data
);
475 require_action_string(false, out
, aks_return
= kAKSReturnError
, "wrong decoded data type");
481 aks_ref_key_free(&key_handle
);
492 static CFDataRef
kc_create_auth_data(SecAccessControlRef access_control
, CFDictionaryRef auth_attributes
)
494 CFDictionaryRef constraints
= SecAccessControlGetConstraints(access_control
);
495 CFMutableDictionaryRef auth_data
= CFDictionaryCreateMutableCopy(NULL
, 0, auth_attributes
);
496 CFDictionarySetValue(auth_data
, kAKSKeyAcl
, constraints
);
497 CFDataRef encoded
= CFPropertyListCreateDERData(kCFAllocatorDefault
, auth_data
, NULL
);
498 CFReleaseSafe(auth_data
);
502 static CFDataRef
kc_copy_constraints_data(SecAccessControlRef access_control
, CFDictionaryRef auth_attributes
)
504 CFDictionaryRef constraints
= SecAccessControlGetConstraints(access_control
);
505 CFMutableDictionaryRef auth_data
= CFDictionaryCreateMutableCopy(NULL
, 0, constraints
);
506 if (auth_attributes
) {
507 CFDictionaryForEach(auth_attributes
, ^(const void *key
, const void *value
) {
508 CFDictionaryAddValue(auth_data
, key
, value
);
512 CFDataRef encoded
= CFPropertyListCreateDERData(kCFAllocatorDefault
, auth_data
, NULL
);
513 CFReleaseSafe(auth_data
);
519 int si_77_SecAccessControl(int argc
, char *const *argv
)
521 #if LA_CONTEXT_IMPLEMENTED && TARGET_HAS_KEYSTORE