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