1/*
2 * Copyright (c) 2002-2012 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#include "SecKey.h"
25#include "SecKeyPriv.h"
26#include "SecItem.h"
27#include "SecItemPriv.h"
28#include <libDER/asn1Types.h>
29#include <libDER/DER_Encode.h>
30#include <libDER/DER_Decode.h>
31#include <libDER/DER_Keys.h>
32#include <Security/SecAsn1Types.h>
33#include <Security/SecAsn1Coder.h>
34#include <security_keychain/KeyItem.h>
35#include <CommonCrypto/CommonKeyDerivation.h>
36
37#include "SecBridge.h"
38
39#include <security_keychain/Access.h>
40#include <security_keychain/Keychains.h>
41#include <security_keychain/KeyItem.h>
42#include <string.h>
43#include <syslog.h>
44
45#include <security_cdsa_utils/cuCdsaUtils.h>
46#include <security_cdsa_client/wrapkey.h>
47
48#include "SecImportExportCrypto.h"
49
50CFTypeID
51SecKeyGetTypeID(void)
52{
53	BEGIN_SECAPI
54
55	return gTypes().KeyItem.typeID;
56
57	END_SECAPI1(_kCFRuntimeNotATypeID)
58}
59
60static OSStatus SecKeyCreatePairInternal(
61	SecKeychainRef keychainRef,
62	CSSM_ALGORITHMS algorithm,
63	uint32 keySizeInBits,
64	CSSM_CC_HANDLE contextHandle,
65	CSSM_KEYUSE publicKeyUsage,
66	uint32 publicKeyAttr,
67	CSSM_KEYUSE privateKeyUsage,
68	uint32 privateKeyAttr,
69	SecAccessRef initialAccess,
70	SecKeyRef* publicKeyRef,
71	SecKeyRef* privateKeyRef)
72{
73	BEGIN_SECAPI
74
75	Keychain keychain = Keychain::optional(keychainRef);
76	SecPointer<Access> theAccess(initialAccess ? Access::required(initialAccess) : new Access("<key>"));
77	SecPointer<KeyItem> pubItem, privItem;
78
79    Mutex *keychainMutex = keychain->getKeychainMutex();
80    StLock<Mutex> _(*keychainMutex);
81
82	KeyItem::createPair(keychain,
83        algorithm,
84        keySizeInBits,
85        contextHandle,
86        publicKeyUsage,
87        publicKeyAttr,
88        privateKeyUsage,
89        privateKeyAttr,
90        theAccess,
91        pubItem,
92        privItem);
93
94	// Return the generated keys.
95	if (publicKeyRef)
96		*publicKeyRef = pubItem->handle();
97	if (privateKeyRef)
98		*privateKeyRef = privItem->handle();
99
100	END_SECAPI
101}
102
103OSStatus
104SecKeyCreatePair(
105	SecKeychainRef keychainRef,
106	CSSM_ALGORITHMS algorithm,
107	uint32 keySizeInBits,
108	CSSM_CC_HANDLE contextHandle,
109	CSSM_KEYUSE publicKeyUsage,
110	uint32 publicKeyAttr,
111	CSSM_KEYUSE privateKeyUsage,
112	uint32 privateKeyAttr,
113	SecAccessRef initialAccess,
114	SecKeyRef* publicKeyRef,
115	SecKeyRef* privateKeyRef)
116{
117    OSStatus result = SecKeyCreatePairInternal(keychainRef, algorithm, keySizeInBits, contextHandle, publicKeyUsage,
118                                               publicKeyAttr, privateKeyUsage, privateKeyAttr, initialAccess, publicKeyRef, privateKeyRef);
119
120    return result;
121}
122
123
124
125OSStatus
126SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY **cssmKey)
127{
128	BEGIN_SECAPI
129
130	Required(cssmKey) = KeyItem::required(key)->key();
131
132	END_SECAPI
133}
134
135
136//
137// Private APIs
138//
139
140OSStatus
141SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle)
142{
143    BEGIN_SECAPI
144
145	SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
146	Required(cspHandle) = keyItem->csp()->handle();
147
148	END_SECAPI
149}
150
151/* deprecated as of 10.8 */
152OSStatus
153SecKeyGetAlgorithmID(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER **algid)
154{
155    BEGIN_SECAPI
156
157	SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
158	Required(algid) = &keyItem->algorithmIdentifier();
159
160	END_SECAPI
161}
162
163/* new for 10.8 */
164CFIndex
165SecKeyGetAlgorithmId(SecKeyRef key)
166{
167	const CSSM_KEY *cssmKey;
168
169	if (SecKeyGetCSSMKey(key, &cssmKey) != errSecSuccess)
170		return kSecNullAlgorithmID;
171
172	switch (cssmKey->KeyHeader.AlgorithmId) {
173		case CSSM_ALGID_RSA:
174			return kSecRSAAlgorithmID;
175		case CSSM_ALGID_DSA:
176			return kSecDSAAlgorithmID;
177		case CSSM_ALGID_ECDSA:
178			return kSecECDSAAlgorithmID;
179		default:
180			assert(0); /* other algorithms TBA */
181			return kSecNullAlgorithmID;
182	}
183}
184
185OSStatus
186SecKeyGetStrengthInBits(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER *algid, unsigned int *strength)
187{
188    BEGIN_SECAPI
189
190	SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
191	Required(strength) = keyItem->strengthInBits(algid);
192
193	END_SECAPI
194}
195
196OSStatus
197SecKeyGetCredentials(
198	SecKeyRef keyRef,
199	CSSM_ACL_AUTHORIZATION_TAG operation,
200	SecCredentialType credentialType,
201	const CSSM_ACCESS_CREDENTIALS **outCredentials)
202{
203	BEGIN_SECAPI
204
205	SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
206	Required(outCredentials) = keyItem->getCredentials(operation, credentialType);
207
208	END_SECAPI
209}
210
211OSStatus
212SecKeyImportPair(
213	SecKeychainRef keychainRef,
214	const CSSM_KEY *publicCssmKey,
215	const CSSM_KEY *privateCssmKey,
216	SecAccessRef initialAccess,
217	SecKeyRef* publicKey,
218	SecKeyRef* privateKey)
219{
220	BEGIN_SECAPI
221
222	Keychain keychain = Keychain::optional(keychainRef);
223	SecPointer<Access> theAccess(initialAccess ? Access::required(initialAccess) : new Access("<key>"));
224	SecPointer<KeyItem> pubItem, privItem;
225
226	KeyItem::importPair(keychain,
227		Required(publicCssmKey),
228		Required(privateCssmKey),
229        theAccess,
230        pubItem,
231        privItem);
232
233	// Return the generated keys.
234	if (publicKey)
235		*publicKey = pubItem->handle();
236	if (privateKey)
237		*privateKey = privItem->handle();
238
239	END_SECAPI
240}
241
242static OSStatus
243SecKeyGenerateWithAttributes(
244	SecKeychainAttributeList* attrList,
245	SecKeychainRef keychainRef,
246	CSSM_ALGORITHMS algorithm,
247	uint32 keySizeInBits,
248	CSSM_CC_HANDLE contextHandle,
249	CSSM_KEYUSE keyUsage,
250	uint32 keyAttr,
251	SecAccessRef initialAccess,
252	SecKeyRef* keyRef)
253{
254	BEGIN_SECAPI
255
256	Keychain keychain;
257	SecPointer<Access> theAccess;
258
259	if (keychainRef)
260		keychain = KeychainImpl::required(keychainRef);
261	if (initialAccess)
262		theAccess = Access::required(initialAccess);
263
264	SecPointer<KeyItem> item = KeyItem::generateWithAttributes(attrList,
265        keychain,
266        algorithm,
267        keySizeInBits,
268        contextHandle,
269        keyUsage,
270        keyAttr,
271        theAccess);
272
273	// Return the generated key.
274	if (keyRef)
275		*keyRef = item->handle();
276
277	END_SECAPI
278}
279
280OSStatus
281SecKeyGenerate(
282	SecKeychainRef keychainRef,
283	CSSM_ALGORITHMS algorithm,
284	uint32 keySizeInBits,
285	CSSM_CC_HANDLE contextHandle,
286	CSSM_KEYUSE keyUsage,
287	uint32 keyAttr,
288	SecAccessRef initialAccess,
289	SecKeyRef* keyRef)
290{
291	return SecKeyGenerateWithAttributes(NULL,
292		keychainRef, algorithm, keySizeInBits,
293		contextHandle, keyUsage, keyAttr,
294		initialAccess, keyRef);
295}
296
297
298/* new in 10.6 */
299/* Create a key from supplied data and parameters */
300SecKeyRef
301SecKeyCreate(CFAllocatorRef allocator,
302    const SecKeyDescriptor *keyClass,
303	const uint8_t *keyData,
304	CFIndex keyDataLength,
305	SecKeyEncoding encoding)
306{
307	SecKeyRef keyRef = NULL;
308    OSStatus __secapiresult;
309	try {
310		//FIXME: needs implementation
311
312		__secapiresult=errSecSuccess;
313	}
314	catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
315	catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
316	catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
317	catch (...) { __secapiresult=errSecInternalComponent; }
318	return keyRef;
319}
320
321/* new in 10.6 */
322/* Generate a floating key reference from a CSSM_KEY */
323OSStatus
324SecKeyCreateWithCSSMKey(const CSSM_KEY *cssmKey,
325    SecKeyRef *keyRef)
326{
327	BEGIN_SECAPI
328
329	Required(cssmKey);
330	CssmClient::CSP csp(cssmKey->KeyHeader.CspId);
331	CssmClient::Key key(csp, *cssmKey);
332	KeyItem *item = new KeyItem(key);
333
334	// Return the generated key.
335	if (keyRef)
336		*keyRef = item->handle();
337
338	END_SECAPI
339}
340
341
342
343static u_int32_t ConvertCFStringToInteger(CFStringRef ref)
344{
345	if (ref == NULL)
346	{
347		return 0;
348	}
349
350	// figure out the size of the string
351	CFIndex numChars = CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref), kCFStringEncodingUTF8);
352	char buffer[numChars];
353	if (!CFStringGetCString(ref, buffer, numChars, kCFStringEncodingUTF8))
354	{
355		MacOSError::throwMe(errSecParam);
356	}
357
358	return atoi(buffer);
359}
360
361
362
363static OSStatus CheckAlgorithmType(CFDictionaryRef parameters, CSSM_ALGORITHMS &algorithms)
364{
365	// figure out the algorithm to use
366	CFStringRef ktype = (CFStringRef) CFDictionaryGetValue(parameters, kSecAttrKeyType);
367	if (ktype == NULL)
368	{
369		return errSecParam;
370	}
371
372	if (CFEqual(ktype, kSecAttrKeyTypeRSA)) {
373		algorithms = CSSM_ALGID_RSA;
374		return errSecSuccess;
375       } else if(CFEqual(ktype, kSecAttrKeyTypeECDSA) ||
376                       CFEqual(ktype, kSecAttrKeyTypeEC)) {
377		algorithms = CSSM_ALGID_ECDSA;
378		return errSecSuccess;
379	} else if(CFEqual(ktype, kSecAttrKeyTypeAES)) {
380		algorithms = CSSM_ALGID_AES;
381		return errSecSuccess;
382	} else if(CFEqual(ktype, kSecAttrKeyType3DES)) {
383		algorithms = CSSM_ALGID_3DES;
384		return errSecSuccess;
385	} else {
386		return errSecUnsupportedAlgorithm;
387	}
388}
389
390
391
392static OSStatus GetKeySize(CFDictionaryRef parameters, CSSM_ALGORITHMS algorithms, uint32 &keySizeInBits)
393{
394
395    // get the key size and check it for validity
396    CFTypeRef ref = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits);
397
398    keySizeInBits = kSecDefaultKeySize;
399
400    CFTypeID bitSizeType = CFGetTypeID(ref);
401    if (bitSizeType == CFStringGetTypeID())
402        keySizeInBits = ConvertCFStringToInteger((CFStringRef) ref);
403    else if (bitSizeType == CFNumberGetTypeID())
404        CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &keySizeInBits);
405    else return errSecParam;
406
407
408    switch (algorithms) {
409    case CSSM_ALGID_ECDSA:
410        if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSecp256r1;
411        if(keySizeInBits == kSecp192r1 || keySizeInBits == kSecp256r1 || keySizeInBits == kSecp384r1 || keySizeInBits == kSecp521r1 ) return errSecSuccess;
412        break;
413    case CSSM_ALGID_RSA:
414			  if(keySizeInBits % 8) return errSecParam;
415        if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = 2048;
416        if(keySizeInBits >= kSecRSAMin && keySizeInBits <= kSecRSAMax) return errSecSuccess;
417        break;
418    case CSSM_ALGID_AES:
419        if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSecAES128;
420        if(keySizeInBits == kSecAES128 || keySizeInBits == kSecAES192 || keySizeInBits == kSecAES256) return errSecSuccess;
421        break;
422    case CSSM_ALGID_3DES:
423        if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSec3DES192;
424        if(keySizeInBits == kSec3DES192) return errSecSuccess;
425        break;
426    default:
427        break;
428    }
429    return errSecParam;
430}
431
432
433
434enum AttributeType
435{
436	kStringType,
437	kBooleanType,
438	kIntegerType
439};
440
441
442
443struct ParameterAttribute
444{
445	const CFTypeRef *name;
446	AttributeType type;
447};
448
449
450
451static ParameterAttribute gAttributes[] =
452{
453	{
454		&kSecAttrLabel,
455		kStringType
456	},
457	{
458		&kSecAttrIsPermanent,
459		kBooleanType
460	},
461	{
462		&kSecAttrApplicationTag,
463		kStringType
464	},
465	{
466		&kSecAttrEffectiveKeySize,
467		kBooleanType
468	},
469	{
470		&kSecAttrCanEncrypt,
471		kBooleanType
472	},
473	{
474		&kSecAttrCanDecrypt,
475		kBooleanType
476	},
477	{
478		&kSecAttrCanDerive,
479		kBooleanType
480	},
481	{
482		&kSecAttrCanSign,
483		kBooleanType
484	},
485	{
486		&kSecAttrCanVerify,
487		kBooleanType
488	},
489	{
490		&kSecAttrCanUnwrap,
491		kBooleanType
492	}
493};
494
495const int kNumberOfAttributes = sizeof(gAttributes) / sizeof(ParameterAttribute);
496
497static OSStatus ScanDictionaryForParameters(CFDictionaryRef parameters, void* attributePointers[])
498{
499	int i;
500	for (i = 0; i < kNumberOfAttributes; ++i)
501	{
502		// see if the corresponding tag exists in the dictionary
503		CFTypeRef value = CFDictionaryGetValue(parameters, *(gAttributes[i].name));
504		if (value != NULL)
505		{
506			switch (gAttributes[i].type)
507			{
508				case kStringType:
509					// just return the value
510					*(CFTypeRef*) attributePointers[i] = value;
511				break;
512
513				case kBooleanType:
514				{
515					CFBooleanRef bRef = (CFBooleanRef) value;
516					*(bool*) attributePointers[i] = CFBooleanGetValue(bRef);
517				}
518				break;
519
520				case kIntegerType:
521				{
522					CFNumberRef nRef = (CFNumberRef) value;
523					CFNumberGetValue(nRef, kCFNumberSInt32Type, attributePointers[i]);
524				}
525				break;
526			}
527		}
528	}
529
530	return errSecSuccess;
531}
532
533
534
535static OSStatus GetKeyParameters(CFDictionaryRef parameters, int keySize, bool isPublic, CSSM_KEYUSE &keyUse, uint32 &attrs, CFTypeRef &labelRef, CFDataRef &applicationTagRef)
536{
537	// establish default values
538	labelRef = NULL;
539	bool isPermanent = false;
540	applicationTagRef = NULL;
541	CFTypeRef effectiveKeySize = NULL;
542	bool canDecrypt = isPublic ? false : true;
543	bool canEncrypt = !canDecrypt;
544	bool canDerive = true;
545	bool canSign = isPublic ? false : true;
546	bool canVerify = !canSign;
547	bool canUnwrap = isPublic ? false : true;
548	attrs = CSSM_KEYATTR_EXTRACTABLE;
549	keyUse = 0;
550
551	void* attributePointers[] = {&labelRef, &isPermanent, &applicationTagRef, &effectiveKeySize, &canEncrypt, &canDecrypt,
552								 &canDerive, &canSign, &canVerify, &canUnwrap};
553
554	// look for modifiers in the general dictionary
555	OSStatus result = ScanDictionaryForParameters(parameters, attributePointers);
556	if (result != errSecSuccess)
557	{
558		return result;
559	}
560
561	// see if we have anything which modifies the defaults
562	CFTypeRef key;
563	if (isPublic)
564	{
565		key = kSecPublicKeyAttrs;
566	}
567	else
568	{
569		key = kSecPrivateKeyAttrs;
570	}
571
572	CFTypeRef dType = CFDictionaryGetValue(parameters, key);
573	if (dType != NULL)
574	{
575		// this had better be a dictionary
576		if (CFGetTypeID(dType) != CFDictionaryGetTypeID())
577		{
578			return errSecParam;
579		}
580
581		// pull any additional parameters out of this dictionary
582		result = ScanDictionaryForParameters((CFDictionaryRef)dType, attributePointers);
583		if (result != errSecSuccess)
584		{
585			return result;
586		}
587	}
588
589	// figure out the key usage
590	keyUse = 0;
591	if (canDecrypt)
592	{
593		keyUse |= CSSM_KEYUSE_DECRYPT;
594	}
595
596	if (canEncrypt)
597	{
598		keyUse |= CSSM_KEYUSE_ENCRYPT;
599	}
600
601	if (canDerive)
602	{
603		keyUse |= CSSM_KEYUSE_DERIVE;
604	}
605
606	if (canSign)
607	{
608		keyUse |= CSSM_KEYUSE_SIGN;
609	}
610
611	if (canVerify)
612	{
613		keyUse |= CSSM_KEYUSE_VERIFY;
614	}
615
616	if (canUnwrap)
617	{
618		keyUse |= CSSM_KEYUSE_UNWRAP;
619	}
620
621	// public key is always extractable;
622	// private key is extractable by default unless explicitly set to false
623	CFTypeRef value = NULL;
624	if (!isPublic && CFDictionaryGetValueIfPresent(parameters, kSecAttrIsExtractable, (const void **)&value) && value)
625	{
626		Boolean keyIsExtractable = CFEqual(kCFBooleanTrue, value);
627		if (!keyIsExtractable)
628			attrs = 0;
629	}
630
631	attrs |= CSSM_KEYATTR_PERMANENT;
632
633	return errSecSuccess;
634}
635
636
637
638static OSStatus MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters,
639												   CSSM_ALGORITHMS &algorithms,
640												   uint32 &keySizeInBits,
641												   CSSM_KEYUSE &publicKeyUse,
642												   uint32 &publicKeyAttr,
643												   CFTypeRef &publicKeyLabelRef,
644												   CFDataRef &publicKeyAttributeTagRef,
645												   CSSM_KEYUSE &privateKeyUse,
646												   uint32 &privateKeyAttr,
647												   CFTypeRef &privateKeyLabelRef,
648												   CFDataRef &privateKeyAttributeTagRef,
649												   SecAccessRef &initialAccess)
650{
651	OSStatus result;
652
653	result = CheckAlgorithmType(parameters, algorithms);
654	if (result != errSecSuccess)
655	{
656		return result;
657	}
658
659	result = GetKeySize(parameters, algorithms, keySizeInBits);
660	if (result != errSecSuccess)
661	{
662		return result;
663	}
664
665	result = GetKeyParameters(parameters, keySizeInBits, false, privateKeyUse, privateKeyAttr, privateKeyLabelRef, privateKeyAttributeTagRef);
666	if (result != errSecSuccess)
667	{
668		return result;
669	}
670
671	result = GetKeyParameters(parameters, keySizeInBits, true, publicKeyUse, publicKeyAttr, publicKeyLabelRef, publicKeyAttributeTagRef);
672	if (result != errSecSuccess)
673	{
674		return result;
675	}
676
677	if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrAccess, (const void **)&initialAccess))
678	{
679		initialAccess = NULL;
680	}
681	else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess))
682	{
683		return errSecParam;
684	}
685
686	return errSecSuccess;
687}
688
689
690
691static OSStatus SetKeyLabelAndTag(SecKeyRef keyRef, CFTypeRef label, CFDataRef tag)
692{
693	int numToModify = 0;
694	if (label != NULL)
695	{
696		numToModify += 1;
697	}
698
699	if (tag != NULL)
700	{
701		numToModify += 1;
702	}
703
704	if (numToModify == 0)
705	{
706		return errSecSuccess;
707	}
708
709	SecKeychainAttributeList attrList;
710	SecKeychainAttribute attributes[numToModify];
711
712	int i = 0;
713
714	if (label != NULL)
715	{
716		if (CFStringGetTypeID() == CFGetTypeID(label)) {
717			CFStringRef label_string = static_cast<CFStringRef>(label);
718			attributes[i].tag = kSecKeyPrintName;
719			attributes[i].data = (void*) CFStringGetCStringPtr(label_string, kCFStringEncodingUTF8);
720			if (NULL == attributes[i].data) {
721				CFIndex buffer_length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string), kCFStringEncodingUTF8);
722				attributes[i].data = alloca((size_t)buffer_length);
723				if (NULL == attributes[i].data) {
724					UnixError::throwMe(ENOMEM);
725				}
726				if (!CFStringGetCString(label_string, static_cast<char *>(attributes[i].data), buffer_length, kCFStringEncodingUTF8)) {
727					MacOSError::throwMe(errSecParam);
728				}
729			}
730			attributes[i].length = (UInt32)strlen(static_cast<char *>(attributes[i].data));
731		} else if (CFDataGetTypeID() == CFGetTypeID(label)) {
732			// 10.6 bug compatibility
733			CFDataRef label_data = static_cast<CFDataRef>(label);
734			attributes[i].tag = kSecKeyLabel;
735			attributes[i].data = (void*) CFDataGetBytePtr(label_data);
736			attributes[i].length = (UInt32)CFDataGetLength(label_data);
737		} else {
738			MacOSError::throwMe(errSecParam);
739		}
740		i++;
741	}
742
743	if (tag != NULL)
744	{
745		attributes[i].tag = kSecKeyApplicationTag;
746		attributes[i].data = (void*) CFDataGetBytePtr(tag);
747		attributes[i].length = (UInt32)CFDataGetLength(tag);
748		i++;
749	}
750
751	attrList.count = numToModify;
752	attrList.attr = attributes;
753
754	return SecKeychainItemModifyAttributesAndData((SecKeychainItemRef) keyRef, &attrList, 0, NULL);
755}
756
757
758
759/* new in 10.6 */
760/* Generate a private/public keypair. */
761OSStatus
762SecKeyGeneratePair(
763	CFDictionaryRef parameters,
764	SecKeyRef *publicKey,
765	SecKeyRef *privateKey)
766{
767	BEGIN_SECAPI
768
769	Required(parameters);
770	Required(publicKey);
771	Required(privateKey);
772
773	CSSM_ALGORITHMS algorithms;
774	uint32 keySizeInBits;
775	CSSM_KEYUSE publicKeyUse;
776	uint32 publicKeyAttr;
777	CFTypeRef publicKeyLabelRef;
778	CFDataRef publicKeyAttributeTagRef;
779	CSSM_KEYUSE privateKeyUse;
780	uint32 privateKeyAttr;
781	CFTypeRef privateKeyLabelRef;
782	CFDataRef privateKeyAttributeTagRef;
783	SecAccessRef initialAccess;
784	SecKeychainRef keychain;
785
786	OSStatus result = MakeKeyGenParametersFromDictionary(parameters, algorithms, keySizeInBits, publicKeyUse, publicKeyAttr, publicKeyLabelRef,
787														 publicKeyAttributeTagRef, privateKeyUse, privateKeyAttr, privateKeyLabelRef, privateKeyAttributeTagRef,
788														 initialAccess);
789
790	if (result != errSecSuccess)
791	{
792		return result;
793	}
794
795	// verify keychain parameter
796	keychain = NULL;
797	if (!CFDictionaryGetValueIfPresent(parameters, kSecUseKeychain, (const void **)&keychain))
798		keychain = NULL;
799	else if (SecKeychainGetTypeID() != CFGetTypeID(keychain))
800		keychain = NULL;
801
802	// do the key generation
803	result = SecKeyCreatePair(keychain, algorithms, keySizeInBits, 0, publicKeyUse, publicKeyAttr, privateKeyUse, privateKeyAttr, initialAccess, publicKey, privateKey);
804	if (result != errSecSuccess)
805	{
806		return result;
807	}
808
809	// set the label and print attributes on the keys
810	SetKeyLabelAndTag(*publicKey, publicKeyLabelRef, publicKeyAttributeTagRef);
811	SetKeyLabelAndTag(*privateKey, privateKeyLabelRef, privateKeyAttributeTagRef);
812	return result;
813
814	END_SECAPI
815}
816
817/* new in 10.6 */
818OSStatus
819SecKeyRawSign(
820    SecKeyRef           key,
821	SecPadding          padding,
822	const uint8_t       *dataToSign,
823	size_t              dataToSignLen,
824	uint8_t             *sig,
825	size_t              *sigLen)
826{
827	BEGIN_SECAPI
828
829	Required(key);
830	SecPointer<KeyItem> keyItem(KeyItem::required(key));
831	CSSM_DATA dataInput;
832
833	dataInput.Data = (uint8_t*) dataToSign;
834	dataInput.Length = dataToSignLen;
835
836	CSSM_DATA output;
837	output.Data = sig;
838	output.Length = *sigLen;
839
840	const AccessCredentials* credentials = keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeDefault);
841
842	keyItem->RawSign(padding, dataInput, credentials, output);
843	*sigLen = output.Length;
844
845	END_SECAPI
846}
847
848OSStatus SecKeyRawVerifyOSX(
849    SecKeyRef           key,            /* Public key */
850	SecPadding          padding,		/* kSecPaddingNone or kSecPaddingPKCS1 */
851	const uint8_t       *signedData,	/* signature over this data */
852	size_t              signedDataLen,	/* length of dataToSign */
853	const uint8_t       *sig,			/* signature */
854	size_t              sigLen)
855{
856    return SecKeyRawVerify(key,padding,signedData,signedDataLen,sig,sigLen);
857}
858
859/* new in 10.6 */
860OSStatus
861SecKeyRawVerify(
862    SecKeyRef           key,
863	SecPadding          padding,
864	const uint8_t       *signedData,
865	size_t              signedDataLen,
866	const uint8_t       *sig,
867	size_t              sigLen)
868{
869	BEGIN_SECAPI
870
871	Required(key);
872
873	SecPointer<KeyItem> keyItem(KeyItem::required(key));
874	CSSM_DATA dataInput;
875
876	dataInput.Data = (uint8_t*) signedData;
877	dataInput.Length = signedDataLen;
878
879	CSSM_DATA signature;
880	signature.Data = (uint8_t*) sig;
881	signature.Length = sigLen;
882
883	const AccessCredentials* credentials = keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ANY, kSecCredentialTypeDefault);
884
885	keyItem->RawVerify(padding, dataInput, credentials, signature);
886
887	END_SECAPI
888}
889
890/* new in 10.6 */
891OSStatus
892SecKeyEncrypt(
893    SecKeyRef           key,
894	SecPadding          padding,
895	const uint8_t		*plainText,
896	size_t              plainTextLen,
897	uint8_t             *cipherText,
898	size_t              *cipherTextLen)
899{
900	BEGIN_SECAPI
901
902	SecPointer<KeyItem> keyItem(KeyItem::required(key));
903	CSSM_DATA inData, outData;
904	inData.Data = (uint8*) plainText;
905	inData.Length = plainTextLen;
906	outData.Data = cipherText;
907	outData.Length = *cipherTextLen;
908
909	const AccessCredentials* credentials = keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT, kSecCredentialTypeDefault);
910
911	keyItem->Encrypt(padding, inData, credentials, outData);
912	*cipherTextLen = outData.Length;
913
914	END_SECAPI
915}
916
917/* new in 10.6 */
918OSStatus
919SecKeyDecrypt(
920    SecKeyRef           key,                /* Private key */
921	SecPadding          padding,			/* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
922	const uint8_t       *cipherText,
923	size_t              cipherTextLen,		/* length of cipherText */
924	uint8_t             *plainText,
925	size_t              *plainTextLen)		/* IN/OUT */
926{
927	BEGIN_SECAPI
928
929	SecPointer<KeyItem> keyItem(KeyItem::required(key));
930	CSSM_DATA inData, outData;
931	inData.Data = (uint8*) cipherText;
932	inData.Length = cipherTextLen;
933	outData.Data = plainText;
934	outData.Length = *plainTextLen;
935
936	const AccessCredentials* credentials = keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT, kSecCredentialTypeDefault);
937
938	keyItem->Decrypt(padding, inData, credentials, outData);
939	*plainTextLen = outData.Length;
940
941	END_SECAPI
942}
943
944/* new in 10.6 */
945size_t
946SecKeyGetBlockSize(SecKeyRef key)
947{
948	size_t blockSize = 0;
949    OSStatus __secapiresult;
950	try {
951		CSSM_KEY cssmKey = KeyItem::required(key)->key();
952		switch(cssmKey.KeyHeader.AlgorithmId)
953		{
954			case CSSM_ALGID_RSA:
955			case CSSM_ALGID_DSA:
956				blockSize = cssmKey.KeyHeader.LogicalKeySizeInBits / 8;
957				break;
958			case CSSM_ALGID_ECDSA:
959			{
960				/* Block size is up to 9 bytes of DER encoding for sequence of 2 integers,
961				 * plus both coordinates for the point used */
962				#define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8)
963				#define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1)
964				size_t coordSize = ECDSA_MAX_COORD_SIZE_IN_BYTES(cssmKey.KeyHeader.LogicalKeySizeInBits);
965				assert(coordSize < 256); /* size must fit in a byte for DER */
966				size_t coordDERLen = (coordSize > 127) ? 2 : 1;
967				size_t coordLen = 1 + coordDERLen + coordSize;
968
969				size_t pointSize = 2 * coordLen;
970				assert(pointSize < 256); /* size must fit in a byte for DER */
971				size_t pointDERLen = (pointSize > 127) ? 2 : 1;
972				size_t pointLen = 1 + pointDERLen + pointSize;
973
974				blockSize = pointLen;
975			}
976			break;
977			case CSSM_ALGID_AES:
978				blockSize = 16; /* all AES keys use 128-bit blocks */
979				break;
980			case CSSM_ALGID_DES:
981			case CSSM_ALGID_3DES_3KEY:
982				blockSize = 8; /* all DES keys use 64-bit blocks */
983				break;
984			default:
985				assert(0); /* some other key algorithm */
986				blockSize = 16; /* FIXME: revisit this */
987				break;
988		}
989		__secapiresult=errSecSuccess;
990	}
991	catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
992	catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
993	catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
994	catch (...) { __secapiresult=errSecInternalComponent; }
995	return blockSize;
996}
997
998
999/*
1000    M4 Additions
1001*/
1002
1003static CFTypeRef
1004utilGetStringFromCFDict(CFDictionaryRef parameters, CFTypeRef key, CFTypeRef defaultValue)
1005{
1006		CFTypeRef value = CFDictionaryGetValue(parameters, key);
1007        if (value != NULL) return value;
1008        return defaultValue;
1009}
1010
1011static uint32_t
1012utilGetNumberFromCFDict(CFDictionaryRef parameters, CFTypeRef key, uint32_t defaultValue)
1013{
1014        uint32_t integerValue;
1015		CFTypeRef value = CFDictionaryGetValue(parameters, key);
1016        if (value != NULL) {
1017            CFNumberRef nRef = (CFNumberRef) value;
1018            CFNumberGetValue(nRef, kCFNumberSInt32Type, &integerValue);
1019            return integerValue;
1020        }
1021        return defaultValue;
1022 }
1023
1024static uint32_t
1025utilGetMaskValFromCFDict(CFDictionaryRef parameters, CFTypeRef key, uint32_t maskValue)
1026{
1027		CFTypeRef value = CFDictionaryGetValue(parameters, key);
1028        if (value != NULL) {
1029            CFBooleanRef bRef = (CFBooleanRef) value;
1030            if(CFBooleanGetValue(bRef)) return maskValue;
1031        }
1032        return 0;
1033}
1034
1035static void
1036utilGetKeyParametersFromCFDict(CFDictionaryRef parameters, CSSM_ALGORITHMS *algorithm, uint32 *keySizeInBits, CSSM_KEYUSE *keyUsage, CSSM_KEYCLASS *keyClass)
1037{
1038    CFTypeRef algorithmDictValue = utilGetStringFromCFDict(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES);
1039    CFTypeRef keyClassDictValue = utilGetStringFromCFDict(parameters, kSecAttrKeyClass, kSecAttrKeyClassSymmetric);
1040
1041    if(CFEqual(algorithmDictValue, kSecAttrKeyTypeAES)) {
1042        *algorithm = CSSM_ALGID_AES;
1043        *keySizeInBits = 128;
1044        *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1045    } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeDES)) {
1046        *algorithm = CSSM_ALGID_DES;
1047        *keySizeInBits = 128;
1048         *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1049    } else if(CFEqual(algorithmDictValue, kSecAttrKeyType3DES)) {
1050        *algorithm = CSSM_ALGID_3DES_3KEY_EDE;
1051        *keySizeInBits = 128;
1052        *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1053    } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRC4)) {
1054        *algorithm = CSSM_ALGID_RC4;
1055        *keySizeInBits = 128;
1056        *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1057    } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRC2)) {
1058        *algorithm = CSSM_ALGID_RC2;
1059        *keySizeInBits = 128;
1060         *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1061    } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeCAST)) {
1062        *algorithm = CSSM_ALGID_CAST;
1063        *keySizeInBits = 128;
1064         *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1065    } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRSA)) {
1066        *algorithm = CSSM_ALGID_RSA;
1067        *keySizeInBits = 128;
1068         *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1069    } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeDSA)) {
1070        *algorithm = CSSM_ALGID_DSA;
1071        *keySizeInBits = 128;
1072         *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1073    } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeECDSA) ||
1074            CFEqual(algorithmDictValue, kSecAttrKeyTypeEC)) {
1075        *algorithm = CSSM_ALGID_ECDSA;
1076        *keySizeInBits = 128;
1077        *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1078    } else {
1079        *algorithm = CSSM_ALGID_AES;
1080        *keySizeInBits = 128;
1081        *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1082    }
1083
1084    if(CFEqual(keyClassDictValue, kSecAttrKeyClassPublic)) {
1085        *keyClass = CSSM_KEYCLASS_PUBLIC_KEY;
1086    } else if(CFEqual(keyClassDictValue, kSecAttrKeyClassPrivate)) {
1087        *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1088    } else if(CFEqual(keyClassDictValue, kSecAttrKeyClassSymmetric)) {
1089         *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1090    }
1091
1092    *keySizeInBits = utilGetNumberFromCFDict(parameters, kSecAttrKeySizeInBits, *keySizeInBits);
1093    *keyUsage =  utilGetMaskValFromCFDict(parameters, kSecAttrCanEncrypt, CSSM_KEYUSE_ENCRYPT) |
1094                utilGetMaskValFromCFDict(parameters, kSecAttrCanDecrypt, CSSM_KEYUSE_DECRYPT) |
1095                utilGetMaskValFromCFDict(parameters, kSecAttrCanWrap, CSSM_KEYUSE_WRAP) |
1096                utilGetMaskValFromCFDict(parameters, kSecAttrCanUnwrap, CSSM_KEYUSE_UNWRAP);
1097
1098
1099    if(*keyClass == CSSM_KEYCLASS_PRIVATE_KEY || *keyClass == CSSM_KEYCLASS_PUBLIC_KEY) {
1100		*keyUsage |=  utilGetMaskValFromCFDict(parameters, kSecAttrCanSign, CSSM_KEYUSE_SIGN) |
1101					utilGetMaskValFromCFDict(parameters, kSecAttrCanVerify, CSSM_KEYUSE_VERIFY);
1102    }
1103
1104    if(*keyUsage == 0) {
1105		switch (*keyClass) {
1106			case CSSM_KEYCLASS_PRIVATE_KEY:
1107				*keyUsage = CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_SIGN;
1108				break;
1109			case CSSM_KEYCLASS_PUBLIC_KEY:
1110				*keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP;
1111				break;
1112			default:
1113				*keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY;
1114				break;
1115		}
1116	}
1117}
1118
1119static CFStringRef
1120utilCopyDefaultKeyLabel(void)
1121{
1122	// generate a default label from the current date
1123	CFDateRef dateNow = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent());
1124	CFStringRef defaultLabel = CFCopyDescription(dateNow);
1125	CFRelease(dateNow);
1126
1127	return defaultLabel;
1128}
1129
1130SecKeyRef
1131SecKeyGenerateSymmetric(CFDictionaryRef parameters, CFErrorRef *error)
1132{
1133	OSStatus result = errSecParam; // default result for an early exit
1134	SecKeyRef key = NULL;
1135	SecKeychainRef keychain = NULL;
1136	SecAccessRef access;
1137	CFStringRef label;
1138	CFStringRef appLabel;
1139	CFStringRef appTag;
1140	CFStringRef dateLabel = NULL;
1141
1142	CSSM_ALGORITHMS algorithm;
1143	uint32 keySizeInBits;
1144	CSSM_KEYUSE keyUsage;
1145	uint32 keyAttr = CSSM_KEYATTR_RETURN_DEFAULT;
1146	CSSM_KEYCLASS keyClass;
1147	CFTypeRef value;
1148	Boolean isPermanent;
1149	Boolean isExtractable;
1150
1151	// verify keychain parameter
1152	if (!CFDictionaryGetValueIfPresent(parameters, kSecUseKeychain, (const void **)&keychain))
1153		keychain = NULL;
1154	else if (SecKeychainGetTypeID() != CFGetTypeID(keychain)) {
1155		keychain = NULL;
1156		goto errorExit;
1157	}
1158	else
1159		CFRetain(keychain);
1160
1161	// verify permanent parameter
1162	if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrIsPermanent, (const void **)&value))
1163		isPermanent = false;
1164	else if (!value || (CFBooleanGetTypeID() != CFGetTypeID(value)))
1165		goto errorExit;
1166	else
1167		isPermanent = CFEqual(kCFBooleanTrue, value);
1168	if (isPermanent) {
1169		if (keychain == NULL) {
1170			// no keychain was specified, so use the default keychain
1171			result = SecKeychainCopyDefault(&keychain);
1172		}
1173		keyAttr |= CSSM_KEYATTR_PERMANENT;
1174	}
1175
1176	// verify extractable parameter
1177	if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrIsExtractable, (const void **)&value))
1178		isExtractable = true; // default to extractable if value not specified
1179	else if (!value || (CFBooleanGetTypeID() != CFGetTypeID(value)))
1180		goto errorExit;
1181	else
1182		isExtractable = CFEqual(kCFBooleanTrue, value);
1183	if (isExtractable)
1184		keyAttr |= CSSM_KEYATTR_EXTRACTABLE;
1185
1186	// verify access parameter
1187	if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrAccess, (const void **)&access))
1188		access = NULL;
1189	else if (SecAccessGetTypeID() != CFGetTypeID(access))
1190		goto errorExit;
1191
1192	// verify label parameter
1193	if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrLabel, (const void **)&label))
1194		label = (dateLabel = utilCopyDefaultKeyLabel()); // no label provided, so use default
1195	else if (CFStringGetTypeID() != CFGetTypeID(label))
1196		goto errorExit;
1197
1198	// verify application label parameter
1199	if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrApplicationLabel, (const void **)&appLabel))
1200		appLabel = (dateLabel) ? dateLabel : (dateLabel = utilCopyDefaultKeyLabel());
1201	else if (CFStringGetTypeID() != CFGetTypeID(appLabel))
1202		goto errorExit;
1203
1204	// verify application tag parameter
1205	if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrApplicationTag, (const void **)&appTag))
1206		appTag = NULL;
1207	else if (CFStringGetTypeID() != CFGetTypeID(appTag))
1208		goto errorExit;
1209
1210    utilGetKeyParametersFromCFDict(parameters, &algorithm, &keySizeInBits, &keyUsage, &keyClass);
1211
1212	if (!keychain) {
1213		// the generated key will not be stored in any keychain
1214		result = SecKeyGenerate(keychain, algorithm, keySizeInBits, 0, keyUsage, keyAttr, access, &key);
1215	}
1216	else {
1217		// we can set the label attributes on the generated key if it's a keychain item
1218		size_t labelBufLen = (label) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label), kCFStringEncodingUTF8) + 1 : 0;
1219		char *labelBuf = (char *)malloc(labelBufLen);
1220		size_t appLabelBufLen = (appLabel) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel), kCFStringEncodingUTF8) + 1 : 0;
1221		char *appLabelBuf = (char *)malloc(appLabelBufLen);
1222		size_t appTagBufLen = (appTag) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag), kCFStringEncodingUTF8) + 1 : 0;
1223		char *appTagBuf = (char *)malloc(appTagBufLen);
1224
1225		if (label && !CFStringGetCString(label, labelBuf, labelBufLen-1, kCFStringEncodingUTF8))
1226			labelBuf[0]=0;
1227		if (appLabel && !CFStringGetCString(appLabel, appLabelBuf, appLabelBufLen-1, kCFStringEncodingUTF8))
1228			appLabelBuf[0]=0;
1229		if (appTag && !CFStringGetCString(appTag, appTagBuf, appTagBufLen-1, kCFStringEncodingUTF8))
1230			appTagBuf[0]=0;
1231
1232		SecKeychainAttribute attrs[] = {
1233			{ kSecKeyPrintName, (UInt32)strlen(labelBuf), (char *)labelBuf },
1234			{ kSecKeyLabel, (UInt32)strlen(appLabelBuf), (char *)appLabelBuf },
1235			{ kSecKeyApplicationTag, (UInt32)strlen(appTagBuf), (char *)appTagBuf }	};
1236		SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
1237		if (!appTag) --attributes.count;
1238
1239		result = SecKeyGenerateWithAttributes(&attributes,
1240			keychain, algorithm, keySizeInBits, 0,
1241			keyUsage, keyAttr, access, &key);
1242
1243		free(labelBuf);
1244		free(appLabelBuf);
1245		free(appTagBuf);
1246	}
1247
1248errorExit:
1249	if (result && error) {
1250		*error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, result, NULL);
1251	}
1252	if (dateLabel)
1253		CFRelease(dateLabel);
1254	if (keychain)
1255		CFRelease(keychain);
1256
1257    return key;
1258}
1259
1260
1261
1262SecKeyRef
1263SecKeyCreateFromData(CFDictionaryRef parameters, CFDataRef keyData, CFErrorRef *error)
1264{
1265	CSSM_ALGORITHMS		algorithm;
1266    uint32				keySizeInBits;
1267    CSSM_KEYUSE			keyUsage;
1268    CSSM_KEYCLASS		keyClass;
1269    CSSM_RETURN			crtn;
1270
1271    utilGetKeyParametersFromCFDict(parameters, &algorithm, &keySizeInBits, &keyUsage, &keyClass);
1272
1273	CSSM_CSP_HANDLE cspHandle = cuCspStartup(CSSM_FALSE); // TRUE => CSP, FALSE => CSPDL
1274
1275	SecKeyImportExportParameters iparam;
1276	memset(&iparam, 0, sizeof(iparam));
1277	iparam.keyUsage = keyUsage;
1278
1279	SecExternalItemType itype;
1280	switch (keyClass) {
1281		case CSSM_KEYCLASS_PRIVATE_KEY:
1282			itype = kSecItemTypePrivateKey;
1283			break;
1284		case CSSM_KEYCLASS_PUBLIC_KEY:
1285			itype = kSecItemTypePublicKey;
1286			break;
1287		case CSSM_KEYCLASS_SESSION_KEY:
1288			itype = kSecItemTypeSessionKey;
1289			break;
1290		default:
1291			itype = kSecItemTypeUnknown;
1292			break;
1293	}
1294
1295	CFMutableArrayRef ka = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1296	// NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful.
1297	crtn = impExpImportRawKey(keyData, kSecFormatUnknown, itype, algorithm, NULL, cspHandle, 0, NULL, NULL, ka);
1298	if (crtn == CSSM_OK && CFArrayGetCount((CFArrayRef)ka)) {
1299		SecKeyRef sk = (SecKeyRef)CFArrayGetValueAtIndex((CFArrayRef)ka, 0);
1300		CFRetain(sk);
1301		CFRelease(ka);
1302		return sk;
1303	} else {
1304		if (error) {
1305			*error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, crtn ? crtn : CSSM_ERRCODE_INTERNAL_ERROR, NULL);
1306		}
1307		return NULL;
1308	}
1309}
1310
1311
1312void
1313SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable, dispatch_queue_t deliveryQueue,
1314						SecKeyGeneratePairBlock result)
1315{
1316	CFDictionaryRef parameters = CFDictionaryCreateCopy(NULL, parametersWhichMightBeMutiable);
1317	dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
1318		SecKeyRef publicKey = NULL;
1319		SecKeyRef privateKey = NULL;
1320		OSStatus status = SecKeyGeneratePair(parameters, &publicKey, &privateKey);
1321		dispatch_async(deliveryQueue, ^{
1322			CFErrorRef error = NULL;
1323			if (errSecSuccess != status) {
1324				error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, NULL);
1325			}
1326			result(publicKey, privateKey, error);
1327			if (error) {
1328				CFRelease(error);
1329			}
1330			if (publicKey) {
1331				CFRelease(publicKey);
1332			}
1333			if (privateKey) {
1334				CFRelease(privateKey);
1335			}
1336			CFRelease(parameters);
1337		});
1338	});
1339}
1340
1341SecKeyRef
1342SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErrorRef *error)
1343{
1344    char *thePassword = NULL;
1345    CFIndex passwordLen;
1346    uint8_t *salt = NULL;
1347    size_t saltLen;
1348    CCPBKDFAlgorithm algorithm;
1349    uint rounds;
1350    uint8_t *derivedKey = NULL;
1351    size_t derivedKeyLen;
1352    CFDataRef saltDictValue, algorithmDictValue;
1353
1354    /* Pick Values from parameters */
1355
1356    if((saltDictValue = (CFDataRef) CFDictionaryGetValue(parameters, kSecAttrSalt)) == NULL) {
1357        *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecMissingAlgorithmParms, NULL);
1358        return NULL;
1359    }
1360
1361    derivedKeyLen = utilGetNumberFromCFDict(parameters, kSecAttrKeySizeInBits, 128);
1362	// This value come in bits but the rest of the code treats it as bytes
1363	derivedKeyLen /= 8;
1364
1365    algorithmDictValue = (CFDataRef) utilGetStringFromCFDict(parameters, kSecAttrPRF, kSecAttrPRFHmacAlgSHA256);
1366
1367    rounds = utilGetNumberFromCFDict(parameters, kSecAttrRounds, 0);
1368
1369    /* Convert any remaining parameters and get the password bytes */
1370
1371    saltLen = CFDataGetLength(saltDictValue);
1372    if((salt = (uint8_t *) malloc(saltLen)) == NULL) {
1373        *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL);
1374        return NULL;
1375    }
1376
1377    CFDataGetBytes(saltDictValue, CFRangeMake(0, saltLen), (UInt8 *) salt);
1378
1379    passwordLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(password), kCFStringEncodingUTF8) + 1;
1380    if((thePassword = (char *) malloc(passwordLen)) == NULL) {
1381        free(salt);
1382        *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL);
1383        return NULL;
1384    }
1385    CFStringGetBytes(password, CFRangeMake(0, CFStringGetLength(password)), kCFStringEncodingUTF8, '?', FALSE, (UInt8*)thePassword, passwordLen, &passwordLen);
1386
1387    if((derivedKey = (uint8_t *) malloc(derivedKeyLen)) == NULL) {
1388        free(salt);
1389        bzero(thePassword, strlen(thePassword));
1390        free(thePassword);
1391        *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL);
1392        return NULL;
1393    }
1394
1395
1396    if(algorithmDictValue == NULL) {
1397        algorithm = kCCPRFHmacAlgSHA1; /* default */
1398    } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA1)) {
1399        algorithm = kCCPRFHmacAlgSHA1;
1400    } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA224)) {
1401        algorithm = kCCPRFHmacAlgSHA224;
1402    } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA256)) {
1403        algorithm = kCCPRFHmacAlgSHA256;
1404    } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA384)) {
1405        algorithm = kCCPRFHmacAlgSHA384;
1406    } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA512)) {
1407        algorithm = kCCPRFHmacAlgSHA512;
1408    } else {
1409#warning "This else clause is here to prevent the use of unitialized variable, but really, this should return an error, without leaking."
1410        algorithm = kCCPRFHmacAlgSHA1;
1411    }
1412
1413    if(rounds == 0) {
1414        rounds = 33333; // we need to pass back a consistent value since there's no way to record the round count.
1415    }
1416
1417
1418    if(CCKeyDerivationPBKDF(kCCPBKDF2, thePassword, passwordLen, salt, saltLen, algorithm, rounds, derivedKey, derivedKeyLen)) {
1419#warning "Aren't we leaking salt and thePassword when this fail???"
1420        *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL);
1421        return NULL;
1422    }
1423
1424    free(salt);
1425    bzero(thePassword, strlen(thePassword));
1426    free(thePassword);
1427
1428    CFDataRef keyData = CFDataCreate(NULL, derivedKey, derivedKeyLen);
1429    bzero(derivedKey, derivedKeyLen);
1430    free(derivedKey);
1431
1432    SecKeyRef retval =  SecKeyCreateFromData(parameters, keyData, error);
1433    return retval;
1434
1435}
1436
1437CFDataRef
1438SecKeyWrapSymmetric(SecKeyRef keyToWrap, SecKeyRef wrappingKey, CFDictionaryRef parameters, CFErrorRef *error)
1439{
1440    *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
1441    return NULL;
1442}
1443
1444SecKeyRef
1445SecKeyUnwrapSymmetric(CFDataRef *keyToUnwrap, SecKeyRef unwrappingKey, CFDictionaryRef parameters, CFErrorRef *error)
1446{
1447    *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
1448    return NULL;
1449}
1450
1451
1452/* iOS SecKey shim functions */
1453
1454#define MAX_DIGEST_LEN (CC_SHA512_DIGEST_LENGTH)
1455
1456/* Currently length of SHA512 oid + 1 */
1457#define MAX_OID_LEN (10)
1458
1459#define DER_MAX_DIGEST_INFO_LEN  (10 + MAX_DIGEST_LEN + MAX_OID_LEN)
1460
1461/* Encode the digestInfo header into digestInfo and return the offset from
1462 digestInfo at which to put the actual digest.  Returns 0 if digestInfo
1463 won't fit within digestInfoLength bytes.
1464
1465 0x30, topLen,
1466 0x30, algIdLen,
1467 0x06, oid.Len, oid.Data,
1468 0x05, 0x00
1469 0x04, digestLen
1470 digestData
1471 */
1472static size_t DEREncodeDigestInfoPrefix(const SecAsn1Oid *oid,
1473                                        size_t digestLength,
1474                                        uint8_t *digestInfo,
1475                                        size_t digestInfoLength)
1476{
1477    size_t algIdLen = oid->Length + 4;
1478    size_t topLen = algIdLen + digestLength + 4;
1479	size_t totalLen = topLen + 2;
1480
1481    if (totalLen > digestInfoLength) {
1482        return 0;
1483    }
1484
1485    size_t ix = 0;
1486    digestInfo[ix++] = (SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED);
1487    digestInfo[ix++] = topLen;
1488    digestInfo[ix++] = (SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED);
1489    digestInfo[ix++] = algIdLen;
1490    digestInfo[ix++] = SEC_ASN1_OBJECT_ID;
1491    digestInfo[ix++] = oid->Length;
1492    memcpy(&digestInfo[ix], oid->Data, oid->Length);
1493    ix += oid->Length;
1494    digestInfo[ix++] = SEC_ASN1_NULL;
1495    digestInfo[ix++] = 0;
1496    digestInfo[ix++] = SEC_ASN1_OCTET_STRING;
1497    digestInfo[ix++] = digestLength;
1498
1499    return ix;
1500}
1501
1502static OSStatus SecKeyGetDigestInfo(SecKeyRef key, const SecAsn1AlgId *algId,
1503                                    const uint8_t *data, size_t dataLen, bool digestData,
1504                                    uint8_t *digestInfo, size_t *digestInfoLen /* IN/OUT */)
1505{
1506    unsigned char *(*digestFcn)(const void *, CC_LONG, unsigned char *);
1507    CFIndex keyAlgID = kSecNullAlgorithmID;
1508    const SecAsn1Oid *digestOid;
1509    size_t digestLen;
1510    size_t offset = 0;
1511
1512    /* Since these oids all have the same prefix, use switch. */
1513    if ((algId->algorithm.Length == CSSMOID_RSA.Length) &&
1514        !memcmp(algId->algorithm.Data, CSSMOID_RSA.Data,
1515                algId->algorithm.Length - 1)) {
1516            keyAlgID = kSecRSAAlgorithmID;
1517            switch (algId->algorithm.Data[algId->algorithm.Length - 1]) {
1518#if 0
1519                case 2: /* oidMD2WithRSA */
1520                    digestFcn = CC_MD2;
1521                    digestLen = CC_MD2_DIGEST_LENGTH;
1522                    digestOid = &CSSMOID_MD2;
1523                    break;
1524                case 3: /* oidMD4WithRSA */
1525                    digestFcn = CC_MD4;
1526                    digestLen = CC_MD4_DIGEST_LENGTH;
1527                    digestOid = &CSSMOID_MD4;
1528                    break;
1529                case 4: /* oidMD5WithRSA */
1530                    digestFcn = CC_MD5;
1531                    digestLen = CC_MD5_DIGEST_LENGTH;
1532                    digestOid = &CSSMOID_MD5;
1533                    break;
1534#endif /* 0 */
1535                case 5: /* oidSHA1WithRSA */
1536                    digestFcn = CC_SHA1;
1537                    digestLen = CC_SHA1_DIGEST_LENGTH;
1538                    digestOid = &CSSMOID_SHA1;
1539                    break;
1540                case 11: /* oidSHA256WithRSA */
1541                    digestFcn = CC_SHA256;
1542                    digestLen = CC_SHA256_DIGEST_LENGTH;
1543                    digestOid = &CSSMOID_SHA256;
1544                    break;
1545                case 12: /* oidSHA384WithRSA */
1546                    /* pkcs1 12 */
1547                    digestFcn = CC_SHA384;
1548                    digestLen = CC_SHA384_DIGEST_LENGTH;
1549                    digestOid = &CSSMOID_SHA384;
1550                    break;
1551                case 13: /* oidSHA512WithRSA */
1552                    digestFcn = CC_SHA512;
1553                    digestLen = CC_SHA512_DIGEST_LENGTH;
1554                    digestOid = &CSSMOID_SHA512;
1555                    break;
1556                case 14: /* oidSHA224WithRSA */
1557                    digestFcn = CC_SHA224;
1558                    digestLen = CC_SHA224_DIGEST_LENGTH;
1559                    digestOid = &CSSMOID_SHA224;
1560                    break;
1561                default:
1562                    secdebug("key", "unsupported rsa signature algorithm");
1563                    return errSecUnsupportedAlgorithm;
1564            }
1565        } else if ((algId->algorithm.Length == CSSMOID_ECDSA_WithSHA224.Length) &&
1566                   !memcmp(algId->algorithm.Data, CSSMOID_ECDSA_WithSHA224.Data,
1567                           algId->algorithm.Length - 1)) {
1568                       keyAlgID = kSecECDSAAlgorithmID;
1569                       switch (algId->algorithm.Data[algId->algorithm.Length - 1]) {
1570                           case 1: /* oidSHA224WithECDSA */
1571                               digestFcn = CC_SHA224;
1572                               digestLen = CC_SHA224_DIGEST_LENGTH;
1573                               break;
1574                           case 2: /* oidSHA256WithECDSA */
1575                               digestFcn = CC_SHA256;
1576                               digestLen = CC_SHA256_DIGEST_LENGTH;
1577                               break;
1578                           case 3: /* oidSHA384WithECDSA */
1579                               /* pkcs1 12 */
1580                               digestFcn = CC_SHA384;
1581                               digestLen = CC_SHA384_DIGEST_LENGTH;
1582                               break;
1583                           case 4: /* oidSHA512WithECDSA */
1584                               digestFcn = CC_SHA512;
1585                               digestLen = CC_SHA512_DIGEST_LENGTH;
1586                               break;
1587                           default:
1588                               secdebug("key", "unsupported ecdsa signature algorithm");
1589                               return errSecUnsupportedAlgorithm;
1590                       }
1591                   } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_ECDSA_WithSHA1)) {
1592                       keyAlgID = kSecECDSAAlgorithmID;
1593                       digestFcn = CC_SHA1;
1594                       digestLen = CC_SHA1_DIGEST_LENGTH;
1595                   } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_SHA1)) {
1596                       digestFcn = CC_SHA1;
1597                       digestLen = CC_SHA1_DIGEST_LENGTH;
1598                       digestOid = &CSSMOID_SHA1;
1599                   } else if ((algId->algorithm.Length == CSSMOID_SHA224.Length) &&
1600                              !memcmp(algId->algorithm.Data, CSSMOID_SHA224.Data, algId->algorithm.Length - 1))
1601                   {
1602                       switch (algId->algorithm.Data[algId->algorithm.Length - 1]) {
1603                           case 4: /* OID_SHA224 */
1604                               digestFcn = CC_SHA224;
1605                               digestLen = CC_SHA224_DIGEST_LENGTH;
1606                               digestOid = &CSSMOID_SHA224;
1607                               break;
1608                           case 1: /* OID_SHA256 */
1609                               digestFcn = CC_SHA256;
1610                               digestLen = CC_SHA256_DIGEST_LENGTH;
1611                               digestOid = &CSSMOID_SHA256;
1612                               break;
1613                           case 2: /* OID_SHA384 */
1614                               /* pkcs1 12 */
1615                               digestFcn = CC_SHA384;
1616                               digestLen = CC_SHA384_DIGEST_LENGTH;
1617                               digestOid = &CSSMOID_SHA384;
1618                               break;
1619                           case 3: /* OID_SHA512 */
1620                               digestFcn = CC_SHA512;
1621                               digestLen = CC_SHA512_DIGEST_LENGTH;
1622                               digestOid = &CSSMOID_SHA512;
1623                               break;
1624                           default:
1625                               secdebug("key", "unsupported sha-2 signature algorithm");
1626                               return errSecUnsupportedAlgorithm;
1627                       }
1628                   } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_MD5)) {
1629                       digestFcn = CC_MD5;
1630                       digestLen = CC_MD5_DIGEST_LENGTH;
1631                       digestOid = &CSSMOID_MD5;
1632                   } else {
1633                       secdebug("key", "unsupported digesting algorithm");
1634                       return errSecUnsupportedAlgorithm;
1635                   }
1636
1637    /* check key is appropriate for signature (superfluous for digest only oid) */
1638    {
1639        CFIndex supportedKeyAlgID = kSecNullAlgorithmID;
1640    #if TARGET_OS_EMBEDDED
1641        supportedKeyAlgID = SecKeyGetAlgorithmID(key);
1642    #else
1643        const CSSM_KEY* temporaryKey;
1644        SecKeyGetCSSMKey(key, &temporaryKey);
1645        CSSM_ALGORITHMS tempAlgorithm = temporaryKey->KeyHeader.AlgorithmId;
1646        if (CSSM_ALGID_RSA == tempAlgorithm) {
1647            supportedKeyAlgID = kSecRSAAlgorithmID;
1648        } else if (CSSM_ALGID_ECDSA == tempAlgorithm) {
1649            supportedKeyAlgID = kSecECDSAAlgorithmID;
1650        }
1651    #endif
1652
1653        if (keyAlgID == kSecNullAlgorithmID) {
1654            keyAlgID = supportedKeyAlgID;
1655        }
1656        else if (keyAlgID != supportedKeyAlgID) {
1657            return errSecUnsupportedAlgorithm;
1658        }
1659    }
1660
1661    switch(keyAlgID) {
1662        case kSecRSAAlgorithmID:
1663            offset = DEREncodeDigestInfoPrefix(digestOid, digestLen,
1664                                               digestInfo, *digestInfoLen);
1665            if (!offset)
1666                return errSecBufferTooSmall;
1667            break;
1668        case kSecDSAAlgorithmID:
1669            if (digestOid != &CSSMOID_SHA1)
1670                return errSecUnsupportedAlgorithm;
1671            break;
1672        case kSecECDSAAlgorithmID:
1673            break;
1674        default:
1675            secdebug("key", "unsupported signature algorithm");
1676            return errSecUnsupportedAlgorithm;
1677    }
1678
1679    if (digestData) {
1680        if(dataLen>UINT32_MAX) /* Check for overflow with CC_LONG cast */
1681            return errSecParam;
1682        digestFcn(data, (CC_LONG)dataLen, &digestInfo[offset]);
1683        *digestInfoLen = offset + digestLen;
1684    } else {
1685        if (dataLen != digestLen)
1686            return errSecParam;
1687        memcpy(&digestInfo[offset], data, dataLen);
1688        *digestInfoLen = offset + dataLen;
1689    }
1690
1691    return errSecSuccess;
1692}
1693
1694OSStatus SecKeyVerifyDigest(
1695    SecKeyRef           key,            /* Private key */
1696    const SecAsn1AlgId  *algId,         /* algorithm oid/params */
1697    const uint8_t       *digestData,    /* signature over this digest */
1698    size_t              digestDataLen,  /* length of dataToDigest */
1699    const uint8_t       *sig,           /* signature to verify */
1700    size_t              sigLen)         /* length of sig */
1701{
1702    size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN;
1703    uint8_t digestInfo[digestInfoLength];
1704    OSStatus status;
1705
1706    status = SecKeyGetDigestInfo(key, algId, digestData, digestDataLen, false /* data is digest */,
1707                                 digestInfo, &digestInfoLength);
1708    if (status)
1709        return status;
1710    return SecKeyRawVerify(key, kSecPaddingPKCS1,
1711                           digestInfo, digestInfoLength, sig, sigLen);
1712}
1713
1714OSStatus SecKeySignDigest(
1715    SecKeyRef           key,            /* Private key */
1716    const SecAsn1AlgId  *algId,         /* algorithm oid/params */
1717    const uint8_t       *digestData,	/* signature over this digest */
1718    size_t              digestDataLen,  /* length of digestData */
1719    uint8_t             *sig,			/* signature, RETURNED */
1720    size_t              *sigLen)		/* IN/OUT */
1721{
1722    size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN;
1723    uint8_t digestInfo[digestInfoLength];
1724    OSStatus status;
1725
1726    status = SecKeyGetDigestInfo(key, algId, digestData, digestDataLen, false,
1727                                 digestInfo, &digestInfoLength);
1728    if (status)
1729        return status;
1730    return SecKeyRawSign(key, kSecPaddingPKCS1,
1731                         digestInfo, digestInfoLength, sig, sigLen);
1732}
1733
1734/* It's debatable whether this belongs here or in the ssl code since the
1735 curve values come from a tls related rfc4492. */
1736SecECNamedCurve SecECKeyGetNamedCurve(SecKeyRef key)
1737{
1738    try {
1739        SecPointer<KeyItem> keyItem(KeyItem::required(key));
1740        switch (keyItem->key().header().LogicalKeySizeInBits) {
1741#if 0
1742            case 192:
1743                return kSecECCurveSecp192r1;
1744            case 224:
1745                return kSecECCurveSecp224r1;
1746#endif
1747            case 256:
1748                return kSecECCurveSecp256r1;
1749            case 384:
1750                return kSecECCurveSecp384r1;
1751            case 521:
1752                return kSecECCurveSecp521r1;
1753        }
1754    }
1755    catch (...) {}
1756    return kSecECCurveNone;
1757}
1758
1759static inline CFDataRef _CFDataCreateReferenceFromRange(CFAllocatorRef allocator, CFDataRef sourceData, CFRange range)
1760{
1761    return CFDataCreateWithBytesNoCopy(allocator,
1762                                       CFDataGetBytePtr(sourceData) + range.location, range.length,
1763                                       kCFAllocatorNull);
1764}
1765
1766static inline CFDataRef _CFDataCreateCopyFromRange(CFAllocatorRef allocator, CFDataRef sourceData, CFRange range)
1767{
1768    return CFDataCreate(allocator, CFDataGetBytePtr(sourceData) + range.location, range.length);
1769}
1770
1771static inline bool _CFDataEquals(CFDataRef left, CFDataRef right)
1772{
1773    return (left != NULL) &&
1774    (right != NULL) &&
1775    (CFDataGetLength(left) == CFDataGetLength(right)) &&
1776    (0 == memcmp(CFDataGetBytePtr(left), CFDataGetBytePtr(right), (size_t)CFDataGetLength(left)));
1777}
1778
1779#if ECDSA_DEBUG
1780void secdump(const unsigned char *data, unsigned long len)
1781{
1782	unsigned long i;
1783	char s[128];
1784	char t[32];
1785	s[0]=0;
1786	for(i=0;i<len;i++)
1787	{
1788		if((i&0xf)==0) {
1789			sprintf(t, "%04lx :", i);
1790			strcat(s, t);
1791		}
1792		sprintf(t, " %02x", data[i]);
1793		strcat(s, t);
1794		if((i&0xf)==0xf) {
1795			strcat(s, "\n");
1796			syslog(LOG_NOTICE, s);
1797			s[0]=0;
1798		}
1799	}
1800	strcat(s, "\n");
1801	syslog(LOG_NOTICE, s);
1802}
1803#endif
1804
1805OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* publicBytes)
1806{
1807	CFIndex keyAlgId;
1808#if TARGET_OS_EMBEDDED
1809	keyAlgId = SecKeyGetAlgorithmID(key);
1810#else
1811	keyAlgId = SecKeyGetAlgorithmId(key);
1812#endif
1813
1814	OSStatus ecStatus = errSecParam;
1815	CFDataRef tempPublicData = NULL;
1816	CFDataRef headerlessPublicData = NULL;
1817	CFIndex headerLength = 0;
1818    const UInt8* pData_Ptr = NULL;
1819
1820	if (kSecRSAAlgorithmID == keyAlgId)
1821	{
1822		return SecItemExport(key, kSecFormatBSAFE, 0, NULL, publicBytes);
1823	}
1824
1825	if (kSecECDSAAlgorithmID == keyAlgId)
1826	{
1827		// First export the key so there is access to the underlying key material
1828		ecStatus = SecItemExport(key, kSecFormatOpenSSL, 0, NULL, &tempPublicData);
1829		if(ecStatus != errSecSuccess)
1830		{
1831			secdebug("key", "SecKeyCopyPublicBytes: SecItemExport error (%d) for ECDSA public key %p",
1832					ecStatus, (uintptr_t)key);
1833
1834	        return ecStatus;
1835        }
1836
1837
1838        // Get a pointer to the first byte of the exported data
1839        pData_Ptr = CFDataGetBytePtr(tempPublicData);
1840
1841        // the first byte should be a sequence 0x30
1842        if (*pData_Ptr != 0x30)
1843        {
1844            secdebug("key", "SecKeyCopyPublicBytes: exported data is invalid");
1845             if (NULL != tempPublicData)
1846	            CFRelease(tempPublicData);
1847
1848			ecStatus = errSecParam;
1849	        return ecStatus;
1850        }
1851
1852        // move past the sequence byte
1853        pData_Ptr++;
1854
1855        // Check to see if the high bit is set which
1856        // indicates that the length will be at least
1857        // two bytes.  If the high bit is set then
1858        // The lower seven bits specifies the number of
1859    	// bytes used for the length.  The additonal 1
1860    	// is for the current byte. Otherwise just move past the
1861    	// single length byte
1862        pData_Ptr += (*pData_Ptr & 0x80) ? ((*pData_Ptr & 0x7F) + 1) : 1;
1863
1864        // The current byte should be a sequence 0x30
1865        if (*pData_Ptr != 0x30)
1866        {
1867        	secdebug("key", "SecKeyCopyPublicBytes: Could not find the key sequence");
1868             if (NULL != tempPublicData)
1869	            CFRelease(tempPublicData);
1870
1871			ecStatus = errSecParam;
1872
1873	        return ecStatus;
1874        }
1875
1876        // The next bytes will always be the same
1877        // 0x30 = SEQUENCE
1878        // XX Length Byte
1879        // 0x06 OBJECT ID
1880        // 0x07 Length Byte
1881        // ECDSA public KEY OID value 0x2a,0x86,0x48,0xce,0x3d,0x02,0x01
1882        // 0x06 OBJECT ID
1883        // This is a total of 12 bytes
1884        pData_Ptr += 12;
1885
1886        // Next byte is the length of the ECDSA curve OID
1887        // Move past the length byte and the curve OID
1888        pData_Ptr += (((int)*pData_Ptr) + 1);
1889
1890        // Should be at a BINARY String which is specifed by a 0x3
1891        if (*pData_Ptr != 0x03)
1892        {
1893        	secdebug("key", "SecKeyCopyPublicBytes: Invalid key structure");
1894             if (NULL != tempPublicData)
1895	            CFRelease(tempPublicData);
1896
1897			ecStatus = errSecParam;
1898
1899	        return ecStatus;
1900        }
1901
1902        // Move past the BINARY String specifier 0x03
1903        pData_Ptr++;
1904
1905
1906        // Check to see if the high bit is set which
1907        // indicates that the length will be at least
1908        // two bytes.  If the high bit is set then
1909        // The lower seven bits specifies the number of
1910    	// bytes used for the length.  The additonal 1
1911    	// is for the current byte. Otherwise just move past the
1912    	// single length byte
1913        pData_Ptr += (*pData_Ptr & 0x80) ? ((*pData_Ptr & 0x7F) + 1) : 1;
1914
1915        // Move past the beginning marker for the BINARY String 0x00
1916        pData_Ptr++;
1917
1918        // pData_Ptr now points to the first bytes of the key material
1919        headerLength = (CFIndex)(((intptr_t)pData_Ptr) -  ((intptr_t)CFDataGetBytePtr(tempPublicData)));
1920
1921        headerlessPublicData = _CFDataCreateCopyFromRange(kCFAllocatorDefault,
1922            tempPublicData, CFRangeMake(headerLength, CFDataGetLength(tempPublicData) - headerLength));
1923
1924        if (!headerlessPublicData)
1925        {
1926			printf("SecKeyCopyPublicBytes: headerlessPublicData is nil (1)\n");
1927		 if (NULL != tempPublicData)
1928	            CFRelease(tempPublicData);
1929
1930			ecStatus = errSecParam;
1931
1932	        return ecStatus;
1933		}
1934
1935        if (publicBytes)
1936        {
1937        	*publicBytes = headerlessPublicData;
1938        }
1939
1940        ecStatus = errSecSuccess;
1941
1942        if (NULL != tempPublicData)
1943            CFRelease(tempPublicData);
1944
1945        return ecStatus;
1946      }
1947
1948  return errSecParam;
1949}
1950
1951
1952CFDataRef SecECKeyCopyPublicBits(SecKeyRef key)
1953{
1954    CFDataRef exportedKey;
1955    if(SecKeyCopyPublicBytes(key, &exportedKey) != errSecSuccess) {
1956        exportedKey = NULL;
1957    }
1958    return exportedKey;
1959}
1960
1961SecKeyRef SecKeyCreateFromPublicData(CFAllocatorRef allocator, CFIndex algorithmID, CFDataRef publicBytes)
1962{
1963    SecExternalFormat externalFormat = kSecFormatOpenSSL;
1964    SecExternalItemType externalItemType = kSecItemTypePublicKey;
1965    CFDataRef workingData = NULL;
1966    CFArrayRef outArray = NULL;
1967    SecKeyRef retVal = NULL;
1968
1969    if (kSecRSAAlgorithmID == algorithmID) {
1970		/*
1971		 * kSecFormatBSAFE uses the original PKCS#1 definition:
1972		 *     RSAPublicKey ::= SEQUENCE {
1973		 *        modulus           INTEGER,  -- n
1974		 *        publicExponent    INTEGER   -- e
1975		 *     }
1976		 * kSecFormatOpenSSL uses different ASN.1 encoding.
1977		 */
1978		externalFormat = kSecFormatBSAFE;
1979        workingData = _CFDataCreateReferenceFromRange(kCFAllocatorDefault, publicBytes, CFRangeMake(0, CFDataGetLength(publicBytes)));
1980    } else if (kSecECDSAAlgorithmID == algorithmID) {
1981        CFMutableDataRef tempData;
1982        uint8 headerBytes[] = { 0x30,0x59,0x30,0x13,0x06,0x07,0x2a,0x86,
1983                                0x48,0xce,0x3d,0x02,0x01,0x06,0x08,0x2a,
1984                                0x86,0x48,0xce,0x3d,0x03,0x01,0x07,0x03,
1985                                0x42,0x00 };
1986
1987        /* FIXME: this code only handles one specific curve type; need to expand this */
1988        tempData = CFDataCreateMutable(kCFAllocatorDefault, 0);
1989        CFDataAppendBytes(tempData, headerBytes, sizeof(headerBytes));
1990        CFDataAppendBytes(tempData, CFDataGetBytePtr(publicBytes), CFDataGetLength(publicBytes));
1991        workingData = tempData;
1992    }
1993    if(SecItemImport(workingData, NULL, &externalFormat, &externalItemType, 0, NULL, NULL, &outArray) != errSecSuccess) {
1994		goto cleanup;
1995    }
1996	if(!outArray || CFArrayGetCount(outArray) == 0) {
1997		goto cleanup;
1998	}
1999    retVal = (SecKeyRef)CFArrayGetValueAtIndex(outArray, 0);
2000    CFRetain(retVal);
2001
2002cleanup:
2003    if(workingData) CFRelease(workingData);
2004    if(outArray) CFRelease(outArray);
2005    return retVal;
2006}
2007
2008SecKeyRef SecKeyCreateRSAPublicKey(CFAllocatorRef allocator,
2009    const uint8_t *keyData, CFIndex keyDataLength,
2010    SecKeyEncoding encoding)
2011{
2012	CFDataRef pubKeyData = NULL;
2013    if(kSecKeyEncodingPkcs1 == encoding) {
2014        /* DER-encoded according to PKCS1. */
2015		pubKeyData = CFDataCreate(allocator, keyData, keyDataLength);
2016
2017    } else if(kSecKeyEncodingApplePkcs1 == encoding) {
2018        /* DER-encoded according to PKCS1 with Apple Extensions. */
2019		/* FIXME: need to actually handle extensions */
2020		return NULL;
2021
2022    } else if(kSecKeyEncodingRSAPublicParams == encoding) {
2023        /* SecRSAPublicKeyParams format; we must encode as PKCS1. */
2024		SecRSAPublicKeyParams *params = (SecRSAPublicKeyParams *)keyData;
2025		DERSize m_size = params->modulusLength;
2026		DERSize e_size = params->exponentLength;
2027		const DERSize seq_size = DERLengthOfItem(ASN1_INTEGER, m_size) +
2028			DERLengthOfItem(ASN1_INTEGER, e_size);
2029		const DERSize result_size = DERLengthOfItem(ASN1_SEQUENCE, seq_size);
2030		DERSize r_size, remaining_size = result_size;
2031		DERReturn drtn;
2032
2033		CFMutableDataRef pkcs1 = CFDataCreateMutable(allocator, result_size);
2034		if (pkcs1 == NULL) {
2035			return NULL;
2036		}
2037		CFDataSetLength(pkcs1, result_size);
2038		uint8_t *bytes = CFDataGetMutableBytePtr(pkcs1);
2039
2040		*bytes++ = ASN1_CONSTR_SEQUENCE;
2041		remaining_size--;
2042		r_size = 4;
2043		drtn = DEREncodeLength(seq_size, bytes, &r_size);
2044		if (r_size <= remaining_size) {
2045			bytes += r_size;
2046			remaining_size -= r_size;
2047		}
2048		r_size = remaining_size;
2049		drtn = DEREncodeItem(ASN1_INTEGER, m_size, (const DERByte *)params->modulus, (DERByte *)bytes, &r_size);
2050		if (r_size <= remaining_size) {
2051			bytes += r_size;
2052			remaining_size -= r_size;
2053		}
2054		r_size = remaining_size;
2055		drtn = DEREncodeItem(ASN1_INTEGER, e_size, (const DERByte *)params->exponent, (DERByte *)bytes, &r_size);
2056
2057		pubKeyData = pkcs1;
2058
2059    } else {
2060        /* unsupported encoding */
2061        return NULL;
2062    }
2063    SecKeyRef publicKey = SecKeyCreateFromPublicData(allocator, kSecRSAAlgorithmID, pubKeyData);
2064    CFRelease(pubKeyData);
2065    return publicKey;
2066}
2067
2068#if !TARGET_OS_EMBEDDED
2069//
2070// Given a CSSM public key, copy its modulus and/or exponent data.
2071// Caller is responsible for releasing the returned CFDataRefs.
2072//
2073static
2074OSStatus _SecKeyCopyRSAPublicModulusAndExponent(SecKeyRef key, CFDataRef *modulus, CFDataRef *exponent)
2075{
2076	const CSSM_KEY          *pubKey;
2077	const CSSM_KEYHEADER	*hdr;
2078	CSSM_DATA               pubKeyBlob;
2079	OSStatus                result;
2080
2081    result = SecKeyGetCSSMKey(key, &pubKey);
2082	if(result != errSecSuccess) {
2083		return result;
2084	}
2085	hdr = &pubKey->KeyHeader;
2086	if(hdr->KeyClass != CSSM_KEYCLASS_PUBLIC_KEY) {
2087		return errSSLInternal;
2088	}
2089	if(hdr->AlgorithmId != CSSM_ALGID_RSA) {
2090		return errSSLInternal;
2091	}
2092	switch(hdr->BlobType) {
2093		case CSSM_KEYBLOB_RAW:
2094			pubKeyBlob.Length = pubKey->KeyData.Length;
2095			pubKeyBlob.Data = pubKey->KeyData.Data;
2096			break;
2097		case CSSM_KEYBLOB_REFERENCE:
2098			// FIXME: currently SSL only uses raw public keys, obtained from the CL
2099		default:
2100			return errSSLInternal;
2101	}
2102	assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
2103	// at this point we should have a PKCS1-encoded blob
2104
2105    DERItem keyItem = {(DERByte *)pubKeyBlob.Data, pubKeyBlob.Length};
2106    DERRSAPubKeyPKCS1 decodedKey;
2107    if(DERParseSequence(&keyItem, DERNumRSAPubKeyPKCS1ItemSpecs,
2108                        DERRSAPubKeyPKCS1ItemSpecs,
2109                        &decodedKey, sizeof(decodedKey)) != DR_Success) {
2110        return errSecDecode;
2111    }
2112    if(modulus) {
2113        *modulus = CFDataCreate(kCFAllocatorDefault, decodedKey.modulus.data, decodedKey.modulus.length);
2114        if(*modulus == NULL) {
2115            return errSecDecode;
2116        }
2117    }
2118    if(exponent) {
2119        *exponent = CFDataCreate(kCFAllocatorDefault, decodedKey.pubExponent.data, decodedKey.pubExponent.length);
2120        if(*exponent == NULL) {
2121            return errSecDecode;
2122        }
2123    }
2124
2125    return errSecSuccess;
2126}
2127#endif /* !TARGET_OS_EMBEDDED */
2128
2129CFDataRef SecKeyCopyModulus(SecKeyRef key)
2130{
2131#if TARGET_OS_EMBEDDED
2132    ccrsa_pub_ctx_t pubkey;
2133    pubkey.pub = key->key;
2134
2135    size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey));
2136
2137	CFAllocatorRef allocator = CFGetAllocator(key);
2138	CFMutableDataRef modulusData = CFDataCreateMutable(allocator, m_size);
2139
2140    if (modulusData == NULL)
2141        return NULL;
2142
2143	CFDataSetLength(modulusData, m_size);
2144
2145    ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), m_size, CFDataGetMutableBytePtr(modulusData));
2146#else
2147    CFDataRef modulusData;
2148    OSStatus status = _SecKeyCopyRSAPublicModulusAndExponent(key, &modulusData, NULL);
2149    if(status != errSecSuccess) {
2150        modulusData = NULL;
2151    }
2152#endif
2153
2154    return modulusData;
2155}
2156
2157CFDataRef SecKeyCopyExponent(SecKeyRef key)
2158{
2159#if TARGET_OS_EMBEDDED
2160    ccrsa_pub_ctx_t pubkey;
2161    pubkey.pub = key->key;
2162
2163    size_t e_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey));
2164
2165	CFAllocatorRef allocator = CFGetAllocator(key);
2166	CFMutableDataRef exponentData = CFDataCreateMutable(allocator, e_size);
2167
2168    if (exponentData == NULL)
2169        return NULL;
2170
2171	CFDataSetLength(exponentData, e_size);
2172
2173    ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), e_size, CFDataGetMutableBytePtr(exponentData));
2174#else
2175    CFDataRef exponentData;
2176    OSStatus status = _SecKeyCopyRSAPublicModulusAndExponent(key, NULL, &exponentData);
2177    if(status != errSecSuccess) {
2178        exponentData = NULL;
2179    }
2180#endif
2181
2182    return exponentData;
2183}
2184
2185SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey) {
2186    OSStatus status = errSecParam;
2187
2188    CFDataRef serializedPublic = NULL;
2189
2190    status = SecKeyCopyPublicBytes(privateKey, &serializedPublic);
2191    if ((status == errSecSuccess) && (serializedPublic != NULL)) {
2192        SecKeyRef publicKeyRef = SecKeyCreateFromPublicData(kCFAllocatorDefault, SecKeyGetAlgorithmId(privateKey), serializedPublic);
2193        CFRelease(serializedPublic);
2194        if (publicKeyRef != NULL) {
2195            return publicKeyRef;
2196        }
2197    }
2198
2199    const void *keys[]      = { kSecClass, kSecValueRef, kSecReturnAttributes };
2200    const void *values[]    = { kSecClassKey, privateKey,  kCFBooleanTrue };
2201    CFDictionaryRef query= CFDictionaryCreate(NULL, keys, values,
2202                                              (sizeof(values) / sizeof(*values)),
2203                                              &kCFTypeDictionaryKeyCallBacks,
2204                                              &kCFTypeDictionaryValueCallBacks);
2205    CFTypeRef foundItem = NULL;
2206    status = SecItemCopyMatching(query, &foundItem);
2207
2208    if (status == errSecSuccess) {
2209        if (CFGetTypeID(foundItem) == CFDictionaryGetTypeID()) {
2210            CFMutableDictionaryRef query2 = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2211            CFDictionaryAddValue(query2, kSecClass, kSecClassKey);
2212            CFDictionaryAddValue(query2, kSecAttrKeyClass, kSecAttrKeyClassPublic);
2213            CFDictionaryAddValue(query2, kSecAttrApplicationLabel, CFDictionaryGetValue((CFDictionaryRef)foundItem, kSecAttrApplicationLabel));
2214            CFDictionaryAddValue(query2, kSecReturnRef, kCFBooleanTrue);
2215
2216            CFTypeRef foundKey = NULL;
2217            status = SecItemCopyMatching(query2, &foundKey);
2218            if (status == errSecSuccess) {
2219                if (CFGetTypeID(foundKey) == SecKeyGetTypeID()) {
2220                    CFRelease(query);
2221                    CFRelease(query2);
2222                    CFRelease(foundItem);
2223                    return (SecKeyRef)foundKey;
2224                } else {
2225                    status = errSecItemNotFound;
2226                }
2227            }
2228            CFRelease(query2);
2229
2230        } else {
2231            status = errSecItemNotFound;
2232        }
2233        CFRelease(foundItem);
2234    }
2235
2236    CFRelease(query);
2237    return NULL;
2238}
2239
2240