5 // Created by Ben Williamson on 6/2/17.
12 * This is to fool os services to not provide the Keychain manager
13 * interface that doens't work since we don't have unified headers
14 * between iOS and OS X. rdar://23405418/
16 #define __KEYCHAINCORE__ 1
18 #import <Security/Security.h>
19 #import <Security/SecItemPriv.h>
20 #import <Security/SecBasePriv.h>
21 #import <Security/SecIdentityPriv.h>
23 #if SEC_OS_OSX_INCLUDES
24 #import <Security/SecKeychain.h>
30 static NSString *kAccessGroup = @"manifeststresstest";
31 static NSString *kService = @"manifeststresstest";
35 @implementation Keychain
37 - (OSStatus)addItem:(NSString *)name value:(NSString *)value view:(NSString *)view pRef:(NSArray **)result
39 NSDictionary *query = @{
40 (id)kSecClass : (id)kSecClassGenericPassword,
41 (id)kSecAttrAccessGroup : kAccessGroup,
42 (id)kSecAttrService : kService,
43 (id)kSecAttrAccount : name,
44 (id)kSecValueData : [value dataUsingEncoding:NSUTF8StringEncoding],
45 (id)kSecAttrSynchronizable: (id)kCFBooleanTrue,
46 (id)kSecAttrNoLegacy : (id)kCFBooleanTrue,
47 (id)kSecAttrSyncViewHint : view,
48 (id)kSecReturnPersistentRef: @YES,
50 CFArrayRef itemRef = NULL;
51 OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, (void *)&itemRef);
53 *result = CFBridgingRelease(itemRef);
59 - (OSStatus)addItem:(NSString *)name value:(NSString *)value view:(NSString *)view
61 return [self addItem:name value:value view:view pRef:nil];
64 - (OSStatus)updateItemWithName:(NSString *)name newValue:(NSString *)newValue
67 NSDictionary *query = @{
68 (id)kSecClass : (id)kSecClassGenericPassword,
69 (id)kSecAttrAccessGroup : kAccessGroup,
70 (id)kSecAttrService : kService,
71 (id)kSecAttrAccount : name,
72 (id)kSecAttrSynchronizable: (id)kCFBooleanTrue,
74 NSDictionary *modifications = @{
75 (id)kSecValueData : [newValue dataUsingEncoding:NSUTF8StringEncoding],
77 return SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)modifications);
80 - (OSStatus)updateItem:(id)pRef newValue:(NSString *)newValue
82 return [self updateItem:pRef modifications:@{
83 (id)kSecValueData : [newValue dataUsingEncoding:NSUTF8StringEncoding],
87 - (OSStatus)updateItem:(id)pRef newName:(NSString *)newName
89 return [self updateItem:pRef modifications:@{
90 (id)kSecAttrAccount : newName,
94 - (OSStatus)updateItem:(id)pRef newName:(NSString *)newName newValue:(NSString *)newValue
96 return [self updateItem:pRef modifications:@{
97 (id)kSecAttrAccount : newName,
98 (id)kSecValueData : [newValue dataUsingEncoding:NSUTF8StringEncoding],
102 - (OSStatus)updateItem:(id)pRef modifications:(NSDictionary *)modifications
104 NSDictionary *query = @{
105 (id)kSecClass : (id)kSecClassGenericPassword,
106 (id)kSecValuePersistentRef: ([pRef isKindOfClass:[NSData class]] ? pRef : pRef[0]),
108 return SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)modifications);
111 - (OSStatus)deleteItem:(id)pRef
113 NSDictionary *query = @{
114 (id)kSecClass : (id)kSecClassGenericPassword,
115 (id)kSecValuePersistentRef: ([pRef isKindOfClass:[NSData class]] ? pRef : pRef[0]),
117 return SecItemDelete((__bridge CFDictionaryRef)query);
120 - (OSStatus)deleteItemWithName:(NSString *)name
122 NSDictionary *query = @{
123 (id)kSecClass : (id)kSecClassGenericPassword,
124 (id)kSecAttrAccessGroup : kAccessGroup,
125 (id)kSecAttrService : kService,
126 (id)kSecAttrSynchronizable: (id)kCFBooleanTrue,
127 (id)kSecAttrAccount : name,
129 return SecItemDelete((__bridge CFDictionaryRef)query);
132 - (OSStatus)deleteAllItems
134 NSDictionary *query = @{
135 (id)kSecClass : (id)kSecClassGenericPassword,
136 (id)kSecAttrAccessGroup : kAccessGroup,
137 (id)kSecAttrSynchronizable: (id)kCFBooleanTrue,
139 return SecItemDelete((__bridge CFDictionaryRef)query);
142 - (NSDictionary<NSString *, NSArray *> *)getAllItems
144 CFArrayRef result = NULL;
145 NSDictionary *query = @{
146 (id)kSecMatchLimit : (id)kSecMatchLimitAll,
147 (id)kSecReturnData : (id)kCFBooleanTrue,
148 (id)kSecReturnAttributes : (id)kCFBooleanTrue,
149 (id)kSecReturnPersistentRef : (id)kCFBooleanTrue,
150 (id)kSecClass : (id)kSecClassGenericPassword,
151 (id)kSecAttrAccessGroup : kAccessGroup,
152 (id)kSecAttrService : kService,
153 (id)kSecAttrNoLegacy : (id)kCFBooleanTrue,
154 (id)kSecAttrSynchronizable: (id)kCFBooleanTrue,
156 OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
157 if (status == errSecItemNotFound) {
160 if (status != errSecSuccess) {
161 printf("Error reading items to verify: %d\n", (int)status);
164 NSArray *arr = CFBridgingRelease(result);
166 NSMutableDictionary *items = [NSMutableDictionary dictionary];
167 for (NSDictionary *dict in arr) {
168 NSString *name = dict[(id)kSecAttrAccount];
169 NSData *data = dict[(id)kSecValueData];
170 NSData *ref = dict[(id)kSecValuePersistentRef];
171 NSString *value = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
173 printf("Item %s has data that is not valid UTF-8.\n", [name UTF8String]);
176 items[name] = @[ref, value];