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