]> git.saurik.com Git - apple/security.git/blob - tests/secdmockaks/mockaksKeychain.m
Security-59306.11.20.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 // BT root key, should not be deleted
140 NSMutableDictionary* bt = [@{
141 (id)kSecClass : (id)kSecClassGenericPassword,
142 (id)kSecAttrAccessGroup : @"com.apple.bluetooth",
143 (id)kSecAttrService : @"BluetoothGlobal",
144 (id)kSecAttrAccessible : (id)kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate,
145 (id)kSecAttrSynchronizable : @(NO),
146 (id)kSecValueData : [@"btkey" dataUsingEncoding:NSUTF8StringEncoding],
147 } mutableCopy];
148
149 // lockdown-identities, should not be deleted
150 NSMutableDictionary* ld = [@{
151 (id)kSecClass : (id)kSecClassKey,
152 (id)kSecAttrAccessGroup : @"lockdown-identities",
153 (id)kSecAttrLabel : @"com.apple.lockdown.identity.activation",
154 (id)kSecAttrAccessible : (id)kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate,
155 (id)kSecAttrSynchronizable : @(NO),
156 (id)kSecValueData : [@"ldkey" dataUsingEncoding:NSUTF8StringEncoding],
157 } mutableCopy];
158
159 // general nonsyncable item, should be deleted
160 NSMutableDictionary* s0 = [@{
161 (id)kSecClass : (id)kSecClassGenericPassword,
162 (id)kSecAttrService : @"NonsyncableService",
163 (id)kSecAttrSynchronizable : @(NO),
164 (id)kSecValueData : [@"s0pwd" dataUsingEncoding:NSUTF8StringEncoding],
165 } mutableCopy];
166
167 // general syncable item, should be deleted
168 NSMutableDictionary* s1 = [@{
169 (id)kSecClass : (id)kSecClassGenericPassword,
170 (id)kSecAttrService : @"SyncableService",
171 (id)kSecAttrSynchronizable : @(YES),
172 (id)kSecValueData : [@"s0pwd" dataUsingEncoding:NSUTF8StringEncoding],
173 } mutableCopy];
174
175 // Insert all items
176 OSStatus status;
177 status = SecItemAdd((__bridge CFDictionaryRef)bt, NULL);
178 XCTAssertEqual(status, errSecSuccess, "failed to add bt item to keychain");
179 status = SecItemAdd((__bridge CFDictionaryRef)ld, NULL);
180 XCTAssertEqual(status, errSecSuccess, "failed to add ld item to keychain");
181 status = SecItemAdd((__bridge CFDictionaryRef)s0, NULL);
182 XCTAssertEqual(status, errSecSuccess, "failed to add s0 item to keychain");
183 status = SecItemAdd((__bridge CFDictionaryRef)s1, NULL);
184 XCTAssertEqual(status, errSecSuccess, "failed to add s1 item to keychain");
185
186 // Make sure they exist now
187 bt[(id)kSecValueData] = nil;
188 ld[(id)kSecValueData] = nil;
189 s0[(id)kSecValueData] = nil;
190 s1[(id)kSecValueData] = nil;
191 status = SecItemCopyMatching((__bridge CFDictionaryRef)bt, NULL);
192 XCTAssertEqual(status, errSecSuccess, "failed to find bt item in keychain");
193 status = SecItemCopyMatching((__bridge CFDictionaryRef)ld, NULL);
194 XCTAssertEqual(status, errSecSuccess, "failed to find ld item in keychain");
195 status = SecItemCopyMatching((__bridge CFDictionaryRef)s0, NULL);
196 XCTAssertEqual(status, errSecSuccess, "failed to find s0 item in keychain");
197 status = SecItemCopyMatching((__bridge CFDictionaryRef)s1, NULL);
198 XCTAssertEqual(status, errSecSuccess, "failed to find s1 item in keychain");
199
200 // Nuke the keychain
201 CFErrorRef error = NULL;
202 _SecItemDeleteAll(&error);
203 XCTAssertEqual(error, NULL, "_SecItemDeleteAll returned an error: %@", error);
204 CFReleaseNull(error);
205
206 // Does the function work properly with an error pre-set?
207 error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, errSecItemNotFound, NULL);
208 _SecItemDeleteAll(&error);
209 XCTAssertEqual(CFErrorGetDomain(error), kCFErrorDomainOSStatus);
210 XCTAssertEqual(CFErrorGetCode(error), errSecItemNotFound);
211 CFReleaseNull(error);
212
213 // Check the relevant items are missing
214 status = SecItemCopyMatching((__bridge CFDictionaryRef)bt, NULL);
215 XCTAssertEqual(status, errSecSuccess, "failed to find bt item in keychain");
216 status = SecItemCopyMatching((__bridge CFDictionaryRef)ld, NULL);
217 XCTAssertEqual(status, errSecSuccess, "failed to find ld item in keychain");
218 status = SecItemCopyMatching((__bridge CFDictionaryRef)s0, NULL);
219 XCTAssertEqual(status, errSecItemNotFound, "unexpectedly found s0 item in keychain");
220 status = SecItemCopyMatching((__bridge CFDictionaryRef)s1, NULL);
221 XCTAssertEqual(status, errSecItemNotFound, "unexpectedly found s1 item in keychain");
222 }
223
224 - (void)createManyKeys
225 {
226 unsigned n;
227 for (n = 0; n < 50; n++) {
228 NSDictionary* keyParams = @{
229 (id)kSecAttrKeyType : (id)kSecAttrKeyTypeRSA,
230 (id)kSecAttrKeySizeInBits : @(1024)
231 };
232 SecKeyRef key = SecKeyCreateRandomKey((__bridge CFDictionaryRef)keyParams, NULL);
233 NSDictionary* item = @{ (id)kSecClass : (id)kSecClassKey,
234 (id)kSecValueRef : (__bridge id)key,
235 (id)kSecAttrLabel : [NSString stringWithFormat:@"TestLabel-%u", n],
236 (id)kSecUseDataProtectionKeychain : @(YES) };
237
238 OSStatus result = SecItemAdd((__bridge CFDictionaryRef)item, NULL);
239 XCTAssertEqual(result, 0, @"failed to add test key to keychain: %u", n);
240 }
241 }
242
243
244 - (void)testBackupRestoreItem
245 {
246 [self createManyItems];
247 [self createManyKeys];
248
249
250 NSDictionary* item = @{ (id)kSecClass : (id)kSecClassGenericPassword,
251 (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
252 (id)kSecAttrAccount : @"TestAccount",
253 (id)kSecAttrService : @"TestService",
254 (id)kSecUseDataProtectionKeychain : @(YES) };
255
256 OSStatus result = SecItemAdd((__bridge CFDictionaryRef)item, NULL);
257 XCTAssertEqual(result, 0, @"failed to add test item to keychain");
258
259 NSMutableDictionary* dataQuery = item.mutableCopy;
260 [dataQuery removeObjectForKey:(id)kSecValueData];
261 dataQuery[(id)kSecReturnData] = @(YES);
262 CFTypeRef foundItem = NULL;
263
264 /*
265 * Create backup
266 */
267
268 CFDataRef keybag = CFDataCreate(kCFAllocatorDefault, NULL, 0);
269 CFDataRef password = CFDataCreate(kCFAllocatorDefault, NULL, 0);
270
271 CFDataRef backup = _SecKeychainCopyBackup(keybag, password);
272 XCTAssert(backup, "expected to have a backup");
273
274 result = SecItemDelete((__bridge CFDictionaryRef)dataQuery);
275 XCTAssertEqual(result, 0, @"failed to delete item");
276
277 result = SecItemCopyMatching((__bridge CFDictionaryRef)dataQuery, &foundItem);
278 XCTAssertEqual(result, errSecItemNotFound,
279 @"failed to find the data for the item we just added in the keychain");
280 CFReleaseNull(foundItem);
281
282 /*
283 * Restore backup and see that item is resurected
284 */
285
286 XCTAssertEqual(0, _SecKeychainRestoreBackup(backup, keybag, password));
287
288 CFReleaseNull(backup);
289 CFReleaseNull(password);
290 CFReleaseNull(keybag);
291
292 result = SecItemCopyMatching((__bridge CFDictionaryRef)dataQuery, &foundItem);
293 XCTAssertEqual(result, 0, @"failed to find the data for the item we just added in the keychain");
294 CFReleaseNull(foundItem);
295
296 result = SecItemDelete((__bridge CFDictionaryRef)dataQuery);
297 XCTAssertEqual(result, 0, @"failed to delete item");
298 }
299
300 - (void)testCreateSampleDatabase
301 {
302 #if USE_KEYSTORE
303 id mock = OCMClassMock([SecMockAKS class]);
304 OCMStub([mock useGenerationCount]).andReturn(true);
305 #endif
306
307 [self createManyItems];
308 [self createManyKeys];
309
310 /*
311 sleep(600);
312 lsof -p $(pgrep xctest)
313 sqlite3 database
314 .output mydatabase.h
315 .dump
316
317 add header and footer
318 */
319
320 [self findManyItems:50];
321 }
322
323 - (void)testTestAKSGenerationCount
324 {
325 #if USE_KEYSTORE
326 id mock = OCMClassMock([SecMockAKS class]);
327 OCMStub([mock useGenerationCount]).andReturn(true);
328
329 [self createManyItems];
330 [self findManyItems:50];
331 #endif
332 }
333
334
335 - (void)loadDatabase:(const char **)dumpstring
336 {
337 const char *s;
338 unsigned n = 0;
339
340 // We need a fresh directory to plop down our SQLite data
341 SetCustomHomeURLString((__bridge CFStringRef)[self createKeychainDirectoryWithSubPath:@"loadManualDB"]);
342 NSString* path = CFBridgingRelease(__SecKeychainCopyPath());
343 // On macOS the full path gets created, on iOS not (yet?)
344 [self createKeychainDirectoryWithSubPath:@"loadManualDB/Library/Keychains"];
345
346 sqlite3 *handle = NULL;
347
348 XCTAssertEqual(SQLITE_OK, sqlite3_open([path UTF8String], &handle), "create keychain");
349
350 while ((s = dumpstring[n++]) != NULL) {
351 char * errmsg = NULL;
352 XCTAssertEqual(SQLITE_OK, sqlite3_exec(handle, s, NULL, NULL, &errmsg),
353 "exec: %s: %s", s, errmsg);
354 if (errmsg) {
355 sqlite3_free(errmsg);
356 }
357 }
358 XCTAssertEqual(SQLITE_OK, sqlite3_close(handle), "close sqlite");
359 }
360
361 - (void)checkIncremental
362 {
363 /*
364 * check that we made incremental vacuum mode
365 */
366
367 __block CFErrorRef localError = NULL;
368 __block bool ok = true;
369 __block int vacuumMode = -1;
370
371 kc_with_dbt(true, NULL, ^bool (SecDbConnectionRef dbt) {
372 ok &= SecDbPrepare(dbt, CFSTR("PRAGMA auto_vacuum"), &localError, ^(sqlite3_stmt *stmt) {
373 ok = SecDbStep(dbt, stmt, NULL, ^(bool *stop) {
374 vacuumMode = sqlite3_column_int(stmt, 0);
375 });
376 });
377 return ok;
378 });
379 XCTAssertEqual(ok, true, "should work to fetch auto_vacuum value: %@", localError);
380 XCTAssertEqual(vacuumMode, 2, "vacuum mode should be incremental (2)");
381
382 CFReleaseNull(localError);
383
384 }
385
386 - (void)testUpgradeFromVersion10_5
387 {
388 SecKeychainDbReset(^{
389 NSLog(@"resetting database");
390 [self loadDatabase:secdmock_db_version10_5];
391 });
392
393 NSLog(@"find items from old database");
394 [self findManyItems:50];
395
396 [self checkIncremental];
397 }
398
399 - (void)testUpgradeFromVersion11_1
400 {
401 SecKeychainDbReset(^{
402 NSLog(@"resetting database");
403 [self loadDatabase:secdmock_db_version11_1];
404 });
405
406 NSLog(@"find items from old database");
407 [self findManyItems:50];
408
409 [self checkIncremental];
410 }
411
412 #if TARGET_OS_IOS
413
414 - (void)testPersonaBasic
415 {
416 SecSecuritySetPersonaMusr(NULL);
417
418 [self createManyItems];
419 [self findManyItems:10];
420
421 SecSecuritySetPersonaMusr(CFSTR("99C5D3CC-2C2D-47C4-9A1C-976EC047BF3C"));
422
423 [self findNoItems:10];
424 [self createManyItems];
425 [self findManyItems:10];
426
427 [self deleteAllItems];
428 [self findNoItems:10];
429
430 SecSecuritySetPersonaMusr(NULL);
431
432 [self findManyItems:10];
433 [self deleteAllItems];
434 [self findNoItems:10];
435
436 SecSecuritySetPersonaMusr(CFSTR("8E90C6BE-0AF6-40D6-8A4B-D46E4CF6A622"));
437
438 [self createManyItems];
439
440 SecSecuritySetPersonaMusr(CFSTR("38B615CA-02C2-4733-A71C-1ABA46D27B13"));
441
442 [self findNoItems:10];
443 [self createManyItems];
444
445 SecSecuritySetPersonaMusr(NULL);
446
447 XCTestExpectation *expection = [self expectationWithDescription:@"wait for deletion"];
448
449 _SecKeychainDeleteMultiUser(@"8E90C6BE-0AF6-40D6-8A4B-D46E4CF6A622", ^(bool status, NSError *error) {
450 [expection fulfill];
451 });
452
453 [self waitForExpectations:@[expection] timeout:10.0];
454
455 /* check that delete worked ... */
456 SecSecuritySetPersonaMusr(CFSTR("8E90C6BE-0AF6-40D6-8A4B-D46E4CF6A622"));
457 [self findNoItems:10];
458
459 /* ... but didn't delete another account */
460 SecSecuritySetPersonaMusr(CFSTR("38B615CA-02C2-4733-A71C-1ABA46D27B13"));
461 [self findManyItems:10];
462
463 SecSecuritySetPersonaMusr(NULL);
464
465
466 [self findNoItems:10];
467 }
468
469 #endif /* TARGET_OS_IOS */
470
471 #if USE_KEYSTORE
472
473 - (void)testAddKeyByReference
474 {
475 NSDictionary* keyParams = @{ (id)kSecAttrKeyType : (id)kSecAttrKeyTypeRSA, (id)kSecAttrKeySizeInBits : @(1024) };
476 SecKeyRef key = SecKeyCreateRandomKey((__bridge CFDictionaryRef)keyParams, NULL);
477 NSDictionary* item = @{ (id)kSecClass : (id)kSecClassKey,
478 (id)kSecValueRef : (__bridge id)key,
479 (id)kSecAttrLabel : @"TestLabel",
480 (id)kSecUseDataProtectionKeychain : @(YES) };
481
482 OSStatus result = SecItemAdd((__bridge CFDictionaryRef)item, NULL);
483 XCTAssertEqual(result, 0, @"failed to add test item to keychain");
484
485 NSMutableDictionary* refQuery = item.mutableCopy;
486 [refQuery removeObjectForKey:(id)kSecValueData];
487 refQuery[(id)kSecReturnRef] = @(YES);
488 CFTypeRef foundItem = NULL;
489 result = SecItemCopyMatching((__bridge CFDictionaryRef)refQuery, &foundItem);
490 XCTAssertEqual(result, 0, @"failed to find the reference for the item we just added in the keychain");
491
492 NSData* originalKeyData = (__bridge_transfer NSData*)SecKeyCopyExternalRepresentation(key, NULL);
493 NSData* foundKeyData = (__bridge_transfer NSData*)SecKeyCopyExternalRepresentation((SecKeyRef)foundItem, NULL);
494 XCTAssertEqualObjects(originalKeyData, foundKeyData, @"found key does not match the key we put in the keychain");
495
496 result = SecItemDelete((__bridge CFDictionaryRef)refQuery);
497 XCTAssertEqual(result, 0, @"failed to delete key");
498 }
499
500 - (bool)isLockedSoon:(keyclass_t)key_class
501 {
502 if (key_class == key_class_d || key_class == key_class_dku)
503 return false;
504 if (self.lockCounter <= 0)
505 return true;
506 self.lockCounter--;
507 return false;
508 }
509
510 /*
511 * Lock in the middle of migration
512 */
513 - (void)testUpgradeFromVersion10_5WhileLocked
514 {
515 OSStatus result = 0;
516 id mock = OCMClassMock([SecMockAKS class]);
517 [[[[mock stub] andCall:@selector(isLockedSoon:) onObject:self] ignoringNonObjectArgs] isLocked:0];
518
519 SecKeychainDbReset(^{
520 NSLog(@"resetting database");
521 [self loadDatabase:secdmock_db_version10_5];
522 });
523
524 self.lockCounter = 0;
525
526 NSDictionary* item = @{
527 (id)kSecClass : (id)kSecClassGenericPassword,
528 (id)kSecAttrAccount : @"TestAccount-11",
529 (id)kSecAttrService : @"TestService",
530 (id)kSecReturnData : @YES,
531 (id)kSecUseDataProtectionKeychain : @YES
532 };
533 result = SecItemCopyMatching((__bridge CFDictionaryRef)item, NULL);
534 XCTAssertEqual(result, errSecInteractionNotAllowed, @"SEP not locked?");
535
536 XCTAssertEqual(self.lockCounter, 0, "Device didn't lock");
537
538 NSLog(@"user unlock");
539 [mock stopMocking];
540
541 result = SecItemCopyMatching((__bridge CFDictionaryRef)item, NULL);
542 XCTAssertEqual(result, 0, @"can't find item");
543
544
545 NSLog(@"find items from old database");
546 [self findManyItems:50];
547 }
548
549
550 - (void)testUpgradeFromVersion10_5HungSEP
551 {
552 id mock = OCMClassMock([SecMockAKS class]);
553 OSStatus result = 0;
554
555 OCMStub([mock isSEPDown]).andReturn(true);
556
557 SecKeychainDbReset(^{
558 NSLog(@"resetting database");
559 [self loadDatabase:secdmock_db_version10_5];
560 });
561
562 NSDictionary* item = @{
563 (id)kSecClass : (id)kSecClassGenericPassword,
564 (id)kSecAttrAccount : @"TestAccount-0",
565 (id)kSecAttrService : @"TestService",
566 (id)kSecUseDataProtectionKeychain : @(YES)
567 };
568 result = SecItemCopyMatching((__bridge CFDictionaryRef)item, NULL);
569 XCTAssertEqual(result, errSecNotAvailable, @"SEP not down?");
570
571 kc_with_dbt(true, NULL, ^bool (SecDbConnectionRef dbt) {
572 CFErrorRef error = NULL;
573 int version = 0;
574 SecKeychainDbGetVersion(dbt, &version, &error);
575 XCTAssertEqual(error, NULL, "error getting version");
576 XCTAssertEqual(version, 0x50a, "managed to upgrade when we shouldn't have");
577
578 return true;
579 });
580
581 /* user got the SEP out of DFU */
582 NSLog(@"SEP alive");
583 [mock stopMocking];
584
585 result = SecItemCopyMatching((__bridge CFDictionaryRef)item, NULL);
586 XCTAssertEqual(result, 0, @"failed to find test item to keychain");
587
588 kc_with_dbt(true, NULL, ^bool (SecDbConnectionRef dbt) {
589 CFErrorRef error = NULL;
590 int version = 0;
591 SecKeychainDbGetVersion(dbt, &version, &error);
592 XCTAssertEqual(error, NULL, "error getting version");
593 const SecDbSchema *schema = current_schema();
594 int schemaVersion = (((schema)->minorVersion) << 8) | ((schema)->majorVersion);
595 XCTAssertEqual(version, schemaVersion, "didn't manage to upgrade");
596
597 return true;
598 });
599
600 NSLog(@"find items from old database");
601 [self findManyItems:50];
602 }
603
604 // We used to try and parse a CFTypeRef as a 32 bit int before trying 64, but that fails if keytype is weird.
605 - (void)testBindObjectIntParsing
606 {
607 NSMutableDictionary* query = [@{ (id)kSecClass : (id)kSecClassKey,
608 (id)kSecAttrCanEncrypt : @(YES),
609 (id)kSecAttrCanDecrypt : @(YES),
610 (id)kSecAttrCanDerive : @(NO),
611 (id)kSecAttrCanSign : @(NO),
612 (id)kSecAttrCanVerify : @(NO),
613 (id)kSecAttrCanWrap : @(NO),
614 (id)kSecAttrCanUnwrap : @(NO),
615 (id)kSecAttrKeySizeInBits : @(256),
616 (id)kSecAttrEffectiveKeySize : @(256),
617 (id)kSecValueData : [@"a" dataUsingEncoding:NSUTF8StringEncoding],
618 (id)kSecAttrKeyType : [NSNumber numberWithUnsignedInt:0x80000001L], // durr
619 } mutableCopy];
620
621 XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess, "Succeeded in adding key to keychain");
622
623 query[(id)kSecValueData] = nil;
624 NSDictionary* update = @{(id)kSecValueData : [@"b" dataUsingEncoding:NSUTF8StringEncoding]};
625 XCTAssertEqual(SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update), errSecSuccess, "Successfully updated key in keychain");
626
627 CFTypeRef output = NULL;
628 query[(id)kSecReturnAttributes] = @(YES);
629 XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, &output), errSecSuccess, "Found key in keychain");
630 XCTAssertNotNil((__bridge id)output, "got output from SICM");
631 XCTAssertEqual(CFGetTypeID(output), CFDictionaryGetTypeID(), "output is a dictionary");
632 XCTAssertEqual(CFDictionaryGetValue(output, (id)kSecAttrKeyType), (__bridge CFNumberRef)[NSNumber numberWithUnsignedInt:0x80000001L], "keytype is unchanged");
633 }
634
635 #endif /* USE_KEYSTORE */
636
637 @end