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>
26 #include <coreauthd_spi.h>
29 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
30 #include <MobileKeyBag/MobileKeyBag.h>
40 kAccessabilityItemAttr
,
44 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
45 CFStringRef temporaryPasscode
= CFSTR("1111");
46 static bool changePasscode(CFStringRef oldPasscode
, CFStringRef newPasscode
)
48 CFDataRef oldPasscodeData
= NULL
;
49 CFDataRef newPasscodeData
= NULL
;
51 oldPasscodeData
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, oldPasscode
, kCFStringEncodingUTF8
, 0x00);
55 newPasscodeData
= CFStringCreateExternalRepresentation(kCFAllocatorDefault
, newPasscode
, kCFStringEncodingUTF8
, 0x00);
58 int status
= MKBKeyBagChangeSystemSecret(oldPasscodeData
, newPasscodeData
, NULL
);
60 CFReleaseSafe(oldPasscodeData
);
61 CFReleaseSafe(newPasscodeData
);
62 return status
== kMobileKeyBagSuccess
;
66 #if !TARGET_OS_SIMULATOR
67 static void WithEachString(void(^each
)(CFStringRef attr
, enum ItemAttrType atype
), ...) {
71 while((attr
= va_arg(ap
, CFStringRef
)) != NULL
) {
72 enum ItemAttrType atype
= va_arg(ap
, enum ItemAttrType
);
78 static void ItemForEachPKAttr(CFMutableDictionaryRef item
, void(^each
)(CFStringRef attr
, enum ItemAttrType atype
)) {
79 CFStringRef iclass
= CFDictionaryGetValue(item
, kSecClass
);
82 } else if (CFEqual(iclass
, kSecClassGenericPassword
)) {
84 kSecAttrAccessible
, kAccessabilityItemAttr
,
85 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
86 kSecAttrAccount
, kStringItemAttr
,
87 kSecAttrService
, kStringItemAttr
,
88 kSecAttrSynchronizable
, kBoolItemAttr
,
90 } else if (CFEqual(iclass
, kSecClassInternetPassword
)) {
92 kSecAttrAccessible
, kAccessabilityItemAttr
,
93 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
94 kSecAttrAccount
, kStringItemAttr
,
95 kSecAttrSecurityDomain
, kStringItemAttr
,
96 kSecAttrServer
, kStringItemAttr
,
97 kSecAttrProtocol
, kNumberItemAttr
,
98 kSecAttrAuthenticationType
, kNumberItemAttr
,
99 kSecAttrPort
, kNumberItemAttr
,
100 kSecAttrPath
, kStringItemAttr
,
101 kSecAttrSynchronizable
, kBoolItemAttr
,
103 } else if (CFEqual(iclass
, kSecClassCertificate
)) {
105 kSecAttrAccessible
, kAccessabilityItemAttr
,
106 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
107 kSecAttrCertificateType
, kNumberItemAttr
,
108 kSecAttrIssuer
, kDataItemAttr
,
109 kSecAttrSerialNumber
, kDataItemAttr
,
110 kSecAttrSynchronizable
, kBoolItemAttr
,
112 } else if (CFEqual(iclass
, kSecClassKey
)) {
114 kSecAttrAccessible
, kAccessabilityItemAttr
,
115 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
116 kSecAttrKeyClass
, kStringItemAttr
, // kNumberItemAttr on replies
117 kSecAttrApplicationLabel
, kDataItemAttr
,
118 kSecAttrApplicationTag
, kDataItemAttr
,
119 kSecAttrKeyType
, kNumberItemAttr
,
120 kSecAttrKeySizeInBits
, kNumberItemAttr
,
121 kSecAttrEffectiveKeySize
, kNumberItemAttr
,
122 kSecAttrStartDate
, kDateItemAttr
,
123 kSecAttrEndDate
, kDateItemAttr
,
124 kSecAttrSynchronizable
, kBoolItemAttr
,
126 } else if (CFEqual(iclass
, kSecClassIdentity
)) {
128 kSecAttrAccessible
, kAccessabilityItemAttr
,
129 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
130 kSecAttrCertificateType
, kNumberItemAttr
,
131 kSecAttrIssuer
, kDataItemAttr
,
132 kSecAttrSerialNumber
, kDataItemAttr
,
133 kSecAttrSynchronizable
, kBoolItemAttr
,
134 kSecAttrKeyClass
, kStringItemAttr
, // kNumberItemAttr on replies
135 kSecAttrApplicationLabel
, kDataItemAttr
,
136 kSecAttrApplicationTag
, kDataItemAttr
,
137 kSecAttrKeyType
, kNumberItemAttr
,
138 kSecAttrKeySizeInBits
, kNumberItemAttr
,
139 kSecAttrEffectiveKeySize
, kNumberItemAttr
,
140 kSecAttrStartDate
, kDateItemAttr
,
141 kSecAttrEndDate
, kDateItemAttr
,
142 kSecAttrSynchronizable
, kBoolItemAttr
,
147 static CFMutableDictionaryRef
ItemCreate(int num
) {
148 CFStringRef iclass
= NULL
;
151 iclass
= kSecClassInternetPassword
;
154 iclass
= kSecClassGenericPassword
;
157 iclass
= kSecClassKey
;
160 iclass
= kSecClassCertificate
;
163 return CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, iclass
, NULL
);
166 static void tests(bool isPasscodeSet
)
168 for (int num
= 0 ; num
< 8; ++num
) {
169 __block CFTypeRef protection
= kSecAttrAccessibleWhenUnlocked
;
170 CFMutableDictionaryRef item
= ItemCreate(num
);
171 ItemForEachPKAttr(item
, ^(CFStringRef attr
, enum ItemAttrType atype
) {
172 CFTypeRef value
= NULL
;
175 value
= (num
% 2 == 0 ? kCFBooleanTrue
: kCFBooleanFalse
);
178 case kNumberItemAttr
:
179 value
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &num
);
181 case kStringItemAttr
:
183 value
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("acl-stress-string-%d"), num
);
188 int len
= snprintf(buf
, sizeof(buf
), "acl-stress-data-%d", num
);
189 value
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)buf
, len
);
193 value
= NULL
; // Don't mess with dates on create.
195 case kAccessabilityItemAttr
:
197 CFStringRef accessabilites
[] = {
198 kSecAttrAccessibleWhenUnlocked
,
199 kSecAttrAccessibleAfterFirstUnlock
,
200 kSecAttrAccessibleAlwaysPrivate
,
201 kSecAttrAccessibleWhenUnlockedThisDeviceOnly
,
202 kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
,
203 kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate
,
205 protection
= accessabilites
[num
% array_size(accessabilites
)];
208 case kAccessGroupItemAttr
:
210 CFStringRef accessGroups
[] = {
212 CFSTR("com.apple.security.sos"), // Secd internally uses this
214 value
= accessGroups
[num
% array_size(accessGroups
)];
219 CFDictionarySetValue(item
, attr
, value
);
220 CFReleaseSafe(value
);
223 SecAccessControlRef aclRef
= SecAccessControlCreate(kCFAllocatorDefault
, NULL
);
224 ok(aclRef
, "Create SecAccessControlRef");
225 ok(SecAccessControlSetProtection(aclRef
, protection
, NULL
), "Set protection");
226 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpDecrypt
, kCFBooleanTrue
, NULL
), "Set operation decrypt to true");
227 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpDelete
, kCFBooleanTrue
, NULL
), "Set operation delete to true");
228 ok(SecAccessControlAddConstraintForOperation(aclRef
, kAKSKeyOpEncrypt
, kCFBooleanTrue
, NULL
), "Set operation encrypt to true");
230 SecAccessControlRef invalidAclRef
= SecAccessControlCreate(kCFAllocatorDefault
, NULL
);
231 ok(invalidAclRef
, "Create invalid SecAccessControlRef");
232 ok(SecAccessControlSetProtection(invalidAclRef
, protection
, NULL
), "Set protection");
233 CFTypeRef constraint
= SecAccessConstraintCreatePolicy(kCFAllocatorDefault
, CFSTR("invalidPolicy"), NULL
);
234 ok(constraint
, "Create invalid constraint");
235 ok(SecAccessControlAddConstraintForOperation(invalidAclRef
, kAKSKeyOpDecrypt
, constraint
, NULL
), "Add invalid constraint");
236 CFReleaseSafe(constraint
);
238 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
239 CFDictionarySetValue(item
, kSecAttrAccessControl
, invalidAclRef
);
240 is_status(SecItemAdd(item
, NULL
), errSecParam
, "do not add local with invalid acl");
241 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find after add failed");
243 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclRef
);
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");
249 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanTrue
);
250 is_status(SecItemAdd(item
, NULL
), errSecParam
, "add sync");
251 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find sync");
252 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
);
254 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
256 SecAccessControlRef privateKeyUsageAclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, protection
, kSecAccessControlPrivateKeyUsage
, NULL
);
257 ok(privateKeyUsageAclRef
, "Create SecAccessControlRef for kSecAccessControlPrivateKeyUsage");
258 CFDictionarySetValue(item
, kSecAttrAccessControl
, privateKeyUsageAclRef
);
259 is_status(SecItemAdd(item
, NULL
), errSecAuthFailed
, "add local - kSecAccessControlPrivateKeyUsage without constraint");
260 CFReleaseNull(privateKeyUsageAclRef
);
263 privateKeyUsageAclRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, protection
, kSecAccessControlDevicePasscode
| kSecAccessControlPrivateKeyUsage
, NULL
);
264 ok(privateKeyUsageAclRef
, "Create SecAccessControlRef for kSecAccessControlPrivateKeyUsage");
265 CFDictionarySetValue(item
, kSecAttrAccessControl
, privateKeyUsageAclRef
);
266 is_status(SecItemAdd(item
, NULL
), errSecAuthFailed
, "add local - kSecAccessControlPrivateKeyUsage with constraint");
267 CFReleaseSafe(privateKeyUsageAclRef
);
268 SecAccessControlRef aclWithUIRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, protection
, kSecAccessControlUserPresence
, NULL
);
269 ok(aclWithUIRef
, "Create SecAccessControlRef which require UI interaction");
271 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclWithUIRef
);
272 ok_status(SecItemAdd(item
, NULL
), "add local - acl with authentication UI");
273 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUIFail
);
274 is_status(SecItemCopyMatching(item
, NULL
), errSecInteractionNotAllowed
, "find local - acl with authentication UI");
275 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUISkip
);
276 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "find local - acl with authentication UI");
277 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUIAllow
);
278 ok_status(SecItemDelete(item
), "delete local - acl with authentication UI");
279 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find after delete local - acl with authentication UI");
281 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUIFail
);
282 ok_status(SecItemAdd(item
, NULL
), "add local - acl with authentication UI");
283 is_status(SecItemCopyMatching(item
, NULL
), errSecInteractionNotAllowed
, "find local - acl with authentication UI");
284 ok_status(SecItemDelete(item
), "delete local - acl with authentication UI");
285 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find after delete local - acl with authentication UI");
286 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUIAllow
);
287 CFReleaseSafe(aclWithUIRef
);
289 aclWithUIRef
= SecAccessControlCreateWithFlags(kCFAllocatorDefault
, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
, kSecAccessControlUserPresence
, NULL
);
290 ok(aclWithUIRef
, "Create SecAccessControlRef which require UI interaction");
292 CFDictionarySetValue(item
, kSecAttrAccessControl
, aclWithUIRef
);
293 ok_status(SecItemAdd(item
, NULL
), "add local - acl with authentication UI");
294 changePasscode(temporaryPasscode
, NULL
);
295 ok_status(SecItemDelete(item
), "delete local - AKPU");
296 changePasscode(NULL
, temporaryPasscode
);
297 CFReleaseSafe(aclWithUIRef
);
301 CFDictionarySetValue(item
, kSecUseAuthenticationUI
, kSecUseAuthenticationUISkip
);
302 is_status(SecItemAdd(item
, NULL
), errSecParam
, "add local - invalid kSecUseAuthenticationUISkip");
303 is_status(SecItemDelete(item
), errSecParam
, "delete local - invalid kSecUseAuthenticationUISkip");
306 CFReleaseSafe(aclRef
);
307 CFReleaseSafe(invalidAclRef
);
312 int sec_acl_stress(int argc
, char *const *argv
)
314 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
315 bool removeTemporaryPasscode
= false;
316 bool isPasscodeSet
= false;
317 if (MKBGetDeviceLockState(NULL
) == kMobileKeyBagDisabled
) {
318 removeTemporaryPasscode
= changePasscode(NULL
, temporaryPasscode
);
319 isPasscodeSet
= MKBGetDeviceLockState(NULL
) != kMobileKeyBagDisabled
;
322 plan_tests(isPasscodeSet
?288:168);
323 tests(isPasscodeSet
);
325 if (removeTemporaryPasscode
) {
326 changePasscode(temporaryPasscode
, NULL
);
328 #elif TARGET_OS_MAC && !TARGET_OS_SIMULATOR