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