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