]> git.saurik.com Git - apple/security.git/blob - sec/Security/SecKey.c
Security-55471.14.8.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 <utilities/SecIOFormat.h>
35
36 #include <utilities/SecCFWrappers.h>
37
38 #include "SecRSAKeyPriv.h"
39 #include "SecECKey.h"
40 #include "SecBasePriv.h"
41
42 #include <CoreFoundation/CFNumber.h>
43 #include <CoreFoundation/CFString.h>
44 #include <Security/SecBase.h>
45 #include <pthread.h>
46 #include <string.h>
47 #include <AssertMacros.h>
48 #include <utilities/debugging.h>
49 #include <utilities/SecCFError.h>
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>
57 #include <stdlib.h>
58
59 static pthread_once_t kSecKeyRegisterClass = PTHREAD_ONCE_INIT;
60 static CFTypeID kSecKeyTypeID = _kCFRuntimeNotATypeID;
61
62 /* Forward declartions of static functions. */
63 static CFStringRef SecKeyCopyDescription(CFTypeRef cf);
64 static 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
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 static struct ccrng_system_state ccrng_system_state_seckey;
114
115 static 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
121 static 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);
133 errOut:
134 CFReleaseNull(pubKeyBlob);
135 return pubKeyDigest;
136 }
137
138
139 /*
140 */
141 static CF_RETURNS_RETAINED CFDictionaryRef SecKeyGenerateAttributeDictionaryFor(SecKeyRef key,
142 CFTypeRef keyType,
143 CFDataRef privateBlob)
144 {
145 CFAllocatorRef allocator = CFGetAllocator(key);
146 DICT_DECLARE(25);
147 CFDataRef pubKeyDigest = NULL, pubKeyBlob = NULL;
148 CFDictionaryRef dict = NULL;
149
150 size_t sizeValue = SecKeyGetSize(key, kSecKeyKeySizeInBits);
151 CFNumberRef sizeInBits = CFNumberCreate(allocator, kCFNumberLongType, &sizeValue);
152
153 /* encode the public key. */
154 require_noerr(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut);
155 require(pubKeyBlob, errOut);
156
157 /* Calculate the digest of the public key. */
158 require(pubKeyDigest = SecSHA1DigestCreate(allocator,
159 CFDataGetBytePtr(pubKeyBlob), CFDataGetLength(pubKeyBlob)),
160 errOut);
161
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);
186
187 errOut:
188 // @@@ Zero out key material.
189 CFReleaseSafe(pubKeyDigest);
190 CFReleaseSafe(pubKeyBlob);
191 CFReleaseSafe(sizeInBits);
192
193 return dict;
194 }
195
196 CFDictionaryRef SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key,
197 CFTypeRef keyType,
198 CFDataRef privateBlob)
199 {
200 return SecKeyGenerateAttributeDictionaryFor(key, keyType, privateBlob);
201 }
202
203 CFDictionaryRef SecKeyGeneratePublicAttributeDictionary(SecKeyRef key, CFTypeRef keyType)
204 {
205 return SecKeyGenerateAttributeDictionaryFor(key, keyType, NULL);
206 }
207
208 /*
209 */
210
211 static CFStringRef SecKeyCopyDescription(CFTypeRef cf) {
212 SecKeyRef key = (SecKeyRef)cf;
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);
218 }
219
220 static void SecKeyDestroy(CFTypeRef cf) {
221 SecKeyRef key = (SecKeyRef)cf;
222 if (key->key_class->destroy)
223 key->key_class->destroy(key);
224 }
225
226 static Boolean SecKeyEqual(CFTypeRef cf1, CFTypeRef cf2)
227 {
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);
236
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
247 static 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 */
257 SecKeyCopyDescription /* copyDebugDesc */
258 };
259
260 kSecKeyTypeID = _CFRuntimeRegisterClass(&kSecKeyClass);
261 register_algs();
262 }
263
264 /* Public API functions. */
265 CFTypeID SecKeyGetTypeID(void) {
266 pthread_once(&kSecKeyRegisterClass, SecKeyRegisterClass);
267 return kSecKeyTypeID;
268 }
269
270 static 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 }
279
280 return default_value;
281 }
282
283 static OSStatus add_ref(CFTypeRef item, CFMutableDictionaryRef dict) {
284 CFDictionarySetValue(dict, kSecValueRef, item);
285 return SecItemAdd(dict, NULL);
286 }
287
288 static 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. */
296 static CFMutableDictionaryRef merge_params(CFDictionaryRef dict,
297 CFStringRef key) {
298 CFDictionaryRef subdict = CFDictionaryGetValue(dict, key);
299 CFMutableDictionaryRef result;
300
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 }
308
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);
314
315 return result;
316 }
317
318 /* Generate a private/public keypair. */
319 OSStatus 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),
325 privParams = merge_params(parameters, kSecPrivateKeyAttrs);
326 CFStringRef ktype = CFDictionaryGetValue(parameters, kSecAttrKeyType);
327
328 require(ktype, errOut);
329
330 if (CFEqual(ktype, kSecAttrKeyTypeEC)) {
331 result = SecECKeyGeneratePair(parameters, &pubKey, &privKey);
332 } else if (CFEqual(ktype, kSecAttrKeyTypeRSA)) {
333 result = SecRSAKeyGeneratePair(parameters, &pubKey, &privKey);
334 }
335
336 require_noerr(result, errOut);
337
338 /* Store the keys in the keychain if they are marked as permanent. */
339 if (getBoolForKey(pubParams, kSecAttrIsPermanent, false)) {
340 require_noerr_quiet(result = add_ref(pubKey, pubParams), errOut);
341 }
342 if (getBoolForKey(privParams, kSecAttrIsPermanent, false)) {
343 require_noerr_quiet(result = add_ref(privKey, privParams), errOut);
344 }
345
346 if (publicKey) {
347 *publicKey = pubKey;
348 pubKey = NULL;
349 }
350 if (privateKey) {
351 *privateKey = privKey;
352 privKey = NULL;
353 }
354
355 errOut:
356 CFReleaseSafe(pubParams);
357 CFReleaseSafe(privParams);
358 CFReleaseSafe(pubKey);
359 CFReleaseSafe(privKey);
360
361 return result;
362 }
363
364 SecKeyRef 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
373 fail:
374 CFReleaseSafe(serializedPublic);
375
376 return result;
377 }
378
379 static 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
395 CFDataRef 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);
401 fail:
402 CFReleaseNull(query);
403 return (CFDataRef)persistentRef;
404 }
405
406 SecKeyRef 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);
413 fail:
414 CFReleaseNull(query);
415 return (SecKeyRef)private_key;
416 }
417
418 SecKeyRef SecKeyCreatePublicFromDER(CFAllocatorRef allocator,
419 const SecAsn1Oid *oid, const SecAsn1Item *params,
420 const SecAsn1Item *keyData) {
421 SecKeyRef publicKey = NULL;
422 if (SecAsn1OidCompare(oid, &CSSMOID_RSA)) {
423 /* pkcs1 1 */
424 publicKey = SecKeyCreateRSAPublicKey(kCFAllocatorDefault,
425 keyData->Data, keyData->Length, kSecKeyEncodingPkcs1);
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,
438 (const uint8_t *)&derKey, sizeof(derKey), kSecDERKeyEncoding);
439 } else {
440 secwarning("Unsupported algorithm oid");
441 }
442
443 return publicKey;
444 }
445
446 SecKeyRef SecKeyCreate(CFAllocatorRef allocator,
447 const SecKeyDescriptor *key_class, const uint8_t *keyData,
448 CFIndex keyDataLength, SecKeyEncoding encoding) {
449 check(key_class);
450
451 size_t size = sizeof(struct __SecKey) + key_class->extraBytes;
452 SecKeyRef result = (SecKeyRef)_CFRuntimeCreateInstance(allocator,
453 SecKeyGetTypeID(), size - sizeof(CFRuntimeBase), NULL);
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) {
465 secwarning("init %s key: %" PRIdOSStatus, key_class->name, status);
466 CFRelease(result);
467 result = NULL;
468 }
469 }
470 }
471 return result;
472 }
473
474 enum {
475 kSecKeyDigestInfoSign,
476 kSecKeyDigestInfoVerify
477 };
478
479 static OSStatus SecKeyDigestInfoSignVerify(
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) {
487 size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN;
488 uint8_t digestInfo[digestInfoLength];
489 const SecAsn1Oid *digestOid;
490 size_t digestLen;
491
492 switch (padding) {
493 #if 0
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;
506 #endif
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;
529 }
530
531 if (dataToSignLen != digestLen)
532 return errSecParam;
533
534 size_t offset = DEREncodeDigestInfoPrefix(digestOid, digestLen,
535 digestInfo, digestInfoLength);
536 if (!offset)
537 return errSecBufferTooSmall;
538
539 /* Append the digest to the digestInfo prefix and adjust the length. */
540 memcpy(&digestInfo[offset], dataToSign, digestLen);
541 digestInfoLength = offset + digestLen;
542
543 if (mode == kSecKeyDigestInfoSign) {
544 return key->key_class->rawSign(key, kSecPaddingPKCS1,
545 digestInfo, digestInfoLength, sig, sigLen);
546 } else {
547 return key->key_class->rawVerify(key, kSecPaddingPKCS1,
548 digestInfo, digestInfoLength, sig, *sigLen);
549 }
550
551 return errSecSuccess;
552 }
553
554 OSStatus SecKeyRawSign(
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 */
561 if (!key->key_class->rawSign)
562 return errSecUnsupportedOperation;
563
564 if (padding < kSecPaddingPKCS1MD2) {
565 return key->key_class->rawSign(key, padding, dataToSign, dataToSignLen,
566 sig, sigLen);
567 } else {
568 return SecKeyDigestInfoSignVerify(key, padding, dataToSign, dataToSignLen,
569 sig, sigLen, kSecKeyDigestInfoSign);
570 }
571 }
572
573 OSStatus SecKeyRawVerify(
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 */
580 if (!key->key_class->rawVerify)
581 return errSecUnsupportedOperation;
582
583 if (padding < kSecPaddingPKCS1MD2) {
584 return key->key_class->rawVerify(key, padding, signedData, signedDataLen,
585 sig, sigLen);
586 } else {
587 /* Casting away the constness of sig is safe since
588 SecKeyDigestInfoSignVerify only modifies sig if
589 mode == kSecKeyDigestInfoSign. */
590 return SecKeyDigestInfoSignVerify(key, padding,
591 signedData, signedDataLen, (uint8_t *)sig, &sigLen,
592 kSecKeyDigestInfoVerify);
593 }
594 }
595
596 OSStatus SecKeyEncrypt(
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 */
603 if (key->key_class->encrypt)
604 return key->key_class->encrypt(key, padding, plainText, plainTextLen,
605 cipherText, cipherTextLen);
606 return errSecUnsupportedOperation;
607 }
608
609 OSStatus SecKeyDecrypt(
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 */
616 if (key->key_class->decrypt)
617 return key->key_class->decrypt(key, padding, cipherText, cipherTextLen,
618 plainText, plainTextLen);
619 return errSecUnsupportedOperation;
620 }
621
622 size_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
630 CFDictionaryRef SecKeyCopyAttributeDictionary(SecKeyRef key) {
631 if (key->key_class->copyDictionary)
632 return key->key_class->copyDictionary(key);
633 return NULL;
634 }
635
636 SecKeyRef 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;
643
644 /* First figure out the key type (algorithm). */
645 if (CFGetTypeID(ktype) == CFNumberGetTypeID()) {
646 CFNumberGetValue(ktype, kCFNumberSInt32Type, &algorithm);
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 {
657 secwarning("Unsupported key type: %@", ktype);
658 return NULL;
659 }
660
661 /* TODO: The code below won't scale well, consider moving to something
662 table driven. */
663 SInt32 class;
664 CFTypeRef kclass = CFDictionaryGetValue(refAttributes, kSecAttrKeyClass);
665 if (CFGetTypeID(kclass) == CFNumberGetTypeID()) {
666 CFNumberGetValue(kclass, kCFNumberSInt32Type, &class);
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 {
677 secwarning("Unsupported key class: %@", kclass);
678 return NULL;
679 }
680
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
690 case 73: // kSecAlgorithmEC
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
709 case 73: // kSecAlgorithmEC
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 }
728
729 return ref;
730 }
731
732 /* TODO: This function should ensure that this keys algorithm matches the
733 signature algorithm. */
734 static OSStatus SecKeyGetDigestInfo(SecKeyRef this, const SecAsn1AlgId *algId,
735 const uint8_t *data, size_t dataLen, bool digestData,
736 uint8_t *digestInfo, size_t *digestInfoLen /* IN/OUT */) {
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;
742
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,
746 algId->algorithm.Length - 1)) {
747 keyAlgID = kSecRSAAlgorithmID;
748 switch (algId->algorithm.Data[algId->algorithm.Length - 1]) {
749 #if 0
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;
765 #endif /* 0 */
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
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;
873
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 }
891
892 if (digestData) {
893 if(dataLen>UINT32_MAX) /* Check for overflow with CC_LONG cast */
894 return errSecParam;
895 digestFcn(data, (CC_LONG)dataLen, &digestInfo[offset]);
896 *digestInfoLen = offset + digestLen;
897 } else {
898 if (dataLen != digestLen)
899 return errSecParam;
900 memcpy(&digestInfo[offset], data, dataLen);
901 *digestInfoLen = offset + dataLen;
902 }
903
904 return errSecSuccess;
905 }
906
907 OSStatus SecKeyDigestAndVerify(
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 */
914 size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN;
915 uint8_t digestInfo[digestInfoLength];
916 OSStatus status;
917
918 if (this == NULL)
919 return errSecParam;
920
921 status = SecKeyGetDigestInfo(this, algId, dataToDigest, dataToDigestLen, true,
922 digestInfo, &digestInfoLength);
923 if (status)
924 return status;
925 return SecKeyRawVerify(this, kSecPaddingPKCS1,
926 digestInfo, digestInfoLength, sig, sigLen);
927 }
928
929 OSStatus SecKeyDigestAndSign(
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 */
936 size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN;
937 uint8_t digestInfo[digestInfoLength];
938 OSStatus status;
939
940 status = SecKeyGetDigestInfo(this, algId, dataToDigest, dataToDigestLen, true /* digest data */,
941 digestInfo, &digestInfoLength);
942 if (status)
943 return status;
944 return SecKeyRawSign(this, kSecPaddingPKCS1,
945 digestInfo, digestInfoLength, sig, sigLen);
946 }
947
948 OSStatus SecKeyVerifyDigest(
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 */
955 size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN;
956 uint8_t digestInfo[digestInfoLength];
957 OSStatus status;
958
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
967 OSStatus SecKeySignDigest(
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 */
974 size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN;
975 uint8_t digestInfo[digestInfoLength];
976 OSStatus status;
977
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
986 CFIndex 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
995 OSStatus 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
1001 SecKeyRef 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
1018 SecKeyRef 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.
1025 size_t SecKeyGetSize(SecKeyRef key, SecKeySize whichSize)
1026 {
1027 size_t result = SecKeyGetBlockSize(key);
1028
1029 if (kSecECDSAAlgorithmID == SecKeyGetAlgorithmID(key)) {
1030 switch (whichSize) {
1031 case kSecKeyEncryptedDataSize:
1032 result = 0;
1033 break;
1034 case kSecKeySignatureSize:
1035 result = (result >= 66 ? 9 : 8) + 2 * result;
1036 break;
1037 case kSecKeyKeySizeInBits:
1038 if (result >= 66)
1039 return 521;
1040 }
1041 }
1042
1043 if (whichSize == kSecKeyKeySizeInBits)
1044 result *= 8;
1045
1046 return result;
1047
1048 }
1049
1050 OSStatus 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;
1074 }
1075
1076 OSStatus 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 }