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