]> git.saurik.com Git - apple/security.git/blob - tests/secdmockaks/mockaksKeychain.m
Security-59306.41.2.tar.gz
[apple/security.git] / tests / secdmockaks / mockaksKeychain.m
1 /*
2 * Copyright (c) 2018 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #import "SecKeybagSupport.h"
25 #import "SecDbKeychainItem.h"
26 #import "SecdTestKeychainUtilities.h"
27 #import "CKKS.h"
28 #import "SecItemPriv.h"
29 #import "SecItemServer.h"
30 #import "SecItemSchema.h"
31 #include "OSX/sec/Security/SecItemShim.h"
32 #import "spi.h"
33 #import <utilities/SecCFWrappers.h>
34 #import <utilities/SecFileLocations.h>
35 #import <SecurityFoundation/SFEncryptionOperation.h>
36 #import <XCTest/XCTest.h>
37 #import <OCMock/OCMock.h>
38 #if USE_KEYSTORE
39 #if __has_include(<libaks.h>)
40 #import <libaks.h>
41 #endif // aks.h
42 #endif
43 #import <sqlite3.h>
44 #import "mockaks.h"
45
46 #import "secdmock_db_version_10_5.h"
47 #import "secdmock_db_version_11_1.h"
48
49 #import "mockaksxcbase.h"
50
51 @interface secdmockaks : mockaksxcbase
52 @end
53
54 @implementation secdmockaks
55
56
57 - (void)testAddDeleteItem
58 {
59 NSDictionary* item = @{ (id)kSecClass : (id)kSecClassGenericPassword,
60 (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
61 (id)kSecAttrAccount : @"TestAccount",
62 (id)kSecAttrService : @"TestService",
63 (id)kSecUseDataProtectionKeychain : @(YES) };
64
65 OSStatus result = SecItemAdd((__bridge CFDictionaryRef)item, NULL);
66 XCTAssertEqual(result, 0, @"failed to add test item to keychain");
67
68 NSMutableDictionary* dataQuery = item.mutableCopy;
69 [dataQuery removeObjectForKey:(id)kSecValueData];
70 dataQuery[(id)kSecReturnData] = @(YES);
71 CFTypeRef foundItem = NULL;
72 result = SecItemCopyMatching((__bridge CFDictionaryRef)dataQuery, &foundItem);
73 XCTAssertEqual(result, 0, @"failed to find the data for the item we just added in the keychain");
74
75 result = SecItemDelete((__bridge CFDictionaryRef)dataQuery);
76 XCTAssertEqual(result, 0, @"failed to delete item");
77 }
78
79
80 - (void)createManyItems
81 {
82 unsigned n;
83 for (n = 0; n < 50; n++) {
84 NSDictionary* item = @{
85 (id)kSecClass : (id)kSecClassGenericPassword,
86 (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
87 (id)kSecAttrAccount : [NSString stringWithFormat:@"TestAccount-%u", n],
88 (id)kSecAttrService : @"TestService",
89 (id)kSecUseDataProtectionKeychain : @(YES)
90 };
91 OSStatus result = SecItemAdd((__bridge CFDictionaryRef)item, NULL);
92 XCTAssertEqual(result, errSecSuccess, @"failed to add test item to keychain: %u", n);
93 }
94 }
95
96 - (void)findManyItems:(unsigned)searchLimit
97 {
98 unsigned n;
99 for (n = 0; n < searchLimit; n++) {
100 NSDictionary* item = @{
101 (id)kSecClass : (id)kSecClassGenericPassword,
102 (id)kSecAttrAccount : [NSString stringWithFormat:@"TestAccount-%u", n],
103 (id)kSecAttrService : @"TestService",
104 (id)kSecUseDataProtectionKeychain : @(YES)
105 };
106 OSStatus result = SecItemCopyMatching((__bridge CFDictionaryRef)item, NULL);
107 XCTAssertEqual(result, errSecSuccess, @"failed to find test item to keychain: %u", n);
108 }
109 }
110
111 - (void)findNoItems:(unsigned)searchLimit
112 {
113 unsigned n;
114 for (n = 0; n < searchLimit; n++) {
115 NSDictionary* item = @{
116 (id)kSecClass : (id)kSecClassGenericPassword,
117 (id)kSecAttrAccount : [NSString stringWithFormat:@"TestAccount-%u", n],
118 (id)kSecAttrService : @"TestService",
119 (id)kSecUseDataProtectionKeychain : @(YES)
120 };
121 OSStatus result = SecItemCopyMatching((__bridge CFDictionaryRef)item, NULL);
122 XCTAssertEqual(result, errSecItemNotFound, @"not expecting to find an item (%d): %u", (int)result, n);
123 }
124 }
125
126 - (void)deleteAllItems
127 {
128 NSDictionary* item = @{
129 (id)kSecClass : (id)kSecClassGenericPassword,
130 (id)kSecAttrService : @"TestService",
131 (id)kSecUseDataProtectionKeychain : @(YES)
132 };
133 OSStatus result = SecItemDelete((__bridge CFDictionaryRef)item);
134 XCTAssertEqual(result, 0, @"failed to delete all test items");
135 }
136
137 - (void)testSecItemServerDeleteAll
138 {
139 [self addAccessGroup:@"com.apple.bluetooth"];
140 [self addAccessGroup:@"lockdown-identities"];
141
142 // BT root key, should not be deleted
143 NSMutableDictionary* bt = [@{
144 (id)kSecClass : (id)kSecClassGenericPassword,
145 (id)kSecAttrAccessGroup : @"com.apple.bluetooth",
146 (id)kSecAttrService : @"BluetoothGlobal",
147 (id)kSecAttrAccessible : (id)kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate,
148 (id)kSecAttrSynchronizable : @(NO),
149 (id)kSecValueData : [@"btkey" dataUsingEncoding:NSUTF8StringEncoding],
150 } mutableCopy];
151
152 // lockdown-identities, should not be deleted
153 NSMutableDictionary* ld = [@{
154 (id)kSecClass : (id)kSecClassKey,
155 (id)kSecAttrAccessGroup : @"lockdown-identities",
156 (id)kSecAttrLabel : @"com.apple.lockdown.identity.activation",
157 (id)kSecAttrAccessible : (id)kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate,
158 (id)kSecAttrSynchronizable : @(NO),
159 (id)kSecValueData : [@"ldkey" dataUsingEncoding:NSUTF8StringEncoding],
160 } mutableCopy];
161
162 // general nonsyncable item, should be deleted
163 NSMutableDictionary* s0 = [@{
164 (id)kSecClass : (id)kSecClassGenericPassword,
165 (id)kSecAttrService : @"NonsyncableService",
166 (id)kSecAttrSynchronizable : @(NO),
167 (id)kSecValueData : [@"s0pwd" dataUsingEncoding:NSUTF8StringEncoding],
168 } mutableCopy];
169
170 // general syncable item, should be deleted
171 NSMutableDictionary* s1 = [@{
172 (id)kSecClass : (id)kSecClassGenericPassword,
173 (id)kSecAttrService : @"SyncableService",
174 (id)kSecAttrSynchronizable : @(YES),
175 (id)kSecValueData : [@"s0pwd" dataUsingEncoding:NSUTF8StringEncoding],
176 } mutableCopy];
177
178 // Insert all items
179 OSStatus status;
180 status = SecItemAdd((__bridge CFDictionaryRef)bt, NULL);
181 XCTAssertEqual(status, errSecSuccess, "failed to add bt item to keychain");
182 status = SecItemAdd((__bridge CFDictionaryRef)ld, NULL);
183 XCTAssertEqual(status, errSecSuccess, "failed to add ld item to keychain");
184 status = SecItemAdd((__bridge CFDictionaryRef)s0, NULL);
185 XCTAssertEqual(status, errSecSuccess, "failed to add s0 item to keychain");
186 status = SecItemAdd((__bridge CFDictionaryRef)s1, NULL);
187 XCTAssertEqual(status, errSecSuccess, "failed to add s1 item to keychain");
188
189 // Make sure they exist now
190 bt[(id)kSecValueData] = nil;
191 ld[(id)kSecValueData] = nil;
192 s0[(id)kSecValueData] = nil;
193 s1[(id)kSecValueData] = nil;
194 status = SecItemCopyMatching((__bridge CFDictionaryRef)bt, NULL);
195 XCTAssertEqual(status, errSecSuccess, "failed to find bt item in keychain");
196 status = SecItemCopyMatching((__bridge CFDictionaryRef)ld, NULL);
197 XCTAssertEqual(status, errSecSuccess, "failed to find ld item in keychain");
198 status = SecItemCopyMatching((__bridge CFDictionaryRef)s0, NULL);
199 XCTAssertEqual(status, errSecSuccess, "failed to find s0 item in keychain");
200 status = SecItemCopyMatching((__bridge CFDictionaryRef)s1, NULL);
201 XCTAssertEqual(status, errSecSuccess, "failed to find s1 item in keychain");
202
203 // Nuke the keychain
204 CFErrorRef error = NULL;
205 _SecItemDeleteAll(&error);
206 XCTAssertEqual(error, NULL, "_SecItemDeleteAll returned an error: %@", error);
207 CFReleaseNull(error);
208
209 // Does the function work properly with an error pre-set?
210 error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, errSecItemNotFound, NULL);
211 _SecItemDeleteAll(&error);
212 XCTAssertEqual(CFErrorGetDomain(error), kCFErrorDomainOSStatus);
213 XCTAssertEqual(CFErrorGetCode(error), errSecItemNotFound);
214 CFReleaseNull(error);
215
216 // Check the relevant items are missing
217 status = SecItemCopyMatching((__bridge CFDictionaryRef)bt, NULL);
218 XCTAssertEqual(status, errSecSuccess, "failed to find bt item in keychain");
219 status = SecItemCopyMatching((__bridge CFDictionaryRef)ld, NULL);
220 XCTAssertEqual(status, errSecSuccess, "failed to find ld item in keychain");
221 status = SecItemCopyMatching((__bridge CFDictionaryRef)s0, NULL);
222 XCTAssertEqual(status, errSecItemNotFound, "unexpectedly found s0 item in keychain");
223 status = SecItemCopyMatching((__bridge CFDictionaryRef)s1, NULL);
224 XCTAssertEqual(status, errSecItemNotFound, "unexpectedly found s1 item in keychain");
225 }
226
227 - (void)createManyKeys
228 {
229 unsigned n;
230 for (n = 0; n < 50; n++) {
231 NSDictionary* keyParams = @{
232 (id)kSecAttrKeyType : (id)kSecAttrKeyTypeRSA,
233 (id)kSecAttrKeySizeInBits : @(1024)
234 };
235 SecKeyRef key = SecKeyCreateRandomKey((__bridge CFDictionaryRef)keyParams, NULL);
236 NSDictionary* item = @{ (id)kSecClass : (id)kSecClassKey,
237 (id)kSecValueRef : (__bridge id)key,
238 (id)kSecAttrLabel : [NSString stringWithFormat:@"TestLabel-%u", n],
239 (id)kSecUseDataProtectionKeychain : @(YES) };
240
241 OSStatus result = SecItemAdd((__bridge CFDictionaryRef)item, NULL);
242 XCTAssertEqual(result, 0, @"failed to add test key to keychain: %u", n);
243 }
244 }
245
246
247 - (void)testBackupRestoreItem
248 {
249 [self createManyItems];
250 [self createManyKeys];
251
252
253 NSDictionary* item = @{ (id)kSecClass : (id)kSecClassGenericPassword,
254 (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
255 (id)kSecAttrAccount : @"TestAccount",
256 (id)kSecAttrService : @"TestService",
257 (id)kSecUseDataProtectionKeychain : @(YES) };
258
259 OSStatus result = SecItemAdd((__bridge CFDictionaryRef)item, NULL);
260 XCTAssertEqual(result, 0, @"failed to add test item to keychain");
261
262 NSMutableDictionary* dataQuery = item.mutableCopy;
263 [dataQuery removeObjectForKey:(id)kSecValueData];
264 dataQuery[(id)kSecReturnData] = @(YES);
265 CFTypeRef foundItem = NULL;
266
267 /*
268 * Create backup
269 */
270
271 CFDataRef keybag = CFDataCreate(kCFAllocatorDefault, NULL, 0);
272 CFDataRef password = CFDataCreate(kCFAllocatorDefault, NULL, 0);
273
274 CFDataRef backup = _SecKeychainCopyBackup(keybag, password);
275 XCTAssert(backup, "expected to have a backup");
276
277 result = SecItemDelete((__bridge CFDictionaryRef)dataQuery);
278 XCTAssertEqual(result, 0, @"failed to delete item");
279
280 result = SecItemCopyMatching((__bridge CFDictionaryRef)dataQuery, &foundItem);
281 XCTAssertEqual(result, errSecItemNotFound,
282 @"failed to find the data for the item we just added in the keychain");
283 CFReleaseNull(foundItem);
284
285 /*
286 * Restore backup and see that item is resurected
287 */
288
289 XCTAssertEqual(0, _SecKeychainRestoreBackup(backup, keybag, password));
290
291 CFReleaseNull(backup);
292 CFReleaseNull(password);
293 CFReleaseNull(keybag);
294
295 result = SecItemCopyMatching((__bridge CFDictionaryRef)dataQuery, &foundItem);
296 XCTAssertEqual(result, 0, @"failed to find the data for the item we just added in the keychain");
297 CFReleaseNull(foundItem);
298
299 result = SecItemDelete((__bridge CFDictionaryRef)dataQuery);
300 XCTAssertEqual(result, 0, @"failed to delete item");
301 }
302
303 - (void)testCreateSampleDatabase
304 {
305 #if USE_KEYSTORE
306 id mock = OCMClassMock([SecMockAKS class]);
307 OCMStub([mock useGenerationCount]).andReturn(true);
308 #endif
309
310 [self createManyItems];
311 [self createManyKeys];
312
313 /*
314 sleep(600);
315 lsof -p $(pgrep xctest)
316 sqlite3 database
317 .output mydatabase.h
318 .dump
319
320 add header and footer
321 */
322
323 [self findManyItems:50];
324 }
325
326 - (void)testTestAKSGenerationCount
327 {
328 #if USE_KEYSTORE
329 id mock = OCMClassMock([SecMockAKS class]);
330 OCMStub([mock useGenerationCount]).andReturn(true);
331
332 [self createManyItems];
333 [self findManyItems:50];
334 #endif
335 }
336
337
338 - (void)loadDatabase:(const char **)dumpstring
339 {
340 const char *s;
341 unsigned n = 0;
342
343 // We need a fresh directory to plop down our SQLite data
344 SetCustomHomeURLString((__bridge CFStringRef)[self createKeychainDirectoryWithSubPath:@"loadManualDB"]);
345 NSString* path = CFBridgingRelease(__SecKeychainCopyPath());
346 // On macOS the full path gets created, on iOS not (yet?)
347 [self createKeychainDirectoryWithSubPath:@"loadManualDB/Library/Keychains"];
348
349 sqlite3 *handle = NULL;
350
351 XCTAssertEqual(SQLITE_OK, sqlite3_open([path UTF8String], &handle), "create keychain");
352
353 while ((s = dumpstring[n++]) != NULL) {
354 char * errmsg = NULL;
355 XCTAssertEqual(SQLITE_OK, sqlite3_exec(handle, s, NULL, NULL, &errmsg),
356 "exec: %s: %s", s, errmsg);
357 if (errmsg) {
358 sqlite3_free(errmsg);
359 }
360 }
361 XCTAssertEqual(SQLITE_OK, sqlite3_close(handle), "close sqlite");
362 }
363
364 - (void)checkIncremental
365 {
366 /*
367 * check that we made incremental vacuum mode
368 */
369
370 __block CFErrorRef localError = NULL;
371 __block bool ok = true;
372 __block int vacuumMode = -1;
373
374 kc_with_dbt(true, NULL, ^bool (SecDbConnectionRef dbt) {
375 ok &= SecDbPrepare(dbt, CFSTR("PRAGMA auto_vacuum"), &localError, ^(sqlite3_stmt *stmt) {
376 ok = SecDbStep(dbt, stmt, NULL, ^(bool *stop) {
377 vacuumMode = sqlite3_column_int(stmt, 0);
378 });
379 });
380 return ok;
381 });
382 XCTAssertEqual(ok, true, "should work to fetch auto_vacuum value: %@", localError);
383 XCTAssertEqual(vacuumMode, 2, "vacuum mode should be incremental (2)");
384
385 CFReleaseNull(localError);
386
387 }
388
389 - (void)testUpgradeFromVersion10_5
390 {
391 SecKeychainDbReset(^{
392 NSLog(@"resetting database");
393 [self loadDatabase:secdmock_db_version10_5];
394 });
395
396 NSLog(@"find items from old database");
397 [self findManyItems:50];
398
399 [self checkIncremental];
400 }
401
402 - (void)testUpgradeFromVersion11_1
403 {
404 SecKeychainDbReset(^{
405 NSLog(@"resetting database");
406 [self loadDatabase:secdmock_db_version11_1];
407 });
408
409 NSLog(@"find items from old database");
410 [self findManyItems:50];
411
412 [self checkIncremental];
413 }
414
415 #if TARGET_OS_IOS
416
417 - (void)testPersonaBasic
418 {
419 SecSecuritySetPersonaMusr(NULL);
420
421 [self createManyItems];
422 [self findManyItems:10];
423
424 SecSecuritySetPersonaMusr(CFSTR("99C5D3CC-2C2D-47C4-9A1C-976EC047BF3C"));
425
426 [self findNoItems:10];
427 [self createManyItems];
428 [self findManyItems:10];
429
430 [self deleteAllItems];
431 [self findNoItems:10];
432
433 SecSecuritySetPersonaMusr(NULL);
434
435 [self findManyItems:10];
436 [self deleteAllItems];
437 [self findNoItems:10];
438
439 SecSecuritySetPersonaMusr(CFSTR("8E90C6BE-0AF6-40D6-8A4B-D46E4CF6A622"));
440
441 [self createManyItems];
442
443 SecSecuritySetPersonaMusr(CFSTR("38B615CA-02C2-4733-A71C-1ABA46D27B13"));
444
445 [self findNoItems:10];
446 [self createManyItems];
447
448 SecSecuritySetPersonaMusr(NULL);
449
450 XCTestExpectation *expection = [self expectationWithDescription:@"wait for deletion"];
451
452 _SecKeychainDeleteMultiUser(@"8E90C6BE-0AF6-40D6-8A4B-D46E4CF6A622", ^(bool status, NSError *error) {
453 [expection fulfill];
454 });
455
456 [self waitForExpectations:@[expection] timeout:10.0];
457
458 /* check that delete worked ... */
459 SecSecuritySetPersonaMusr(CFSTR("8E90C6BE-0AF6-40D6-8A4B-D46E4CF6A622"));
460 [self findNoItems:10];
461
462 /* ... but didn't delete another account */
463 SecSecuritySetPersonaMusr(CFSTR("38B615CA-02C2-4733-A71C-1ABA46D27B13"));
464 [self findManyItems:10];
465
466 SecSecuritySetPersonaMusr(NULL);
467
468
469 [self findNoItems:10];
470 }
471
472 #endif /* TARGET_OS_IOS */
473
474 #if USE_KEYSTORE
475
476 - (void)testAddKeyByReference
477 {
478 NSDictionary* keyParams = @{ (id)kSecAttrKeyType : (id)kSecAttrKeyTypeRSA, (id)kSecAttrKeySizeInBits : @(1024) };
479 SecKeyRef key = SecKeyCreateRandomKey((__bridge CFDictionaryRef)keyParams, NULL);
480 NSDictionary* item = @{ (id)kSecClass : (id)kSecClassKey,
481 (id)kSecValueRef : (__bridge id)key,
482 (id)kSecAttrLabel : @"TestLabel",
483 (id)kSecUseDataProtectionKeychain : @(YES) };
484
485 OSStatus result = SecItemAdd((__bridge CFDictionaryRef)item, NULL);
486 XCTAssertEqual(result, 0, @"failed to add test item to keychain");
487
488 NSMutableDictionary* refQuery = item.mutableCopy;
489 [refQuery removeObjectForKey:(id)kSecValueData];
490 refQuery[(id)kSecReturnRef] = @(YES);
491 CFTypeRef foundItem = NULL;
492 result = SecItemCopyMatching((__bridge CFDictionaryRef)refQuery, &foundItem);
493 XCTAssertEqual(result, 0, @"failed to find the reference for the item we just added in the keychain");
494
495 NSData* originalKeyData = (__bridge_transfer NSData*)SecKeyCopyExternalRepresentation(key, NULL);
496 NSData* foundKeyData = (__bridge_transfer NSData*)SecKeyCopyExternalRepresentation((SecKeyRef)foundItem, NULL);
497 XCTAssertEqualObjects(originalKeyData, foundKeyData, @"found key does not match the key we put in the keychain");
498
499 result = SecItemDelete((__bridge CFDictionaryRef)refQuery);
500 XCTAssertEqual(result, 0, @"failed to delete key");
501 }
502
503 - (bool)isLockedSoon:(keyclass_t)key_class
504 {
505 if (key_class == key_class_d || key_class == key_class_dku)
506 return false;
507 if (self.lockCounter <= 0)
508 return true;
509 self.lockCounter--;
510 return false;
511 }
512
513 /*
514 * Lock in the middle of migration
515 */
516 - (void)testUpgradeFromVersion10_5WhileLocked
517 {
518 OSStatus result = 0;
519 id mock = OCMClassMock([SecMockAKS class]);
520 [[[[mock stub] andCall:@selector(isLockedSoon:) onObject:self] ignoringNonObjectArgs] isLocked:0];
521
522 SecKeychainDbReset(^{
523 NSLog(@"resetting database");
524 [self loadDatabase:secdmock_db_version10_5];
525 });
526
527 self.lockCounter = 0;
528
529 NSDictionary* item = @{
530 (id)kSecClass : (id)kSecClassGenericPassword,
531 (id)kSecAttrAccount : @"TestAccount-11",
532 (id)kSecAttrService : @"TestService",
533 (id)kSecReturnData : @YES,
534 (id)kSecUseDataProtectionKeychain : @YES
535 };
536 result = SecItemCopyMatching((__bridge CFDictionaryRef)item, NULL);
537 XCTAssertEqual(result, errSecInteractionNotAllowed, @"SEP not locked?");
538
539 XCTAssertEqual(self.lockCounter, 0, "Device didn't lock");
540
541 NSLog(@"user unlock");
542 [mock stopMocking];
543
544 result = SecItemCopyMatching((__bridge CFDictionaryRef)item, NULL);
545 XCTAssertEqual(result, 0, @"can't find item");
546
547
548 NSLog(@"find items from old database");
549 [self findManyItems:50];
550 }
551
552
553 - (void)testUpgradeFromVersion10_5HungSEP
554 {
555 id mock = OCMClassMock([SecMockAKS class]);
556 OSStatus result = 0;
557
558 OCMStub([mock isSEPDown]).andReturn(true);
559
560 SecKeychainDbReset(^{
561 NSLog(@"resetting database");
562 [self loadDatabase:secdmock_db_version10_5];
563 });
564
565 NSDictionary* item = @{
566 (id)kSecClass : (id)kSecClassGenericPassword,
567 (id)kSecAttrAccount : @"TestAccount-0",
568 (id)kSecAttrService : @"TestService",
569 (id)kSecUseDataProtectionKeychain : @(YES)
570 };
571 result = SecItemCopyMatching((__bridge CFDictionaryRef)item, NULL);
572 XCTAssertEqual(result, errSecNotAvailable, @"SEP not down?");
573
574 kc_with_dbt(true, NULL, ^bool (SecDbConnectionRef dbt) {
575 CFErrorRef error = NULL;
576 int version = 0;
577 SecKeychainDbGetVersion(dbt, &version, &error);
578 XCTAssertEqual(error, NULL, "error getting version");
579 XCTAssertEqual(version, 0x50a, "managed to upgrade when we shouldn't have");
580
581 return true;
582 });
583
584 /* user got the SEP out of DFU */
585 NSLog(@"SEP alive");
586 [mock stopMocking];
587
588 result = SecItemCopyMatching((__bridge CFDictionaryRef)item, NULL);
589 XCTAssertEqual(result, 0, @"failed to find test item to keychain");
590
591 kc_with_dbt(true, NULL, ^bool (SecDbConnectionRef dbt) {
592 CFErrorRef error = NULL;
593 int version = 0;
594 SecKeychainDbGetVersion(dbt, &version, &error);
595 XCTAssertEqual(error, NULL, "error getting version");
596 const SecDbSchema *schema = current_schema();
597 int schemaVersion = (((schema)->minorVersion) << 8) | ((schema)->majorVersion);
598 XCTAssertEqual(version, schemaVersion, "didn't manage to upgrade");
599
600 return true;
601 });
602
603 NSLog(@"find items from old database");
604 [self findManyItems:50];
605 }
606
607 // We used to try and parse a CFTypeRef as a 32 bit int before trying 64, but that fails if keytype is weird.
608 - (void)testBindObjectIntParsing
609 {
610 NSMutableDictionary* query = [@{ (id)kSecClass : (id)kSecClassKey,
611 (id)kSecAttrCanEncrypt : @(YES),
612 (id)kSecAttrCanDecrypt : @(YES),
613 (id)kSecAttrCanDerive : @(NO),
614 (id)kSecAttrCanSign : @(NO),
615 (id)kSecAttrCanVerify : @(NO),
616 (id)kSecAttrCanWrap : @(NO),
617 (id)kSecAttrCanUnwrap : @(NO),
618 (id)kSecAttrKeySizeInBits : @(256),
619 (id)kSecAttrEffectiveKeySize : @(256),
620 (id)kSecValueData : [@"a" dataUsingEncoding:NSUTF8StringEncoding],
621 (id)kSecAttrKeyType : [NSNumber numberWithUnsignedInt:0x80000001L], // durr
622 } mutableCopy];
623
624 XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess, "Succeeded in adding key to keychain");
625
626 query[(id)kSecValueData] = nil;
627 NSDictionary* update = @{(id)kSecValueData : [@"b" dataUsingEncoding:NSUTF8StringEncoding]};
628 XCTAssertEqual(SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update), errSecSuccess, "Successfully updated key in keychain");
629
630 CFTypeRef output = NULL;
631 query[(id)kSecReturnAttributes] = @(YES);
632 XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, &output), errSecSuccess, "Found key in keychain");
633 XCTAssertNotNil((__bridge id)output, "got output from SICM");
634 XCTAssertEqual(CFGetTypeID(output), CFDictionaryGetTypeID(), "output is a dictionary");
635 XCTAssertEqual(CFDictionaryGetValue(output, (id)kSecAttrKeyType), (__bridge CFNumberRef)[NSNumber numberWithUnsignedInt:0x80000001L], "keytype is unchanged");
636 }
637
638 #endif /* USE_KEYSTORE */
639
640 @end