]> git.saurik.com Git - apple/security.git/blob - RegressionTests/secitemcanarytest/secitemcanarytest.m
Security-59754.41.1.tar.gz
[apple/security.git] / RegressionTests / secitemcanarytest / secitemcanarytest.m
1 #include <Foundation/Foundation.h>
2 #include <Security/Security.h>
3 #include <Security/SecItemPriv.h>
4 #include <err.h>
5
6 static void usage(void) __dead2;
7 static bool create_item(NSString *acct);
8 static bool verify_item(NSString *acct, bool deleteit);
9 static void initial_state(void) __dead2;
10 static uint64_t update_state(void);
11 static void reset(void) __dead2;
12
13 static NSString *kCanaryAccessGroup = @"com.apple.security.test.canary";
14 static NSString *kCanaryStateAccount = @"com.apple.security.test.canaryState";
15
16 int
17 main(int argc, char *argv[])
18 {
19 int ch;
20 uint64_t iter;
21 bool success;
22
23 iter = 0;
24 while ((ch = getopt(argc, argv, "ir")) != -1) {
25 switch (ch) {
26 case 'i':
27 initial_state();
28 /*notreached*/
29 case 'r':
30 reset();
31 /*notreached*/
32 default:
33 usage();
34 /*notreached*/
35 }
36 }
37
38 iter = update_state();
39 fprintf(stderr, "iter = %llu\n\n", iter);
40
41 @autoreleasepool {
42 if (iter > 0) {
43 printf("[TEST] Verify and delete previous canary item\n");
44 success = verify_item([NSString stringWithFormat:@"canary%llu", iter - 1], true);
45 printf("[%s]\n", success ? "PASS" : "FAIL");
46 fprintf(stderr, "\n");
47 }
48
49 printf("[TEST] Create canary item\n");
50 success = create_item([NSString stringWithFormat:@"canary%llu", iter]);
51 printf("[%s]\n", success ? "PASS" : "FAIL");
52 }
53 }
54
55 static void
56 usage(void)
57 {
58
59 fprintf(stderr, "usage: secitemcanarytest -i Generate initial state\n"
60 " secitemcanarytest Normal operation\n"
61 " secitemcanarytest -r Reset everything\n");
62 exit(1);
63 }
64
65 static bool
66 create_item(NSString *acct)
67 {
68 OSStatus status;
69 NSDictionary *attrs;
70 int nerrors = 0;
71
72 attrs = @{
73 (id)kSecClass : (id)kSecClassGenericPassword,
74 (id)kSecAttrLabel : @"secitemcanarytest-oneItem",
75 (id)kSecAttrAccount : acct,
76 (id)kSecAttrAccessGroup : kCanaryAccessGroup,
77 (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock,
78 (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue,
79 (id)kSecValueData : [NSData dataWithBytes:"password" length: 8],
80 };
81 status = SecItemAdd((__bridge CFDictionaryRef)attrs, NULL);
82 if (status != 0) {
83 nerrors++;
84 fprintf(stderr, "SecItemAdd(%s): %d\n", acct.UTF8String, status);
85 } else {
86 printf("created: %s\n", acct.UTF8String);
87 }
88
89 if (!verify_item(acct, false)) {
90 nerrors++;
91 }
92
93 return (nerrors == 0);
94 }
95
96 static bool
97 verify_item(NSString *acct, bool deleteit)
98 {
99 OSStatus status;
100 NSDictionary *query;
101 CFTypeRef result;
102 int nerrors = 0;
103
104 query = @{
105 (id)kSecClass : (id)kSecClassGenericPassword,
106 (id)kSecAttrAccessGroup : kCanaryAccessGroup,
107 (id)kSecAttrAccount : acct,
108 (id)kSecReturnAttributes : @YES,
109 (id)kSecMatchLimit : (id)kSecMatchLimitAll,
110 (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue,
111 };
112 result = NULL;
113 status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
114 if (status != 0) {
115 nerrors++;
116 fprintf(stderr, "SecItemCopyMatching(%s): %d\n", acct.UTF8String, status);
117 } else {
118 if (CFGetTypeID(result) != CFArrayGetTypeID()) {
119 nerrors++;
120 fprintf(stderr, "SecItemCopyMatching(%s): not array\n", acct.UTF8String);
121 } else if (CFArrayGetCount(result) != 1) {
122 nerrors++;
123 fprintf(stderr, "SecItemCopyMatching(%s): incorrect number of results\n", acct.UTF8String);
124 } else {
125 printf("verified: %s\n", acct.UTF8String);
126 }
127 CFRelease(result);
128 }
129
130 if (deleteit) {
131 status = SecItemDelete((__bridge CFDictionaryRef)query);
132 if (status != 0) {
133 nerrors++;
134 fprintf(stderr, "SecItemDelete(%s): %d\n", acct.UTF8String, status);
135 } else {
136 printf("deleted: %s\n", acct.UTF8String);
137 }
138 }
139
140 return (nerrors == 0);
141 }
142
143 static void
144 initial_state(void)
145 {
146 OSStatus status;
147 uint64_t state;
148 NSDictionary *attrs;
149
150 state = 0;
151 attrs = @{
152 (id)kSecClass : (id)kSecClassGenericPassword,
153 (id)kSecAttrLabel : @"canary test state",
154 (id)kSecAttrAccount : kCanaryStateAccount,
155 (id)kSecAttrAccessGroup : kCanaryAccessGroup,
156 (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock,
157 (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue,
158 (id)kSecValueData : [NSData dataWithBytes:&state length:sizeof(state)],
159 };
160 status = SecItemAdd((__bridge CFDictionaryRef)attrs, NULL);
161 switch (status) {
162 case 0:
163 exit(0);
164 /*notreached*/
165 default:
166 errx(1, "SecItemAdd: %d", status);
167 /*notreached*/
168 }
169 }
170
171 static uint64_t
172 update_state(void)
173 {
174 OSStatus status;
175 NSMutableDictionary *query;
176 NSDictionary *update;
177 CFTypeRef result;
178 uint64_t state = 0, next_state;
179
180 query = [NSMutableDictionary dictionary];
181 query[(id)kSecClass] = (id)kSecClassGenericPassword;
182 query[(id)kSecAttrAccessGroup] = kCanaryAccessGroup;
183 query[(id)kSecAttrAccount] = kCanaryStateAccount;
184 query[(id)kSecUseDataProtectionKeychain] = (id)kCFBooleanTrue;
185 query[(id)kSecReturnData] = @YES;
186
187 status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
188 switch (status) {
189 case 0:
190 if (result != NULL && CFGetTypeID(result) == CFDataGetTypeID() && CFDataGetLength(result) == sizeof(state)) {
191 memcpy(&state, CFDataGetBytePtr(result), sizeof(state));
192 } else {
193 errx(1, "invalid state");
194 /*notreached*/
195 }
196 break;
197 default:
198 errx(1, "failed to retrieve state: SecItemCopyMatching(state): %d", status);
199 /*notreached*/
200 }
201
202 next_state = state + 1;
203
204 query[(id)kSecReturnData] = nil;
205 update = @{
206 (id)kSecValueData : [NSData dataWithBytes:&next_state length:sizeof(next_state)],
207 };
208 status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update);
209
210 if (status != 0) {
211 errx(1, "SecItemUpdate: %d", status);
212 }
213
214 return state;
215 }
216
217 static void
218 reset(void)
219 {
220 OSStatus status;
221 NSDictionary *query;
222
223 query = @{
224 (id)kSecClass : (id)kSecClassGenericPassword,
225 (id)kSecAttrAccessGroup : kCanaryAccessGroup,
226 (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue,
227 };
228 status = SecItemDelete((__bridge CFDictionaryRef)query);
229 switch (status) {
230 case 0:
231 case errSecItemNotFound:
232 exit(0);
233 /*notreached*/
234 default:
235 errx(1, "SecItemDelete: %d", status);
236 /*notreached*/
237 }
238 }