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 #if LA_CONTEXT_IMPLEMENTED
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
);
67 kAccessabilityItemAttr
,
71 extern void LASetErrorCodeBlock(CFErrorRef (^newCreateErrorBlock
)(void));
73 static void WithEachString(void(^each
)(CFStringRef attr
, enum ItemAttrType atype
), ...) {
77 while((attr
= va_arg(ap
, CFStringRef
)) != NULL
) {
78 enum ItemAttrType atype
= va_arg(ap
, enum ItemAttrType
);
84 static void ItemForEachPKAttr(CFMutableDictionaryRef item
, void(^each
)(CFStringRef attr
, enum ItemAttrType atype
)) {
85 CFStringRef iclass
= CFDictionaryGetValue(item
, kSecClass
);
88 } else if (CFEqual(iclass
, kSecClassGenericPassword
)) {
90 kSecAttrAccessible
, kAccessabilityItemAttr
,
91 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
92 kSecAttrAccount
, kStringItemAttr
,
93 kSecAttrService
, kStringItemAttr
,
94 kSecAttrSynchronizable
, kBoolItemAttr
,
96 } else if (CFEqual(iclass
, kSecClassInternetPassword
)) {
98 kSecAttrAccessible
, kAccessabilityItemAttr
,
99 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
100 kSecAttrAccount
, kStringItemAttr
,
101 kSecAttrSecurityDomain
, kStringItemAttr
,
102 kSecAttrServer
, kStringItemAttr
,
103 kSecAttrProtocol
, kNumberItemAttr
,
104 kSecAttrAuthenticationType
, kNumberItemAttr
,
105 kSecAttrPort
, kNumberItemAttr
,
106 kSecAttrPath
, kStringItemAttr
,
107 kSecAttrSynchronizable
, kBoolItemAttr
,
109 } else if (CFEqual(iclass
, kSecClassCertificate
)) {
111 kSecAttrAccessible
, kAccessabilityItemAttr
,
112 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
113 kSecAttrCertificateType
, kNumberItemAttr
,
114 kSecAttrIssuer
, kDataItemAttr
,
115 kSecAttrSerialNumber
, kDataItemAttr
,
116 kSecAttrSynchronizable
, kBoolItemAttr
,
118 } else if (CFEqual(iclass
, kSecClassKey
)) {
120 kSecAttrAccessible
, kAccessabilityItemAttr
,
121 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
122 kSecAttrKeyClass
, kStringItemAttr
, // kNumberItemAttr on replies
123 kSecAttrApplicationLabel
, kDataItemAttr
,
124 kSecAttrApplicationTag
, kDataItemAttr
,
125 kSecAttrKeyType
, kNumberItemAttr
,
126 kSecAttrKeySizeInBits
, kNumberItemAttr
,
127 kSecAttrEffectiveKeySize
, kNumberItemAttr
,
128 kSecAttrStartDate
, kDateItemAttr
,
129 kSecAttrEndDate
, kDateItemAttr
,
130 kSecAttrSynchronizable
, kBoolItemAttr
,
132 } else if (CFEqual(iclass
, kSecClassIdentity
)) {
134 kSecAttrAccessible
, kAccessabilityItemAttr
,
135 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
136 kSecAttrCertificateType
, kNumberItemAttr
,
137 kSecAttrIssuer
, kDataItemAttr
,
138 kSecAttrSerialNumber
, kDataItemAttr
,
139 kSecAttrSynchronizable
, kBoolItemAttr
,
140 kSecAttrKeyClass
, kStringItemAttr
, // kNumberItemAttr on replies
141 kSecAttrApplicationLabel
, kDataItemAttr
,
142 kSecAttrApplicationTag
, kDataItemAttr
,
143 kSecAttrKeyType
, kNumberItemAttr
,
144 kSecAttrKeySizeInBits
, kNumberItemAttr
,
145 kSecAttrEffectiveKeySize
, kNumberItemAttr
,
146 kSecAttrStartDate
, kDateItemAttr
,
147 kSecAttrEndDate
, kDateItemAttr
,
148 kSecAttrSynchronizable
, kBoolItemAttr
,
153 static void fillItem(CFMutableDictionaryRef item
, uint32_t num
)
155 ItemForEachPKAttr(item
, ^(CFStringRef attr
, enum ItemAttrType atype
) {
156 CFTypeRef value
= NULL
;
159 value
= (num
% 2 == 0 ? kCFBooleanTrue
: kCFBooleanFalse
);
162 case kNumberItemAttr
:
163 value
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &num
);
165 case kStringItemAttr
:
167 value
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("acl-stress-string-%d"), num
);
172 int len
= snprintf(buf
, sizeof(buf
), "acl-stress-data-%d", num
);
173 value
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)buf
, len
);
177 value
= NULL
; // Don't mess with dates on create.
179 case kAccessabilityItemAttr
:
181 case kAccessGroupItemAttr
:
183 CFStringRef accessGroups
[] = {
185 CFSTR("com.apple.security.sos"), // Secd internally uses this
187 value
= accessGroups
[num
% array_size(accessGroups
)];
192 CFDictionarySetValue(item
, attr
, value
);
193 CFReleaseSafe(value
);
197 #if LA_CONTEXT_IMPLEMENTED
199 static CFErrorRef
createCFError(CFStringRef message
, CFIndex code
)
201 const void* keysPtr
[1];
202 const void* messagesPtr
[1];
204 keysPtr
[0] = kCFErrorLocalizedDescriptionKey
;
205 messagesPtr
[0] = message
;
206 return CFErrorCreateWithUserInfoKeysAndValues(kCFAllocatorDefault
, CFSTR(kLAErrorDomain
), code
, keysPtr
, messagesPtr
, 1);
210 static void set_app_password(ACMContextRef acmContext
)
212 CFDataRef appPwdData
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, CFSTR("Application password"), kCFStringEncodingUTF8
, 0);
213 ACMCredentialRef acmCredential
= NULL
;
214 ok_status(ACMCredentialCreate(kACMCredentialTypePassphraseEntered
, &acmCredential
), "Create ACM credential");
215 ACMPassphrasePurpose purpose
= kACMPassphrasePurposeGeneral
;
216 ok_status(ACMCredentialSetProperty(acmCredential
, kACMCredentialPropertyPassphrase
, CFDataGetBytePtr(appPwdData
), CFDataGetLength(appPwdData
)), "Set ACM credential property - passphrase");
217 ok_status(ACMCredentialSetProperty(acmCredential
, kACMCredentialPropertyPassphrasePurpose
, &purpose
, sizeof(purpose
)), "Set ACM credential property - purpose");
218 ok_status(ACMContextAddCredentialWithScope(acmContext
, acmCredential
, kACMScopeContext
), "aad ACM credential to ACM context");
219 ACMCredentialDelete(acmCredential
);
220 CFReleaseSafe(appPwdData
);
224 static void item_with_application_password(uint32_t *item_num
)
227 CFErrorRef (^okBlock
)(void) = ^ {
228 return (CFErrorRef
)NULL
;
231 CFErrorRef (^authFailedBlock
)(void) = ^ {
232 return createCFError(CFSTR(""), kLAErrorAuthenticationFailed
);
235 CFMutableDictionaryRef item
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, kSecClassInternetPassword
, NULL
);
236 fillItem(item
, (*item_num
)++);
238 LASetErrorCodeBlock(okBlock
);
239 SecAccessControlRef aclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, kSecAccessControlApplicationPassword
, NULL
);
240 ok(aclRef
, "Create SecAccessControlRef");
242 ACMContextRef acmContext
= NULL
;
243 ok_status(ACMContextCreate(&acmContext
), "Create ACM context");
244 set_app_password(acmContext
);
246 __block CFDataRef credRefData
= NULL
;
247 ACMContextGetExternalForm(acmContext
, ^(const void *externalForm
, size_t dataBufferLength
) {
248 credRefData
= CFDataCreate(kCFAllocatorDefault
, externalForm
, dataBufferLength
);
251 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclRef
);
252 CFDictionarySetValue(item
, kSecUseCredentialReference
, credRefData
);
253 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
254 ok_status(SecItemAdd(item
, NULL
), "add local - acl with application password");
255 ok_status(SecItemCopyMatching(item
, NULL
), "find local - acl with application password");
256 ok_status(SecItemDelete(item
), "delete local - acl with application password");
258 CFReleaseSafe(aclRef
);
260 LASetErrorCodeBlock(okBlock
);
261 aclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, kSecAccessControlUserPresence
, NULL
);
262 SecAccessControlSetRequirePassword(aclRef
, true);
263 ok(aclRef
, "Create SecAccessControlRef");
265 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclRef
);
266 CFDictionarySetValue(item
, kSecUseCredentialReference
, credRefData
);
267 ok_status(SecItemAdd(item
, NULL
), "add local - acl with application password and user present");
268 LASetErrorCodeBlock(authFailedBlock
);
269 is_status(SecItemCopyMatching(item
, NULL
), errSecAuthFailed
, "find local - acl with application password and user present");
270 LASetErrorCodeBlock(okBlock
);
271 set_app_password(acmContext
);
272 ok_status(SecItemDelete(item
), "delete local - acl with application password and user present");
273 CFReleaseSafe(aclRef
);
275 LASetErrorCodeBlock(okBlock
);
276 aclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, kSecAccessControlUserPresence
, NULL
);
277 SecAccessControlSetRequirePassword(aclRef
, true);
278 SecAccessConstraintRef constraint
= SecAccessConstraintCreatePolicy(kCFAllocatorDefault
, CFSTR(kACMPolicyDeviceOwnerAuthentication
), NULL
);
279 SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpDelete
, constraint
, NULL
);
280 CFRelease(constraint
);
281 ok(aclRef
, "Create SecAccessControlRef");
283 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclRef
);
284 CFDictionarySetValue(item
, kSecUseCredentialReference
, credRefData
);
285 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
286 ok_status(SecItemAdd(item
, NULL
), "add local - acl with application password and user present");
287 LASetErrorCodeBlock(authFailedBlock
);
288 is_status(SecItemCopyMatching(item
, NULL
), errSecAuthFailed
, "find local - acl with application password and user present");
289 set_app_password(acmContext
);
290 is_status(SecItemDelete(item
), errSecAuthFailed
, "delete local - acl with application password and user present");
293 CFReleaseSafe(aclRef
);
295 // Update tests for item with application password:
297 // Prepare query for item without ACL.
298 item
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, kSecClassInternetPassword
, NULL
);
299 fillItem(item
, (*item_num
)++);
300 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
302 // Add test item without ACL and check that it can be found.
303 ok_status(SecItemAdd(item
, NULL
), "add local - no acl");
304 ok_status(SecItemCopyMatching(item
, NULL
), "find local - no acl");
306 // Update test item by adding ACL with application password flag.
307 CFMutableDictionaryRef update
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
308 aclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleAlwaysPrivate
, kSecAccessControlApplicationPassword
, NULL
);
309 CFDictionarySetValue(update
, kSecAttrAccessControl
, aclRef
);
310 set_app_password(acmContext
);
311 CFDictionarySetValue(item
, kSecUseCredentialReference
, credRefData
);
312 LASetErrorCodeBlock(okBlock
);
313 ok_status(SecItemUpdate(item
, update
), "update local - acl with application password");
315 LASetErrorCodeBlock(authFailedBlock
);
316 ok_status(SecItemCopyMatching(item
, NULL
), "find local - acl with application password");
317 CFDictionaryRemoveValue(item
, kSecUseCredentialReference
);
318 is_status(SecItemCopyMatching(item
, NULL
), errSecAuthFailed
, "find local - acl with application password (without ACM context)");
319 CFDictionarySetValue(item
, kSecUseCredentialReference
, credRefData
);
320 ok_status(SecItemCopyMatching(item
, NULL
), "find local - acl with application password (with ACM context)");
322 // 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).
323 CFDictionarySetValue(update
, kSecUseCredentialReference
, credRefData
);
324 LASetErrorCodeBlock(okBlock
);
325 is_status(SecItemUpdate(item
, update
), errSecParam
, "update local - add application password");
327 CFDictionaryRemoveValue(update
, kSecUseCredentialReference
);
328 LASetErrorCodeBlock(okBlock
);
329 ok_status(SecItemUpdate(item
, update
), "update local - updated with the same application password");
330 LASetErrorCodeBlock(authFailedBlock
);
331 ok_status(SecItemCopyMatching(item
, NULL
), "find local - updated with the same application password"); // LA authFailedBlock is not called.
333 CFReleaseSafe(aclRef
);
334 // Update item with ACL without application password.
335 aclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleAlwaysPrivate
, 0, NULL
);
336 CFDictionarySetValue(update
, kSecAttrAccessControl
, aclRef
);
338 LASetErrorCodeBlock(okBlock
);
339 ok_status(SecItemUpdate(item
, update
), "update local - remove application password");
341 CFDictionaryRemoveValue(item
, kSecUseCredentialReference
);
342 LASetErrorCodeBlock(authFailedBlock
);
343 ok_status(SecItemCopyMatching(item
, NULL
), "find local - acl without application password"); // LA authFailedBlock is not called.
345 ok_status(SecItemDelete(item
), "delete local - acl without application password");
349 CFReleaseSafe(aclRef
);
351 ACMContextDelete(acmContext
, true);
352 CFReleaseSafe(credRefData
);
356 static void item_with_invalid_acl(uint32_t *item_num
)
358 CFErrorRef (^errorParamBlock
)(void) = ^ {
359 return createCFError(CFSTR(""), kLAErrorParameter
);
362 CFMutableDictionaryRef item
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, kSecClassInternetPassword
, NULL
);
363 fillItem(item
, (*item_num
)++);
365 SecAccessControlRef invalidAclRef
= SecAccessControlCreate(kCFAllocatorDefault
, NULL
);
366 ok(invalidAclRef
, "Create invalid SecAccessControlRef");
367 ok(SecAccessControlSetProtection(invalidAclRef
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, NULL
), "Set protection");
368 CFTypeRef constraint
= SecAccessConstraintCreatePolicy(kCFAllocatorDefault
, CFSTR("invalidPolicy"), NULL
);
369 ok(constraint
, "Create invalid constraint");
370 ok(SecAccessControlAddConstraintForOperation(invalidAclRef
, kAKSKeyOpDecrypt
, constraint
, NULL
), "Add invalid constraint");
371 CFReleaseSafe(constraint
);
373 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
374 CFDictionarySetValue(item
, kSecAttrAccessControl
, invalidAclRef
);
376 LASetErrorCodeBlock(errorParamBlock
);
377 is_status(SecItemAdd(item
, NULL
), errSecParam
, "do not add local with invalid acl");
378 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find after add failed");
380 CFReleaseSafe(invalidAclRef
);
384 static void item_with_acl_caused_maxauth(uint32_t *item_num
)
386 CFErrorRef (^okBlock
)(void) = ^ {
387 return (CFErrorRef
)NULL
;
390 CFMutableDictionaryRef item
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, kSecClassInternetPassword
, NULL
);
391 fillItem(item
, (*item_num
)++);
393 SecAccessControlRef aclRef
= SecAccessControlCreate(kCFAllocatorDefault
, NULL
);
394 ok(aclRef
, "Create SecAccessControlRef");
395 ok(SecAccessControlSetProtection(aclRef
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, NULL
));
396 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpEncrpyt
, kCFBooleanFalse
, NULL
));
398 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
399 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclRef
);
401 __security_simulatecrash_enable(false);
403 LASetErrorCodeBlock(okBlock
);
404 diag("this will cause an internal assert - on purpose");
405 is_status(SecItemAdd(item
, NULL
), errSecAuthFailed
, "max auth attempts failed");
407 is(__security_simulatecrash_enable(true), 1, "Expecting simcrash max auth threshold passed");
409 CFReleaseSafe(aclRef
);
413 static void item_with_akpu(uint32_t *item_num
)
415 CFErrorRef (^okBlock
)(void) = ^ {
416 return (CFErrorRef
)NULL
;
419 CFMutableDictionaryRef item
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, kSecClassGenericPassword
, NULL
);
420 fillItem(item
, (*item_num
)++);
422 SecAccessControlRef aclRef
= SecAccessControlCreate(kCFAllocatorDefault
, NULL
);
423 ok(aclRef
, "Create SecAccessControlRef");
424 ok(SecAccessControlSetProtection(aclRef
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, NULL
));
425 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpEncrpyt
, kCFBooleanTrue
, NULL
));
426 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpDecrypt
, kCFBooleanTrue
, NULL
));
427 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpDelete
, kCFBooleanTrue
, NULL
));
429 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
430 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclRef
);
432 LASetErrorCodeBlock(okBlock
);
433 ok_status(SecItemAdd(item
, NULL
), "add item with akpu");
434 ok_status(SecItemCopyMatching(item
, NULL
), "find item with akpu");
435 changePasscode(passcode1
, NULL
);
436 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find item with akpu");
437 is_status(SecItemAdd(item
, NULL
), errSecAuthFailed
, "cannot add item with akpu without passcode");
438 changePasscode(NULL
, passcode2
);
439 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find item with akpu");
440 ok_status(SecItemAdd(item
, NULL
), "add item with akpu");
442 changePasscode(passcode2
, passcode1
);
443 CFReleaseSafe(aclRef
);
448 static void item_with_skip_auth_ui(uint32_t *item_num
)
450 CFMutableDictionaryRef item
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, kSecClassInternetPassword
, NULL
);
451 fillItem(item
, (*item_num
)++);
453 SecAccessControlRef aclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, kSecAccessControlDevicePasscode
, NULL
);
454 ok(aclRef
, "Create SecAccessControlRef");
456 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclRef
);
457 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUISkip
);
458 is_status(SecItemAdd(item
, NULL
), errSecParam
, "add local - invalid kSecUseAuthenticationUISkip");
459 is_status(SecItemDelete(item
), errSecParam
, "delete local - invalid kSecUseAuthenticationUISkip");
461 CFReleaseNull(aclRef
);
465 int secd_81_item_acl(int argc
, char *const *argv
)
467 uint32_t item_num
= 1;
468 #if LA_CONTEXT_IMPLEMENTED
469 secd_test_setup_temp_keychain(__FUNCTION__
, ^{
470 keybag_state_t state
;
471 int passcode_len
=(int)strlen(passcode1
);
473 ok(kIOReturnSuccess
==aks_create_bag(passcode1
, passcode_len
, kAppleKeyStoreDeviceBag
, &test_keybag
), "create keybag");
474 ok(kIOReturnSuccess
==aks_get_lock_state(test_keybag
, &state
), "get keybag state");
475 ok(!(state
&keybag_state_locked
), "keybag unlocked");
476 SecItemServerSetKeychainKeybag(test_keybag
);
483 item_with_skip_auth_ui(&item_num
);
484 item_with_invalid_acl(&item_num
);
485 item_with_application_password(&item_num
);
486 item_with_acl_caused_maxauth(&item_num
);
487 item_with_akpu(&item_num
);
490 item_with_skip_auth_ui(&item_num
);
493 #if LA_CONTEXT_IMPLEMENTED
494 SecItemServerResetKeychainKeybag();