2 * Copyright (c) 2002-2014 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 if(cssmKey
->KeyData
.Length
== 0){
331 MacOSError::throwMe(errSecInvalidAttributeKeyLength
);
333 if(cssmKey
->KeyData
.Data
== NULL
){
334 MacOSError::throwMe(errSecInvalidPointer
);
336 CssmClient::CSP
csp(cssmKey
->KeyHeader
.CspId
);
337 CssmClient::Key
key(csp
, *cssmKey
);
338 KeyItem
*item
= new KeyItem(key
);
340 // Return the generated key.
342 *keyRef
= item
->handle();
349 static u_int32_t
ConvertCFStringToInteger(CFStringRef ref
)
356 // figure out the size of the string
357 CFIndex numChars
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref
), kCFStringEncodingUTF8
);
358 char buffer
[numChars
];
359 if (!CFStringGetCString(ref
, buffer
, numChars
, kCFStringEncodingUTF8
))
361 MacOSError::throwMe(errSecParam
);
369 static OSStatus
CheckAlgorithmType(CFDictionaryRef parameters
, CSSM_ALGORITHMS
&algorithms
)
371 // figure out the algorithm to use
372 CFStringRef ktype
= (CFStringRef
) CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
378 if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
379 algorithms
= CSSM_ALGID_RSA
;
380 return errSecSuccess
;
381 } else if(CFEqual(ktype
, kSecAttrKeyTypeECDSA
) ||
382 CFEqual(ktype
, kSecAttrKeyTypeEC
)) {
383 algorithms
= CSSM_ALGID_ECDSA
;
384 return errSecSuccess
;
385 } else if(CFEqual(ktype
, kSecAttrKeyTypeAES
)) {
386 algorithms
= CSSM_ALGID_AES
;
387 return errSecSuccess
;
388 } else if(CFEqual(ktype
, kSecAttrKeyType3DES
)) {
389 algorithms
= CSSM_ALGID_3DES
;
390 return errSecSuccess
;
392 return errSecUnsupportedAlgorithm
;
398 static OSStatus
GetKeySize(CFDictionaryRef parameters
, CSSM_ALGORITHMS algorithms
, uint32
&keySizeInBits
)
401 // get the key size and check it for validity
402 CFTypeRef ref
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
404 keySizeInBits
= kSecDefaultKeySize
;
406 CFTypeID bitSizeType
= CFGetTypeID(ref
);
407 if (bitSizeType
== CFStringGetTypeID())
408 keySizeInBits
= ConvertCFStringToInteger((CFStringRef
) ref
);
409 else if (bitSizeType
== CFNumberGetTypeID())
410 CFNumberGetValue((CFNumberRef
) ref
, kCFNumberSInt32Type
, &keySizeInBits
);
411 else return errSecParam
;
414 switch (algorithms
) {
415 case CSSM_ALGID_ECDSA
:
416 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecp256r1
;
417 if(keySizeInBits
== kSecp192r1
|| keySizeInBits
== kSecp256r1
|| keySizeInBits
== kSecp384r1
|| keySizeInBits
== kSecp521r1
) return errSecSuccess
;
420 if(keySizeInBits
% 8) return errSecParam
;
421 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= 2048;
422 if(keySizeInBits
>= kSecRSAMin
&& keySizeInBits
<= kSecRSAMax
) return errSecSuccess
;
425 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecAES128
;
426 if(keySizeInBits
== kSecAES128
|| keySizeInBits
== kSecAES192
|| keySizeInBits
== kSecAES256
) return errSecSuccess
;
428 case CSSM_ALGID_3DES
:
429 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSec3DES192
;
430 if(keySizeInBits
== kSec3DES192
) return errSecSuccess
;
449 struct ParameterAttribute
451 const CFTypeRef
*name
;
457 static ParameterAttribute gAttributes
[] =
464 &kSecAttrIsPermanent
,
468 &kSecAttrApplicationTag
,
472 &kSecAttrEffectiveKeySize
,
501 const int kNumberOfAttributes
= sizeof(gAttributes
) / sizeof(ParameterAttribute
);
503 static OSStatus
ScanDictionaryForParameters(CFDictionaryRef parameters
, void* attributePointers
[])
506 for (i
= 0; i
< kNumberOfAttributes
; ++i
)
508 // see if the corresponding tag exists in the dictionary
509 CFTypeRef value
= CFDictionaryGetValue(parameters
, *(gAttributes
[i
].name
));
512 switch (gAttributes
[i
].type
)
515 // just return the value
516 *(CFTypeRef
*) attributePointers
[i
] = value
;
521 CFBooleanRef bRef
= (CFBooleanRef
) value
;
522 *(bool*) attributePointers
[i
] = CFBooleanGetValue(bRef
);
528 CFNumberRef nRef
= (CFNumberRef
) value
;
529 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, attributePointers
[i
]);
536 return errSecSuccess
;
541 static OSStatus
GetKeyParameters(CFDictionaryRef parameters
, int keySize
, bool isPublic
, CSSM_KEYUSE
&keyUse
, uint32
&attrs
, CFTypeRef
&labelRef
, CFDataRef
&applicationTagRef
)
543 // establish default values
545 bool isPermanent
= false;
546 applicationTagRef
= NULL
;
547 CFTypeRef effectiveKeySize
= NULL
;
548 bool canDecrypt
= isPublic
? false : true;
549 bool canEncrypt
= !canDecrypt
;
550 bool canDerive
= true;
551 bool canSign
= isPublic
? false : true;
552 bool canVerify
= !canSign
;
553 bool canUnwrap
= isPublic
? false : true;
554 attrs
= CSSM_KEYATTR_EXTRACTABLE
;
557 void* attributePointers
[] = {&labelRef
, &isPermanent
, &applicationTagRef
, &effectiveKeySize
, &canEncrypt
, &canDecrypt
,
558 &canDerive
, &canSign
, &canVerify
, &canUnwrap
};
560 // look for modifiers in the general dictionary
561 OSStatus result
= ScanDictionaryForParameters(parameters
, attributePointers
);
562 if (result
!= errSecSuccess
)
567 // see if we have anything which modifies the defaults
571 key
= kSecPublicKeyAttrs
;
575 key
= kSecPrivateKeyAttrs
;
578 CFTypeRef dType
= CFDictionaryGetValue(parameters
, key
);
581 // this had better be a dictionary
582 if (CFGetTypeID(dType
) != CFDictionaryGetTypeID())
587 // pull any additional parameters out of this dictionary
588 result
= ScanDictionaryForParameters((CFDictionaryRef
)dType
, attributePointers
);
589 if (result
!= errSecSuccess
)
595 // figure out the key usage
599 keyUse
|= CSSM_KEYUSE_DECRYPT
;
604 keyUse
|= CSSM_KEYUSE_ENCRYPT
;
609 keyUse
|= CSSM_KEYUSE_DERIVE
;
614 keyUse
|= CSSM_KEYUSE_SIGN
;
619 keyUse
|= CSSM_KEYUSE_VERIFY
;
624 keyUse
|= CSSM_KEYUSE_UNWRAP
;
627 // public key is always extractable;
628 // private key is extractable by default unless explicitly set to false
629 CFTypeRef value
= NULL
;
630 if (!isPublic
&& CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
) && value
)
632 Boolean keyIsExtractable
= CFEqual(kCFBooleanTrue
, value
);
633 if (!keyIsExtractable
)
637 attrs
|= CSSM_KEYATTR_PERMANENT
;
639 return errSecSuccess
;
644 static OSStatus
MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters
,
645 CSSM_ALGORITHMS
&algorithms
,
646 uint32
&keySizeInBits
,
647 CSSM_KEYUSE
&publicKeyUse
,
648 uint32
&publicKeyAttr
,
649 CFTypeRef
&publicKeyLabelRef
,
650 CFDataRef
&publicKeyAttributeTagRef
,
651 CSSM_KEYUSE
&privateKeyUse
,
652 uint32
&privateKeyAttr
,
653 CFTypeRef
&privateKeyLabelRef
,
654 CFDataRef
&privateKeyAttributeTagRef
,
655 SecAccessRef
&initialAccess
)
659 result
= CheckAlgorithmType(parameters
, algorithms
);
660 if (result
!= errSecSuccess
)
665 result
= GetKeySize(parameters
, algorithms
, keySizeInBits
);
666 if (result
!= errSecSuccess
)
671 result
= GetKeyParameters(parameters
, keySizeInBits
, false, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
672 if (result
!= errSecSuccess
)
677 result
= GetKeyParameters(parameters
, keySizeInBits
, true, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
678 if (result
!= errSecSuccess
)
683 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&initialAccess
))
685 initialAccess
= NULL
;
687 else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess
))
692 return errSecSuccess
;
697 static OSStatus
SetKeyLabelAndTag(SecKeyRef keyRef
, CFTypeRef label
, CFDataRef tag
)
710 if (numToModify
== 0)
712 return errSecSuccess
;
715 SecKeychainAttributeList attrList
;
716 SecKeychainAttribute attributes
[numToModify
];
722 if (CFStringGetTypeID() == CFGetTypeID(label
)) {
723 CFStringRef label_string
= static_cast<CFStringRef
>(label
);
724 attributes
[i
].tag
= kSecKeyPrintName
;
725 attributes
[i
].data
= (void*) CFStringGetCStringPtr(label_string
, kCFStringEncodingUTF8
);
726 if (NULL
== attributes
[i
].data
) {
727 CFIndex buffer_length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string
), kCFStringEncodingUTF8
);
728 attributes
[i
].data
= alloca((size_t)buffer_length
);
729 if (NULL
== attributes
[i
].data
) {
730 UnixError::throwMe(ENOMEM
);
732 if (!CFStringGetCString(label_string
, static_cast<char *>(attributes
[i
].data
), buffer_length
, kCFStringEncodingUTF8
)) {
733 MacOSError::throwMe(errSecParam
);
736 attributes
[i
].length
= (UInt32
)strlen(static_cast<char *>(attributes
[i
].data
));
737 } else if (CFDataGetTypeID() == CFGetTypeID(label
)) {
738 // 10.6 bug compatibility
739 CFDataRef label_data
= static_cast<CFDataRef
>(label
);
740 attributes
[i
].tag
= kSecKeyLabel
;
741 attributes
[i
].data
= (void*) CFDataGetBytePtr(label_data
);
742 attributes
[i
].length
= (UInt32
)CFDataGetLength(label_data
);
744 MacOSError::throwMe(errSecParam
);
751 attributes
[i
].tag
= kSecKeyApplicationTag
;
752 attributes
[i
].data
= (void*) CFDataGetBytePtr(tag
);
753 attributes
[i
].length
= (UInt32
)CFDataGetLength(tag
);
757 attrList
.count
= numToModify
;
758 attrList
.attr
= attributes
;
760 return SecKeychainItemModifyAttributesAndData((SecKeychainItemRef
) keyRef
, &attrList
, 0, NULL
);
766 /* Generate a private/public keypair. */
769 CFDictionaryRef parameters
,
770 SecKeyRef
*publicKey
,
771 SecKeyRef
*privateKey
)
775 Required(parameters
);
777 Required(privateKey
);
779 CSSM_ALGORITHMS algorithms
;
780 uint32 keySizeInBits
;
781 CSSM_KEYUSE publicKeyUse
;
782 uint32 publicKeyAttr
;
783 CFTypeRef publicKeyLabelRef
;
784 CFDataRef publicKeyAttributeTagRef
;
785 CSSM_KEYUSE privateKeyUse
;
786 uint32 privateKeyAttr
;
787 CFTypeRef privateKeyLabelRef
;
788 CFDataRef privateKeyAttributeTagRef
;
789 SecAccessRef initialAccess
;
790 SecKeychainRef keychain
;
792 OSStatus result
= MakeKeyGenParametersFromDictionary(parameters
, algorithms
, keySizeInBits
, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
,
793 publicKeyAttributeTagRef
, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
,
796 if (result
!= errSecSuccess
)
801 // verify keychain parameter
803 if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
))
805 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
))
808 // do the key generation
809 result
= SecKeyCreatePair(keychain
, algorithms
, keySizeInBits
, 0, publicKeyUse
, publicKeyAttr
, privateKeyUse
, privateKeyAttr
, initialAccess
, publicKey
, privateKey
);
810 if (result
!= errSecSuccess
)
815 // set the label and print attributes on the keys
816 SetKeyLabelAndTag(*publicKey
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
817 SetKeyLabelAndTag(*privateKey
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
828 const uint8_t *dataToSign
,
829 size_t dataToSignLen
,
836 SecPointer
<KeyItem
> keyItem(KeyItem::required(key
));
839 dataInput
.Data
= (uint8_t*) dataToSign
;
840 dataInput
.Length
= dataToSignLen
;
844 output
.Length
= *sigLen
;
846 const AccessCredentials
* credentials
= keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN
, kSecCredentialTypeDefault
);
848 keyItem
->RawSign(padding
, dataInput
, credentials
, output
);
849 *sigLen
= output
.Length
;
854 OSStatus
SecKeyRawVerifyOSX(
855 SecKeyRef key
, /* Public key */
856 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
857 const uint8_t *signedData
, /* signature over this data */
858 size_t signedDataLen
, /* length of dataToSign */
859 const uint8_t *sig
, /* signature */
862 return SecKeyRawVerify(key
,padding
,signedData
,signedDataLen
,sig
,sigLen
);
870 const uint8_t *signedData
,
871 size_t signedDataLen
,
879 SecPointer
<KeyItem
> keyItem(KeyItem::required(key
));
882 dataInput
.Data
= (uint8_t*) signedData
;
883 dataInput
.Length
= signedDataLen
;
886 signature
.Data
= (uint8_t*) sig
;
887 signature
.Length
= sigLen
;
889 const AccessCredentials
* credentials
= keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ANY
, kSecCredentialTypeDefault
);
891 keyItem
->RawVerify(padding
, dataInput
, credentials
, signature
);
901 const uint8_t *plainText
,
904 size_t *cipherTextLen
)
908 SecPointer
<KeyItem
> keyItem(KeyItem::required(key
));
909 CSSM_DATA inData
, outData
;
910 inData
.Data
= (uint8
*) plainText
;
911 inData
.Length
= plainTextLen
;
912 outData
.Data
= cipherText
;
913 outData
.Length
= *cipherTextLen
;
915 const AccessCredentials
* credentials
= keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT
, kSecCredentialTypeDefault
);
917 keyItem
->Encrypt(padding
, inData
, credentials
, outData
);
918 *cipherTextLen
= outData
.Length
;
926 SecKeyRef key
, /* Private key */
927 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
928 const uint8_t *cipherText
,
929 size_t cipherTextLen
, /* length of cipherText */
931 size_t *plainTextLen
) /* IN/OUT */
935 SecPointer
<KeyItem
> keyItem(KeyItem::required(key
));
936 CSSM_DATA inData
, outData
;
937 inData
.Data
= (uint8
*) cipherText
;
938 inData
.Length
= cipherTextLen
;
939 outData
.Data
= plainText
;
940 outData
.Length
= *plainTextLen
;
942 const AccessCredentials
* credentials
= keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT
, kSecCredentialTypeDefault
);
944 keyItem
->Decrypt(padding
, inData
, credentials
, outData
);
945 *plainTextLen
= outData
.Length
;
952 SecKeyGetBlockSize(SecKeyRef key
)
954 size_t blockSize
= 0;
955 OSStatus __secapiresult
;
957 CSSM_KEY cssmKey
= KeyItem::required(key
)->key();
958 switch(cssmKey
.KeyHeader
.AlgorithmId
)
962 blockSize
= cssmKey
.KeyHeader
.LogicalKeySizeInBits
/ 8;
964 case CSSM_ALGID_ECDSA
:
966 /* Block size is up to 9 bytes of DER encoding for sequence of 2 integers,
967 * plus both coordinates for the point used */
968 #define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8)
969 #define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1)
970 size_t coordSize
= ECDSA_MAX_COORD_SIZE_IN_BYTES(cssmKey
.KeyHeader
.LogicalKeySizeInBits
);
971 assert(coordSize
< 256); /* size must fit in a byte for DER */
972 size_t coordDERLen
= (coordSize
> 127) ? 2 : 1;
973 size_t coordLen
= 1 + coordDERLen
+ coordSize
;
975 size_t pointSize
= 2 * coordLen
;
976 assert(pointSize
< 256); /* size must fit in a byte for DER */
977 size_t pointDERLen
= (pointSize
> 127) ? 2 : 1;
978 size_t pointLen
= 1 + pointDERLen
+ pointSize
;
980 blockSize
= pointLen
;
984 blockSize
= 16; /* all AES keys use 128-bit blocks */
987 case CSSM_ALGID_3DES_3KEY
:
988 blockSize
= 8; /* all DES keys use 64-bit blocks */
991 assert(0); /* some other key algorithm */
992 blockSize
= 16; /* FIXME: revisit this */
995 __secapiresult
=errSecSuccess
;
997 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
998 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
999 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
1000 catch (...) { __secapiresult
=errSecInternalComponent
; }
1010 utilGetStringFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, CFTypeRef defaultValue
)
1012 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1013 if (value
!= NULL
) return value
;
1014 return defaultValue
;
1018 utilGetNumberFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t defaultValue
)
1020 uint32_t integerValue
;
1021 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1022 if (value
!= NULL
) {
1023 CFNumberRef nRef
= (CFNumberRef
) value
;
1024 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, &integerValue
);
1025 return integerValue
;
1027 return defaultValue
;
1031 utilGetMaskValFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t maskValue
)
1033 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1034 if (value
!= NULL
) {
1035 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1036 if(CFBooleanGetValue(bRef
)) return maskValue
;
1042 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters
, CSSM_ALGORITHMS
*algorithm
, uint32
*keySizeInBits
, CSSM_KEYUSE
*keyUsage
, CSSM_KEYCLASS
*keyClass
)
1044 CFTypeRef algorithmDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeAES
);
1045 CFTypeRef keyClassDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1047 if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeAES
)) {
1048 *algorithm
= CSSM_ALGID_AES
;
1049 *keySizeInBits
= 128;
1050 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1051 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDES
)) {
1052 *algorithm
= CSSM_ALGID_DES
;
1053 *keySizeInBits
= 128;
1054 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1055 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyType3DES
)) {
1056 *algorithm
= CSSM_ALGID_3DES_3KEY_EDE
;
1057 *keySizeInBits
= 128;
1058 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1059 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC4
)) {
1060 *algorithm
= CSSM_ALGID_RC4
;
1061 *keySizeInBits
= 128;
1062 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1063 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC2
)) {
1064 *algorithm
= CSSM_ALGID_RC2
;
1065 *keySizeInBits
= 128;
1066 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1067 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeCAST
)) {
1068 *algorithm
= CSSM_ALGID_CAST
;
1069 *keySizeInBits
= 128;
1070 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1071 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRSA
)) {
1072 *algorithm
= CSSM_ALGID_RSA
;
1073 *keySizeInBits
= 128;
1074 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1075 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDSA
)) {
1076 *algorithm
= CSSM_ALGID_DSA
;
1077 *keySizeInBits
= 128;
1078 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1079 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeECDSA
) ||
1080 CFEqual(algorithmDictValue
, kSecAttrKeyTypeEC
)) {
1081 *algorithm
= CSSM_ALGID_ECDSA
;
1082 *keySizeInBits
= 128;
1083 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1085 *algorithm
= CSSM_ALGID_AES
;
1086 *keySizeInBits
= 128;
1087 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1090 if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPublic
)) {
1091 *keyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
1092 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPrivate
)) {
1093 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1094 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassSymmetric
)) {
1095 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1098 *keySizeInBits
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, *keySizeInBits
);
1099 *keyUsage
= utilGetMaskValFromCFDict(parameters
, kSecAttrCanEncrypt
, CSSM_KEYUSE_ENCRYPT
) |
1100 utilGetMaskValFromCFDict(parameters
, kSecAttrCanDecrypt
, CSSM_KEYUSE_DECRYPT
) |
1101 utilGetMaskValFromCFDict(parameters
, kSecAttrCanWrap
, CSSM_KEYUSE_WRAP
) |
1102 utilGetMaskValFromCFDict(parameters
, kSecAttrCanUnwrap
, CSSM_KEYUSE_UNWRAP
);
1105 if(*keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
|| *keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
) {
1106 *keyUsage
|= utilGetMaskValFromCFDict(parameters
, kSecAttrCanSign
, CSSM_KEYUSE_SIGN
) |
1107 utilGetMaskValFromCFDict(parameters
, kSecAttrCanVerify
, CSSM_KEYUSE_VERIFY
);
1110 if(*keyUsage
== 0) {
1111 switch (*keyClass
) {
1112 case CSSM_KEYCLASS_PRIVATE_KEY
:
1113 *keyUsage
= CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
;
1115 case CSSM_KEYCLASS_PUBLIC_KEY
:
1116 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
;
1119 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
;
1126 utilCopyDefaultKeyLabel(void)
1128 // generate a default label from the current date
1129 CFDateRef dateNow
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent());
1130 CFStringRef defaultLabel
= CFCopyDescription(dateNow
);
1133 return defaultLabel
;
1137 SecKeyGenerateSymmetric(CFDictionaryRef parameters
, CFErrorRef
*error
)
1139 OSStatus result
= errSecParam
; // default result for an early exit
1140 SecKeyRef key
= NULL
;
1141 SecKeychainRef keychain
= NULL
;
1142 SecAccessRef access
;
1144 CFStringRef appLabel
;
1146 CFStringRef dateLabel
= NULL
;
1148 CSSM_ALGORITHMS algorithm
;
1149 uint32 keySizeInBits
;
1150 CSSM_KEYUSE keyUsage
;
1151 uint32 keyAttr
= CSSM_KEYATTR_RETURN_DEFAULT
;
1152 CSSM_KEYCLASS keyClass
;
1154 Boolean isPermanent
;
1155 Boolean isExtractable
;
1157 // verify keychain parameter
1158 if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
))
1160 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1167 // verify permanent parameter
1168 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsPermanent
, (const void **)&value
))
1169 isPermanent
= false;
1170 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1173 isPermanent
= CFEqual(kCFBooleanTrue
, value
);
1175 if (keychain
== NULL
) {
1176 // no keychain was specified, so use the default keychain
1177 result
= SecKeychainCopyDefault(&keychain
);
1179 keyAttr
|= CSSM_KEYATTR_PERMANENT
;
1182 // verify extractable parameter
1183 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
))
1184 isExtractable
= true; // default to extractable if value not specified
1185 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1188 isExtractable
= CFEqual(kCFBooleanTrue
, value
);
1190 keyAttr
|= CSSM_KEYATTR_EXTRACTABLE
;
1192 // verify access parameter
1193 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&access
))
1195 else if (SecAccessGetTypeID() != CFGetTypeID(access
))
1198 // verify label parameter
1199 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrLabel
, (const void **)&label
))
1200 label
= (dateLabel
= utilCopyDefaultKeyLabel()); // no label provided, so use default
1201 else if (CFStringGetTypeID() != CFGetTypeID(label
))
1204 // verify application label parameter
1205 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationLabel
, (const void **)&appLabel
))
1206 appLabel
= (dateLabel
) ? dateLabel
: (dateLabel
= utilCopyDefaultKeyLabel());
1207 else if (CFStringGetTypeID() != CFGetTypeID(appLabel
))
1210 // verify application tag parameter
1211 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationTag
, (const void **)&appTag
))
1213 else if (CFStringGetTypeID() != CFGetTypeID(appTag
))
1216 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1219 // the generated key will not be stored in any keychain
1220 result
= SecKeyGenerate(keychain
, algorithm
, keySizeInBits
, 0, keyUsage
, keyAttr
, access
, &key
);
1223 // we can set the label attributes on the generated key if it's a keychain item
1224 size_t labelBufLen
= (label
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label
), kCFStringEncodingUTF8
) + 1 : 0;
1225 char *labelBuf
= (char *)malloc(labelBufLen
);
1226 size_t appLabelBufLen
= (appLabel
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel
), kCFStringEncodingUTF8
) + 1 : 0;
1227 char *appLabelBuf
= (char *)malloc(appLabelBufLen
);
1228 size_t appTagBufLen
= (appTag
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag
), kCFStringEncodingUTF8
) + 1 : 0;
1229 char *appTagBuf
= (char *)malloc(appTagBufLen
);
1231 if (label
&& !CFStringGetCString(label
, labelBuf
, labelBufLen
-1, kCFStringEncodingUTF8
))
1233 if (appLabel
&& !CFStringGetCString(appLabel
, appLabelBuf
, appLabelBufLen
-1, kCFStringEncodingUTF8
))
1235 if (appTag
&& !CFStringGetCString(appTag
, appTagBuf
, appTagBufLen
-1, kCFStringEncodingUTF8
))
1238 SecKeychainAttribute attrs
[] = {
1239 { kSecKeyPrintName
, (UInt32
)strlen(labelBuf
), (char *)labelBuf
},
1240 { kSecKeyLabel
, (UInt32
)strlen(appLabelBuf
), (char *)appLabelBuf
},
1241 { kSecKeyApplicationTag
, (UInt32
)strlen(appTagBuf
), (char *)appTagBuf
} };
1242 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
1243 if (!appTag
) --attributes
.count
;
1245 result
= SecKeyGenerateWithAttributes(&attributes
,
1246 keychain
, algorithm
, keySizeInBits
, 0,
1247 keyUsage
, keyAttr
, access
, &key
);
1255 if (result
&& error
) {
1256 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, result
, NULL
);
1259 CFRelease(dateLabel
);
1261 CFRelease(keychain
);
1269 SecKeyCreateFromData(CFDictionaryRef parameters
, CFDataRef keyData
, CFErrorRef
*error
)
1271 CSSM_ALGORITHMS algorithm
;
1272 uint32 keySizeInBits
;
1273 CSSM_KEYUSE keyUsage
;
1274 CSSM_KEYCLASS keyClass
;
1277 if(keyData
== NULL
|| CFDataGetLength(keyData
) == 0){
1278 MacOSError::throwMe(errSecUnsupportedKeySize
);
1281 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1283 CSSM_CSP_HANDLE cspHandle
= cuCspStartup(CSSM_FALSE
); // TRUE => CSP, FALSE => CSPDL
1285 SecKeyImportExportParameters iparam
;
1286 memset(&iparam
, 0, sizeof(iparam
));
1287 iparam
.keyUsage
= keyUsage
;
1289 SecExternalItemType itype
;
1291 case CSSM_KEYCLASS_PRIVATE_KEY
:
1292 itype
= kSecItemTypePrivateKey
;
1294 case CSSM_KEYCLASS_PUBLIC_KEY
:
1295 itype
= kSecItemTypePublicKey
;
1297 case CSSM_KEYCLASS_SESSION_KEY
:
1298 itype
= kSecItemTypeSessionKey
;
1301 itype
= kSecItemTypeUnknown
;
1305 CFMutableArrayRef ka
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1306 // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful.
1307 crtn
= impExpImportRawKey(keyData
, kSecFormatUnknown
, itype
, algorithm
, NULL
, cspHandle
, 0, NULL
, NULL
, ka
);
1308 if (crtn
== CSSM_OK
&& CFArrayGetCount((CFArrayRef
)ka
)) {
1309 SecKeyRef sk
= (SecKeyRef
)CFArrayGetValueAtIndex((CFArrayRef
)ka
, 0);
1315 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, crtn
? crtn
: CSSM_ERRCODE_INTERNAL_ERROR
, NULL
);
1323 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable
, dispatch_queue_t deliveryQueue
,
1324 SecKeyGeneratePairBlock result
)
1326 CFDictionaryRef parameters
= CFDictionaryCreateCopy(NULL
, parametersWhichMightBeMutiable
);
1327 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
1328 SecKeyRef publicKey
= NULL
;
1329 SecKeyRef privateKey
= NULL
;
1330 OSStatus status
= SecKeyGeneratePair(parameters
, &publicKey
, &privateKey
);
1331 dispatch_async(deliveryQueue
, ^{
1332 CFErrorRef error
= NULL
;
1333 if (errSecSuccess
!= status
) {
1334 error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, NULL
);
1336 result(publicKey
, privateKey
, error
);
1341 CFRelease(publicKey
);
1344 CFRelease(privateKey
);
1346 CFRelease(parameters
);
1351 static inline void utilClearAndFree(void *p
, size_t len
) {
1353 if(len
) bzero(p
, len
);
1359 SecKeyDeriveFromPassword(CFStringRef password
, CFDictionaryRef parameters
, CFErrorRef
*error
)
1361 CCPBKDFAlgorithm algorithm
;
1362 CFIndex passwordLen
= 0;
1363 CFDataRef keyData
= NULL
;
1364 char *thePassword
= NULL
;
1365 uint8_t *salt
= NULL
;
1366 uint8_t *derivedKey
= NULL
;
1367 size_t saltLen
= 0, derivedKeyLen
= 0;
1369 CFDataRef saltDictValue
, algorithmDictValue
;
1370 SecKeyRef retval
= NULL
;
1372 /* Pick Values from parameters */
1374 if((saltDictValue
= (CFDataRef
) CFDictionaryGetValue(parameters
, kSecAttrSalt
)) == NULL
) {
1375 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecMissingAlgorithmParms
, NULL
);
1379 derivedKeyLen
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, 128);
1380 // This value come in bits but the rest of the code treats it as bytes
1383 algorithmDictValue
= (CFDataRef
) utilGetStringFromCFDict(parameters
, kSecAttrPRF
, kSecAttrPRFHmacAlgSHA256
);
1385 rounds
= utilGetNumberFromCFDict(parameters
, kSecAttrRounds
, 0);
1387 /* Convert any remaining parameters and get the password bytes */
1389 saltLen
= CFDataGetLength(saltDictValue
);
1390 if((salt
= (uint8_t *) malloc(saltLen
)) == NULL
) {
1391 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
1395 CFDataGetBytes(saltDictValue
, CFRangeMake(0, saltLen
), (UInt8
*) salt
);
1397 passwordLen
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1;
1398 if((thePassword
= (char *) malloc(passwordLen
)) == NULL
) {
1399 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
1402 CFStringGetBytes(password
, CFRangeMake(0, CFStringGetLength(password
)), kCFStringEncodingUTF8
, '?', FALSE
, (UInt8
*)thePassword
, passwordLen
, &passwordLen
);
1404 if((derivedKey
= (uint8_t *) malloc(derivedKeyLen
)) == NULL
) {
1405 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
1409 if(algorithmDictValue
== NULL
) {
1410 algorithm
= kCCPRFHmacAlgSHA1
; /* default */
1411 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA1
)) {
1412 algorithm
= kCCPRFHmacAlgSHA1
;
1413 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA224
)) {
1414 algorithm
= kCCPRFHmacAlgSHA224
;
1415 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA256
)) {
1416 algorithm
= kCCPRFHmacAlgSHA256
;
1417 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA384
)) {
1418 algorithm
= kCCPRFHmacAlgSHA384
;
1419 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA512
)) {
1420 algorithm
= kCCPRFHmacAlgSHA512
;
1422 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidAlgorithmParms
, NULL
);
1427 rounds
= 33333; // we need to pass back a consistent value since there's no way to record the round count.
1430 if(CCKeyDerivationPBKDF(kCCPBKDF2
, thePassword
, passwordLen
, salt
, saltLen
, algorithm
, rounds
, derivedKey
, derivedKeyLen
)) {
1431 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
1435 if((keyData
= CFDataCreate(NULL
, derivedKey
, derivedKeyLen
)) != NULL
) {
1436 retval
= SecKeyCreateFromData(parameters
, keyData
, error
);
1439 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
1443 utilClearAndFree(salt
, saltLen
);
1444 utilClearAndFree(thePassword
, passwordLen
);
1445 utilClearAndFree(derivedKey
, derivedKeyLen
);
1450 SecKeyWrapSymmetric(SecKeyRef keyToWrap
, SecKeyRef wrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
1452 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);
1457 SecKeyUnwrapSymmetric(CFDataRef
*keyToUnwrap
, SecKeyRef unwrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
1459 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);
1464 /* iOS SecKey shim functions */
1466 #define MAX_DIGEST_LEN (CC_SHA512_DIGEST_LENGTH)
1468 /* Currently length of SHA512 oid + 1 */
1469 #define MAX_OID_LEN (10)
1471 #define DER_MAX_DIGEST_INFO_LEN (10 + MAX_DIGEST_LEN + MAX_OID_LEN)
1473 /* Encode the digestInfo header into digestInfo and return the offset from
1474 digestInfo at which to put the actual digest. Returns 0 if digestInfo
1475 won't fit within digestInfoLength bytes.
1479 0x06, oid.Len, oid.Data,
1484 static size_t DEREncodeDigestInfoPrefix(const SecAsn1Oid
*oid
,
1485 size_t digestLength
,
1486 uint8_t *digestInfo
,
1487 size_t digestInfoLength
)
1489 size_t algIdLen
= oid
->Length
+ 4;
1490 size_t topLen
= algIdLen
+ digestLength
+ 4;
1491 size_t totalLen
= topLen
+ 2;
1493 if (totalLen
> digestInfoLength
) {
1498 digestInfo
[ix
++] = (SEC_ASN1_SEQUENCE
| SEC_ASN1_CONSTRUCTED
);
1499 digestInfo
[ix
++] = topLen
;
1500 digestInfo
[ix
++] = (SEC_ASN1_SEQUENCE
| SEC_ASN1_CONSTRUCTED
);
1501 digestInfo
[ix
++] = algIdLen
;
1502 digestInfo
[ix
++] = SEC_ASN1_OBJECT_ID
;
1503 digestInfo
[ix
++] = oid
->Length
;
1504 memcpy(&digestInfo
[ix
], oid
->Data
, oid
->Length
);
1506 digestInfo
[ix
++] = SEC_ASN1_NULL
;
1507 digestInfo
[ix
++] = 0;
1508 digestInfo
[ix
++] = SEC_ASN1_OCTET_STRING
;
1509 digestInfo
[ix
++] = digestLength
;
1514 static OSStatus
SecKeyGetDigestInfo(SecKeyRef key
, const SecAsn1AlgId
*algId
,
1515 const uint8_t *data
, size_t dataLen
, bool digestData
,
1516 uint8_t *digestInfo
, size_t *digestInfoLen
/* IN/OUT */)
1518 unsigned char *(*digestFcn
)(const void *, CC_LONG
, unsigned char *);
1519 CFIndex keyAlgID
= kSecNullAlgorithmID
;
1520 const SecAsn1Oid
*digestOid
;
1524 /* Since these oids all have the same prefix, use switch. */
1525 if ((algId
->algorithm
.Length
== CSSMOID_RSA
.Length
) &&
1526 !memcmp(algId
->algorithm
.Data
, CSSMOID_RSA
.Data
,
1527 algId
->algorithm
.Length
- 1)) {
1528 keyAlgID
= kSecRSAAlgorithmID
;
1529 switch (algId
->algorithm
.Data
[algId
->algorithm
.Length
- 1]) {
1531 case 2: /* oidMD2WithRSA */
1533 digestLen
= CC_MD2_DIGEST_LENGTH
;
1534 digestOid
= &CSSMOID_MD2
;
1536 case 3: /* oidMD4WithRSA */
1538 digestLen
= CC_MD4_DIGEST_LENGTH
;
1539 digestOid
= &CSSMOID_MD4
;
1541 case 4: /* oidMD5WithRSA */
1543 digestLen
= CC_MD5_DIGEST_LENGTH
;
1544 digestOid
= &CSSMOID_MD5
;
1547 case 5: /* oidSHA1WithRSA */
1548 digestFcn
= CC_SHA1
;
1549 digestLen
= CC_SHA1_DIGEST_LENGTH
;
1550 digestOid
= &CSSMOID_SHA1
;
1552 case 11: /* oidSHA256WithRSA */
1553 digestFcn
= CC_SHA256
;
1554 digestLen
= CC_SHA256_DIGEST_LENGTH
;
1555 digestOid
= &CSSMOID_SHA256
;
1557 case 12: /* oidSHA384WithRSA */
1559 digestFcn
= CC_SHA384
;
1560 digestLen
= CC_SHA384_DIGEST_LENGTH
;
1561 digestOid
= &CSSMOID_SHA384
;
1563 case 13: /* oidSHA512WithRSA */
1564 digestFcn
= CC_SHA512
;
1565 digestLen
= CC_SHA512_DIGEST_LENGTH
;
1566 digestOid
= &CSSMOID_SHA512
;
1568 case 14: /* oidSHA224WithRSA */
1569 digestFcn
= CC_SHA224
;
1570 digestLen
= CC_SHA224_DIGEST_LENGTH
;
1571 digestOid
= &CSSMOID_SHA224
;
1574 secdebug("key", "unsupported rsa signature algorithm");
1575 return errSecUnsupportedAlgorithm
;
1577 } else if ((algId
->algorithm
.Length
== CSSMOID_ECDSA_WithSHA224
.Length
) &&
1578 !memcmp(algId
->algorithm
.Data
, CSSMOID_ECDSA_WithSHA224
.Data
,
1579 algId
->algorithm
.Length
- 1)) {
1580 keyAlgID
= kSecECDSAAlgorithmID
;
1581 switch (algId
->algorithm
.Data
[algId
->algorithm
.Length
- 1]) {
1582 case 1: /* oidSHA224WithECDSA */
1583 digestFcn
= CC_SHA224
;
1584 digestLen
= CC_SHA224_DIGEST_LENGTH
;
1586 case 2: /* oidSHA256WithECDSA */
1587 digestFcn
= CC_SHA256
;
1588 digestLen
= CC_SHA256_DIGEST_LENGTH
;
1590 case 3: /* oidSHA384WithECDSA */
1592 digestFcn
= CC_SHA384
;
1593 digestLen
= CC_SHA384_DIGEST_LENGTH
;
1595 case 4: /* oidSHA512WithECDSA */
1596 digestFcn
= CC_SHA512
;
1597 digestLen
= CC_SHA512_DIGEST_LENGTH
;
1600 secdebug("key", "unsupported ecdsa signature algorithm");
1601 return errSecUnsupportedAlgorithm
;
1603 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_ECDSA_WithSHA1
)) {
1604 keyAlgID
= kSecECDSAAlgorithmID
;
1605 digestFcn
= CC_SHA1
;
1606 digestLen
= CC_SHA1_DIGEST_LENGTH
;
1607 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_SHA1
)) {
1608 digestFcn
= CC_SHA1
;
1609 digestLen
= CC_SHA1_DIGEST_LENGTH
;
1610 digestOid
= &CSSMOID_SHA1
;
1611 } else if ((algId
->algorithm
.Length
== CSSMOID_SHA224
.Length
) &&
1612 !memcmp(algId
->algorithm
.Data
, CSSMOID_SHA224
.Data
, algId
->algorithm
.Length
- 1))
1614 switch (algId
->algorithm
.Data
[algId
->algorithm
.Length
- 1]) {
1615 case 4: /* OID_SHA224 */
1616 digestFcn
= CC_SHA224
;
1617 digestLen
= CC_SHA224_DIGEST_LENGTH
;
1618 digestOid
= &CSSMOID_SHA224
;
1620 case 1: /* OID_SHA256 */
1621 digestFcn
= CC_SHA256
;
1622 digestLen
= CC_SHA256_DIGEST_LENGTH
;
1623 digestOid
= &CSSMOID_SHA256
;
1625 case 2: /* OID_SHA384 */
1627 digestFcn
= CC_SHA384
;
1628 digestLen
= CC_SHA384_DIGEST_LENGTH
;
1629 digestOid
= &CSSMOID_SHA384
;
1631 case 3: /* OID_SHA512 */
1632 digestFcn
= CC_SHA512
;
1633 digestLen
= CC_SHA512_DIGEST_LENGTH
;
1634 digestOid
= &CSSMOID_SHA512
;
1637 secdebug("key", "unsupported sha-2 signature algorithm");
1638 return errSecUnsupportedAlgorithm
;
1640 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_MD5
)) {
1642 digestLen
= CC_MD5_DIGEST_LENGTH
;
1643 digestOid
= &CSSMOID_MD5
;
1645 secdebug("key", "unsupported digesting algorithm");
1646 return errSecUnsupportedAlgorithm
;
1649 /* check key is appropriate for signature (superfluous for digest only oid) */
1651 CFIndex supportedKeyAlgID
= kSecNullAlgorithmID
;
1652 #if TARGET_OS_EMBEDDED
1653 supportedKeyAlgID
= SecKeyGetAlgorithmID(key
);
1655 const CSSM_KEY
* temporaryKey
;
1656 SecKeyGetCSSMKey(key
, &temporaryKey
);
1657 CSSM_ALGORITHMS tempAlgorithm
= temporaryKey
->KeyHeader
.AlgorithmId
;
1658 if (CSSM_ALGID_RSA
== tempAlgorithm
) {
1659 supportedKeyAlgID
= kSecRSAAlgorithmID
;
1660 } else if (CSSM_ALGID_ECDSA
== tempAlgorithm
) {
1661 supportedKeyAlgID
= kSecECDSAAlgorithmID
;
1665 if (keyAlgID
== kSecNullAlgorithmID
) {
1666 keyAlgID
= supportedKeyAlgID
;
1668 else if (keyAlgID
!= supportedKeyAlgID
) {
1669 return errSecUnsupportedAlgorithm
;
1674 case kSecRSAAlgorithmID
:
1675 offset
= DEREncodeDigestInfoPrefix(digestOid
, digestLen
,
1676 digestInfo
, *digestInfoLen
);
1678 return errSecBufferTooSmall
;
1680 case kSecDSAAlgorithmID
:
1681 if (digestOid
!= &CSSMOID_SHA1
)
1682 return errSecUnsupportedAlgorithm
;
1684 case kSecECDSAAlgorithmID
:
1687 secdebug("key", "unsupported signature algorithm");
1688 return errSecUnsupportedAlgorithm
;
1692 if(dataLen
>UINT32_MAX
) /* Check for overflow with CC_LONG cast */
1694 digestFcn(data
, (CC_LONG
)dataLen
, &digestInfo
[offset
]);
1695 *digestInfoLen
= offset
+ digestLen
;
1697 if (dataLen
!= digestLen
)
1699 memcpy(&digestInfo
[offset
], data
, dataLen
);
1700 *digestInfoLen
= offset
+ dataLen
;
1703 return errSecSuccess
;
1706 OSStatus
SecKeyVerifyDigest(
1707 SecKeyRef key
, /* Private key */
1708 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
1709 const uint8_t *digestData
, /* signature over this digest */
1710 size_t digestDataLen
, /* length of dataToDigest */
1711 const uint8_t *sig
, /* signature to verify */
1712 size_t sigLen
) /* length of sig */
1714 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
1715 uint8_t digestInfo
[digestInfoLength
];
1718 status
= SecKeyGetDigestInfo(key
, algId
, digestData
, digestDataLen
, false /* data is digest */,
1719 digestInfo
, &digestInfoLength
);
1722 return SecKeyRawVerify(key
, kSecPaddingPKCS1
,
1723 digestInfo
, digestInfoLength
, sig
, sigLen
);
1726 OSStatus
SecKeySignDigest(
1727 SecKeyRef key
, /* Private key */
1728 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
1729 const uint8_t *digestData
, /* signature over this digest */
1730 size_t digestDataLen
, /* length of digestData */
1731 uint8_t *sig
, /* signature, RETURNED */
1732 size_t *sigLen
) /* IN/OUT */
1734 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
1735 uint8_t digestInfo
[digestInfoLength
];
1738 status
= SecKeyGetDigestInfo(key
, algId
, digestData
, digestDataLen
, false,
1739 digestInfo
, &digestInfoLength
);
1742 return SecKeyRawSign(key
, kSecPaddingPKCS1
,
1743 digestInfo
, digestInfoLength
, sig
, sigLen
);
1746 /* It's debatable whether this belongs here or in the ssl code since the
1747 curve values come from a tls related rfc4492. */
1748 SecECNamedCurve
SecECKeyGetNamedCurve(SecKeyRef key
)
1751 SecPointer
<KeyItem
> keyItem(KeyItem::required(key
));
1752 switch (keyItem
->key().header().LogicalKeySizeInBits
) {
1755 return kSecECCurveSecp192r1
;
1757 return kSecECCurveSecp224r1
;
1760 return kSecECCurveSecp256r1
;
1762 return kSecECCurveSecp384r1
;
1764 return kSecECCurveSecp521r1
;
1768 return kSecECCurveNone
;
1771 static inline CFDataRef
_CFDataCreateReferenceFromRange(CFAllocatorRef allocator
, CFDataRef sourceData
, CFRange range
)
1773 return CFDataCreateWithBytesNoCopy(allocator
,
1774 CFDataGetBytePtr(sourceData
) + range
.location
, range
.length
,
1778 static inline CFDataRef
_CFDataCreateCopyFromRange(CFAllocatorRef allocator
, CFDataRef sourceData
, CFRange range
)
1780 return CFDataCreate(allocator
, CFDataGetBytePtr(sourceData
) + range
.location
, range
.length
);
1783 #pragma clang diagnostic push
1784 #pragma clang diagnostic ignored "-Wunused-function"
1785 static inline bool _CFDataEquals(CFDataRef left
, CFDataRef right
)
1787 return (left
!= NULL
) &&
1789 (CFDataGetLength(left
) == CFDataGetLength(right
)) &&
1790 (0 == memcmp(CFDataGetBytePtr(left
), CFDataGetBytePtr(right
), (size_t)CFDataGetLength(left
)));
1792 #pragma clang diagnostic pop
1795 void secdump(const unsigned char *data
, unsigned long len
)
1804 sprintf(t
, "%04lx :", i
);
1807 sprintf(t
, " %02x", data
[i
]);
1811 syslog(LOG_NOTICE
, s
);
1816 syslog(LOG_NOTICE
, s
);
1820 OSStatus
SecKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
* publicBytes
)
1823 #if TARGET_OS_EMBEDDED
1824 keyAlgId
= SecKeyGetAlgorithmID(key
);
1826 keyAlgId
= SecKeyGetAlgorithmId(key
);
1829 OSStatus ecStatus
= errSecParam
;
1830 CFDataRef tempPublicData
= NULL
;
1831 CFDataRef headerlessPublicData
= NULL
;
1832 CFIndex headerLength
= 0;
1833 const UInt8
* pData_Ptr
= NULL
;
1835 if (kSecRSAAlgorithmID
== keyAlgId
)
1837 return SecItemExport(key
, kSecFormatBSAFE
, 0, NULL
, publicBytes
);
1840 if (kSecECDSAAlgorithmID
== keyAlgId
)
1842 // First export the key so there is access to the underlying key material
1843 ecStatus
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, &tempPublicData
);
1844 if(ecStatus
!= errSecSuccess
)
1846 secdebug("key", "SecKeyCopyPublicBytes: SecItemExport error (%d) for ECDSA public key %p",
1847 ecStatus
, (uintptr_t)key
);
1853 // Get a pointer to the first byte of the exported data
1854 pData_Ptr
= CFDataGetBytePtr(tempPublicData
);
1856 // the first byte should be a sequence 0x30
1857 if (*pData_Ptr
!= 0x30)
1859 secdebug("key", "SecKeyCopyPublicBytes: exported data is invalid");
1860 if (NULL
!= tempPublicData
)
1861 CFRelease(tempPublicData
);
1863 ecStatus
= errSecParam
;
1867 // move past the sequence byte
1870 // Check to see if the high bit is set which
1871 // indicates that the length will be at least
1872 // two bytes. If the high bit is set then
1873 // The lower seven bits specifies the number of
1874 // bytes used for the length. The additonal 1
1875 // is for the current byte. Otherwise just move past the
1876 // single length byte
1877 pData_Ptr
+= (*pData_Ptr
& 0x80) ? ((*pData_Ptr
& 0x7F) + 1) : 1;
1879 // The current byte should be a sequence 0x30
1880 if (*pData_Ptr
!= 0x30)
1882 secdebug("key", "SecKeyCopyPublicBytes: Could not find the key sequence");
1883 if (NULL
!= tempPublicData
)
1884 CFRelease(tempPublicData
);
1886 ecStatus
= errSecParam
;
1891 // The next bytes will always be the same
1896 // ECDSA public KEY OID value 0x2a,0x86,0x48,0xce,0x3d,0x02,0x01
1898 // This is a total of 12 bytes
1901 // Next byte is the length of the ECDSA curve OID
1902 // Move past the length byte and the curve OID
1903 pData_Ptr
+= (((int)*pData_Ptr
) + 1);
1905 // Should be at a BINARY String which is specifed by a 0x3
1906 if (*pData_Ptr
!= 0x03)
1908 secdebug("key", "SecKeyCopyPublicBytes: Invalid key structure");
1909 if (NULL
!= tempPublicData
)
1910 CFRelease(tempPublicData
);
1912 ecStatus
= errSecParam
;
1917 // Move past the BINARY String specifier 0x03
1921 // Check to see if the high bit is set which
1922 // indicates that the length will be at least
1923 // two bytes. If the high bit is set then
1924 // The lower seven bits specifies the number of
1925 // bytes used for the length. The additonal 1
1926 // is for the current byte. Otherwise just move past the
1927 // single length byte
1928 pData_Ptr
+= (*pData_Ptr
& 0x80) ? ((*pData_Ptr
& 0x7F) + 1) : 1;
1930 // Move past the beginning marker for the BINARY String 0x00
1933 // pData_Ptr now points to the first bytes of the key material
1934 headerLength
= (CFIndex
)(((intptr_t)pData_Ptr
) - ((intptr_t)CFDataGetBytePtr(tempPublicData
)));
1936 headerlessPublicData
= _CFDataCreateCopyFromRange(kCFAllocatorDefault
,
1937 tempPublicData
, CFRangeMake(headerLength
, CFDataGetLength(tempPublicData
) - headerLength
));
1939 if (!headerlessPublicData
)
1941 printf("SecKeyCopyPublicBytes: headerlessPublicData is nil (1)\n");
1942 if (NULL
!= tempPublicData
)
1943 CFRelease(tempPublicData
);
1945 ecStatus
= errSecParam
;
1952 *publicBytes
= headerlessPublicData
;
1955 ecStatus
= errSecSuccess
;
1957 if (NULL
!= tempPublicData
)
1958 CFRelease(tempPublicData
);
1967 CFDataRef
SecECKeyCopyPublicBits(SecKeyRef key
)
1969 CFDataRef exportedKey
;
1970 if(SecKeyCopyPublicBytes(key
, &exportedKey
) != errSecSuccess
) {
1976 SecKeyRef
SecKeyCreateFromPublicData(CFAllocatorRef allocator
, CFIndex algorithmID
, CFDataRef publicBytes
)
1978 SecExternalFormat externalFormat
= kSecFormatOpenSSL
;
1979 SecExternalItemType externalItemType
= kSecItemTypePublicKey
;
1980 CFDataRef workingData
= NULL
;
1981 CFArrayRef outArray
= NULL
;
1982 SecKeyRef retVal
= NULL
;
1984 if (kSecRSAAlgorithmID
== algorithmID
) {
1986 * kSecFormatBSAFE uses the original PKCS#1 definition:
1987 * RSAPublicKey ::= SEQUENCE {
1988 * modulus INTEGER, -- n
1989 * publicExponent INTEGER -- e
1991 * kSecFormatOpenSSL uses different ASN.1 encoding.
1993 externalFormat
= kSecFormatBSAFE
;
1994 workingData
= _CFDataCreateReferenceFromRange(kCFAllocatorDefault
, publicBytes
, CFRangeMake(0, CFDataGetLength(publicBytes
)));
1995 } else if (kSecECDSAAlgorithmID
== algorithmID
) {
1996 CFMutableDataRef tempData
;
1997 uint8 requiredFirstDERByte
[] = {0x04};
1998 uint8 placeholder
[1];
1999 uint8 headerBytes
[] = { 0x30,0x59,0x30,0x13,0x06,0x07,0x2a,0x86,
2000 0x48,0xce,0x3d,0x02,0x01,0x06,0x08,0x2a,
2001 0x86,0x48,0xce,0x3d,0x03,0x01,0x07,0x03,
2004 /* FIXME: this code only handles one specific curve type; need to expand this */
2005 if(CFDataGetLength(publicBytes
) != 65)
2008 CFDataGetBytes(publicBytes
, CFRangeMake(0, 1), placeholder
);
2010 if(requiredFirstDERByte
[0] != placeholder
[0])
2014 tempData
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
2015 CFDataAppendBytes(tempData
, headerBytes
, sizeof(headerBytes
));
2016 CFDataAppendBytes(tempData
, CFDataGetBytePtr(publicBytes
), CFDataGetLength(publicBytes
));
2018 workingData
= tempData
;
2020 if(SecItemImport(workingData
, NULL
, &externalFormat
, &externalItemType
, 0, NULL
, NULL
, &outArray
) != errSecSuccess
) {
2023 if(!outArray
|| CFArrayGetCount(outArray
) == 0) {
2026 retVal
= (SecKeyRef
)CFArrayGetValueAtIndex(outArray
, 0);
2030 if(workingData
) CFRelease(workingData
);
2031 if(outArray
) CFRelease(outArray
);
2035 SecKeyRef
SecKeyCreateRSAPublicKey(CFAllocatorRef allocator
,
2036 const uint8_t *keyData
, CFIndex keyDataLength
,
2037 SecKeyEncoding encoding
)
2039 CFDataRef pubKeyData
= NULL
;
2040 if(kSecKeyEncodingPkcs1
== encoding
) {
2041 /* DER-encoded according to PKCS1. */
2042 pubKeyData
= CFDataCreate(allocator
, keyData
, keyDataLength
);
2044 } else if(kSecKeyEncodingApplePkcs1
== encoding
) {
2045 /* DER-encoded according to PKCS1 with Apple Extensions. */
2046 /* FIXME: need to actually handle extensions */
2049 } else if(kSecKeyEncodingRSAPublicParams
== encoding
) {
2050 /* SecRSAPublicKeyParams format; we must encode as PKCS1. */
2051 SecRSAPublicKeyParams
*params
= (SecRSAPublicKeyParams
*)keyData
;
2052 DERSize m_size
= params
->modulusLength
;
2053 DERSize e_size
= params
->exponentLength
;
2054 const DERSize seq_size
= DERLengthOfItem(ASN1_INTEGER
, m_size
) +
2055 DERLengthOfItem(ASN1_INTEGER
, e_size
);
2056 const DERSize result_size
= DERLengthOfItem(ASN1_SEQUENCE
, seq_size
);
2057 DERSize r_size
, remaining_size
= result_size
;
2060 CFMutableDataRef pkcs1
= CFDataCreateMutable(allocator
, result_size
);
2061 if (pkcs1
== NULL
) {
2064 CFDataSetLength(pkcs1
, result_size
);
2065 uint8_t *bytes
= CFDataGetMutableBytePtr(pkcs1
);
2067 *bytes
++ = ASN1_CONSTR_SEQUENCE
;
2070 drtn
= DEREncodeLength(seq_size
, bytes
, &r_size
);
2071 if (r_size
<= remaining_size
) {
2073 remaining_size
-= r_size
;
2075 r_size
= remaining_size
;
2076 drtn
= DEREncodeItem(ASN1_INTEGER
, m_size
, (const DERByte
*)params
->modulus
, (DERByte
*)bytes
, &r_size
);
2077 if (r_size
<= remaining_size
) {
2079 remaining_size
-= r_size
;
2081 r_size
= remaining_size
;
2082 drtn
= DEREncodeItem(ASN1_INTEGER
, e_size
, (const DERByte
*)params
->exponent
, (DERByte
*)bytes
, &r_size
);
2087 /* unsupported encoding */
2090 SecKeyRef publicKey
= SecKeyCreateFromPublicData(allocator
, kSecRSAAlgorithmID
, pubKeyData
);
2091 CFRelease(pubKeyData
);
2095 #if !TARGET_OS_EMBEDDED
2097 // Given a CSSM public key, copy its modulus and/or exponent data.
2098 // Caller is responsible for releasing the returned CFDataRefs.
2101 OSStatus
_SecKeyCopyRSAPublicModulusAndExponent(SecKeyRef key
, CFDataRef
*modulus
, CFDataRef
*exponent
)
2103 const CSSM_KEY
*pubKey
;
2104 const CSSM_KEYHEADER
*hdr
;
2105 CSSM_DATA pubKeyBlob
;
2108 result
= SecKeyGetCSSMKey(key
, &pubKey
);
2109 if(result
!= errSecSuccess
) {
2112 hdr
= &pubKey
->KeyHeader
;
2113 if(hdr
->KeyClass
!= CSSM_KEYCLASS_PUBLIC_KEY
) {
2114 return errSSLInternal
;
2116 if(hdr
->AlgorithmId
!= CSSM_ALGID_RSA
) {
2117 return errSSLInternal
;
2119 switch(hdr
->BlobType
) {
2120 case CSSM_KEYBLOB_RAW
:
2121 pubKeyBlob
.Length
= pubKey
->KeyData
.Length
;
2122 pubKeyBlob
.Data
= pubKey
->KeyData
.Data
;
2124 case CSSM_KEYBLOB_REFERENCE
:
2125 // FIXME: currently SSL only uses raw public keys, obtained from the CL
2127 return errSSLInternal
;
2129 assert(hdr
->BlobType
== CSSM_KEYBLOB_RAW
);
2130 // at this point we should have a PKCS1-encoded blob
2132 DERItem keyItem
= {(DERByte
*)pubKeyBlob
.Data
, pubKeyBlob
.Length
};
2133 DERRSAPubKeyPKCS1 decodedKey
;
2134 if(DERParseSequence(&keyItem
, DERNumRSAPubKeyPKCS1ItemSpecs
,
2135 DERRSAPubKeyPKCS1ItemSpecs
,
2136 &decodedKey
, sizeof(decodedKey
)) != DR_Success
) {
2137 return errSecDecode
;
2140 *modulus
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.modulus
.data
, decodedKey
.modulus
.length
);
2141 if(*modulus
== NULL
) {
2142 return errSecDecode
;
2146 *exponent
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.pubExponent
.data
, decodedKey
.pubExponent
.length
);
2147 if(*exponent
== NULL
) {
2148 return errSecDecode
;
2152 return errSecSuccess
;
2154 #endif /* !TARGET_OS_EMBEDDED */
2156 CFDataRef
SecKeyCopyModulus(SecKeyRef key
)
2158 #if TARGET_OS_EMBEDDED
2159 ccrsa_pub_ctx_t pubkey
;
2160 pubkey
.pub
= key
->key
;
2162 size_t m_size
= ccn_write_uint_size(ccrsa_ctx_n(pubkey
), ccrsa_ctx_m(pubkey
));
2164 CFAllocatorRef allocator
= CFGetAllocator(key
);
2165 CFMutableDataRef modulusData
= CFDataCreateMutable(allocator
, m_size
);
2167 if (modulusData
== NULL
)
2170 CFDataSetLength(modulusData
, m_size
);
2172 ccn_write_uint(ccrsa_ctx_n(pubkey
), ccrsa_ctx_m(pubkey
), m_size
, CFDataGetMutableBytePtr(modulusData
));
2174 CFDataRef modulusData
;
2175 OSStatus status
= _SecKeyCopyRSAPublicModulusAndExponent(key
, &modulusData
, NULL
);
2176 if(status
!= errSecSuccess
) {
2184 CFDataRef
SecKeyCopyExponent(SecKeyRef key
)
2186 #if TARGET_OS_EMBEDDED
2187 ccrsa_pub_ctx_t pubkey
;
2188 pubkey
.pub
= key
->key
;
2190 size_t e_size
= ccn_write_uint_size(ccrsa_ctx_n(pubkey
), ccrsa_ctx_e(pubkey
));
2192 CFAllocatorRef allocator
= CFGetAllocator(key
);
2193 CFMutableDataRef exponentData
= CFDataCreateMutable(allocator
, e_size
);
2195 if (exponentData
== NULL
)
2198 CFDataSetLength(exponentData
, e_size
);
2200 ccn_write_uint(ccrsa_ctx_n(pubkey
), ccrsa_ctx_m(pubkey
), e_size
, CFDataGetMutableBytePtr(exponentData
));
2202 CFDataRef exponentData
;
2203 OSStatus status
= _SecKeyCopyRSAPublicModulusAndExponent(key
, NULL
, &exponentData
);
2204 if(status
!= errSecSuccess
) {
2205 exponentData
= NULL
;
2209 return exponentData
;
2212 SecKeyRef
SecKeyCreatePublicFromPrivate(SecKeyRef privateKey
) {
2213 OSStatus status
= errSecParam
;
2215 CFDataRef serializedPublic
= NULL
;
2217 status
= SecKeyCopyPublicBytes(privateKey
, &serializedPublic
);
2218 if ((status
== errSecSuccess
) && (serializedPublic
!= NULL
)) {
2219 SecKeyRef publicKeyRef
= SecKeyCreateFromPublicData(kCFAllocatorDefault
, SecKeyGetAlgorithmId(privateKey
), serializedPublic
);
2220 CFRelease(serializedPublic
);
2221 if (publicKeyRef
!= NULL
) {
2222 return publicKeyRef
;
2226 const void *keys
[] = { kSecClass
, kSecValueRef
, kSecReturnAttributes
};
2227 const void *values
[] = { kSecClassKey
, privateKey
, kCFBooleanTrue
};
2228 CFDictionaryRef query
= CFDictionaryCreate(NULL
, keys
, values
,
2229 (sizeof(values
) / sizeof(*values
)),
2230 &kCFTypeDictionaryKeyCallBacks
,
2231 &kCFTypeDictionaryValueCallBacks
);
2232 CFTypeRef foundItem
= NULL
;
2233 status
= SecItemCopyMatching(query
, &foundItem
);
2235 if (status
== errSecSuccess
) {
2236 if (CFGetTypeID(foundItem
) == CFDictionaryGetTypeID()) {
2237 CFMutableDictionaryRef query2
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2238 CFDictionaryAddValue(query2
, kSecClass
, kSecClassKey
);
2239 CFDictionaryAddValue(query2
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
2240 CFDictionaryAddValue(query2
, kSecAttrApplicationLabel
, CFDictionaryGetValue((CFDictionaryRef
)foundItem
, kSecAttrApplicationLabel
));
2241 CFDictionaryAddValue(query2
, kSecReturnRef
, kCFBooleanTrue
);
2243 CFTypeRef foundKey
= NULL
;
2244 status
= SecItemCopyMatching(query2
, &foundKey
);
2245 if (status
== errSecSuccess
) {
2246 if (CFGetTypeID(foundKey
) == SecKeyGetTypeID()) {
2249 CFRelease(foundItem
);
2250 return (SecKeyRef
)foundKey
;
2252 status
= errSecItemNotFound
;
2258 status
= errSecItemNotFound
;
2260 CFRelease(foundItem
);