]> git.saurik.com Git - apple/security.git/blame - sec/Security/SecKey.c
Security-55471.14.18.tar.gz
[apple/security.git] / sec / Security / SecKey.c
CommitLineData
b1ab9ed8
A
1/*
2 * Copyright (c) 2006-2011 Apple Inc. All Rights Reserved.
427c49bc 3 *
b1ab9ed8 4 * @APPLE_LICENSE_HEADER_START@
427c49bc 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.
427c49bc 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.
427c49bc 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>
32#include <Security/SecFramework.h>
33
427c49bc
A
34#include <utilities/SecIOFormat.h>
35
36#include <utilities/SecCFWrappers.h>
37
b1ab9ed8
A
38#include "SecRSAKeyPriv.h"
39#include "SecECKey.h"
40#include "SecBasePriv.h"
41
42#include <CoreFoundation/CFNumber.h>
43#include <CoreFoundation/CFString.h>
427c49bc 44#include <Security/SecBase.h>
b1ab9ed8
A
45#include <pthread.h>
46#include <string.h>
47#include <AssertMacros.h>
427c49bc
A
48#include <utilities/debugging.h>
49#include <utilities/SecCFError.h>
b1ab9ed8
A
50#include <CommonCrypto/CommonDigest.h>
51#include <Security/SecAsn1Coder.h>
52#include <Security/oidsalg.h>
53#include <Security/SecInternal.h>
54#include <Security/SecRandom.h>
55#include <corecrypto/ccrng_system.h>
56#include <asl.h>
427c49bc 57#include <stdlib.h>
b1ab9ed8
A
58
59static pthread_once_t kSecKeyRegisterClass = PTHREAD_ONCE_INIT;
60static CFTypeID kSecKeyTypeID = _kCFRuntimeNotATypeID;
61
62/* Forward declartions of static functions. */
427c49bc 63static CFStringRef SecKeyCopyDescription(CFTypeRef cf);
b1ab9ed8
A
64static void SecKeyDestroy(CFTypeRef cf);
65
66/* Static functions. */
67#define MAX_DIGEST_LEN (CC_SHA512_DIGEST_LENGTH)
68
69/* Currently length of SHA512 oid + 1 */
70#define MAX_OID_LEN (10)
71
72#define DER_MAX_DIGEST_INFO_LEN (10 + MAX_DIGEST_LEN + MAX_OID_LEN)
73
74/* Encode the digestInfo header into digestInfo and return the offset from
427c49bc
A
75 digestInfo at which to put the actual digest. Returns 0 if digestInfo
76 won't fit within digestInfoLength bytes.
77
78 0x30, topLen,
79 0x30, algIdLen,
80 0x06, oid.Len, oid.Data,
81 0x05, 0x00
82 0x04, digestLen
83 digestData
84 */
85
b1ab9ed8 86static size_t DEREncodeDigestInfoPrefix(const SecAsn1Oid *oid,
427c49bc 87 size_t digestLength, uint8_t *digestInfo, size_t digestInfoLength) {
b1ab9ed8
A
88 size_t algIdLen = oid->Length + 4;
89 size_t topLen = algIdLen + digestLength + 4;
90 size_t totalLen = topLen + 2;
427c49bc 91
b1ab9ed8
A
92 if (totalLen > digestInfoLength) {
93 return 0;
94 }
427c49bc 95
b1ab9ed8
A
96 size_t ix = 0;
97 digestInfo[ix++] = (SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED);
98 digestInfo[ix++] = topLen;
99 digestInfo[ix++] = (SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED);
100 digestInfo[ix++] = algIdLen;
101 digestInfo[ix++] = SEC_ASN1_OBJECT_ID;
102 digestInfo[ix++] = oid->Length;
103 memcpy(&digestInfo[ix], oid->Data, oid->Length);
104 ix += oid->Length;
105 digestInfo[ix++] = SEC_ASN1_NULL;
106 digestInfo[ix++] = 0;
107 digestInfo[ix++] = SEC_ASN1_OCTET_STRING;
108 digestInfo[ix++] = digestLength;
427c49bc 109
b1ab9ed8
A
110 return ix;
111}
112
113static struct ccrng_system_state ccrng_system_state_seckey;
114
115static void register_algs(void) {
116 ccrng_seckey = (struct ccrng_state *)&ccrng_system_state_seckey;
117 ccrng_system_init(&ccrng_system_state_seckey);
118}
119
120
427c49bc
A
121static CFDataRef SecKeyCopyPublicKeyHash(SecKeyRef key)
122{
123 CFDataRef pubKeyDigest = NULL, pubKeyBlob = NULL;
124
125 /* encode the public key. */
126 require_noerr(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut);
127 require(pubKeyBlob, errOut);
128
129 /* Calculate the digest of the public key. */
130 require(pubKeyDigest = SecSHA1DigestCreate(CFGetAllocator(key),
131 CFDataGetBytePtr(pubKeyBlob), CFDataGetLength(pubKeyBlob)),
132 errOut);
133errOut:
134 CFReleaseNull(pubKeyBlob);
135 return pubKeyDigest;
136}
137
138
b1ab9ed8
A
139/*
140 */
427c49bc
A
141static CF_RETURNS_RETAINED CFDictionaryRef SecKeyGenerateAttributeDictionaryFor(SecKeyRef key,
142 CFTypeRef keyType,
143 CFDataRef privateBlob)
b1ab9ed8
A
144{
145 CFAllocatorRef allocator = CFGetAllocator(key);
146 DICT_DECLARE(25);
147 CFDataRef pubKeyDigest = NULL, pubKeyBlob = NULL;
148 CFDictionaryRef dict = NULL;
427c49bc 149
b1ab9ed8
A
150 size_t sizeValue = SecKeyGetSize(key, kSecKeyKeySizeInBits);
151 CFNumberRef sizeInBits = CFNumberCreate(allocator, kCFNumberLongType, &sizeValue);
427c49bc 152
b1ab9ed8
A
153 /* encode the public key. */
154 require_noerr(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut);
155 require(pubKeyBlob, errOut);
427c49bc 156
b1ab9ed8
A
157 /* Calculate the digest of the public key. */
158 require(pubKeyDigest = SecSHA1DigestCreate(allocator,
159 CFDataGetBytePtr(pubKeyBlob), CFDataGetLength(pubKeyBlob)),
160 errOut);
427c49bc 161
b1ab9ed8
A
162 DICT_ADDPAIR(kSecClass, kSecClassKey);
163 DICT_ADDPAIR(kSecAttrKeyClass, privateBlob ? kSecAttrKeyClassPrivate : kSecAttrKeyClassPublic);
164 DICT_ADDPAIR(kSecAttrApplicationLabel, pubKeyDigest);
165 DICT_ADDPAIR(kSecAttrIsPermanent, kCFBooleanTrue);
166 DICT_ADDPAIR(kSecAttrIsPrivate, kCFBooleanTrue);
167 DICT_ADDPAIR(kSecAttrIsModifiable, kCFBooleanTrue);
168 DICT_ADDPAIR(kSecAttrKeyType, keyType);
169 DICT_ADDPAIR(kSecAttrKeySizeInBits, sizeInBits);
170 DICT_ADDPAIR(kSecAttrEffectiveKeySize, sizeInBits);
171 DICT_ADDPAIR(kSecAttrIsSensitive, kCFBooleanFalse);
172 DICT_ADDPAIR(kSecAttrWasAlwaysSensitive, kCFBooleanFalse);
173 DICT_ADDPAIR(kSecAttrIsExtractable, kCFBooleanTrue);
174 DICT_ADDPAIR(kSecAttrWasNeverExtractable, kCFBooleanFalse);
175 DICT_ADDPAIR(kSecAttrCanEncrypt, kCFBooleanFalse);
176 DICT_ADDPAIR(kSecAttrCanDecrypt, kCFBooleanTrue);
177 DICT_ADDPAIR(kSecAttrCanDerive, kCFBooleanTrue);
178 DICT_ADDPAIR(kSecAttrCanSign, kCFBooleanTrue);
179 DICT_ADDPAIR(kSecAttrCanVerify, kCFBooleanFalse);
180 DICT_ADDPAIR(kSecAttrCanSignRecover, kCFBooleanFalse);
181 DICT_ADDPAIR(kSecAttrCanVerifyRecover, kCFBooleanFalse);
182 DICT_ADDPAIR(kSecAttrCanWrap, kCFBooleanFalse);
183 DICT_ADDPAIR(kSecAttrCanUnwrap, kCFBooleanTrue);
184 DICT_ADDPAIR(kSecValueData, privateBlob ? privateBlob : pubKeyBlob);
185 dict = DICT_CREATE(allocator);
427c49bc 186
b1ab9ed8
A
187errOut:
188 // @@@ Zero out key material.
189 CFReleaseSafe(pubKeyDigest);
190 CFReleaseSafe(pubKeyBlob);
191 CFReleaseSafe(sizeInBits);
427c49bc 192
b1ab9ed8
A
193 return dict;
194}
195
196CFDictionaryRef SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key,
197 CFTypeRef keyType,
198 CFDataRef privateBlob)
199{
200 return SecKeyGenerateAttributeDictionaryFor(key, keyType, privateBlob);
201}
202
203CFDictionaryRef SecKeyGeneratePublicAttributeDictionary(SecKeyRef key, CFTypeRef keyType)
204{
205 return SecKeyGenerateAttributeDictionaryFor(key, keyType, NULL);
206}
207
208/*
209 */
210
427c49bc 211static CFStringRef SecKeyCopyDescription(CFTypeRef cf) {
b1ab9ed8 212 SecKeyRef key = (SecKeyRef)cf;
427c49bc
A
213
214 if(key->key_class->describe)
215 return key->key_class->describe(key);
216 else
217 return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecKeyRef: %p>"), key);
b1ab9ed8
A
218}
219
220static void SecKeyDestroy(CFTypeRef cf) {
221 SecKeyRef key = (SecKeyRef)cf;
222 if (key->key_class->destroy)
223 key->key_class->destroy(key);
224}
225
427c49bc
A
226static Boolean SecKeyEqual(CFTypeRef cf1, CFTypeRef cf2)
227{
b1ab9ed8
A
228 SecKeyRef key1 = (SecKeyRef)cf1;
229 SecKeyRef key2 = (SecKeyRef)cf2;
230 if (key1 == key2)
231 return true;
232 if (!key2 || key1->key_class != key2->key_class)
233 return false;
234 if (key1->key_class->extraBytes)
235 return !memcmp(key1->key, key2->key, key1->key_class->extraBytes);
427c49bc 236
b1ab9ed8
A
237 /* TODO: Won't work when we get reference keys. */
238 CFDictionaryRef d1, d2;
239 d1 = SecKeyCopyAttributeDictionary(key1);
240 d2 = SecKeyCopyAttributeDictionary(key2);
241 Boolean result = CFEqual(d1, d2);
242 CFReleaseSafe(d1);
243 CFReleaseSafe(d2);
244 return result;
245}
246
247static void SecKeyRegisterClass(void) {
248 static const CFRuntimeClass kSecKeyClass = {
249 0, /* version */
250 "SecKey", /* class name */
251 NULL, /* init */
252 NULL, /* copy */
253 SecKeyDestroy, /* dealloc */
254 SecKeyEqual, /* equal */
255 NULL, /* hash */
256 NULL, /* copyFormattingDesc */
427c49bc 257 SecKeyCopyDescription /* copyDebugDesc */
b1ab9ed8 258 };
427c49bc 259
b1ab9ed8
A
260 kSecKeyTypeID = _CFRuntimeRegisterClass(&kSecKeyClass);
261 register_algs();
262}
263
264/* Public API functions. */
265CFTypeID SecKeyGetTypeID(void) {
266 pthread_once(&kSecKeyRegisterClass, SecKeyRegisterClass);
267 return kSecKeyTypeID;
268}
269
270static bool getBoolForKey(CFDictionaryRef dict, CFStringRef key, bool default_value) {
271 CFTypeRef value = CFDictionaryGetValue(dict, key);
272 if (value) {
273 if (CFGetTypeID(value) == CFBooleanGetTypeID()) {
274 return CFBooleanGetValue(value);
275 } else {
276 secwarning("Value %@ for key %@ is not bool", value, key);
277 }
278 }
427c49bc 279
b1ab9ed8
A
280 return default_value;
281}
282
283static OSStatus add_ref(CFTypeRef item, CFMutableDictionaryRef dict) {
284 CFDictionarySetValue(dict, kSecValueRef, item);
285 return SecItemAdd(dict, NULL);
286}
287
288static void merge_params_applier(const void *key, const void *value,
289 void *context) {
290 CFMutableDictionaryRef result = (CFMutableDictionaryRef)context;
291 CFDictionaryAddValue(result, key, value);
292}
293
294/* Create a mutable dictionary that is based on the subdictionary for key
295 with any attributes from the top level dict merged in. */
296static CFMutableDictionaryRef merge_params(CFDictionaryRef dict,
297 CFStringRef key) {
298 CFDictionaryRef subdict = CFDictionaryGetValue(dict, key);
299 CFMutableDictionaryRef result;
427c49bc 300
b1ab9ed8
A
301 if (subdict) {
302 result = CFDictionaryCreateMutableCopy(NULL, 0, subdict);
303 /* Add everything in dict not already in result to result. */
304 CFDictionaryApplyFunction(dict, merge_params_applier, result);
305 } else {
306 result = CFDictionaryCreateMutableCopy(NULL, 0, dict);
307 }
427c49bc 308
b1ab9ed8
A
309 /* Remove values that only belong in the top level dict. */
310 CFDictionaryRemoveValue(result, kSecPublicKeyAttrs);
311 CFDictionaryRemoveValue(result, kSecPrivateKeyAttrs);
312 CFDictionaryRemoveValue(result, kSecAttrKeyType);
313 CFDictionaryRemoveValue(result, kSecAttrKeySizeInBits);
427c49bc 314
b1ab9ed8
A
315 return result;
316}
317
318/* Generate a private/public keypair. */
319OSStatus SecKeyGeneratePair(CFDictionaryRef parameters,
320 SecKeyRef *publicKey, SecKeyRef *privateKey) {
321 OSStatus result = errSecUnsupportedAlgorithm;
322 SecKeyRef privKey = NULL;
323 SecKeyRef pubKey = NULL;
324 CFMutableDictionaryRef pubParams = merge_params(parameters, kSecPublicKeyAttrs),
427c49bc 325 privParams = merge_params(parameters, kSecPrivateKeyAttrs);
b1ab9ed8 326 CFStringRef ktype = CFDictionaryGetValue(parameters, kSecAttrKeyType);
427c49bc 327
b1ab9ed8 328 require(ktype, errOut);
427c49bc 329
b1ab9ed8
A
330 if (CFEqual(ktype, kSecAttrKeyTypeEC)) {
331 result = SecECKeyGeneratePair(parameters, &pubKey, &privKey);
332 } else if (CFEqual(ktype, kSecAttrKeyTypeRSA)) {
333 result = SecRSAKeyGeneratePair(parameters, &pubKey, &privKey);
334 }
427c49bc 335
b1ab9ed8 336 require_noerr(result, errOut);
427c49bc 337
b1ab9ed8
A
338 /* Store the keys in the keychain if they are marked as permanent. */
339 if (getBoolForKey(pubParams, kSecAttrIsPermanent, false)) {
427c49bc 340 require_noerr_quiet(result = add_ref(pubKey, pubParams), errOut);
b1ab9ed8
A
341 }
342 if (getBoolForKey(privParams, kSecAttrIsPermanent, false)) {
427c49bc 343 require_noerr_quiet(result = add_ref(privKey, privParams), errOut);
b1ab9ed8 344 }
427c49bc 345
b1ab9ed8
A
346 if (publicKey) {
347 *publicKey = pubKey;
348 pubKey = NULL;
349 }
350 if (privateKey) {
351 *privateKey = privKey;
352 privKey = NULL;
353 }
427c49bc 354
b1ab9ed8
A
355errOut:
356 CFReleaseSafe(pubParams);
357 CFReleaseSafe(privParams);
358 CFReleaseSafe(pubKey);
359 CFReleaseSafe(privKey);
427c49bc
A
360
361 return result;
362}
b1ab9ed8 363
427c49bc
A
364SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey) {
365 CFDataRef serializedPublic = NULL;
366 SecKeyRef result = NULL;
367
368 require_noerr_quiet(SecKeyCopyPublicBytes(privateKey, &serializedPublic), fail);
369 require_quiet(serializedPublic, fail);
370
371 result = SecKeyCreateFromPublicData(kCFAllocatorDefault, SecKeyGetAlgorithmID(privateKey), serializedPublic);
372
373fail:
374 CFReleaseSafe(serializedPublic);
375
b1ab9ed8
A
376 return result;
377}
378
427c49bc
A
379static CFDictionaryRef CreatePrivateKeyMatchingQuery(SecKeyRef publicKey, bool returnPersistentRef)
380{
381 CFDataRef public_key_hash = SecKeyCopyPublicKeyHash(publicKey);
382
383 CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
384 kSecClass, kSecClassKey,
385 kSecAttrKeyClass, kSecAttrKeyClassPrivate,
386 kSecAttrSynchronizable, kSecAttrSynchronizableAny,
387 kSecAttrApplicationLabel, public_key_hash,
388 kSecReturnPersistentRef, kCFBooleanTrue,
389 NULL);
390 CFReleaseNull(public_key_hash);
391
392 return query;
393}
394
395CFDataRef SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) {
396 CFTypeRef persistentRef = NULL;
397 CFDictionaryRef query = CreatePrivateKeyMatchingQuery(publicKey, true);
398
399 require_quiet(SecError(SecItemCopyMatching(query, &persistentRef),error ,
400 CFSTR("Error finding persistent ref to key from public: %@"), publicKey), fail);
401fail:
402 CFReleaseNull(query);
403 return (CFDataRef)persistentRef;
404}
405
406SecKeyRef SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) {
407 CFTypeRef private_key = NULL;
408
409 CFDictionaryRef query = CreatePrivateKeyMatchingQuery(publicKey, false);
410
411 require_quiet(SecError(SecItemCopyMatching(query, &private_key), error,
412 CFSTR("Error finding private key from public: %@"), publicKey), fail);
413fail:
414 CFReleaseNull(query);
415 return (SecKeyRef)private_key;
416}
417
b1ab9ed8 418SecKeyRef SecKeyCreatePublicFromDER(CFAllocatorRef allocator,
427c49bc
A
419 const SecAsn1Oid *oid, const SecAsn1Item *params,
420 const SecAsn1Item *keyData) {
b1ab9ed8
A
421 SecKeyRef publicKey = NULL;
422 if (SecAsn1OidCompare(oid, &CSSMOID_RSA)) {
423 /* pkcs1 1 */
424 publicKey = SecKeyCreateRSAPublicKey(kCFAllocatorDefault,
427c49bc 425 keyData->Data, keyData->Length, kSecKeyEncodingPkcs1);
b1ab9ed8
A
426 } else if (SecAsn1OidCompare(oid, &CSSMOID_ecPublicKey)) {
427 SecDERKey derKey = {
428 .oid = oid->Data,
429 .oidLength = oid->Length,
430 .key = keyData->Data,
431 .keyLength = keyData->Length,
432 };
433 if (params) {
434 derKey.parameters = params->Data;
435 derKey.parametersLength = params->Length;
436 }
437 publicKey = SecKeyCreateECPublicKey(kCFAllocatorDefault,
427c49bc 438 (const uint8_t *)&derKey, sizeof(derKey), kSecDERKeyEncoding);
b1ab9ed8
A
439 } else {
440 secwarning("Unsupported algorithm oid");
441 }
427c49bc 442
b1ab9ed8
A
443 return publicKey;
444}
445
446SecKeyRef SecKeyCreate(CFAllocatorRef allocator,
427c49bc
A
447 const SecKeyDescriptor *key_class, const uint8_t *keyData,
448 CFIndex keyDataLength, SecKeyEncoding encoding) {
b1ab9ed8 449 check(key_class);
427c49bc 450
b1ab9ed8
A
451 size_t size = sizeof(struct __SecKey) + key_class->extraBytes;
452 SecKeyRef result = (SecKeyRef)_CFRuntimeCreateInstance(allocator,
427c49bc 453 SecKeyGetTypeID(), size - sizeof(CFRuntimeBase), NULL);
b1ab9ed8
A
454 if (result) {
455 memset((char*)result + sizeof(result->_base), 0, size - sizeof(result->_base));
456 result->key_class = key_class;
457 if (key_class->extraBytes) {
458 /* Make result->key point to the extraBytes we allocated. */
459 result->key = ((char*)result) + sizeof(*result);
460 }
461 if (key_class->init) {
462 OSStatus status;
463 status = key_class->init(result, keyData, keyDataLength, encoding);
464 if (status) {
427c49bc 465 secwarning("init %s key: %" PRIdOSStatus, key_class->name, status);
b1ab9ed8
A
466 CFRelease(result);
467 result = NULL;
468 }
469 }
470 }
471 return result;
472}
473
474enum {
475 kSecKeyDigestInfoSign,
476 kSecKeyDigestInfoVerify
477};
478
479static OSStatus SecKeyDigestInfoSignVerify(
427c49bc
A
480 SecKeyRef key, /* Private key */
481 SecPadding padding, /* kSecPaddingPKCS1@@@ */
482 const uint8_t *dataToSign, /* signature over this data */
483 size_t dataToSignLen, /* length of dataToSign */
484 uint8_t *sig, /* signature, RETURNED */
485 size_t *sigLen, /* IN/OUT */
486 int mode) {
b1ab9ed8
A
487 size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN;
488 uint8_t digestInfo[digestInfoLength];
489 const SecAsn1Oid *digestOid;
490 size_t digestLen;
427c49bc 491
b1ab9ed8
A
492 switch (padding) {
493#if 0
427c49bc
A
494 case kSecPaddingPKCS1MD2:
495 digestLen = CC_MD2_DIGEST_LENGTH;
496 digestOid = &CSSMOID_MD2;
497 break;
498 case kSecPaddingPKCS1MD4:
499 digestLen = CC_MD4_DIGEST_LENGTH;
500 digestOid = &CSSMOID_MD4;
501 break;
502 case kSecPaddingPKCS1MD5:
503 digestLen = CC_MD5_DIGEST_LENGTH;
504 digestOid = &CSSMOID_MD5;
505 break;
b1ab9ed8 506#endif
427c49bc
A
507 case kSecPaddingPKCS1SHA1:
508 digestLen = CC_SHA1_DIGEST_LENGTH;
509 digestOid = &CSSMOID_SHA1;
510 break;
511 case kSecPaddingPKCS1SHA224:
512 digestLen = CC_SHA224_DIGEST_LENGTH;
513 digestOid = &CSSMOID_SHA224;
514 break;
515 case kSecPaddingPKCS1SHA256:
516 digestLen = CC_SHA256_DIGEST_LENGTH;
517 digestOid = &CSSMOID_SHA256;
518 break;
519 case kSecPaddingPKCS1SHA384:
520 digestLen = CC_SHA384_DIGEST_LENGTH;
521 digestOid = &CSSMOID_SHA384;
522 break;
523 case kSecPaddingPKCS1SHA512:
524 digestLen = CC_SHA512_DIGEST_LENGTH;
525 digestOid = &CSSMOID_SHA512;
526 break;
527 default:
528 return errSecUnsupportedPadding;
b1ab9ed8 529 }
427c49bc 530
b1ab9ed8
A
531 if (dataToSignLen != digestLen)
532 return errSecParam;
427c49bc 533
b1ab9ed8 534 size_t offset = DEREncodeDigestInfoPrefix(digestOid, digestLen,
427c49bc 535 digestInfo, digestInfoLength);
b1ab9ed8
A
536 if (!offset)
537 return errSecBufferTooSmall;
427c49bc 538
b1ab9ed8
A
539 /* Append the digest to the digestInfo prefix and adjust the length. */
540 memcpy(&digestInfo[offset], dataToSign, digestLen);
541 digestInfoLength = offset + digestLen;
427c49bc 542
b1ab9ed8
A
543 if (mode == kSecKeyDigestInfoSign) {
544 return key->key_class->rawSign(key, kSecPaddingPKCS1,
427c49bc 545 digestInfo, digestInfoLength, sig, sigLen);
b1ab9ed8
A
546 } else {
547 return key->key_class->rawVerify(key, kSecPaddingPKCS1,
427c49bc 548 digestInfo, digestInfoLength, sig, *sigLen);
b1ab9ed8 549 }
427c49bc
A
550
551 return errSecSuccess;
b1ab9ed8
A
552}
553
554OSStatus SecKeyRawSign(
427c49bc
A
555 SecKeyRef key, /* Private key */
556 SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */
557 const uint8_t *dataToSign, /* signature over this data */
558 size_t dataToSignLen, /* length of dataToSign */
559 uint8_t *sig, /* signature, RETURNED */
560 size_t *sigLen) { /* IN/OUT */
b1ab9ed8
A
561 if (!key->key_class->rawSign)
562 return errSecUnsupportedOperation;
427c49bc 563
b1ab9ed8
A
564 if (padding < kSecPaddingPKCS1MD2) {
565 return key->key_class->rawSign(key, padding, dataToSign, dataToSignLen,
427c49bc 566 sig, sigLen);
b1ab9ed8
A
567 } else {
568 return SecKeyDigestInfoSignVerify(key, padding, dataToSign, dataToSignLen,
427c49bc 569 sig, sigLen, kSecKeyDigestInfoSign);
b1ab9ed8
A
570 }
571}
572
573OSStatus SecKeyRawVerify(
427c49bc
A
574 SecKeyRef key, /* Public key */
575 SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */
576 const uint8_t *signedData, /* signature over this data */
577 size_t signedDataLen, /* length of dataToSign */
578 const uint8_t *sig, /* signature */
579 size_t sigLen) { /* length of signature */
b1ab9ed8
A
580 if (!key->key_class->rawVerify)
581 return errSecUnsupportedOperation;
427c49bc 582
b1ab9ed8
A
583 if (padding < kSecPaddingPKCS1MD2) {
584 return key->key_class->rawVerify(key, padding, signedData, signedDataLen,
427c49bc 585 sig, sigLen);
b1ab9ed8
A
586 } else {
587 /* Casting away the constness of sig is safe since
427c49bc
A
588 SecKeyDigestInfoSignVerify only modifies sig if
589 mode == kSecKeyDigestInfoSign. */
b1ab9ed8 590 return SecKeyDigestInfoSignVerify(key, padding,
427c49bc
A
591 signedData, signedDataLen, (uint8_t *)sig, &sigLen,
592 kSecKeyDigestInfoVerify);
b1ab9ed8
A
593 }
594}
595
596OSStatus SecKeyEncrypt(
427c49bc
A
597 SecKeyRef key, /* Public key */
598 SecPadding padding, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
599 const uint8_t *plainText,
600 size_t plainTextLen, /* length of plainText */
601 uint8_t *cipherText,
602 size_t *cipherTextLen) { /* IN/OUT */
b1ab9ed8
A
603 if (key->key_class->encrypt)
604 return key->key_class->encrypt(key, padding, plainText, plainTextLen,
427c49bc 605 cipherText, cipherTextLen);
b1ab9ed8
A
606 return errSecUnsupportedOperation;
607}
608
609OSStatus SecKeyDecrypt(
427c49bc
A
610 SecKeyRef key, /* Private key */
611 SecPadding padding, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
612 const uint8_t *cipherText,
613 size_t cipherTextLen, /* length of cipherText */
614 uint8_t *plainText,
615 size_t *plainTextLen) { /* IN/OUT */
b1ab9ed8
A
616 if (key->key_class->decrypt)
617 return key->key_class->decrypt(key, padding, cipherText, cipherTextLen,
427c49bc 618 plainText, plainTextLen);
b1ab9ed8
A
619 return errSecUnsupportedOperation;
620}
621
622size_t SecKeyGetBlockSize(SecKeyRef key) {
623 if (key->key_class->blockSize)
624 return key->key_class->blockSize(key);
625 return 0;
626}
627
628/* Private API functions. */
629
630CFDictionaryRef SecKeyCopyAttributeDictionary(SecKeyRef key) {
631 if (key->key_class->copyDictionary)
632 return key->key_class->copyDictionary(key);
633 return NULL;
634}
635
636SecKeyRef SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes) {
637 /* TODO: Support having an allocator in refAttributes. */
638 CFAllocatorRef allocator = NULL;
639 CFDataRef data = CFDictionaryGetValue(refAttributes, kSecValueData);
640 CFTypeRef ktype = CFDictionaryGetValue(refAttributes, kSecAttrKeyType);
641 SInt32 algorithm;
642 SecKeyRef ref;
427c49bc 643
b1ab9ed8
A
644 /* First figure out the key type (algorithm). */
645 if (CFGetTypeID(ktype) == CFNumberGetTypeID()) {
646 CFNumberGetValue(ktype, kCFNumberSInt32Type, &algorithm);
427c49bc
A
647 } else if (isString(ktype)) {
648 algorithm = CFStringGetIntValue(ktype);
649 CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) algorithm);
650 if (!CFEqual(t, ktype)) {
651 secwarning("Unsupported key class: %@", ktype);
652 CFReleaseSafe(t);
653 return NULL;
654 }
655 CFReleaseSafe(t);
656 } else {
b1ab9ed8
A
657 secwarning("Unsupported key type: %@", ktype);
658 return NULL;
659 }
427c49bc 660
b1ab9ed8 661 /* TODO: The code below won't scale well, consider moving to something
427c49bc 662 table driven. */
b1ab9ed8
A
663 SInt32 class;
664 CFTypeRef kclass = CFDictionaryGetValue(refAttributes, kSecAttrKeyClass);
665 if (CFGetTypeID(kclass) == CFNumberGetTypeID()) {
666 CFNumberGetValue(kclass, kCFNumberSInt32Type, &class);
427c49bc
A
667 } else if (isString(kclass)) {
668 class = CFStringGetIntValue(kclass);
669 CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) class);
670 if (!CFEqual(t, kclass)) {
671 CFReleaseSafe(t);
672 secwarning("Unsupported key class: %@", kclass);
673 return NULL;
674 }
675 CFReleaseSafe(t);
676 } else {
b1ab9ed8
A
677 secwarning("Unsupported key class: %@", kclass);
678 return NULL;
679 }
427c49bc 680
b1ab9ed8
A
681 switch (class) {
682 case 0: // kSecAttrKeyClassPublic
683 switch (algorithm) {
684 case 42: // kSecAlgorithmRSA
685 ref = SecKeyCreateRSAPublicKey(allocator,
686 CFDataGetBytePtr(data), CFDataGetLength(data),
687 kSecKeyEncodingBytes);
688 break;
689 case 43: // kSecAlgorithmECDSA
427c49bc 690 case 73: // kSecAlgorithmEC
b1ab9ed8
A
691 ref = SecKeyCreateECPublicKey(allocator,
692 CFDataGetBytePtr(data), CFDataGetLength(data),
693 kSecKeyEncodingBytes);
694 break;
695 default:
696 secwarning("Unsupported public key type: %@", ktype);
697 ref = NULL;
698 break;
699 };
700 break;
701 case 1: // kSecAttrKeyClassPrivate
702 switch (algorithm) {
703 case 42: // kSecAlgorithmRSA
704 ref = SecKeyCreateRSAPrivateKey(allocator,
705 CFDataGetBytePtr(data), CFDataGetLength(data),
706 kSecKeyEncodingBytes);
707 break;
708 case 43: // kSecAlgorithmECDSA
427c49bc 709 case 73: // kSecAlgorithmEC
b1ab9ed8
A
710 ref = SecKeyCreateECPrivateKey(allocator,
711 CFDataGetBytePtr(data), CFDataGetLength(data),
712 kSecKeyEncodingBytes);
713 break;
714 default:
715 secwarning("Unsupported private key type: %@", ktype);
716 ref = NULL;
717 break;
718 };
719 break;
720 case 2: // kSecAttrKeyClassSymmetric
721 secwarning("Unsupported symmetric key type: %@", ktype);
722 ref = NULL;
723 break;
724 default:
725 secwarning("Unsupported key class: %@", kclass);
726 ref = NULL;
727 }
427c49bc 728
b1ab9ed8
A
729 return ref;
730}
731
732/* TODO: This function should ensure that this keys algorithm matches the
427c49bc 733 signature algorithm. */
b1ab9ed8 734static OSStatus SecKeyGetDigestInfo(SecKeyRef this, const SecAsn1AlgId *algId,
427c49bc
A
735 const uint8_t *data, size_t dataLen, bool digestData,
736 uint8_t *digestInfo, size_t *digestInfoLen /* IN/OUT */) {
b1ab9ed8
A
737 unsigned char *(*digestFcn)(const void *, CC_LONG, unsigned char *);
738 CFIndex keyAlgID = kSecNullAlgorithmID;
739 const SecAsn1Oid *digestOid;
740 size_t digestLen;
741 size_t offset = 0;
427c49bc 742
b1ab9ed8
A
743 /* Since these oids all have the same prefix, use switch. */
744 if ((algId->algorithm.Length == CSSMOID_RSA.Length) &&
745 !memcmp(algId->algorithm.Data, CSSMOID_RSA.Data,
427c49bc
A
746 algId->algorithm.Length - 1)) {
747 keyAlgID = kSecRSAAlgorithmID;
748 switch (algId->algorithm.Data[algId->algorithm.Length - 1]) {
b1ab9ed8 749#if 0
427c49bc
A
750 case 2: /* oidMD2WithRSA */
751 digestFcn = CC_MD2;
752 digestLen = CC_MD2_DIGEST_LENGTH;
753 digestOid = &CSSMOID_MD2;
754 break;
755 case 3: /* oidMD4WithRSA */
756 digestFcn = CC_MD4;
757 digestLen = CC_MD4_DIGEST_LENGTH;
758 digestOid = &CSSMOID_MD4;
759 break;
760 case 4: /* oidMD5WithRSA */
761 digestFcn = CC_MD5;
762 digestLen = CC_MD5_DIGEST_LENGTH;
763 digestOid = &CSSMOID_MD5;
764 break;
b1ab9ed8 765#endif /* 0 */
427c49bc
A
766 case 5: /* oidSHA1WithRSA */
767 digestFcn = CC_SHA1;
768 digestLen = CC_SHA1_DIGEST_LENGTH;
769 digestOid = &CSSMOID_SHA1;
770 break;
771 case 11: /* oidSHA256WithRSA */
772 digestFcn = CC_SHA256;
773 digestLen = CC_SHA256_DIGEST_LENGTH;
774 digestOid = &CSSMOID_SHA256;
775 break;
776 case 12: /* oidSHA384WithRSA */
777 /* pkcs1 12 */
778 digestFcn = CC_SHA384;
779 digestLen = CC_SHA384_DIGEST_LENGTH;
780 digestOid = &CSSMOID_SHA384;
781 break;
782 case 13: /* oidSHA512WithRSA */
783 digestFcn = CC_SHA512;
784 digestLen = CC_SHA512_DIGEST_LENGTH;
785 digestOid = &CSSMOID_SHA512;
786 break;
787 case 14: /* oidSHA224WithRSA */
788 digestFcn = CC_SHA224;
789 digestLen = CC_SHA224_DIGEST_LENGTH;
790 digestOid = &CSSMOID_SHA224;
791 break;
792 default:
793 secdebug("key", "unsupported rsa signature algorithm");
794 return errSecUnsupportedAlgorithm;
795 }
796 } else if ((algId->algorithm.Length == CSSMOID_ECDSA_WithSHA224.Length) &&
797 !memcmp(algId->algorithm.Data, CSSMOID_ECDSA_WithSHA224.Data,
798 algId->algorithm.Length - 1)) {
799 keyAlgID = kSecECDSAAlgorithmID;
800 switch (algId->algorithm.Data[algId->algorithm.Length - 1]) {
801 case 1: /* oidSHA224WithECDSA */
802 digestFcn = CC_SHA224;
803 digestLen = CC_SHA224_DIGEST_LENGTH;
804 break;
805 case 2: /* oidSHA256WithECDSA */
806 digestFcn = CC_SHA256;
807 digestLen = CC_SHA256_DIGEST_LENGTH;
808 break;
809 case 3: /* oidSHA384WithECDSA */
810 /* pkcs1 12 */
811 digestFcn = CC_SHA384;
812 digestLen = CC_SHA384_DIGEST_LENGTH;
813 break;
814 case 4: /* oidSHA512WithECDSA */
815 digestFcn = CC_SHA512;
816 digestLen = CC_SHA512_DIGEST_LENGTH;
817 break;
818 default:
819 secdebug("key", "unsupported ecdsa signature algorithm");
820 return errSecUnsupportedAlgorithm;
821 }
822 } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_ECDSA_WithSHA1)) {
823 keyAlgID = kSecECDSAAlgorithmID;
824 digestFcn = CC_SHA1;
825 digestLen = CC_SHA1_DIGEST_LENGTH;
826 } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_SHA1)) {
827 digestFcn = CC_SHA1;
828 digestLen = CC_SHA1_DIGEST_LENGTH;
829 digestOid = &CSSMOID_SHA1;
830 } else if ((algId->algorithm.Length == CSSMOID_SHA224.Length) &&
831 !memcmp(algId->algorithm.Data, CSSMOID_SHA224.Data, algId->algorithm.Length - 1))
832 {
833 switch (algId->algorithm.Data[algId->algorithm.Length - 1]) {
834 case 4: /* OID_SHA224 */
835 digestFcn = CC_SHA224;
836 digestLen = CC_SHA224_DIGEST_LENGTH;
837 digestOid = &CSSMOID_SHA224;
838 break;
839 case 1: /* OID_SHA256 */
840 digestFcn = CC_SHA256;
841 digestLen = CC_SHA256_DIGEST_LENGTH;
842 digestOid = &CSSMOID_SHA256;
843 break;
844 case 2: /* OID_SHA384 */
845 /* pkcs1 12 */
846 digestFcn = CC_SHA384;
847 digestLen = CC_SHA384_DIGEST_LENGTH;
848 digestOid = &CSSMOID_SHA384;
849 break;
850 case 3: /* OID_SHA512 */
851 digestFcn = CC_SHA512;
852 digestLen = CC_SHA512_DIGEST_LENGTH;
853 digestOid = &CSSMOID_SHA512;
854 break;
855 default:
856 secdebug("key", "unsupported sha-2 signature algorithm");
857 return errSecUnsupportedAlgorithm;
858 }
859 } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_MD5)) {
860 digestFcn = CC_MD5;
861 digestLen = CC_MD5_DIGEST_LENGTH;
862 digestOid = &CSSMOID_MD5;
863 } else {
864 secdebug("key", "unsupported digesting algorithm");
865 return errSecUnsupportedAlgorithm;
866 }
867
b1ab9ed8
A
868 /* check key is appropriate for signature (superfluous for digest only oid) */
869 if (keyAlgID == kSecNullAlgorithmID)
870 keyAlgID = SecKeyGetAlgorithmID(this);
871 else if (keyAlgID != SecKeyGetAlgorithmID(this))
872 return errSecUnsupportedAlgorithm;
427c49bc 873
b1ab9ed8
A
874 switch(keyAlgID) {
875 case kSecRSAAlgorithmID:
876 offset = DEREncodeDigestInfoPrefix(digestOid, digestLen,
877 digestInfo, *digestInfoLen);
878 if (!offset)
879 return errSecBufferTooSmall;
880 break;
881 case kSecDSAAlgorithmID:
882 if (digestOid != &CSSMOID_SHA1)
883 return errSecUnsupportedAlgorithm;
884 break;
885 case kSecECDSAAlgorithmID:
886 break;
887 default:
888 secdebug("key", "unsupported signature algorithm");
889 return errSecUnsupportedAlgorithm;
890 }
427c49bc 891
b1ab9ed8
A
892 if (digestData) {
893 if(dataLen>UINT32_MAX) /* Check for overflow with CC_LONG cast */
427c49bc 894 return errSecParam;
b1ab9ed8
A
895 digestFcn(data, (CC_LONG)dataLen, &digestInfo[offset]);
896 *digestInfoLen = offset + digestLen;
897 } else {
898 if (dataLen != digestLen)
427c49bc 899 return errSecParam;
b1ab9ed8
A
900 memcpy(&digestInfo[offset], data, dataLen);
901 *digestInfoLen = offset + dataLen;
902 }
427c49bc
A
903
904 return errSecSuccess;
b1ab9ed8
A
905}
906
907OSStatus SecKeyDigestAndVerify(
427c49bc
A
908 SecKeyRef this, /* Private key */
909 const SecAsn1AlgId *algId, /* algorithm oid/params */
910 const uint8_t *dataToDigest, /* signature over this data */
911 size_t dataToDigestLen,/* length of dataToDigest */
912 const uint8_t *sig, /* signature to verify */
913 size_t sigLen) { /* length of sig */
b1ab9ed8
A
914 size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN;
915 uint8_t digestInfo[digestInfoLength];
916 OSStatus status;
427c49bc
A
917
918 if (this == NULL)
919 return errSecParam;
920
b1ab9ed8 921 status = SecKeyGetDigestInfo(this, algId, dataToDigest, dataToDigestLen, true,
427c49bc 922 digestInfo, &digestInfoLength);
b1ab9ed8
A
923 if (status)
924 return status;
925 return SecKeyRawVerify(this, kSecPaddingPKCS1,
427c49bc 926 digestInfo, digestInfoLength, sig, sigLen);
b1ab9ed8
A
927}
928
929OSStatus SecKeyDigestAndSign(
427c49bc
A
930 SecKeyRef this, /* Private key */
931 const SecAsn1AlgId *algId, /* algorithm oid/params */
932 const uint8_t *dataToDigest, /* signature over this data */
933 size_t dataToDigestLen,/* length of dataToDigest */
934 uint8_t *sig, /* signature, RETURNED */
935 size_t *sigLen) { /* IN/OUT */
b1ab9ed8
A
936 size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN;
937 uint8_t digestInfo[digestInfoLength];
938 OSStatus status;
427c49bc 939
b1ab9ed8 940 status = SecKeyGetDigestInfo(this, algId, dataToDigest, dataToDigestLen, true /* digest data */,
427c49bc 941 digestInfo, &digestInfoLength);
b1ab9ed8
A
942 if (status)
943 return status;
944 return SecKeyRawSign(this, kSecPaddingPKCS1,
427c49bc 945 digestInfo, digestInfoLength, sig, sigLen);
b1ab9ed8
A
946}
947
948OSStatus SecKeyVerifyDigest(
427c49bc
A
949 SecKeyRef this, /* Private key */
950 const SecAsn1AlgId *algId, /* algorithm oid/params */
951 const uint8_t *digestData, /* signature over this digest */
952 size_t digestDataLen,/* length of dataToDigest */
953 const uint8_t *sig, /* signature to verify */
954 size_t sigLen) { /* length of sig */
b1ab9ed8
A
955 size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN;
956 uint8_t digestInfo[digestInfoLength];
957 OSStatus status;
427c49bc 958
b1ab9ed8
A
959 status = SecKeyGetDigestInfo(this, algId, digestData, digestDataLen, false /* data is digest */,
960 digestInfo, &digestInfoLength);
961 if (status)
962 return status;
963 return SecKeyRawVerify(this, kSecPaddingPKCS1,
964 digestInfo, digestInfoLength, sig, sigLen);
965}
966
967OSStatus SecKeySignDigest(
427c49bc
A
968 SecKeyRef this, /* Private key */
969 const SecAsn1AlgId *algId, /* algorithm oid/params */
970 const uint8_t *digestData, /* signature over this digest */
971 size_t digestDataLen,/* length of digestData */
972 uint8_t *sig, /* signature, RETURNED */
973 size_t *sigLen) { /* IN/OUT */
b1ab9ed8
A
974 size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN;
975 uint8_t digestInfo[digestInfoLength];
976 OSStatus status;
427c49bc 977
b1ab9ed8
A
978 status = SecKeyGetDigestInfo(this, algId, digestData, digestDataLen, false,
979 digestInfo, &digestInfoLength);
980 if (status)
981 return status;
982 return SecKeyRawSign(this, kSecPaddingPKCS1,
983 digestInfo, digestInfoLength, sig, sigLen);
984}
985
986CFIndex SecKeyGetAlgorithmID(SecKeyRef key) {
987 /* This method was added to version 1 keys. */
988 if (key->key_class->version > 0 && key->key_class->getAlgorithmID)
989 return key->key_class->getAlgorithmID(key);
990 /* All version 0 key were RSA. */
991 return kSecRSAAlgorithmID;
992}
993
994
995OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* serializedPublic) {
996 if (key->key_class->version > 1 && key->key_class->copyPublic)
997 return key->key_class->copyPublic(key, serializedPublic);
998 return errSecUnimplemented;
999}
1000
1001SecKeyRef SecKeyCreateFromPublicBytes(CFAllocatorRef allocator, CFIndex algorithmID, const uint8_t *keyData, CFIndex keyDataLength)
1002{
1003 switch (algorithmID)
1004 {
1005 case kSecRSAAlgorithmID:
1006 return SecKeyCreateRSAPublicKey(allocator,
1007 keyData, keyDataLength,
1008 kSecKeyEncodingBytes);
1009 case kSecECDSAAlgorithmID:
1010 return SecKeyCreateECPublicKey(allocator,
1011 keyData, keyDataLength,
1012 kSecKeyEncodingBytes);
1013 default:
1014 return NULL;
1015 }
1016}
1017
1018SecKeyRef SecKeyCreateFromPublicData(CFAllocatorRef allocator, CFIndex algorithmID, CFDataRef serialized)
1019{
1020 return SecKeyCreateFromPublicBytes(allocator, algorithmID, CFDataGetBytePtr(serialized), CFDataGetLength(serialized));
1021}
1022
1023// This is a bit icky hack to avoid changing the vtable for
1024// SecKey.
1025size_t SecKeyGetSize(SecKeyRef key, SecKeySize whichSize)
1026{
1027 size_t result = SecKeyGetBlockSize(key);
427c49bc 1028
b1ab9ed8
A
1029 if (kSecECDSAAlgorithmID == SecKeyGetAlgorithmID(key)) {
1030 switch (whichSize) {
1031 case kSecKeyEncryptedDataSize:
1032 result = 0;
1033 break;
1034 case kSecKeySignatureSize:
427c49bc 1035 result = (result >= 66 ? 9 : 8) + 2 * result;
b1ab9ed8
A
1036 break;
1037 case kSecKeyKeySizeInBits:
1038 if (result >= 66)
1039 return 521;
1040 }
1041 }
427c49bc 1042
b1ab9ed8 1043 if (whichSize == kSecKeyKeySizeInBits)
427c49bc
A
1044 result *= 8;
1045
b1ab9ed8 1046 return result;
427c49bc
A
1047
1048}
b1ab9ed8 1049
427c49bc
A
1050OSStatus SecKeyFindWithPersistentRef(CFDataRef persistentRef, SecKeyRef* lookedUpData)
1051{
1052 CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
1053 kSecReturnRef, kCFBooleanTrue,
1054 kSecClass, kSecClassKey,
1055 kSecValuePersistentRef, persistentRef,
1056 NULL);
1057 CFTypeRef foundRef = NULL;
1058 OSStatus status = SecItemCopyMatching(query, &foundRef);
1059
1060 if (status == errSecSuccess) {
1061 if (CFGetTypeID(foundRef) == SecKeyGetTypeID()) {
1062 *lookedUpData = (SecKeyRef) foundRef;
1063 foundRef = NULL;
1064 status = errSecSuccess;
1065 } else {
1066 status = errSecItemNotFound;
1067 }
1068 }
1069
1070 CFReleaseSafe(foundRef);
1071 CFReleaseSafe(query);
1072
1073 return status;
b1ab9ed8
A
1074}
1075
427c49bc
A
1076OSStatus SecKeyCopyPersistentRef(SecKeyRef key, CFDataRef* persistentRef)
1077{
1078 CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
1079 kSecReturnPersistentRef, kCFBooleanTrue,
1080 kSecValueRef, key,
1081 kSecAttrSynchronizable, kSecAttrSynchronizableAny,
1082 NULL);
1083 CFTypeRef foundRef = NULL;
1084 OSStatus status = SecItemCopyMatching(query, &foundRef);
1085
1086 if (status == errSecSuccess) {
1087 if (CFGetTypeID(foundRef) == CFDataGetTypeID()) {
1088 *persistentRef = foundRef;
1089 foundRef = NULL;
1090 } else {
1091 status = errSecItemNotFound;
1092 }
1093 }
1094
1095 CFReleaseSafe(foundRef);
1096 CFReleaseSafe(query);
1097
1098 return status;
1099}