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-key-helpers.h"
27 #ifndef kc_30_xara_key_helpers_h
28 #define kc_30_xara_key_helpers_h
32 static void makeCustomKeyWithIntegrity(const char* name
, SecKeychainRef kc
, CFStringRef label
, CFStringRef expectedHash
) {
33 SecKeyRef key
= makeCustomKey(name
, kc
, label
);
34 checkIntegrityHash(name
, (SecKeychainItemRef
) key
, expectedHash
);
35 checkPartitionIDs(name
, (SecKeychainItemRef
) key
, 1);
38 #define makeCustomKeyWithIntegrityTests (makeCustomKeyTests + checkIntegrityHashTests + checkPartitionIDsTests)
40 static void makeKeyWithIntegrity(const char* name
, SecKeychainRef kc
, CFStringRef expectedHash
) {
41 makeCustomKeyWithIntegrity(name
, kc
, CFSTR("test_key"), expectedHash
);
43 #define makeKeyWithIntegrityTests makeCustomKeyWithIntegrityTests
45 // Note that this is nearly useless, as key pairs will never have stable hashes
46 static void makeKeyPairWithIntegrity(const char* name
, SecKeychainRef kc
, CFStringRef expectedPubHash
, CFStringRef expectedPrivHash
) {
49 makeKeyPair(name
, kc
, &pub
, &priv
);
51 checkIntegrityHash(name
, (SecKeychainItemRef
) pub
, expectedPubHash
);
52 checkIntegrityHash(name
, (SecKeychainItemRef
) priv
, expectedPrivHash
);
54 #define makeKeyPairWithIntegrityTests (makeKeyTests + checkIntegrityHashTests)
56 // And now for the actual tests
58 static void testAddKey(CFStringRef expectedHash
) {
59 char* name
= "testAddKey";
60 SecKeychainRef kc
= newKeychain(name
);
61 makeKeyWithIntegrity(name
, kc
, expectedHash
);
62 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
65 #define testAddKeyTests (newKeychainTests + makeKeyWithIntegrityTests + 1)
67 static void testAddFreeKey(CFStringRef expectedHash
) {
68 // Due to <rdar://problem/8431281> SecItemAdd() will not add a generated symmetric key to the keychain
69 // we can't actually run this test. Code is included here as a reference.
70 //char* name = "testAddFreeKey";
71 //SecKeychainRef kc = newKeychain(name);
73 //SecKeyRef key = makeFreeKey(name, kc);
74 //checkIntegrityHash(name, (SecKeychainItemRef) key, expectedHash);
76 //ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
79 //#define testAddFreeKeyTests (newKeychainTests + makeFreeKeyTests + checkIntegrityHashTests + 1)
80 #define testAddFreeKeyTests 0
82 static void testCopyMatchingKey(CFStringRef expectedHash
) {
83 char* name
= "testCopyMatchingKey";
84 secnotice("integrity", "************************************* %s", name
);
86 SecKeychainRef kc
= newKeychain(name
);
87 checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 0);
89 makeKeyWithIntegrity(name
, kc
, expectedHash
);
91 SecKeyRef item
= (SecKeyRef
) checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
92 checkIntegrityHash(name
, (SecKeychainItemRef
) item
, expectedHash
);
93 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
96 #define testCopyMatchingKeyTests (newKeychainTests + checkNTests + makeKeyWithIntegrityTests + checkNTests + checkIntegrityHashTests + 1)
99 static void testUpdateKey(CFStringRef expectedHash
, CFStringRef expectedHashAfter
) {
100 char * name
= "testUpdateKey";
101 secnotice("integrity", "************************************* %s", name
);
103 SecKeychainRef kc
= newKeychain(name
);
104 makeKeyWithIntegrity(name
, kc
, expectedHash
);
105 SecKeychainItemRef item
= checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
108 CFStringRef label
= CFSTR("a modified label");
110 CFMutableDictionaryRef query
= makeQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
);
111 CFMutableDictionaryRef update
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
112 CFDictionarySetValue(update
, kSecAttrLabel
, label
);
113 ok_status(SecItemUpdate(query
, update
), "%s: SecItemUpdate", name
);
115 CFReleaseNull(query
);
116 CFReleaseNull(update
);
118 // Find the item again.
119 query
= makeQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
);
120 CFDictionarySetValue(query
, kSecAttrLabel
, label
);
121 item
= checkN(name
, query
, 1);
122 checkIntegrityHash(name
, item
, expectedHashAfter
);
123 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
126 #define testUpdateKeyTests (newKeychainTests + makeKeyWithIntegrityTests + checkNTests + 1 + checkNTests + checkIntegrityHashTests + 1)
128 // Key Pairs have non-predictable hashes, since they receive an attribute kSecKeyLabel that is
129 // the hash of the public key. Since the key is generated randomly, so is the label.
131 // We can't do our normal "add", "copymatching", "update" tests here, so do
132 // something special...
134 static void testKeyPair() {
135 char* name
= "testKeyPair";
136 secnotice("integrity", "************************************* %s", name
);
138 SecKeychainRef kc
= newKeychain(name
);
139 checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 0);
140 checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 0);
144 makeKeyPair(name
, kc
, &pub
, &priv
);
146 // Now that we have the key pair, make sure we can pull the individual keys
147 // out (and the hashes match)
149 CFStringRef label
= CFSTR("a modified label");
150 CFMutableDictionaryRef query
;
151 CFMutableDictionaryRef update
;
153 // Ensure that the public key still exists and can be updated
156 item
= (SecKeyRef
) checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 1);
157 checkHashesMatch(name
, (SecKeychainItemRef
)pub
, (SecKeychainItemRef
)item
);
159 query
= makeQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
);
160 CFDictionarySetValue(query
, kSecAttrLabel
, label
);
161 item
= (SecKeyRef
) checkN(name
, query
, 0);
163 query
= makeQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
);
164 update
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
165 CFDictionarySetValue(update
, kSecAttrLabel
, label
);
166 ok_status(SecItemUpdate(query
, update
), "%s: SecItemUpdate (public key)", name
);
168 query
= makeQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
);
169 CFDictionarySetValue(query
, kSecAttrLabel
, label
);
170 item
= (SecKeyRef
) checkN(name
, query
, 1);
173 // Ensure that the private key still exists and can be updated
175 item
= (SecKeyRef
) checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
176 checkHashesMatch(name
, (SecKeychainItemRef
)priv
, (SecKeychainItemRef
)item
);
178 query
= makeQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
);
179 CFDictionarySetValue(query
, kSecAttrLabel
, label
);
180 item
= (SecKeyRef
) checkN(name
, query
, 0);
182 query
= makeQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
);
183 update
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
184 CFDictionarySetValue(update
, kSecAttrLabel
, label
);
185 ok_status(SecItemUpdate(query
, update
), "%s: SecItemUpdate (private key)", name
);
187 query
= makeQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
);
188 CFDictionarySetValue(query
, kSecAttrLabel
, label
);
189 item
= (SecKeyRef
) checkN(name
, query
, 1);
192 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
195 #define testKeyPairTests (newKeychainTests + checkNTests + checkNTests + makeKeyPairTests \
196 + checkNTests + checkHashesMatchTests \
197 + checkNTests + 1 + checkNTests \
198 + checkNTests + checkHashesMatchTests \
199 + checkNTests + 1 + checkNTests \
202 static void testAddDuplicateKey(CFStringRef expectedHash
) {
203 char * name
= "testAddDuplicateKey";
204 secnotice("integrity", "************************************* %s", name
);
206 SecKeychainRef kc
= newKeychain(name
);
207 checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 0);
209 makeKeyWithIntegrity(name
, kc
, expectedHash
);
211 SecKeychainItemRef item
= checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
212 makeDuplicateKey(name
, kc
);
213 checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
215 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
218 #define testAddDuplicateKeyTests (newKeychainTests + checkNTests +makeKeyWithIntegrityTests + checkNTests + makeDuplicateKeyTests + checkNTests + 1)
220 static void testAddDuplicateFreeKey(CFStringRef expectedHash
) {
221 // Due to <rdar://problem/8431281> SecItemAdd() will not add a generated symmetric key to the keychain
222 // we can't actually run this test. Code is included here as a reference.
223 //char * name = "testAddDuplicateFreeKey";
224 //secnotice("integrity", "************************************* %s", name);
225 //SecKeychainRef kc = newKeychain(name);
226 //checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
228 //SecKeyRef key = makeFreeKey(name, kc);
229 //checkIntegrityHash(name, (SecKeychainItemRef) key, expectedHash);
230 //SecKeychainItemRef item = checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
232 //makeDuplicateFreeKey(name, kc);
233 //checkN(name, makeQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
235 //ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
238 //#define testAddDuplicateFreeKeyTests (newKeychainTests + checkNTests + makeFreeKeyTests + checkIntegrityHashTests + checkNTests \
239 // + makeDuplicateKeyTests + checkNTests + 1)
240 #define testAddDuplicateFreeKeyTests 0
242 // testAddDuplicateKeyPair:
244 // By use of the Sec* APIs, you will almost certainly never get an
245 // errSecDuplicateItem out of SecKeychainGeneratePair. Since it sets a primary
246 // key attribute as the hash of the public key, it just will never generate a
249 static void testExportImportKeyPair() {
250 char* name
= "testExportImportKeyPair";
251 secnotice("integrity", "************************************* %s", name
);
253 SecKeychainRef kc
= newKeychain(name
);
254 checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 0);
255 checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 0);
259 makeKeyPair(name
, kc
, &pub
, &priv
);
261 // Now that we have the key pair, make sure we can pull the individual keys out
264 item
= (SecKeyRef
) checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 1);
265 checkHashesMatch(name
, (SecKeychainItemRef
)pub
, (SecKeychainItemRef
)item
);
267 item
= (SecKeyRef
) checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
268 checkHashesMatch(name
, (SecKeychainItemRef
)priv
, (SecKeychainItemRef
)item
);
270 CFMutableArrayRef applications
= (CFMutableArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeArrayCallBacks
);
271 SecTrustedApplicationRef app
= NULL
;
273 ok_status(SecTrustedApplicationCreateFromPath(NULL
, &app
), "%s: SecTrustedApplicationCreateFromPath", name
);
274 CFArrayAppendValue(applications
, app
);
276 ok_status(SecTrustedApplicationCreateFromPath("/usr/bin/codesign", &app
), "%s: SecTrustedApplicationCreateFromPath", name
);
277 CFArrayAppendValue(applications
, app
);
279 SecAccessRef accessRef
= NULL
;
280 ok_status(SecAccessCreate(CFSTR("accessDescription"), applications
, &accessRef
), "%s: SecAccessCreate", name
);
282 const SecItemImportExportKeyParameters keyParams
=
284 SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION
,
291 CFArrayRef items
= NULL
;
293 CFDataRef keyData
= NULL
;
294 ok_status(SecItemExport(pub
, kSecFormatPEMSequence
, kSecItemPemArmour
, &keyParams
, &keyData
), "%s: SecItemExport", name
);
295 ok_status(SecKeychainItemDelete((SecKeychainItemRef
)pub
), "%s: SecKeychainItemDelete", name
);;
299 checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 0);
300 ok_status(SecItemImport(keyData
, NULL
, NULL
, NULL
, kSecItemPemArmour
, &keyParams
, kc
, &items
), "%s: SecItemImport", name
);
301 checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 1);
304 ok_status(SecItemExport(priv
, kSecFormatPEMSequence
, kSecItemPemArmour
, &keyParams
, &keyData
), "%s: SecItemExport", name
);
305 ok_status(SecKeychainItemDelete((SecKeychainItemRef
)priv
), "%s: SecKeychainItemDelete", name
);;
309 checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 0);
311 ok_status(SecItemImport(keyData
, NULL
, NULL
, NULL
, kSecItemPemArmour
, &keyParams
, kc
, &items
), "%s: SecItemImport", name
);
313 checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
315 SecAccessRef newRef
= NULL
;
316 ok_status(SecKeychainItemCopyAccess((SecKeychainItemRef
) CFArrayGetValueAtIndex(items
, 0), &newRef
), "%s:SecKeychainItemCopyAccess", name
);
318 SecKeyRef importedKey
= items
&& CFArrayGetCount(items
) > 0 ? (SecKeyRef
)CFArrayGetValueAtIndex(items
, 0) : NULL
;
320 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
321 CFDictionaryAddValue(query
, kSecClass
, kSecClassKey
);
322 CFDictionaryAddValue(query
, kSecValueRef
, importedKey
);
324 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
325 CFDictionaryAddValue(attrs
, kSecAttrLabel
, CFSTR("private key custom label"));
327 ok_status( SecItemUpdate(query
, attrs
), "%s: SecItemUpdate", name
);
329 fail("%s: Didn't have an item to update", name
);
332 ok_status(SecKeychainItemCopyAccess((SecKeychainItemRef
) CFArrayGetValueAtIndex(items
, 0), &newRef
), "%s:SecKeychainItemCopyAccess", name
);
333 // TODO: should probably check this AccessRef object to make sure it's simple
335 checkN(name
, makeQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
337 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
340 #define testExportImportKeyPairTests (newKeychainTests + checkNTests + checkNTests + makeKeyPairTests \
341 + checkNTests + checkHashesMatchTests \
342 + checkNTests + checkHashesMatchTests \
343 + 5 + checkNTests + 1 + checkNTests \
344 + 2 + checkNTests + 1 + checkNTests + 1 + 1 + 1 + checkNTests\
350 #endif /* TARGET_OS_MAC */
353 #endif /* kc_30_xara_key_helpers_h */