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 "kc-30-xara-helpers.h"
25 #include "kc-item-helpers.h"
27 #ifndef kc_30_xara_item_helpers_h
28 #define kc_30_xara_item_helpers_h
32 #pragma clang diagnostic push
33 #pragma clang diagnostic ignored "-Wunused-variable"
34 #pragma clang diagnostic ignored "-Wunused-function"
36 static void makeCustomItemWithIntegrity(const char* name
, SecKeychainRef kc
, CFStringRef itemclass
, CFStringRef label
, CFStringRef expectedHash
) {
37 SecKeychainItemRef item
= makeItem(name
, kc
, itemclass
, label
);
38 checkIntegrityHash(name
, item
, expectedHash
);
39 checkPartitionIDs(name
, (SecKeychainItemRef
) item
, 1);
43 #define makeCustomItemWithIntegrityTests (makeItemTests + checkIntegrityHashTests + checkPartitionIDsTests)
45 static void makeItemWithIntegrity(const char* name
, SecKeychainRef kc
, CFStringRef itemclass
, CFStringRef expectedHash
) {
46 makeCustomItemWithIntegrity(name
, kc
, itemclass
, CFSTR("test_label"), expectedHash
);
48 #define makeItemWithIntegrityTests (makeCustomItemWithIntegrityTests)
50 static void testAddItem(CFStringRef itemclass
, CFStringRef expectedHash
) {
52 sprintf(name
, "testAddItem[%s]", CFStringGetCStringPtr(itemclass
, kCFStringEncodingUTF8
));
53 secnotice("integrity", "************************************* %s", name
);
55 SecKeychainRef kc
= newKeychain(name
);
56 makeItemWithIntegrity(name
, kc
, itemclass
, expectedHash
);
58 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
61 #define testAddItemTests (newKeychainTests + makeItemWithIntegrityTests + 1)
63 static void testCopyMatchingItem(CFStringRef itemclass
, CFStringRef expectedHash
) {
65 sprintf(name
, "testCopyMatchingItem[%s]", CFStringGetCStringPtr(itemclass
, kCFStringEncodingUTF8
));
66 secnotice("integrity", "************************************* %s", name
);
68 SecKeychainRef kc
= newKeychain(name
);
69 makeItemWithIntegrity(name
, kc
, itemclass
, expectedHash
);
71 SecKeychainItemRef item
= checkN(name
, makeQueryItemDictionary(kc
, itemclass
), 1);
72 checkIntegrityHash(name
, item
, expectedHash
);
73 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
76 #define testCopyMatchingItemTests (newKeychainTests + makeItemWithIntegrityTests + checkNTests + checkIntegrityHashTests + 1)
78 static void testUpdateItem(CFStringRef itemclass
, CFStringRef expectedHashOrig
, CFStringRef expectedHashAfter
) {
80 sprintf(name
, "testUpdateItem[%s]", CFStringGetCStringPtr(itemclass
, kCFStringEncodingUTF8
));
81 secnotice("integrity", "************************************* %s", name
);
83 SecKeychainRef kc
= newKeychain(name
);
84 makeItemWithIntegrity(name
, kc
, itemclass
, expectedHashOrig
);
86 CFMutableDictionaryRef query
= makeQueryItemDictionary(kc
, itemclass
);
87 CFMutableDictionaryRef update
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
88 CFDictionarySetValue(update
, kSecAttrComment
, CFSTR("a modification"));
89 CFDictionarySetValue(update
, kSecAttrAccount
, CFSTR("a account modification"));
90 CFDictionarySetValue(update
, kSecAttrLabel
, CFSTR("a label modification"));
91 ok_status(SecItemUpdate(query
, update
), "%s: SecItemUpdate", name
);
93 CFReleaseNull(update
);
95 SecKeychainItemRef item
= checkN(name
, makeQueryItemDictionary(kc
, itemclass
), 1);
96 checkIntegrityHash(name
, item
, expectedHashAfter
);
99 // Check that updating data works
100 update
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
101 CFDictionarySetValue(update
, kSecValueData
, CFDataCreate(NULL
, (void*)"data", 4));
102 ok_status(SecItemUpdate(query
, update
), "%s: SecItemUpdate", name
);
104 item
= checkN(name
, makeQueryItemDictionary(kc
, itemclass
), 1);
105 checkIntegrityHash(name
, item
, expectedHashAfter
);
106 checkPartitionIDs(name
, item
, 1);
108 CFReleaseNull(query
);
109 CFReleaseNull(update
);
111 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
114 #define testUpdateItemTests (newKeychainTests + makeItemWithIntegrityTests \
115 + 1 + checkNTests + checkIntegrityHashTests \
116 + 1 + checkNTests + checkIntegrityHashTests + checkPartitionIDsTests \
119 static void testAddDuplicateItem(CFStringRef itemclass
, CFStringRef expectedHash
) {
121 sprintf(name
, "testAddDuplicateItem[%s]", CFStringGetCStringPtr(itemclass
, kCFStringEncodingUTF8
));
122 secnotice("integrity", "************************************* %s", name
);
124 SecKeychainRef kc
= newKeychain(name
);
125 makeItemWithIntegrity(name
, kc
, itemclass
, expectedHash
);
127 makeDuplicateItem(name
, kc
, itemclass
);
129 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
132 #define testAddDuplicateItemTests (newKeychainTests + makeItemWithIntegrityTests + makeDuplicateItemTests + 1)
134 static void testDeleteItem(CFStringRef itemclass
, CFStringRef expectedHash
) {
136 sprintf(name
, "testDeleteItem[%s]", CFStringGetCStringPtr(itemclass
, kCFStringEncodingUTF8
));
137 secnotice("integrity", "************************************* %s", name
);
139 SecKeychainRef kc
= newKeychain(name
);
140 makeItemWithIntegrity(name
, kc
, itemclass
, expectedHash
);
142 SecKeychainItemRef item
= checkN(name
, makeQueryItemDictionary(kc
, itemclass
), 1);
143 checkIntegrityHash(name
, item
, expectedHash
);
145 ok_status(SecKeychainItemDelete(item
), "%s: SecKeychainItemDelete", name
);
146 checkN(name
, makeQueryItemDictionary(kc
, itemclass
), 0);
147 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
150 #define testDeleteItemTests (newKeychainTests + makeItemWithIntegrityTests + checkNTests + checkIntegrityHashTests + 1 + checkNTests + 1)
152 static void writeEmptyV512Keychain(const char* name
, const char* keychainFile
);
154 // This test is to find <rdar://problem/23515265> CrashTracer: accountsd at …curity: Security::KeychainCore::CCallbackMgr::consume + 387
156 // The issue was that items could remain in the Keychain cache, even after the
157 // actual object was freed. The main path involved updating an item so that it
158 // had the same primary key as an item which was in the cache but not in the
159 // database (this could be caused by another process deleting the item and us
160 // not receiving the notification).
162 // This test should pass. Failure is shown by crashing.
164 static void testUpdateRetainedItem(CFStringRef itemclass
) {
166 sprintf(name
, "testUpdateRetainedItem[%s]", CFStringGetCStringPtr(itemclass
, kCFStringEncodingUTF8
));
167 secnotice("integrity", "************************************* %s", name
);
169 writeEmptyV512Keychain(name
, keychainDbFile
);
170 SecKeychainRef kc
= openCustomKeychain(name
, keychainName
, "password");
172 SecKeychainItemRef item
= makeCustomItem(name
, kc
, makeAddCustomItemDictionary(kc
, itemclass
, CFSTR("test_label"), CFSTR("account1")));
174 CFRelease(checkN(name
, makeQueryCustomItemDictionary(kc
, itemclass
, CFSTR("test_label")), 1));
176 cmp_ok(CFGetRetainCount(item
), >=, 1, "%s: CFGetRetainCount(item)", name
);
178 // Bump our local database version number a few times, so we'll re-read the database when we reset it later
179 CFReleaseSafe(makeCustomItem(name
, kc
, makeAddCustomItemDictionary(kc
, itemclass
, CFSTR("version"), CFSTR("version"))));
180 CFReleaseSafe(makeCustomItem(name
, kc
, makeAddCustomItemDictionary(kc
, itemclass
, CFSTR("bump"), CFSTR("bump"))));
182 // Simulate another process deleting the items we just made, and us not receiving the notification
183 writeEmptyV512Keychain(name
, keychainDbFile
);
185 // Generate some keychain notifications on a different keychain so the AppleDatabase will reload test.keychain
186 SecKeychainRef kc2
= newCustomKeychain(name
, "unrelated.keychain", "password");
187 CFReleaseSafe(makeCustomItem(name
, kc2
, makeAddCustomItemDictionary(kc
, itemclass
, CFSTR("unrelated1_label"), CFSTR("unrelated1"))));
188 ok_status(SecKeychainDelete(kc2
), "%s: SecKeychainDelete", name
);
191 secnotice("integrity", "************************************* should reload database\n");
193 SecKeychainItemRef item2
= makeCustomItem(name
, kc
, makeAddCustomItemDictionary(kc
, itemclass
, CFSTR("not_a_test_label"), CFSTR("account2")));
194 CFReleaseSafe(checkN(name
, makeQueryCustomItemDictionary(kc
, itemclass
, CFSTR("not_a_test_label")), 1));
195 cmp_ok(CFGetRetainCount(item2
), >=, 1, "%s: CFGetRetainCount(item2)", name
);
197 // Now, update the second item so it would collide with the first
198 CFMutableDictionaryRef query
= makeQueryCustomItemDictionary(kc
, itemclass
, CFSTR("not_a_test_label"));
199 CFMutableDictionaryRef update
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
200 CFDictionarySetValue(update
, kSecAttrAccount
, CFSTR("account1"));
201 CFDictionarySetValue(update
, kSecAttrLabel
, CFSTR("test_label"));
202 ok_status(SecItemUpdate(query
, update
), "%s: SecItemUpdate", name
);
204 cmp_ok(CFGetRetainCount(item
), >=, 1, "%s: CFGetRetainCount(item)", name
);
207 SecKeychainItemRef result
= checkN(name
, makeQueryCustomItemDictionary(kc
, itemclass
, CFSTR("test_label")), 1);
208 CFReleaseNull(result
);
209 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
212 #define testUpdateRetainedItemTests (openCustomKeychainTests + makeCustomItemTests + checkNTests \
213 + 1 + makeCustomItemTests + makeCustomItemTests \
214 + newCustomKeychainTests + makeCustomItemTests + 1 \
215 + makeCustomItemTests + checkNTests + 1 \
216 + 1 + 1 + checkNTests + 1)
221 #endif /* TARGET_OS_MAC */
224 #endif /* kc_30_xara_item_helpers_h */