]>
Commit | Line | Data |
---|---|---|
d8f41ccd | 1 | // |
5c19dc3a A |
2 | // sec_acl_stress.c |
3 | // Security | |
d8f41ccd | 4 | // |
5c19dc3a | 5 | // Created by Vratislav Kužela on 20/05/15. |
d8f41ccd A |
6 | // |
7 | // | |
8 | ||
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> | |
16 | #include <stdlib.h> | |
17 | #include <unistd.h> | |
18 | #include <Security/SecAccessControl.h> | |
19 | #include <Security/SecAccessControlPriv.h> | |
20 | #include <libaks_acl_cf_keys.h> | |
d8f41ccd | 21 | |
5c19dc3a | 22 | #include "testlist.h" |
d8f41ccd | 23 | |
5c19dc3a | 24 | #if TARGET_OS_MAC && !(TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR) |
d8f41ccd | 25 | #define USE_KEYSTORE 1 |
5c19dc3a | 26 | #elif TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR |
d8f41ccd A |
27 | #define USE_KEYSTORE 1 |
28 | #else /* no keystore on this platform */ | |
29 | #define USE_KEYSTORE 0 | |
30 | #endif | |
31 | ||
32 | #if USE_KEYSTORE | |
33 | #include <coreauthd_spi.h> | |
34 | #endif | |
35 | ||
5c19dc3a A |
36 | #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR |
37 | #include <MobileKeyBag/MobileKeyBag.h> | |
38 | #endif | |
39 | ||
d8f41ccd A |
40 | enum ItemAttrType { |
41 | kBoolItemAttr, | |
42 | kNumberItemAttr, | |
43 | kStringItemAttr, | |
44 | kDataItemAttr, | |
45 | kBlobItemAttr, | |
46 | kDateItemAttr, | |
47 | kAccessabilityItemAttr, | |
48 | kAccessGroupItemAttr, | |
49 | }; | |
50 | ||
5c19dc3a A |
51 | #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR |
52 | CFStringRef temporaryPasscode = CFSTR("1111"); | |
53 | static bool changePasscode(CFStringRef oldPasscode, CFStringRef newPasscode) | |
54 | { | |
55 | CFDataRef oldPasscodeData = NULL; | |
56 | CFDataRef newPasscodeData= NULL; | |
57 | if (oldPasscode) { | |
58 | oldPasscodeData = CFStringCreateExternalRepresentation(kCFAllocatorDefault, oldPasscode, kCFStringEncodingUTF8, 0x00); | |
59 | } | |
60 | ||
61 | if (newPasscode) { | |
62 | newPasscodeData = CFStringCreateExternalRepresentation(kCFAllocatorDefault, newPasscode, kCFStringEncodingUTF8, 0x00); | |
63 | } | |
64 | ||
65 | int status = MKBKeyBagChangeSystemSecret(oldPasscodeData, newPasscodeData, NULL); | |
66 | ||
67 | CFReleaseSafe(oldPasscodeData); | |
68 | CFReleaseSafe(newPasscodeData); | |
69 | return status == kMobileKeyBagSuccess; | |
70 | } | |
71 | #endif | |
72 | ||
73 | #if !TARGET_IPHONE_SIMULATOR | |
d8f41ccd A |
74 | static void WithEachString(void(^each)(CFStringRef attr, enum ItemAttrType atype), ...) { |
75 | va_list ap; | |
76 | va_start(ap, each); | |
77 | CFStringRef attr; | |
78 | while((attr = va_arg(ap, CFStringRef)) != NULL) { | |
79 | enum ItemAttrType atype = va_arg(ap, enum ItemAttrType); | |
80 | each(attr, atype); | |
81 | } | |
82 | va_end(ap); | |
83 | } | |
84 | ||
85 | static void ItemForEachPKAttr(CFMutableDictionaryRef item, void(^each)(CFStringRef attr, enum ItemAttrType atype)) { | |
86 | CFStringRef iclass = CFDictionaryGetValue(item, kSecClass); | |
87 | if (!iclass) { | |
88 | return; | |
89 | } else if (CFEqual(iclass, kSecClassGenericPassword)) { | |
90 | WithEachString(each, | |
5c19dc3a | 91 | kSecAttrAccessible, kAccessabilityItemAttr, |
d8f41ccd A |
92 | kSecAttrAccessGroup, kAccessGroupItemAttr, |
93 | kSecAttrAccount, kStringItemAttr, | |
94 | kSecAttrService, kStringItemAttr, | |
95 | kSecAttrSynchronizable, kBoolItemAttr, | |
96 | NULL); | |
97 | } else if (CFEqual(iclass, kSecClassInternetPassword)) { | |
98 | WithEachString(each, | |
5c19dc3a | 99 | kSecAttrAccessible, kAccessabilityItemAttr, |
d8f41ccd A |
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, | |
109 | NULL); | |
110 | } else if (CFEqual(iclass, kSecClassCertificate)) { | |
111 | WithEachString(each, | |
5c19dc3a | 112 | kSecAttrAccessible, kAccessabilityItemAttr, |
d8f41ccd A |
113 | kSecAttrAccessGroup, kAccessGroupItemAttr, |
114 | kSecAttrCertificateType, kNumberItemAttr, | |
115 | kSecAttrIssuer, kDataItemAttr, | |
116 | kSecAttrSerialNumber, kDataItemAttr, | |
117 | kSecAttrSynchronizable, kBoolItemAttr, | |
118 | NULL); | |
119 | } else if (CFEqual(iclass, kSecClassKey)) { | |
120 | WithEachString(each, | |
5c19dc3a | 121 | kSecAttrAccessible, kAccessabilityItemAttr, |
d8f41ccd A |
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, | |
132 | NULL); | |
133 | } else if (CFEqual(iclass, kSecClassIdentity)) { | |
134 | WithEachString(each, | |
5c19dc3a | 135 | kSecAttrAccessible, kAccessabilityItemAttr, |
d8f41ccd A |
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, | |
150 | NULL); | |
151 | } | |
152 | } | |
153 | ||
154 | static CFMutableDictionaryRef ItemCreate(int num) { | |
155 | CFStringRef iclass = NULL; | |
156 | switch (num % 4) { | |
157 | case 0: | |
158 | iclass = kSecClassInternetPassword; | |
159 | break; | |
160 | case 1: | |
161 | iclass = kSecClassGenericPassword; | |
162 | break; | |
163 | case 2: | |
164 | iclass = kSecClassKey; | |
165 | break; | |
166 | case 3: | |
167 | iclass = kSecClassCertificate; | |
168 | break; | |
169 | } | |
170 | return CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, iclass, NULL); | |
171 | } | |
172 | ||
173 | static void tests(bool isPasscodeSet) | |
174 | { | |
d8f41ccd | 175 | for (int num = 0 ; num < 8; ++num) { |
fa7225c8 | 176 | __block CFTypeRef protection = kSecAttrAccessibleWhenUnlocked; |
d8f41ccd A |
177 | CFMutableDictionaryRef item = ItemCreate(num); |
178 | ItemForEachPKAttr(item, ^(CFStringRef attr, enum ItemAttrType atype) { | |
179 | CFTypeRef value = NULL; | |
180 | switch (atype) { | |
181 | case kBoolItemAttr: | |
182 | value = (num % 2 == 0 ? kCFBooleanTrue : kCFBooleanFalse); | |
183 | CFRetain(value); | |
184 | break; | |
185 | case kNumberItemAttr: | |
186 | value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num); | |
187 | break; | |
188 | case kStringItemAttr: | |
189 | case kBlobItemAttr: | |
5c19dc3a | 190 | value = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("acl-stress-string-%d"), num); |
d8f41ccd A |
191 | break; |
192 | case kDataItemAttr: | |
193 | { | |
194 | char buf[10]; | |
5c19dc3a | 195 | int len = snprintf(buf, sizeof(buf), "acl-stress-data-%d", num); |
d8f41ccd A |
196 | value = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)buf, len); |
197 | break; | |
198 | } | |
199 | case kDateItemAttr: | |
200 | value = NULL; // Don't mess with dates on create. | |
201 | break; | |
202 | case kAccessabilityItemAttr: | |
203 | { | |
204 | CFStringRef accessabilites[] = { | |
205 | kSecAttrAccessibleWhenUnlocked, | |
206 | kSecAttrAccessibleAfterFirstUnlock, | |
fa7225c8 | 207 | kSecAttrAccessibleAlwaysPrivate, |
d8f41ccd A |
208 | kSecAttrAccessibleWhenUnlockedThisDeviceOnly, |
209 | kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, | |
fa7225c8 | 210 | kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate, |
d8f41ccd | 211 | }; |
5c19dc3a | 212 | protection = accessabilites[num % array_size(accessabilites)]; |
d8f41ccd A |
213 | break; |
214 | } | |
215 | case kAccessGroupItemAttr: | |
216 | { | |
217 | CFStringRef accessGroups[] = { | |
218 | NULL, | |
d8f41ccd | 219 | CFSTR("com.apple.security.sos"), // Secd internally uses this |
d8f41ccd A |
220 | }; |
221 | value = accessGroups[num % array_size(accessGroups)]; | |
222 | break; | |
223 | } | |
224 | } | |
225 | if (value) | |
226 | CFDictionarySetValue(item, attr, value); | |
227 | CFReleaseSafe(value); | |
228 | }); | |
229 | ||
5c19dc3a A |
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"); | |
236 | ||
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); | |
244 | ||
d8f41ccd A |
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"); | |
249 | ||
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"); | |
255 | ||
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); | |
5c19dc3a A |
260 | |
261 | #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR | |
fa7225c8 | 262 | assert(protection); |
5c19dc3a A |
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); | |
268 | ||
d8f41ccd | 269 | if(isPasscodeSet) { |
5c19dc3a A |
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"); | |
277 | ||
d8f41ccd | 278 | CFDictionarySetValue(item, kSecAttrAccessControl, aclWithUIRef); |
d8f41ccd | 279 | ok_status(SecItemAdd(item, NULL), "add local - acl with authentication UI"); |
5c19dc3a | 280 | CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIFail); |
d8f41ccd | 281 | is_status(SecItemCopyMatching(item, NULL), errSecInteractionNotAllowed, "find local - acl with authentication UI"); |
5c19dc3a A |
282 | CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUISkip); |
283 | is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "find local - acl with authentication UI"); | |
284 | CFDictionarySetValue(item, kSecUseAuthenticationUI, kSecUseAuthenticationUIAllow); | |
d8f41ccd A |
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"); | |
5c19dc3a A |
287 | |
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); | |
295 | ||
296 | aclWithUIRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlUserPresence, NULL); | |
297 | ok(aclWithUIRef, "Create SecAccessControlRef which require UI interaction"); | |
298 | ||
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); | |
d8f41ccd | 305 | } |
5c19dc3a A |
306 | #endif |
307 | ||
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"); | |
d8f41ccd A |
311 | |
312 | CFRelease(item); | |
5c19dc3a A |
313 | CFReleaseSafe(aclRef); |
314 | CFReleaseSafe(invalidAclRef); | |
d8f41ccd | 315 | } |
d8f41ccd | 316 | } |
5c19dc3a | 317 | #endif |
d8f41ccd | 318 | |
5c19dc3a | 319 | int sec_acl_stress(int argc, char *const *argv) |
d8f41ccd | 320 | { |
5c19dc3a A |
321 | #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR |
322 | bool removeTemporaryPasscode = false; | |
d8f41ccd | 323 | bool isPasscodeSet = false; |
5c19dc3a A |
324 | if (MKBGetDeviceLockState(NULL) == kMobileKeyBagDisabled) { |
325 | removeTemporaryPasscode = changePasscode(NULL, temporaryPasscode); | |
326 | isPasscodeSet = MKBGetDeviceLockState(NULL) != kMobileKeyBagDisabled; | |
327 | } | |
328 | ||
329 | plan_tests(isPasscodeSet?288:168); | |
d8f41ccd | 330 | tests(isPasscodeSet); |
5c19dc3a A |
331 | |
332 | if (removeTemporaryPasscode) { | |
333 | changePasscode(temporaryPasscode, NULL); | |
334 | } | |
335 | #elif TARGET_OS_MAC && !TARGET_IPHONE_SIMULATOR | |
336 | plan_tests(152); | |
337 | tests(false); | |
338 | #else | |
339 | plan_tests(1); | |
340 | ok(true); | |
341 | #endif | |
342 | ||
343 | ||
d8f41ccd A |
344 | return 0; |
345 | } |