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, generation_noop, 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);
206 CFDictionarySetValue(item, kSecValueData, (__bridge CFDataRef)[NSData dataWithBytes:"some data" length:9]);
209 static void tests(bool isPasscodeSet)
211 CFErrorRef (^okBlock)(void) = ^ {
212 return (CFErrorRef)NULL;
215 #if LA_CONTEXT_IMPLEMENTED
216 CFErrorRef (^errorNotInteractiveBlock)(void) = ^ {
217 return createCFError(CFSTR(""), kLAErrorNotInteractive);
221 CFArrayRef classArray = CFArrayCreateForCFTypes(kCFAllocatorDefault, kSecClassInternetPassword, kSecClassGenericPassword, kSecClassKey, kSecClassCertificate, NULL);
222 CFArrayRef protectionClassArray = CFArrayCreateForCFTypes(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlocked, kSecAttrAccessibleAfterFirstUnlock, kSecAttrAccessibleAlwaysPrivate,
223 kSecAttrAccessibleWhenUnlockedThisDeviceOnly, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
224 kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, NULL);
226 __block uint32_t pass = 0;
227 CFArrayForEach(classArray, ^(CFTypeRef itemClass) {
228 CFArrayForEach(protectionClassArray, ^(CFTypeRef protectionClass) {
229 CFMutableDictionaryRef item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, itemClass, NULL);
230 fillItem(item, ++pass);
232 LASetErrorCodeBlock(okBlock);
233 SecAccessControlRef aclRef = SecAccessControlCreate(kCFAllocatorDefault, NULL);
234 ok(aclRef, "Create SecAccessControlRef");
235 ok(SecAccessControlSetProtection(aclRef, protectionClass, NULL), "Set protection");
236 ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpDecrypt, kCFBooleanTrue, NULL), "Set operation decrypt to true");
237 ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpDelete, kCFBooleanTrue, NULL), "Set operation delete to true");
238 ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpEncrypt, kCFBooleanTrue, NULL), "Set operation encrypt to true");
240 LASetErrorCodeBlock(okBlock);
241 CFDictionarySetValue(item, kSecAttrAccessControl, aclRef);
242 CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse);
243 #if LA_CONTEXT_IMPLEMENTED
244 ok_status(SecItemAdd(item, NULL), "add local ");
245 ok_status(SecItemCopyMatching(item, NULL), "find local");
246 ok_status(SecItemDelete(item), "delete local");
247 is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find after delete local");
248 CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanTrue);
249 is_status(SecItemAdd(item, NULL), errSecParam, "add sync");
250 is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find sync");
251 CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse);
254 SecAccessControlRef aclWithUIRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, protectionClass, kSecAccessControlUserPresence, NULL);
255 ok(aclWithUIRef, "Create SecAccessControlRef which require UI interaction");
257 CFDictionarySetValue(item, kSecAttrAccessControl, aclWithUIRef);
258 ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI");
259 CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIFail);
260 LASetErrorCodeBlock(errorNotInteractiveBlock);
261 is_status(SecItemCopyMatching(item, NULL), errSecInteractionNotAllowed, "find local - acl with authentication UI");
262 CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUISkip);
263 is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "find local - acl with authentication UI");
264 CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow);
265 LASetErrorCodeBlock(okBlock);
266 ok_status(SecItemDelete(item), "delete local - acl with authentication UI");
267 is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find after delete local - acl with authentication UI");
269 CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIFail);
270 ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI");
271 LASetErrorCodeBlock(errorNotInteractiveBlock);
272 is_status(SecItemCopyMatching(item, NULL), errSecInteractionNotAllowed, "find local - acl with authentication UI");
273 LASetErrorCodeBlock(okBlock);
274 ok_status(SecItemDelete(item), "delete local - acl with authentication UI");
275 is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find after delete local - acl with authentication UI");
276 CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow);
278 SecAccessControlRef aclWithDeleteConstraintRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, protectionClass, kSecAccessControlUserPresence, NULL);
279 ok(aclWithDeleteConstraintRef, "Create SecAccessControlRef which require UI interaction for Delete operation");
280 CFTypeRef constraint = SecAccessConstraintCreatePolicy(kCFAllocatorDefault, CFSTR("DeviceOwnerAuthentication"), NULL);
282 ok(SecAccessControlAddConstraintForOperation(aclWithDeleteConstraintRef, kAKSKeyOpDelete, constraint, NULL), "Add constraint for operation delete");
283 CFReleaseSafe(constraint);
285 CFDictionarySetValue(item, kSecAttrAccessControl, aclWithDeleteConstraintRef);
286 ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI");
287 CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIFail);
288 LASetErrorCodeBlock(errorNotInteractiveBlock);
289 is_status(SecItemDelete(item), errSecInteractionNotAllowed, "delete local - acl with authentication UI");
291 if (CFEqual(protectionClass, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) {
292 CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow);
293 ok(changePasscode(passcode, NULL));
294 LASetErrorCodeBlock(okBlock);
295 ok_status(SecItemDelete(item), "delete local - acl with authentication UI");
296 ok(changePasscode(NULL, passcode));
298 CFReleaseSafe(aclWithUIRef);
299 CFReleaseSafe(aclWithDeleteConstraintRef);
301 aclWithUIRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence, NULL);
302 ok(aclWithUIRef, "Create SecAccessControlRef which require UI interaction");
304 CFDictionarySetValue(item, kSecAttrAccessControl, aclWithUIRef);
305 ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI");
306 changePasscode(passcode, NULL);
307 ok_status(SecItemDelete(item), "delete local - AKPU");
308 changePasscode(NULL, passcode);
310 aclWithDeleteConstraintRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence, NULL);
311 ok(aclWithDeleteConstraintRef, "Create SecAccessControlRef which require UI interaction for Delete operation");
312 constraint = SecAccessConstraintCreatePolicy(kCFAllocatorDefault, CFSTR("DeviceOwnerAuthentication"), NULL);
314 ok(SecAccessControlAddConstraintForOperation(aclWithDeleteConstraintRef, kAKSKeyOpDelete, constraint, NULL), "Add constraint for operation delete");
315 CFReleaseSafe(constraint);
317 CFDictionarySetValue(item, kSecAttrAccessControl, aclWithDeleteConstraintRef);
318 ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI");
319 changePasscode(passcode, NULL);
320 ok_status(SecItemDelete(item), "delete local - AKPU + prot odel");
321 changePasscode(NULL, passcode);
323 CFReleaseNull(aclWithUIRef);
324 CFReleaseNull(aclWithDeleteConstraintRef);
326 CFReleaseNull(aclWithUIRef);
327 CFReleaseNull(aclWithDeleteConstraintRef);
331 CFReleaseNull(aclRef);
335 CFRelease(classArray);
336 CFRelease(protectionClassArray);
339 int secd_81_item_acl_stress(int argc, char *const *argv)
341 #if LA_CONTEXT_IMPLEMENTED
342 secd_test_setup_temp_keychain(__FUNCTION__, ^{
343 keybag_state_t state;
344 int passcode_len=(int)strlen(passcode);
346 ok(kIOReturnSuccess==aks_create_bag(passcode, passcode_len, kAppleKeyStoreDeviceBag, &test_keybag), "create keybag");
347 ok(kIOReturnSuccess==aks_get_lock_state(test_keybag, &state), "get keybag state");
348 ok(!(state&keybag_state_locked), "keybag unlocked");
349 SecItemServerSetKeychainKeybag(test_keybag);
352 bool isPasscodeSet = true;
354 bool isPasscodeSet = false;
357 plan_tests(isPasscodeSet?776:140);
359 tests(isPasscodeSet);
361 #if LA_CONTEXT_IMPLEMENTED
362 SecItemServerResetKeychainKeybag();