]> git.saurik.com Git - apple/security.git/blob - tests/stashtester/main.m
Security-59754.41.1.tar.gz
[apple/security.git] / tests / stashtester / main.m
1 #import <Foundation/Foundation.h>
2 #import <Security/SecKeychainPriv.h>
3 #include <MobileKeyBag/MobileKeyBag.h>
4
5 static void print(NSString* str) {
6 if (![str hasSuffix:@"\n"]) {
7 str = [str stringByAppendingString:@"\n"];
8 }
9 [str writeToFile:@"/dev/stdout" atomically:NO encoding:NSUTF8StringEncoding error:nil];
10 }
11
12 static void usage() {
13 print(@"Usage: stashtester [commands]");
14 print(@"");
15 print(@"Commands:");
16 print(@" -c Combine stash and load requests (equivalent to -s and -l)");
17 print(@" -l Send stash login request to securityd (SecKeychainLogin)");
18 print(@" -s Send stash request to securityd (SecKeychainStash)");
19 print(@" -t Test the complete operation");
20 }
21
22 static bool performStash() {
23 NSLog(@"attempting stash");
24 OSStatus result = SecKeychainStash();
25 NSLog(@"result from stash: %ld", (long)result);
26 return result == errSecSuccess;
27 }
28
29 static bool performLoad() {
30 NSLog(@"attempting load");
31 OSStatus result = SecKeychainLogin(0, NULL, 0, NULL);
32 NSLog(@"result from load: %ld", (long)result);
33 return result == errSecSuccess;
34 }
35
36 static NSMutableDictionary* makeQuery(bool includeData) {
37 NSMutableDictionary* query = [@{
38 (id)kSecClass : (id)kSecClassGenericPassword,
39 (id)kSecAttrAccount : @"stashtester",
40 (id)kSecUseDataProtectionKeychain : @NO,
41 } mutableCopy];
42 if (includeData) {
43 query[(id)kSecValueData] = [@"sekrit" dataUsingEncoding:NSUTF8StringEncoding];
44 }
45 return query;
46 }
47
48 static bool performTest() {
49 NSLog(@"Begin test");
50 NSLog(@"Adding item to keychain");
51 NSMutableDictionary* addQ = makeQuery(true);
52 OSStatus result = SecItemAdd((__bridge CFDictionaryRef)addQ, NULL);
53 if (result != errSecSuccess) {
54 NSLog(@"Failed to add item pre-stash: %d; aborting test", (int)result);
55 return false;
56 }
57
58 if (!performStash()) {
59 NSLog(@"Stash failed; aborting test");
60 return false;
61 }
62
63 NSLog(@"Locking legacy keychain");
64 SecKeychainRef loginkc = NULL;
65 SecKeychainCopyLogin(&loginkc);
66 result = SecKeychainCopyLogin(&loginkc);
67 if (result != errSecSuccess) {
68 NSLog(@"Unable to obtain reference to login keychain; aborting test");
69 return false;
70 }
71 result = SecKeychainLock(loginkc);
72 if (result != errSecSuccess) {
73 NSLog(@"Unable to lock login keychain; aborting test");
74 return false;
75 }
76
77 SecKeychainStatus status = 0;
78 result = SecKeychainGetStatus(loginkc, &status);
79 CFRelease(loginkc);
80 if (result != errSecSuccess) {
81 NSLog(@"Unable to get login keychain status; aborting test");
82 return false;
83 }
84
85 if (status & kSecUnlockStateStatus) {
86 NSLog(@"Login keychain not locked after locking; aborting test");
87 return false;
88 }
89
90 NSLog(@"Locking keybag");
91 int rc = MKBLockDevice((__bridge CFDictionaryRef)@{(id)kKeyBagLockDeviceNow : @YES});
92 if (rc != kIOReturnSuccess) {
93 NSLog(@"Failed to lock keybag (%d); aborting test", rc);
94 return false;
95 }
96
97 // MKB asynchronously locks bag, make sure we don't race it
98 NSLog(@"Twiddling thumbs for 11 seconds");
99 sleep(11);
100
101 NSLog(@"Verifying keybag is locked");
102 NSMutableDictionary* checkQ = makeQuery(false);
103 checkQ[(id)kSecUseDataProtectionKeychain] = @YES;
104 result = SecItemAdd((__bridge CFDictionaryRef)checkQ, NULL);
105 if (result != errSecInteractionNotAllowed) {
106 NSLog(@"Data protection keychain unexpectedly not locked; aborting test");
107 return false;
108 }
109
110 if (!performLoad()) {
111 NSLog(@"Failed to load stash (%d); aborting test", result);
112 return false;
113 }
114
115 NSMutableDictionary* findQ = makeQuery(false);
116 findQ[(id)kSecReturnData] = @YES;
117 CFTypeRef object = NULL;
118 result = SecItemCopyMatching((__bridge CFDictionaryRef)findQ, &object);
119 NSData* password;
120 if (object) {
121 password = CFBridgingRelease(object);
122 }
123 if (result != errSecSuccess || !password || ![[@"sekrit" dataUsingEncoding:NSUTF8StringEncoding] isEqual:password]) {
124 NSLog(@"Unable to find item post-stashload (%d, %@); aborting test", result, password);
125 return false;
126 }
127
128 NSLog(@"Test succeeded");
129 return true;
130 }
131
132 static bool cleanup() {
133 NSLog(@"Cleaning up");
134 NSMutableDictionary* query = makeQuery(false);
135 OSStatus result = SecItemDelete((__bridge CFDictionaryRef)query);
136 if (result != errSecSuccess) {
137 NSLog(@"Cleanup: failed to delete item");
138 return false;
139 }
140 return true;
141 }
142
143 int main(int argc, const char * argv[]) {
144 @autoreleasepool {
145 bool stash = false;
146 bool load = false;
147 bool test = false;
148 int arg = 0;
149 char * const *gargv = (char * const *)argv;
150 while ((arg = getopt(argc, gargv, "clst")) != -1) {
151 switch (arg) {
152 case 'c':
153 stash = true;
154 load = true;
155 break;
156 case 'l':
157 load = true;
158 break;
159 case 's':
160 stash = true;
161 break;
162 case 't':
163 test = true;
164 break;
165 default:
166 usage();
167 return 1;
168 }
169 }
170
171 if ((!stash && !load && !test) ||
172 (test && (stash || load)))
173 {
174 usage();
175 return 1;
176 }
177
178 if (test) {
179 bool testresult = performTest();
180 bool cleanresult = cleanup();
181 return (testresult && cleanresult) ? 0 : -1;
182 }
183
184 if (stash && !performStash()) {
185 return -1;
186 }
187
188 if (load && !performLoad()) {
189 return -1;
190 }
191 }
192 return 0;
193 }