5 // Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
9 #include <CoreFoundation/CoreFoundation.h>
10 #include <Security/SecCertificate.h>
11 #include <Security/SecItem.h>
12 #include <Security/SecItemPriv.h>
13 #include <Security/SecBase.h>
14 #include <utilities/array_size.h>
15 #include <utilities/SecCFWrappers.h>
18 #include <Security/SecAccessControl.h>
19 #include <Security/SecAccessControlPriv.h>
20 #include <libaks_acl_cf_keys.h>
21 #include <LocalAuthentication/LAPublicDefines.h>
22 #include <LocalAuthentication/LAPrivateDefines.h>
23 #include <securityd/SecItemServer.h>
24 #include <LocalAuthentication/LAPublicDefines.h>
26 #include "secd_regressions.h"
30 #include <coreauthd_spi.h>
31 #include "SecdTestKeychainUtilities.h"
33 #include <MobileKeyBag/MobileKeyBag.h>
36 void kc_dbhandle_reset(void);
37 static keybag_handle_t test_keybag
;
38 static const char *passcode1
= "passcode1";
39 static const char *passcode2
= "passcode2";
41 static bool changePasscode(const char *old_passcode
, const char *new_passcode
)
43 size_t old_passcode_len
= 0;
44 size_t new_passcode_len
= 0;
47 old_passcode_len
= strlen(old_passcode
);
50 new_passcode_len
= strlen(new_passcode
);
52 kern_return_t status
= aks_change_secret(test_keybag
, old_passcode
, (int)old_passcode_len
, new_passcode
, (int)new_passcode_len
, NULL
, NULL
);
66 kAccessabilityItemAttr
,
70 extern void LASetErrorCodeBlock(CFErrorRef (^newCreateErrorBlock
)(void));
72 static void WithEachString(void(^each
)(CFStringRef attr
, enum ItemAttrType atype
), ...) {
76 while((attr
= va_arg(ap
, CFStringRef
)) != NULL
) {
77 enum ItemAttrType atype
= va_arg(ap
, enum ItemAttrType
);
83 static void ItemForEachPKAttr(CFMutableDictionaryRef item
, void(^each
)(CFStringRef attr
, enum ItemAttrType atype
)) {
84 CFStringRef iclass
= CFDictionaryGetValue(item
, kSecClass
);
87 } else if (CFEqual(iclass
, kSecClassGenericPassword
)) {
89 kSecAttrAccessible
, kAccessabilityItemAttr
,
90 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
91 kSecAttrAccount
, kStringItemAttr
,
92 kSecAttrService
, kStringItemAttr
,
93 kSecAttrSynchronizable
, kBoolItemAttr
,
95 } else if (CFEqual(iclass
, kSecClassInternetPassword
)) {
97 kSecAttrAccessible
, kAccessabilityItemAttr
,
98 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
99 kSecAttrAccount
, kStringItemAttr
,
100 kSecAttrSecurityDomain
, kStringItemAttr
,
101 kSecAttrServer
, kStringItemAttr
,
102 kSecAttrProtocol
, kNumberItemAttr
,
103 kSecAttrAuthenticationType
, kNumberItemAttr
,
104 kSecAttrPort
, kNumberItemAttr
,
105 kSecAttrPath
, kStringItemAttr
,
106 kSecAttrSynchronizable
, kBoolItemAttr
,
108 } else if (CFEqual(iclass
, kSecClassCertificate
)) {
110 kSecAttrAccessible
, kAccessabilityItemAttr
,
111 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
112 kSecAttrCertificateType
, kNumberItemAttr
,
113 kSecAttrIssuer
, kDataItemAttr
,
114 kSecAttrSerialNumber
, kDataItemAttr
,
115 kSecAttrSynchronizable
, kBoolItemAttr
,
117 } else if (CFEqual(iclass
, kSecClassKey
)) {
119 kSecAttrAccessible
, kAccessabilityItemAttr
,
120 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
121 kSecAttrKeyClass
, kStringItemAttr
, // kNumberItemAttr on replies
122 kSecAttrApplicationLabel
, kDataItemAttr
,
123 kSecAttrApplicationTag
, kDataItemAttr
,
124 kSecAttrKeyType
, kNumberItemAttr
,
125 kSecAttrKeySizeInBits
, kNumberItemAttr
,
126 kSecAttrEffectiveKeySize
, kNumberItemAttr
,
127 kSecAttrStartDate
, kDateItemAttr
,
128 kSecAttrEndDate
, kDateItemAttr
,
129 kSecAttrSynchronizable
, kBoolItemAttr
,
131 } else if (CFEqual(iclass
, kSecClassIdentity
)) {
133 kSecAttrAccessible
, kAccessabilityItemAttr
,
134 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
135 kSecAttrCertificateType
, kNumberItemAttr
,
136 kSecAttrIssuer
, kDataItemAttr
,
137 kSecAttrSerialNumber
, kDataItemAttr
,
138 kSecAttrSynchronizable
, kBoolItemAttr
,
139 kSecAttrKeyClass
, kStringItemAttr
, // kNumberItemAttr on replies
140 kSecAttrApplicationLabel
, kDataItemAttr
,
141 kSecAttrApplicationTag
, kDataItemAttr
,
142 kSecAttrKeyType
, kNumberItemAttr
,
143 kSecAttrKeySizeInBits
, kNumberItemAttr
,
144 kSecAttrEffectiveKeySize
, kNumberItemAttr
,
145 kSecAttrStartDate
, kDateItemAttr
,
146 kSecAttrEndDate
, kDateItemAttr
,
147 kSecAttrSynchronizable
, kBoolItemAttr
,
152 static void fillItem(CFMutableDictionaryRef item
, uint32_t num
)
154 ItemForEachPKAttr(item
, ^(CFStringRef attr
, enum ItemAttrType atype
) {
155 CFTypeRef value
= NULL
;
158 value
= (num
% 2 == 0 ? kCFBooleanTrue
: kCFBooleanFalse
);
161 case kNumberItemAttr
:
162 value
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &num
);
164 case kStringItemAttr
:
166 value
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("acl-stress-string-%d"), num
);
171 int len
= snprintf(buf
, sizeof(buf
), "acl-stress-data-%d", num
);
172 value
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)buf
, len
);
176 value
= NULL
; // Don't mess with dates on create.
178 case kAccessabilityItemAttr
:
180 case kAccessGroupItemAttr
:
182 CFStringRef accessGroups
[] = {
184 CFSTR("com.apple.security.sos"), // Secd internally uses this
186 value
= accessGroups
[num
% array_size(accessGroups
)];
191 CFDictionarySetValue(item
, attr
, value
);
192 CFReleaseSafe(value
);
198 static CFErrorRef
createCFError(CFStringRef message
, CFIndex code
)
200 const void* keysPtr
[1];
201 const void* messagesPtr
[1];
203 keysPtr
[0] = kCFErrorLocalizedDescriptionKey
;
204 messagesPtr
[0] = message
;
205 return CFErrorCreateWithUserInfoKeysAndValues(kCFAllocatorDefault
, CFSTR(kLAErrorDomain
), code
, keysPtr
, messagesPtr
, 1);
209 static void set_app_password(ACMContextRef acmContext
)
211 CFDataRef appPwdData
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, CFSTR("Application password"), kCFStringEncodingUTF8
, 0);
212 ACMCredentialRef acmCredential
= NULL
;
213 ok_status(ACMCredentialCreate(kACMCredentialTypePassphraseEntered
, &acmCredential
), "Create ACM credential");
214 ACMPassphrasePurpose purpose
= kACMPassphrasePurposeGeneral
;
215 ok_status(ACMCredentialSetProperty(acmCredential
, kACMCredentialPropertyPassphrase
, CFDataGetBytePtr(appPwdData
), CFDataGetLength(appPwdData
)), "Set ACM credential property - passphrase");
216 ok_status(ACMCredentialSetProperty(acmCredential
, kACMCredentialPropertyPassphrasePurpose
, &purpose
, sizeof(purpose
)), "Set ACM credential property - purpose");
217 ok_status(ACMContextAddCredentialWithScope(acmContext
, acmCredential
, kACMScopeContext
), "aad ACM credential to ACM context");
218 ACMCredentialDelete(acmCredential
);
219 CFReleaseSafe(appPwdData
);
223 static void item_with_application_password(uint32_t *item_num
)
226 CFErrorRef (^okBlock
)(void) = ^ {
227 return (CFErrorRef
)NULL
;
230 CFErrorRef (^authFailedBlock
)(void) = ^ {
231 return createCFError(CFSTR(""), kLAErrorAuthenticationFailed
);
234 CFMutableDictionaryRef item
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, kSecClassInternetPassword
, NULL
);
235 fillItem(item
, (*item_num
)++);
237 LASetErrorCodeBlock(okBlock
);
238 SecAccessControlRef aclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, kSecAccessControlApplicationPassword
, NULL
);
239 ok(aclRef
, "Create SecAccessControlRef");
241 ACMContextRef acmContext
= NULL
;
242 ok_status(ACMContextCreate(&acmContext
), "Create ACM context");
243 set_app_password(acmContext
);
245 __block CFDataRef credRefData
= NULL
;
246 ACMContextGetExternalForm(acmContext
, ^(const void *externalForm
, size_t dataBufferLength
) {
247 credRefData
= CFDataCreate(kCFAllocatorDefault
, externalForm
, dataBufferLength
);
250 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclRef
);
251 CFDictionarySetValue(item
, kSecUseCredentialReference
, credRefData
);
252 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
253 ok_status(SecItemAdd(item
, NULL
), "add local - acl with application password");
254 ok_status(SecItemCopyMatching(item
, NULL
), "find local - acl with application password");
255 ok_status(SecItemDelete(item
), "delete local - acl with application password");
257 CFReleaseSafe(aclRef
);
259 LASetErrorCodeBlock(okBlock
);
260 aclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, kSecAccessControlUserPresence
, NULL
);
261 SecAccessControlSetRequirePassword(aclRef
, true);
262 ok(aclRef
, "Create SecAccessControlRef");
264 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclRef
);
265 CFDictionarySetValue(item
, kSecUseCredentialReference
, credRefData
);
266 ok_status(SecItemAdd(item
, NULL
), "add local - acl with application password and user present");
267 LASetErrorCodeBlock(authFailedBlock
);
268 is_status(SecItemCopyMatching(item
, NULL
), errSecAuthFailed
, "find local - acl with application password and user present");
269 LASetErrorCodeBlock(okBlock
);
270 set_app_password(acmContext
);
271 ok_status(SecItemDelete(item
), "delete local - acl with application password and user present");
272 CFReleaseSafe(aclRef
);
274 LASetErrorCodeBlock(okBlock
);
275 aclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, kSecAccessControlUserPresence
, NULL
);
276 SecAccessControlSetRequirePassword(aclRef
, true);
277 SecAccessConstraintRef constraint
= SecAccessConstraintCreatePolicy(kCFAllocatorDefault
, CFSTR(kACMPolicyDeviceOwnerAuthentication
), NULL
);
278 SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpDelete
, constraint
, NULL
);
279 CFRelease(constraint
);
280 ok(aclRef
, "Create SecAccessControlRef");
282 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclRef
);
283 CFDictionarySetValue(item
, kSecUseCredentialReference
, credRefData
);
284 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
285 ok_status(SecItemAdd(item
, NULL
), "add local - acl with application password and user present");
286 LASetErrorCodeBlock(authFailedBlock
);
287 is_status(SecItemCopyMatching(item
, NULL
), errSecAuthFailed
, "find local - acl with application password and user present");
288 set_app_password(acmContext
);
289 is_status(SecItemDelete(item
), errSecAuthFailed
, "delete local - acl with application password and user present");
292 CFReleaseSafe(aclRef
);
294 // Update tests for item with application password:
296 // Prepare query for item without ACL.
297 item
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, kSecClassInternetPassword
, NULL
);
298 fillItem(item
, (*item_num
)++);
299 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
301 // Add test item without ACL and check that it can be found.
302 ok_status(SecItemAdd(item
, NULL
), "add local - no acl");
303 ok_status(SecItemCopyMatching(item
, NULL
), "find local - no acl");
305 // Update test item by adding ACL with application password flag.
306 CFMutableDictionaryRef update
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
307 aclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleAlways
, kSecAccessControlApplicationPassword
, NULL
);
308 CFDictionarySetValue(update
, kSecAttrAccessControl
, aclRef
);
309 set_app_password(acmContext
);
310 CFDictionarySetValue(item
, kSecUseCredentialReference
, credRefData
);
311 LASetErrorCodeBlock(okBlock
);
312 ok_status(SecItemUpdate(item
, update
), "update local - acl with application password");
314 LASetErrorCodeBlock(authFailedBlock
);
315 ok_status(SecItemCopyMatching(item
, NULL
), "find local - acl with application password");
316 CFDictionaryRemoveValue(item
, kSecUseCredentialReference
);
317 is_status(SecItemCopyMatching(item
, NULL
), errSecAuthFailed
, "find local - acl with application password (without ACM context)");
318 CFDictionarySetValue(item
, kSecUseCredentialReference
, credRefData
);
319 ok_status(SecItemCopyMatching(item
, NULL
), "find local - acl with application password (with ACM context)");
321 // Try to update item with ACL with application password with the same password (it will fail because ACM context is not allowd for update attributes).
322 CFDictionarySetValue(update
, kSecUseCredentialReference
, credRefData
);
323 LASetErrorCodeBlock(okBlock
);
324 is_status(SecItemUpdate(item
, update
), errSecParam
, "update local - add application password");
326 CFDictionaryRemoveValue(update
, kSecUseCredentialReference
);
327 LASetErrorCodeBlock(okBlock
);
328 ok_status(SecItemUpdate(item
, update
), "update local - updated with the same application password");
329 LASetErrorCodeBlock(authFailedBlock
);
330 ok_status(SecItemCopyMatching(item
, NULL
), "find local - updated with the same application password"); // LA authFailedBlock is not called.
332 CFReleaseSafe(aclRef
);
333 // Update item with ACL without application password.
334 aclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleAlways
, 0, NULL
);
335 CFDictionarySetValue(update
, kSecAttrAccessControl
, aclRef
);
337 LASetErrorCodeBlock(okBlock
);
338 ok_status(SecItemUpdate(item
, update
), "update local - remove application password");
340 CFDictionaryRemoveValue(item
, kSecUseCredentialReference
);
341 LASetErrorCodeBlock(authFailedBlock
);
342 ok_status(SecItemCopyMatching(item
, NULL
), "find local - acl without application password"); // LA authFailedBlock is not called.
344 ok_status(SecItemDelete(item
), "delete local - acl without application password");
348 CFReleaseSafe(aclRef
);
350 ACMContextDelete(acmContext
, true);
351 CFReleaseSafe(credRefData
);
355 static void item_with_invalid_acl(uint32_t *item_num
)
357 CFErrorRef (^errorParamBlock
)(void) = ^ {
358 return createCFError(CFSTR(""), kLAErrorParameter
);
361 CFMutableDictionaryRef item
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, kSecClassInternetPassword
, NULL
);
362 fillItem(item
, (*item_num
)++);
364 SecAccessControlRef invalidAclRef
= SecAccessControlCreate(kCFAllocatorDefault
, NULL
);
365 ok(invalidAclRef
, "Create invalid SecAccessControlRef");
366 ok(SecAccessControlSetProtection(invalidAclRef
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, NULL
), "Set protection");
367 CFTypeRef constraint
= SecAccessConstraintCreatePolicy(kCFAllocatorDefault
, CFSTR("invalidPolicy"), NULL
);
368 ok(constraint
, "Create invalid constraint");
369 ok(SecAccessControlAddConstraintForOperation(invalidAclRef
, kAKSKeyOpDecrypt
, constraint
, NULL
), "Add invalid constraint");
370 CFReleaseSafe(constraint
);
372 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
373 CFDictionarySetValue(item
, kSecAttrAccessControl
, invalidAclRef
);
375 LASetErrorCodeBlock(errorParamBlock
);
376 is_status(SecItemAdd(item
, NULL
), errSecParam
, "do not add local with invalid acl");
377 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find after add failed");
379 CFReleaseSafe(invalidAclRef
);
383 static void item_with_acl_caused_maxauth(uint32_t *item_num
)
385 CFErrorRef (^okBlock
)(void) = ^ {
386 return (CFErrorRef
)NULL
;
389 CFMutableDictionaryRef item
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, kSecClassInternetPassword
, NULL
);
390 fillItem(item
, (*item_num
)++);
392 SecAccessControlRef aclRef
= SecAccessControlCreate(kCFAllocatorDefault
, NULL
);
393 ok(aclRef
, "Create SecAccessControlRef");
394 ok(SecAccessControlSetProtection(aclRef
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, NULL
));
395 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpEncrpyt
, kCFBooleanFalse
, NULL
));
397 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
398 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclRef
);
400 __security_simulatecrash_enable(false);
402 LASetErrorCodeBlock(okBlock
);
403 is_status(SecItemAdd(item
, NULL
), errSecAuthFailed
, "max auth attempts failed");
405 is(__security_simulatecrash_enable(true), 1, "Expecting simcrash max auth threshold passed");
407 CFReleaseSafe(aclRef
);
411 static void item_with_akpu(uint32_t *item_num
)
413 CFErrorRef (^okBlock
)(void) = ^ {
414 return (CFErrorRef
)NULL
;
417 CFMutableDictionaryRef item
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, kSecClassGenericPassword
, NULL
);
418 fillItem(item
, (*item_num
)++);
420 SecAccessControlRef aclRef
= SecAccessControlCreate(kCFAllocatorDefault
, NULL
);
421 ok(aclRef
, "Create SecAccessControlRef");
422 ok(SecAccessControlSetProtection(aclRef
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, NULL
));
423 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpEncrpyt
, kCFBooleanTrue
, NULL
));
424 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpDecrypt
, kCFBooleanTrue
, NULL
));
425 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpDelete
, kCFBooleanTrue
, NULL
));
427 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
428 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclRef
);
430 LASetErrorCodeBlock(okBlock
);
431 ok_status(SecItemAdd(item
, NULL
), "add item with akpu");
432 ok_status(SecItemCopyMatching(item
, NULL
), "find item with akpu");
433 changePasscode(passcode1
, NULL
);
434 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find item with akpu");
435 is_status(SecItemAdd(item
, NULL
), errSecAuthFailed
, "cannot add item with akpu without passcode");
436 changePasscode(NULL
, passcode2
);
437 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find item with akpu");
438 ok_status(SecItemAdd(item
, NULL
), "add item with akpu");
440 changePasscode(passcode2
, passcode1
);
441 CFReleaseSafe(aclRef
);
446 static void item_with_skip_auth_ui(uint32_t *item_num
)
448 CFMutableDictionaryRef item
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, kSecClassInternetPassword
, NULL
);
449 fillItem(item
, (*item_num
)++);
451 SecAccessControlRef aclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, kSecAccessControlDevicePasscode
, NULL
);
452 ok(aclRef
, "Create SecAccessControlRef");
454 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclRef
);
455 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUISkip
);
456 is_status(SecItemAdd(item
, NULL
), errSecParam
, "add local - invalid kSecUseAuthenticationUISkip");
457 is_status(SecItemDelete(item
), errSecParam
, "delete local - invalid kSecUseAuthenticationUISkip");
459 CFReleaseNull(aclRef
);
463 int secd_81_item_acl(int argc
, char *const *argv
)
465 uint32_t item_num
= 1;
467 secd_test_setup_temp_keychain(__FUNCTION__
, ^{
468 keybag_state_t state
;
469 int passcode_len
=(int)strlen(passcode1
);
471 ok(kIOReturnSuccess
==aks_create_bag(passcode1
, passcode_len
, kAppleKeyStoreDeviceBag
, &test_keybag
), "create keybag");
472 ok(kIOReturnSuccess
==aks_get_lock_state(test_keybag
, &state
), "get keybag state");
473 ok(!(state
&keybag_state_locked
), "keybag unlocked");
474 SecItemServerSetKeychainKeybag(test_keybag
);
481 item_with_skip_auth_ui(&item_num
);
482 item_with_invalid_acl(&item_num
);
483 item_with_application_password(&item_num
);
484 item_with_acl_caused_maxauth(&item_num
);
485 item_with_akpu(&item_num
);
488 item_with_skip_auth_ui(&item_num
);
492 SecItemServerResetKeychainKeybag();