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