]> git.saurik.com Git - apple/security.git/blob - RegressionTests/secitemfunctionality/secitemfunctionality.m
Security-59306.41.2.tar.gz
[apple/security.git] / RegressionTests / secitemfunctionality / secitemfunctionality.m
1 //
2 // Copyright 2016 Apple. All rights reserved.
3 //
4
5 /*
6 * This is to fool os services to not provide the Keychain manager
7 * interface tht doens't work since we don't have unified headers
8 * between iOS and OS X. rdar://23405418/
9 */
10 #define __KEYCHAINCORE__ 1
11
12 #include <Foundation/Foundation.h>
13 #include <Security/Security.h>
14 #include <Security/SecItemPriv.h>
15 #include <Security/SecBasePriv.h>
16 #include <Security/SecIdentityPriv.h>
17 #include <mach/mach_time.h>
18 #include <err.h>
19 #include <strings.h>
20
21 #if SEC_OS_OSX_INCLUDES
22 #include <Security/SecKeychain.h>
23 #endif
24
25 static void
26 fail(const char *fmt, ...) __printflike(1, 2) __attribute__((noreturn));
27
28
29 static void
30 fail(const char *fmt, ...)
31 {
32 va_list ap;
33 printf("[FAIL]\n");
34 fflush(stdout);
35
36 va_start(ap, fmt);
37 verrx(1, fmt, ap);
38 va_end(ap);
39 }
40
41 #if 0
42 /*
43 * Create item w/o data, try to make sure we end up in the OS X keychain
44 */
45
46 static void
47 CheckItemAddDeleteMaybeLegacyKeychainNoData(void)
48 {
49 OSStatus status;
50
51 printf("[BEGIN] %s\n", __FUNCTION__);
52
53 NSDictionary *query = @{
54 (id)kSecClass : (id)kSecClassGenericPassword,
55 (id)kSecAttrAccount : @"item-delete-me",
56 (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock,
57 };
58 status = SecItemDelete((__bridge CFDictionaryRef)query);
59 if (status != errSecSuccess && status != errSecItemNotFound)
60 fail("cleanup item: %d", (int)status);
61
62 /*
63 * now check add notification
64 */
65
66 status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
67 if (status != errSecSuccess)
68 fail("add item: %d: %s", (int)status, [[query description] UTF8String]);
69
70 /*
71 * clean up
72 */
73
74 status = SecItemDelete((__bridge CFDictionaryRef)query);
75 if (status != errSecSuccess)
76 fail("cleanup2 item: %d", (int)status);
77
78
79 printf("[PASS] %s\n", __FUNCTION__);
80
81 }
82 #endif
83
84 static void
85 CheckItemAddDeleteNoData(void)
86 {
87 OSStatus status;
88
89 printf("[BEGIN] %s\n", __FUNCTION__);
90
91 NSDictionary *query = @{
92 (id)kSecClass : (id)kSecClassGenericPassword,
93 (id)kSecAttrAccessGroup : @"keychain-test1",
94 (id)kSecAttrAccount : @"item-delete-me",
95 (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock,
96 (id)kSecUseDataProtectionKeychain: @YES,
97 };
98 status = SecItemDelete((__bridge CFDictionaryRef)query);
99 if (status != errSecSuccess && status != errSecItemNotFound)
100 fail("cleanup item: %d", (int)status);
101
102 /*
103 * Add item
104 */
105
106 status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
107 if (status != errSecSuccess)
108 fail("add item: %d: %s", (int)status, [[query description] UTF8String]);
109
110 /*
111 * clean up
112 */
113
114 status = SecItemDelete((__bridge CFDictionaryRef)query);
115 if (status != errSecSuccess)
116 fail("cleanup2 item: %d", (int)status);
117
118 printf("[PASS] %s\n", __FUNCTION__);
119 }
120
121 static void
122 CheckItemUpdateAccessGroupGENP(void)
123 {
124 OSStatus status;
125
126 printf("[BEGIN] %s\n", __FUNCTION__);
127
128 NSDictionary *clean1 = @{
129 (id)kSecClass : (id)kSecClassGenericPassword,
130 (id)kSecAttrAccessGroup : @"keychain-test1",
131 (id)kSecUseDataProtectionKeychain: @YES,
132 };
133 NSDictionary *clean2 = @{
134 (id)kSecClass : (id)kSecClassGenericPassword,
135 (id)kSecAttrAccessGroup : @"keychain-test2",
136 (id)kSecUseDataProtectionKeychain: @YES,
137 };
138
139 (void)SecItemDelete((__bridge CFDictionaryRef)clean1);
140 (void)SecItemDelete((__bridge CFDictionaryRef)clean2);
141
142 /*
143 * Add item
144 */
145
146 NSDictionary *add = @{
147 (id)kSecClass : (id)kSecClassGenericPassword,
148 (id)kSecAttrAccessGroup : @"keychain-test1",
149 (id)kSecAttrAccount : @"item-delete-me",
150 (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue,
151 (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock,
152 (id)kSecUseDataProtectionKeychain: @YES,
153 };
154 status = SecItemAdd((__bridge CFDictionaryRef)add, NULL);
155 if (status != errSecSuccess)
156 fail("add item: %d: %s", (int)status, [[add description] UTF8String]);
157
158 /*
159 * Update access group
160 */
161 NSDictionary *query = @{
162 (id)kSecClass : (id)kSecClassGenericPassword,
163 (id)kSecAttrAccessGroup : @"keychain-test1",
164 (id)kSecAttrAccount : @"item-delete-me",
165 (id)kSecUseDataProtectionKeychain: @YES,
166 };
167 NSDictionary *modified = @{
168 (id)kSecAttrAccessGroup : @"keychain-test2",
169 };
170
171 status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)modified);
172 if (status != errSecSuccess)
173 fail("cleanup2 item: %d", (int)status);
174
175 /*
176 *
177 */
178 NSDictionary *check1 = @{
179 (id)kSecClass : (id)kSecClassGenericPassword,
180 (id)kSecAttrAccessGroup : @"keychain-test1",
181 (id)kSecAttrAccount : @"item-delete-me",
182 (id)kSecUseDataProtectionKeychain: @YES,
183 };
184 status = SecItemCopyMatching((__bridge CFDictionaryRef)check1, NULL);
185 if (status != errSecItemNotFound)
186 fail("check1 item: %d", (int)status);
187
188
189 NSDictionary *check2 = @{
190 (id)kSecClass : (id)kSecClassGenericPassword,
191 (id)kSecAttrAccessGroup : @"keychain-test2",
192 (id)kSecAttrAccount : @"item-delete-me",
193 (id)kSecUseDataProtectionKeychain: @YES,
194 };
195 status = SecItemCopyMatching((__bridge CFDictionaryRef)check2, NULL);
196 if (status != errSecSuccess)
197 fail("check2 item: %d", (int)status);
198
199 /*
200 * Clean
201 */
202 (void)SecItemDelete((__bridge CFDictionaryRef)clean1);
203 (void)SecItemDelete((__bridge CFDictionaryRef)clean2);
204
205 printf("[PASS] %s\n", __FUNCTION__);
206 }
207
208 static NSString *certDataBase64 = @"\
209 MIIEQjCCAyqgAwIBAgIJAJdFadWqNIfiMA0GCSqGSIb3DQEBBQUAMHMxCzAJBgNVBAYTAkNaMQ8wDQYD\
210 VQQHEwZQcmFndWUxFTATBgNVBAoTDENvc21vcywgSW5jLjEXMBUGA1UEAxMOc3VuLmNvc21vcy5nb2Qx\
211 IzAhBgkqhkiG9w0BCQEWFHRoaW5nQHN1bi5jb3Ntb3MuZ29kMB4XDTE2MDIyNjE0NTQ0OVoXDTE4MTEy\
212 MjE0NTQ0OVowczELMAkGA1UEBhMCQ1oxDzANBgNVBAcTBlByYWd1ZTEVMBMGA1UEChMMQ29zbW9zLCBJ\
213 bmMuMRcwFQYDVQQDEw5zdW4uY29zbW9zLmdvZDEjMCEGCSqGSIb3DQEJARYUdGhpbmdAc3VuLmNvc21v\
214 cy5nb2QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5u9gnYEDzQIVu7yC40VcXTZ01D9CJ\
215 oD/mH62tebEHEdfVPLWKeq+uAHnJ6fTIJQvksaISOxwiOosFjtI30mbe6LZ/oK22wYX+OUwKhAYjZQPy\
216 RYfuaJe/52F0zmfUSJ+KTbUZrXbVVFma4xPfpg4bptvtGkFJWnufvEEHimOGmO5O69lXA0Hit1yLU0/A\
217 MQrIMmZT8gb8LMZGPZearT90KhCbTHAxjcBfswZYeL8q3xuEVHXC7EMs6mq8IgZL7mzSBmrCfmBAIO0V\
218 jW2kvmy0NFxkjIeHUShtYb11oYYyfHuz+1vr1y6FIoLmDejKVnwfcuNb545m26o+z/m9Lv9bAgMBAAGj\
219 gdgwgdUwHQYDVR0OBBYEFGDdpPELS92xT+Hkh/7lcc+4G56VMIGlBgNVHSMEgZ0wgZqAFGDdpPELS92x\
220 T+Hkh/7lcc+4G56VoXekdTBzMQswCQYDVQQGEwJDWjEPMA0GA1UEBxMGUHJhZ3VlMRUwEwYDVQQKEwxD\
221 b3Ntb3MsIEluYy4xFzAVBgNVBAMTDnN1bi5jb3Ntb3MuZ29kMSMwIQYJKoZIhvcNAQkBFhR0aGluZ0Bz\
222 dW4uY29zbW9zLmdvZIIJAJdFadWqNIfiMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAFYi\
223 Zu/dfAMOrD51bYxP88Wu6iDGBe9nMG/0lkKgnX5JQKCxfxFMk875rfa+pljdUMOaPxegOXq1DrYmQB9O\
224 /pHI+t7ozuWHRj2zKkVgMWAygNWDPcoqBEus53BdAgA644aPN2JvnE4NEPCllOMKftPoIWbd/5ZjCx3a\
225 bCuxBdXq5YSmiEnOdGfKeXjeeEiIDgARb4tLgH5rkOpB1uH/ZCWn1hkiajBhrGhhPhpA0zbkZg2Ug+8g\
226 XPlx1yQB1VOJkj2Z8dUEXCaRRijInCJ2eU+pgJvwLV7mxmSED7DEJ+b+opxJKYrsdKBU6RmYpPrDa+KC\
227 /Yfu88P9hKKj0LmBiREA\
228 ";
229
230 static NSString *keyDataBase64 = @"\
231 MIIEogIBAAKCAQEAubvYJ2BA80CFbu8guNFXF02dNQ/QiaA/5h+trXmxBxHX1Ty1inqvrgB5yen0yCUL\
232 5LGiEjscIjqLBY7SN9Jm3ui2f6CttsGF/jlMCoQGI2UD8kWH7miXv+dhdM5n1Eifik21Ga121VRZmuMT\
233 36YOG6bb7RpBSVp7n7xBB4pjhpjuTuvZVwNB4rdci1NPwDEKyDJmU/IG/CzGRj2Xmq0/dCoQm0xwMY3A\
234 X7MGWHi/Kt8bhFR1wuxDLOpqvCIGS+5s0gZqwn5gQCDtFY1tpL5stDRcZIyHh1EobWG9daGGMnx7s/tb\
235 69cuhSKC5g3oylZ8H3LjW+eOZtuqPs/5vS7/WwIDAQABAoIBAGcwmQAPdyZus3OVwa1NCUD2KyB+39KG\
236 yNmWwgx+br9Jx4s+RnJghVh8BS4MIKZOBtSRaEUOuCvAMNrupZbD+8leq34vDDRcQpCizr+M6Egj6FRj\
237 Ewl+7Mh+yeN2hbMoghL552MTv9D4Iyxteu4nuPDd/JQ3oQwbDFIL6mlBFtiBDUr9ndemmcJ0WKuzor6a\
238 3rgsygLs8SPyMefwIKjh5rJZls+iv3AyVEoBdCbHBz0HKgLVE9ZNmY/gWqda2dzAcJxxMdafeNVwHovv\
239 BtyyRGnA7Yikx2XT4WLgKfuUsYLnDWs4GdAa738uxPBfiddQNeRjN7jRT1GZIWCk0P29rMECgYEA8jWi\
240 g1Dph+4VlESPOffTEt1aCYQQWtHs13Qex95HrXX/L49fs6cOE7pvBh7nVzaKwBnPRh5+3bCPsPmRVb7h\
241 k/GreOriCjTZtyt2XGp8eIfstfirofB7c1lNBjT61BhgjJ8Moii5c2ksNIOOZnKtD53n47mf7hiarYkw\
242 xFEgU6ECgYEAxE8Js3gIPOBjsSw47XHuvsjP880nZZx/oiQ4IeJb/0rkoDMVJjU69WQu1HTNNAnMg4/u\
243 RXo31h+gDZOlE9t9vSXHdrn3at67KAVmoTbRknGxZ+8tYpRJpPj1hyufynBGcKwevv3eHJHnE5eDqbHx\
244 ynZFkXemzT9aMy3R4CCFMXsCgYAYyZpnG/m6WohE0zthMFaeoJ6dSLGvyboWVqDrzXjCbMf/4wllRlxv\
245 cm34T2NXjpJmlH2c7HQJVg9uiivwfYdyb5If3tHhP4VkdIM5dABnCWoVOWy/NvA7XtE+KF/fItuGqKRP\
246 WCGaiRHoEeqZ23SQm5VmvdF7OXNi/R5LiQ3o4QKBgAGX8qg2TTrRR33ksgGbbyi1UJrWC3/TqWWTjbEY\
247 uU51OS3jvEQ3ImdjjM3EtPW7LqHSxUhjGZjvYMk7bZefrIGgkOHx2IRRkotcn9ynKURbD+mcE249beuc\
248 6cFTJVTrXGcFvqomPWtV895A2JzECQZvt1ja88uuu/i2YoHDQdGJAoGAL2TEgiMXiunb6PzYMMKKa+mx\
249 mFnagF0Ek3UJ9ByXKoLz3HFEl7cADIkqyenXFsAER/ifMyCoZp/PDBd6ZkpqLTdH0jQ2Yo4SllLykoiZ\
250 fBWMfjRu4iw9E0MbPB3blmtzfv53BtWKy0LUOlN4juvpqryA7TgaUlZkfMT+T1TC7xU=\
251 ";
252
253
254 static SecIdentityRef
255 CreateTestIdentity(void)
256 {
257 NSData *certData = [[NSData alloc] initWithBase64EncodedString:certDataBase64 options:0];
258 SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)certData);
259 if (cert == NULL)
260 fail("create certificate from data");
261
262 NSData *keyData = [[NSData alloc] initWithBase64EncodedString:keyDataBase64 options:0];
263 NSDictionary *keyAttrs = @{
264 (id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA,
265 (id)kSecAttrKeySizeInBits: @2048,
266 (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate
267 };
268 SecKeyRef privateKey = SecKeyCreateWithData((CFDataRef)keyData, (CFDictionaryRef)keyAttrs, NULL);
269 if (privateKey == NULL)
270 fail("create private key from data");
271
272 // Create identity from certificate and private key.
273 SecIdentityRef identity = SecIdentityCreate(kCFAllocatorDefault, cert, privateKey);
274 CFRelease(privateKey);
275 CFRelease(cert);
276
277 return identity;
278 }
279
280 static void
281 CheckIdentityItem(NSString *accessGroup, OSStatus expectedStatus)
282 {
283 OSStatus status;
284
285 NSDictionary *check = @{
286 (id)kSecClass : (id)kSecClassIdentity,
287 (id)kSecAttrAccessGroup : accessGroup,
288 (id)kSecAttrLabel : @"item-delete-me",
289 (id)kSecUseDataProtectionKeychain: @YES,
290 };
291 status = SecItemCopyMatching((__bridge CFDictionaryRef)check, NULL);
292 if (status != expectedStatus)
293 fail("check %s for %d item: %d", [accessGroup UTF8String], (int)expectedStatus, (int)status);
294 }
295
296 static void
297 CheckItemUpdateAccessGroupIdentity(void)
298 {
299 OSStatus status;
300 CFTypeRef ref = NULL;
301
302 printf("[BEGIN] %s\n", __FUNCTION__);
303
304 NSDictionary *clean1 = @{
305 (id)kSecClass : (id)kSecClassIdentity,
306 (id)kSecAttrAccessGroup : @"keychain-test1",
307 };
308 NSDictionary *clean2 = @{
309 (id)kSecClass : (id)kSecClassIdentity,
310 (id)kSecAttrAccessGroup : @"keychain-test2",
311 };
312
313 (void)SecItemDelete((__bridge CFDictionaryRef)clean1);
314 (void)SecItemDelete((__bridge CFDictionaryRef)clean2);
315
316 CheckIdentityItem(@"keychain-test1", errSecItemNotFound);
317 CheckIdentityItem(@"keychain-test2", errSecItemNotFound);
318
319 SecIdentityRef identity = CreateTestIdentity();
320 if (identity == NULL)
321 fail("create private key from data");
322
323
324 /*
325 * Add item
326 */
327
328 NSDictionary *add = @{
329 (id)kSecValueRef : (__bridge id)identity,
330 (id)kSecAttrAccessGroup : @"keychain-test1",
331 (id)kSecAttrLabel : @"item-delete-me",
332 (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock,
333 (id)kSecUseDataProtectionKeychain: @YES,
334 (id)kSecReturnPersistentRef: (id)kCFBooleanTrue,
335 };
336 status = SecItemAdd((__bridge CFDictionaryRef)add, &ref);
337 if (status != errSecSuccess)
338 fail("add item: %d: %s", (int)status, [[add description] UTF8String]);
339
340 /*
341 *
342 */
343 CheckIdentityItem(@"keychain-test1", errSecSuccess);
344 CheckIdentityItem(@"keychain-test2", errSecItemNotFound);
345
346
347 /*
348 * Update access group
349 */
350 NSDictionary *query = @{
351 (id)kSecClass : (id)kSecClassIdentity,
352 (id)kSecAttrAccessGroup : @"keychain-test1",
353 (id)kSecAttrLabel : @"item-delete-me",
354 (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue,
355 };
356 NSDictionary *modified = @{
357 (id)kSecAttrAccessGroup : @"keychain-test2",
358 };
359
360 status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)modified);
361 if (status != errSecSuccess)
362 fail("cleanup2 item: %d", (int)status);
363
364 /*
365 *
366 */
367
368 CheckIdentityItem(@"keychain-test1", errSecItemNotFound);
369 CheckIdentityItem(@"keychain-test2", errSecSuccess);
370
371 /*
372 * Check pref
373 */
374 CFDataRef data = NULL;
375
376 NSDictionary *prefQuery = @{
377 (id)kSecClass : (id)kSecClassIdentity,
378 (id)kSecAttrAccessGroup : @"keychain-test2",
379 (id)kSecAttrLabel : @"item-delete-me",
380 (id)kSecUseDataProtectionKeychain: @YES,
381 (id)kSecReturnPersistentRef : (id)kCFBooleanTrue,
382 };
383 status = SecItemCopyMatching((__bridge CFDictionaryRef)prefQuery, (CFTypeRef *)&data);
384 if (status != errSecSuccess)
385 fail("prefQuery item: %d", (int)status);
386
387 /*
388 * Update access group for identity
389 */
390 NSDictionary *query2 = @{
391 (id)kSecValuePersistentRef : (__bridge id)data,
392 (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue,
393 };
394 NSDictionary *modified2 = @{
395 (id)kSecAttrAccessGroup : @"keychain-test1",
396 };
397
398 status = SecItemUpdate((__bridge CFDictionaryRef)query2, (__bridge CFDictionaryRef)modified2);
399 if (status != errSecInternal)
400 fail("update identity with pref fails differntly: %d", (int)status);
401
402 /*
403 CheckIdentityItem(@"keychain-test1", errSecSuccess);
404 CheckIdentityItem(@"keychain-test2", errSecItemNotFound);
405 */
406
407
408 /*
409 * Clean
410 */
411 (void)SecItemDelete((__bridge CFDictionaryRef)clean1);
412 (void)SecItemDelete((__bridge CFDictionaryRef)clean2);
413
414 CFRelease(identity);
415
416 CheckIdentityItem(@"keychain-test1", errSecItemNotFound);
417 CheckIdentityItem(@"keychain-test2", errSecItemNotFound);
418
419
420 printf("[PASS] %s\n", __FUNCTION__);
421 }
422
423 static void
424 CheckFindIdentityByReference(void)
425 {
426 OSStatus status;
427 CFDataRef pref = NULL, pref2 = NULL;
428
429 printf("[BEGIN] %s\n", __FUNCTION__);
430
431 /*
432 * Clean identities
433 */
434 NSDictionary *clean1 = @{
435 (id)kSecClass : (id)kSecClassIdentity,
436 (id)kSecAttrAccessGroup : @"keychain-test1",
437 };
438 (void)SecItemDelete((__bridge CFDictionaryRef)clean1);
439
440 /*
441 * Add
442 */
443 SecIdentityRef identity = CreateTestIdentity();
444 if (identity == NULL)
445 fail("create private key from data");
446
447
448 NSDictionary *add = @{
449 (id)kSecValueRef : (__bridge id)identity,
450 (id)kSecAttrAccessGroup : @"keychain-test1",
451 (id)kSecAttrLabel : @"CheckItemReference",
452 (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock,
453 (id)kSecUseDataProtectionKeychain: @YES,
454 (id)kSecReturnPersistentRef: (id)kCFBooleanTrue,
455 };
456 status = SecItemAdd((__bridge CFDictionaryRef)add, (CFTypeRef *)&pref);
457 if (status != errSecSuccess)
458 fail("add item: %d: %s", (int)status, [[add description] UTF8String]);
459
460 if (pref == NULL || CFGetTypeID(pref) != CFDataGetTypeID())
461 fail("no pref returned");
462
463 /*
464 * Find by identity
465 */
466
467 NSDictionary *query = @{
468 (id)kSecValueRef : (__bridge id)identity,
469 (id)kSecReturnPersistentRef: (id)kCFBooleanTrue,
470 };
471 status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&pref2);
472 if (status)
473 fail("SecItemCopyMatching: %d", (int)status);
474
475 if (pref2 == NULL || CFGetTypeID(pref2) != CFDataGetTypeID())
476 fail("no pref2 returned");
477
478
479 if (!CFEqual(pref, pref2))
480 fail("prefs not same");
481
482 CFRelease(pref2);
483
484 /*
485 * Find by label
486 */
487
488 NSDictionary *query2 = @{
489 (id)kSecClass : (id)kSecClassIdentity,
490 (id)kSecAttrAccessGroup : @"keychain-test1",
491 (id)kSecAttrLabel : @"CheckItemReference",
492 (id)kSecUseDataProtectionKeychain: @YES,
493 (id)kSecReturnPersistentRef: (id)kCFBooleanTrue,
494 };
495 status = SecItemCopyMatching((CFDictionaryRef)query2, (CFTypeRef *)&pref2);
496 if (status)
497 fail("SecItemCopyMatching: %d", (int)status);
498
499 if (pref2 == NULL || CFGetTypeID(pref2) != CFDataGetTypeID())
500 fail("no pref2 returned");
501
502
503 if (!CFEqual(pref, pref2))
504 fail("prefs not same");
505
506 CFRelease(pref2);
507
508 /*
509 * Find by label + reference
510 */
511
512 NSDictionary *query3 = @{
513 (id)kSecAttrAccessGroup : @"keychain-test1",
514 (id)kSecAttrLabel : @"CheckItemReference",
515 (id)kSecValueRef : (__bridge id)identity,
516 (id)kSecUseDataProtectionKeychain: @YES,
517 (id)kSecReturnPersistentRef: (id)kCFBooleanTrue,
518 };
519 status = SecItemCopyMatching((CFDictionaryRef)query3, (CFTypeRef *)&pref2);
520 if (status)
521 fail("SecItemCopyMatching: %d", (int)status);
522
523 if (pref2 == NULL || CFGetTypeID(pref2) != CFDataGetTypeID())
524 fail("no pref2 returned");
525
526
527 if (!CFEqual(pref, pref2))
528 fail("prefs not same");
529
530 CFRelease(pref2);
531
532 /*
533 * Free stuff
534 */
535
536 CFRelease(pref);
537 if(identity) {
538 CFRelease(identity);
539 identity = NULL;
540 }
541
542 printf("[PASS] %s\n", __FUNCTION__);
543 }
544
545 static uint64_t
546 timeDiff(uint64_t start, uint64_t stop)
547 {
548 static uint64_t time_overhead_measured = 0;
549 static double timebase_factor = 0;
550
551 if (time_overhead_measured == 0) {
552 uint64_t t0 = mach_absolute_time();
553 time_overhead_measured = mach_absolute_time() - t0;
554
555 struct mach_timebase_info timebase_info = {};
556 mach_timebase_info(&timebase_info);
557 timebase_factor = ((double)timebase_info.numer)/((double)timebase_info.denom);
558 }
559
560 return ((stop - start - time_overhead_measured) * timebase_factor) / NSEC_PER_USEC;
561 }
562
563 static void
564 RunCopyPerfTest(NSString *name, NSDictionary *query)
565 {
566 uint64_t start = mach_absolute_time();
567 OSStatus status;
568 CFTypeRef result = NULL;
569
570 status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
571 uint64_t stop = mach_absolute_time();
572
573 if (status != 0) {
574 printf("SecItemCopyMatching failed with: %d\n", (int)status);
575 fflush(stdout);
576 abort();
577 }
578
579 if (result)
580 CFRelease(result);
581
582 uint64_t us = timeDiff(start, stop);
583
584 puts([[NSString stringWithFormat:@"[RESULT_KEY] SecItemCopyMatching-%@\n[RESULT_VALUE] %lu\n",
585 name, (unsigned long)us] UTF8String]);
586 }
587
588 static void
589 RunDigestPerfTest(NSString *name, NSString *itemClass, NSString *accessGroup, NSUInteger expectedCount)
590 {
591 uint64_t start = mach_absolute_time();
592 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
593 __block uint64_t stop;
594
595 _SecItemFetchDigests(itemClass, accessGroup, ^(NSArray *items, NSError *error) {
596 stop = mach_absolute_time();
597 if (error) {
598 printf("%s: _SecItemFetchDigests failed with: %ld\n", [name UTF8String], (long)error.code);
599 fflush(stdout);
600 abort();
601 }
602 dispatch_semaphore_signal(sema);
603
604 if (expectedCount != [items count]) {
605 printf("%s: _SecItemFetchDigests didn't return expected items: %ld\n", [name UTF8String], (long)[items count]);
606 fflush(stdout);
607 abort();
608 }
609 });
610 dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
611
612
613 uint64_t us = timeDiff(start, stop);
614
615 puts([[NSString stringWithFormat:@"[RESULT_KEY] SecItemCopyDigest-%@\n[RESULT_VALUE] %lu\n",
616 name, (unsigned long)us] UTF8String]);
617 }
618
619
620 static void
621 CheckItemPerformance(void)
622 {
623 unsigned n;
624
625 printf("[BEGIN] %s\n", __FUNCTION__);
626
627 /*
628 * Clean identities
629 */
630 NSDictionary *clean1 = @{
631 (id)kSecClass : (id)kSecClassGenericPassword,
632 (id)kSecAttrService : @"service",
633 (id)kSecAttrAccessGroup : @"keychain-test1",
634 (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue,
635 };
636 (void)SecItemDelete((__bridge CFDictionaryRef)clean1);
637
638 NSData *data = [NSData dataWithBytes:"password" length:8];
639
640 for (n = 0; n < 1000; n++) {
641 NSDictionary *item = @{
642 (id)kSecClass : (id)kSecClassGenericPassword,
643 (id)kSecAttrAccount : [NSString stringWithFormat:@"account-%d", n],
644 (id)kSecAttrService : @"service",
645 (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue,
646 (id)kSecAttrAccessGroup : @"keychain-test1",
647 (id)kSecUseDataProtectionKeychain: @YES,
648 (id)kSecValueData : data,
649 };
650 SecItemAdd((__bridge CFDictionaryRef)item, NULL);
651 }
652
653
654 RunCopyPerfTest(@"FindOneItemLimit", @{
655 (id)kSecClass : (id)kSecClassGenericPassword,
656 (id)kSecAttrService : @"service",
657 (id)kSecMatchLimit : (id)kSecMatchLimitOne,
658 (id)kSecUseDataProtectionKeychain: @YES,
659 });
660 RunCopyPerfTest(@"FindOneItemUnique", @{
661 (id)kSecClass : (id)kSecClassGenericPassword,
662 (id)kSecAttrAccount : @"account-0",
663 (id)kSecAttrService : @"service",
664 (id)kSecMatchLimit : (id)kSecMatchLimitAll,
665 (id)kSecUseDataProtectionKeychain: @YES,
666 });
667 RunCopyPerfTest(@"Find1000Items", @{
668 (id)kSecClass : (id)kSecClassGenericPassword,
669 (id)kSecAttrService : @"service",
670 (id)kSecMatchLimit : (id)kSecMatchLimitAll,
671 (id)kSecUseDataProtectionKeychain: @YES,
672 });
673 RunDigestPerfTest(@"Digest1000Items", (id)kSecClassGenericPassword, @"keychain-test1", 1000);
674 RunCopyPerfTest(@"GetAttrOneItemUnique", @{
675 (id)kSecClass : (id)kSecClassGenericPassword,
676 (id)kSecAttrAccount : @"account-0",
677 (id)kSecAttrService : @"service",
678 (id)kSecReturnAttributes : (id)kCFBooleanTrue,
679 (id)kSecMatchLimit : (id)kSecMatchLimitAll,
680 (id)kSecUseDataProtectionKeychain: @YES,
681 });
682 RunCopyPerfTest(@"GetData1000Items", @{
683 (id)kSecClass : (id)kSecClassGenericPassword,
684 (id)kSecAttrService : @"service",
685 (id)kSecReturnData : (id)kCFBooleanTrue,
686 (id)kSecMatchLimit : (id)kSecMatchLimitAll,
687 (id)kSecUseDataProtectionKeychain: @YES,
688 });
689 RunCopyPerfTest(@"GetDataOneItemUnique", @{
690 (id)kSecClass : (id)kSecClassGenericPassword,
691 (id)kSecAttrAccount : @"account-0",
692 (id)kSecAttrService : @"service",
693 (id)kSecReturnData : (id)kCFBooleanTrue,
694 (id)kSecMatchLimit : (id)kSecMatchLimitAll,
695 (id)kSecUseDataProtectionKeychain: @YES,
696 });
697 RunCopyPerfTest(@"GetDataAttrOneItemUnique", @{
698 (id)kSecClass : (id)kSecClassGenericPassword,
699 (id)kSecAttrAccount : @"account-0",
700 (id)kSecAttrService : @"service",
701 (id)kSecReturnData : (id)kCFBooleanTrue,
702 (id)kSecReturnAttributes : (id)kCFBooleanTrue,
703 (id)kSecMatchLimit : (id)kSecMatchLimitAll,
704 (id)kSecUseDataProtectionKeychain: @YES,
705 });
706 #if TARGET_OS_IPHONE /* macOS doesn't support fetching data for more then one item */
707 RunCopyPerfTest(@"GetData1000Items", @{
708 (id)kSecClass : (id)kSecClassGenericPassword,
709 (id)kSecAttrService : @"service",
710 (id)kSecReturnData : (id)kCFBooleanTrue,
711 (id)kSecMatchLimit : (id)kSecMatchLimitAll,
712 (id)kSecUseDataProtectionKeychain: @YES,
713 });
714 RunCopyPerfTest(@"GetDataAttr1000Items", @{
715 (id)kSecClass : (id)kSecClassGenericPassword,
716 (id)kSecAttrService : @"service",
717 (id)kSecReturnData : (id)kCFBooleanTrue,
718 (id)kSecReturnAttributes : (id)kCFBooleanTrue,
719 (id)kSecMatchLimit : (id)kSecMatchLimitAll,
720 (id)kSecUseDataProtectionKeychain: @YES,
721 });
722 #endif
723
724 (void)SecItemDelete((__bridge CFDictionaryRef)clean1);
725
726
727 printf("[PASS] %s\n", __FUNCTION__);
728 }
729
730 int
731 main(int argc, const char ** argv)
732 {
733 printf("[TEST] secitemfunctionality\n");
734
735 CheckItemPerformance();
736
737 CheckFindIdentityByReference();
738
739 //CheckItemAddDeleteMaybeLegacyKeychainNoData();
740 CheckItemAddDeleteNoData();
741 CheckItemUpdateAccessGroupGENP();
742 CheckItemUpdateAccessGroupIdentity();
743
744 printf("[SUMMARY]\n");
745 printf("test completed\n");
746
747 return 0;
748 }