5 // Created by Vratislav Kužela on 20/05/15.
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>
24 #if TARGET_OS_MAC && !(TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)
25 #define USE_KEYSTORE 1
26 #elif TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
27 #define USE_KEYSTORE 1
28 #else /* no keystore on this platform */
29 #define USE_KEYSTORE 0
33 #include <coreauthd_spi.h>
36 #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
37 #include <MobileKeyBag/MobileKeyBag.h>
47 kAccessabilityItemAttr
,
51 #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
52 CFStringRef temporaryPasscode
= CFSTR("1111");
53 static bool changePasscode(CFStringRef oldPasscode
, CFStringRef newPasscode
)
55 CFDataRef oldPasscodeData
= NULL
;
56 CFDataRef newPasscodeData
= NULL
;
58 oldPasscodeData
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, oldPasscode
, kCFStringEncodingUTF8
, 0x00);
62 newPasscodeData
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, newPasscode
, kCFStringEncodingUTF8
, 0x00);
65 int status
= MKBKeyBagChangeSystemSecret(oldPasscodeData
, newPasscodeData
, NULL
);
67 CFReleaseSafe(oldPasscodeData
);
68 CFReleaseSafe(newPasscodeData
);
69 return status
== kMobileKeyBagSuccess
;
73 #if !TARGET_IPHONE_SIMULATOR
74 static void WithEachString(void(^each
)(CFStringRef attr
, enum ItemAttrType atype
), ...) {
78 while((attr
= va_arg(ap
, CFStringRef
)) != NULL
) {
79 enum ItemAttrType atype
= va_arg(ap
, enum ItemAttrType
);
85 static void ItemForEachPKAttr(CFMutableDictionaryRef item
, void(^each
)(CFStringRef attr
, enum ItemAttrType atype
)) {
86 CFStringRef iclass
= CFDictionaryGetValue(item
, kSecClass
);
89 } else if (CFEqual(iclass
, kSecClassGenericPassword
)) {
91 kSecAttrAccessible
, kAccessabilityItemAttr
,
92 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
93 kSecAttrAccount
, kStringItemAttr
,
94 kSecAttrService
, kStringItemAttr
,
95 kSecAttrSynchronizable
, kBoolItemAttr
,
97 } else if (CFEqual(iclass
, kSecClassInternetPassword
)) {
99 kSecAttrAccessible
, kAccessabilityItemAttr
,
100 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
101 kSecAttrAccount
, kStringItemAttr
,
102 kSecAttrSecurityDomain
, kStringItemAttr
,
103 kSecAttrServer
, kStringItemAttr
,
104 kSecAttrProtocol
, kNumberItemAttr
,
105 kSecAttrAuthenticationType
, kNumberItemAttr
,
106 kSecAttrPort
, kNumberItemAttr
,
107 kSecAttrPath
, kStringItemAttr
,
108 kSecAttrSynchronizable
, kBoolItemAttr
,
110 } else if (CFEqual(iclass
, kSecClassCertificate
)) {
112 kSecAttrAccessible
, kAccessabilityItemAttr
,
113 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
114 kSecAttrCertificateType
, kNumberItemAttr
,
115 kSecAttrIssuer
, kDataItemAttr
,
116 kSecAttrSerialNumber
, kDataItemAttr
,
117 kSecAttrSynchronizable
, kBoolItemAttr
,
119 } else if (CFEqual(iclass
, kSecClassKey
)) {
121 kSecAttrAccessible
, kAccessabilityItemAttr
,
122 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
123 kSecAttrKeyClass
, kStringItemAttr
, // kNumberItemAttr on replies
124 kSecAttrApplicationLabel
, kDataItemAttr
,
125 kSecAttrApplicationTag
, kDataItemAttr
,
126 kSecAttrKeyType
, kNumberItemAttr
,
127 kSecAttrKeySizeInBits
, kNumberItemAttr
,
128 kSecAttrEffectiveKeySize
, kNumberItemAttr
,
129 kSecAttrStartDate
, kDateItemAttr
,
130 kSecAttrEndDate
, kDateItemAttr
,
131 kSecAttrSynchronizable
, kBoolItemAttr
,
133 } else if (CFEqual(iclass
, kSecClassIdentity
)) {
135 kSecAttrAccessible
, kAccessabilityItemAttr
,
136 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
137 kSecAttrCertificateType
, kNumberItemAttr
,
138 kSecAttrIssuer
, kDataItemAttr
,
139 kSecAttrSerialNumber
, kDataItemAttr
,
140 kSecAttrSynchronizable
, kBoolItemAttr
,
141 kSecAttrKeyClass
, kStringItemAttr
, // kNumberItemAttr on replies
142 kSecAttrApplicationLabel
, kDataItemAttr
,
143 kSecAttrApplicationTag
, kDataItemAttr
,
144 kSecAttrKeyType
, kNumberItemAttr
,
145 kSecAttrKeySizeInBits
, kNumberItemAttr
,
146 kSecAttrEffectiveKeySize
, kNumberItemAttr
,
147 kSecAttrStartDate
, kDateItemAttr
,
148 kSecAttrEndDate
, kDateItemAttr
,
149 kSecAttrSynchronizable
, kBoolItemAttr
,
154 static CFMutableDictionaryRef
ItemCreate(int num
) {
155 CFStringRef iclass
= NULL
;
158 iclass
= kSecClassInternetPassword
;
161 iclass
= kSecClassGenericPassword
;
164 iclass
= kSecClassKey
;
167 iclass
= kSecClassCertificate
;
170 return CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, iclass
, NULL
);
173 static void tests(bool isPasscodeSet
)
175 for (int num
= 0 ; num
< 8; ++num
) {
176 __block CFTypeRef protection
= kSecAttrAccessibleWhenUnlocked
;
177 CFMutableDictionaryRef item
= ItemCreate(num
);
178 ItemForEachPKAttr(item
, ^(CFStringRef attr
, enum ItemAttrType atype
) {
179 CFTypeRef value
= NULL
;
182 value
= (num
% 2 == 0 ? kCFBooleanTrue
: kCFBooleanFalse
);
185 case kNumberItemAttr
:
186 value
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &num
);
188 case kStringItemAttr
:
190 value
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("acl-stress-string-%d"), num
);
195 int len
= snprintf(buf
, sizeof(buf
), "acl-stress-data-%d", num
);
196 value
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)buf
, len
);
200 value
= NULL
; // Don't mess with dates on create.
202 case kAccessabilityItemAttr
:
204 CFStringRef accessabilites
[] = {
205 kSecAttrAccessibleWhenUnlocked
,
206 kSecAttrAccessibleAfterFirstUnlock
,
207 kSecAttrAccessibleAlwaysPrivate
,
208 kSecAttrAccessibleWhenUnlockedThisDeviceOnly
,
209 kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
,
210 kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate
,
212 protection
= accessabilites
[num
% array_size(accessabilites
)];
215 case kAccessGroupItemAttr
:
217 CFStringRef accessGroups
[] = {
219 CFSTR("com.apple.security.sos"), // Secd internally uses this
221 value
= accessGroups
[num
% array_size(accessGroups
)];
226 CFDictionarySetValue(item
, attr
, value
);
227 CFReleaseSafe(value
);
230 SecAccessControlRef aclRef
= SecAccessControlCreate(kCFAllocatorDefault
, NULL
);
231 ok(aclRef
, "Create SecAccessControlRef");
232 ok(SecAccessControlSetProtection(aclRef
, protection
, NULL
), "Set protection");
233 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpDecrypt
, kCFBooleanTrue
, NULL
), "Set operation decrypt to true");
234 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpDelete
, kCFBooleanTrue
, NULL
), "Set operation delete to true");
235 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpEncrypt
, kCFBooleanTrue
, NULL
), "Set operation encrypt to true");
237 SecAccessControlRef invalidAclRef
= SecAccessControlCreate(kCFAllocatorDefault
, NULL
);
238 ok(invalidAclRef
, "Create invalid SecAccessControlRef");
239 ok(SecAccessControlSetProtection(invalidAclRef
, protection
, NULL
), "Set protection");
240 CFTypeRef constraint
= SecAccessConstraintCreatePolicy(kCFAllocatorDefault
, CFSTR("invalidPolicy"), NULL
);
241 ok(constraint
, "Create invalid constraint");
242 ok(SecAccessControlAddConstraintForOperation(invalidAclRef
, kAKSKeyOpDecrypt
, constraint
, NULL
), "Add invalid constraint");
243 CFReleaseSafe(constraint
);
245 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
246 CFDictionarySetValue(item
, kSecAttrAccessControl
, invalidAclRef
);
247 is_status(SecItemAdd(item
, NULL
), errSecParam
, "do not add local with invalid acl");
248 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find after add failed");
250 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclRef
);
251 ok_status(SecItemAdd(item
, NULL
), "add local ");
252 ok_status(SecItemCopyMatching(item
, NULL
), "find local");
253 ok_status(SecItemDelete(item
), "delete local");
254 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find after delete local");
256 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanTrue
);
257 is_status(SecItemAdd(item
, NULL
), errSecParam
, "add sync");
258 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find sync");
259 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
261 #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
263 SecAccessControlRef privateKeyUsageAclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, protection
, kSecAccessControlPrivateKeyUsage
, NULL
);
264 ok(privateKeyUsageAclRef
, "Create SecAccessControlRef for kSecAccessControlPrivateKeyUsage");
265 CFDictionarySetValue(item
, kSecAttrAccessControl
, privateKeyUsageAclRef
);
266 is_status(SecItemAdd(item
, NULL
), errSecAuthFailed
, "add local - kSecAccessControlPrivateKeyUsage without constraint");
267 CFReleaseNull(privateKeyUsageAclRef
);
270 privateKeyUsageAclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, protection
, kSecAccessControlDevicePasscode
| kSecAccessControlPrivateKeyUsage
, NULL
);
271 ok(privateKeyUsageAclRef
, "Create SecAccessControlRef for kSecAccessControlPrivateKeyUsage");
272 CFDictionarySetValue(item
, kSecAttrAccessControl
, privateKeyUsageAclRef
);
273 is_status(SecItemAdd(item
, NULL
), errSecAuthFailed
, "add local - kSecAccessControlPrivateKeyUsage with constraint");
274 CFReleaseSafe(privateKeyUsageAclRef
);
275 SecAccessControlRef aclWithUIRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, protection
, kSecAccessControlUserPresence
, NULL
);
276 ok(aclWithUIRef
, "Create SecAccessControlRef which require UI interaction");
278 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclWithUIRef
);
279 ok_status(SecItemAdd(item
, NULL
), "add local - acl with authentication UI");
280 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUIFail
);
281 is_status(SecItemCopyMatching(item
, NULL
), errSecInteractionNotAllowed
, "find local - acl with authentication UI");
282 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUISkip
);
283 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "find local - acl with authentication UI");
284 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUIAllow
);
285 ok_status(SecItemDelete(item
), "delete local - acl with authentication UI");
286 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find after delete local - acl with authentication UI");
288 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUIFail
);
289 ok_status(SecItemAdd(item
, NULL
), "add local - acl with authentication UI");
290 is_status(SecItemCopyMatching(item
, NULL
), errSecInteractionNotAllowed
, "find local - acl with authentication UI");
291 ok_status(SecItemDelete(item
), "delete local - acl with authentication UI");
292 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find after delete local - acl with authentication UI");
293 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUIAllow
);
294 CFReleaseSafe(aclWithUIRef
);
296 aclWithUIRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, kSecAccessControlUserPresence
, NULL
);
297 ok(aclWithUIRef
, "Create SecAccessControlRef which require UI interaction");
299 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclWithUIRef
);
300 ok_status(SecItemAdd(item
, NULL
), "add local - acl with authentication UI");
301 changePasscode(temporaryPasscode
, NULL
);
302 ok_status(SecItemDelete(item
), "delete local - AKPU");
303 changePasscode(NULL
, temporaryPasscode
);
304 CFReleaseSafe(aclWithUIRef
);
308 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUISkip
);
309 is_status(SecItemAdd(item
, NULL
), errSecParam
, "add local - invalid kSecUseAuthenticationUISkip");
310 is_status(SecItemDelete(item
), errSecParam
, "delete local - invalid kSecUseAuthenticationUISkip");
313 CFReleaseSafe(aclRef
);
314 CFReleaseSafe(invalidAclRef
);
319 int sec_acl_stress(int argc
, char *const *argv
)
321 #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
322 bool removeTemporaryPasscode
= false;
323 bool isPasscodeSet
= false;
324 if (MKBGetDeviceLockState(NULL
) == kMobileKeyBagDisabled
) {
325 removeTemporaryPasscode
= changePasscode(NULL
, temporaryPasscode
);
326 isPasscodeSet
= MKBGetDeviceLockState(NULL
) != kMobileKeyBagDisabled
;
329 plan_tests(isPasscodeSet
?288:168);
330 tests(isPasscodeSet
);
332 if (removeTemporaryPasscode
) {
333 changePasscode(temporaryPasscode
, NULL
);
335 #elif TARGET_OS_MAC && !TARGET_IPHONE_SIMULATOR