2 * Copyright (c) 2002-2012 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include "SecKeyPriv.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>
37 #include "SecBridge.h"
39 #include <security_keychain/Access.h>
40 #include <security_keychain/Keychains.h>
41 #include <security_keychain/KeyItem.h>
45 #include <security_cdsa_utils/cuCdsaUtils.h>
46 #include <security_cdsa_client/wrapkey.h>
48 #include "SecImportExportCrypto.h"
55 return gTypes().KeyItem
.typeID
;
57 END_SECAPI1(_kCFRuntimeNotATypeID
)
60 static OSStatus
SecKeyCreatePairInternal(
61 SecKeychainRef keychainRef
,
62 CSSM_ALGORITHMS algorithm
,
64 CSSM_CC_HANDLE contextHandle
,
65 CSSM_KEYUSE publicKeyUsage
,
67 CSSM_KEYUSE privateKeyUsage
,
68 uint32 privateKeyAttr
,
69 SecAccessRef initialAccess
,
70 SecKeyRef
* publicKeyRef
,
71 SecKeyRef
* privateKeyRef
)
75 Keychain keychain
= Keychain::optional(keychainRef
);
76 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
77 SecPointer
<KeyItem
> pubItem
, privItem
;
79 Mutex
*keychainMutex
= keychain
->getKeychainMutex();
80 StLock
<Mutex
> _(*keychainMutex
);
82 KeyItem::createPair(keychain
,
94 // Return the generated keys.
96 *publicKeyRef
= pubItem
->handle();
98 *privateKeyRef
= privItem
->handle();
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
)
117 OSStatus result
= SecKeyCreatePairInternal(keychainRef
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
,
118 publicKeyAttr
, privateKeyUsage
, privateKeyAttr
, initialAccess
, publicKeyRef
, privateKeyRef
);
126 SecKeyGetCSSMKey(SecKeyRef key
, const CSSM_KEY
**cssmKey
)
130 Required(cssmKey
) = KeyItem::required(key
)->key();
141 SecKeyGetCSPHandle(SecKeyRef keyRef
, CSSM_CSP_HANDLE
*cspHandle
)
145 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
146 Required(cspHandle
) = keyItem
->csp()->handle();
151 /* deprecated as of 10.8 */
153 SecKeyGetAlgorithmID(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
**algid
)
157 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
158 Required(algid
) = &keyItem
->algorithmIdentifier();
165 SecKeyGetAlgorithmId(SecKeyRef key
)
167 const CSSM_KEY
*cssmKey
;
169 if (SecKeyGetCSSMKey(key
, &cssmKey
) != errSecSuccess
)
170 return kSecNullAlgorithmID
;
172 switch (cssmKey
->KeyHeader
.AlgorithmId
) {
174 return kSecRSAAlgorithmID
;
176 return kSecDSAAlgorithmID
;
177 case CSSM_ALGID_ECDSA
:
178 return kSecECDSAAlgorithmID
;
180 assert(0); /* other algorithms TBA */
181 return kSecNullAlgorithmID
;
186 SecKeyGetStrengthInBits(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
*algid
, unsigned int *strength
)
190 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
191 Required(strength
) = keyItem
->strengthInBits(algid
);
197 SecKeyGetCredentials(
199 CSSM_ACL_AUTHORIZATION_TAG operation
,
200 SecCredentialType credentialType
,
201 const CSSM_ACCESS_CREDENTIALS
**outCredentials
)
205 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
206 Required(outCredentials
) = keyItem
->getCredentials(operation
, credentialType
);
213 SecKeychainRef keychainRef
,
214 const CSSM_KEY
*publicCssmKey
,
215 const CSSM_KEY
*privateCssmKey
,
216 SecAccessRef initialAccess
,
217 SecKeyRef
* publicKey
,
218 SecKeyRef
* privateKey
)
222 Keychain keychain
= Keychain::optional(keychainRef
);
223 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
224 SecPointer
<KeyItem
> pubItem
, privItem
;
226 KeyItem::importPair(keychain
,
227 Required(publicCssmKey
),
228 Required(privateCssmKey
),
233 // Return the generated keys.
235 *publicKey
= pubItem
->handle();
237 *privateKey
= privItem
->handle();
243 SecKeyGenerateWithAttributes(
244 SecKeychainAttributeList
* attrList
,
245 SecKeychainRef keychainRef
,
246 CSSM_ALGORITHMS algorithm
,
247 uint32 keySizeInBits
,
248 CSSM_CC_HANDLE contextHandle
,
249 CSSM_KEYUSE keyUsage
,
251 SecAccessRef initialAccess
,
257 SecPointer
<Access
> theAccess
;
260 keychain
= KeychainImpl::required(keychainRef
);
262 theAccess
= Access::required(initialAccess
);
264 SecPointer
<KeyItem
> item
= KeyItem::generateWithAttributes(attrList
,
273 // Return the generated key.
275 *keyRef
= item
->handle();
282 SecKeychainRef keychainRef
,
283 CSSM_ALGORITHMS algorithm
,
284 uint32 keySizeInBits
,
285 CSSM_CC_HANDLE contextHandle
,
286 CSSM_KEYUSE keyUsage
,
288 SecAccessRef initialAccess
,
291 return SecKeyGenerateWithAttributes(NULL
,
292 keychainRef
, algorithm
, keySizeInBits
,
293 contextHandle
, keyUsage
, keyAttr
,
294 initialAccess
, keyRef
);
299 /* Create a key from supplied data and parameters */
301 SecKeyCreate(CFAllocatorRef allocator
,
302 const SecKeyDescriptor
*keyClass
,
303 const uint8_t *keyData
,
304 CFIndex keyDataLength
,
305 SecKeyEncoding encoding
)
307 SecKeyRef keyRef
= NULL
;
308 OSStatus __secapiresult
;
310 //FIXME: needs implementation
312 __secapiresult
=errSecSuccess
;
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
; }
322 /* Generate a floating key reference from a CSSM_KEY */
324 SecKeyCreateWithCSSMKey(const CSSM_KEY
*cssmKey
,
330 CssmClient::CSP
csp(cssmKey
->KeyHeader
.CspId
);
331 CssmClient::Key
key(csp
, *cssmKey
);
332 KeyItem
*item
= new KeyItem(key
);
334 // Return the generated key.
336 *keyRef
= item
->handle();
343 static u_int32_t
ConvertCFStringToInteger(CFStringRef ref
)
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
))
355 MacOSError::throwMe(errSecParam
);
363 static OSStatus
CheckAlgorithmType(CFDictionaryRef parameters
, CSSM_ALGORITHMS
&algorithms
)
365 // figure out the algorithm to use
366 CFStringRef ktype
= (CFStringRef
) CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
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
;
386 return errSecUnsupportedAlgorithm
;
392 static OSStatus
GetKeySize(CFDictionaryRef parameters
, CSSM_ALGORITHMS algorithms
, uint32
&keySizeInBits
)
395 // get the key size and check it for validity
396 CFTypeRef ref
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
398 keySizeInBits
= kSecDefaultKeySize
;
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
;
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
;
414 if(keySizeInBits
% 8) return errSecParam
;
415 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= 2048;
416 if(keySizeInBits
>= kSecRSAMin
&& keySizeInBits
<= kSecRSAMax
) return errSecSuccess
;
419 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecAES128
;
420 if(keySizeInBits
== kSecAES128
|| keySizeInBits
== kSecAES192
|| keySizeInBits
== kSecAES256
) return errSecSuccess
;
422 case CSSM_ALGID_3DES
:
423 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSec3DES192
;
424 if(keySizeInBits
== kSec3DES192
) return errSecSuccess
;
443 struct ParameterAttribute
445 const CFTypeRef
*name
;
451 static ParameterAttribute gAttributes
[] =
458 &kSecAttrIsPermanent
,
462 &kSecAttrApplicationTag
,
466 &kSecAttrEffectiveKeySize
,
495 const int kNumberOfAttributes
= sizeof(gAttributes
) / sizeof(ParameterAttribute
);
497 static OSStatus
ScanDictionaryForParameters(CFDictionaryRef parameters
, void* attributePointers
[])
500 for (i
= 0; i
< kNumberOfAttributes
; ++i
)
502 // see if the corresponding tag exists in the dictionary
503 CFTypeRef value
= CFDictionaryGetValue(parameters
, *(gAttributes
[i
].name
));
506 switch (gAttributes
[i
].type
)
509 // just return the value
510 *(CFTypeRef
*) attributePointers
[i
] = value
;
515 CFBooleanRef bRef
= (CFBooleanRef
) value
;
516 *(bool*) attributePointers
[i
] = CFBooleanGetValue(bRef
);
522 CFNumberRef nRef
= (CFNumberRef
) value
;
523 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, attributePointers
[i
]);
530 return errSecSuccess
;
535 static OSStatus
GetKeyParameters(CFDictionaryRef parameters
, int keySize
, bool isPublic
, CSSM_KEYUSE
&keyUse
, uint32
&attrs
, CFTypeRef
&labelRef
, CFDataRef
&applicationTagRef
)
537 // establish default values
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
;
551 void* attributePointers
[] = {&labelRef
, &isPermanent
, &applicationTagRef
, &effectiveKeySize
, &canEncrypt
, &canDecrypt
,
552 &canDerive
, &canSign
, &canVerify
, &canUnwrap
};
554 // look for modifiers in the general dictionary
555 OSStatus result
= ScanDictionaryForParameters(parameters
, attributePointers
);
556 if (result
!= errSecSuccess
)
561 // see if we have anything which modifies the defaults
565 key
= kSecPublicKeyAttrs
;
569 key
= kSecPrivateKeyAttrs
;
572 CFTypeRef dType
= CFDictionaryGetValue(parameters
, key
);
575 // this had better be a dictionary
576 if (CFGetTypeID(dType
) != CFDictionaryGetTypeID())
581 // pull any additional parameters out of this dictionary
582 result
= ScanDictionaryForParameters((CFDictionaryRef
)dType
, attributePointers
);
583 if (result
!= errSecSuccess
)
589 // figure out the key usage
593 keyUse
|= CSSM_KEYUSE_DECRYPT
;
598 keyUse
|= CSSM_KEYUSE_ENCRYPT
;
603 keyUse
|= CSSM_KEYUSE_DERIVE
;
608 keyUse
|= CSSM_KEYUSE_SIGN
;
613 keyUse
|= CSSM_KEYUSE_VERIFY
;
618 keyUse
|= CSSM_KEYUSE_UNWRAP
;
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
)
626 Boolean keyIsExtractable
= CFEqual(kCFBooleanTrue
, value
);
627 if (!keyIsExtractable
)
631 attrs
|= CSSM_KEYATTR_PERMANENT
;
633 return errSecSuccess
;
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
)
653 result
= CheckAlgorithmType(parameters
, algorithms
);
654 if (result
!= errSecSuccess
)
659 result
= GetKeySize(parameters
, algorithms
, keySizeInBits
);
660 if (result
!= errSecSuccess
)
665 result
= GetKeyParameters(parameters
, keySizeInBits
, false, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
666 if (result
!= errSecSuccess
)
671 result
= GetKeyParameters(parameters
, keySizeInBits
, true, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
672 if (result
!= errSecSuccess
)
677 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&initialAccess
))
679 initialAccess
= NULL
;
681 else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess
))
686 return errSecSuccess
;
691 static OSStatus
SetKeyLabelAndTag(SecKeyRef keyRef
, CFTypeRef label
, CFDataRef tag
)
704 if (numToModify
== 0)
706 return errSecSuccess
;
709 SecKeychainAttributeList attrList
;
710 SecKeychainAttribute attributes
[numToModify
];
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
);
726 if (!CFStringGetCString(label_string
, static_cast<char *>(attributes
[i
].data
), buffer_length
, kCFStringEncodingUTF8
)) {
727 MacOSError::throwMe(errSecParam
);
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
);
738 MacOSError::throwMe(errSecParam
);
745 attributes
[i
].tag
= kSecKeyApplicationTag
;
746 attributes
[i
].data
= (void*) CFDataGetBytePtr(tag
);
747 attributes
[i
].length
= (UInt32
)CFDataGetLength(tag
);
751 attrList
.count
= numToModify
;
752 attrList
.attr
= attributes
;
754 return SecKeychainItemModifyAttributesAndData((SecKeychainItemRef
) keyRef
, &attrList
, 0, NULL
);
760 /* Generate a private/public keypair. */
763 CFDictionaryRef parameters
,
764 SecKeyRef
*publicKey
,
765 SecKeyRef
*privateKey
)
769 Required(parameters
);
771 Required(privateKey
);
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
;
786 OSStatus result
= MakeKeyGenParametersFromDictionary(parameters
, algorithms
, keySizeInBits
, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
,
787 publicKeyAttributeTagRef
, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
,
790 if (result
!= errSecSuccess
)
795 // verify keychain parameter
797 if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
))
799 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
))
802 // do the key generation
803 result
= SecKeyCreatePair(keychain
, algorithms
, keySizeInBits
, 0, publicKeyUse
, publicKeyAttr
, privateKeyUse
, privateKeyAttr
, initialAccess
, publicKey
, privateKey
);
804 if (result
!= errSecSuccess
)
809 // set the label and print attributes on the keys
810 SetKeyLabelAndTag(*publicKey
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
811 SetKeyLabelAndTag(*privateKey
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
822 const uint8_t *dataToSign
,
823 size_t dataToSignLen
,
830 SecPointer
<KeyItem
> keyItem(KeyItem::required(key
));
833 dataInput
.Data
= (uint8_t*) dataToSign
;
834 dataInput
.Length
= dataToSignLen
;
838 output
.Length
= *sigLen
;
840 const AccessCredentials
* credentials
= keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN
, kSecCredentialTypeDefault
);
842 keyItem
->RawSign(padding
, dataInput
, credentials
, output
);
843 *sigLen
= output
.Length
;
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 */
856 return SecKeyRawVerify(key
,padding
,signedData
,signedDataLen
,sig
,sigLen
);
864 const uint8_t *signedData
,
865 size_t signedDataLen
,
873 SecPointer
<KeyItem
> keyItem(KeyItem::required(key
));
876 dataInput
.Data
= (uint8_t*) signedData
;
877 dataInput
.Length
= signedDataLen
;
880 signature
.Data
= (uint8_t*) sig
;
881 signature
.Length
= sigLen
;
883 const AccessCredentials
* credentials
= keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ANY
, kSecCredentialTypeDefault
);
885 keyItem
->RawVerify(padding
, dataInput
, credentials
, signature
);
895 const uint8_t *plainText
,
898 size_t *cipherTextLen
)
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
;
909 const AccessCredentials
* credentials
= keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT
, kSecCredentialTypeDefault
);
911 keyItem
->Encrypt(padding
, inData
, credentials
, outData
);
912 *cipherTextLen
= outData
.Length
;
920 SecKeyRef key
, /* Private key */
921 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
922 const uint8_t *cipherText
,
923 size_t cipherTextLen
, /* length of cipherText */
925 size_t *plainTextLen
) /* IN/OUT */
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
;
936 const AccessCredentials
* credentials
= keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT
, kSecCredentialTypeDefault
);
938 keyItem
->Decrypt(padding
, inData
, credentials
, outData
);
939 *plainTextLen
= outData
.Length
;
946 SecKeyGetBlockSize(SecKeyRef key
)
948 size_t blockSize
= 0;
949 OSStatus __secapiresult
;
951 CSSM_KEY cssmKey
= KeyItem::required(key
)->key();
952 switch(cssmKey
.KeyHeader
.AlgorithmId
)
956 blockSize
= cssmKey
.KeyHeader
.LogicalKeySizeInBits
/ 8;
958 case CSSM_ALGID_ECDSA
:
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
;
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
;
974 blockSize
= pointLen
;
978 blockSize
= 16; /* all AES keys use 128-bit blocks */
981 case CSSM_ALGID_3DES_3KEY
:
982 blockSize
= 8; /* all DES keys use 64-bit blocks */
985 assert(0); /* some other key algorithm */
986 blockSize
= 16; /* FIXME: revisit this */
989 __secapiresult
=errSecSuccess
;
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
; }
1004 utilGetStringFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, CFTypeRef defaultValue
)
1006 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1007 if (value
!= NULL
) return value
;
1008 return defaultValue
;
1012 utilGetNumberFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t defaultValue
)
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
;
1021 return defaultValue
;
1025 utilGetMaskValFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t maskValue
)
1027 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1028 if (value
!= NULL
) {
1029 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1030 if(CFBooleanGetValue(bRef
)) return maskValue
;
1036 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters
, CSSM_ALGORITHMS
*algorithm
, uint32
*keySizeInBits
, CSSM_KEYUSE
*keyUsage
, CSSM_KEYCLASS
*keyClass
)
1038 CFTypeRef algorithmDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeAES
);
1039 CFTypeRef keyClassDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
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
;
1079 *algorithm
= CSSM_ALGID_AES
;
1080 *keySizeInBits
= 128;
1081 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
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
;
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
);
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
);
1104 if(*keyUsage
== 0) {
1105 switch (*keyClass
) {
1106 case CSSM_KEYCLASS_PRIVATE_KEY
:
1107 *keyUsage
= CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
;
1109 case CSSM_KEYCLASS_PUBLIC_KEY
:
1110 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
;
1113 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
;
1120 utilCopyDefaultKeyLabel(void)
1122 // generate a default label from the current date
1123 CFDateRef dateNow
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent());
1124 CFStringRef defaultLabel
= CFCopyDescription(dateNow
);
1127 return defaultLabel
;
1131 SecKeyGenerateSymmetric(CFDictionaryRef parameters
, CFErrorRef
*error
)
1133 OSStatus result
= errSecParam
; // default result for an early exit
1134 SecKeyRef key
= NULL
;
1135 SecKeychainRef keychain
= NULL
;
1136 SecAccessRef access
;
1138 CFStringRef appLabel
;
1140 CFStringRef dateLabel
= NULL
;
1142 CSSM_ALGORITHMS algorithm
;
1143 uint32 keySizeInBits
;
1144 CSSM_KEYUSE keyUsage
;
1145 uint32 keyAttr
= CSSM_KEYATTR_RETURN_DEFAULT
;
1146 CSSM_KEYCLASS keyClass
;
1148 Boolean isPermanent
;
1149 Boolean isExtractable
;
1151 // verify keychain parameter
1152 if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
))
1154 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1161 // verify permanent parameter
1162 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsPermanent
, (const void **)&value
))
1163 isPermanent
= false;
1164 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1167 isPermanent
= CFEqual(kCFBooleanTrue
, value
);
1169 if (keychain
== NULL
) {
1170 // no keychain was specified, so use the default keychain
1171 result
= SecKeychainCopyDefault(&keychain
);
1173 keyAttr
|= CSSM_KEYATTR_PERMANENT
;
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
)))
1182 isExtractable
= CFEqual(kCFBooleanTrue
, value
);
1184 keyAttr
|= CSSM_KEYATTR_EXTRACTABLE
;
1186 // verify access parameter
1187 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&access
))
1189 else if (SecAccessGetTypeID() != CFGetTypeID(access
))
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
))
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
))
1204 // verify application tag parameter
1205 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationTag
, (const void **)&appTag
))
1207 else if (CFStringGetTypeID() != CFGetTypeID(appTag
))
1210 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1213 // the generated key will not be stored in any keychain
1214 result
= SecKeyGenerate(keychain
, algorithm
, keySizeInBits
, 0, keyUsage
, keyAttr
, access
, &key
);
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
);
1225 if (label
&& !CFStringGetCString(label
, labelBuf
, labelBufLen
-1, kCFStringEncodingUTF8
))
1227 if (appLabel
&& !CFStringGetCString(appLabel
, appLabelBuf
, appLabelBufLen
-1, kCFStringEncodingUTF8
))
1229 if (appTag
&& !CFStringGetCString(appTag
, appTagBuf
, appTagBufLen
-1, kCFStringEncodingUTF8
))
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
;
1239 result
= SecKeyGenerateWithAttributes(&attributes
,
1240 keychain
, algorithm
, keySizeInBits
, 0,
1241 keyUsage
, keyAttr
, access
, &key
);
1249 if (result
&& error
) {
1250 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, result
, NULL
);
1253 CFRelease(dateLabel
);
1255 CFRelease(keychain
);
1263 SecKeyCreateFromData(CFDictionaryRef parameters
, CFDataRef keyData
, CFErrorRef
*error
)
1265 CSSM_ALGORITHMS algorithm
;
1266 uint32 keySizeInBits
;
1267 CSSM_KEYUSE keyUsage
;
1268 CSSM_KEYCLASS keyClass
;
1271 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1273 CSSM_CSP_HANDLE cspHandle
= cuCspStartup(CSSM_FALSE
); // TRUE => CSP, FALSE => CSPDL
1275 SecKeyImportExportParameters iparam
;
1276 memset(&iparam
, 0, sizeof(iparam
));
1277 iparam
.keyUsage
= keyUsage
;
1279 SecExternalItemType itype
;
1281 case CSSM_KEYCLASS_PRIVATE_KEY
:
1282 itype
= kSecItemTypePrivateKey
;
1284 case CSSM_KEYCLASS_PUBLIC_KEY
:
1285 itype
= kSecItemTypePublicKey
;
1287 case CSSM_KEYCLASS_SESSION_KEY
:
1288 itype
= kSecItemTypeSessionKey
;
1291 itype
= kSecItemTypeUnknown
;
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);
1305 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, crtn
? crtn
: CSSM_ERRCODE_INTERNAL_ERROR
, NULL
);
1313 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable
, dispatch_queue_t deliveryQueue
,
1314 SecKeyGeneratePairBlock result
)
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
);
1326 result(publicKey
, privateKey
, error
);
1331 CFRelease(publicKey
);
1334 CFRelease(privateKey
);
1336 CFRelease(parameters
);
1342 SecKeyDeriveFromPassword(CFStringRef password
, CFDictionaryRef parameters
, CFErrorRef
*error
)
1344 char *thePassword
= NULL
;
1345 CFIndex passwordLen
;
1346 uint8_t *salt
= NULL
;
1348 CCPBKDFAlgorithm algorithm
;
1350 uint8_t *derivedKey
= NULL
;
1351 size_t derivedKeyLen
;
1352 CFDataRef saltDictValue
, algorithmDictValue
;
1354 /* Pick Values from parameters */
1356 if((saltDictValue
= (CFDataRef
) CFDictionaryGetValue(parameters
, kSecAttrSalt
)) == NULL
) {
1357 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecMissingAlgorithmParms
, NULL
);
1361 derivedKeyLen
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, 128);
1362 // This value come in bits but the rest of the code treats it as bytes
1365 algorithmDictValue
= (CFDataRef
) utilGetStringFromCFDict(parameters
, kSecAttrPRF
, kSecAttrPRFHmacAlgSHA256
);
1367 rounds
= utilGetNumberFromCFDict(parameters
, kSecAttrRounds
, 0);
1369 /* Convert any remaining parameters and get the password bytes */
1371 saltLen
= CFDataGetLength(saltDictValue
);
1372 if((salt
= (uint8_t *) malloc(saltLen
)) == NULL
) {
1373 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
1377 CFDataGetBytes(saltDictValue
, CFRangeMake(0, saltLen
), (UInt8
*) salt
);
1379 passwordLen
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1;
1380 if((thePassword
= (char *) malloc(passwordLen
)) == NULL
) {
1382 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
1385 CFStringGetBytes(password
, CFRangeMake(0, CFStringGetLength(password
)), kCFStringEncodingUTF8
, '?', FALSE
, (UInt8
*)thePassword
, passwordLen
, &passwordLen
);
1387 if((derivedKey
= (uint8_t *) malloc(derivedKeyLen
)) == NULL
) {
1389 bzero(thePassword
, strlen(thePassword
));
1391 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
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
;
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
;
1414 rounds
= 33333; // we need to pass back a consistent value since there's no way to record the round count.
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
);
1425 bzero(thePassword
, strlen(thePassword
));
1428 CFDataRef keyData
= CFDataCreate(NULL
, derivedKey
, derivedKeyLen
);
1429 bzero(derivedKey
, derivedKeyLen
);
1432 SecKeyRef retval
= SecKeyCreateFromData(parameters
, keyData
, error
);
1438 SecKeyWrapSymmetric(SecKeyRef keyToWrap
, SecKeyRef wrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
1440 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);
1445 SecKeyUnwrapSymmetric(CFDataRef
*keyToUnwrap
, SecKeyRef unwrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
1447 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);
1452 /* iOS SecKey shim functions */
1454 #define MAX_DIGEST_LEN (CC_SHA512_DIGEST_LENGTH)
1456 /* Currently length of SHA512 oid + 1 */
1457 #define MAX_OID_LEN (10)
1459 #define DER_MAX_DIGEST_INFO_LEN (10 + MAX_DIGEST_LEN + MAX_OID_LEN)
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.
1467 0x06, oid.Len, oid.Data,
1472 static size_t DEREncodeDigestInfoPrefix(const SecAsn1Oid
*oid
,
1473 size_t digestLength
,
1474 uint8_t *digestInfo
,
1475 size_t digestInfoLength
)
1477 size_t algIdLen
= oid
->Length
+ 4;
1478 size_t topLen
= algIdLen
+ digestLength
+ 4;
1479 size_t totalLen
= topLen
+ 2;
1481 if (totalLen
> digestInfoLength
) {
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
);
1494 digestInfo
[ix
++] = SEC_ASN1_NULL
;
1495 digestInfo
[ix
++] = 0;
1496 digestInfo
[ix
++] = SEC_ASN1_OCTET_STRING
;
1497 digestInfo
[ix
++] = digestLength
;
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 */)
1506 unsigned char *(*digestFcn
)(const void *, CC_LONG
, unsigned char *);
1507 CFIndex keyAlgID
= kSecNullAlgorithmID
;
1508 const SecAsn1Oid
*digestOid
;
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]) {
1519 case 2: /* oidMD2WithRSA */
1521 digestLen
= CC_MD2_DIGEST_LENGTH
;
1522 digestOid
= &CSSMOID_MD2
;
1524 case 3: /* oidMD4WithRSA */
1526 digestLen
= CC_MD4_DIGEST_LENGTH
;
1527 digestOid
= &CSSMOID_MD4
;
1529 case 4: /* oidMD5WithRSA */
1531 digestLen
= CC_MD5_DIGEST_LENGTH
;
1532 digestOid
= &CSSMOID_MD5
;
1535 case 5: /* oidSHA1WithRSA */
1536 digestFcn
= CC_SHA1
;
1537 digestLen
= CC_SHA1_DIGEST_LENGTH
;
1538 digestOid
= &CSSMOID_SHA1
;
1540 case 11: /* oidSHA256WithRSA */
1541 digestFcn
= CC_SHA256
;
1542 digestLen
= CC_SHA256_DIGEST_LENGTH
;
1543 digestOid
= &CSSMOID_SHA256
;
1545 case 12: /* oidSHA384WithRSA */
1547 digestFcn
= CC_SHA384
;
1548 digestLen
= CC_SHA384_DIGEST_LENGTH
;
1549 digestOid
= &CSSMOID_SHA384
;
1551 case 13: /* oidSHA512WithRSA */
1552 digestFcn
= CC_SHA512
;
1553 digestLen
= CC_SHA512_DIGEST_LENGTH
;
1554 digestOid
= &CSSMOID_SHA512
;
1556 case 14: /* oidSHA224WithRSA */
1557 digestFcn
= CC_SHA224
;
1558 digestLen
= CC_SHA224_DIGEST_LENGTH
;
1559 digestOid
= &CSSMOID_SHA224
;
1562 secdebug("key", "unsupported rsa signature algorithm");
1563 return errSecUnsupportedAlgorithm
;
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
;
1574 case 2: /* oidSHA256WithECDSA */
1575 digestFcn
= CC_SHA256
;
1576 digestLen
= CC_SHA256_DIGEST_LENGTH
;
1578 case 3: /* oidSHA384WithECDSA */
1580 digestFcn
= CC_SHA384
;
1581 digestLen
= CC_SHA384_DIGEST_LENGTH
;
1583 case 4: /* oidSHA512WithECDSA */
1584 digestFcn
= CC_SHA512
;
1585 digestLen
= CC_SHA512_DIGEST_LENGTH
;
1588 secdebug("key", "unsupported ecdsa signature algorithm");
1589 return errSecUnsupportedAlgorithm
;
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))
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
;
1608 case 1: /* OID_SHA256 */
1609 digestFcn
= CC_SHA256
;
1610 digestLen
= CC_SHA256_DIGEST_LENGTH
;
1611 digestOid
= &CSSMOID_SHA256
;
1613 case 2: /* OID_SHA384 */
1615 digestFcn
= CC_SHA384
;
1616 digestLen
= CC_SHA384_DIGEST_LENGTH
;
1617 digestOid
= &CSSMOID_SHA384
;
1619 case 3: /* OID_SHA512 */
1620 digestFcn
= CC_SHA512
;
1621 digestLen
= CC_SHA512_DIGEST_LENGTH
;
1622 digestOid
= &CSSMOID_SHA512
;
1625 secdebug("key", "unsupported sha-2 signature algorithm");
1626 return errSecUnsupportedAlgorithm
;
1628 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_MD5
)) {
1630 digestLen
= CC_MD5_DIGEST_LENGTH
;
1631 digestOid
= &CSSMOID_MD5
;
1633 secdebug("key", "unsupported digesting algorithm");
1634 return errSecUnsupportedAlgorithm
;
1637 /* check key is appropriate for signature (superfluous for digest only oid) */
1639 CFIndex supportedKeyAlgID
= kSecNullAlgorithmID
;
1640 #if TARGET_OS_EMBEDDED
1641 supportedKeyAlgID
= SecKeyGetAlgorithmID(key
);
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
;
1653 if (keyAlgID
== kSecNullAlgorithmID
) {
1654 keyAlgID
= supportedKeyAlgID
;
1656 else if (keyAlgID
!= supportedKeyAlgID
) {
1657 return errSecUnsupportedAlgorithm
;
1662 case kSecRSAAlgorithmID
:
1663 offset
= DEREncodeDigestInfoPrefix(digestOid
, digestLen
,
1664 digestInfo
, *digestInfoLen
);
1666 return errSecBufferTooSmall
;
1668 case kSecDSAAlgorithmID
:
1669 if (digestOid
!= &CSSMOID_SHA1
)
1670 return errSecUnsupportedAlgorithm
;
1672 case kSecECDSAAlgorithmID
:
1675 secdebug("key", "unsupported signature algorithm");
1676 return errSecUnsupportedAlgorithm
;
1680 if(dataLen
>UINT32_MAX
) /* Check for overflow with CC_LONG cast */
1682 digestFcn(data
, (CC_LONG
)dataLen
, &digestInfo
[offset
]);
1683 *digestInfoLen
= offset
+ digestLen
;
1685 if (dataLen
!= digestLen
)
1687 memcpy(&digestInfo
[offset
], data
, dataLen
);
1688 *digestInfoLen
= offset
+ dataLen
;
1691 return errSecSuccess
;
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 */
1702 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
1703 uint8_t digestInfo
[digestInfoLength
];
1706 status
= SecKeyGetDigestInfo(key
, algId
, digestData
, digestDataLen
, false /* data is digest */,
1707 digestInfo
, &digestInfoLength
);
1710 return SecKeyRawVerify(key
, kSecPaddingPKCS1
,
1711 digestInfo
, digestInfoLength
, sig
, sigLen
);
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 */
1722 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
1723 uint8_t digestInfo
[digestInfoLength
];
1726 status
= SecKeyGetDigestInfo(key
, algId
, digestData
, digestDataLen
, false,
1727 digestInfo
, &digestInfoLength
);
1730 return SecKeyRawSign(key
, kSecPaddingPKCS1
,
1731 digestInfo
, digestInfoLength
, sig
, sigLen
);
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
)
1739 SecPointer
<KeyItem
> keyItem(KeyItem::required(key
));
1740 switch (keyItem
->key().header().LogicalKeySizeInBits
) {
1743 return kSecECCurveSecp192r1
;
1745 return kSecECCurveSecp224r1
;
1748 return kSecECCurveSecp256r1
;
1750 return kSecECCurveSecp384r1
;
1752 return kSecECCurveSecp521r1
;
1756 return kSecECCurveNone
;
1759 static inline CFDataRef
_CFDataCreateReferenceFromRange(CFAllocatorRef allocator
, CFDataRef sourceData
, CFRange range
)
1761 return CFDataCreateWithBytesNoCopy(allocator
,
1762 CFDataGetBytePtr(sourceData
) + range
.location
, range
.length
,
1766 static inline CFDataRef
_CFDataCreateCopyFromRange(CFAllocatorRef allocator
, CFDataRef sourceData
, CFRange range
)
1768 return CFDataCreate(allocator
, CFDataGetBytePtr(sourceData
) + range
.location
, range
.length
);
1771 static inline bool _CFDataEquals(CFDataRef left
, CFDataRef right
)
1773 return (left
!= NULL
) &&
1775 (CFDataGetLength(left
) == CFDataGetLength(right
)) &&
1776 (0 == memcmp(CFDataGetBytePtr(left
), CFDataGetBytePtr(right
), (size_t)CFDataGetLength(left
)));
1780 void secdump(const unsigned char *data
, unsigned long len
)
1789 sprintf(t
, "%04lx :", i
);
1792 sprintf(t
, " %02x", data
[i
]);
1796 syslog(LOG_NOTICE
, s
);
1801 syslog(LOG_NOTICE
, s
);
1805 OSStatus
SecKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
* publicBytes
)
1808 #if TARGET_OS_EMBEDDED
1809 keyAlgId
= SecKeyGetAlgorithmID(key
);
1811 keyAlgId
= SecKeyGetAlgorithmId(key
);
1814 OSStatus ecStatus
= errSecParam
;
1815 CFDataRef tempPublicData
= NULL
;
1816 CFDataRef headerlessPublicData
= NULL
;
1817 CFIndex headerLength
= 0;
1818 const UInt8
* pData_Ptr
= NULL
;
1820 if (kSecRSAAlgorithmID
== keyAlgId
)
1822 return SecItemExport(key
, kSecFormatBSAFE
, 0, NULL
, publicBytes
);
1825 if (kSecECDSAAlgorithmID
== keyAlgId
)
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
)
1831 secdebug("key", "SecKeyCopyPublicBytes: SecItemExport error (%d) for ECDSA public key %p",
1832 ecStatus
, (uintptr_t)key
);
1838 // Get a pointer to the first byte of the exported data
1839 pData_Ptr
= CFDataGetBytePtr(tempPublicData
);
1841 // the first byte should be a sequence 0x30
1842 if (*pData_Ptr
!= 0x30)
1844 secdebug("key", "SecKeyCopyPublicBytes: exported data is invalid");
1845 if (NULL
!= tempPublicData
)
1846 CFRelease(tempPublicData
);
1848 ecStatus
= errSecParam
;
1852 // move past the sequence byte
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;
1864 // The current byte should be a sequence 0x30
1865 if (*pData_Ptr
!= 0x30)
1867 secdebug("key", "SecKeyCopyPublicBytes: Could not find the key sequence");
1868 if (NULL
!= tempPublicData
)
1869 CFRelease(tempPublicData
);
1871 ecStatus
= errSecParam
;
1876 // The next bytes will always be the same
1881 // ECDSA public KEY OID value 0x2a,0x86,0x48,0xce,0x3d,0x02,0x01
1883 // This is a total of 12 bytes
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);
1890 // Should be at a BINARY String which is specifed by a 0x3
1891 if (*pData_Ptr
!= 0x03)
1893 secdebug("key", "SecKeyCopyPublicBytes: Invalid key structure");
1894 if (NULL
!= tempPublicData
)
1895 CFRelease(tempPublicData
);
1897 ecStatus
= errSecParam
;
1902 // Move past the BINARY String specifier 0x03
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;
1915 // Move past the beginning marker for the BINARY String 0x00
1918 // pData_Ptr now points to the first bytes of the key material
1919 headerLength
= (CFIndex
)(((intptr_t)pData_Ptr
) - ((intptr_t)CFDataGetBytePtr(tempPublicData
)));
1921 headerlessPublicData
= _CFDataCreateCopyFromRange(kCFAllocatorDefault
,
1922 tempPublicData
, CFRangeMake(headerLength
, CFDataGetLength(tempPublicData
) - headerLength
));
1924 if (!headerlessPublicData
)
1926 printf("SecKeyCopyPublicBytes: headerlessPublicData is nil (1)\n");
1927 if (NULL
!= tempPublicData
)
1928 CFRelease(tempPublicData
);
1930 ecStatus
= errSecParam
;
1937 *publicBytes
= headerlessPublicData
;
1940 ecStatus
= errSecSuccess
;
1942 if (NULL
!= tempPublicData
)
1943 CFRelease(tempPublicData
);
1952 CFDataRef
SecECKeyCopyPublicBits(SecKeyRef key
)
1954 CFDataRef exportedKey
;
1955 if(SecKeyCopyPublicBytes(key
, &exportedKey
) != errSecSuccess
) {
1961 SecKeyRef
SecKeyCreateFromPublicData(CFAllocatorRef allocator
, CFIndex algorithmID
, CFDataRef publicBytes
)
1963 SecExternalFormat externalFormat
= kSecFormatOpenSSL
;
1964 SecExternalItemType externalItemType
= kSecItemTypePublicKey
;
1965 CFDataRef workingData
= NULL
;
1966 CFArrayRef outArray
= NULL
;
1967 SecKeyRef retVal
= NULL
;
1969 if (kSecRSAAlgorithmID
== algorithmID
) {
1971 * kSecFormatBSAFE uses the original PKCS#1 definition:
1972 * RSAPublicKey ::= SEQUENCE {
1973 * modulus INTEGER, -- n
1974 * publicExponent INTEGER -- e
1976 * kSecFormatOpenSSL uses different ASN.1 encoding.
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,
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
;
1993 if(SecItemImport(workingData
, NULL
, &externalFormat
, &externalItemType
, 0, NULL
, NULL
, &outArray
) != errSecSuccess
) {
1996 if(!outArray
|| CFArrayGetCount(outArray
) == 0) {
1999 retVal
= (SecKeyRef
)CFArrayGetValueAtIndex(outArray
, 0);
2003 if(workingData
) CFRelease(workingData
);
2004 if(outArray
) CFRelease(outArray
);
2008 SecKeyRef
SecKeyCreateRSAPublicKey(CFAllocatorRef allocator
,
2009 const uint8_t *keyData
, CFIndex keyDataLength
,
2010 SecKeyEncoding encoding
)
2012 CFDataRef pubKeyData
= NULL
;
2013 if(kSecKeyEncodingPkcs1
== encoding
) {
2014 /* DER-encoded according to PKCS1. */
2015 pubKeyData
= CFDataCreate(allocator
, keyData
, keyDataLength
);
2017 } else if(kSecKeyEncodingApplePkcs1
== encoding
) {
2018 /* DER-encoded according to PKCS1 with Apple Extensions. */
2019 /* FIXME: need to actually handle extensions */
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
;
2033 CFMutableDataRef pkcs1
= CFDataCreateMutable(allocator
, result_size
);
2034 if (pkcs1
== NULL
) {
2037 CFDataSetLength(pkcs1
, result_size
);
2038 uint8_t *bytes
= CFDataGetMutableBytePtr(pkcs1
);
2040 *bytes
++ = ASN1_CONSTR_SEQUENCE
;
2043 drtn
= DEREncodeLength(seq_size
, bytes
, &r_size
);
2044 if (r_size
<= remaining_size
) {
2046 remaining_size
-= r_size
;
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
) {
2052 remaining_size
-= r_size
;
2054 r_size
= remaining_size
;
2055 drtn
= DEREncodeItem(ASN1_INTEGER
, e_size
, (const DERByte
*)params
->exponent
, (DERByte
*)bytes
, &r_size
);
2060 /* unsupported encoding */
2063 SecKeyRef publicKey
= SecKeyCreateFromPublicData(allocator
, kSecRSAAlgorithmID
, pubKeyData
);
2064 CFRelease(pubKeyData
);
2068 #if !TARGET_OS_EMBEDDED
2070 // Given a CSSM public key, copy its modulus and/or exponent data.
2071 // Caller is responsible for releasing the returned CFDataRefs.
2074 OSStatus
_SecKeyCopyRSAPublicModulusAndExponent(SecKeyRef key
, CFDataRef
*modulus
, CFDataRef
*exponent
)
2076 const CSSM_KEY
*pubKey
;
2077 const CSSM_KEYHEADER
*hdr
;
2078 CSSM_DATA pubKeyBlob
;
2081 result
= SecKeyGetCSSMKey(key
, &pubKey
);
2082 if(result
!= errSecSuccess
) {
2085 hdr
= &pubKey
->KeyHeader
;
2086 if(hdr
->KeyClass
!= CSSM_KEYCLASS_PUBLIC_KEY
) {
2087 return errSSLInternal
;
2089 if(hdr
->AlgorithmId
!= CSSM_ALGID_RSA
) {
2090 return errSSLInternal
;
2092 switch(hdr
->BlobType
) {
2093 case CSSM_KEYBLOB_RAW
:
2094 pubKeyBlob
.Length
= pubKey
->KeyData
.Length
;
2095 pubKeyBlob
.Data
= pubKey
->KeyData
.Data
;
2097 case CSSM_KEYBLOB_REFERENCE
:
2098 // FIXME: currently SSL only uses raw public keys, obtained from the CL
2100 return errSSLInternal
;
2102 assert(hdr
->BlobType
== CSSM_KEYBLOB_RAW
);
2103 // at this point we should have a PKCS1-encoded blob
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
;
2113 *modulus
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.modulus
.data
, decodedKey
.modulus
.length
);
2114 if(*modulus
== NULL
) {
2115 return errSecDecode
;
2119 *exponent
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.pubExponent
.data
, decodedKey
.pubExponent
.length
);
2120 if(*exponent
== NULL
) {
2121 return errSecDecode
;
2125 return errSecSuccess
;
2127 #endif /* !TARGET_OS_EMBEDDED */
2129 CFDataRef
SecKeyCopyModulus(SecKeyRef key
)
2131 #if TARGET_OS_EMBEDDED
2132 ccrsa_pub_ctx_t pubkey
;
2133 pubkey
.pub
= key
->key
;
2135 size_t m_size
= ccn_write_uint_size(ccrsa_ctx_n(pubkey
), ccrsa_ctx_m(pubkey
));
2137 CFAllocatorRef allocator
= CFGetAllocator(key
);
2138 CFMutableDataRef modulusData
= CFDataCreateMutable(allocator
, m_size
);
2140 if (modulusData
== NULL
)
2143 CFDataSetLength(modulusData
, m_size
);
2145 ccn_write_uint(ccrsa_ctx_n(pubkey
), ccrsa_ctx_m(pubkey
), m_size
, CFDataGetMutableBytePtr(modulusData
));
2147 CFDataRef modulusData
;
2148 OSStatus status
= _SecKeyCopyRSAPublicModulusAndExponent(key
, &modulusData
, NULL
);
2149 if(status
!= errSecSuccess
) {
2157 CFDataRef
SecKeyCopyExponent(SecKeyRef key
)
2159 #if TARGET_OS_EMBEDDED
2160 ccrsa_pub_ctx_t pubkey
;
2161 pubkey
.pub
= key
->key
;
2163 size_t e_size
= ccn_write_uint_size(ccrsa_ctx_n(pubkey
), ccrsa_ctx_e(pubkey
));
2165 CFAllocatorRef allocator
= CFGetAllocator(key
);
2166 CFMutableDataRef exponentData
= CFDataCreateMutable(allocator
, e_size
);
2168 if (exponentData
== NULL
)
2171 CFDataSetLength(exponentData
, e_size
);
2173 ccn_write_uint(ccrsa_ctx_n(pubkey
), ccrsa_ctx_m(pubkey
), e_size
, CFDataGetMutableBytePtr(exponentData
));
2175 CFDataRef exponentData
;
2176 OSStatus status
= _SecKeyCopyRSAPublicModulusAndExponent(key
, NULL
, &exponentData
);
2177 if(status
!= errSecSuccess
) {
2178 exponentData
= NULL
;
2182 return exponentData
;
2185 SecKeyRef
SecKeyCreatePublicFromPrivate(SecKeyRef privateKey
) {
2186 OSStatus status
= errSecParam
;
2188 CFDataRef serializedPublic
= NULL
;
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
;
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
);
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
);
2216 CFTypeRef foundKey
= NULL
;
2217 status
= SecItemCopyMatching(query2
, &foundKey
);
2218 if (status
== errSecSuccess
) {
2219 if (CFGetTypeID(foundKey
) == SecKeyGetTypeID()) {
2222 CFRelease(foundItem
);
2223 return (SecKeyRef
)foundKey
;
2225 status
= errSecItemNotFound
;
2231 status
= errSecItemNotFound
;
2233 CFRelease(foundItem
);