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