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"
29 #include <coreauthd_spi.h>
30 #include "SecdTestKeychainUtilities.h"
31 #if TARGET_OS_EMBEDDED
32 #include <MobileKeyBag/MobileKeyBag.h>
44 kAccessabilityItemAttr
,
48 extern void LASetErrorCodeBlock(CFErrorRef (^newCreateErrorBlock
)(void));
50 #if LA_CONTEXT_IMPLEMENTED
51 static keybag_handle_t test_keybag
;
52 static const char *passcode
= "password";
54 static bool changePasscode(const char *old_passcode
, const char *new_passcode
)
56 size_t old_passcode_len
= 0;
57 size_t new_passcode_len
= 0;
60 old_passcode_len
= strlen(old_passcode
);
63 new_passcode_len
= strlen(new_passcode
);
65 kern_return_t status
= aks_change_secret(test_keybag
, old_passcode
, (int)old_passcode_len
, new_passcode
, (int)new_passcode_len
, NULL
, NULL
);
70 static void WithEachString(void(^each
)(CFStringRef attr
, enum ItemAttrType atype
), ...) {
74 while((attr
= va_arg(ap
, CFStringRef
)) != NULL
) {
75 enum ItemAttrType atype
= va_arg(ap
, enum ItemAttrType
);
81 static void ItemForEachPKAttr(CFMutableDictionaryRef item
, void(^each
)(CFStringRef attr
, enum ItemAttrType atype
)) {
82 CFStringRef iclass
= CFDictionaryGetValue(item
, kSecClass
);
85 } else if (CFEqual(iclass
, kSecClassGenericPassword
)) {
87 kSecAttrAccessible
, kAccessabilityItemAttr
,
88 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
89 kSecAttrAccount
, kStringItemAttr
,
90 kSecAttrService
, kStringItemAttr
,
91 kSecAttrSynchronizable
, kBoolItemAttr
,
93 } else if (CFEqual(iclass
, kSecClassInternetPassword
)) {
95 kSecAttrAccessible
, kAccessabilityItemAttr
,
96 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
97 kSecAttrAccount
, kStringItemAttr
,
98 kSecAttrSecurityDomain
, kStringItemAttr
,
99 kSecAttrServer
, kStringItemAttr
,
100 kSecAttrProtocol
, kNumberItemAttr
,
101 kSecAttrAuthenticationType
, kNumberItemAttr
,
102 kSecAttrPort
, kNumberItemAttr
,
103 kSecAttrPath
, kStringItemAttr
,
104 kSecAttrSynchronizable
, kBoolItemAttr
,
106 } else if (CFEqual(iclass
, kSecClassCertificate
)) {
108 kSecAttrAccessible
, kAccessabilityItemAttr
,
109 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
110 kSecAttrCertificateType
, kNumberItemAttr
,
111 kSecAttrIssuer
, kDataItemAttr
,
112 kSecAttrSerialNumber
, kDataItemAttr
,
113 kSecAttrSynchronizable
, kBoolItemAttr
,
115 } else if (CFEqual(iclass
, kSecClassKey
)) {
117 kSecAttrAccessible
, kAccessabilityItemAttr
,
118 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
119 kSecAttrKeyClass
, kStringItemAttr
, // kNumberItemAttr on replies
120 kSecAttrApplicationLabel
, kDataItemAttr
,
121 kSecAttrApplicationTag
, kDataItemAttr
,
122 kSecAttrKeyType
, kNumberItemAttr
,
123 kSecAttrKeySizeInBits
, kNumberItemAttr
,
124 kSecAttrEffectiveKeySize
, kNumberItemAttr
,
125 kSecAttrStartDate
, kDateItemAttr
,
126 kSecAttrEndDate
, kDateItemAttr
,
127 kSecAttrSynchronizable
, kBoolItemAttr
,
129 } else if (CFEqual(iclass
, kSecClassIdentity
)) {
131 kSecAttrAccessible
, kAccessabilityItemAttr
,
132 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
133 kSecAttrCertificateType
, kNumberItemAttr
,
134 kSecAttrIssuer
, kDataItemAttr
,
135 kSecAttrSerialNumber
, kDataItemAttr
,
136 kSecAttrSynchronizable
, kBoolItemAttr
,
137 kSecAttrKeyClass
, kStringItemAttr
, // kNumberItemAttr on replies
138 kSecAttrApplicationLabel
, kDataItemAttr
,
139 kSecAttrApplicationTag
, kDataItemAttr
,
140 kSecAttrKeyType
, kNumberItemAttr
,
141 kSecAttrKeySizeInBits
, kNumberItemAttr
,
142 kSecAttrEffectiveKeySize
, kNumberItemAttr
,
143 kSecAttrStartDate
, kDateItemAttr
,
144 kSecAttrEndDate
, kDateItemAttr
,
145 kSecAttrSynchronizable
, kBoolItemAttr
,
150 #if LA_CONTEXT_IMPLEMENTED
152 static CFErrorRef
createCFError(CFStringRef message
, CFIndex code
)
154 const void* keysPtr
[1];
155 const void* messagesPtr
[1];
157 keysPtr
[0] = kCFErrorLocalizedDescriptionKey
;
158 messagesPtr
[0] = message
;
159 return CFErrorCreateWithUserInfoKeysAndValues(kCFAllocatorDefault
, CFSTR(kLAErrorDomain
), code
, keysPtr
, messagesPtr
, 1);
163 static void fillItem(CFMutableDictionaryRef item
, uint32_t num
)
165 ItemForEachPKAttr(item
, ^(CFStringRef attr
, enum ItemAttrType atype
) {
166 CFTypeRef value
= NULL
;
169 value
= (num
% 2 == 0 ? kCFBooleanTrue
: kCFBooleanFalse
);
172 case kNumberItemAttr
:
173 value
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &num
);
175 case kStringItemAttr
:
177 value
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("acl-stress-string-%d"), num
);
182 int len
= snprintf(buf
, sizeof(buf
), "acl-stress-data-%d", num
);
183 value
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)buf
, len
);
187 value
= NULL
; // Don't mess with dates on create.
189 case kAccessabilityItemAttr
:
191 case kAccessGroupItemAttr
:
193 CFStringRef accessGroups
[] = {
195 CFSTR("com.apple.security.sos"), // Secd internally uses this
197 value
= accessGroups
[num
% array_size(accessGroups
)];
202 CFDictionarySetValue(item
, attr
, value
);
203 CFReleaseSafe(value
);
207 static void tests(bool isPasscodeSet
)
209 CFErrorRef (^okBlock
)(void) = ^ {
210 return (CFErrorRef
)NULL
;
213 #if LA_CONTEXT_IMPLEMENTED
214 CFErrorRef (^errorNotInteractiveBlock
)(void) = ^ {
215 return createCFError(CFSTR(""), kLAErrorNotInteractive
);
219 CFArrayRef classArray
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, kSecClassInternetPassword
, kSecClassGenericPassword
, kSecClassKey
, kSecClassCertificate
, NULL
);
220 CFArrayRef protectionClassArray
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, kSecAttrAccessibleWhenUnlocked
, kSecAttrAccessibleAfterFirstUnlock
, kSecAttrAccessibleAlways
,
221 kSecAttrAccessibleWhenUnlockedThisDeviceOnly
, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
,
222 kSecAttrAccessibleAlwaysThisDeviceOnly
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, NULL
);
224 __block
uint32_t pass
= 0;
225 CFArrayForEach(classArray
, ^(CFTypeRef itemClass
) {
226 CFArrayForEach(protectionClassArray
, ^(CFTypeRef protectionClass
) {
227 CFMutableDictionaryRef item
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, itemClass
, NULL
);
228 fillItem(item
, ++pass
);
230 LASetErrorCodeBlock(okBlock
);
231 SecAccessControlRef aclRef
= SecAccessControlCreate(kCFAllocatorDefault
, NULL
);
232 ok(aclRef
, "Create SecAccessControlRef");
233 ok(SecAccessControlSetProtection(aclRef
, protectionClass
, NULL
), "Set protection");
234 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpDecrypt
, kCFBooleanTrue
, NULL
), "Set operation decrypt to true");
235 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpDelete
, kCFBooleanTrue
, NULL
), "Set operation delete to true");
236 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpEncrypt
, kCFBooleanTrue
, NULL
), "Set operation encrypt to true");
238 LASetErrorCodeBlock(okBlock
);
239 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclRef
);
240 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
241 #if LA_CONTEXT_IMPLEMENTED
242 ok_status(SecItemAdd(item
, NULL
), "add local ");
243 ok_status(SecItemCopyMatching(item
, NULL
), "find local");
244 ok_status(SecItemDelete(item
), "delete local");
245 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find after delete local");
246 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanTrue
);
247 is_status(SecItemAdd(item
, NULL
), errSecParam
, "add sync");
248 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find sync");
249 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
252 SecAccessControlRef aclWithUIRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, protectionClass
, kSecAccessControlUserPresence
, NULL
);
253 ok(aclWithUIRef
, "Create SecAccessControlRef which require UI interaction");
255 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclWithUIRef
);
256 ok_status(SecItemAdd(item
, NULL
), "add local - acl with authentication UI");
257 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUIFail
);
258 LASetErrorCodeBlock(errorNotInteractiveBlock
);
259 is_status(SecItemCopyMatching(item
, NULL
), errSecInteractionNotAllowed
, "find local - acl with authentication UI");
260 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUISkip
);
261 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "find local - acl with authentication UI");
262 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUIAllow
);
263 LASetErrorCodeBlock(okBlock
);
264 ok_status(SecItemDelete(item
), "delete local - acl with authentication UI");
265 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find after delete local - acl with authentication UI");
267 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUIFail
);
268 ok_status(SecItemAdd(item
, NULL
), "add local - acl with authentication UI");
269 LASetErrorCodeBlock(errorNotInteractiveBlock
);
270 is_status(SecItemCopyMatching(item
, NULL
), errSecInteractionNotAllowed
, "find local - acl with authentication UI");
271 LASetErrorCodeBlock(okBlock
);
272 ok_status(SecItemDelete(item
), "delete local - acl with authentication UI");
273 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find after delete local - acl with authentication UI");
274 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUIAllow
);
276 SecAccessControlRef aclWithDeleteConstraintRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, protectionClass
, kSecAccessControlUserPresence
, NULL
);
277 ok(aclWithDeleteConstraintRef
, "Create SecAccessControlRef which require UI interaction for Delete operation");
278 CFTypeRef constraint
= SecAccessConstraintCreatePolicy(kCFAllocatorDefault
, CFSTR("DeviceOwnerAuthentication"), NULL
);
280 ok(SecAccessControlAddConstraintForOperation(aclWithDeleteConstraintRef
, kAKSKeyOpDelete
, constraint
, NULL
), "Add constraint for operation delete");
281 CFReleaseSafe(constraint
);
283 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclWithDeleteConstraintRef
);
284 ok_status(SecItemAdd(item
, NULL
), "add local - acl with authentication UI");
285 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUIFail
);
286 LASetErrorCodeBlock(errorNotInteractiveBlock
);
287 is_status(SecItemDelete(item
), errSecInteractionNotAllowed
, "delete local - acl with authentication UI");
289 if (CFEqual(protectionClass
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
)) {
290 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUIAllow
);
291 ok(changePasscode(passcode
, NULL
));
292 LASetErrorCodeBlock(okBlock
);
293 ok_status(SecItemDelete(item
), "delete local - acl with authentication UI");
294 ok(changePasscode(NULL
, passcode
));
296 CFReleaseSafe(aclWithUIRef
);
297 CFReleaseSafe(aclWithDeleteConstraintRef
);
299 aclWithUIRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, kSecAccessControlUserPresence
, NULL
);
300 ok(aclWithUIRef
, "Create SecAccessControlRef which require UI interaction");
302 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclWithUIRef
);
303 ok_status(SecItemAdd(item
, NULL
), "add local - acl with authentication UI");
304 changePasscode(passcode
, NULL
);
305 ok_status(SecItemDelete(item
), "delete local - AKPU");
306 changePasscode(NULL
, passcode
);
308 aclWithDeleteConstraintRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, kSecAccessControlUserPresence
, NULL
);
309 ok(aclWithDeleteConstraintRef
, "Create SecAccessControlRef which require UI interaction for Delete operation");
310 constraint
= SecAccessConstraintCreatePolicy(kCFAllocatorDefault
, CFSTR("DeviceOwnerAuthentication"), NULL
);
312 ok(SecAccessControlAddConstraintForOperation(aclWithDeleteConstraintRef
, kAKSKeyOpDelete
, constraint
, NULL
), "Add constraint for operation delete");
313 CFReleaseSafe(constraint
);
315 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclWithDeleteConstraintRef
);
316 ok_status(SecItemAdd(item
, NULL
), "add local - acl with authentication UI");
317 changePasscode(passcode
, NULL
);
318 ok_status(SecItemDelete(item
), "delete local - AKPU + prot odel");
319 changePasscode(NULL
, passcode
);
321 CFReleaseNull(aclWithUIRef
);
322 CFReleaseNull(aclWithDeleteConstraintRef
);
324 CFReleaseNull(aclWithUIRef
);
325 CFReleaseNull(aclWithDeleteConstraintRef
);
329 CFReleaseNull(aclRef
);
333 CFRelease(classArray
);
334 CFRelease(protectionClassArray
);
337 int secd_81_item_acl_stress(int argc
, char *const *argv
)
339 #if LA_CONTEXT_IMPLEMENTED
340 secd_test_setup_temp_keychain(__FUNCTION__
, ^{
341 keybag_state_t state
;
342 int passcode_len
=(int)strlen(passcode
);
344 ok(kIOReturnSuccess
==aks_create_bag(passcode
, passcode_len
, kAppleKeyStoreDeviceBag
, &test_keybag
), "create keybag");
345 ok(kIOReturnSuccess
==aks_get_lock_state(test_keybag
, &state
), "get keybag state");
346 ok(!(state
&keybag_state_locked
), "keybag unlocked");
347 SecItemServerSetKeychainKeybag(test_keybag
);
350 bool isPasscodeSet
= true;
352 bool isPasscodeSet
= false;
355 plan_tests(isPasscodeSet
?776:140);
357 tests(isPasscodeSet
);
359 #if LA_CONTEXT_IMPLEMENTED
360 SecItemServerResetKeychainKeybag();