2 * Copyright (c) 2015 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #include "keychain_regressions.h"
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>
38 #include "kc-30-xara-item-helpers.h"
39 #include "kc-30-xara-key-helpers.h"
40 #include "kc-30-xara-upgrade-helpers.h"
44 #pragma clang diagnostic push
45 #pragma clang diagnostic ignored "-Wunused-variable"
46 #pragma clang diagnostic ignored "-Wunused-function"
48 /* Test basic add delete update copy matching stuff. */
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
};
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
;
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");
70 #define initializeDLTests 3
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");
77 #define unloadDLTests 3
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
,
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
);
88 CSSM_QUERY queryAll
= {};
89 queryAll
.RecordType
= recordType
;
91 CSSM_HANDLE results
= 0;
93 CSSM_DB_UNIQUE_RECORD_PTR uniqueIdPtr
= NULL
;
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
;
101 attributes
.AttributeData
[0].NumberOfValues
= 1;
102 attributes
.AttributeData
[0].Value
= malloc(sizeof(CSSM_DATA
)*attributes
.AttributeData
[0].NumberOfValues
);
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
);
111 CSSM_DL_DataModify(dldbHandle
,
112 attributes
.DataRecordType
,
115 NULL
, // no data modification
116 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
118 CSSM_DL_FreeUniqueRecord(dldbHandle
, uniqueIdPtr
);
119 status
= CSSM_DL_DataGetNext(dldbHandle
, results
, &attributes
, &data
, &uniqueIdPtr
);
121 ok_status(CSSM_DL_DbClose(dldbHandle
), "%s: CSSM_DL_DbClose", name
);
123 #define modifyAttributeInKeychainTests 2
125 static void testAttackItem(CSSM_DL_DB_HANDLE dldbHandle
) {
126 char * name
= "testAttackItem";
127 secnotice("integrity", "************************************* %s", name
);
129 SecKeychainRef kc
= newKeychain(name
);
130 checkN(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 0);
132 makeItemWithIntegrity(name
, kc
, kSecClassGenericPassword
, CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
133 SecKeychainItemRef item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
137 char * modification
= "evil_application";
138 modifyAttributeInKeychain(name
, dldbHandle
, keychainDbFile
, CSSM_DL_DB_RECORD_GENERIC_PASSWORD
, "PrintName", modification
, strlen(modification
));
140 kc
= openKeychain(name
);
141 item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
142 readPasswordContentsWithResult(item
, errSecInvalidItemRef
, NULL
);
144 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
147 #define testAttackItemTests (newKeychainTests + checkNTests + makeItemWithIntegrityTests + checkNTests + modifyAttributeInKeychainTests + openKeychainTests + checkNTests + readPasswordContentsWithResultTests + 1)
149 static void testAttackKey(CSSM_DL_DB_HANDLE dldbHandle
) {
150 char * name
= "testAttackKey";
151 secnotice("integrity", "************************************* %s", name
);
153 SecKeychainRef kc
= newKeychain(name
);
154 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 0);
156 makeKeyWithIntegrity(name
, kc
, CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
157 SecKeychainItemRef item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
159 checkKeyUse((SecKeyRef
) item
, errSecSuccess
);
164 char * modification
= "evil_application";
165 modifyAttributeInKeychain(name
, dldbHandle
, keychainDbFile
, CSSM_DL_DB_RECORD_SYMMETRIC_KEY
, "Label", modification
, strlen(modification
));
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
);
173 #define testAttackKeyTests (newKeychainTests + checkNTests + makeKeyWithIntegrityTests + checkNTests + checkKeyUseTests + modifyAttributeInKeychainTests \
174 + openKeychainTests + checkNTests + checkKeyUseTests + 1)
177 static void testAddAfterCorruptItem(CSSM_DL_DB_HANDLE dldbHandle
) {
178 char * name
= "testAddAfterCorruptItem";
179 secnotice("integrity", "************************************* %s", name
);
181 SecKeychainRef kc
= newKeychain(name
);
182 checkN(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 0);
184 makeCustomItemWithIntegrity(name
, kc
, kSecClassGenericPassword
, CFSTR("test_label"), CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
185 checkN(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
187 makeDuplicateItem(name
, kc
, kSecClassGenericPassword
);
190 char * modification
= "evil_application";
191 modifyAttributeInKeychain(name
, dldbHandle
, keychainDbFile
, CSSM_DL_DB_RECORD_GENERIC_PASSWORD
, "PrintName", modification
, strlen(modification
));
193 kc
= openKeychain(name
);
194 SecKeychainItemRef item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
196 checkN(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 0);
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
);
204 #define testAddAfterCorruptItemTests (newKeychainTests + checkNTests + makeCustomItemWithIntegrityTests + checkNTests + makeDuplicateItemTests \
205 + modifyAttributeInKeychainTests + openKeychainTests + checkNTests + deleteItemTests \
206 + checkNTests + makeCustomItemWithIntegrityTests + checkNTests + makeCustomDuplicateItemTests + 1)
208 static void testAddAfterCorruptKey(CSSM_DL_DB_HANDLE dldbHandle
) {
209 char * name
= "testAddAfterCorruptKey";
210 secnotice("integrity", "************************************* %s", name
);
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);
217 // Make a symmetric key
218 makeCustomKeyWithIntegrity(name
, kc
, CFSTR("test_key"), CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
220 SecKeychainItemRef item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
221 makeCustomDuplicateKey(name
, kc
, CFSTR("test_key"));
227 makeCustomKeyPair(name
, kc
, CFSTR("test_key_pair"), &pub
, &priv
);
228 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 1);
229 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
233 ok_status(SecKeychainListRemoveKeychain(&kc
), "%s: SecKeychainListRemoveKeychain", name
);
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
));
240 kc
= openKeychain(name
);
242 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
244 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 0);
246 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 1);
248 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 0);
250 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
252 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 0);
254 makeCustomKeyWithIntegrity(name
, kc
, CFSTR("evil_application"), CFSTR("ca6d90a0b053113e43bbb67f64030230c96537f77601f66bdf821d8684431dfc"));
255 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
257 makeCustomDuplicateKey(name
, kc
, CFSTR("evil_application"));
259 makeCustomKeyPair(name
, kc
, CFSTR("evil_application"), &pub
, &priv
);
260 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 1);
261 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
263 // We cannot create a duplicate key pair, so don't try.
266 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
269 #define testAddAfterCorruptKeyTests (newKeychainTests \
270 + checkNTests + checkNTests + checkNTests \
271 + makeCustomKeyWithIntegrityTests + checkNTests + makeCustomDuplicateKeyTests \
272 + makeCustomKeyPairTests + checkNTests + checkNTests \
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 \
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
291 static void testKeychainUpgrade() {
293 sprintf(name
, "testKeychainUpgrade");
294 secnotice("integrity", "************************************* %s", name
);
296 char* path
= malloc(sizeof(char) * 400);
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"));
303 writeOldKeychain(name
, oldkcFile
);
305 SecKeychainRef kc
= openCustomKeychain(name
, oldkcFile
, "password");
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
);
319 ok_status(copyfile(oldkcFile
, keychainFile
, NULL
, COPYFILE_UNLINK
| COPYFILE_ALL
), "%s: copyfile", name
);
321 unlink(keychainDbFile
);
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
);
329 dispatch_group_t g
= dispatch_group_create();
330 SecKeychainItemRef item
;
332 char* __block blockName
= NULL
;
333 asprintf(&blockName
, "%s", name
);
335 kc
= openCustomKeychain(name
, keychainName
, "password");
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
);
347 secerror("ending 1\n");
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
);
360 secerror("ending 2\n");
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
);
373 secerror("ending 3\n");
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
);
386 secerror("ending 4\n");
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
);
399 secerror("ending 5\n");
402 dispatch_group_wait(g
, DISPATCH_TIME_FOREVER
);
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"));
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
);
417 // Now close the keychain and open it again
419 kc
= openCustomKeychain(name
, keychainName
, "password");
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"));
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"));
431 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
432 checkIntegrityHash(name
, (SecKeychainItemRef
) item
, CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
433 checkPartitionIDs(name
, (SecKeychainItemRef
) item
, 0);
435 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 1);
436 checkIntegrityHash(name
, (SecKeychainItemRef
) item
, CFSTR("42d29fd5e9935edffcf6d0261eabddb00782ec775caa93716119e8e553ab5578"));
437 checkPartitionIDs(name
, (SecKeychainItemRef
) item
, 0);
439 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
440 checkIntegrityHash(name
, (SecKeychainItemRef
) item
, CFSTR("bdf219cdbc2dc6c4521cf39d1beda2e3491ef0330ba59eb41229dd909632f48d"));
441 checkPartitionIDs(name
, (SecKeychainItemRef
) item
, 0);
443 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
446 // make sure we clean up any files left over
447 unlink(keychainDbFile
);
448 unlink(keychainFile
);
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 \
465 // tests that SecKeychainCreate over an old .keychain file returns an empty keychain
466 static void testKeychainCreateOver() {
468 sprintf(name
, "testKeychainCreateOver");
469 secnotice("integrity", "************************************* %s", name
);
471 char* path
= malloc(sizeof(char) * 400);
474 writeOldKeychain(name
, keychainFile
);
475 unlink(keychainDbFile
);
477 SecKeychainItemRef item
= NULL
;
479 // Check that we upgrade on SecKeychainOpen
480 SecKeychainRef kc
= openCustomKeychain(name
, keychainName
, "password");
482 item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
483 checkIntegrityHash(name
, item
, CFSTR("39c56eadd3e3b496b6099e5f3d5ff88eaee9ca2e3a50c1be8319807a72e451e5"));
486 ok_status(SecKeychainDelete(kc
));
489 // the old file should still exist, but the -db file should not.
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
);
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
);
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);
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
);
511 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
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
);
518 // make sure we clean up any files left over
519 unlink(keychainDbFile
);
520 unlink(keychainFile
);
522 #define testKeychainCreateOverTests (openCustomKeychainTests + \
523 + checkNTests + checkIntegrityHashTests \
532 static void testKeychainDowngrade() {
533 char *name
= "testKeychainDowngrade";
534 secnotice("integrity", "************************************* %s", name
);
536 // For now, don't worry about filenames
537 writeFullV512Keychain(name
, keychainDbFile
);
538 unlink(keychainFile
);
539 writeFullV512Keyfile(name
, keychainTempFile
);
541 SecKeychainRef kc
= openCustomKeychain(name
, keychainName
, "password");
544 ok_status(SecKeychainGetKeychainVersion(kc
, &version
), "%s: SecKeychainGetKeychainVersion", name
);
545 is(version
, version_partition
, "%s: version of initial keychain is incorrect", name
);
547 SecKeychainItemRef item
;
549 item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
550 checkIntegrityHash(name
, item
, CFSTR("6ba8d9f77ddba54d9373b11ae5c8f7b55a5e81da27e05e86723eeceb0a9a8e0c"));
551 makeCustomDuplicateItem(name
, kc
, kSecClassGenericPassword
, CFSTR("test_generic"));
553 item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassInternetPassword
), 1);
554 checkIntegrityHash(name
, item
, CFSTR("630a9fe4f0191db8a99d6e8455e7114f628ce8f0f9eb3559efa572a98877a2b2"));
555 makeCustomDuplicateItem(name
, kc
, kSecClassInternetPassword
, CFSTR("test_internet"));
557 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
558 checkIntegrityHash(name
, (SecKeychainItemRef
) item
, CFSTR("44f10f6bb508d47f8905859efc06eaee500304bc4da408b1f4d2a58c6502147b"));
560 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 1);
561 checkIntegrityHash(name
, (SecKeychainItemRef
) item
, CFSTR("d27ee2be4920d5b6f47f6b19696d09c9a6c1a5d80c6f148f778db27b4ba99d9a"));
563 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
564 checkIntegrityHash(name
, (SecKeychainItemRef
) item
, CFSTR("4b3f7bd7f9e48dc71006ce670990aed9dba6d5089b84d4113121bab41d0a3228"));
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
);
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"));
577 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
578 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 1);
579 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
581 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
584 // make sure we clean up
585 unlink(keychainTempFile
);
586 unlink(keychainDbFile
);
587 unlink(keychainFile
);
589 #define testKeychainDowngradeTests (openCustomKeychainTests + 2 \
590 + checkNTests + checkIntegrityHashTests + makeCustomDuplicateItemTests \
591 + checkNTests + checkIntegrityHashTests + makeCustomDuplicateItemTests \
592 + checkNTests + checkIntegrityHashTests +\
593 + checkNTests + checkIntegrityHashTests +\
594 + checkNTests + checkIntegrityHashTests +\
596 + checkNTests + makeCustomDuplicateItemTests \
597 + checkNTests + makeCustomDuplicateItemTests \
603 // Test opening and upgrading a v256 keychain at a -db filename.
604 static void testKeychainWrongFile256() {
606 sprintf(name
, "testKeychainWrongFile256");
607 secnotice("integrity", "************************************* %s", name
);
610 unlink(keychainFile
);
611 writeOldKeychain(name
, keychainDbFile
);
613 // Only keychainDb file should exist
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
);
618 SecKeychainRef kc
= openCustomKeychain(name
, keychainName
, "password");
620 SecKeychainItemRef item
;
622 // Iterate over the keychain to trigger upgrade
623 item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
624 makeCustomDuplicateItem(name
, kc
, kSecClassGenericPassword
, CFSTR("test_generic"));
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
);
630 // Check the keychain's version and path
632 UInt32 len
= sizeof(path
);
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
);
639 item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
640 makeCustomDuplicateItem(name
, kc
, kSecClassGenericPassword
, CFSTR("test_generic"));
642 item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassInternetPassword
), 1);
643 makeCustomDuplicateItem(name
, kc
, kSecClassInternetPassword
, CFSTR("test_internet"));
645 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
646 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 1);
647 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
649 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
652 // make sure we clean up any files left over
653 unlink(keychainDbFile
);
654 unlink(keychainFile
);
656 #define testKeychainWrongFile256Tests (2 + openCustomKeychainTests \
657 + checkNTests + makeCustomDuplicateItemTests \
659 + checkNTests + makeCustomDuplicateItemTests \
660 + checkNTests + makeCustomDuplicateItemTests \
666 // Test opening and upgrading a v512 keychain at a .keychain filename.
667 static void testKeychainWrongFile512() {
669 sprintf(name
, "testKeychainWrongFile512");
670 secnotice("integrity", "************************************* %s", name
);
673 writeFullV512Keychain(name
, keychainFile
);
674 unlink(keychainDbFile
);
676 // Only keychain file should exist
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
);
681 SecKeychainRef kc
= openCustomKeychain(name
, keychainName
, "password");
683 SecKeychainItemRef item
;
685 // Iterate over the keychain to trigger upgrade
686 item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
687 makeCustomDuplicateItem(name
, kc
, kSecClassGenericPassword
, CFSTR("test_generic"));
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
);
693 // Check the keychain's version and path
695 UInt32 len
= sizeof(path
);
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
);
702 item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
703 makeCustomDuplicateItem(name
, kc
, kSecClassGenericPassword
, CFSTR("test_generic"));
705 item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassInternetPassword
), 1);
706 makeCustomDuplicateItem(name
, kc
, kSecClassInternetPassword
, CFSTR("test_internet"));
708 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
709 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 1);
710 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
712 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
715 // make sure we clean up any files left over
716 unlink(keychainDbFile
);
717 unlink(keychainFile
);
719 #define testKeychainWrongFile512Tests (2 + openCustomKeychainTests \
720 + checkNTests + makeCustomDuplicateItemTests \
722 + checkNTests + makeCustomDuplicateItemTests \
723 + checkNTests + makeCustomDuplicateItemTests \
730 #undef version_partition
731 #undef version_MacOS_10_0
733 static SecAccessRef
makeUidAccess(uid_t uid
)
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)
741 0 // gid (not matched here)
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
750 // rights granted (replace with individual list if desired)
751 CSSM_ACL_AUTHORIZATION_TAG rights
[] = {
752 CSSM_ACL_AUTHORIZATION_ANY
// everything
754 // owner component (right to change ACL)
755 CSSM_ACL_OWNER_PROTOTYPE owner
= {
757 { CSSM_LIST_TYPE_UNKNOWN
, &subject1
, &subject2
},
761 // ACL entries (any number, just one here)
762 CSSM_ACL_ENTRY_INFO acls
[] = {
767 { CSSM_LIST_TYPE_UNKNOWN
, &subject1
, &subject2
},
769 // rights for this entry
770 { sizeof(rights
) / sizeof(rights
[0]), rights
},
777 SecAccessCreateFromOwnerAndACL(&owner
, sizeof(acls
) / sizeof(acls
[0]), acls
, &access
);
781 static void checkAccessLength(const char * name
, SecAccessRef access
, int expected
) {
782 CFArrayRef acllist
= NULL
;
783 ok_status(SecAccessCopyACLList(access
, &acllist
), "%s: SecAccessCopyACLList", name
);
785 // Count the number of non-integrity ACLs in this access
787 CFStringRef output
= NULL
;
790 for(int i
= 0; i
< CFArrayGetCount(acllist
); i
++) {
791 SecACLRef acl
= (SecACLRef
) CFArrayGetValueAtIndex(acllist
, i
);
793 CFArrayRef auths
= SecACLCopyAuthorizations(acl
);
794 CFRange searchrange
= CFRangeMake(0, CFArrayGetCount(auths
));
795 if(!CFArrayContainsValue(auths
, searchrange
, kSecACLAuthorizationIntegrity
) &&
796 !CFArrayContainsValue(auths
, searchrange
, kSecACLAuthorizationPartitionID
)) {
801 CFReleaseNull(auths
);
804 CFReleaseNull(acllist
);
806 is(aclsFound
, expected
, "%s: ACL has correct number of entries", name
);
808 #define checkAccessLengthTests 2
810 static void testUidAccess() {
812 sprintf(name
, "testUidAccess");
813 secnotice("integrity", "************************************* %s", name
);
815 SecAccessRef access
= makeUidAccess(getuid());
817 SecKeychainRef kc
= newKeychain(name
);
818 CFMutableDictionaryRef query
= createAddItemDictionary(kc
, kSecClassGenericPassword
, CFSTR("test label"));
819 CFDictionarySetValue(query
, kSecAttrAccess
, access
);
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
);
826 SecKeychainItemRef item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
828 ok_status(SecKeychainItemSetAccess(item
, access
), "%s: SecKeychainItemSetAccess", name
);
829 checkN(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
831 // Check to make sure the ACL stays
833 ok_status(SecKeychainItemCopyAccess(item
, &access
), "%s: SecKeychainItemCopyAccess", name
);
834 checkAccessLength(name
, access
, 2);
836 const char * newPassword
= "newPassword";
837 ok_status(SecKeychainItemModifyContent(item
, NULL
, (UInt32
) strlen(newPassword
), newPassword
), "%s: SecKeychainItemModifyContent", name
);
840 ok_status(SecKeychainItemCopyAccess(item
, &access
), "%s: SecKeychainItemCopyAccess", name
);
841 checkAccessLength(name
, access
, 2);
843 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
846 #define testUidAccessTests (newKeychainTests + 2 + checkNTests + 1 + checkNTests + 1 + checkAccessLengthTests \
847 + 2 + checkAccessLengthTests + 1)
850 static SecAccessRef
makeMultipleUidAccess(uid_t
* uids
, uint32 count
)
852 // rights granted (replace with individual list if desired)
853 CSSM_ACL_AUTHORIZATION_TAG rights
[] =
855 CSSM_ACL_AUTHORIZATION_ANY
// everything
857 size_t numRights
= sizeof(rights
) / sizeof(rights
[0]);
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
));
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)
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
;
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
]);
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
;
895 acls
[i
].EntryPublicInfo
.Authorization
.AuthTags
= rights
;
896 acls
[i
].EntryHandle
= i
;
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
;
905 SecAccessCreateFromOwnerAndACL(&owner
, count
, acls
, &access
);
908 static void testMultipleUidAccess() {
910 sprintf(name
, "testMultipleUidAccess");
911 secnotice("integrity", "************************************* %s", name
);
920 SecAccessRef access
= makeMultipleUidAccess(uids
, 5);
922 SecKeychainRef kc
= newKeychain(name
);
923 CFMutableDictionaryRef query
= createAddItemDictionary(kc
, kSecClassGenericPassword
, CFSTR("test label"));
924 CFDictionarySetValue(query
, kSecAttrAccess
, access
);
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
);
931 checkN(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
933 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
936 #define testMultipleUidAccessTests (newKeychainTests + checkNTests + 3)
938 static void testRootUidAccess() {
940 sprintf(name
, "testRootUidAccess");
941 secnotice("integrity", "************************************* %s", name
);
943 CFErrorRef error
= NULL
;
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
);
951 SecKeychainRef kc
= newKeychain(name
);
952 CFMutableDictionaryRef query
= createAddItemDictionary(kc
, kSecClassGenericPassword
, CFSTR("test label"));
953 CFDictionarySetValue(query
, kSecAttrAccess
, access
);
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
);
960 query
= createQueryItemDictionary(kc
, kSecClassGenericPassword
);
962 SecKeychainItemRef item
= checkNCopyFirst(name
, query
, 1);
964 ok_status(SecKeychainItemSetAccess(item
, access
), "%s: SecKeychainItemSetAccess", name
);
965 CFReleaseNull(access
);
966 checkN(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
968 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
971 #define testRootUidAccessTests (newKeychainTests + 2 + checkNTests + 4 + checkNTests)
973 static void testBadACL() {
975 sprintf(name
, "testBadACL");
976 secnotice("integrity", "************************************* %s", name
);
978 SecKeychainItemRef item
= NULL
;
980 unlink(keychainFile
);
981 writeFullV512Keychain(name
, keychainDbFile
);
983 SecKeychainRef kc
= openCustomKeychain(name
, keychainName
, "password");
985 // Check that these exist in this keychain...
986 checkN(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
987 checkN(name
, createQueryItemDictionary(kc
, kSecClassInternetPassword
), 1);
989 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
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
);
997 char * str
= "<key>Partitions</key>";
998 while( (p
= memmem(fileBuffer
, FULL_V512_SIZE
, (void*) str
, strlen(str
))) ) {
1001 writeFile(keychainDbFile
, fileBuffer
, FULL_V512_SIZE
);
1004 kc
= openCustomKeychain(name
, keychainName
, "password");
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
1010 checkN(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 0);
1012 item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassInternetPassword
), 1);
1013 readPasswordContentsWithResult(item
, errSecInvalidItemRef
, NULL
); // we don't expect to be able to read this
1015 checkN(name
, createQueryItemDictionary(kc
, kSecClassInternetPassword
), 0);
1017 // These should work
1018 makeItem(name
, kc
, kSecClassGenericPassword
, CFSTR("test_generic"));
1019 makeItem(name
, kc
, kSecClassInternetPassword
, CFSTR("test_internet"));
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"));
1027 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
1030 #define testBadACLTests (openCustomKeychainTests + checkNTests * 2 + 1 + openCustomKeychainTests \
1031 + 2*(checkNTests + readPasswordContentsWithResultTests + deleteItemTests + checkNTests) \
1032 + makeItemTests*2 + checkNTests*2 + readPasswordContentsTests*2 + 1)
1034 static void testIterateLockedKeychain() {
1036 sprintf(name
, "testIterateLockedKeychain");
1037 secnotice("integrity", "************************************* %s", name
);
1039 SecKeychainItemRef item
= NULL
;
1041 unlink(keychainFile
);
1042 writeFullV512Keychain(name
, keychainDbFile
);
1044 SecKeychainRef kc
= openCustomKeychain(name
, keychainName
, "password");
1046 ok_status(SecKeychainLock(kc
), "%s: SecKeychainLock", name
);
1048 item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassGenericPassword
), 1);
1049 item
= checkNCopyFirst(name
, createQueryItemDictionary(kc
, kSecClassInternetPassword
), 1);
1051 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
1052 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 1);
1053 item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
1055 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
1058 #define testIterateLockedKeychainTests (openCustomKeychainTests + 1 + checkNTests*5 + 1)
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 \
1075 + testAddFreeKeyTests \
1076 + testCopyMatchingKeyTests \
1077 + testUpdateKeyTests \
1078 + testAddDuplicateKeyTests \
1079 + testKeyPairTests \
1080 + testExportImportKeyPairTests \
1082 + initializeDLTests \
1083 + testAttackItemTests \
1084 + testAttackKeyTests \
1085 + testAddAfterCorruptItemTests \
1086 + testAddAfterCorruptKeyTests \
1089 + testKeychainUpgradeTests \
1090 + testKeychainCreateOverTests \
1091 + testKeychainDowngradeTests \
1092 + testKeychainWrongFile256Tests \
1093 + testKeychainWrongFile512Tests \
1094 + testUidAccessTests \
1095 + testMultipleUidAccessTests \
1096 + testRootUidAccessTests \
1098 + testIterateLockedKeychainTests \
1101 static void tests(void)
1103 initializeKeychainTests("kc-30-xara");
1105 testKeychainUpgrade();
1106 testKeychainCreateOver();
1107 testKeychainDowngrade();
1108 testKeychainWrongFile256();
1109 testKeychainWrongFile512();
1111 testMultipleUidAccess();
1112 testRootUidAccess();
1114 testIterateLockedKeychain();
1116 testAddItem(kSecClassGenericPassword
, CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
1117 testAddItem(kSecClassInternetPassword
, CFSTR("be34c4562153063ce9cdefc2c34451d5e6e98a447f293d68a67349c1b5d1164f"));
1119 testCopyMatchingItem(kSecClassGenericPassword
, CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
1120 testCopyMatchingItem(kSecClassInternetPassword
, CFSTR("be34c4562153063ce9cdefc2c34451d5e6e98a447f293d68a67349c1b5d1164f"));
1122 testUpdateItem(kSecClassGenericPassword
, CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"),
1123 CFSTR("7b7be2fd6ee9f81ba4c5575ea451f2c21117fc0f241625a6cf90c65180b8c9f5"));
1124 testUpdateItem(kSecClassInternetPassword
, CFSTR("be34c4562153063ce9cdefc2c34451d5e6e98a447f293d68a67349c1b5d1164f"),
1125 CFSTR("d71af9e4d54127a5dbc10c5ec097b828065cfbaf2b775caf1a3c4e3410f80851"));
1127 testAddDuplicateItem(kSecClassGenericPassword
, CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
1128 testAddDuplicateItem(kSecClassInternetPassword
, CFSTR("be34c4562153063ce9cdefc2c34451d5e6e98a447f293d68a67349c1b5d1164f"));
1130 testDeleteItem(kSecClassGenericPassword
, CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4"));
1131 testDeleteItem(kSecClassInternetPassword
, CFSTR("be34c4562153063ce9cdefc2c34451d5e6e98a447f293d68a67349c1b5d1164f"));
1133 testUpdateRetainedItem(kSecClassGenericPassword
);
1134 testUpdateRetainedItem(kSecClassInternetPassword
);
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"));
1145 testExportImportKeyPair();
1147 CSSM_DL_DB_HANDLE dldbHandle
= initializeDL();
1148 testAttackItem(dldbHandle
);
1149 testAttackKey(dldbHandle
);
1151 testAddAfterCorruptItem(dldbHandle
);
1152 testAddAfterCorruptKey(dldbHandle
);
1153 unloadDL(&dldbHandle
);
1155 //makeOldKeychainBlob();
1158 #pragma clang diagnostic pop
1161 #define kTestCount (0)
1164 static void tests(void)
1168 #endif /* TARGET_OS_MAC */
1171 int kc_30_xara(int argc
, char *const *argv
)
1173 plan_tests(kTestCount
);