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