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 #pragma clang diagnostic push
33 #pragma clang diagnostic ignored "-Wunused-variable"
34 #pragma clang diagnostic ignored "-Wunused-function"
36 static void makeCustomKeyWithIntegrity(const char* name
, SecKeychainRef kc
, CFStringRef label
, CFStringRef expectedHash
) {
37 SecKeyRef key
= createCustomKey(name
, kc
, label
);
38 checkIntegrityHash(name
, (SecKeychainItemRef
) key
, expectedHash
);
39 checkPartitionIDs(name
, (SecKeychainItemRef
) key
, 1);
42 #define makeCustomKeyWithIntegrityTests (createCustomKeyTests + checkIntegrityHashTests + checkPartitionIDsTests)
44 static void makeKeyWithIntegrity(const char* name
, SecKeychainRef kc
, CFStringRef expectedHash
) {
45 makeCustomKeyWithIntegrity(name
, kc
, CFSTR("test_key"), expectedHash
);
47 #define makeKeyWithIntegrityTests makeCustomKeyWithIntegrityTests
49 // Note that this is nearly useless, as key pairs will never have stable hashes
50 static void makeKeyPairWithIntegrity(const char* name
, SecKeychainRef kc
, CFStringRef expectedPubHash
, CFStringRef expectedPrivHash
) {
53 makeKeyPair(name
, kc
, &pub
, &priv
);
55 checkIntegrityHash(name
, (SecKeychainItemRef
) pub
, expectedPubHash
);
56 checkIntegrityHash(name
, (SecKeychainItemRef
) priv
, expectedPrivHash
);
58 #define makeKeyPairWithIntegrityTests (makeKeyTests + checkIntegrityHashTests)
60 // And now for the actual tests
62 static void testAddKey(CFStringRef expectedHash
) {
63 char* name
= "testAddKey";
64 SecKeychainRef kc
= newKeychain(name
);
65 makeKeyWithIntegrity(name
, kc
, expectedHash
);
66 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
69 #define testAddKeyTests (newKeychainTests + makeKeyWithIntegrityTests + 1)
71 static void testAddFreeKey(CFStringRef expectedHash
) {
72 // Due to <rdar://problem/8431281> SecItemAdd() will not add a generated symmetric key to the keychain
73 // we can't actually run this test. Code is included here as a reference.
74 //char* name = "testAddFreeKey";
75 //SecKeychainRef kc = newKeychain(name);
77 //SecKeyRef key = makeFreeKey(name, kc);
78 //checkIntegrityHash(name, (SecKeychainItemRef) key, expectedHash);
80 //ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
83 //#define testAddFreeKeyTests (newKeychainTests + makeFreeKeyTests + checkIntegrityHashTests + 1)
84 #define testAddFreeKeyTests 0
86 static void testCopyMatchingKey(CFStringRef expectedHash
) {
87 char* name
= "testCopyMatchingKey";
88 secnotice("integrity", "************************************* %s", name
);
90 SecKeychainRef kc
= newKeychain(name
);
91 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 0);
93 makeKeyWithIntegrity(name
, kc
, expectedHash
);
95 SecKeyRef item
= (SecKeyRef
) checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
96 checkIntegrityHash(name
, (SecKeychainItemRef
) item
, expectedHash
);
97 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
101 #define testCopyMatchingKeyTests (newKeychainTests + checkNTests + makeKeyWithIntegrityTests + checkNTests + checkIntegrityHashTests + 1)
104 static void testUpdateKey(CFStringRef expectedHash
, CFStringRef expectedHashAfter
) {
105 char * name
= "testUpdateKey";
106 secnotice("integrity", "************************************* %s", name
);
108 SecKeychainRef kc
= newKeychain(name
);
109 makeKeyWithIntegrity(name
, kc
, expectedHash
);
110 SecKeychainItemRef item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
113 CFStringRef label
= CFSTR("a modified label");
115 CFMutableDictionaryRef query
= createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
);
116 CFMutableDictionaryRef update
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
117 CFDictionarySetValue(update
, kSecAttrLabel
, label
);
118 ok_status(SecItemUpdate(query
, update
), "%s: SecItemUpdate", name
);
120 CFReleaseNull(query
);
121 CFReleaseNull(update
);
123 // Find the item again.
124 query
= createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
);
125 CFDictionarySetValue(query
, kSecAttrLabel
, label
);
126 item
= checkNCopyFirst(name
, query
, 1);
127 checkIntegrityHash(name
, item
, expectedHashAfter
);
128 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
131 #define testUpdateKeyTests (newKeychainTests + makeKeyWithIntegrityTests + checkNTests + 1 + checkNTests + checkIntegrityHashTests + 1)
133 // Key Pairs have non-predictable hashes, since they receive an attribute kSecKeyLabel that is
134 // the hash of the public key. Since the key is generated randomly, so is the label.
136 // We can't do our normal "add", "copymatching", "update" tests here, so do
137 // something special...
139 static void testKeyPair() {
140 char* name
= "testKeyPair";
141 secnotice("integrity", "************************************* %s", name
);
143 SecKeychainRef kc
= newKeychain(name
);
144 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 0);
145 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 0);
149 makeKeyPair(name
, kc
, &pub
, &priv
);
151 // Now that we have the key pair, make sure we can pull the individual keys
152 // out (and the hashes match)
154 CFStringRef label
= CFSTR("a modified label");
155 CFMutableDictionaryRef query
;
156 CFMutableDictionaryRef update
;
158 // Ensure that the public key still exists and can be updated
161 item
= (SecKeyRef
) checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 1);
162 checkHashesMatch(name
, (SecKeychainItemRef
)pub
, (SecKeychainItemRef
)item
);
164 query
= createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
);
165 CFDictionarySetValue(query
, kSecAttrLabel
, label
);
166 item
= (SecKeyRef
) checkNCopyFirst(name
, query
, 0);
168 query
= createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
);
169 update
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
170 CFDictionarySetValue(update
, kSecAttrLabel
, label
);
171 ok_status(SecItemUpdate(query
, update
), "%s: SecItemUpdate (public key)", name
);
173 query
= createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
);
174 CFDictionarySetValue(query
, kSecAttrLabel
, label
);
175 item
= (SecKeyRef
) checkNCopyFirst(name
, query
, 1);
178 // Ensure that the private key still exists and can be updated
180 item
= (SecKeyRef
) checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
181 checkHashesMatch(name
, (SecKeychainItemRef
)priv
, (SecKeychainItemRef
)item
);
183 query
= createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
);
184 CFDictionarySetValue(query
, kSecAttrLabel
, label
);
185 item
= (SecKeyRef
) checkNCopyFirst(name
, query
, 0);
187 query
= createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
);
188 update
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
189 CFDictionarySetValue(update
, kSecAttrLabel
, label
);
190 ok_status(SecItemUpdate(query
, update
), "%s: SecItemUpdate (private key)", name
);
192 query
= createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
);
193 CFDictionarySetValue(query
, kSecAttrLabel
, label
);
194 item
= (SecKeyRef
) checkNCopyFirst(name
, query
, 1);
197 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
200 #define testKeyPairTests (newKeychainTests + checkNTests + checkNTests + makeKeyPairTests \
201 + checkNTests + checkHashesMatchTests \
202 + checkNTests + 1 + checkNTests \
203 + checkNTests + checkHashesMatchTests \
204 + checkNTests + 1 + checkNTests \
207 static void testAddDuplicateKey(CFStringRef expectedHash
) {
208 char * name
= "testAddDuplicateKey";
209 secnotice("integrity", "************************************* %s", name
);
211 SecKeychainRef kc
= newKeychain(name
);
212 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 0);
214 makeKeyWithIntegrity(name
, kc
, expectedHash
);
216 SecKeychainItemRef item
= checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
217 makeDuplicateKey(name
, kc
);
218 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassSymmetric
), 1);
221 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
224 #define testAddDuplicateKeyTests (newKeychainTests + checkNTests +makeKeyWithIntegrityTests + checkNTests + makeDuplicateKeyTests + checkNTests + 1)
226 static void testAddDuplicateFreeKey(CFStringRef expectedHash
) {
227 // Due to <rdar://problem/8431281> SecItemAdd() will not add a generated symmetric key to the keychain
228 // we can't actually run this test. Code is included here as a reference.
229 //char * name = "testAddDuplicateFreeKey";
230 //secnotice("integrity", "************************************* %s", name);
231 //SecKeychainRef kc = newKeychain(name);
232 //checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 0);
234 //SecKeyRef key = makeFreeKey(name, kc);
235 //checkIntegrityHash(name, (SecKeychainItemRef) key, expectedHash);
236 //SecKeychainItemRef item = checkNCopyFirst(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
238 //makeDuplicateFreeKey(name, kc);
239 //checkN(name, createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric), 1);
241 //ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name);
244 //#define testAddDuplicateFreeKeyTests (newKeychainTests + checkNTests + makeFreeKeyTests + checkIntegrityHashTests + checkNTests \
245 // + makeDuplicateKeyTests + checkNTests + 1)
246 #define testAddDuplicateFreeKeyTests 0
248 // testAddDuplicateKeyPair:
250 // By use of the Sec* APIs, you will almost certainly never get an
251 // errSecDuplicateItem out of SecKeychainGeneratePair. Since it sets a primary
252 // key attribute as the hash of the public key, it just will never generate a
255 static void testExportImportKeyPair() {
256 char* name
= "testExportImportKeyPair";
257 secnotice("integrity", "************************************* %s", name
);
259 SecKeychainRef kc
= newKeychain(name
);
260 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 0);
261 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 0);
265 makeKeyPair(name
, kc
, &pub
, &priv
);
267 // Now that we have the key pair, make sure we can pull the individual keys out
270 item
= (SecKeyRef
) checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 1);
271 checkHashesMatch(name
, (SecKeychainItemRef
)pub
, (SecKeychainItemRef
)item
);
273 item
= (SecKeyRef
) checkNCopyFirst(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
274 checkHashesMatch(name
, (SecKeychainItemRef
)priv
, (SecKeychainItemRef
)item
);
276 CFMutableArrayRef applications
= (CFMutableArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeArrayCallBacks
);
277 SecTrustedApplicationRef app
= NULL
;
279 ok_status(SecTrustedApplicationCreateFromPath(NULL
, &app
), "%s: SecTrustedApplicationCreateFromPath", name
);
280 CFArrayAppendValue(applications
, app
);
282 ok_status(SecTrustedApplicationCreateFromPath("/usr/bin/codesign", &app
), "%s: SecTrustedApplicationCreateFromPath", name
);
283 CFArrayAppendValue(applications
, app
);
285 SecAccessRef accessRef
= NULL
;
286 ok_status(SecAccessCreate(CFSTR("accessDescription"), applications
, &accessRef
), "%s: SecAccessCreate", name
);
288 const SecItemImportExportKeyParameters keyParams
=
290 SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION
,
297 CFArrayRef items
= NULL
;
299 CFDataRef keyData
= NULL
;
300 ok_status(SecItemExport(pub
, kSecFormatPEMSequence
, kSecItemPemArmour
, &keyParams
, &keyData
), "%s: SecItemExport", name
);
301 ok_status(SecKeychainItemDelete((SecKeychainItemRef
)pub
), "%s: SecKeychainItemDelete", name
);;
305 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 0);
306 ok_status(SecItemImport(keyData
, NULL
, NULL
, NULL
, kSecItemPemArmour
, &keyParams
, kc
, &items
), "%s: SecItemImport", name
);
307 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPublic
), 1);
310 ok_status(SecItemExport(priv
, kSecFormatPEMSequence
, kSecItemPemArmour
, &keyParams
, &keyData
), "%s: SecItemExport", name
);
311 ok_status(SecKeychainItemDelete((SecKeychainItemRef
)priv
), "%s: SecKeychainItemDelete", name
);;
315 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 0);
317 ok_status(SecItemImport(keyData
, NULL
, NULL
, NULL
, kSecItemPemArmour
, &keyParams
, kc
, &items
), "%s: SecItemImport", name
);
319 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
321 SecAccessRef newRef
= NULL
;
322 ok_status(SecKeychainItemCopyAccess((SecKeychainItemRef
) CFArrayGetValueAtIndex(items
, 0), &newRef
), "%s:SecKeychainItemCopyAccess", name
);
324 SecKeyRef importedKey
= items
&& CFArrayGetCount(items
) > 0 ? (SecKeyRef
)CFArrayGetValueAtIndex(items
, 0) : NULL
;
326 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
327 CFDictionaryAddValue(query
, kSecClass
, kSecClassKey
);
328 CFDictionaryAddValue(query
, kSecValueRef
, importedKey
);
330 CFMutableDictionaryRef attrs
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
331 CFDictionaryAddValue(attrs
, kSecAttrLabel
, CFSTR("private key custom label"));
333 ok_status( SecItemUpdate(query
, attrs
), "%s: SecItemUpdate", name
);
335 fail("%s: Didn't have an item to update", name
);
338 ok_status(SecKeychainItemCopyAccess((SecKeychainItemRef
) CFArrayGetValueAtIndex(items
, 0), &newRef
), "%s:SecKeychainItemCopyAccess", name
);
339 // TODO: should probably check this AccessRef object to make sure it's simple
341 checkN(name
, createQueryKeyDictionary(kc
, kSecAttrKeyClassPrivate
), 1);
343 ok_status(SecKeychainDelete(kc
), "%s: SecKeychainDelete", name
);
346 #define testExportImportKeyPairTests (newKeychainTests + checkNTests + checkNTests + makeKeyPairTests \
347 + checkNTests + checkHashesMatchTests \
348 + checkNTests + checkHashesMatchTests \
349 + 5 + checkNTests + 1 + checkNTests \
350 + 2 + checkNTests + 1 + checkNTests + 1 + 1 + 1 + checkNTests\
353 #pragma clang diagnostic pop
357 #endif /* TARGET_OS_MAC */
360 #endif /* kc_30_xara_key_helpers_h */