]> git.saurik.com Git - apple/security.git/blob - secdxctests/KeychainBackupTests.m
Security-59754.80.3.tar.gz
[apple/security.git] / secdxctests / KeychainBackupTests.m
1 #import "KeychainXCTest.h"
2 #import <Security/Security.h>
3 #import <Security/SecItemPriv.h>
4 #include <Security/SecEntitlements.h>
5 #include <ipc/server_security_helpers.h>
6
7 @interface KeychainBackupTests : KeychainXCTest
8 @end
9
10
11 @implementation KeychainBackupTests {
12 NSString* _applicationIdentifier;
13 }
14
15 - (void)setUp {
16 // Put setup code here. This method is called before the invocation of each test method in the class.
17 [super setUp];
18 _applicationIdentifier = @"com.apple.security.backuptests";
19 SecSecurityClientSetApplicationIdentifier((__bridge CFStringRef)_applicationIdentifier);
20 }
21
22 - (void)tearDown {
23 // Put teardown code here. This method is called after the invocation of each test method in the class.
24 }
25
26 # pragma mark - Test OTA Backups
27
28 // Code lovingly adapted from si-33-keychain-backup
29 #if USE_KEYSTORE
30 - (NSData*)createKeybagWithType:(keybag_handle_t)bag_type password:(NSData*)password
31 {
32 keybag_handle_t handle = bad_keybag_handle;
33 kern_return_t bag_created = aks_create_bag(password ? password.bytes : NULL, password ? (int)password.length : 0, bag_type, &handle);
34 XCTAssertEqual(bag_created, kAKSReturnSuccess, @"Unable to create keybag");
35
36 void *bag = NULL;
37 int bagLen = 0;
38 kern_return_t bag_saved = aks_save_bag(handle, &bag, &bagLen);
39 XCTAssertEqual(bag_saved, kAKSReturnSuccess, @"Unable to save keybag");
40
41 NSData* bagData = [NSData dataWithBytes:bag length:bagLen];
42 XCTAssertNotNil(bagData, @"Unable to create NSData from bag bytes");
43
44 return bagData;
45 }
46 #endif
47
48 // All backup paths ultimately lead to SecServerCopyKeychainPlist which does the actual exporting,
49 // so this test ought to suffice for all backup configurations
50 - (void)testAppClipDoesNotBackup {
51
52 // First add a "regular" item for each class, which we expect to be in the backup later
53 NSMutableDictionary* query = [@{
54 (id)kSecClass : (id)kSecClassGenericPassword,
55 (id)kSecUseDataProtectionKeychain : @YES,
56 (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
57 } mutableCopy];
58
59 XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
60 XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
61
62 query[(id)kSecClass] = (id)kSecClassInternetPassword;
63 XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
64 XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
65
66 query[(id)kSecClass] = (id)kSecClassCertificate;
67 XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
68 XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
69
70 query[(id)kSecClass] = (id)kSecClassKey;
71 XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
72 XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
73
74 // Switch to being an app clip, add another item for each class, which we expect not to find in the backup
75 SecSecurityClientRegularToAppClip();
76 [self setEntitlements:@{@"com.apple.application-identifier" : _applicationIdentifier} validated:YES];
77
78 query[(id)kSecClass] = (id)kSecClassGenericPassword;
79 XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
80 XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
81
82 query[(id)kSecClass] = (id)kSecClassInternetPassword;
83 XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
84 XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
85
86 query[(id)kSecClass] = (id)kSecClassCertificate;
87 XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
88 XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
89
90 query[(id)kSecClass] = (id)kSecClassKey;
91 XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
92 XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
93
94 SecSecurityClientAppClipToRegular();
95 SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementRestoreKeychain, @YES);
96
97 // Code lovingly adapted from si-33-keychain-backup
98 NSData* keybag;
99 #if USE_KEYSTORE
100 keybag = [self createKeybagWithType:kAppleKeyStoreBackupBag password:nil];
101 #else
102 keybag = [NSData new];
103 #endif
104
105 NSData* data = CFBridgingRelease(_SecKeychainCopyBackup((__bridge CFDataRef)keybag, nil));
106
107 XCTAssert(data);
108 XCTAssertGreaterThan([data length], 42, @"Got empty dictionary");
109 NSDictionary* keychain = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:nil error:nil];
110
111 // Only one item should be here for each class, which is the regular one.
112 XCTAssertEqual([keychain[@"genp"] count], 1);
113 XCTAssertEqual([keychain[@"inet"] count], 1);
114 XCTAssertEqual([keychain[@"cert"] count], 1);
115 XCTAssertEqual([keychain[@"keys"] count], 1);
116 }
117
118 @end