]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/regressions/kc-30-xara-item-helpers.h
Security-57337.40.85.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / regressions / kc-30-xara-item-helpers.h
1 /*
2 * Copyright (c) 2015 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include "kc-30-xara-helpers.h"
25
26 #ifndef kc_30_xara_item_helpers_h
27 #define kc_30_xara_item_helpers_h
28
29 #if TARGET_OS_MAC
30
31 #pragma clang diagnostic push
32 #pragma clang diagnostic ignored "-Wunused-variable"
33 #pragma clang diagnostic ignored "-Wunused-function"
34
35
36 static CFMutableDictionaryRef makeBaseItemDictionary(CFStringRef itemclass) {
37 CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
38 CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
39 CFDictionarySetValue(query, kSecClass, itemclass);
40
41 if(CFEqual(itemclass, kSecClassInternetPassword)) {
42 CFDictionarySetValue(query, kSecAttrServer, CFSTR("test_service"));
43 CFDictionarySetValue(query, kSecAttrAuthenticationType, CFSTR("dflt")); // Default, I guess?
44 } else {
45 // Generic passwords have services
46 CFDictionarySetValue(query, kSecAttrService, CFSTR("test_service"));
47 }
48 return query;
49 }
50
51 static CFMutableDictionaryRef makeQueryItemDictionary(SecKeychainRef kc, CFStringRef itemclass) {
52 CFMutableDictionaryRef query = makeBaseItemDictionary(itemclass);
53
54 CFMutableArrayRef searchList = (CFMutableArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
55 CFArrayAppendValue((CFMutableArrayRef)searchList, kc);
56 CFDictionarySetValue(query, kSecMatchSearchList, searchList);
57
58 CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
59
60 return query;
61 }
62
63 static CFMutableDictionaryRef makeQueryCustomItemDictionary(SecKeychainRef kc, CFStringRef itemclass, CFStringRef label) {
64 CFMutableDictionaryRef query = makeQueryItemDictionary(kc, itemclass);
65 CFDictionarySetValue(query, kSecAttrLabel, label);
66 return query;
67 }
68
69 static CFMutableDictionaryRef makeAddCustomItemDictionary(SecKeychainRef kc, CFStringRef itemclass, CFStringRef label, CFStringRef account) {
70 CFMutableDictionaryRef query = makeBaseItemDictionary(itemclass);
71
72 CFDictionaryAddValue(query, kSecUseKeychain, kc);
73 CFDictionarySetValue(query, kSecAttrAccount, account);
74 CFDictionarySetValue(query, kSecAttrComment, CFSTR("a comment"));
75 CFDictionarySetValue(query, kSecAttrLabel, label);
76 CFDictionarySetValue(query, kSecValueData, CFDataCreate(NULL, (void*)"data", 4));
77 return query;
78 }
79
80 static CFMutableDictionaryRef makeAddItemDictionary(SecKeychainRef kc, CFStringRef itemclass, CFStringRef label) {
81 return makeAddCustomItemDictionary(kc, itemclass, label, CFSTR("test_account"));
82 }
83
84 static SecKeychainItemRef makeCustomItem(const char* name, SecKeychainRef kc, CFDictionaryRef addDictionary) {
85 CFTypeRef result = NULL;
86 ok_status(SecItemAdd(addDictionary, &result), "%s: SecItemAdd", name);
87 ok(result != NULL, "%s: SecItemAdd returned a result", name);
88
89 SecKeychainItemRef item = (SecKeychainItemRef) result;
90 ok(item != NULL, "%s: Couldn't convert into SecKeychainItemRef", name);
91
92 return item;
93 }
94 #define makeCustomItemTests 3
95
96 static SecKeychainItemRef makeItem(const char* name, SecKeychainRef kc, CFStringRef itemclass, CFStringRef label) {
97 CFMutableDictionaryRef query = makeAddItemDictionary(kc, itemclass, label);
98
99 SecKeychainItemRef item = makeCustomItem(name, kc, query);
100
101 CFReleaseNull(query);
102 return item;
103 }
104 #define makeItemTests makeCustomItemTests
105
106 static void makeCustomDuplicateItem(const char* name, SecKeychainRef kc, CFStringRef itemclass, CFStringRef label) {
107 CFMutableDictionaryRef query = makeAddItemDictionary(kc, itemclass, label);
108
109 CFTypeRef result = NULL;
110 is(SecItemAdd(query, &result), errSecDuplicateItem, "%s: SecItemAdd (duplicate)", name);
111
112 CFReleaseNull(query);
113 }
114 #define makeCustomDuplicateItemTests 1
115
116 static void makeDuplicateItem(const char* name, SecKeychainRef kc, CFStringRef itemclass) {
117 return makeCustomDuplicateItem(name, kc, itemclass, CFSTR("test_label"));
118 }
119 #define makeDuplicateItemTests makeCustomDuplicateItemTests
120
121 static void makeCustomItemWithIntegrity(const char* name, SecKeychainRef kc, CFStringRef itemclass, CFStringRef label, CFStringRef expectedHash) {
122 SecKeychainItemRef item = makeItem(name, kc, itemclass, label);
123 checkIntegrityHash(name, item, expectedHash);
124 CFReleaseNull(item);
125 }
126 #define makeCustomItemWithIntegrityTests (makeItemTests + checkIntegrityHashTests)
127
128 static void makeItemWithIntegrity(const char* name, SecKeychainRef kc, CFStringRef itemclass, CFStringRef expectedHash) {
129 makeCustomItemWithIntegrity(name, kc, itemclass, CFSTR("test_label"), expectedHash);
130 }
131 #define makeItemWithIntegrityTests (makeCustomItemWithIntegrityTests)
132
133 static void testAddItem(CFStringRef itemclass, CFStringRef expectedHash) {
134 char name[100];
135 sprintf(name, "testAddItem[%s]", CFStringGetCStringPtr(itemclass, kCFStringEncodingUTF8));
136 secdebugfunc("integrity", "************************************* %s", name);
137
138 SecKeychainRef kc = newKeychain(name);
139 makeItemWithIntegrity(name, kc, itemclass, expectedHash);
140
141 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
142 }
143 #define testAddItemTests (newKeychainTests + makeItemWithIntegrityTests + 1)
144
145 static void testCopyMatchingItem(CFStringRef itemclass, CFStringRef expectedHash) {
146 char name[100];
147 sprintf(name, "testCopyMatchingItem[%s]", CFStringGetCStringPtr(itemclass, kCFStringEncodingUTF8));
148 secdebugfunc("integrity", "************************************* %s", name);
149
150 SecKeychainRef kc = newKeychain(name);
151 makeItemWithIntegrity(name, kc, itemclass, expectedHash);
152
153 SecKeychainItemRef item = checkN(name, makeQueryItemDictionary(kc, itemclass), 1);
154 checkIntegrityHash(name, item, expectedHash);
155 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
156 }
157 #define testCopyMatchingItemTests (newKeychainTests + makeItemWithIntegrityTests + checkNTests + checkIntegrityHashTests + 1)
158
159 static void testUpdateItem(CFStringRef itemclass, CFStringRef expectedHashOrig, CFStringRef expectedHashAfter) {
160 char name[100];
161 sprintf(name, "testUpdateItem[%s]", CFStringGetCStringPtr(itemclass, kCFStringEncodingUTF8));
162 secdebugfunc("integrity", "************************************* %s", name);
163
164 SecKeychainRef kc = newKeychain(name);
165 makeItemWithIntegrity(name, kc, itemclass, expectedHashOrig);
166
167 CFMutableDictionaryRef query = makeQueryItemDictionary(kc, itemclass);
168 CFMutableDictionaryRef update = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
169 CFDictionarySetValue(update, kSecAttrComment, CFSTR("a modification"));
170 CFDictionarySetValue(update, kSecAttrAccount, CFSTR("a account modification"));
171 CFDictionarySetValue(update, kSecAttrLabel, CFSTR("a label modification"));
172 ok_status(SecItemUpdate(query, update), "%s: SecItemUpdate", name);
173
174 CFReleaseNull(update);
175
176 SecKeychainItemRef item = checkN(name, makeQueryItemDictionary(kc, itemclass), 1);
177 checkIntegrityHash(name, item, expectedHashAfter);
178 CFReleaseNull(item);
179
180 // Check that updating data works
181 update = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
182 CFDictionarySetValue(update, kSecValueData, CFDataCreate(NULL, (void*)"data", 4));
183 ok_status(SecItemUpdate(query, update), "%s: SecItemUpdate", name);
184
185 item = checkN(name, makeQueryItemDictionary(kc, itemclass), 1);
186 checkIntegrityHash(name, item, expectedHashAfter);
187
188 CFReleaseNull(query);
189 CFReleaseNull(update);
190
191 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
192 }
193 #define testUpdateItemTests (newKeychainTests + makeItemWithIntegrityTests \
194 + 1 + checkNTests + checkIntegrityHashTests \
195 + 1 + checkNTests + checkIntegrityHashTests \
196 + 1)
197
198 static void testAddDuplicateItem(CFStringRef itemclass, CFStringRef expectedHash) {
199 char name[100];
200 sprintf(name, "testAddDuplicateItem[%s]", CFStringGetCStringPtr(itemclass, kCFStringEncodingUTF8));
201 secdebugfunc("integrity", "************************************* %s", name);
202
203 SecKeychainRef kc = newKeychain(name);
204 makeItemWithIntegrity(name, kc, itemclass, expectedHash);
205
206 makeDuplicateItem(name, kc, itemclass);
207
208 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
209 }
210 #define testAddDuplicateItemTests (newKeychainTests + makeItemWithIntegrityTests + makeDuplicateItemTests + 1)
211
212 static void testDeleteItem(CFStringRef itemclass, CFStringRef expectedHash) {
213 char name[100];
214 sprintf(name, "testDeleteItem[%s]", CFStringGetCStringPtr(itemclass, kCFStringEncodingUTF8));
215 secdebugfunc("integrity", "************************************* %s", name);
216
217 SecKeychainRef kc = newKeychain(name);
218 makeItemWithIntegrity(name, kc, itemclass, expectedHash);
219
220 SecKeychainItemRef item = checkN(name, makeQueryItemDictionary(kc, itemclass), 1);
221 checkIntegrityHash(name, item, expectedHash);
222
223 ok_status(SecKeychainItemDelete(item), "%s: SecKeychainItemDelete", name);
224 checkN(name, makeQueryItemDictionary(kc, itemclass), 0);
225 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
226 }
227 #define testDeleteItemTests (newKeychainTests + makeItemWithIntegrityTests + checkNTests + checkIntegrityHashTests + 1 + checkNTests + 1)
228
229 static void writeEmptyV512Keychain(const char* name, const char* keychainFile);
230
231 // This test is to find <rdar://problem/23515265> CrashTracer: accountsd at …curity: Security::KeychainCore::CCallbackMgr::consume + 387
232 //
233 // The issue was that items could remain in the Keychain cache, even after the
234 // actual object was freed. The main path involved updating an item so that it
235 // had the same primary key as an item which was in the cache but not in the
236 // database (this could be caused by another process deleting the item and us
237 // not receiving the notification).
238 //
239 // This test should pass. Failure is shown by crashing.
240 //
241 static void testUpdateRetainedItem(CFStringRef itemclass) {
242 char name[100];
243 sprintf(name, "testUpdateRetainedItem[%s]", CFStringGetCStringPtr(itemclass, kCFStringEncodingUTF8));
244 secdebugfunc("integrity", "************************************* %s", name);
245
246 writeEmptyV512Keychain(name, keychainFile);
247 SecKeychainRef kc = openCustomKeychain(name, "test.keychain", "password");
248
249 SecKeychainItemRef item = makeCustomItem(name, kc, makeAddCustomItemDictionary(kc, itemclass, CFSTR("test_label"), CFSTR("account1")));
250
251 CFRelease(checkN(name, makeQueryCustomItemDictionary(kc, itemclass, CFSTR("test_label")), 1));
252
253 is(CFGetRetainCount(item), 1, "%s: CFGetRetainCount(item)", name);
254
255 // Bump our local database version number a few times, so we'll re-read the database when we reset it later
256 CFReleaseSafe(makeCustomItem(name, kc, makeAddCustomItemDictionary(kc, itemclass, CFSTR("version"), CFSTR("version"))));
257 CFReleaseSafe(makeCustomItem(name, kc, makeAddCustomItemDictionary(kc, itemclass, CFSTR("bump"), CFSTR("bump"))));
258
259 // Simulate another process deleting the items we just made, and us not receiving the notification
260 writeEmptyV512Keychain(name, keychainFile);
261
262 // Generate some keychain notifications on a different keychain so the AppleDatabase will reload test.keychain
263 SecKeychainRef kc2 = newCustomKeychain(name, "unrelated.keychain", "password");
264 CFReleaseSafe(makeCustomItem(name, kc2, makeAddCustomItemDictionary(kc, itemclass, CFSTR("unrelated1_label"), CFSTR("unrelated1"))));
265 ok_status(SecKeychainDelete(kc2), "%s: SecKeychainDelete", name);
266
267 secdebugfunc("integrity", "************************************* should reload database\n");
268
269 SecKeychainItemRef item2 = makeCustomItem(name, kc, makeAddCustomItemDictionary(kc, itemclass, CFSTR("not_a_test_label"), CFSTR("account2")));
270 CFReleaseSafe(checkN(name, makeQueryCustomItemDictionary(kc, itemclass, CFSTR("not_a_test_label")), 1));
271 is(CFGetRetainCount(item2), 1, "%s: CFGetRetainCount(item2)", name);
272
273 // Now, update the second item so it would collide with the first
274 CFMutableDictionaryRef query = makeQueryCustomItemDictionary(kc, itemclass, CFSTR("not_a_test_label"));
275 CFMutableDictionaryRef update = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
276 CFDictionarySetValue(update, kSecAttrAccount, CFSTR("account1"));
277 CFDictionarySetValue(update, kSecAttrLabel, CFSTR("test_label"));
278 ok_status(SecItemUpdate(query, update), "%s: SecItemUpdate", name);
279
280 is(CFGetRetainCount(item), 1, "%s: CFGetRetainCount(item)", name);
281 CFReleaseNull(item);
282
283 SecKeychainItemRef result = checkN(name, makeQueryCustomItemDictionary(kc, itemclass, CFSTR("test_label")), 1);
284 CFReleaseNull(result);
285 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
286 }
287 #define testUpdateRetainedItemTests (openCustomKeychainTests + makeCustomItemTests + checkNTests \
288 + 1 + makeCustomItemTests + makeCustomItemTests \
289 + newCustomKeychainTests + makeCustomItemTests + 1 \
290 + makeCustomItemTests + checkNTests + 1 \
291 + 1 + 1 + checkNTests + 1)
292
293 #pragma clang pop
294 #else
295
296 #endif /* TARGET_OS_MAC */
297
298
299 #endif /* kc_30_xara_item_helpers_h */