]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/regressions/kc-30-xara.c
Security-58286.200.222.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / regressions / kc-30-xara.c
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 "keychain_regressions.h"
25
26 #include <CoreFoundation/CoreFoundation.h>
27 #include <Security/Security.h>
28 #include <Security/SecBase.h>
29 #include <Security/SecBasePriv.h>
30 #include <Security/SecKeychainPriv.h>
31 #include <TargetConditionals.h>
32 #include <Security/cssmapi.h>
33 #include <stdlib.h>
34 #include <sys/stat.h>
35 #include <copyfile.h>
36 #include <unistd.h>
37
38 #include "kc-30-xara-item-helpers.h"
39 #include "kc-30-xara-key-helpers.h"
40 #include "kc-30-xara-upgrade-helpers.h"
41
42 #if TARGET_OS_MAC
43
44 #pragma clang diagnostic push
45 #pragma clang diagnostic ignored "-Wunused-variable"
46 #pragma clang diagnostic ignored "-Wunused-function"
47
48 /* Test basic add delete update copy matching stuff. */
49
50
51 /* Standard memory functions required by CSSM. */
52 static void *cssmMalloc(CSSM_SIZE size, void *allocRef) { return malloc(size); }
53 static void cssmFree(void *mem_ptr, void *allocRef) { free(mem_ptr); return; }
54 static void *cssmRealloc(void *ptr, CSSM_SIZE size, void *allocRef) { return realloc( ptr, size ); }
55 static void *cssmCalloc(uint32 num, CSSM_SIZE size, void *allocRef) { return calloc( num, size ); }
56 static CSSM_API_MEMORY_FUNCS memFuncs = { cssmMalloc, cssmFree, cssmRealloc, cssmCalloc, NULL };
57
58 static CSSM_DL_DB_HANDLE initializeDL() {
59 CSSM_VERSION version = { 2, 0 };
60 CSSM_DL_DB_HANDLE dldbHandle = { 0, 0 };
61 CSSM_GUID myGuid = { 0xFADE, 0, 0, { 1, 2, 3, 4, 5, 6, 7, 0 } };
62 CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
63
64 ok_status(CSSM_Init(&version, CSSM_PRIVILEGE_SCOPE_NONE, &myGuid, CSSM_KEY_HIERARCHY_NONE, &pvcPolicy, NULL), "cssm_init");
65 ok_status(CSSM_ModuleLoad(&gGuidAppleFileDL, CSSM_KEY_HIERARCHY_NONE, NULL, NULL), "module_load");
66 ok_status(CSSM_ModuleAttach(&gGuidAppleFileDL, &version, &memFuncs, 0, CSSM_SERVICE_DL, 0, CSSM_KEY_HIERARCHY_NONE, NULL, 0, NULL, &dldbHandle.DLHandle), "module_attach");
67
68 return dldbHandle;
69 }
70 #define initializeDLTests 3
71
72 static void unloadDL(CSSM_DL_DB_HANDLE* dldbHandle) {
73 ok_status(CSSM_ModuleDetach(dldbHandle->DLHandle), "detach");
74 ok_status(CSSM_ModuleUnload(&gGuidAppleFileDL, NULL, NULL), "unload");
75 ok_status(CSSM_Terminate(), "terminate");
76 }
77 #define unloadDLTests 3
78
79 static void modifyAttributeInKeychain(char * name, CSSM_DL_DB_HANDLE dldbHandle, char * keychainName, CSSM_DB_RECORDTYPE recordType, char* attributeName, char* newValue, size_t len) {
80 CSSM_RETURN status = CSSM_OK;
81 ok_status(CSSM_DL_DbOpen(dldbHandle.DLHandle, keychainName,
82 NULL,
83 CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
84 NULL, /* Access cred? */
85 NULL, /* Open Parameters? */
86 &dldbHandle.DBHandle), "%s: CSSM_DL_DbOpen", name);
87
88 CSSM_QUERY queryAll = {};
89 queryAll.RecordType = recordType;
90
91 CSSM_HANDLE results = 0;
92 CSSM_DATA data = {};
93 CSSM_DB_UNIQUE_RECORD_PTR uniqueIdPtr = NULL;
94
95 CSSM_DB_RECORD_ATTRIBUTE_DATA attributes = {};
96 attributes.NumberOfAttributes = 1;
97 attributes.AttributeData = malloc(sizeof(CSSM_DB_ATTRIBUTE_DATA) * attributes.NumberOfAttributes);
98 attributes.AttributeData[0].Info.Label.AttributeName = attributeName;
99 attributes.AttributeData[0].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
100
101 attributes.AttributeData[0].NumberOfValues = 1;
102 attributes.AttributeData[0].Value = malloc(sizeof(CSSM_DATA)*attributes.AttributeData[0].NumberOfValues);
103
104
105 status = CSSM_DL_DataGetFirst(dldbHandle, &queryAll, &results, &attributes, &data, &uniqueIdPtr);
106 while(status == CSSM_OK) {
107 // I'm sure it has one thing and that thing needs to change.
108 attributes.AttributeData[0].Value[0].Data = (void*)newValue;
109 attributes.AttributeData[0].Value[0].Length = strlen(newValue);
110
111 CSSM_DL_DataModify(dldbHandle,
112 attributes.DataRecordType,
113 uniqueIdPtr,
114 &attributes,
115 NULL, // no data modification
116 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
117
118 CSSM_DL_FreeUniqueRecord(dldbHandle, uniqueIdPtr);
119 status = CSSM_DL_DataGetNext(dldbHandle, results, &attributes, &data, &uniqueIdPtr);
120 }
121 ok_status(CSSM_DL_DbClose(dldbHandle), "%s: CSSM_DL_DbClose", name);
122 }
123 #define modifyAttributeInKeychainTests 2
124
125 static void testAttackItem(CSSM_DL_DB_HANDLE dldbHandle) {
126 char * name = "testAttackItem";
127 secnotice("integrity", "************************************* %s", name);
128
129 SecKeychainRef kc = newKeychain(name);
130 checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 0);
131
132 makeItemWithIntegrity(name, kc, kSecClassGenericPassword, CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
133 SecKeychainItemRef item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
134 CFReleaseNull(item);
135 CFReleaseNull(kc);
136
137 char * modification = "evil_application";
138 modifyAttributeInKeychain(name, dldbHandle, keychainDbFile, CSSM_DL_DB_RECORD_GENERIC_PASSWORD, "PrintName", modification, strlen(modification));
139
140 kc = openKeychain(name);
141 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
142 readPasswordContentsWithResult(item, errSecInvalidItemRef, NULL);
143
144 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
145 CFReleaseNull(kc);
146 }
147 #define testAttackItemTests (newKeychainTests + checkNTests + makeItemWithIntegrityTests + checkNTests + modifyAttributeInKeychainTests + openKeychainTests + checkNTests + readPasswordContentsWithResultTests + 1)
148
149 static void testAttackKey(CSSM_DL_DB_HANDLE dldbHandle) {
150 char * name = "testAttackKey";
151 secnotice("integrity", "************************************* %s", name);
152
153 SecKeychainRef kc = newKeychain(name);
154 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
155
156 makeKeyWithIntegrity(name, kc, CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
157 SecKeychainItemRef item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
158
159 checkKeyUse((SecKeyRef) item, errSecSuccess);
160
161 CFReleaseNull(item);
162 CFReleaseNull(kc);
163
164 char * modification = "evil_application";
165 modifyAttributeInKeychain(name, dldbHandle, keychainDbFile, CSSM_DL_DB_RECORD_SYMMETRIC_KEY, "Label", modification, strlen(modification));
166
167 kc = openKeychain(name);
168 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
169 checkKeyUse((SecKeyRef) item, errSecInvalidItemRef);
170 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
171 CFReleaseNull(kc);
172 }
173 #define testAttackKeyTests (newKeychainTests + checkNTests + makeKeyWithIntegrityTests + checkNTests + checkKeyUseTests + modifyAttributeInKeychainTests \
174 + openKeychainTests + checkNTests + checkKeyUseTests + 1)
175
176
177 static void testAddAfterCorruptItem(CSSM_DL_DB_HANDLE dldbHandle) {
178 char * name = "testAddAfterCorruptItem";
179 secnotice("integrity", "************************************* %s", name);
180
181 SecKeychainRef kc = newKeychain(name);
182 checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 0);
183
184 makeCustomItemWithIntegrity(name, kc, kSecClassGenericPassword, CFSTR("test_label"), CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
185 checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
186
187 makeDuplicateItem(name, kc, kSecClassGenericPassword);
188 CFReleaseNull(kc);
189
190 char * modification = "evil_application";
191 modifyAttributeInKeychain(name, dldbHandle, keychainDbFile, CSSM_DL_DB_RECORD_GENERIC_PASSWORD, "PrintName", modification, strlen(modification));
192
193 kc = openKeychain(name);
194 SecKeychainItemRef item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
195 deleteItem(item);
196 checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 0);
197
198 makeCustomItemWithIntegrity(name, kc, kSecClassGenericPassword, CFSTR("evil_application"), CFSTR("d2aa97b30a1f96f9e61fcade2b00d9f4284976a83a5b68392251ee5ec827f8cc"));
199 checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
200 makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("evil_application"));
201 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
202 CFReleaseNull(kc);
203 }
204 #define testAddAfterCorruptItemTests (newKeychainTests + checkNTests + makeCustomItemWithIntegrityTests + checkNTests + makeDuplicateItemTests \
205 + modifyAttributeInKeychainTests + openKeychainTests + checkNTests + deleteItemTests \
206 + checkNTests + makeCustomItemWithIntegrityTests + checkNTests + makeCustomDuplicateItemTests + 1)
207
208 static void testAddAfterCorruptKey(CSSM_DL_DB_HANDLE dldbHandle) {
209 char * name = "testAddAfterCorruptKey";
210 secnotice("integrity", "************************************* %s", name);
211
212 SecKeychainRef kc = newKeychain(name);
213 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
214 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 0);
215 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 0);
216
217 // Make a symmetric key
218 makeCustomKeyWithIntegrity(name, kc, CFSTR("test_key"), CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
219
220 SecKeychainItemRef item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
221 makeCustomDuplicateKey(name, kc, CFSTR("test_key"));
222 CFReleaseNull(item);
223
224 // Make a key pair
225 SecKeyRef pub;
226 SecKeyRef priv;
227 makeCustomKeyPair(name, kc, CFSTR("test_key_pair"), &pub, &priv);
228 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
229 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
230 CFReleaseNull(pub);
231 CFReleaseNull(priv);
232
233 ok_status(SecKeychainListRemoveKeychain(&kc), "%s: SecKeychainListRemoveKeychain", name);
234
235 char * modification = "evil_application";
236 modifyAttributeInKeychain(name, dldbHandle, keychainDbFile, CSSM_DL_DB_RECORD_SYMMETRIC_KEY, "PrintName", modification, strlen(modification));
237 modifyAttributeInKeychain(name, dldbHandle, keychainDbFile, CSSM_DL_DB_RECORD_PUBLIC_KEY, "PrintName", modification, strlen(modification));
238 modifyAttributeInKeychain(name, dldbHandle, keychainDbFile, CSSM_DL_DB_RECORD_PRIVATE_KEY, "PrintName", modification, strlen(modification));
239
240 kc = openKeychain(name);
241
242 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
243 deleteItem(item);
244 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
245
246 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
247 deleteItem(item);
248 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 0);
249
250 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
251 deleteItem(item);
252 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 0);
253
254 makeCustomKeyWithIntegrity(name, kc, CFSTR("evil_application"), CFSTR("ca6d90a0b053113e43bbb67f64030230c96537f77601f66bdf821d8684431dfc"));
255 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
256
257 makeCustomDuplicateKey(name, kc, CFSTR("evil_application"));
258
259 makeCustomKeyPair(name, kc, CFSTR("evil_application"), &pub, &priv);
260 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
261 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
262
263 // We cannot create a duplicate key pair, so don't try.
264
265 CFReleaseNull(item);
266 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
267 CFReleaseNull(kc);
268 }
269 #define testAddAfterCorruptKeyTests (newKeychainTests \
270 + checkNTests + checkNTests + checkNTests \
271 + makeCustomKeyWithIntegrityTests + checkNTests + makeCustomDuplicateKeyTests \
272 + makeCustomKeyPairTests + checkNTests + checkNTests \
273 + 1 \
274 + modifyAttributeInKeychainTests \
275 + modifyAttributeInKeychainTests \
276 + modifyAttributeInKeychainTests \
277 + openKeychainTests \
278 + checkNTests + deleteItemTests + checkNTests \
279 + checkNTests + deleteItemTests + checkNTests \
280 + checkNTests + deleteItemTests + checkNTests \
281 + makeCustomKeyWithIntegrityTests + checkNTests \
282 + makeCustomDuplicateKeyTests \
283 + makeCustomKeyPairTests + checkNTests + checkNTests \
284 + 1)
285
286
287 // These constants are in CommonBlob, but we're in C and can't access them
288 #define version_MacOS_10_0 0x00000100
289 #define version_partition 0x00000200
290
291 static void testKeychainUpgrade() {
292 char name[100];
293 sprintf(name, "testKeychainUpgrade");
294 secnotice("integrity", "************************************* %s", name);
295 UInt32 version;
296 char* path = malloc(sizeof(char) * 400);
297 UInt32 len = 400;
298
299 // To test multi-threading, we want the upgrade to take a while. Add a bunch of passwords...
300 char oldkcFile[MAXPATHLEN];
301 snprintf(oldkcFile, sizeof(oldkcFile), "%s/Library/test.keychain", getenv("HOME"));
302 unlink(oldkcFile);
303 writeOldKeychain(name, oldkcFile);
304
305 SecKeychainRef kc = openCustomKeychain(name, oldkcFile, "password");
306
307 for(int i = 0; i < 200; i++) {
308 CFTypeRef result = NULL;
309 CFStringRef cflabel = CFStringCreateWithFormat(NULL, NULL, CFSTR("item%d"), i);
310 CFMutableDictionaryRef query = createAddCustomItemDictionaryWithService(kc, kSecClassInternetPassword, cflabel, cflabel, CFSTR("no service"));
311 SecItemAdd(query, &result); // don't particuluarly care if this fails...
312 CFReleaseNull(query);
313 CFReleaseNull(cflabel);
314 CFReleaseNull(result);
315 }
316
317 CFReleaseNull(kc);
318
319 ok_status(copyfile(oldkcFile, keychainFile, NULL, COPYFILE_UNLINK | COPYFILE_ALL), "%s: copyfile", name);
320 unlink(oldkcFile);
321 unlink(keychainDbFile);
322
323 static dispatch_once_t onceToken = 0;
324 static dispatch_queue_t release_queue = NULL;
325 dispatch_once(&onceToken, ^{
326 release_queue = dispatch_queue_create("com.apple.security.keychain-upgrade-queue", DISPATCH_QUEUE_CONCURRENT);
327 });
328
329 dispatch_group_t g = dispatch_group_create();
330 SecKeychainItemRef item;
331
332 char* __block blockName = NULL;
333 asprintf(&blockName, "%s", name);
334
335 kc = openCustomKeychain(name, keychainName, "password");
336
337 // Directly after an upgrade, no items should have partition ID lists
338 dispatch_group_async(g, release_queue, ^() {
339 secerror("beginning 1\n");
340 SecKeychainRef blockKc;
341 SecKeychainOpen(keychainName, &blockKc);
342 SecKeychainItemRef item = checkNCopyFirst(blockName, createQueryItemDictionary(blockKc, kSecClassGenericPassword), 1);
343 checkIntegrityHash(blockName, item, CFSTR("39c56eadd3e3b496b6099e5f3d5ff88eaee9ca2e3a50c1be8319807a72e451e5"));
344 checkPartitionIDs(blockName, item, 0);
345 CFReleaseSafe(blockKc);
346 CFReleaseSafe(item);
347 secerror("ending 1\n");
348 });
349
350 dispatch_group_async(g, release_queue, ^() {
351 usleep(0.1 * USEC_PER_SEC); // use different timings to try to find multithreaded upgrade bugs
352 secerror("beginning 2\n");
353 SecKeychainRef blockKc;
354 SecKeychainOpen(keychainName, &blockKc);
355 SecKeychainItemRef item = checkNCopyFirst(blockName, createQueryItemDictionaryWithService(blockKc, kSecClassInternetPassword, CFSTR("test_service")), 1);
356 checkIntegrityHash(blockName, item, CFSTR("4f1b64e3c156968916e72d8ff3f1a8eb78b32abe0b2b43f0578eb07c722aaf03"));
357 checkPartitionIDs(blockName, item, 0);
358 CFReleaseSafe(blockKc);
359 CFReleaseSafe(item);
360 secerror("ending 2\n");
361 });
362
363 dispatch_group_async(g, release_queue, ^() {
364 usleep(0.3 * USEC_PER_SEC);
365 secerror("beginning 3\n");
366 SecKeychainRef blockKc;
367 SecKeychainOpen(keychainName, &blockKc);
368 SecKeychainItemRef item = checkNCopyFirst(blockName, createQueryKeyDictionary(blockKc, kSecAttrKeyClassSymmetric), 1);
369 checkIntegrityHash(blockName, (SecKeychainItemRef) item, CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
370 checkPartitionIDs(blockName, (SecKeychainItemRef) item, 0);
371 CFReleaseSafe(blockKc);
372 CFReleaseSafe(item);
373 secerror("ending 3\n");
374 });
375
376 dispatch_group_async(g, release_queue, ^() {
377 usleep(0.5 * USEC_PER_SEC);
378 secerror("beginning 4\n");
379 SecKeychainRef blockKc;
380 SecKeychainOpen(keychainName, &blockKc);
381 SecKeychainItemRef item = checkNCopyFirst(blockName, createQueryKeyDictionary(blockKc, kSecAttrKeyClassPublic), 1);
382 checkIntegrityHash(blockName, (SecKeychainItemRef) item, CFSTR("42d29fd5e9935edffcf6d0261eabddb00782ec775caa93716119e8e553ab5578"));
383 checkPartitionIDs(blockName, (SecKeychainItemRef) item, 0);
384 CFReleaseSafe(blockKc);
385 CFReleaseSafe(item);
386 secerror("ending 4\n");
387 });
388
389 dispatch_group_async(g, release_queue, ^() {
390 usleep(1 * USEC_PER_SEC);
391 secerror("beginning 5\n");
392 SecKeychainRef blockKc;
393 SecKeychainOpen(keychainName, &blockKc);
394 SecKeychainItemRef item = checkNCopyFirst(blockName, createQueryKeyDictionary(blockKc, kSecAttrKeyClassPrivate), 1);
395 checkIntegrityHash(blockName, (SecKeychainItemRef) item, CFSTR("bdf219cdbc2dc6c4521cf39d1beda2e3491ef0330ba59eb41229dd909632f48d"));
396 checkPartitionIDs(blockName, (SecKeychainItemRef) item, 0);
397 CFReleaseSafe(blockKc);
398 CFReleaseSafe(item);
399 secerror("ending 5\n");
400 });
401
402 dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
403
404 // @@@ I'm worried that there are still some thread issues in AppleDatabase; if these are run in the blocks above
405 // you can sometimes get CSSMERR_DL_INVALID_RECORD_UID/errSecInvalidRecord instead of errSecDuplicateItem
406 // <rdar://problem/27085024> Multi-threading duplicate item creation sometimes returns -67701
407 makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
408 makeCustomDuplicateItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
409
410 // Check the keychain's version and path
411 ok_status(SecKeychainGetKeychainVersion(kc, &version), "%s: SecKeychainGetKeychainVersion", name);
412 is(version, version_partition, "%s: version of upgraded keychain is incorrect", name);
413 ok_status(SecKeychainGetPath(kc, &len, path), "%s: SecKeychainGetKeychainPath", name);
414 eq_stringn(path, len, keychainDbFile, strlen(keychainDbFile), "%s: paths do not match", name);
415 free(path);
416
417 // Now close the keychain and open it again
418 CFReleaseNull(kc);
419 kc = openCustomKeychain(name, keychainName, "password");
420
421 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
422 checkIntegrityHash(name, item, CFSTR("39c56eadd3e3b496b6099e5f3d5ff88eaee9ca2e3a50c1be8319807a72e451e5"));
423 checkPartitionIDs(name, item, 0);
424 makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
425
426 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
427 checkIntegrityHash(name, item, CFSTR("4f1b64e3c156968916e72d8ff3f1a8eb78b32abe0b2b43f0578eb07c722aaf03"));
428 checkPartitionIDs(name, item, 0);
429 makeCustomDuplicateItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
430
431 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
432 checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
433 checkPartitionIDs(name, (SecKeychainItemRef) item, 0);
434
435 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
436 checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("42d29fd5e9935edffcf6d0261eabddb00782ec775caa93716119e8e553ab5578"));
437 checkPartitionIDs(name, (SecKeychainItemRef) item, 0);
438
439 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
440 checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("bdf219cdbc2dc6c4521cf39d1beda2e3491ef0330ba59eb41229dd909632f48d"));
441 checkPartitionIDs(name, (SecKeychainItemRef) item, 0);
442
443 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
444 CFReleaseNull(kc);
445
446 // make sure we clean up any files left over
447 unlink(keychainDbFile);
448 unlink(keychainFile);
449 unlink(oldkcFile);
450 }
451 #define testKeychainUpgradeTests (openCustomKeychainTests + 1 + openCustomKeychainTests + 4 \
452 + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests + makeCustomDuplicateItemTests \
453 + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests + makeCustomDuplicateItemTests \
454 + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests \
455 + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests \
456 + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests \
457 + openCustomKeychainTests \
458 + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests + makeCustomDuplicateItemTests \
459 + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests + makeCustomDuplicateItemTests \
460 + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests \
461 + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests \
462 + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests \
463 + 1)
464
465 // tests that SecKeychainCreate over an old .keychain file returns an empty keychain
466 static void testKeychainCreateOver() {
467 char name[100];
468 sprintf(name, "testKeychainCreateOver");
469 secnotice("integrity", "************************************* %s", name);
470 UInt32 version;
471 char* path = malloc(sizeof(char) * 400);
472 UInt32 len = 400;
473
474 writeOldKeychain(name, keychainFile);
475 unlink(keychainDbFile);
476
477 SecKeychainItemRef item = NULL;
478
479 // Check that we upgrade on SecKeychainOpen
480 SecKeychainRef kc = openCustomKeychain(name, keychainName, "password");
481
482 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
483 checkIntegrityHash(name, item, CFSTR("39c56eadd3e3b496b6099e5f3d5ff88eaee9ca2e3a50c1be8319807a72e451e5"));
484 CFReleaseNull(item);
485
486 ok_status(SecKeychainDelete(kc));
487 CFReleaseNull(kc);
488
489 // the old file should still exist, but the -db file should not.
490 struct stat filebuf;
491 is(stat(keychainFile, &filebuf), 0, "%s: check %s exists", name, keychainFile);
492 isnt(stat(keychainDbFile, &filebuf), 0, "%s: check %s does not exist", name, keychainDbFile);
493
494 // Now create a new keychain over the old remnants.
495 ok_status(SecKeychainCreate(keychainFile, (UInt32) strlen("password"), "password", false, NULL, &kc), "%s: SecKeychainCreate", name);
496
497 // Directly after creating a keychain, there shouldn't be any items (even though an old keychain exists underneath)
498 checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 0);
499 checkN(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 0);
500 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
501 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 0);
502 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 0);
503
504 // Check the keychain's version and path
505 ok_status(SecKeychainGetKeychainVersion(kc, &version), "%s: SecKeychainGetKeychainVersion", name);
506 is(version, version_partition, "%s: version of upgraded keychain is incorrect", name);
507 ok_status(SecKeychainGetPath(kc, &len, path), "%s: SecKeychainGetKeychainPath", name);
508 eq_stringn(path, len, keychainDbFile, strlen(keychainDbFile), "%s: paths do not match", name);
509 free(path);
510
511 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
512 CFReleaseNull(kc);
513
514 // final check that the files on-disk are as we expect
515 is(stat(keychainFile, &filebuf), 0, "%s: check %s exists", name, keychainFile);
516 isnt(stat(keychainDbFile, &filebuf), 0, "%s: check %s does not exist", name, keychainDbFile);
517
518 // make sure we clean up any files left over
519 unlink(keychainDbFile);
520 unlink(keychainFile);
521 }
522 #define testKeychainCreateOverTests (openCustomKeychainTests + \
523 + checkNTests + checkIntegrityHashTests \
524 + 1 + 2 + 1 \
525 + checkNTests \
526 + checkNTests \
527 + checkNTests \
528 + checkNTests \
529 + checkNTests \
530 + 4 + 1 + 2)
531
532 static void testKeychainDowngrade() {
533 char *name = "testKeychainDowngrade";
534 secnotice("integrity", "************************************* %s", name);
535
536 // For now, don't worry about filenames
537 writeFullV512Keychain(name, keychainDbFile);
538 unlink(keychainFile);
539 writeFullV512Keyfile(name, keychainTempFile);
540
541 SecKeychainRef kc = openCustomKeychain(name, keychainName, "password");
542 UInt32 version;
543
544 ok_status(SecKeychainGetKeychainVersion(kc, &version), "%s: SecKeychainGetKeychainVersion", name);
545 is(version, version_partition, "%s: version of initial keychain is incorrect", name);
546
547 SecKeychainItemRef item;
548
549 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
550 checkIntegrityHash(name, item, CFSTR("6ba8d9f77ddba54d9373b11ae5c8f7b55a5e81da27e05e86723eeceb0a9a8e0c"));
551 makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
552
553 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
554 checkIntegrityHash(name, item, CFSTR("630a9fe4f0191db8a99d6e8455e7114f628ce8f0f9eb3559efa572a98877a2b2"));
555 makeCustomDuplicateItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
556
557 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
558 checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
559
560 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
561 checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("d27ee2be4920d5b6f47f6b19696d09c9a6c1a5d80c6f148f778db27b4ba99d9a"));
562
563 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
564 checkIntegrityHash(name, (SecKeychainItemRef) item, CFSTR("4b3f7bd7f9e48dc71006ce670990aed9dba6d5089b84d4113121bab41d0a3228"));
565
566
567
568 ok_status(SecKeychainAttemptMigrationWithMasterKey(kc, version_MacOS_10_0, keychainTempFile), "%s: SecKeychainAttemptKeychainMigrationWithMasterKey", name);
569 ok_status(SecKeychainGetKeychainVersion(kc, &version), "%s: SecKeychainGetKeychainVersion", name);
570 is(version, version_MacOS_10_0, "%s: version of downgraded keychain is incorrect", name);
571
572 checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
573 makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
574 checkN(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
575 makeCustomDuplicateItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
576
577 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
578 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
579 checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
580
581 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
582 CFReleaseNull(kc);
583
584 // make sure we clean up
585 unlink(keychainTempFile);
586 unlink(keychainDbFile);
587 unlink(keychainFile);
588 }
589 #define testKeychainDowngradeTests (openCustomKeychainTests + 2 \
590 + checkNTests + checkIntegrityHashTests + makeCustomDuplicateItemTests \
591 + checkNTests + checkIntegrityHashTests + makeCustomDuplicateItemTests \
592 + checkNTests + checkIntegrityHashTests +\
593 + checkNTests + checkIntegrityHashTests +\
594 + checkNTests + checkIntegrityHashTests +\
595 + 3 + \
596 + checkNTests + makeCustomDuplicateItemTests \
597 + checkNTests + makeCustomDuplicateItemTests \
598 + checkNTests \
599 + checkNTests \
600 + checkNTests \
601 + 1)\
602
603 // Test opening and upgrading a v256 keychain at a -db filename.
604 static void testKeychainWrongFile256() {
605 char name[100];
606 sprintf(name, "testKeychainWrongFile256");
607 secnotice("integrity", "************************************* %s", name);
608 UInt32 version;
609
610 unlink(keychainFile);
611 writeOldKeychain(name, keychainDbFile);
612
613 // Only keychainDb file should exist
614 struct stat filebuf;
615 isnt(stat(keychainFile, &filebuf), 0, "%s: %s exists and shouldn't", name, keychainFile);
616 is(stat(keychainDbFile, &filebuf), 0, "%s: %s does not exist", name, keychainDbFile);
617
618 SecKeychainRef kc = openCustomKeychain(name, keychainName, "password");
619
620 SecKeychainItemRef item;
621
622 // Iterate over the keychain to trigger upgrade
623 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
624 makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
625
626 // We should have created keychainFile, check for it
627 is(stat(keychainFile, &filebuf), 0, "%s: %s does not exist", name, keychainFile);
628 is(stat(keychainDbFile, &filebuf), 0, "%s: %s does not exist", name, keychainDbFile);
629
630 // Check the keychain's version and path
631 char path[400];
632 UInt32 len = sizeof(path);
633
634 ok_status(SecKeychainGetKeychainVersion(kc, &version), "%s: SecKeychainGetKeychainVersion", name);
635 is(version, version_partition, "%s: version of re-upgraded keychain is incorrect", name);
636 ok_status(SecKeychainGetPath(kc, &len, path), "%s: SecKeychainGetPath", name);
637 eq_stringn(path, len, keychainDbFile, strlen(keychainDbFile), "%s: paths do not match", name);
638
639 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
640 makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
641
642 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
643 makeCustomDuplicateItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
644
645 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
646 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
647 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
648
649 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
650 CFReleaseNull(kc);
651
652 // make sure we clean up any files left over
653 unlink(keychainDbFile);
654 unlink(keychainFile);
655 }
656 #define testKeychainWrongFile256Tests (2 + openCustomKeychainTests \
657 + checkNTests + makeCustomDuplicateItemTests \
658 + 2 + 4 \
659 + checkNTests + makeCustomDuplicateItemTests \
660 + checkNTests + makeCustomDuplicateItemTests \
661 + checkNTests \
662 + checkNTests \
663 + checkNTests \
664 + 1)
665
666 // Test opening and upgrading a v512 keychain at a .keychain filename.
667 static void testKeychainWrongFile512() {
668 char name[100];
669 sprintf(name, "testKeychainWrongFile512");
670 secnotice("integrity", "************************************* %s", name);
671 UInt32 version;
672
673 writeFullV512Keychain(name, keychainFile);
674 unlink(keychainDbFile);
675
676 // Only keychain file should exist
677 struct stat filebuf;
678 isnt(stat(keychainDbFile, &filebuf), 0, "%s: %s exists and shouldn't", name, keychainFile);
679 is(stat(keychainFile, &filebuf), 0, "%s: %s does not exist", name, keychainDbFile);
680
681 SecKeychainRef kc = openCustomKeychain(name, keychainName, "password");
682
683 SecKeychainItemRef item;
684
685 // Iterate over the keychain to trigger upgrade
686 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
687 makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
688
689 // We should have move the keychain to keychainDbFile, check for it
690 isnt(stat(keychainFile, &filebuf), 0, "%s: %s still exists", name, keychainFile);
691 is(stat(keychainDbFile, &filebuf), 0, "%s: %s does not exist", name, keychainDbFile);
692
693 // Check the keychain's version and path
694 char path[400];
695 UInt32 len = sizeof(path);
696
697 ok_status(SecKeychainGetKeychainVersion(kc, &version), "%s: SecKeychainGetKeychainVersion", name);
698 is(version, version_partition, "%s: version of moved keychain is incorrect", name);
699 ok_status(SecKeychainGetPath(kc, &len, path), "%s: SecKeychainGetPath", name);
700 eq_stringn(path, len, keychainDbFile, strlen(keychainDbFile), "%s: paths do not match", name);
701
702 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
703 makeCustomDuplicateItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
704
705 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
706 makeCustomDuplicateItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
707
708 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
709 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
710 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
711
712 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
713 CFReleaseNull(kc);
714
715 // make sure we clean up any files left over
716 unlink(keychainDbFile);
717 unlink(keychainFile);
718 }
719 #define testKeychainWrongFile512Tests (2 + openCustomKeychainTests \
720 + checkNTests + makeCustomDuplicateItemTests \
721 + 2 + 4 \
722 + checkNTests + makeCustomDuplicateItemTests \
723 + checkNTests + makeCustomDuplicateItemTests \
724 + checkNTests \
725 + checkNTests \
726 + checkNTests \
727 + 1)
728
729
730 #undef version_partition
731 #undef version_MacOS_10_0
732
733 static SecAccessRef makeUidAccess(uid_t uid)
734 {
735 // make the "uid/gid" ACL subject
736 // this is a CSSM_LIST_ELEMENT chain
737 CSSM_ACL_PROCESS_SUBJECT_SELECTOR selector = {
738 CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION, // selector version
739 CSSM_ACL_MATCH_UID, // set mask: match uids (only)
740 uid, // uid to match
741 0 // gid (not matched here)
742 };
743 CSSM_LIST_ELEMENT subject2 = { NULL, 0 };
744 subject2.Element.Word.Data = (UInt8 *)&selector;
745 subject2.Element.Word.Length = sizeof(selector);
746 CSSM_LIST_ELEMENT subject1 = {
747 &subject2, CSSM_ACL_SUBJECT_TYPE_PROCESS, CSSM_LIST_ELEMENT_WORDID
748 };
749
750 // rights granted (replace with individual list if desired)
751 CSSM_ACL_AUTHORIZATION_TAG rights[] = {
752 CSSM_ACL_AUTHORIZATION_ANY // everything
753 };
754 // owner component (right to change ACL)
755 CSSM_ACL_OWNER_PROTOTYPE owner = {
756 // TypedSubject
757 { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 },
758 // Delegate
759 false
760 };
761 // ACL entries (any number, just one here)
762 CSSM_ACL_ENTRY_INFO acls[] = {
763 {
764 // prototype
765 {
766 // TypedSubject
767 { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 },
768 false, // Delegate
769 // rights for this entry
770 { sizeof(rights) / sizeof(rights[0]), rights },
771 // rest is defaulted
772 }
773 }
774 };
775
776 SecAccessRef access;
777 SecAccessCreateFromOwnerAndACL(&owner, sizeof(acls) / sizeof(acls[0]), acls, &access);
778 return access;
779 }
780
781 static void checkAccessLength(const char * name, SecAccessRef access, int expected) {
782 CFArrayRef acllist = NULL;
783 ok_status(SecAccessCopyACLList(access, &acllist), "%s: SecAccessCopyACLList", name);
784
785 // Count the number of non-integrity ACLs in this access
786 int aclsFound = 0;
787 CFStringRef output = NULL;
788
789 if(acllist) {
790 for(int i = 0; i < CFArrayGetCount(acllist); i++) {
791 SecACLRef acl = (SecACLRef) CFArrayGetValueAtIndex(acllist, i);
792
793 CFArrayRef auths = SecACLCopyAuthorizations(acl);
794 CFRange searchrange = CFRangeMake(0, CFArrayGetCount(auths));
795 if(!CFArrayContainsValue(auths, searchrange, kSecACLAuthorizationIntegrity) &&
796 !CFArrayContainsValue(auths, searchrange, kSecACLAuthorizationPartitionID)) {
797
798 aclsFound += 1;
799 }
800
801 CFReleaseNull(auths);
802 }
803
804 CFReleaseNull(acllist);
805 }
806 is(aclsFound, expected, "%s: ACL has correct number of entries", name);
807 }
808 #define checkAccessLengthTests 2
809
810 static void testUidAccess() {
811 char name[100];
812 sprintf(name, "testUidAccess");
813 secnotice("integrity", "************************************* %s", name);
814
815 SecAccessRef access = makeUidAccess(getuid());
816
817 SecKeychainRef kc = newKeychain(name);
818 CFMutableDictionaryRef query = createAddItemDictionary(kc, kSecClassGenericPassword, CFSTR("test label"));
819 CFDictionarySetValue(query, kSecAttrAccess, access);
820
821 CFTypeRef result = NULL;
822 ok_status(SecItemAdd(query, &result), "%s: SecItemAdd", name);
823 CFReleaseNull(query);
824 ok(result != NULL, "%s: SecItemAdd returned a result", name);
825
826 SecKeychainItemRef item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
827
828 ok_status(SecKeychainItemSetAccess(item, access), "%s: SecKeychainItemSetAccess", name);
829 checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
830
831 // Check to make sure the ACL stays
832 access = NULL;
833 ok_status(SecKeychainItemCopyAccess(item, &access), "%s: SecKeychainItemCopyAccess", name);
834 checkAccessLength(name, access, 2);
835
836 const char * newPassword = "newPassword";
837 ok_status(SecKeychainItemModifyContent(item, NULL, (UInt32) strlen(newPassword), newPassword), "%s: SecKeychainItemModifyContent", name);
838
839 access = NULL;
840 ok_status(SecKeychainItemCopyAccess(item, &access), "%s: SecKeychainItemCopyAccess", name);
841 checkAccessLength(name, access, 2);
842
843 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
844 CFReleaseNull(kc);
845 }
846 #define testUidAccessTests (newKeychainTests + 2 + checkNTests + 1 + checkNTests + 1 + checkAccessLengthTests \
847 + 2 + checkAccessLengthTests + 1)
848
849
850 static SecAccessRef makeMultipleUidAccess(uid_t* uids, uint32 count)
851 {
852 // rights granted (replace with individual list if desired)
853 CSSM_ACL_AUTHORIZATION_TAG rights[] =
854 {
855 CSSM_ACL_AUTHORIZATION_ANY // everything
856 };
857 size_t numRights = sizeof(rights) / sizeof(rights[0]);
858
859 // allocate the arrays of objects used to define the ACL
860 CSSM_ACL_PROCESS_SUBJECT_SELECTOR selectors[count];
861 CSSM_LIST_ELEMENT heads[count], tails[count];
862 CSSM_ACL_ENTRY_INFO acls[count];
863 // clear all the ACL objects
864 memset(heads, 0, sizeof(heads));
865 memset(acls, 0, sizeof(acls));
866
867 uint32 i = count;
868 while (i--)
869 {
870 // make the "uid/gid" ACL subject
871 selectors[i].version = CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION;
872 selectors[i].mask = CSSM_ACL_MATCH_UID; // set mask: match uids (only)
873 selectors[i].uid = uids[i]; // uid to match
874 selectors[i].gid = 0; // gid (not matched here)
875
876 // this is a CSSM_LIST_ELEMENT chain
877 heads[i].NextElement = &(tails[i]);
878 heads[i].WordID = CSSM_ACL_SUBJECT_TYPE_PROCESS;
879 heads[i].ElementType = CSSM_LIST_ELEMENT_WORDID;
880 // Element is unused
881
882 tails[i].NextElement = NULL;
883 tails[i].WordID = CSSM_WORDID__NLU_;
884 tails[i].ElementType = CSSM_LIST_ELEMENT_DATUM;
885 tails[i].Element.Word.Data = (UInt8 *)&selectors[i];
886 tails[i].Element.Word.Length = sizeof(selectors[i]);
887
888 // ACL entry
889 acls[i].EntryPublicInfo.TypedSubject.ListType = CSSM_LIST_TYPE_UNKNOWN;
890 acls[i].EntryPublicInfo.TypedSubject.Head = &heads[i];
891 acls[i].EntryPublicInfo.TypedSubject.Tail = &tails[i];
892 acls[i].EntryPublicInfo.Delegate = CSSM_FALSE;
893 acls[i].EntryPublicInfo.Authorization.NumberOfAuthTags = (uint32) numRights;
894
895 acls[i].EntryPublicInfo.Authorization.AuthTags = rights;
896 acls[i].EntryHandle = i;
897 }
898
899 // owner component (right to change ACL)
900 CSSM_ACL_OWNER_PROTOTYPE owner;
901 owner.TypedSubject = acls[0].EntryPublicInfo.TypedSubject;
902 owner.Delegate = acls[0].EntryPublicInfo.Delegate;
903
904 SecAccessRef access;
905 SecAccessCreateFromOwnerAndACL(&owner, count, acls, &access);
906 return access;
907 }
908 static void testMultipleUidAccess() {
909 char name[100];
910 sprintf(name, "testMultipleUidAccess");
911 secnotice("integrity", "************************************* %s", name);
912
913 uid_t uids[5];
914 uids[0] = getuid();
915 uids[1] = 0;
916 uids[2] = 500;
917 uids[3] = 501;
918 uids[4] = 502;
919
920 SecAccessRef access = makeMultipleUidAccess(uids, 5);
921
922 SecKeychainRef kc = newKeychain(name);
923 CFMutableDictionaryRef query = createAddItemDictionary(kc, kSecClassGenericPassword, CFSTR("test label"));
924 CFDictionarySetValue(query, kSecAttrAccess, access);
925
926 CFTypeRef result = NULL;
927 ok_status(SecItemAdd(query, &result), "%s: SecItemAdd", name);
928 CFReleaseNull(query);
929 ok(result != NULL, "%s: SecItemAdd returned a result", name);
930
931 checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
932
933 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
934 CFReleaseNull(kc);
935 }
936 #define testMultipleUidAccessTests (newKeychainTests + checkNTests + 3)
937
938 static void testRootUidAccess() {
939 char name[100];
940 sprintf(name, "testRootUidAccess");
941 secnotice("integrity", "************************************* %s", name);
942
943 CFErrorRef error = NULL;
944
945 SecAccessRef access = SecAccessCreateWithOwnerAndACL(getuid(), 0, (kSecUseOnlyUID | kSecHonorRoot), NULL, &error);
946 ok(access, "%s: SecAccessCreateWithOwnerAndACL returned an access", name);
947 CFStringRef errorDesc = error ? CFErrorCopyDescription(error) : NULL;
948 is(error, NULL, "%s: SecAccessCreateWithOwnerAndACL did not return an error: %@", name, errorDesc ? errorDesc : CFSTR("no error"));
949 CFReleaseNull(errorDesc);
950
951 SecKeychainRef kc = newKeychain(name);
952 CFMutableDictionaryRef query = createAddItemDictionary(kc, kSecClassGenericPassword, CFSTR("test label"));
953 CFDictionarySetValue(query, kSecAttrAccess, access);
954
955 CFTypeRef result = NULL;
956 ok_status(SecItemAdd(query, &result), "%s: SecItemAdd", name);
957 CFReleaseNull(query);
958 ok(result != NULL, "%s: SecItemAdd returned a result", name);
959
960 query = createQueryItemDictionary(kc, kSecClassGenericPassword);
961
962 SecKeychainItemRef item = checkNCopyFirst(name, query, 1);
963
964 ok_status(SecKeychainItemSetAccess(item, access), "%s: SecKeychainItemSetAccess", name);
965 CFReleaseNull(access);
966 checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
967
968 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
969 CFReleaseNull(kc);
970 }
971 #define testRootUidAccessTests (newKeychainTests + 2 + checkNTests + 4 + checkNTests)
972
973 static void testBadACL() {
974 char name[100];
975 sprintf(name, "testBadACL");
976 secnotice("integrity", "************************************* %s", name);
977
978 SecKeychainItemRef item = NULL;
979
980 unlink(keychainFile);
981 writeFullV512Keychain(name, keychainDbFile);
982
983 SecKeychainRef kc = openCustomKeychain(name, keychainName, "password");
984
985 // Check that these exist in this keychain...
986 checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
987 checkN(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
988
989 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
990 CFRelease(kc);
991
992 // Corrupt all the ACLs, by changing the partition id plist entry
993 uint8_t * fileBuffer = (uint8_t*) malloc(FULL_V512_SIZE);
994 memcpy(fileBuffer, full_v512, FULL_V512_SIZE);
995
996 void* p;
997 char * str = "<key>Partitions</key>";
998 while( (p = memmem(fileBuffer, FULL_V512_SIZE, (void*) str, strlen(str))) ) {
999 *(uint8_t*) p = 0;
1000 }
1001 writeFile(keychainDbFile, fileBuffer, FULL_V512_SIZE);
1002 free(fileBuffer);
1003
1004 kc = openCustomKeychain(name, keychainName, "password");
1005
1006 // These items exist in this keychain, but their ACL is corrupted. We should be able to find them, but not fetch data.
1007 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
1008 readPasswordContentsWithResult(item, errSecInvalidItemRef, NULL); // we don't expect to be able to read this
1009 deleteItem(item);
1010 checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 0);
1011
1012 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
1013 readPasswordContentsWithResult(item, errSecInvalidItemRef, NULL); // we don't expect to be able to read this
1014 deleteItem(item);
1015 checkN(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 0);
1016
1017 // These should work
1018 makeItem(name, kc, kSecClassGenericPassword, CFSTR("test_generic"));
1019 makeItem(name, kc, kSecClassInternetPassword, CFSTR("test_internet"));
1020
1021 // And now the items should exist
1022 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
1023 readPasswordContents(item, CFSTR("data"));
1024 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
1025 readPasswordContents(item, CFSTR("data"));
1026
1027 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
1028 CFReleaseNull(kc);
1029 }
1030 #define testBadACLTests (openCustomKeychainTests + checkNTests * 2 + 1 + openCustomKeychainTests \
1031 + 2*(checkNTests + readPasswordContentsWithResultTests + deleteItemTests + checkNTests) \
1032 + makeItemTests*2 + checkNTests*2 + readPasswordContentsTests*2 + 1)
1033
1034 static void testIterateLockedKeychain() {
1035 char name[100];
1036 sprintf(name, "testIterateLockedKeychain");
1037 secnotice("integrity", "************************************* %s", name);
1038
1039 SecKeychainItemRef item = NULL;
1040
1041 unlink(keychainFile);
1042 writeFullV512Keychain(name, keychainDbFile);
1043
1044 SecKeychainRef kc = openCustomKeychain(name, keychainName, "password");
1045
1046 ok_status(SecKeychainLock(kc), "%s: SecKeychainLock", name);
1047
1048 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1);
1049 item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassInternetPassword), 1);
1050
1051 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
1052 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPublic), 1);
1053 item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassPrivate), 1);
1054
1055 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
1056 CFReleaseNull(kc);
1057 }
1058 #define testIterateLockedKeychainTests (openCustomKeychainTests + 1 + checkNTests*5 + 1)
1059
1060 #define kTestCount (0 \
1061 + testAddItemTests \
1062 + testAddItemTests \
1063 + testCopyMatchingItemTests \
1064 + testCopyMatchingItemTests \
1065 + testUpdateItemTests \
1066 + testUpdateItemTests \
1067 + testAddDuplicateItemTests \
1068 + testAddDuplicateItemTests \
1069 + testDeleteItemTests \
1070 + testDeleteItemTests \
1071 + testUpdateRetainedItemTests \
1072 + testUpdateRetainedItemTests \
1073 \
1074 + testAddKeyTests \
1075 + testAddFreeKeyTests \
1076 + testCopyMatchingKeyTests \
1077 + testUpdateKeyTests \
1078 + testAddDuplicateKeyTests \
1079 + testKeyPairTests \
1080 + testExportImportKeyPairTests \
1081 \
1082 + initializeDLTests \
1083 + testAttackItemTests \
1084 + testAttackKeyTests \
1085 + testAddAfterCorruptItemTests \
1086 + testAddAfterCorruptKeyTests \
1087 + unloadDLTests \
1088 \
1089 + testKeychainUpgradeTests \
1090 + testKeychainCreateOverTests \
1091 + testKeychainDowngradeTests \
1092 + testKeychainWrongFile256Tests \
1093 + testKeychainWrongFile512Tests \
1094 + testUidAccessTests \
1095 + testMultipleUidAccessTests \
1096 + testRootUidAccessTests \
1097 + testBadACLTests \
1098 + testIterateLockedKeychainTests \
1099 )
1100
1101 static void tests(void)
1102 {
1103 initializeKeychainTests("kc-30-xara");
1104
1105 testKeychainUpgrade();
1106 testKeychainCreateOver();
1107 testKeychainDowngrade();
1108 testKeychainWrongFile256();
1109 testKeychainWrongFile512();
1110 testUidAccess();
1111 testMultipleUidAccess();
1112 testRootUidAccess();
1113 testBadACL();
1114 testIterateLockedKeychain();
1115
1116 testAddItem(kSecClassGenericPassword, CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
1117 testAddItem(kSecClassInternetPassword, CFSTR("be34c4562153063ce9cdefc2c34451d5e6e98a447f293d68a67349c1b5d1164f"));
1118
1119 testCopyMatchingItem(kSecClassGenericPassword, CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
1120 testCopyMatchingItem(kSecClassInternetPassword, CFSTR("be34c4562153063ce9cdefc2c34451d5e6e98a447f293d68a67349c1b5d1164f"));
1121
1122 testUpdateItem(kSecClassGenericPassword, CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"),
1123 CFSTR("7b7be2fd6ee9f81ba4c5575ea451f2c21117fc0f241625a6cf90c65180b8c9f5"));
1124 testUpdateItem(kSecClassInternetPassword, CFSTR("be34c4562153063ce9cdefc2c34451d5e6e98a447f293d68a67349c1b5d1164f"),
1125 CFSTR("d71af9e4d54127a5dbc10c5ec097b828065cfbaf2b775caf1a3c4e3410f80851"));
1126
1127 testAddDuplicateItem(kSecClassGenericPassword, CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
1128 testAddDuplicateItem(kSecClassInternetPassword, CFSTR("be34c4562153063ce9cdefc2c34451d5e6e98a447f293d68a67349c1b5d1164f"));
1129
1130 testDeleteItem(kSecClassGenericPassword, CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
1131 testDeleteItem(kSecClassInternetPassword, CFSTR("be34c4562153063ce9cdefc2c34451d5e6e98a447f293d68a67349c1b5d1164f"));
1132
1133 testUpdateRetainedItem(kSecClassGenericPassword);
1134 testUpdateRetainedItem(kSecClassInternetPassword);
1135
1136 testAddKey( CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
1137 testAddFreeKey( CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
1138 testCopyMatchingKey(CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
1139 testUpdateKey( CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"),
1140 CFSTR("a744ce6db8359ad264ed5f4a35ecfcc8b6599b89319e7ea316035acd3fb02c22"));
1141 testAddDuplicateKey(CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
1142 testAddDuplicateFreeKey(CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
1143
1144 testKeyPair();
1145 testExportImportKeyPair();
1146
1147 CSSM_DL_DB_HANDLE dldbHandle = initializeDL();
1148 testAttackItem(dldbHandle);
1149 testAttackKey(dldbHandle);
1150
1151 testAddAfterCorruptItem(dldbHandle);
1152 testAddAfterCorruptKey(dldbHandle);
1153 unloadDL(&dldbHandle);
1154
1155 //makeOldKeychainBlob();
1156 }
1157
1158 #pragma clang diagnostic pop
1159 #else
1160
1161 #define kTestCount (0)
1162
1163
1164 static void tests(void)
1165 {
1166 }
1167
1168 #endif /* TARGET_OS_MAC */
1169
1170
1171 int kc_30_xara(int argc, char *const *argv)
1172 {
1173 plan_tests(kTestCount);
1174
1175 tests();
1176
1177 deleteTestFiles();
1178 return 0;
1179 }