1 #include <Foundation/Foundation.h>
2 #include <Security/Security.h>
3 #include <Security/SecItemPriv.h>
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;
13 static NSString *kCanaryAccessGroup = @"com.apple.security.test.canary";
14 static NSString *kCanaryStateAccount = @"com.apple.security.test.canaryState";
17 main(int argc, char *argv[])
24 while ((ch = getopt(argc, argv, "ir")) != -1) {
38 iter = update_state();
39 fprintf(stderr, "iter = %llu\n\n", iter);
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");
49 printf("[TEST] Create canary item\n");
50 success = create_item([NSString stringWithFormat:@"canary%llu", iter]);
51 printf("[%s]\n", success ? "PASS" : "FAIL");
59 fprintf(stderr, "usage: secitemcanarytest -i Generate initial state\n"
60 " secitemcanarytest Normal operation\n"
61 " secitemcanarytest -r Reset everything\n");
66 create_item(NSString *acct)
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],
81 status = SecItemAdd((__bridge CFDictionaryRef)attrs, NULL);
84 fprintf(stderr, "SecItemAdd(%s): %d\n", acct.UTF8String, status);
86 printf("created: %s\n", acct.UTF8String);
89 if (!verify_item(acct, false)) {
93 return (nerrors == 0);
97 verify_item(NSString *acct, bool deleteit)
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,
113 status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
116 fprintf(stderr, "SecItemCopyMatching(%s): %d\n", acct.UTF8String, status);
118 if (CFGetTypeID(result) != CFArrayGetTypeID()) {
120 fprintf(stderr, "SecItemCopyMatching(%s): not array\n", acct.UTF8String);
121 } else if (CFArrayGetCount(result) != 1) {
123 fprintf(stderr, "SecItemCopyMatching(%s): incorrect number of results\n", acct.UTF8String);
125 printf("verified: %s\n", acct.UTF8String);
131 status = SecItemDelete((__bridge CFDictionaryRef)query);
134 fprintf(stderr, "SecItemDelete(%s): %d\n", acct.UTF8String, status);
136 printf("deleted: %s\n", acct.UTF8String);
140 return (nerrors == 0);
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)],
160 status = SecItemAdd((__bridge CFDictionaryRef)attrs, NULL);
166 errx(1, "SecItemAdd: %d", status);
175 NSMutableDictionary *query;
176 NSDictionary *update;
178 uint64_t state = 0, next_state;
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;
187 status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
190 if (result != NULL && CFGetTypeID(result) == CFDataGetTypeID() && CFDataGetLength(result) == sizeof(state)) {
191 memcpy(&state, CFDataGetBytePtr(result), sizeof(state));
193 errx(1, "invalid state");
198 errx(1, "failed to retrieve state: SecItemCopyMatching(state): %d", status);
202 next_state = state + 1;
204 query[(id)kSecReturnData] = nil;
206 (id)kSecValueData : [NSData dataWithBytes:&next_state length:sizeof(next_state)],
208 status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update);
211 errx(1, "SecItemUpdate: %d", status);
224 (id)kSecClass : (id)kSecClassGenericPassword,
225 (id)kSecAttrAccessGroup : kCanaryAccessGroup,
226 (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue,
228 status = SecItemDelete((__bridge CFDictionaryRef)query);
231 case errSecItemNotFound:
235 errx(1, "SecItemDelete: %d", status);