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