]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
5c19dc3a | 2 | * Copyright (c) 2006-2015 Apple Inc. All Rights Reserved. |
427c49bc | 3 | * |
b1ab9ed8 | 4 | * @APPLE_LICENSE_HEADER_START@ |
5c19dc3a | 5 | * |
b1ab9ed8 A |
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 | |
11 | * file. | |
5c19dc3a | 12 | * |
b1ab9ed8 A |
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. | |
5c19dc3a | 20 | * |
b1ab9ed8 A |
21 | * @APPLE_LICENSE_HEADER_END@ |
22 | */ | |
23 | ||
427c49bc | 24 | /* |
b1ab9ed8 A |
25 | * SecKey.c - CoreFoundation based key object |
26 | */ | |
27 | ||
28 | ||
29 | #include <Security/SecKeyInternal.h> | |
30 | #include <Security/SecItem.h> | |
31 | #include <Security/SecItemPriv.h> | |
fa7225c8 | 32 | #include <Security/SecItemShim.h> |
b1ab9ed8 A |
33 | #include <Security/SecFramework.h> |
34 | ||
427c49bc A |
35 | #include <utilities/SecIOFormat.h> |
36 | ||
37 | #include <utilities/SecCFWrappers.h> | |
fa7225c8 | 38 | #include <utilities/array_size.h> |
427c49bc | 39 | |
b1ab9ed8 | 40 | #include "SecRSAKeyPriv.h" |
d8f41ccd | 41 | #include "SecECKeyPriv.h" |
5c19dc3a | 42 | #include "SecCTKKeyPriv.h" |
b1ab9ed8 A |
43 | #include "SecBasePriv.h" |
44 | ||
45 | #include <CoreFoundation/CFNumber.h> | |
46 | #include <CoreFoundation/CFString.h> | |
427c49bc | 47 | #include <Security/SecBase.h> |
b1ab9ed8 A |
48 | #include <pthread.h> |
49 | #include <string.h> | |
50 | #include <AssertMacros.h> | |
427c49bc A |
51 | #include <utilities/debugging.h> |
52 | #include <utilities/SecCFError.h> | |
b1ab9ed8 A |
53 | #include <CommonCrypto/CommonDigest.h> |
54 | #include <Security/SecAsn1Coder.h> | |
55 | #include <Security/oidsalg.h> | |
56 | #include <Security/SecInternal.h> | |
57 | #include <Security/SecRandom.h> | |
fa7225c8 A |
58 | #include <Security/SecureTransport.h> /* For error codes. */ |
59 | ||
b1ab9ed8 | 60 | #include <corecrypto/ccrng_system.h> |
fa7225c8 | 61 | |
b1ab9ed8 | 62 | #include <asl.h> |
427c49bc | 63 | #include <stdlib.h> |
5c19dc3a A |
64 | #include <syslog.h> |
65 | ||
66 | #include <libDER/asn1Types.h> | |
67 | #include <libDER/DER_Keys.h> | |
68 | #include <libDER/DER_Encode.h> | |
69 | ||
5c19dc3a | 70 | CFDataRef SecKeyCopyPublicKeyHash(SecKeyRef key) |
427c49bc A |
71 | { |
72 | CFDataRef pubKeyDigest = NULL, pubKeyBlob = NULL; | |
73 | ||
74 | /* encode the public key. */ | |
fa7225c8 A |
75 | require_noerr_quiet(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut); |
76 | require_quiet(pubKeyBlob, errOut); | |
5c19dc3a | 77 | |
427c49bc | 78 | /* Calculate the digest of the public key. */ |
fa7225c8 A |
79 | require_quiet(pubKeyDigest = SecSHA1DigestCreate(CFGetAllocator(key), |
80 | CFDataGetBytePtr(pubKeyBlob), CFDataGetLength(pubKeyBlob)), | |
427c49bc A |
81 | errOut); |
82 | errOut: | |
83 | CFReleaseNull(pubKeyBlob); | |
84 | return pubKeyDigest; | |
85 | } | |
86 | ||
87 | ||
b1ab9ed8 A |
88 | /* |
89 | */ | |
d8f41ccd A |
90 | static CFDictionaryRef SecKeyCopyAttributeDictionaryWithLocalKey(SecKeyRef key, |
91 | CFTypeRef keyType, | |
92 | CFDataRef privateBlob) | |
b1ab9ed8 A |
93 | { |
94 | CFAllocatorRef allocator = CFGetAllocator(key); | |
95 | DICT_DECLARE(25); | |
96 | CFDataRef pubKeyDigest = NULL, pubKeyBlob = NULL; | |
97 | CFDictionaryRef dict = NULL; | |
5c19dc3a | 98 | |
b1ab9ed8 A |
99 | size_t sizeValue = SecKeyGetSize(key, kSecKeyKeySizeInBits); |
100 | CFNumberRef sizeInBits = CFNumberCreate(allocator, kCFNumberLongType, &sizeValue); | |
5c19dc3a | 101 | |
b1ab9ed8 | 102 | /* encode the public key. */ |
fa7225c8 A |
103 | require_noerr_quiet(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut); |
104 | require_quiet(pubKeyBlob, errOut); | |
5c19dc3a | 105 | |
b1ab9ed8 | 106 | /* Calculate the digest of the public key. */ |
fa7225c8 A |
107 | require_quiet(pubKeyDigest = SecSHA1DigestCreate(allocator, |
108 | CFDataGetBytePtr(pubKeyBlob), CFDataGetLength(pubKeyBlob)), | |
109 | errOut); | |
5c19dc3a | 110 | |
b1ab9ed8 A |
111 | DICT_ADDPAIR(kSecClass, kSecClassKey); |
112 | DICT_ADDPAIR(kSecAttrKeyClass, privateBlob ? kSecAttrKeyClassPrivate : kSecAttrKeyClassPublic); | |
113 | DICT_ADDPAIR(kSecAttrApplicationLabel, pubKeyDigest); | |
114 | DICT_ADDPAIR(kSecAttrIsPermanent, kCFBooleanTrue); | |
115 | DICT_ADDPAIR(kSecAttrIsPrivate, kCFBooleanTrue); | |
116 | DICT_ADDPAIR(kSecAttrIsModifiable, kCFBooleanTrue); | |
117 | DICT_ADDPAIR(kSecAttrKeyType, keyType); | |
118 | DICT_ADDPAIR(kSecAttrKeySizeInBits, sizeInBits); | |
119 | DICT_ADDPAIR(kSecAttrEffectiveKeySize, sizeInBits); | |
120 | DICT_ADDPAIR(kSecAttrIsSensitive, kCFBooleanFalse); | |
121 | DICT_ADDPAIR(kSecAttrWasAlwaysSensitive, kCFBooleanFalse); | |
122 | DICT_ADDPAIR(kSecAttrIsExtractable, kCFBooleanTrue); | |
123 | DICT_ADDPAIR(kSecAttrWasNeverExtractable, kCFBooleanFalse); | |
fa7225c8 A |
124 | DICT_ADDPAIR(kSecAttrCanEncrypt, privateBlob ? kCFBooleanFalse : kCFBooleanTrue); |
125 | DICT_ADDPAIR(kSecAttrCanDecrypt, privateBlob ? kCFBooleanTrue : kCFBooleanFalse); | |
b1ab9ed8 | 126 | DICT_ADDPAIR(kSecAttrCanDerive, kCFBooleanTrue); |
fa7225c8 A |
127 | DICT_ADDPAIR(kSecAttrCanSign, privateBlob ? kCFBooleanTrue : kCFBooleanFalse); |
128 | DICT_ADDPAIR(kSecAttrCanVerify, privateBlob ? kCFBooleanFalse : kCFBooleanTrue); | |
b1ab9ed8 A |
129 | DICT_ADDPAIR(kSecAttrCanSignRecover, kCFBooleanFalse); |
130 | DICT_ADDPAIR(kSecAttrCanVerifyRecover, kCFBooleanFalse); | |
fa7225c8 A |
131 | DICT_ADDPAIR(kSecAttrCanWrap, privateBlob ? kCFBooleanFalse : kCFBooleanTrue); |
132 | DICT_ADDPAIR(kSecAttrCanUnwrap, privateBlob ? kCFBooleanTrue : kCFBooleanFalse); | |
b1ab9ed8 A |
133 | DICT_ADDPAIR(kSecValueData, privateBlob ? privateBlob : pubKeyBlob); |
134 | dict = DICT_CREATE(allocator); | |
5c19dc3a | 135 | |
b1ab9ed8 A |
136 | errOut: |
137 | // @@@ Zero out key material. | |
138 | CFReleaseSafe(pubKeyDigest); | |
139 | CFReleaseSafe(pubKeyBlob); | |
140 | CFReleaseSafe(sizeInBits); | |
5c19dc3a | 141 | |
b1ab9ed8 A |
142 | return dict; |
143 | } | |
144 | ||
145 | CFDictionaryRef SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key, | |
146 | CFTypeRef keyType, | |
147 | CFDataRef privateBlob) | |
148 | { | |
d8f41ccd | 149 | return SecKeyCopyAttributeDictionaryWithLocalKey(key, keyType, privateBlob); |
b1ab9ed8 A |
150 | } |
151 | ||
152 | CFDictionaryRef SecKeyGeneratePublicAttributeDictionary(SecKeyRef key, CFTypeRef keyType) | |
153 | { | |
d8f41ccd | 154 | return SecKeyCopyAttributeDictionaryWithLocalKey(key, keyType, NULL); |
b1ab9ed8 A |
155 | } |
156 | ||
427c49bc | 157 | static CFStringRef SecKeyCopyDescription(CFTypeRef cf) { |
b1ab9ed8 | 158 | SecKeyRef key = (SecKeyRef)cf; |
5c19dc3a | 159 | |
427c49bc A |
160 | if(key->key_class->describe) |
161 | return key->key_class->describe(key); | |
162 | else | |
5c19dc3a | 163 | return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecKeyRef: %p>"), key); |
b1ab9ed8 A |
164 | } |
165 | ||
166 | static void SecKeyDestroy(CFTypeRef cf) { | |
167 | SecKeyRef key = (SecKeyRef)cf; | |
fa7225c8 A |
168 | #if !TARGET_OS_IPHONE |
169 | CFReleaseSafe(key->cdsaKey); | |
170 | #endif | |
b1ab9ed8 A |
171 | if (key->key_class->destroy) |
172 | key->key_class->destroy(key); | |
173 | } | |
174 | ||
427c49bc A |
175 | static Boolean SecKeyEqual(CFTypeRef cf1, CFTypeRef cf2) |
176 | { | |
b1ab9ed8 A |
177 | SecKeyRef key1 = (SecKeyRef)cf1; |
178 | SecKeyRef key2 = (SecKeyRef)cf2; | |
179 | if (key1 == key2) | |
180 | return true; | |
181 | if (!key2 || key1->key_class != key2->key_class) | |
182 | return false; | |
fa7225c8 A |
183 | if (key1->key_class->version >= 4 && key1->key_class->isEqual) |
184 | return key1->key_class->isEqual(key1, key2); | |
b1ab9ed8 A |
185 | if (key1->key_class->extraBytes) |
186 | return !memcmp(key1->key, key2->key, key1->key_class->extraBytes); | |
5c19dc3a | 187 | |
b1ab9ed8 A |
188 | /* TODO: Won't work when we get reference keys. */ |
189 | CFDictionaryRef d1, d2; | |
190 | d1 = SecKeyCopyAttributeDictionary(key1); | |
191 | d2 = SecKeyCopyAttributeDictionary(key2); | |
fa7225c8 A |
192 | // Returning NULL is an error; bail out of the equality check |
193 | if(!d1 || !d2) { | |
194 | return false; | |
195 | } | |
b1ab9ed8 A |
196 | Boolean result = CFEqual(d1, d2); |
197 | CFReleaseSafe(d1); | |
198 | CFReleaseSafe(d2); | |
199 | return result; | |
200 | } | |
201 | ||
d8f41ccd | 202 | struct ccrng_state *ccrng_seckey; |
b1ab9ed8 | 203 | |
d8f41ccd A |
204 | CFGiblisWithFunctions(SecKey, NULL, NULL, SecKeyDestroy, SecKeyEqual, NULL, NULL, SecKeyCopyDescription, NULL, NULL, ^{ |
205 | static struct ccrng_system_state ccrng_system_state_seckey; | |
206 | ccrng_seckey = (struct ccrng_state *)&ccrng_system_state_seckey; | |
207 | ccrng_system_init(&ccrng_system_state_seckey); | |
208 | }) | |
b1ab9ed8 A |
209 | |
210 | static bool getBoolForKey(CFDictionaryRef dict, CFStringRef key, bool default_value) { | |
211 | CFTypeRef value = CFDictionaryGetValue(dict, key); | |
212 | if (value) { | |
213 | if (CFGetTypeID(value) == CFBooleanGetTypeID()) { | |
214 | return CFBooleanGetValue(value); | |
215 | } else { | |
216 | secwarning("Value %@ for key %@ is not bool", value, key); | |
217 | } | |
218 | } | |
5c19dc3a | 219 | |
b1ab9ed8 A |
220 | return default_value; |
221 | } | |
222 | ||
223 | static OSStatus add_ref(CFTypeRef item, CFMutableDictionaryRef dict) { | |
224 | CFDictionarySetValue(dict, kSecValueRef, item); | |
225 | return SecItemAdd(dict, NULL); | |
226 | } | |
227 | ||
228 | static void merge_params_applier(const void *key, const void *value, | |
229 | void *context) { | |
230 | CFMutableDictionaryRef result = (CFMutableDictionaryRef)context; | |
231 | CFDictionaryAddValue(result, key, value); | |
232 | } | |
233 | ||
234 | /* Create a mutable dictionary that is based on the subdictionary for key | |
235 | with any attributes from the top level dict merged in. */ | |
5c19dc3a A |
236 | static CF_RETURNS_RETAINED CFMutableDictionaryRef merge_params(CFDictionaryRef dict, |
237 | CFStringRef key) { | |
b1ab9ed8 A |
238 | CFDictionaryRef subdict = CFDictionaryGetValue(dict, key); |
239 | CFMutableDictionaryRef result; | |
5c19dc3a | 240 | |
b1ab9ed8 A |
241 | if (subdict) { |
242 | result = CFDictionaryCreateMutableCopy(NULL, 0, subdict); | |
243 | /* Add everything in dict not already in result to result. */ | |
244 | CFDictionaryApplyFunction(dict, merge_params_applier, result); | |
245 | } else { | |
246 | result = CFDictionaryCreateMutableCopy(NULL, 0, dict); | |
247 | } | |
5c19dc3a | 248 | |
b1ab9ed8 A |
249 | /* Remove values that only belong in the top level dict. */ |
250 | CFDictionaryRemoveValue(result, kSecPublicKeyAttrs); | |
251 | CFDictionaryRemoveValue(result, kSecPrivateKeyAttrs); | |
252 | CFDictionaryRemoveValue(result, kSecAttrKeyType); | |
253 | CFDictionaryRemoveValue(result, kSecAttrKeySizeInBits); | |
5c19dc3a | 254 | |
b1ab9ed8 A |
255 | return result; |
256 | } | |
257 | ||
5c19dc3a A |
258 | CFIndex SecKeyGetAlgorithmIdentifier(SecKeyRef key) { |
259 | if (!key || !key->key_class) { | |
260 | // TBD: somehow, a key can be created with a NULL key_class in the | |
261 | // SecCertificateCopyPublicKey -> SecKeyCreatePublicFromDER code path | |
262 | return kSecNullAlgorithmID; | |
263 | } | |
264 | /* This method was added to version 1 keys. */ | |
265 | if (key->key_class->version > 0 && key->key_class->getAlgorithmID) { | |
266 | return key->key_class->getAlgorithmID(key); | |
267 | } | |
fa7225c8 | 268 | /* All version 0 keys were RSA. */ |
5c19dc3a A |
269 | return kSecRSAAlgorithmID; |
270 | } | |
271 | ||
b1ab9ed8 A |
272 | /* Generate a private/public keypair. */ |
273 | OSStatus SecKeyGeneratePair(CFDictionaryRef parameters, | |
274 | SecKeyRef *publicKey, SecKeyRef *privateKey) { | |
275 | OSStatus result = errSecUnsupportedAlgorithm; | |
276 | SecKeyRef privKey = NULL; | |
277 | SecKeyRef pubKey = NULL; | |
278 | CFMutableDictionaryRef pubParams = merge_params(parameters, kSecPublicKeyAttrs), | |
427c49bc | 279 | privParams = merge_params(parameters, kSecPrivateKeyAttrs); |
b1ab9ed8 | 280 | CFStringRef ktype = CFDictionaryGetValue(parameters, kSecAttrKeyType); |
5c19dc3a A |
281 | CFStringRef tokenID = CFDictionaryGetValue(parameters, kSecAttrTokenID); |
282 | ||
fa7225c8 | 283 | require_quiet(ktype, errOut); |
5c19dc3a A |
284 | |
285 | if (tokenID != NULL) { | |
286 | result = SecCTKKeyGeneratePair(parameters, &pubKey, &privKey); | |
fa7225c8 | 287 | } else if (CFEqual(ktype, kSecAttrKeyTypeECSECPrimeRandom)) { |
b1ab9ed8 A |
288 | result = SecECKeyGeneratePair(parameters, &pubKey, &privKey); |
289 | } else if (CFEqual(ktype, kSecAttrKeyTypeRSA)) { | |
290 | result = SecRSAKeyGeneratePair(parameters, &pubKey, &privKey); | |
291 | } | |
5c19dc3a | 292 | |
fa7225c8 | 293 | require_noerr_quiet(result, errOut); |
5c19dc3a | 294 | |
b1ab9ed8 A |
295 | /* Store the keys in the keychain if they are marked as permanent. */ |
296 | if (getBoolForKey(pubParams, kSecAttrIsPermanent, false)) { | |
427c49bc | 297 | require_noerr_quiet(result = add_ref(pubKey, pubParams), errOut); |
b1ab9ed8 | 298 | } |
5c19dc3a A |
299 | /* Token-based private keys are automatically stored on the token. */ |
300 | if (tokenID == NULL && getBoolForKey(privParams, kSecAttrIsPermanent, false)) { | |
427c49bc | 301 | require_noerr_quiet(result = add_ref(privKey, privParams), errOut); |
b1ab9ed8 | 302 | } |
5c19dc3a | 303 | |
b1ab9ed8 A |
304 | if (publicKey) { |
305 | *publicKey = pubKey; | |
306 | pubKey = NULL; | |
307 | } | |
308 | if (privateKey) { | |
309 | *privateKey = privKey; | |
310 | privKey = NULL; | |
311 | } | |
5c19dc3a | 312 | |
b1ab9ed8 A |
313 | errOut: |
314 | CFReleaseSafe(pubParams); | |
315 | CFReleaseSafe(privParams); | |
316 | CFReleaseSafe(pubKey); | |
317 | CFReleaseSafe(privKey); | |
5c19dc3a | 318 | |
427c49bc A |
319 | return result; |
320 | } | |
b1ab9ed8 | 321 | |
427c49bc | 322 | SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey) { |
fa7225c8 | 323 | return SecKeyCopyPublicKey(privateKey); |
b1ab9ed8 A |
324 | } |
325 | ||
5c19dc3a | 326 | CFDictionaryRef CreatePrivateKeyMatchingQuery(SecKeyRef publicKey, bool returnPersistentRef) |
427c49bc | 327 | { |
5c19dc3a | 328 | const CFTypeRef refType = (returnPersistentRef) ? kSecReturnPersistentRef: kSecReturnRef; |
fa7225c8 | 329 | |
5c19dc3a A |
330 | CFDataRef public_key_hash = SecKeyCopyPublicKeyHash(publicKey); |
331 | ||
427c49bc A |
332 | CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, |
333 | kSecClass, kSecClassKey, | |
334 | kSecAttrKeyClass, kSecAttrKeyClassPrivate, | |
335 | kSecAttrSynchronizable, kSecAttrSynchronizableAny, | |
336 | kSecAttrApplicationLabel, public_key_hash, | |
5c19dc3a | 337 | refType, kCFBooleanTrue, |
427c49bc A |
338 | NULL); |
339 | CFReleaseNull(public_key_hash); | |
5c19dc3a | 340 | |
427c49bc A |
341 | return query; |
342 | } | |
343 | ||
344 | CFDataRef SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) { | |
345 | CFTypeRef persistentRef = NULL; | |
346 | CFDictionaryRef query = CreatePrivateKeyMatchingQuery(publicKey, true); | |
347 | ||
348 | require_quiet(SecError(SecItemCopyMatching(query, &persistentRef),error , | |
349 | CFSTR("Error finding persistent ref to key from public: %@"), publicKey), fail); | |
350 | fail: | |
351 | CFReleaseNull(query); | |
352 | return (CFDataRef)persistentRef; | |
353 | } | |
354 | ||
355 | SecKeyRef SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) { | |
5c19dc3a A |
356 | SecKeyRef privateKey = NULL; |
357 | CFTypeRef queryResult = NULL; | |
358 | CFDictionaryRef query = NULL; | |
fa7225c8 | 359 | |
822b670c | 360 | require_action_quiet(publicKey != NULL, errOut, SecError(errSecParam, error, CFSTR("Null Public Key"))); |
5c19dc3a A |
361 | |
362 | query = CreatePrivateKeyMatchingQuery(publicKey, false); | |
363 | ||
364 | require_quiet(SecError(SecItemCopyMatching(query, &queryResult), error, | |
365 | CFSTR("Error finding private key from public: %@"), publicKey), errOut); | |
fa7225c8 | 366 | |
5c19dc3a A |
367 | if (CFGetTypeID(queryResult) == SecKeyGetTypeID()) { |
368 | privateKey = (SecKeyRef) queryResult; | |
369 | queryResult = NULL; | |
370 | } | |
371 | ||
372 | errOut: | |
373 | CFReleaseNull(query); | |
374 | CFReleaseNull(queryResult); | |
375 | return privateKey; | |
376 | } | |
377 | ||
378 | OSStatus SecKeyGetMatchingPrivateKeyStatus(SecKeyRef publicKey, CFErrorRef *error) { | |
379 | OSStatus retval = errSecParam; | |
427c49bc | 380 | CFTypeRef private_key = NULL; |
5c19dc3a | 381 | CFDictionaryRef query = NULL; |
fa7225c8 | 382 | |
5c19dc3a A |
383 | require_action_quiet(publicKey != NULL, errOut, SecError(errSecParam, error, NULL, CFSTR("Null Public Key"))); |
384 | ||
385 | query = CreatePrivateKeyMatchingQuery(publicKey, false); | |
fa7225c8 | 386 | |
5c19dc3a | 387 | retval = SecItemCopyMatching(query, &private_key); |
fa7225c8 | 388 | |
5c19dc3a A |
389 | if (!retval && CFGetTypeID(private_key) != SecKeyGetTypeID()) { |
390 | retval = errSecInternalComponent; | |
391 | } | |
fa7225c8 | 392 | |
5c19dc3a | 393 | errOut: |
427c49bc | 394 | CFReleaseNull(query); |
5c19dc3a A |
395 | CFReleaseNull(private_key); |
396 | return retval; | |
427c49bc A |
397 | } |
398 | ||
5c19dc3a | 399 | |
b1ab9ed8 | 400 | SecKeyRef SecKeyCreatePublicFromDER(CFAllocatorRef allocator, |
427c49bc A |
401 | const SecAsn1Oid *oid, const SecAsn1Item *params, |
402 | const SecAsn1Item *keyData) { | |
b1ab9ed8 A |
403 | SecKeyRef publicKey = NULL; |
404 | if (SecAsn1OidCompare(oid, &CSSMOID_RSA)) { | |
405 | /* pkcs1 1 */ | |
fa7225c8 A |
406 | /* Note that we call SecKeyCreateRSAPublicKey_ios directly instead of |
407 | SecKeyCreateRSAPublicKey, since on OS X the latter function will return | |
408 | a CSSM SecKeyRef, and we always want an iOS format SecKeyRef here. | |
409 | */ | |
410 | publicKey = SecKeyCreateRSAPublicKey_ios(allocator, | |
427c49bc | 411 | keyData->Data, keyData->Length, kSecKeyEncodingPkcs1); |
b1ab9ed8 A |
412 | } else if (SecAsn1OidCompare(oid, &CSSMOID_ecPublicKey)) { |
413 | SecDERKey derKey = { | |
414 | .oid = oid->Data, | |
415 | .oidLength = oid->Length, | |
416 | .key = keyData->Data, | |
417 | .keyLength = keyData->Length, | |
418 | }; | |
419 | if (params) { | |
420 | derKey.parameters = params->Data; | |
421 | derKey.parametersLength = params->Length; | |
422 | } | |
fa7225c8 | 423 | publicKey = SecKeyCreateECPublicKey(allocator, |
427c49bc | 424 | (const uint8_t *)&derKey, sizeof(derKey), kSecDERKeyEncoding); |
b1ab9ed8 A |
425 | } else { |
426 | secwarning("Unsupported algorithm oid"); | |
427 | } | |
5c19dc3a | 428 | |
b1ab9ed8 A |
429 | return publicKey; |
430 | } | |
431 | ||
5c19dc3a A |
432 | |
433 | SecKeyRef SecKeyCreateFromSubjectPublicKeyInfoData(CFAllocatorRef allocator, CFDataRef subjectPublicKeyInfoData) | |
434 | { | |
435 | DERReturn drtn; | |
436 | ||
437 | DERItem subjectPublicKeyInfoDER = { | |
438 | .data = (uint8_t *)CFDataGetBytePtr(subjectPublicKeyInfoData), | |
439 | .length = (DERSize)CFDataGetLength(subjectPublicKeyInfoData), | |
440 | }; | |
441 | DERSubjPubKeyInfo subjectPublicKeyInfo; | |
442 | DERAlgorithmId algorithmId; | |
443 | DERItem pubKeyBytes; | |
444 | ||
445 | drtn = DERParseSequence(&subjectPublicKeyInfoDER, | |
446 | DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs, | |
447 | &subjectPublicKeyInfo, sizeof(subjectPublicKeyInfo)); | |
448 | ||
449 | require_noerr_quiet(drtn, out); | |
450 | ||
451 | drtn = DERParseSequenceContent(&subjectPublicKeyInfo.algId, | |
452 | DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs, | |
453 | &algorithmId, sizeof(algorithmId)); | |
454 | require_noerr_quiet(drtn, out); | |
455 | ||
456 | DERByte unusedBits; | |
457 | drtn = DERParseBitString(&subjectPublicKeyInfo.pubKey, &pubKeyBytes, &unusedBits); | |
458 | require_noerr_quiet(drtn, out); | |
459 | ||
460 | /* Convert DERItem to SecAsn1Item : */ | |
461 | const SecAsn1Oid oid = { .Data = algorithmId.oid.data, .Length = algorithmId.oid.length }; | |
462 | const SecAsn1Item params = { .Data = algorithmId.params.data, .Length = algorithmId.params.length }; | |
463 | const SecAsn1Item pubKey = { .Data = pubKeyBytes.data, .Length = pubKeyBytes.length }; | |
464 | ||
465 | return SecKeyCreatePublicFromDER(allocator, &oid, ¶ms, &pubKey); | |
466 | ||
467 | out: | |
468 | ||
469 | return NULL; | |
470 | ||
471 | } | |
472 | ||
473 | ||
474 | ||
b1ab9ed8 | 475 | SecKeyRef SecKeyCreate(CFAllocatorRef allocator, |
427c49bc A |
476 | const SecKeyDescriptor *key_class, const uint8_t *keyData, |
477 | CFIndex keyDataLength, SecKeyEncoding encoding) { | |
d8f41ccd | 478 | if (!key_class) return NULL; |
b1ab9ed8 A |
479 | size_t size = sizeof(struct __SecKey) + key_class->extraBytes; |
480 | SecKeyRef result = (SecKeyRef)_CFRuntimeCreateInstance(allocator, | |
427c49bc | 481 | SecKeyGetTypeID(), size - sizeof(CFRuntimeBase), NULL); |
b1ab9ed8 A |
482 | if (result) { |
483 | memset((char*)result + sizeof(result->_base), 0, size - sizeof(result->_base)); | |
484 | result->key_class = key_class; | |
485 | if (key_class->extraBytes) { | |
486 | /* Make result->key point to the extraBytes we allocated. */ | |
487 | result->key = ((char*)result) + sizeof(*result); | |
488 | } | |
489 | if (key_class->init) { | |
490 | OSStatus status; | |
491 | status = key_class->init(result, keyData, keyDataLength, encoding); | |
492 | if (status) { | |
427c49bc | 493 | secwarning("init %s key: %" PRIdOSStatus, key_class->name, status); |
b1ab9ed8 A |
494 | CFRelease(result); |
495 | result = NULL; | |
496 | } | |
497 | } | |
498 | } | |
499 | return result; | |
500 | } | |
501 | ||
fa7225c8 A |
502 | static SecKeyAlgorithm SecKeyGetSignatureAlgorithmForPadding(SecKeyRef key, SecPadding padding) { |
503 | switch (SecKeyGetAlgorithmIdentifier(key)) { | |
504 | case kSecRSAAlgorithmID: | |
505 | switch (padding) { | |
506 | case kSecPaddingNone: | |
507 | return kSecKeyAlgorithmRSASignatureRaw; | |
508 | case kSecPaddingPKCS1: | |
509 | return kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw; | |
510 | #if TARGET_OS_IPHONE | |
511 | case kSecPaddingPKCS1SHA1: | |
512 | return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1; | |
513 | case kSecPaddingPKCS1SHA224: | |
514 | return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224; | |
515 | case kSecPaddingPKCS1SHA256: | |
516 | return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256; | |
517 | case kSecPaddingPKCS1SHA384: | |
518 | return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384; | |
519 | case kSecPaddingPKCS1SHA512: | |
520 | return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512; | |
521 | #else | |
522 | // On CSSM-based implementation, these functions actually did hash its input, | |
523 | // so keep doing that for backward compatibility. | |
524 | case kSecPaddingPKCS1SHA1: | |
525 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1; | |
526 | case kSecPaddingPKCS1SHA224: | |
527 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224; | |
528 | case kSecPaddingPKCS1SHA256: | |
529 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256; | |
530 | case kSecPaddingPKCS1SHA384: | |
531 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384; | |
532 | case kSecPaddingPKCS1SHA512: | |
533 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512; | |
b1ab9ed8 | 534 | #endif |
fa7225c8 A |
535 | default: |
536 | return NULL; | |
537 | } | |
538 | case kSecECDSAAlgorithmID: | |
539 | switch (padding) { | |
540 | case kSecPaddingSigRaw: | |
541 | return kSecKeyAlgorithmECDSASignatureRFC4754; | |
542 | default: | |
543 | // Although it is not very logical, previous SecECKey implementation really considered | |
544 | // anything else than SigRaw (incl. None!) as PKCS1 (i.e. x962), so we keep the behaviour | |
545 | // for backward compatibility. | |
546 | return kSecKeyAlgorithmECDSASignatureDigestX962; | |
547 | } | |
427c49bc | 548 | default: |
fa7225c8 | 549 | return NULL; |
b1ab9ed8 | 550 | } |
fa7225c8 | 551 | } |
5c19dc3a | 552 | |
fa7225c8 A |
553 | // Generic wrapper helper for invoking new-style CFDataRef-based operations with ptr/length arguments |
554 | // used by legacy RawSign-style functions. | |
555 | static OSStatus SecKeyPerformLegacyOperation(SecKeyRef key, | |
556 | const uint8_t *in1Ptr, size_t in1Len, | |
557 | const uint8_t *in2Ptr, size_t in2Len, | |
558 | uint8_t *outPtr, size_t *outLen, | |
559 | CFTypeRef (^operation)(CFDataRef in1, CFDataRef in2, CFRange *resultRange, CFErrorRef *error)) { | |
560 | CFErrorRef error = NULL; | |
561 | OSStatus status = errSecSuccess; | |
562 | CFDataRef in1 = CFDataCreateWithBytesNoCopy(NULL, in1Ptr, in1Len, kCFAllocatorNull); | |
563 | CFDataRef in2 = in2Ptr ? CFDataCreateWithBytesNoCopy(NULL, in2Ptr, in2Len, kCFAllocatorNull) : NULL; | |
564 | CFRange range = { 0, -1 }; | |
565 | CFTypeRef output = operation(in1, in2, &range, &error); | |
566 | require_quiet(output, out); | |
567 | if (CFGetTypeID(output) == CFDataGetTypeID() && outLen != NULL) { | |
568 | if (range.length == -1) { | |
569 | range.length = CFDataGetLength(output); | |
570 | } | |
571 | require_action_quiet((size_t)range.length <= *outLen, out, | |
572 | SecError(errSecParam, &error, CFSTR("buffer too small"))); | |
573 | *outLen = range.length; | |
574 | CFDataGetBytes(output, range, outPtr); | |
b1ab9ed8 | 575 | } |
5c19dc3a | 576 | |
fa7225c8 A |
577 | out: |
578 | CFReleaseSafe(in1); | |
579 | CFReleaseSafe(in2); | |
580 | CFReleaseSafe(output); | |
581 | if (error != NULL) { | |
582 | status = (OSStatus)CFErrorGetCode(error); | |
583 | if (status == errSecVerifyFailed) { | |
584 | // Legacy functions used errSSLCrypto, while new implementation uses errSecVerifyFailed. | |
585 | status = errSSLCrypto; | |
586 | } | |
587 | CFRelease(error); | |
588 | } | |
589 | return status; | |
b1ab9ed8 A |
590 | } |
591 | ||
592 | OSStatus SecKeyRawSign( | |
427c49bc A |
593 | SecKeyRef key, /* Private key */ |
594 | SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */ | |
595 | const uint8_t *dataToSign, /* signature over this data */ | |
596 | size_t dataToSignLen, /* length of dataToSign */ | |
597 | uint8_t *sig, /* signature, RETURNED */ | |
598 | size_t *sigLen) { /* IN/OUT */ | |
fa7225c8 A |
599 | SecKeyAlgorithm algorithm = SecKeyGetSignatureAlgorithmForPadding(key, padding); |
600 | if (algorithm == NULL) { | |
601 | return errSecParam; | |
b1ab9ed8 | 602 | } |
fa7225c8 A |
603 | return SecKeyPerformLegacyOperation(key, dataToSign, dataToSignLen, NULL, 0, sig, sigLen, |
604 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
605 | return SecKeyCreateSignature(key, algorithm, in1, error); | |
606 | }); | |
b1ab9ed8 A |
607 | } |
608 | ||
609 | OSStatus SecKeyRawVerify( | |
427c49bc A |
610 | SecKeyRef key, /* Public key */ |
611 | SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */ | |
612 | const uint8_t *signedData, /* signature over this data */ | |
613 | size_t signedDataLen, /* length of dataToSign */ | |
614 | const uint8_t *sig, /* signature */ | |
615 | size_t sigLen) { /* length of signature */ | |
fa7225c8 A |
616 | SecKeyAlgorithm algorithm = SecKeyGetSignatureAlgorithmForPadding(key, padding); |
617 | if (algorithm == NULL) { | |
618 | return errSecParam; | |
619 | } | |
620 | OSStatus status = SecKeyPerformLegacyOperation(key, signedData, signedDataLen, sig, sigLen, NULL, NULL, | |
621 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
622 | return in2 != NULL && SecKeyVerifySignature(key, algorithm, in1, in2, error) | |
623 | ? kCFBooleanTrue : NULL; | |
624 | }); | |
625 | return status; | |
626 | } | |
5c19dc3a | 627 | |
fa7225c8 A |
628 | static SecKeyAlgorithm SecKeyGetEncryptionAlgorithmForPadding(SecKeyRef key, SecPadding padding) { |
629 | switch (SecKeyGetAlgorithmIdentifier(key)) { | |
630 | case kSecRSAAlgorithmID: | |
631 | switch (padding) { | |
632 | case kSecPaddingNone: | |
633 | return kSecKeyAlgorithmRSAEncryptionRaw; | |
634 | case kSecPaddingPKCS1: | |
635 | return kSecKeyAlgorithmRSAEncryptionPKCS1; | |
636 | case kSecPaddingOAEP: | |
637 | return kSecKeyAlgorithmRSAEncryptionOAEPSHA1; | |
638 | default: | |
639 | return NULL; | |
640 | } | |
641 | default: | |
642 | return NULL; | |
b1ab9ed8 A |
643 | } |
644 | } | |
645 | ||
646 | OSStatus SecKeyEncrypt( | |
427c49bc A |
647 | SecKeyRef key, /* Public key */ |
648 | SecPadding padding, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */ | |
649 | const uint8_t *plainText, | |
650 | size_t plainTextLen, /* length of plainText */ | |
651 | uint8_t *cipherText, | |
652 | size_t *cipherTextLen) { /* IN/OUT */ | |
fa7225c8 A |
653 | SecKeyAlgorithm algorithm = SecKeyGetEncryptionAlgorithmForPadding(key, padding); |
654 | if (algorithm == NULL) { | |
655 | return errSecParam; | |
656 | } | |
657 | ||
658 | return SecKeyPerformLegacyOperation(key, plainText, plainTextLen, NULL, 0, cipherText, cipherTextLen, | |
659 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
660 | return SecKeyCreateEncryptedData(key, algorithm, in1, error); | |
661 | }); | |
b1ab9ed8 A |
662 | } |
663 | ||
664 | OSStatus SecKeyDecrypt( | |
427c49bc A |
665 | SecKeyRef key, /* Private key */ |
666 | SecPadding padding, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */ | |
667 | const uint8_t *cipherText, | |
668 | size_t cipherTextLen, /* length of cipherText */ | |
669 | uint8_t *plainText, | |
670 | size_t *plainTextLen) { /* IN/OUT */ | |
fa7225c8 A |
671 | SecKeyAlgorithm algorithm = SecKeyGetEncryptionAlgorithmForPadding(key, padding); |
672 | if (algorithm == NULL) { | |
673 | return errSecParam; | |
674 | } | |
675 | return SecKeyPerformLegacyOperation(key, cipherText, cipherTextLen, NULL, 0, plainText, plainTextLen, | |
676 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
677 | CFDataRef decrypted = SecKeyCreateDecryptedData(key, algorithm, in1, error); | |
678 | const UInt8 *data; | |
679 | if (decrypted != NULL && algorithm == kSecKeyAlgorithmRSAEncryptionRaw && | |
680 | *(data = CFDataGetBytePtr(decrypted)) == 0x00) { | |
681 | // Strip zero-padding from the beginning of the block, as the contract of this | |
682 | // function says. | |
683 | range->length = CFDataGetLength(decrypted); | |
684 | while (*data == 0x00 && range->length > 0) { | |
685 | range->location++; | |
686 | range->length--; | |
687 | data++; | |
688 | } | |
689 | } | |
690 | return decrypted; | |
691 | }); | |
b1ab9ed8 A |
692 | } |
693 | ||
694 | size_t SecKeyGetBlockSize(SecKeyRef key) { | |
695 | if (key->key_class->blockSize) | |
696 | return key->key_class->blockSize(key); | |
697 | return 0; | |
698 | } | |
699 | ||
700 | /* Private API functions. */ | |
701 | ||
702 | CFDictionaryRef SecKeyCopyAttributeDictionary(SecKeyRef key) { | |
703 | if (key->key_class->copyDictionary) | |
704 | return key->key_class->copyDictionary(key); | |
705 | return NULL; | |
706 | } | |
707 | ||
708 | SecKeyRef SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes) { | |
fa7225c8 A |
709 | CFErrorRef error = NULL; |
710 | SecKeyRef key = SecKeyCreateWithData(CFDictionaryGetValue(refAttributes, kSecValueData), refAttributes, &error); | |
711 | if (key == NULL) { | |
712 | CFStringRef description = CFErrorCopyDescription(error); | |
713 | secwarning("%@", description); | |
714 | CFRelease(description); | |
715 | CFRelease(error); | |
b1ab9ed8 | 716 | } |
fa7225c8 | 717 | return key; |
b1ab9ed8 A |
718 | } |
719 | ||
fa7225c8 A |
720 | static SecKeyAlgorithm SecKeyGetAlgorithmForSecAsn1AlgId(SecKeyRef key, const SecAsn1AlgId *algId, bool digestData) { |
721 | static const struct TableItem { | |
722 | const SecAsn1Oid *oid1, *oid2; | |
723 | const SecKeyAlgorithm *algorithms[2]; | |
724 | } translationTableRSA[] = { | |
725 | { &CSSMOID_SHA1WithRSA, &CSSMOID_SHA1, { | |
726 | [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1, | |
727 | [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1, | |
728 | } }, | |
729 | { &CSSMOID_SHA224WithRSA, &CSSMOID_SHA224, { | |
730 | [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224, | |
731 | [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224, | |
732 | } }, | |
733 | { &CSSMOID_SHA256WithRSA, &CSSMOID_SHA256, { | |
734 | [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256, | |
735 | [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256, | |
736 | } }, | |
737 | { &CSSMOID_SHA384WithRSA, &CSSMOID_SHA384, { | |
738 | [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384, | |
739 | [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384, | |
740 | } }, | |
741 | { &CSSMOID_SHA512WithRSA, &CSSMOID_SHA512, { | |
742 | [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512, | |
743 | [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512, | |
744 | } }, | |
745 | { &CSSMOID_MD5, NULL, { | |
746 | [false] = &kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5, | |
747 | [true] = &kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5, | |
748 | } }, | |
749 | { NULL }, | |
750 | }, translationTableECDSA[] = { | |
751 | { &CSSMOID_ECDSA_WithSHA1, &CSSMOID_SHA1, { | |
752 | [false] = &kSecKeyAlgorithmECDSASignatureDigestX962, | |
753 | [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA1, | |
754 | } }, | |
755 | { &CSSMOID_ECDSA_WithSHA224, &CSSMOID_SHA224, { | |
756 | [false] = &kSecKeyAlgorithmECDSASignatureDigestX962, | |
757 | [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA224, | |
758 | } }, | |
759 | { &CSSMOID_ECDSA_WithSHA256, &CSSMOID_SHA256, { | |
760 | [false] = &kSecKeyAlgorithmECDSASignatureDigestX962, | |
761 | [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA256, | |
762 | } }, | |
763 | { &CSSMOID_ECDSA_WithSHA384, &CSSMOID_SHA384, { | |
764 | [false] = &kSecKeyAlgorithmECDSASignatureDigestX962, | |
765 | [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA384, | |
766 | } }, | |
767 | { &CSSMOID_ECDSA_WithSHA512, &CSSMOID_SHA512, { | |
768 | [false] = &kSecKeyAlgorithmECDSASignatureDigestX962, | |
769 | [true] = &kSecKeyAlgorithmECDSASignatureMessageX962SHA512, | |
770 | } }, | |
771 | { NULL }, | |
772 | }; | |
773 | ||
774 | const struct TableItem *table; | |
775 | switch (SecKeyGetAlgorithmIdentifier(key)) { | |
b1ab9ed8 | 776 | case kSecRSAAlgorithmID: |
fa7225c8 | 777 | table = translationTableRSA; |
b1ab9ed8 A |
778 | break; |
779 | case kSecECDSAAlgorithmID: | |
fa7225c8 | 780 | table = translationTableECDSA; |
b1ab9ed8 A |
781 | break; |
782 | default: | |
fa7225c8 | 783 | return NULL; |
b1ab9ed8 | 784 | } |
5c19dc3a | 785 | |
fa7225c8 A |
786 | for (; table->oid1 != NULL; table++) { |
787 | if (SecAsn1OidCompare(table->oid1, &algId->algorithm) || | |
788 | (table->oid2 != NULL && SecAsn1OidCompare(table->oid2, &algId->algorithm))) { | |
789 | return *table->algorithms[digestData]; | |
790 | } | |
b1ab9ed8 | 791 | } |
fa7225c8 | 792 | return NULL; |
b1ab9ed8 A |
793 | } |
794 | ||
795 | OSStatus SecKeyDigestAndVerify( | |
fa7225c8 | 796 | SecKeyRef key, /* Private key */ |
427c49bc A |
797 | const SecAsn1AlgId *algId, /* algorithm oid/params */ |
798 | const uint8_t *dataToDigest, /* signature over this data */ | |
799 | size_t dataToDigestLen,/* length of dataToDigest */ | |
800 | const uint8_t *sig, /* signature to verify */ | |
801 | size_t sigLen) { /* length of sig */ | |
5c19dc3a | 802 | |
fa7225c8 A |
803 | SecKeyAlgorithm algorithm = SecKeyGetAlgorithmForSecAsn1AlgId(key, algId, true); |
804 | if (algorithm == NULL) { | |
805 | return errSecUnimplemented; | |
806 | } | |
5c19dc3a | 807 | |
fa7225c8 A |
808 | return SecKeyPerformLegacyOperation(key, dataToDigest, dataToDigestLen, sig, sigLen, NULL, NULL, |
809 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
810 | return SecKeyVerifySignature(key, algorithm, in1, in2, error) ? | |
811 | kCFBooleanTrue : NULL; | |
812 | }); | |
b1ab9ed8 A |
813 | } |
814 | ||
815 | OSStatus SecKeyDigestAndSign( | |
fa7225c8 | 816 | SecKeyRef key, /* Private key */ |
427c49bc A |
817 | const SecAsn1AlgId *algId, /* algorithm oid/params */ |
818 | const uint8_t *dataToDigest, /* signature over this data */ | |
819 | size_t dataToDigestLen,/* length of dataToDigest */ | |
820 | uint8_t *sig, /* signature, RETURNED */ | |
821 | size_t *sigLen) { /* IN/OUT */ | |
fa7225c8 A |
822 | SecKeyAlgorithm algorithm = SecKeyGetAlgorithmForSecAsn1AlgId(key, algId, true); |
823 | if (algorithm == NULL) { | |
824 | return errSecUnimplemented; | |
825 | } | |
826 | ||
827 | return SecKeyPerformLegacyOperation(key, dataToDigest, dataToDigestLen, NULL, 0, sig, sigLen, | |
828 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
829 | return SecKeyCreateSignature(key, algorithm, in1, error); | |
830 | }); | |
b1ab9ed8 A |
831 | } |
832 | ||
833 | OSStatus SecKeyVerifyDigest( | |
fa7225c8 | 834 | SecKeyRef key, /* Private key */ |
427c49bc A |
835 | const SecAsn1AlgId *algId, /* algorithm oid/params */ |
836 | const uint8_t *digestData, /* signature over this digest */ | |
837 | size_t digestDataLen,/* length of dataToDigest */ | |
838 | const uint8_t *sig, /* signature to verify */ | |
839 | size_t sigLen) { /* length of sig */ | |
fa7225c8 A |
840 | SecKeyAlgorithm algorithm = SecKeyGetAlgorithmForSecAsn1AlgId(key, algId, false); |
841 | if (algorithm == NULL) { | |
842 | return errSecUnimplemented; | |
843 | } | |
844 | ||
845 | return SecKeyPerformLegacyOperation(key, digestData, digestDataLen, sig, sigLen, NULL, NULL, | |
846 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
847 | return SecKeyVerifySignature(key, algorithm, in1, in2, error) ? | |
848 | kCFBooleanTrue : NULL; | |
849 | }); | |
b1ab9ed8 A |
850 | } |
851 | ||
852 | OSStatus SecKeySignDigest( | |
fa7225c8 | 853 | SecKeyRef key, /* Private key */ |
427c49bc A |
854 | const SecAsn1AlgId *algId, /* algorithm oid/params */ |
855 | const uint8_t *digestData, /* signature over this digest */ | |
856 | size_t digestDataLen,/* length of digestData */ | |
857 | uint8_t *sig, /* signature, RETURNED */ | |
858 | size_t *sigLen) { /* IN/OUT */ | |
fa7225c8 A |
859 | SecKeyAlgorithm algorithm = SecKeyGetAlgorithmForSecAsn1AlgId(key, algId, false); |
860 | if (algorithm == NULL) { | |
861 | return errSecUnimplemented; | |
862 | } | |
863 | ||
864 | return SecKeyPerformLegacyOperation(key, digestData, digestDataLen, NULL, 0, sig, sigLen, | |
865 | ^CFTypeRef(CFDataRef in1, CFDataRef in2, CFRange *range, CFErrorRef *error) { | |
866 | return SecKeyCreateSignature(key, algorithm, in1, error); | |
867 | }); | |
b1ab9ed8 A |
868 | } |
869 | ||
5c19dc3a A |
870 | CFIndex SecKeyGetAlgorithmId(SecKeyRef key) { |
871 | return SecKeyGetAlgorithmIdentifier(key); | |
b1ab9ed8 A |
872 | } |
873 | ||
5c19dc3a A |
874 | #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)) |
875 | /* On OS X, SecKeyGetAlgorithmID has a different function signature (two arguments, | |
876 | with output in the second argument). Therefore, avoid implementing this function here | |
877 | if compiling for OS X. | |
878 | */ | |
879 | #else | |
880 | CFIndex SecKeyGetAlgorithmID(SecKeyRef key) { | |
881 | return SecKeyGetAlgorithmIdentifier(key); | |
882 | } | |
883 | #endif | |
b1ab9ed8 A |
884 | |
885 | OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* serializedPublic) { | |
886 | if (key->key_class->version > 1 && key->key_class->copyPublic) | |
887 | return key->key_class->copyPublic(key, serializedPublic); | |
888 | return errSecUnimplemented; | |
889 | } | |
890 | ||
891 | SecKeyRef SecKeyCreateFromPublicBytes(CFAllocatorRef allocator, CFIndex algorithmID, const uint8_t *keyData, CFIndex keyDataLength) | |
892 | { | |
893 | switch (algorithmID) | |
894 | { | |
895 | case kSecRSAAlgorithmID: | |
896 | return SecKeyCreateRSAPublicKey(allocator, | |
897 | keyData, keyDataLength, | |
898 | kSecKeyEncodingBytes); | |
899 | case kSecECDSAAlgorithmID: | |
900 | return SecKeyCreateECPublicKey(allocator, | |
901 | keyData, keyDataLength, | |
902 | kSecKeyEncodingBytes); | |
903 | default: | |
904 | return NULL; | |
905 | } | |
906 | } | |
907 | ||
908 | SecKeyRef SecKeyCreateFromPublicData(CFAllocatorRef allocator, CFIndex algorithmID, CFDataRef serialized) | |
909 | { | |
910 | return SecKeyCreateFromPublicBytes(allocator, algorithmID, CFDataGetBytePtr(serialized), CFDataGetLength(serialized)); | |
911 | } | |
912 | ||
913 | // This is a bit icky hack to avoid changing the vtable for | |
914 | // SecKey. | |
915 | size_t SecKeyGetSize(SecKeyRef key, SecKeySize whichSize) | |
916 | { | |
917 | size_t result = SecKeyGetBlockSize(key); | |
5c19dc3a A |
918 | |
919 | if (kSecECDSAAlgorithmID == SecKeyGetAlgorithmIdentifier(key)) { | |
b1ab9ed8 A |
920 | switch (whichSize) { |
921 | case kSecKeyEncryptedDataSize: | |
922 | result = 0; | |
923 | break; | |
924 | case kSecKeySignatureSize: | |
427c49bc | 925 | result = (result >= 66 ? 9 : 8) + 2 * result; |
b1ab9ed8 A |
926 | break; |
927 | case kSecKeyKeySizeInBits: | |
928 | if (result >= 66) | |
929 | return 521; | |
930 | } | |
931 | } | |
5c19dc3a | 932 | |
b1ab9ed8 | 933 | if (whichSize == kSecKeyKeySizeInBits) |
427c49bc | 934 | result *= 8; |
5c19dc3a | 935 | |
b1ab9ed8 | 936 | return result; |
5c19dc3a | 937 | |
427c49bc | 938 | } |
b1ab9ed8 | 939 | |
427c49bc A |
940 | OSStatus SecKeyFindWithPersistentRef(CFDataRef persistentRef, SecKeyRef* lookedUpData) |
941 | { | |
942 | CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, | |
943 | kSecReturnRef, kCFBooleanTrue, | |
944 | kSecClass, kSecClassKey, | |
945 | kSecValuePersistentRef, persistentRef, | |
946 | NULL); | |
947 | CFTypeRef foundRef = NULL; | |
948 | OSStatus status = SecItemCopyMatching(query, &foundRef); | |
5c19dc3a | 949 | |
427c49bc A |
950 | if (status == errSecSuccess) { |
951 | if (CFGetTypeID(foundRef) == SecKeyGetTypeID()) { | |
952 | *lookedUpData = (SecKeyRef) foundRef; | |
953 | foundRef = NULL; | |
954 | status = errSecSuccess; | |
955 | } else { | |
956 | status = errSecItemNotFound; | |
957 | } | |
958 | } | |
5c19dc3a | 959 | |
427c49bc A |
960 | CFReleaseSafe(foundRef); |
961 | CFReleaseSafe(query); | |
5c19dc3a | 962 | |
427c49bc | 963 | return status; |
b1ab9ed8 A |
964 | } |
965 | ||
427c49bc A |
966 | OSStatus SecKeyCopyPersistentRef(SecKeyRef key, CFDataRef* persistentRef) |
967 | { | |
968 | CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, | |
969 | kSecReturnPersistentRef, kCFBooleanTrue, | |
970 | kSecValueRef, key, | |
971 | kSecAttrSynchronizable, kSecAttrSynchronizableAny, | |
972 | NULL); | |
973 | CFTypeRef foundRef = NULL; | |
974 | OSStatus status = SecItemCopyMatching(query, &foundRef); | |
5c19dc3a | 975 | |
427c49bc A |
976 | if (status == errSecSuccess) { |
977 | if (CFGetTypeID(foundRef) == CFDataGetTypeID()) { | |
978 | *persistentRef = foundRef; | |
979 | foundRef = NULL; | |
980 | } else { | |
981 | status = errSecItemNotFound; | |
982 | } | |
983 | } | |
5c19dc3a | 984 | |
427c49bc A |
985 | CFReleaseSafe(foundRef); |
986 | CFReleaseSafe(query); | |
5c19dc3a | 987 | |
427c49bc A |
988 | return status; |
989 | } | |
d8f41ccd A |
990 | |
991 | /* | |
992 | * | |
993 | */ | |
994 | ||
5c19dc3a | 995 | #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v); |
d8f41ccd A |
996 | |
997 | SEC_CONST_DECL(_kSecKeyWrapPGPSymAlg, "kSecKeyWrapPGPSymAlg"); | |
998 | SEC_CONST_DECL(_kSecKeyWrapPGPFingerprint, "kSecKeyWrapPGPFingerprint"); | |
999 | SEC_CONST_DECL(_kSecKeyWrapPGPWrapAlg, "kSecKeyWrapPGPWrapAlg"); | |
1000 | SEC_CONST_DECL(_kSecKeyWrapRFC6637Flags, "kSecKeyWrapPGPECFlags"); | |
1001 | SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA256KekAES128, "kSecKeyWrapPGPECWrapDigestSHA256KekAES128"); | |
1002 | SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA512KekAES256, "kSecKeyWrapPGPECWrapDigestSHA512KekAES256"); | |
1003 | ||
1004 | #undef SEC_CONST_DECL | |
1005 | ||
1006 | CFDataRef | |
1007 | _SecKeyCopyWrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef unwrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error) | |
1008 | { | |
1009 | if (error) | |
1010 | *error = NULL; | |
1011 | if (outParam) | |
1012 | *outParam = NULL; | |
1013 | if (key->key_class->version > 2 && key->key_class->copyWrapKey) | |
1014 | return key->key_class->copyWrapKey(key, type, unwrappedKey, parameters, outParam, error); | |
1015 | SecError(errSecUnsupportedOperation, error, CFSTR("No key wrap supported for key %@"), key); | |
1016 | return NULL; | |
1017 | } | |
1018 | ||
1019 | CFDataRef | |
1020 | _SecKeyCopyUnwrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef wrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error) | |
1021 | { | |
1022 | if (error) | |
1023 | *error = NULL; | |
1024 | if (outParam) | |
1025 | *outParam = NULL; | |
1026 | if (key->key_class->version > 2 && key->key_class->copyUnwrapKey) | |
1027 | return key->key_class->copyUnwrapKey(key, type, wrappedKey, parameters, outParam, error); | |
1028 | ||
1029 | SecError(errSecUnsupportedOperation, error, CFSTR("No key unwrap for key %@"), key); | |
1030 | return NULL; | |
1031 | } | |
fa7225c8 A |
1032 | |
1033 | static SInt32 SecKeyParamsGetSInt32(CFTypeRef value, CFStringRef errName, CFErrorRef *error) { | |
1034 | SInt32 result = -1; | |
1035 | if (CFGetTypeID(value) == CFNumberGetTypeID()) { | |
1036 | if (!CFNumberGetValue(value, kCFNumberSInt32Type, &result) || result < 0) { | |
1037 | SecError(errSecParam, error, CFSTR("Unsupported %@: %@"), errName, value); | |
1038 | } | |
1039 | } else if (isString(value)) { | |
1040 | result = CFStringGetIntValue(value); | |
1041 | CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) result); | |
1042 | if (!CFEqual(t, value) || result < 0) { | |
1043 | SecError(errSecParam, error, CFSTR("Unsupported %@: %@"), errName, value); | |
1044 | result = -1; | |
1045 | } | |
1046 | CFReleaseSafe(t); | |
1047 | } else { | |
1048 | SecError(errSecParam, error, CFSTR("Unsupported %@: %@"), errName, value); | |
1049 | } | |
1050 | return result; | |
1051 | } | |
1052 | ||
1053 | SecKeyRef SecKeyCreateWithData(CFDataRef keyData, CFDictionaryRef parameters, CFErrorRef *error) { | |
1054 | ||
1055 | SecKeyRef key = NULL; | |
1056 | CFAllocatorRef allocator = NULL; | |
1057 | ||
1058 | /* First figure out the key type (algorithm). */ | |
1059 | SInt32 algorithm; | |
1060 | CFTypeRef ktype = CFDictionaryGetValue(parameters, kSecAttrKeyType); | |
1061 | require_quiet((algorithm = SecKeyParamsGetSInt32(ktype, CFSTR("key type"), error)) >= 0, out); | |
1062 | SInt32 class; | |
1063 | CFTypeRef kclass = CFDictionaryGetValue(parameters, kSecAttrKeyClass); | |
1064 | require_quiet((class = SecKeyParamsGetSInt32(kclass, CFSTR("key class"), error)) >= 0, out); | |
1065 | ||
1066 | switch (class) { | |
1067 | case 0: // kSecAttrKeyClassPublic | |
1068 | switch (algorithm) { | |
1069 | case 42: // kSecAlgorithmRSA | |
1070 | key = SecKeyCreateRSAPublicKey(allocator, | |
1071 | CFDataGetBytePtr(keyData), CFDataGetLength(keyData), | |
1072 | kSecKeyEncodingBytes); | |
1073 | if (key == NULL) { | |
1074 | SecError(errSecParam, error, CFSTR("RSA public key creation from data failed")); | |
1075 | } | |
1076 | break; | |
1077 | case 43: // kSecAlgorithmECDSA | |
1078 | case 73: // kSecAlgorithmEC | |
1079 | key = SecKeyCreateECPublicKey(allocator, | |
1080 | CFDataGetBytePtr(keyData), CFDataGetLength(keyData), | |
1081 | kSecKeyEncodingBytes); | |
1082 | if (key == NULL) { | |
1083 | SecError(errSecParam, error, CFSTR("EC public key creation from data failed")); | |
1084 | } | |
1085 | break; | |
1086 | default: | |
1087 | SecError(errSecParam, error, CFSTR("Unsupported public key type: %@"), ktype); | |
1088 | break; | |
1089 | }; | |
1090 | break; | |
1091 | case 1: // kSecAttrKeyClassPrivate | |
1092 | if (CFDictionaryGetValue(parameters, kSecAttrTokenID) != NULL) { | |
1093 | key = SecKeyCreateCTKKey(allocator, parameters, error); | |
1094 | break; | |
1095 | } | |
1096 | switch (algorithm) { | |
1097 | case 42: // kSecAlgorithmRSA | |
1098 | key = SecKeyCreateRSAPrivateKey(allocator, | |
1099 | CFDataGetBytePtr(keyData), CFDataGetLength(keyData), | |
1100 | kSecKeyEncodingBytes); | |
1101 | if (key == NULL) { | |
1102 | SecError(errSecParam, error, CFSTR("RSA private key creation from data failed")); | |
1103 | } | |
1104 | break; | |
1105 | case 43: // kSecAlgorithmECDSA | |
1106 | case 73: // kSecAlgorithmEC | |
1107 | key = SecKeyCreateECPrivateKey(allocator, | |
1108 | CFDataGetBytePtr(keyData), CFDataGetLength(keyData), | |
1109 | kSecKeyEncodingBytes); | |
1110 | if (key == NULL) { | |
1111 | SecError(errSecParam, error, CFSTR("EC public key creation from data failed")); | |
1112 | } | |
1113 | break; | |
1114 | default: | |
1115 | SecError(errSecParam, error, CFSTR("Unsupported private key type: %@"), ktype); | |
1116 | break; | |
1117 | }; | |
1118 | break; | |
1119 | case 2: // kSecAttrKeyClassSymmetric | |
1120 | SecError(errSecUnimplemented, error, CFSTR("Unsupported symmetric key type: %@"), ktype); | |
1121 | break; | |
1122 | default: | |
1123 | SecError(errSecParam, error, CFSTR("Unsupported key class: %@"), kclass); | |
1124 | break; | |
1125 | } | |
1126 | ||
1127 | out: | |
1128 | return key; | |
1129 | } | |
1130 | ||
1131 | CFDataRef SecKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) { | |
1132 | if (!key->key_class->copyExternalRepresentation) { | |
1133 | SecError(errSecUnimplemented, error, CFSTR("export not implemented for key %@"), key); | |
1134 | return NULL; | |
1135 | } | |
1136 | ||
1137 | return key->key_class->copyExternalRepresentation(key, error); | |
1138 | } | |
1139 | ||
1140 | CFDictionaryRef SecKeyCopyAttributes(SecKeyRef key) { | |
1141 | if (key->key_class->copyDictionary) | |
1142 | return key->key_class->copyDictionary(key); | |
1143 | return NULL; | |
1144 | } | |
1145 | ||
1146 | SecKeyRef SecKeyCopyPublicKey(SecKeyRef key) { | |
1147 | SecKeyRef result = NULL; | |
1148 | if (key->key_class->version >= 4 && key->key_class->copyPublicKey) { | |
1149 | result = key->key_class->copyPublicKey(key); | |
1150 | if (result != NULL) { | |
1151 | return result; | |
1152 | } | |
1153 | } | |
1154 | ||
1155 | CFDataRef serializedPublic = NULL; | |
1156 | ||
1157 | require_noerr_quiet(SecKeyCopyPublicBytes(key, &serializedPublic), fail); | |
1158 | require_quiet(serializedPublic, fail); | |
1159 | ||
1160 | result = SecKeyCreateFromPublicData(kCFAllocatorDefault, SecKeyGetAlgorithmIdentifier(key), serializedPublic); | |
1161 | ||
1162 | fail: | |
1163 | CFReleaseSafe(serializedPublic); | |
1164 | return result; | |
1165 | } | |
1166 | ||
1167 | SecKeyRef SecKeyCreateRandomKey(CFDictionaryRef parameters, CFErrorRef *error) { | |
1168 | SecKeyRef privKey = NULL, pubKey = NULL; | |
1169 | OSStatus status = SecKeyGeneratePair(parameters, &pubKey, &privKey); | |
1170 | SecError(status, error, CFSTR("Key generation failed, error %d"), (int)status); | |
1171 | CFReleaseSafe(pubKey); | |
1172 | return privKey; | |
1173 | } | |
1174 | ||
1175 | #pragma mark Generic algorithm adaptor lookup and invocation | |
1176 | ||
1177 | static CFTypeRef SecKeyCopyBackendOperationResult(SecKeyOperationContext *context, SecKeyAlgorithm algorithm, | |
1178 | CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { | |
1179 | CFTypeRef result = NULL; | |
1180 | assert(CFArrayGetCount(context->algorithm) > 0); | |
1181 | if (context->key->key_class->version >= 4 && context->key->key_class->copyOperationResult != NULL) { | |
1182 | return context->key->key_class->copyOperationResult(context->key, context->operation, algorithm, | |
1183 | context->algorithm, context->mode, in1, in2, error); | |
1184 | } | |
1185 | ||
1186 | // Mapping from algorithms to legacy SecPadding values. | |
1187 | static const struct { | |
1188 | const SecKeyAlgorithm *algorithm; | |
1189 | CFIndex keyAlg; | |
1190 | SecPadding padding; | |
1191 | } paddingMap[] = { | |
1192 | { &kSecKeyAlgorithmRSASignatureRaw, kSecRSAAlgorithmID, kSecPaddingNone }, | |
1193 | { &kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw, kSecRSAAlgorithmID, kSecPaddingPKCS1 }, | |
1194 | { &kSecKeyAlgorithmECDSASignatureRFC4754, kSecECDSAAlgorithmID, kSecPaddingSigRaw }, | |
1195 | { &kSecKeyAlgorithmECDSASignatureDigestX962, kSecECDSAAlgorithmID, kSecPaddingPKCS1 }, | |
1196 | { &kSecKeyAlgorithmRSAEncryptionRaw, kSecRSAAlgorithmID, kSecPaddingNone }, | |
1197 | { &kSecKeyAlgorithmRSAEncryptionPKCS1, kSecRSAAlgorithmID, kSecPaddingPKCS1 }, | |
1198 | { &kSecKeyAlgorithmRSAEncryptionOAEPSHA1, kSecRSAAlgorithmID, kSecPaddingOAEP }, | |
1199 | }; | |
1200 | SecPadding padding = (SecPadding)-1; | |
1201 | CFIndex keyAlg = SecKeyGetAlgorithmIdentifier(context->key); | |
1202 | for (size_t i = 0; i < array_size(paddingMap); ++i) { | |
1203 | if (keyAlg == paddingMap[i].keyAlg && CFEqual(algorithm, *paddingMap[i].algorithm)) { | |
1204 | padding = paddingMap[i].padding; | |
1205 | break; | |
1206 | } | |
1207 | } | |
1208 | require_quiet(padding != (SecPadding)-1, out); | |
1209 | ||
1210 | // Check legacy virtual table entries. | |
1211 | size_t size = 0; | |
1212 | OSStatus status = errSecSuccess; | |
1213 | switch (context->operation) { | |
1214 | case kSecKeyOperationTypeSign: | |
1215 | if (context->key->key_class->rawSign != NULL) { | |
1216 | result = kCFBooleanTrue; | |
1217 | if (context->mode == kSecKeyOperationModePerform) { | |
1218 | size = SecKeyGetSize(context->key, kSecKeySignatureSize); | |
1219 | result = CFDataCreateMutableWithScratch(NULL, size); | |
1220 | status = context->key->key_class->rawSign(context->key, padding, | |
1221 | CFDataGetBytePtr(in1), CFDataGetLength(in1), | |
1222 | CFDataGetMutableBytePtr((CFMutableDataRef)result), &size); | |
1223 | } | |
1224 | } | |
1225 | break; | |
1226 | case kSecKeyOperationTypeVerify: | |
1227 | if (context->key->key_class->rawVerify != NULL) { | |
1228 | result = kCFBooleanTrue; | |
1229 | if (context->mode == kSecKeyOperationModePerform) { | |
1230 | status = context->key->key_class->rawVerify(context->key, padding, | |
1231 | CFDataGetBytePtr(in1), CFDataGetLength(in1), | |
1232 | CFDataGetBytePtr(in2), CFDataGetLength(in2)); | |
1233 | } | |
1234 | } | |
1235 | break; | |
1236 | case kSecKeyOperationTypeEncrypt: | |
1237 | if (context->key->key_class->encrypt != NULL) { | |
1238 | result = kCFBooleanTrue; | |
1239 | if (context->mode == kSecKeyOperationModePerform) { | |
1240 | size = SecKeyGetSize(context->key, kSecKeyEncryptedDataSize); | |
1241 | result = CFDataCreateMutableWithScratch(NULL, size); | |
1242 | status = context->key->key_class->encrypt(context->key, padding, | |
1243 | CFDataGetBytePtr(in1), CFDataGetLength(in1), | |
1244 | CFDataGetMutableBytePtr((CFMutableDataRef)result), &size); | |
1245 | } | |
1246 | } | |
1247 | break; | |
1248 | case kSecKeyOperationTypeDecrypt: | |
1249 | if (context->key->key_class->decrypt != NULL) { | |
1250 | result = kCFBooleanTrue; | |
1251 | if (context->mode == kSecKeyOperationModePerform) { | |
1252 | size = SecKeyGetSize(context->key, kSecKeyEncryptedDataSize); | |
1253 | result = CFDataCreateMutableWithScratch(NULL, size); | |
1254 | status = context->key->key_class->decrypt(context->key, padding, | |
1255 | CFDataGetBytePtr(in1), CFDataGetLength(in1), | |
1256 | CFDataGetMutableBytePtr((CFMutableDataRef)result), &size); | |
1257 | } | |
1258 | } | |
1259 | break; | |
1260 | default: | |
1261 | goto out; | |
1262 | } | |
1263 | ||
1264 | if (status == errSecSuccess) { | |
1265 | if (CFGetTypeID(result) == CFDataGetTypeID()) { | |
1266 | CFDataSetLength((CFMutableDataRef)result, size); | |
1267 | } | |
1268 | } else { | |
1269 | SecError(status, error, CFSTR("legacy SecKey backend operation:%d(%d) failed"), (int)context->operation, (int)padding); | |
1270 | CFReleaseNull(result); | |
1271 | } | |
1272 | ||
1273 | out: | |
1274 | return result; | |
1275 | } | |
1276 | ||
1277 | CFTypeRef SecKeyRunAlgorithmAndCopyResult(SecKeyOperationContext *context, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { | |
1278 | ||
1279 | // Check algorithm array for cycles; if any value of it is duplicated inside, report 'algorithm not found' error. | |
1280 | CFIndex algorithmCount = CFArrayGetCount(context->algorithm); | |
1281 | for (CFIndex index = 0; index < algorithmCount - 1; index++) { | |
1282 | SecKeyAlgorithm indexAlgorithm = CFArrayGetValueAtIndex(context->algorithm, index); | |
1283 | for (CFIndex tested = index + 1; tested < algorithmCount; tested++) { | |
1284 | require_quiet(!CFEqual(indexAlgorithm, CFArrayGetValueAtIndex(context->algorithm, tested)), fail); | |
1285 | } | |
1286 | } | |
1287 | ||
1288 | SecKeyAlgorithm algorithm = CFArrayGetValueAtIndex(context->algorithm, algorithmCount - 1); | |
1289 | CFTypeRef output = SecKeyCopyBackendOperationResult(context, algorithm, in1, in2, error); | |
1290 | if (output != kCFNull) { | |
1291 | // Backend handled the operation, return result. | |
1292 | return output; | |
1293 | } | |
1294 | ||
1295 | // To silence static analyzer. | |
1296 | CFReleaseSafe(output); | |
1297 | ||
1298 | // Get adaptor which is able to handle requested algorithm. | |
1299 | SecKeyAlgorithmAdaptor adaptor = SecKeyGetAlgorithmAdaptor(context->operation, algorithm); | |
1300 | require_quiet(adaptor != NULL, fail); | |
1301 | ||
1302 | // Invoke the adaptor and return result. | |
1303 | CFTypeRef result = adaptor(context, in1, in2, error); | |
1304 | require_quiet(result != kCFNull, fail); | |
1305 | return result; | |
1306 | ||
1307 | fail: | |
1308 | if (context->mode == kSecKeyOperationModePerform) { | |
1309 | SecError(errSecParam, error, CFSTR("%@: algorithm not supported by the key %@"), | |
1310 | CFArrayGetValueAtIndex(context->algorithm, 0), context->key); | |
1311 | return NULL; | |
1312 | } else { | |
1313 | return kCFNull; | |
1314 | } | |
1315 | } | |
1316 | ||
1317 | #pragma mark Algorithm-related SecKey API entry points | |
1318 | ||
1319 | static CFMutableArrayRef SecKeyCreateAlgorithmArray(SecKeyAlgorithm algorithm) { | |
1320 | CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); | |
1321 | CFArrayAppendValue(result, algorithm); | |
1322 | return result; | |
1323 | } | |
1324 | ||
1325 | CFDataRef SecKeyCreateSignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef dataToSign, CFErrorRef *error) { | |
1326 | SecKeyOperationContext context = { key, kSecKeyOperationTypeSign, SecKeyCreateAlgorithmArray(algorithm) }; | |
1327 | CFDataRef result = SecKeyRunAlgorithmAndCopyResult(&context, dataToSign, NULL, error); | |
1328 | SecKeyOperationContextDestroy(&context); | |
1329 | return result; | |
1330 | } | |
1331 | ||
1332 | Boolean SecKeyVerifySignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef signedData, CFDataRef signature, | |
1333 | CFErrorRef *error) { | |
1334 | SecKeyOperationContext context = { key, kSecKeyOperationTypeVerify, SecKeyCreateAlgorithmArray(algorithm) }; | |
1335 | CFTypeRef res = SecKeyRunAlgorithmAndCopyResult(&context, signedData, signature, error); | |
1336 | Boolean result = CFEqualSafe(res, kCFBooleanTrue); | |
1337 | CFReleaseSafe(res); | |
1338 | SecKeyOperationContextDestroy(&context); | |
1339 | return result; | |
1340 | } | |
1341 | ||
1342 | CFDataRef SecKeyCreateEncryptedData(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef plainText, CFErrorRef *error) { | |
1343 | SecKeyOperationContext context = { key, kSecKeyOperationTypeEncrypt, SecKeyCreateAlgorithmArray(algorithm) }; | |
1344 | CFDataRef result = SecKeyRunAlgorithmAndCopyResult(&context, plainText, NULL, error); | |
1345 | SecKeyOperationContextDestroy(&context); | |
1346 | return result; | |
1347 | } | |
1348 | ||
1349 | CFDataRef SecKeyCreateDecryptedData(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef cipherText, CFErrorRef *error) { | |
1350 | SecKeyOperationContext context = { key, kSecKeyOperationTypeDecrypt, SecKeyCreateAlgorithmArray(algorithm) }; | |
1351 | CFDataRef result = SecKeyRunAlgorithmAndCopyResult(&context, cipherText, NULL, error); | |
1352 | SecKeyOperationContextDestroy(&context); | |
1353 | return result; | |
1354 | } | |
1355 | ||
1356 | CFDataRef SecKeyCopyKeyExchangeResult(SecKeyRef key, SecKeyAlgorithm algorithm, SecKeyRef publicKey, | |
1357 | CFDictionaryRef parameters, CFErrorRef *error) { | |
1358 | CFDataRef publicKeyData = NULL, result = NULL; | |
1359 | SecKeyOperationContext context = { key, kSecKeyOperationTypeKeyExchange, SecKeyCreateAlgorithmArray(algorithm) }; | |
1360 | require_quiet(publicKeyData = SecKeyCopyExternalRepresentation(publicKey, error), out); | |
1361 | result = SecKeyRunAlgorithmAndCopyResult(&context, publicKeyData, parameters, error); | |
1362 | ||
1363 | out: | |
1364 | CFReleaseSafe(publicKeyData); | |
1365 | SecKeyOperationContextDestroy(&context); | |
1366 | return result; | |
1367 | } | |
1368 | ||
1369 | Boolean SecKeyIsAlgorithmSupported(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm) { | |
1370 | SecKeyOperationContext context = { key, operation, SecKeyCreateAlgorithmArray(algorithm), kSecKeyOperationModeCheckIfSupported }; | |
1371 | CFErrorRef error = NULL; | |
1372 | CFTypeRef res = SecKeyRunAlgorithmAndCopyResult(&context, NULL, NULL, &error); | |
1373 | Boolean result = CFEqualSafe(res, kCFBooleanTrue); | |
1374 | CFReleaseSafe(res); | |
1375 | CFReleaseSafe(error); | |
1376 | SecKeyOperationContextDestroy(&context); | |
1377 | return result; | |
1378 | } |