]> git.saurik.com Git - apple/security.git/blob - libsecurity_keychain/lib/SecKey.cpp
Security-55471.14.tar.gz
[apple/security.git] / libsecurity_keychain / lib / SecKey.cpp
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
50 CFTypeID
51 SecKeyGetTypeID(void)
52 {
53 BEGIN_SECAPI
54
55 return gTypes().KeyItem.typeID;
56
57 END_SECAPI1(_kCFRuntimeNotATypeID)
58 }
59
60 static 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
103 OSStatus
104 SecKeyCreatePair(
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
125 OSStatus
126 SecKeyGetCSSMKey(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
140 OSStatus
141 SecKeyGetCSPHandle(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 */
152 OSStatus
153 SecKeyGetAlgorithmID(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 */
164 CFIndex
165 SecKeyGetAlgorithmId(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
185 OSStatus
186 SecKeyGetStrengthInBits(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
196 OSStatus
197 SecKeyGetCredentials(
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
211 OSStatus
212 SecKeyImportPair(
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
242 static OSStatus
243 SecKeyGenerateWithAttributes(
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
280 OSStatus
281 SecKeyGenerate(
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 */
300 SecKeyRef
301 SecKeyCreate(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 */
323 OSStatus
324 SecKeyCreateWithCSSMKey(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
343 static 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
363 static 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
392 static 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
434 enum AttributeType
435 {
436 kStringType,
437 kBooleanType,
438 kIntegerType
439 };
440
441
442
443 struct ParameterAttribute
444 {
445 const CFTypeRef *name;
446 AttributeType type;
447 };
448
449
450
451 static 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
495 const int kNumberOfAttributes = sizeof(gAttributes) / sizeof(ParameterAttribute);
496
497 static 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
535 static 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
638 static 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
691 static 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. */
761 OSStatus
762 SecKeyGeneratePair(
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 */
818 OSStatus
819 SecKeyRawSign(
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
848 OSStatus 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 */
860 OSStatus
861 SecKeyRawVerify(
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 */
891 OSStatus
892 SecKeyEncrypt(
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 */
918 OSStatus
919 SecKeyDecrypt(
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 */
945 size_t
946 SecKeyGetBlockSize(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
1003 static CFTypeRef
1004 utilGetStringFromCFDict(CFDictionaryRef parameters, CFTypeRef key, CFTypeRef defaultValue)
1005 {
1006 CFTypeRef value = CFDictionaryGetValue(parameters, key);
1007 if (value != NULL) return value;
1008 return defaultValue;
1009 }
1010
1011 static uint32_t
1012 utilGetNumberFromCFDict(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
1024 static uint32_t
1025 utilGetMaskValFromCFDict(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
1035 static void
1036 utilGetKeyParametersFromCFDict(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
1119 static CFStringRef
1120 utilCopyDefaultKeyLabel(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
1130 SecKeyRef
1131 SecKeyGenerateSymmetric(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
1248 errorExit:
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
1262 SecKeyRef
1263 SecKeyCreateFromData(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
1312 void
1313 SecKeyGeneratePairAsync(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
1341 SecKeyRef
1342 SecKeyDeriveFromPassword(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
1437 CFDataRef
1438 SecKeyWrapSymmetric(SecKeyRef keyToWrap, SecKeyRef wrappingKey, CFDictionaryRef parameters, CFErrorRef *error)
1439 {
1440 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
1441 return NULL;
1442 }
1443
1444 SecKeyRef
1445 SecKeyUnwrapSymmetric(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 */
1472 static 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
1502 static 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
1694 OSStatus 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
1714 OSStatus 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. */
1736 SecECNamedCurve 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
1759 static 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
1766 static inline CFDataRef _CFDataCreateCopyFromRange(CFAllocatorRef allocator, CFDataRef sourceData, CFRange range)
1767 {
1768 return CFDataCreate(allocator, CFDataGetBytePtr(sourceData) + range.location, range.length);
1769 }
1770
1771 static 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
1780 void 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
1805 OSStatus 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
1952 CFDataRef SecECKeyCopyPublicBits(SecKeyRef key)
1953 {
1954 CFDataRef exportedKey;
1955 if(SecKeyCopyPublicBytes(key, &exportedKey) != errSecSuccess) {
1956 exportedKey = NULL;
1957 }
1958 return exportedKey;
1959 }
1960
1961 SecKeyRef 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
2002 cleanup:
2003 if(workingData) CFRelease(workingData);
2004 if(outArray) CFRelease(outArray);
2005 return retVal;
2006 }
2007
2008 SecKeyRef 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 //
2073 static
2074 OSStatus _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
2129 CFDataRef 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
2157 CFDataRef 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
2185 SecKeyRef 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