2 * Copyright (c) 2016 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 #ifndef kc_key_helpers_h
25 #define kc_key_helpers_h
27 #include "kc-helpers.h"
28 #include "utilities/SecCFRelease.h"
32 #pragma clang diagnostic push
33 #pragma clang diagnostic ignored "-Wunused-variable"
34 #pragma clang diagnostic ignored "-Wunused-function"
36 static CFMutableDictionaryRef
makeBaseKeyDictionary() {
37 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
38 CFDictionarySetValue(query
, kSecClass
, kSecClassKey
);
42 static CFMutableDictionaryRef
createQueryKeyDictionary(SecKeychainRef kc
, CFStringRef keyClass
) {
43 CFMutableDictionaryRef query
= makeBaseKeyDictionary();
45 CFMutableArrayRef searchList
= (CFMutableArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeArrayCallBacks
);
46 CFArrayAppendValue((CFMutableArrayRef
)searchList
, kc
);
47 CFDictionarySetValue(query
, kSecMatchSearchList
, searchList
);
49 CFDictionarySetValue(query
, kSecAttrKeyClass
, keyClass
);
51 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
55 static CFMutableDictionaryRef
createQueryKeyDictionaryWithLabel(SecKeychainRef kc
, CFStringRef keyClass
, CFStringRef label
) {
56 CFMutableDictionaryRef query
= createQueryKeyDictionary(kc
, keyClass
);
57 CFDictionarySetValue(query
, kSecAttrLabel
, label
);
61 static CFMutableDictionaryRef
createAddKeyDictionaryWithApplicationLabel(SecKeychainRef kc
, CFStringRef keyClass
, CFStringRef label
, CFStringRef applicationLabel
) {
62 CFMutableDictionaryRef query
= makeBaseKeyDictionary();
63 CFDictionaryAddValue(query
, kSecUseKeychain
, kc
);
65 CFDictionarySetValue(query
, kSecAttrLabel
, label
);
66 if(applicationLabel
) {
67 CFDictionarySetValue(query
, kSecAttrApplicationLabel
, applicationLabel
);
69 CFDictionarySetValue(query
, kSecAttrApplicationLabel
, CFSTR("test_application")); // without setting this, it uses the current datetime.
73 if(CFEqual(keyClass
, kSecAttrKeyClassSymmetric
)) {
74 CFDictionarySetValue(query
, kSecAttrKeyType
, kSecAttrKeyTypeAES
);
76 } else if(CFEqual(keyClass
, kSecAttrKeyClassPublic
) ||
77 CFEqual(keyClass
, kSecAttrKeyClassPrivate
)) {
78 CFDictionarySetValue(query
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
81 CFNumberRef num
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &n
);
82 CFDictionarySetValue(query
, kSecAttrKeySizeInBits
, num
);
87 static CFMutableDictionaryRef
createAddKeyDictionary(SecKeychainRef kc
, CFStringRef keyClass
, CFStringRef label
) {
88 return createAddKeyDictionaryWithApplicationLabel(kc
, keyClass
, label
, NULL
);
91 static SecKeyRef
createCustomKeyWithApplicationLabel(const char* name
, SecKeychainRef kc
, CFStringRef label
, CFStringRef applicationLabel
) {
92 CFMutableDictionaryRef query
= createAddKeyDictionaryWithApplicationLabel(kc
, kSecAttrKeyClassSymmetric
, label
, applicationLabel
);
94 CFErrorRef error
= NULL
;
95 SecKeyRef item
= SecKeyGenerateSymmetric(query
, &error
);
96 ok(item
!= NULL
, "%s: SecKeyGenerateSymmetric: %ld", name
, error
? CFErrorGetCode(error
) : 0);
101 #define createCustomKeyWithApplicationLabelTests 1
103 static SecKeyRef
createCustomKey(const char* name
, SecKeychainRef kc
, CFStringRef label
) {
104 return createCustomKeyWithApplicationLabel(name
, kc
, label
, NULL
);
106 #define createCustomKeyTests createCustomKeyWithApplicationLabelTests
108 static SecKeyRef
makeKey(const char* name
, SecKeychainRef kc
) {
109 return createCustomKey(name
, kc
, CFSTR("test_key"));
111 #define makeKeyTests createCustomKeyTests
113 static void makeCustomKeyPair(const char* name
, SecKeychainRef kc
, CFStringRef label
, SecKeyRef
* aPub
, SecKeyRef
* aPriv
) {
114 CFMutableDictionaryRef query
= createAddKeyDictionary(kc
, kSecAttrKeyClassPublic
, label
);
118 ok_status(SecKeyGeneratePair(query
, &pub
, &priv
), "%s: SecKeyGeneratePair returned a result", name
);
127 CFReleaseNull(query
);
129 #define makeCustomKeyPairTests 1
131 static void makeKeyPair(const char* name
, SecKeychainRef kc
, SecKeyRef
* aPub
, SecKeyRef
* aPriv
) {
132 makeCustomKeyPair(name
, kc
, CFSTR("test_key"), aPub
, aPriv
);
134 #define makeKeyPairTests makeCustomKeyPairTests
136 // This only works for symmetric keys; key pairs cannot ever generate a duplicate (due to setting kSecKeyLabel to the hash of the public key)
137 static void makeCustomDuplicateKey(const char* name
, SecKeychainRef kc
, CFStringRef label
) {
138 CFMutableDictionaryRef query
;
140 query
= createAddKeyDictionary(kc
, kSecAttrKeyClassSymmetric
, label
);
141 CFErrorRef error
= NULL
;
142 CFReleaseSafe(SecKeyGenerateSymmetric(query
, &error
));
143 is(CFErrorGetCode(error
), errSecDuplicateItem
, "%s: SecKeyGenerateSymmetric (duplicate) errored: %ld", name
, error
? CFErrorGetCode(error
) : -1);
145 CFReleaseNull(query
);
147 #define makeCustomDuplicateKeyTests 1
149 static void makeDuplicateKey(const char* name
, SecKeychainRef kc
) {
150 makeCustomDuplicateKey(name
, kc
, CFSTR("test_key"));
152 #define makeDuplicateKeyTests makeCustomDuplicateKeyTests
154 static SecKeyRef
makeCustomFreeKey(const char* name
, SecKeychainRef kc
, CFStringRef label
) {
157 ok_status(SecKeyGenerate(
160 0, /* contextHandle */
161 CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
,
162 CSSM_KEYATTR_EXTRACTABLE
,
163 NULL
, /* initialAccess */
164 &symkey
), "%s: SecKeyGenerate", name
);;
166 CFMutableDictionaryRef query
= createAddKeyDictionary(kc
, kSecAttrKeyClassSymmetric
, label
);
168 CFMutableArrayRef itemList
= (CFMutableArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeArrayCallBacks
);
169 CFArrayAppendValue((CFMutableArrayRef
)itemList
, symkey
);
171 CFDictionarySetValue(query
, kSecUseItemList
, itemList
);
173 CFTypeRef result
= NULL
;
174 ok_status(SecItemAdd(query
, &result
), "%s: SecItemAdd", name
);
175 ok(result
!= NULL
, "%s: SecItemAdd returned a result", name
);
176 CFReleaseNull(symkey
);
177 return (SecKeyRef
) result
;
179 #define makeCustomFreeKeyTests 3
181 static SecKeyRef
makeFreeKey(const char* name
, SecKeychainRef kc
) {
182 return makeCustomFreeKey(name
, kc
, CFSTR("test_free_key"));
184 #define makeFreeKeyTests makeCustomFreeKeyTests
186 static SecKeyRef
makeCustomDuplicateFreeKey(const char* name
, SecKeychainRef kc
, CFStringRef label
) {
189 ok_status(SecKeyGenerate(
192 0, /* contextHandle */
193 CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
,
194 CSSM_KEYATTR_EXTRACTABLE
,
195 NULL
, /* initialAccess */
196 &symkey
), "%s: SecKeyGenerate", name
);;
198 CFMutableDictionaryRef query
= createAddKeyDictionary(kc
, kSecAttrKeyClassSymmetric
, label
);
200 CFMutableArrayRef itemList
= (CFMutableArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeArrayCallBacks
);
201 CFArrayAppendValue((CFMutableArrayRef
)itemList
, symkey
);
203 CFDictionarySetValue(query
, kSecUseItemList
, itemList
);
205 CFTypeRef result
= NULL
;
206 is(SecItemAdd(query
, &result
), errSecDuplicateItem
, "%s: SecItemAdd (duplicate)", name
);
207 CFReleaseNull(symkey
);
208 return (SecKeyRef
) result
;
210 #define makeCustomDuplicateFreeKeyTests 2
212 static SecKeyRef
makeDuplicateFreeKey(const char* name
, SecKeychainRef kc
) {
213 return makeCustomFreeKey(name
, kc
, CFSTR("test_free_key"));
215 #define makeDuplicateFreeKeyTests makeCustomDuplicateFreeKeyTests
217 #define checkKeyUseTests 4
218 static void checkKeyUse(SecKeyRef key
, OSStatus expectedStatus
) {
219 CFStringRef plaintext
= CFSTR("A short story: the string goes into the encryptor, and returns unrecognizable. The decryptor reverses.");
220 CFDataRef plaintextData
= CFDataCreate(NULL
, (uint8_t*) CFStringGetCStringPtr(plaintext
, kCFStringEncodingUTF8
), CFStringGetLength(plaintext
));
223 SecTransformRef transform
= SecEncryptTransformCreate(key
, NULL
);
224 SecTransformSetAttribute(transform
, kSecPaddingKey
, kSecPaddingPKCS7Key
, NULL
);
225 SecTransformSetAttribute(transform
, kSecEncryptionMode
, kSecModeCBCKey
, NULL
);
226 SecTransformSetAttribute(transform
, kSecTransformInputAttributeName
, plaintextData
, NULL
);
228 CFErrorRef error
= NULL
;
229 CFDataRef ciphertextData
= SecTransformExecute(transform
, &error
);
230 CFDataRef roundtripData
= NULL
;
233 CFStringRef errorStr
= CFErrorCopyDescription(error
);
234 is(CFErrorGetCode(error
), expectedStatus
, "%s: Encrypting data failed: %d %s (and expected %d)", testName
, (int) CFErrorGetCode(error
), CFStringGetCStringPtr(errorStr
, kCFStringEncodingUTF8
), (int) expectedStatus
);
235 CFReleaseSafe(errorStr
);
237 if(expectedStatus
!= errSecSuccess
) {
238 // make test numbers match and quit
239 for(int i
= 1; i
< checkKeyUseTests
; i
++) {
240 pass("test numbers match");
246 pass("%s: transform executed", testName
);
249 CFReleaseSafe(transform
);
251 /* and now decrypt */
252 transform
= SecDecryptTransformCreate(key
, NULL
);
253 SecTransformSetAttribute(transform
, kSecPaddingKey
, kSecPaddingPKCS7Key
, NULL
);
254 SecTransformSetAttribute(transform
, kSecEncryptionMode
, kSecModeCBCKey
, NULL
);
255 SecTransformSetAttribute(transform
, kSecTransformInputAttributeName
, ciphertextData
, NULL
);
257 roundtripData
= SecTransformExecute(transform
, &error
);
258 is(error
, NULL
, "%s: checkKeyUse: SecTransformExecute (decrypt)", testName
);
261 CFStringRef errorStr
= CFErrorCopyDescription(error
);
262 fail("%s: Decrypting data failed: %d %s", testName
, (int) CFErrorGetCode(error
), CFStringGetCStringPtr(errorStr
, kCFStringEncodingUTF8
));
263 CFReleaseSafe(errorStr
);
265 pass("%s: make test numbers match", testName
);
268 eq_cf(plaintextData
, roundtripData
, "%s: checkKeyUse: roundtripped data is input data", testName
);
271 CFReleaseSafe(transform
);
272 CFReleaseSafe(plaintext
);
273 CFReleaseSafe(plaintextData
);
274 CFReleaseSafe(ciphertextData
);
275 CFReleaseSafe(roundtripData
);
280 #pragma clang diagnostic pop
284 #endif /* TARGET_OS_MAC */
287 #endif /* kc_key_helpers_h */