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