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
79static 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
106static 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);
118errOut:
119    CFReleaseNull(pubKeyBlob);
120    return pubKeyDigest;
121}
122
123
124/*
125 */
126static 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
172errOut:
173	// @@@ Zero out key material.
174	CFReleaseSafe(pubKeyDigest);
175	CFReleaseSafe(pubKeyBlob);
176	CFReleaseSafe(sizeInBits);
177
178	return dict;
179}
180
181CFDictionaryRef SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key,
182                                                         CFTypeRef keyType,
183                                                         CFDataRef privateBlob)
184{
185    return SecKeyCopyAttributeDictionaryWithLocalKey(key, keyType, privateBlob);
186}
187
188CFDictionaryRef SecKeyGeneratePublicAttributeDictionary(SecKeyRef key, CFTypeRef keyType)
189{
190    return SecKeyCopyAttributeDictionaryWithLocalKey(key, keyType, NULL);
191}
192
193static 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
202static void SecKeyDestroy(CFTypeRef cf) {
203    SecKeyRef key = (SecKeyRef)cf;
204    if (key->key_class->destroy)
205        key->key_class->destroy(key);
206}
207
208static 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
229struct ccrng_state *ccrng_seckey;
230
231CFGiblisWithFunctions(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
237static 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
250static OSStatus add_ref(CFTypeRef item, CFMutableDictionaryRef dict) {
251	CFDictionarySetValue(dict, kSecValueRef, item);
252	return SecItemAdd(dict, NULL);
253}
254
255static 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. */
263static 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. */
286OSStatus 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
322errOut:
323	CFReleaseSafe(pubParams);
324	CFReleaseSafe(privParams);
325    CFReleaseSafe(pubKey);
326    CFReleaseSafe(privKey);
327
328    return result;
329}
330
331SecKeyRef 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
340fail:
341    CFReleaseSafe(serializedPublic);
342
343    return result;
344}
345
346static 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
362CFDataRef 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);
368fail:
369    CFReleaseNull(query);
370    return (CFDataRef)persistentRef;
371}
372
373SecKeyRef 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);
380fail:
381    CFReleaseNull(query);
382    return (SecKeyRef)private_key;
383}
384
385SecKeyRef 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
413SecKeyRef 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
440enum {
441    kSecKeyDigestInfoSign,
442    kSecKeyDigestInfoVerify
443};
444
445static 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
520OSStatus 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
539OSStatus 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
562OSStatus 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
575OSStatus 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
588size_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
596CFDictionaryRef SecKeyCopyAttributeDictionary(SecKeyRef key) {
597    if (key->key_class->copyDictionary)
598        return key->key_class->copyDictionary(key);
599    return NULL;
600}
601
602SecKeyRef 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. */
700static 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
873OSStatus 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
895OSStatus 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
914OSStatus 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
933OSStatus 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
952CFIndex 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
961OSStatus 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
967SecKeyRef 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
984SecKeyRef 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.
991size_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
1016OSStatus 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
1042OSStatus 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
1073SEC_CONST_DECL(_kSecKeyWrapPGPSymAlg, "kSecKeyWrapPGPSymAlg");
1074SEC_CONST_DECL(_kSecKeyWrapPGPFingerprint, "kSecKeyWrapPGPFingerprint");
1075SEC_CONST_DECL(_kSecKeyWrapPGPWrapAlg, "kSecKeyWrapPGPWrapAlg");
1076SEC_CONST_DECL(_kSecKeyWrapRFC6637Flags, "kSecKeyWrapPGPECFlags");
1077SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA256KekAES128, "kSecKeyWrapPGPECWrapDigestSHA256KekAES128");
1078SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA512KekAES256, "kSecKeyWrapPGPECWrapDigestSHA512KekAES256");
1079
1080#undef SEC_CONST_DECL
1081
1082CFDataRef
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
1095CFDataRef
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}
1108