2 * Copyright (c) 2002-2015 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"
50 /* Since there are currently two implementations of SecKey present,
51 * we need a specific function to return the registered type of the
52 * CFClass implementation, so we can determine which type we have.
55 SecKeyGetCFClassTypeID(void)
59 return gTypes().KeyItem
.typeID
;
61 END_SECAPI1(_kCFRuntimeNotATypeID
)
67 return SecKeyGetCFClassTypeID();
70 static OSStatus
SecKeyCreatePairInternal(
71 SecKeychainRef keychainRef
,
72 CSSM_ALGORITHMS algorithm
,
74 CSSM_CC_HANDLE contextHandle
,
75 CSSM_KEYUSE publicKeyUsage
,
77 CSSM_KEYUSE privateKeyUsage
,
78 uint32 privateKeyAttr
,
79 SecAccessRef initialAccess
,
80 SecKeyRef
* publicKeyRef
,
81 SecKeyRef
* privateKeyRef
)
85 Keychain keychain
= Keychain::optional(keychainRef
);
86 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
87 SecPointer
<KeyItem
> pubItem
, privItem
;
89 Mutex
*keychainMutex
= keychain
->getKeychainMutex();
90 StLock
<Mutex
> _(*keychainMutex
);
92 KeyItem::createPair(keychain
,
104 // Return the generated keys.
106 *publicKeyRef
= pubItem
->handle();
108 *privateKeyRef
= privItem
->handle();
115 SecKeychainRef keychainRef
,
116 CSSM_ALGORITHMS algorithm
,
117 uint32 keySizeInBits
,
118 CSSM_CC_HANDLE contextHandle
,
119 CSSM_KEYUSE publicKeyUsage
,
120 uint32 publicKeyAttr
,
121 CSSM_KEYUSE privateKeyUsage
,
122 uint32 privateKeyAttr
,
123 SecAccessRef initialAccess
,
124 SecKeyRef
* publicKeyRef
,
125 SecKeyRef
* privateKeyRef
)
127 OSStatus result
= SecKeyCreatePairInternal(keychainRef
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
,
128 publicKeyAttr
, privateKeyUsage
, privateKeyAttr
, initialAccess
, publicKeyRef
, privateKeyRef
);
136 SecKeyGetCSSMKey(SecKeyRef key
, const CSSM_KEY
**cssmKey
)
140 Required(cssmKey
) = KeyItem::required(key
)->key();
151 SecKeyGetCSPHandle(SecKeyRef keyRef
, CSSM_CSP_HANDLE
*cspHandle
)
155 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
156 Required(cspHandle
) = keyItem
->csp()->handle();
161 /* deprecated as of 10.8 */
163 SecKeyGetAlgorithmID(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
**algid
)
168 if (!keyRef
|| (CFGetTypeID(keyRef
) != SecKeyGetCFClassTypeID()))
171 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
172 Required(algid
) = &keyItem
->algorithmIdentifier();
179 SecKeyGetAlgorithmId(SecKeyRef key
)
183 return kSecNullAlgorithmID
;
185 else if (CFGetTypeID(key
) != SecKeyGetCFClassTypeID()) {
186 return SecKeyGetAlgorithmIdentifier(key
);
188 // else fall through, we have a CSSM-based key
191 const CSSM_KEY
*cssmKey
;
193 if (SecKeyGetCSSMKey(key
, &cssmKey
) != errSecSuccess
)
194 return kSecNullAlgorithmID
;
196 switch (cssmKey
->KeyHeader
.AlgorithmId
) {
198 return kSecRSAAlgorithmID
;
200 return kSecDSAAlgorithmID
;
201 case CSSM_ALGID_ECDSA
:
202 return kSecECDSAAlgorithmID
;
204 assert(0); /* other algorithms TBA */
205 return kSecNullAlgorithmID
;
210 SecKeyGetStrengthInBits(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
*algid
, unsigned int *strength
)
214 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
215 Required(strength
) = keyItem
->strengthInBits(algid
);
221 SecKeyGetCredentials(
223 CSSM_ACL_AUTHORIZATION_TAG operation
,
224 SecCredentialType credentialType
,
225 const CSSM_ACCESS_CREDENTIALS
**outCredentials
)
229 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
230 Required(outCredentials
) = keyItem
->getCredentials(operation
, credentialType
);
237 SecKeychainRef keychainRef
,
238 const CSSM_KEY
*publicCssmKey
,
239 const CSSM_KEY
*privateCssmKey
,
240 SecAccessRef initialAccess
,
241 SecKeyRef
* publicKey
,
242 SecKeyRef
* privateKey
)
246 Keychain keychain
= Keychain::optional(keychainRef
);
247 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
248 SecPointer
<KeyItem
> pubItem
, privItem
;
250 KeyItem::importPair(keychain
,
251 Required(publicCssmKey
),
252 Required(privateCssmKey
),
257 // Return the generated keys.
259 *publicKey
= pubItem
->handle();
261 *privateKey
= privItem
->handle();
267 SecKeyGenerateWithAttributes(
268 SecKeychainAttributeList
* attrList
,
269 SecKeychainRef keychainRef
,
270 CSSM_ALGORITHMS algorithm
,
271 uint32 keySizeInBits
,
272 CSSM_CC_HANDLE contextHandle
,
273 CSSM_KEYUSE keyUsage
,
275 SecAccessRef initialAccess
,
281 SecPointer
<Access
> theAccess
;
284 keychain
= KeychainImpl::required(keychainRef
);
286 theAccess
= Access::required(initialAccess
);
288 SecPointer
<KeyItem
> item
= KeyItem::generateWithAttributes(attrList
,
297 // Return the generated key.
299 *keyRef
= item
->handle();
306 SecKeychainRef keychainRef
,
307 CSSM_ALGORITHMS algorithm
,
308 uint32 keySizeInBits
,
309 CSSM_CC_HANDLE contextHandle
,
310 CSSM_KEYUSE keyUsage
,
312 SecAccessRef initialAccess
,
315 return SecKeyGenerateWithAttributes(NULL
,
316 keychainRef
, algorithm
, keySizeInBits
,
317 contextHandle
, keyUsage
, keyAttr
,
318 initialAccess
, keyRef
);
323 /* Create a key from supplied data and parameters */
325 SecKeyCreate(CFAllocatorRef allocator
,
326 const SecKeyDescriptor
*keyClass
,
327 const uint8_t *keyData
,
328 CFIndex keyDataLength
,
329 SecKeyEncoding encoding
)
331 SecKeyRef keyRef
= NULL
;
332 OSStatus __secapiresult
;
334 //FIXME: needs implementation
336 __secapiresult
=errSecSuccess
;
338 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
339 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
340 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
341 catch (...) { __secapiresult
=errSecInternalComponent
; }
346 /* Generate a floating key reference from a CSSM_KEY */
348 SecKeyCreateWithCSSMKey(const CSSM_KEY
*cssmKey
,
354 if(cssmKey
->KeyData
.Length
== 0){
355 MacOSError::throwMe(errSecInvalidAttributeKeyLength
);
357 if(cssmKey
->KeyData
.Data
== NULL
){
358 MacOSError::throwMe(errSecInvalidPointer
);
360 CssmClient::CSP
csp(cssmKey
->KeyHeader
.CspId
);
361 CssmClient::Key
key(csp
, *cssmKey
);
362 KeyItem
*item
= new KeyItem(key
);
364 // Return the generated key.
366 *keyRef
= item
->handle();
373 static u_int32_t
ConvertCFStringToInteger(CFStringRef ref
)
380 // figure out the size of the string
381 CFIndex numChars
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref
), kCFStringEncodingUTF8
);
382 char buffer
[numChars
];
383 if (!CFStringGetCString(ref
, buffer
, numChars
, kCFStringEncodingUTF8
))
385 MacOSError::throwMe(errSecParam
);
393 static OSStatus
CheckAlgorithmType(CFDictionaryRef parameters
, CSSM_ALGORITHMS
&algorithms
)
395 // figure out the algorithm to use
396 CFStringRef ktype
= (CFStringRef
) CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
402 if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
403 algorithms
= CSSM_ALGID_RSA
;
404 return errSecSuccess
;
405 } else if(CFEqual(ktype
, kSecAttrKeyTypeECDSA
) ||
406 CFEqual(ktype
, kSecAttrKeyTypeEC
)) {
407 algorithms
= CSSM_ALGID_ECDSA
;
408 return errSecSuccess
;
409 } else if(CFEqual(ktype
, kSecAttrKeyTypeAES
)) {
410 algorithms
= CSSM_ALGID_AES
;
411 return errSecSuccess
;
412 } else if(CFEqual(ktype
, kSecAttrKeyType3DES
)) {
413 algorithms
= CSSM_ALGID_3DES
;
414 return errSecSuccess
;
416 return errSecUnsupportedAlgorithm
;
422 static OSStatus
GetKeySize(CFDictionaryRef parameters
, CSSM_ALGORITHMS algorithms
, uint32
&keySizeInBits
)
425 // get the key size and check it for validity
426 CFTypeRef ref
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
428 keySizeInBits
= kSecDefaultKeySize
;
430 CFTypeID bitSizeType
= CFGetTypeID(ref
);
431 if (bitSizeType
== CFStringGetTypeID())
432 keySizeInBits
= ConvertCFStringToInteger((CFStringRef
) ref
);
433 else if (bitSizeType
== CFNumberGetTypeID())
434 CFNumberGetValue((CFNumberRef
) ref
, kCFNumberSInt32Type
, &keySizeInBits
);
435 else return errSecParam
;
438 switch (algorithms
) {
439 case CSSM_ALGID_ECDSA
:
440 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecp256r1
;
441 if(keySizeInBits
== kSecp192r1
|| keySizeInBits
== kSecp256r1
|| keySizeInBits
== kSecp384r1
|| keySizeInBits
== kSecp521r1
) return errSecSuccess
;
444 if(keySizeInBits
% 8) return errSecParam
;
445 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= 2048;
446 if(keySizeInBits
>= kSecRSAMin
&& keySizeInBits
<= kSecRSAMax
) return errSecSuccess
;
449 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecAES128
;
450 if(keySizeInBits
== kSecAES128
|| keySizeInBits
== kSecAES192
|| keySizeInBits
== kSecAES256
) return errSecSuccess
;
452 case CSSM_ALGID_3DES
:
453 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSec3DES192
;
454 if(keySizeInBits
== kSec3DES192
) return errSecSuccess
;
473 struct ParameterAttribute
475 const CFStringRef
*name
;
481 static ParameterAttribute gAttributes
[] =
488 &kSecAttrIsPermanent
,
492 &kSecAttrApplicationTag
,
496 &kSecAttrEffectiveKeySize
,
525 const int kNumberOfAttributes
= sizeof(gAttributes
) / sizeof(ParameterAttribute
);
527 static OSStatus
ScanDictionaryForParameters(CFDictionaryRef parameters
, void* attributePointers
[])
530 for (i
= 0; i
< kNumberOfAttributes
; ++i
)
532 // see if the corresponding tag exists in the dictionary
533 CFTypeRef value
= CFDictionaryGetValue(parameters
, *(gAttributes
[i
].name
));
536 switch (gAttributes
[i
].type
)
539 // just return the value
540 *(CFTypeRef
*) attributePointers
[i
] = value
;
545 CFBooleanRef bRef
= (CFBooleanRef
) value
;
546 *(bool*) attributePointers
[i
] = CFBooleanGetValue(bRef
);
552 CFNumberRef nRef
= (CFNumberRef
) value
;
553 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, attributePointers
[i
]);
560 return errSecSuccess
;
565 static OSStatus
GetKeyParameters(CFDictionaryRef parameters
, int keySize
, bool isPublic
, CSSM_KEYUSE
&keyUse
, uint32
&attrs
, CFTypeRef
&labelRef
, CFDataRef
&applicationTagRef
)
567 // establish default values
569 bool isPermanent
= false;
570 applicationTagRef
= NULL
;
571 CFTypeRef effectiveKeySize
= NULL
;
572 bool canDecrypt
= isPublic
? false : true;
573 bool canEncrypt
= !canDecrypt
;
574 bool canDerive
= true;
575 bool canSign
= isPublic
? false : true;
576 bool canVerify
= !canSign
;
577 bool canUnwrap
= isPublic
? false : true;
578 attrs
= CSSM_KEYATTR_EXTRACTABLE
;
581 void* attributePointers
[] = {&labelRef
, &isPermanent
, &applicationTagRef
, &effectiveKeySize
, &canEncrypt
, &canDecrypt
,
582 &canDerive
, &canSign
, &canVerify
, &canUnwrap
};
584 // look for modifiers in the general dictionary
585 OSStatus result
= ScanDictionaryForParameters(parameters
, attributePointers
);
586 if (result
!= errSecSuccess
)
591 // see if we have anything which modifies the defaults
595 key
= kSecPublicKeyAttrs
;
599 key
= kSecPrivateKeyAttrs
;
602 CFTypeRef dType
= CFDictionaryGetValue(parameters
, key
);
605 // this had better be a dictionary
606 if (CFGetTypeID(dType
) != CFDictionaryGetTypeID())
611 // pull any additional parameters out of this dictionary
612 result
= ScanDictionaryForParameters((CFDictionaryRef
)dType
, attributePointers
);
613 if (result
!= errSecSuccess
)
619 // figure out the key usage
623 keyUse
|= CSSM_KEYUSE_DECRYPT
;
628 keyUse
|= CSSM_KEYUSE_ENCRYPT
;
633 keyUse
|= CSSM_KEYUSE_DERIVE
;
638 keyUse
|= CSSM_KEYUSE_SIGN
;
643 keyUse
|= CSSM_KEYUSE_VERIFY
;
648 keyUse
|= CSSM_KEYUSE_UNWRAP
;
651 // public key is always extractable;
652 // private key is extractable by default unless explicitly set to false
653 CFTypeRef value
= NULL
;
654 if (!isPublic
&& CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
) && value
)
656 Boolean keyIsExtractable
= CFEqual(kCFBooleanTrue
, value
);
657 if (!keyIsExtractable
)
661 attrs
|= CSSM_KEYATTR_PERMANENT
;
663 return errSecSuccess
;
668 static OSStatus
MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters
,
669 CSSM_ALGORITHMS
&algorithms
,
670 uint32
&keySizeInBits
,
671 CSSM_KEYUSE
&publicKeyUse
,
672 uint32
&publicKeyAttr
,
673 CFTypeRef
&publicKeyLabelRef
,
674 CFDataRef
&publicKeyAttributeTagRef
,
675 CSSM_KEYUSE
&privateKeyUse
,
676 uint32
&privateKeyAttr
,
677 CFTypeRef
&privateKeyLabelRef
,
678 CFDataRef
&privateKeyAttributeTagRef
,
679 SecAccessRef
&initialAccess
)
683 result
= CheckAlgorithmType(parameters
, algorithms
);
684 if (result
!= errSecSuccess
)
689 result
= GetKeySize(parameters
, algorithms
, keySizeInBits
);
690 if (result
!= errSecSuccess
)
695 result
= GetKeyParameters(parameters
, keySizeInBits
, false, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
696 if (result
!= errSecSuccess
)
701 result
= GetKeyParameters(parameters
, keySizeInBits
, true, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
702 if (result
!= errSecSuccess
)
707 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&initialAccess
))
709 initialAccess
= NULL
;
711 else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess
))
716 return errSecSuccess
;
721 static OSStatus
SetKeyLabelAndTag(SecKeyRef keyRef
, CFTypeRef label
, CFDataRef tag
)
734 if (numToModify
== 0)
736 return errSecSuccess
;
739 SecKeychainAttributeList attrList
;
740 SecKeychainAttribute attributes
[numToModify
];
746 if (CFStringGetTypeID() == CFGetTypeID(label
)) {
747 CFStringRef label_string
= static_cast<CFStringRef
>(label
);
748 attributes
[i
].tag
= kSecKeyPrintName
;
749 attributes
[i
].data
= (void*) CFStringGetCStringPtr(label_string
, kCFStringEncodingUTF8
);
750 if (NULL
== attributes
[i
].data
) {
751 CFIndex buffer_length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string
), kCFStringEncodingUTF8
);
752 attributes
[i
].data
= alloca((size_t)buffer_length
);
753 if (NULL
== attributes
[i
].data
) {
754 UnixError::throwMe(ENOMEM
);
756 if (!CFStringGetCString(label_string
, static_cast<char *>(attributes
[i
].data
), buffer_length
, kCFStringEncodingUTF8
)) {
757 MacOSError::throwMe(errSecParam
);
760 attributes
[i
].length
= (UInt32
)strlen(static_cast<char *>(attributes
[i
].data
));
761 } else if (CFDataGetTypeID() == CFGetTypeID(label
)) {
762 // 10.6 bug compatibility
763 CFDataRef label_data
= static_cast<CFDataRef
>(label
);
764 attributes
[i
].tag
= kSecKeyLabel
;
765 attributes
[i
].data
= (void*) CFDataGetBytePtr(label_data
);
766 attributes
[i
].length
= (UInt32
)CFDataGetLength(label_data
);
768 MacOSError::throwMe(errSecParam
);
775 attributes
[i
].tag
= kSecKeyApplicationTag
;
776 attributes
[i
].data
= (void*) CFDataGetBytePtr(tag
);
777 attributes
[i
].length
= (UInt32
)CFDataGetLength(tag
);
781 attrList
.count
= numToModify
;
782 attrList
.attr
= attributes
;
784 return SecKeychainItemModifyAttributesAndData((SecKeychainItemRef
) keyRef
, &attrList
, 0, NULL
);
790 /* Generate a private/public keypair. */
793 CFDictionaryRef parameters
,
794 SecKeyRef
*publicKey
,
795 SecKeyRef
*privateKey
)
799 Required(parameters
);
801 Required(privateKey
);
803 CSSM_ALGORITHMS algorithms
;
804 uint32 keySizeInBits
;
805 CSSM_KEYUSE publicKeyUse
;
806 uint32 publicKeyAttr
;
807 CFTypeRef publicKeyLabelRef
;
808 CFDataRef publicKeyAttributeTagRef
;
809 CSSM_KEYUSE privateKeyUse
;
810 uint32 privateKeyAttr
;
811 CFTypeRef privateKeyLabelRef
;
812 CFDataRef privateKeyAttributeTagRef
;
813 SecAccessRef initialAccess
;
814 SecKeychainRef keychain
;
816 OSStatus result
= MakeKeyGenParametersFromDictionary(parameters
, algorithms
, keySizeInBits
, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
,
817 publicKeyAttributeTagRef
, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
,
820 if (result
!= errSecSuccess
)
825 // verify keychain parameter
827 if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
))
829 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
))
832 // do the key generation
833 result
= SecKeyCreatePair(keychain
, algorithms
, keySizeInBits
, 0, publicKeyUse
, publicKeyAttr
, privateKeyUse
, privateKeyAttr
, initialAccess
, publicKey
, privateKey
);
834 if (result
!= errSecSuccess
)
839 // set the label and print attributes on the keys
840 SetKeyLabelAndTag(*publicKey
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
841 SetKeyLabelAndTag(*privateKey
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
852 const uint8_t *dataToSign
,
853 size_t dataToSignLen
,
860 SecPointer
<KeyItem
> keyItem(KeyItem::required(key
));
863 dataInput
.Data
= (uint8_t*) dataToSign
;
864 dataInput
.Length
= dataToSignLen
;
868 output
.Length
= *sigLen
;
870 const AccessCredentials
* credentials
= keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN
, kSecCredentialTypeDefault
);
872 keyItem
->RawSign(padding
, dataInput
, credentials
, output
);
873 *sigLen
= output
.Length
;
878 OSStatus
SecKeyRawVerifyOSX(
879 SecKeyRef key
, /* Public key */
880 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
881 const uint8_t *signedData
, /* signature over this data */
882 size_t signedDataLen
, /* length of dataToSign */
883 const uint8_t *sig
, /* signature */
886 return SecKeyRawVerify(key
,padding
,signedData
,signedDataLen
,sig
,sigLen
);
894 const uint8_t *signedData
,
895 size_t signedDataLen
,
903 SecPointer
<KeyItem
> keyItem(KeyItem::required(key
));
906 dataInput
.Data
= (uint8_t*) signedData
;
907 dataInput
.Length
= signedDataLen
;
910 signature
.Data
= (uint8_t*) sig
;
911 signature
.Length
= sigLen
;
913 const AccessCredentials
* credentials
= keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ANY
, kSecCredentialTypeDefault
);
915 keyItem
->RawVerify(padding
, dataInput
, credentials
, signature
);
925 const uint8_t *plainText
,
928 size_t *cipherTextLen
)
932 SecPointer
<KeyItem
> keyItem(KeyItem::required(key
));
933 CSSM_DATA inData
, outData
;
934 inData
.Data
= (uint8
*) plainText
;
935 inData
.Length
= plainTextLen
;
936 outData
.Data
= cipherText
;
937 outData
.Length
= *cipherTextLen
;
939 const AccessCredentials
* credentials
= keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT
, kSecCredentialTypeDefault
);
941 keyItem
->Encrypt(padding
, inData
, credentials
, outData
);
942 *cipherTextLen
= outData
.Length
;
950 SecKeyRef key
, /* Private key */
951 SecPadding padding
, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
952 const uint8_t *cipherText
,
953 size_t cipherTextLen
, /* length of cipherText */
955 size_t *plainTextLen
) /* IN/OUT */
959 SecPointer
<KeyItem
> keyItem(KeyItem::required(key
));
960 CSSM_DATA inData
, outData
;
961 inData
.Data
= (uint8
*) cipherText
;
962 inData
.Length
= cipherTextLen
;
963 outData
.Data
= plainText
;
964 outData
.Length
= *plainTextLen
;
966 const AccessCredentials
* credentials
= keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT
, kSecCredentialTypeDefault
);
968 keyItem
->Decrypt(padding
, inData
, credentials
, outData
);
969 *plainTextLen
= outData
.Length
;
976 SecKeyGetBlockSize(SecKeyRef key
)
978 size_t blockSize
= 0;
979 OSStatus __secapiresult
;
981 CSSM_KEY cssmKey
= KeyItem::required(key
)->key();
982 switch(cssmKey
.KeyHeader
.AlgorithmId
)
986 blockSize
= cssmKey
.KeyHeader
.LogicalKeySizeInBits
/ 8;
988 case CSSM_ALGID_ECDSA
:
990 /* Block size is up to 9 bytes of DER encoding for sequence of 2 integers,
991 * plus both coordinates for the point used */
992 #define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8)
993 #define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1)
994 size_t coordSize
= ECDSA_MAX_COORD_SIZE_IN_BYTES(cssmKey
.KeyHeader
.LogicalKeySizeInBits
);
995 assert(coordSize
< 256); /* size must fit in a byte for DER */
996 size_t coordDERLen
= (coordSize
> 127) ? 2 : 1;
997 size_t coordLen
= 1 + coordDERLen
+ coordSize
;
999 size_t pointSize
= 2 * coordLen
;
1000 assert(pointSize
< 256); /* size must fit in a byte for DER */
1001 size_t pointDERLen
= (pointSize
> 127) ? 2 : 1;
1002 size_t pointLen
= 1 + pointDERLen
+ pointSize
;
1004 blockSize
= pointLen
;
1007 case CSSM_ALGID_AES
:
1008 blockSize
= 16; /* all AES keys use 128-bit blocks */
1010 case CSSM_ALGID_DES
:
1011 case CSSM_ALGID_3DES_3KEY
:
1012 blockSize
= 8; /* all DES keys use 64-bit blocks */
1015 assert(0); /* some other key algorithm */
1016 blockSize
= 16; /* FIXME: revisit this */
1019 __secapiresult
=errSecSuccess
;
1021 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
1022 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
1023 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
1024 catch (...) { __secapiresult
=errSecInternalComponent
; }
1034 utilGetStringFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, CFTypeRef defaultValue
)
1036 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1037 if (value
!= NULL
) return value
;
1038 return defaultValue
;
1042 utilGetNumberFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t defaultValue
)
1044 uint32_t integerValue
;
1045 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1046 if (value
!= NULL
) {
1047 CFNumberRef nRef
= (CFNumberRef
) value
;
1048 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, &integerValue
);
1049 return integerValue
;
1051 return defaultValue
;
1055 utilGetMaskValFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t maskValue
)
1057 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1058 if (value
!= NULL
) {
1059 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1060 if(CFBooleanGetValue(bRef
)) return maskValue
;
1066 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters
, CSSM_ALGORITHMS
*algorithm
, uint32
*keySizeInBits
, CSSM_KEYUSE
*keyUsage
, CSSM_KEYCLASS
*keyClass
)
1068 CFTypeRef algorithmDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeAES
);
1069 CFTypeRef keyClassDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1071 if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeAES
)) {
1072 *algorithm
= CSSM_ALGID_AES
;
1073 *keySizeInBits
= 128;
1074 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1075 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDES
)) {
1076 *algorithm
= CSSM_ALGID_DES
;
1077 *keySizeInBits
= 128;
1078 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1079 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyType3DES
)) {
1080 *algorithm
= CSSM_ALGID_3DES_3KEY_EDE
;
1081 *keySizeInBits
= 128;
1082 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1083 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC4
)) {
1084 *algorithm
= CSSM_ALGID_RC4
;
1085 *keySizeInBits
= 128;
1086 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1087 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC2
)) {
1088 *algorithm
= CSSM_ALGID_RC2
;
1089 *keySizeInBits
= 128;
1090 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1091 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeCAST
)) {
1092 *algorithm
= CSSM_ALGID_CAST
;
1093 *keySizeInBits
= 128;
1094 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1095 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRSA
)) {
1096 *algorithm
= CSSM_ALGID_RSA
;
1097 *keySizeInBits
= 128;
1098 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1099 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDSA
)) {
1100 *algorithm
= CSSM_ALGID_DSA
;
1101 *keySizeInBits
= 128;
1102 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1103 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeECDSA
) ||
1104 CFEqual(algorithmDictValue
, kSecAttrKeyTypeEC
)) {
1105 *algorithm
= CSSM_ALGID_ECDSA
;
1106 *keySizeInBits
= 128;
1107 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1109 *algorithm
= CSSM_ALGID_AES
;
1110 *keySizeInBits
= 128;
1111 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1114 if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPublic
)) {
1115 *keyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
1116 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPrivate
)) {
1117 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1118 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassSymmetric
)) {
1119 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1122 *keySizeInBits
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, *keySizeInBits
);
1123 *keyUsage
= utilGetMaskValFromCFDict(parameters
, kSecAttrCanEncrypt
, CSSM_KEYUSE_ENCRYPT
) |
1124 utilGetMaskValFromCFDict(parameters
, kSecAttrCanDecrypt
, CSSM_KEYUSE_DECRYPT
) |
1125 utilGetMaskValFromCFDict(parameters
, kSecAttrCanWrap
, CSSM_KEYUSE_WRAP
) |
1126 utilGetMaskValFromCFDict(parameters
, kSecAttrCanUnwrap
, CSSM_KEYUSE_UNWRAP
);
1129 if(*keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
|| *keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
) {
1130 *keyUsage
|= utilGetMaskValFromCFDict(parameters
, kSecAttrCanSign
, CSSM_KEYUSE_SIGN
) |
1131 utilGetMaskValFromCFDict(parameters
, kSecAttrCanVerify
, CSSM_KEYUSE_VERIFY
);
1134 if(*keyUsage
== 0) {
1135 switch (*keyClass
) {
1136 case CSSM_KEYCLASS_PRIVATE_KEY
:
1137 *keyUsage
= CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
;
1139 case CSSM_KEYCLASS_PUBLIC_KEY
:
1140 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
;
1143 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
;
1150 utilCopyDefaultKeyLabel(void)
1152 // generate a default label from the current date
1153 CFDateRef dateNow
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent());
1154 CFStringRef defaultLabel
= CFCopyDescription(dateNow
);
1157 return defaultLabel
;
1161 SecKeyGenerateSymmetric(CFDictionaryRef parameters
, CFErrorRef
*error
)
1163 OSStatus result
= errSecParam
; // default result for an early exit
1164 SecKeyRef key
= NULL
;
1165 SecKeychainRef keychain
= NULL
;
1166 SecAccessRef access
;
1168 CFStringRef appLabel
;
1170 CFStringRef dateLabel
= NULL
;
1172 CSSM_ALGORITHMS algorithm
;
1173 uint32 keySizeInBits
;
1174 CSSM_KEYUSE keyUsage
;
1175 uint32 keyAttr
= CSSM_KEYATTR_RETURN_DEFAULT
;
1176 CSSM_KEYCLASS keyClass
;
1178 Boolean isPermanent
;
1179 Boolean isExtractable
;
1181 // verify keychain parameter
1182 if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
))
1184 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1191 // verify permanent parameter
1192 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsPermanent
, (const void **)&value
))
1193 isPermanent
= false;
1194 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1197 isPermanent
= CFEqual(kCFBooleanTrue
, value
);
1199 if (keychain
== NULL
) {
1200 // no keychain was specified, so use the default keychain
1201 result
= SecKeychainCopyDefault(&keychain
);
1203 keyAttr
|= CSSM_KEYATTR_PERMANENT
;
1206 // verify extractable parameter
1207 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
))
1208 isExtractable
= true; // default to extractable if value not specified
1209 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1212 isExtractable
= CFEqual(kCFBooleanTrue
, value
);
1214 keyAttr
|= CSSM_KEYATTR_EXTRACTABLE
;
1216 // verify access parameter
1217 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&access
))
1219 else if (SecAccessGetTypeID() != CFGetTypeID(access
))
1222 // verify label parameter
1223 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrLabel
, (const void **)&label
))
1224 label
= (dateLabel
= utilCopyDefaultKeyLabel()); // no label provided, so use default
1225 else if (CFStringGetTypeID() != CFGetTypeID(label
))
1228 // verify application label parameter
1229 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationLabel
, (const void **)&appLabel
))
1230 appLabel
= (dateLabel
) ? dateLabel
: (dateLabel
= utilCopyDefaultKeyLabel());
1231 else if (CFStringGetTypeID() != CFGetTypeID(appLabel
))
1234 // verify application tag parameter
1235 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationTag
, (const void **)&appTag
))
1237 else if (CFStringGetTypeID() != CFGetTypeID(appTag
))
1240 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1243 // the generated key will not be stored in any keychain
1244 result
= SecKeyGenerate(keychain
, algorithm
, keySizeInBits
, 0, keyUsage
, keyAttr
, access
, &key
);
1247 // we can set the label attributes on the generated key if it's a keychain item
1248 size_t labelBufLen
= (label
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label
), kCFStringEncodingUTF8
) + 1 : 0;
1249 char *labelBuf
= (char *)malloc(labelBufLen
);
1250 size_t appLabelBufLen
= (appLabel
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel
), kCFStringEncodingUTF8
) + 1 : 0;
1251 char *appLabelBuf
= (char *)malloc(appLabelBufLen
);
1252 size_t appTagBufLen
= (appTag
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag
), kCFStringEncodingUTF8
) + 1 : 0;
1253 char *appTagBuf
= (char *)malloc(appTagBufLen
);
1255 if (label
&& !CFStringGetCString(label
, labelBuf
, labelBufLen
-1, kCFStringEncodingUTF8
))
1257 if (appLabel
&& !CFStringGetCString(appLabel
, appLabelBuf
, appLabelBufLen
-1, kCFStringEncodingUTF8
))
1259 if (appTag
&& !CFStringGetCString(appTag
, appTagBuf
, appTagBufLen
-1, kCFStringEncodingUTF8
))
1262 SecKeychainAttribute attrs
[] = {
1263 { kSecKeyPrintName
, (UInt32
)strlen(labelBuf
), (char *)labelBuf
},
1264 { kSecKeyLabel
, (UInt32
)strlen(appLabelBuf
), (char *)appLabelBuf
},
1265 { kSecKeyApplicationTag
, (UInt32
)strlen(appTagBuf
), (char *)appTagBuf
} };
1266 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
1267 if (!appTag
) --attributes
.count
;
1269 result
= SecKeyGenerateWithAttributes(&attributes
,
1270 keychain
, algorithm
, keySizeInBits
, 0,
1271 keyUsage
, keyAttr
, access
, &key
);
1279 if (result
&& error
) {
1280 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, result
, NULL
);
1283 CFRelease(dateLabel
);
1285 CFRelease(keychain
);
1293 SecKeyCreateFromData(CFDictionaryRef parameters
, CFDataRef keyData
, CFErrorRef
*error
)
1295 CSSM_ALGORITHMS algorithm
;
1296 uint32 keySizeInBits
;
1297 CSSM_KEYUSE keyUsage
;
1298 CSSM_KEYCLASS keyClass
;
1301 if(keyData
== NULL
|| CFDataGetLength(keyData
) == 0){
1302 MacOSError::throwMe(errSecUnsupportedKeySize
);
1305 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1307 CSSM_CSP_HANDLE cspHandle
= cuCspStartup(CSSM_FALSE
); // TRUE => CSP, FALSE => CSPDL
1309 SecKeyImportExportParameters iparam
;
1310 memset(&iparam
, 0, sizeof(iparam
));
1311 iparam
.keyUsage
= keyUsage
;
1313 SecExternalItemType itype
;
1315 case CSSM_KEYCLASS_PRIVATE_KEY
:
1316 itype
= kSecItemTypePrivateKey
;
1318 case CSSM_KEYCLASS_PUBLIC_KEY
:
1319 itype
= kSecItemTypePublicKey
;
1321 case CSSM_KEYCLASS_SESSION_KEY
:
1322 itype
= kSecItemTypeSessionKey
;
1325 itype
= kSecItemTypeUnknown
;
1329 CFMutableArrayRef ka
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1330 // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful.
1331 crtn
= impExpImportRawKey(keyData
, kSecFormatUnknown
, itype
, algorithm
, NULL
, cspHandle
, 0, NULL
, NULL
, ka
);
1332 if (crtn
== CSSM_OK
&& CFArrayGetCount((CFArrayRef
)ka
)) {
1333 SecKeyRef sk
= (SecKeyRef
)CFArrayGetValueAtIndex((CFArrayRef
)ka
, 0);
1339 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, crtn
? crtn
: CSSM_ERRCODE_INTERNAL_ERROR
, NULL
);
1347 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable
, dispatch_queue_t deliveryQueue
,
1348 SecKeyGeneratePairBlock result
)
1350 CFDictionaryRef parameters
= CFDictionaryCreateCopy(NULL
, parametersWhichMightBeMutiable
);
1351 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
1352 SecKeyRef publicKey
= NULL
;
1353 SecKeyRef privateKey
= NULL
;
1354 OSStatus status
= SecKeyGeneratePair(parameters
, &publicKey
, &privateKey
);
1355 dispatch_async(deliveryQueue
, ^{
1356 CFErrorRef error
= NULL
;
1357 if (errSecSuccess
!= status
) {
1358 error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, NULL
);
1360 result(publicKey
, privateKey
, error
);
1365 CFRelease(publicKey
);
1368 CFRelease(privateKey
);
1370 CFRelease(parameters
);
1375 static inline void utilClearAndFree(void *p
, size_t len
) {
1377 if(len
) bzero(p
, len
);
1383 SecKeyDeriveFromPassword(CFStringRef password
, CFDictionaryRef parameters
, CFErrorRef
*error
)
1385 CCPBKDFAlgorithm algorithm
;
1386 CFIndex passwordLen
= 0;
1387 CFDataRef keyData
= NULL
;
1388 char *thePassword
= NULL
;
1389 uint8_t *salt
= NULL
;
1390 uint8_t *derivedKey
= NULL
;
1391 size_t saltLen
= 0, derivedKeyLen
= 0;
1393 CFDataRef saltDictValue
, algorithmDictValue
;
1394 SecKeyRef retval
= NULL
;
1396 /* Pick Values from parameters */
1398 if((saltDictValue
= (CFDataRef
) CFDictionaryGetValue(parameters
, kSecAttrSalt
)) == NULL
) {
1399 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecMissingAlgorithmParms
, NULL
);
1403 derivedKeyLen
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, 128);
1404 // This value come in bits but the rest of the code treats it as bytes
1407 algorithmDictValue
= (CFDataRef
) utilGetStringFromCFDict(parameters
, kSecAttrPRF
, kSecAttrPRFHmacAlgSHA256
);
1409 rounds
= utilGetNumberFromCFDict(parameters
, kSecAttrRounds
, 0);
1411 /* Convert any remaining parameters and get the password bytes */
1413 saltLen
= CFDataGetLength(saltDictValue
);
1414 if((salt
= (uint8_t *) malloc(saltLen
)) == NULL
) {
1415 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
1419 CFDataGetBytes(saltDictValue
, CFRangeMake(0, saltLen
), (UInt8
*) salt
);
1421 passwordLen
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1;
1422 if((thePassword
= (char *) malloc(passwordLen
)) == NULL
) {
1423 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
1426 CFStringGetBytes(password
, CFRangeMake(0, CFStringGetLength(password
)), kCFStringEncodingUTF8
, '?', FALSE
, (UInt8
*)thePassword
, passwordLen
, &passwordLen
);
1428 if((derivedKey
= (uint8_t *) malloc(derivedKeyLen
)) == NULL
) {
1429 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
1433 if(algorithmDictValue
== NULL
) {
1434 algorithm
= kCCPRFHmacAlgSHA1
; /* default */
1435 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA1
)) {
1436 algorithm
= kCCPRFHmacAlgSHA1
;
1437 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA224
)) {
1438 algorithm
= kCCPRFHmacAlgSHA224
;
1439 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA256
)) {
1440 algorithm
= kCCPRFHmacAlgSHA256
;
1441 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA384
)) {
1442 algorithm
= kCCPRFHmacAlgSHA384
;
1443 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA512
)) {
1444 algorithm
= kCCPRFHmacAlgSHA512
;
1446 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidAlgorithmParms
, NULL
);
1451 rounds
= 33333; // we need to pass back a consistent value since there's no way to record the round count.
1454 if(CCKeyDerivationPBKDF(kCCPBKDF2
, thePassword
, passwordLen
, salt
, saltLen
, algorithm
, rounds
, derivedKey
, derivedKeyLen
)) {
1455 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
1459 if((keyData
= CFDataCreate(NULL
, derivedKey
, derivedKeyLen
)) != NULL
) {
1460 retval
= SecKeyCreateFromData(parameters
, keyData
, error
);
1463 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
1467 utilClearAndFree(salt
, saltLen
);
1468 utilClearAndFree(thePassword
, passwordLen
);
1469 utilClearAndFree(derivedKey
, derivedKeyLen
);
1474 SecKeyWrapSymmetric(SecKeyRef keyToWrap
, SecKeyRef wrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
1476 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);
1481 SecKeyUnwrapSymmetric(CFDataRef
*keyToUnwrap
, SecKeyRef unwrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
1483 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);
1488 /* iOS SecKey shim functions */
1490 #define MAX_DIGEST_LEN (CC_SHA512_DIGEST_LENGTH)
1492 /* Currently length of SHA512 oid + 1 */
1493 #define MAX_OID_LEN (10)
1495 #define DER_MAX_DIGEST_INFO_LEN (10 + MAX_DIGEST_LEN + MAX_OID_LEN)
1497 /* Encode the digestInfo header into digestInfo and return the offset from
1498 digestInfo at which to put the actual digest. Returns 0 if digestInfo
1499 won't fit within digestInfoLength bytes.
1503 0x06, oid.Len, oid.Data,
1508 static size_t DEREncodeDigestInfoPrefix(const SecAsn1Oid
*oid
,
1509 size_t digestLength
,
1510 uint8_t *digestInfo
,
1511 size_t digestInfoLength
)
1513 size_t algIdLen
= oid
->Length
+ 4;
1514 size_t topLen
= algIdLen
+ digestLength
+ 4;
1515 size_t totalLen
= topLen
+ 2;
1517 if (totalLen
> digestInfoLength
) {
1522 digestInfo
[ix
++] = (SEC_ASN1_SEQUENCE
| SEC_ASN1_CONSTRUCTED
);
1523 digestInfo
[ix
++] = topLen
;
1524 digestInfo
[ix
++] = (SEC_ASN1_SEQUENCE
| SEC_ASN1_CONSTRUCTED
);
1525 digestInfo
[ix
++] = algIdLen
;
1526 digestInfo
[ix
++] = SEC_ASN1_OBJECT_ID
;
1527 digestInfo
[ix
++] = oid
->Length
;
1528 memcpy(&digestInfo
[ix
], oid
->Data
, oid
->Length
);
1530 digestInfo
[ix
++] = SEC_ASN1_NULL
;
1531 digestInfo
[ix
++] = 0;
1532 digestInfo
[ix
++] = SEC_ASN1_OCTET_STRING
;
1533 digestInfo
[ix
++] = digestLength
;
1538 static OSStatus
SecKeyGetDigestInfo(SecKeyRef key
, const SecAsn1AlgId
*algId
,
1539 const uint8_t *data
, size_t dataLen
, bool digestData
,
1540 uint8_t *digestInfo
, size_t *digestInfoLen
/* IN/OUT */)
1542 unsigned char *(*digestFcn
)(const void *, CC_LONG
, unsigned char *);
1543 CFIndex keyAlgID
= kSecNullAlgorithmID
;
1544 const SecAsn1Oid
*digestOid
;
1548 /* Since these oids all have the same prefix, use switch. */
1549 if ((algId
->algorithm
.Length
== CSSMOID_RSA
.Length
) &&
1550 !memcmp(algId
->algorithm
.Data
, CSSMOID_RSA
.Data
,
1551 algId
->algorithm
.Length
- 1)) {
1552 keyAlgID
= kSecRSAAlgorithmID
;
1553 switch (algId
->algorithm
.Data
[algId
->algorithm
.Length
- 1]) {
1555 case 2: /* oidMD2WithRSA */
1557 digestLen
= CC_MD2_DIGEST_LENGTH
;
1558 digestOid
= &CSSMOID_MD2
;
1560 case 3: /* oidMD4WithRSA */
1562 digestLen
= CC_MD4_DIGEST_LENGTH
;
1563 digestOid
= &CSSMOID_MD4
;
1565 case 4: /* oidMD5WithRSA */
1567 digestLen
= CC_MD5_DIGEST_LENGTH
;
1568 digestOid
= &CSSMOID_MD5
;
1571 case 5: /* oidSHA1WithRSA */
1572 digestFcn
= CC_SHA1
;
1573 digestLen
= CC_SHA1_DIGEST_LENGTH
;
1574 digestOid
= &CSSMOID_SHA1
;
1576 case 11: /* oidSHA256WithRSA */
1577 digestFcn
= CC_SHA256
;
1578 digestLen
= CC_SHA256_DIGEST_LENGTH
;
1579 digestOid
= &CSSMOID_SHA256
;
1581 case 12: /* oidSHA384WithRSA */
1583 digestFcn
= CC_SHA384
;
1584 digestLen
= CC_SHA384_DIGEST_LENGTH
;
1585 digestOid
= &CSSMOID_SHA384
;
1587 case 13: /* oidSHA512WithRSA */
1588 digestFcn
= CC_SHA512
;
1589 digestLen
= CC_SHA512_DIGEST_LENGTH
;
1590 digestOid
= &CSSMOID_SHA512
;
1592 case 14: /* oidSHA224WithRSA */
1593 digestFcn
= CC_SHA224
;
1594 digestLen
= CC_SHA224_DIGEST_LENGTH
;
1595 digestOid
= &CSSMOID_SHA224
;
1598 secdebug("key", "unsupported rsa signature algorithm");
1599 return errSecUnsupportedAlgorithm
;
1601 } else if ((algId
->algorithm
.Length
== CSSMOID_ECDSA_WithSHA224
.Length
) &&
1602 !memcmp(algId
->algorithm
.Data
, CSSMOID_ECDSA_WithSHA224
.Data
,
1603 algId
->algorithm
.Length
- 1)) {
1604 keyAlgID
= kSecECDSAAlgorithmID
;
1605 switch (algId
->algorithm
.Data
[algId
->algorithm
.Length
- 1]) {
1606 case 1: /* oidSHA224WithECDSA */
1607 digestFcn
= CC_SHA224
;
1608 digestLen
= CC_SHA224_DIGEST_LENGTH
;
1610 case 2: /* oidSHA256WithECDSA */
1611 digestFcn
= CC_SHA256
;
1612 digestLen
= CC_SHA256_DIGEST_LENGTH
;
1614 case 3: /* oidSHA384WithECDSA */
1616 digestFcn
= CC_SHA384
;
1617 digestLen
= CC_SHA384_DIGEST_LENGTH
;
1619 case 4: /* oidSHA512WithECDSA */
1620 digestFcn
= CC_SHA512
;
1621 digestLen
= CC_SHA512_DIGEST_LENGTH
;
1624 secdebug("key", "unsupported ecdsa signature algorithm");
1625 return errSecUnsupportedAlgorithm
;
1627 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_ECDSA_WithSHA1
)) {
1628 keyAlgID
= kSecECDSAAlgorithmID
;
1629 digestFcn
= CC_SHA1
;
1630 digestLen
= CC_SHA1_DIGEST_LENGTH
;
1631 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_SHA1
)) {
1632 digestFcn
= CC_SHA1
;
1633 digestLen
= CC_SHA1_DIGEST_LENGTH
;
1634 digestOid
= &CSSMOID_SHA1
;
1635 } else if ((algId
->algorithm
.Length
== CSSMOID_SHA224
.Length
) &&
1636 !memcmp(algId
->algorithm
.Data
, CSSMOID_SHA224
.Data
, algId
->algorithm
.Length
- 1))
1638 switch (algId
->algorithm
.Data
[algId
->algorithm
.Length
- 1]) {
1639 case 4: /* OID_SHA224 */
1640 digestFcn
= CC_SHA224
;
1641 digestLen
= CC_SHA224_DIGEST_LENGTH
;
1642 digestOid
= &CSSMOID_SHA224
;
1644 case 1: /* OID_SHA256 */
1645 digestFcn
= CC_SHA256
;
1646 digestLen
= CC_SHA256_DIGEST_LENGTH
;
1647 digestOid
= &CSSMOID_SHA256
;
1649 case 2: /* OID_SHA384 */
1651 digestFcn
= CC_SHA384
;
1652 digestLen
= CC_SHA384_DIGEST_LENGTH
;
1653 digestOid
= &CSSMOID_SHA384
;
1655 case 3: /* OID_SHA512 */
1656 digestFcn
= CC_SHA512
;
1657 digestLen
= CC_SHA512_DIGEST_LENGTH
;
1658 digestOid
= &CSSMOID_SHA512
;
1661 secdebug("key", "unsupported sha-2 signature algorithm");
1662 return errSecUnsupportedAlgorithm
;
1664 } else if (SecAsn1OidCompare(&algId
->algorithm
, &CSSMOID_MD5
)) {
1666 digestLen
= CC_MD5_DIGEST_LENGTH
;
1667 digestOid
= &CSSMOID_MD5
;
1669 secdebug("key", "unsupported digesting algorithm");
1670 return errSecUnsupportedAlgorithm
;
1673 /* check key is appropriate for signature (superfluous for digest only oid) */
1675 CFIndex supportedKeyAlgID
= kSecNullAlgorithmID
;
1676 #if TARGET_OS_EMBEDDED
1677 supportedKeyAlgID
= SecKeyGetAlgorithmID(key
);
1679 const CSSM_KEY
* temporaryKey
;
1680 SecKeyGetCSSMKey(key
, &temporaryKey
);
1681 CSSM_ALGORITHMS tempAlgorithm
= temporaryKey
->KeyHeader
.AlgorithmId
;
1682 if (CSSM_ALGID_RSA
== tempAlgorithm
) {
1683 supportedKeyAlgID
= kSecRSAAlgorithmID
;
1684 } else if (CSSM_ALGID_ECDSA
== tempAlgorithm
) {
1685 supportedKeyAlgID
= kSecECDSAAlgorithmID
;
1689 if (keyAlgID
== kSecNullAlgorithmID
) {
1690 keyAlgID
= supportedKeyAlgID
;
1692 else if (keyAlgID
!= supportedKeyAlgID
) {
1693 return errSecUnsupportedAlgorithm
;
1698 case kSecRSAAlgorithmID
:
1699 offset
= DEREncodeDigestInfoPrefix(digestOid
, digestLen
,
1700 digestInfo
, *digestInfoLen
);
1702 return errSecBufferTooSmall
;
1704 case kSecDSAAlgorithmID
:
1705 if (digestOid
!= &CSSMOID_SHA1
)
1706 return errSecUnsupportedAlgorithm
;
1708 case kSecECDSAAlgorithmID
:
1711 secdebug("key", "unsupported signature algorithm");
1712 return errSecUnsupportedAlgorithm
;
1716 if(dataLen
>UINT32_MAX
) /* Check for overflow with CC_LONG cast */
1718 digestFcn(data
, (CC_LONG
)dataLen
, &digestInfo
[offset
]);
1719 *digestInfoLen
= offset
+ digestLen
;
1721 if (dataLen
!= digestLen
)
1723 memcpy(&digestInfo
[offset
], data
, dataLen
);
1724 *digestInfoLen
= offset
+ dataLen
;
1727 return errSecSuccess
;
1730 OSStatus
SecKeyVerifyDigest(
1731 SecKeyRef key
, /* Private key */
1732 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
1733 const uint8_t *digestData
, /* signature over this digest */
1734 size_t digestDataLen
, /* length of dataToDigest */
1735 const uint8_t *sig
, /* signature to verify */
1736 size_t sigLen
) /* length of sig */
1738 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
1739 uint8_t digestInfo
[digestInfoLength
];
1742 status
= SecKeyGetDigestInfo(key
, algId
, digestData
, digestDataLen
, false /* data is digest */,
1743 digestInfo
, &digestInfoLength
);
1746 return SecKeyRawVerify(key
, kSecPaddingPKCS1
,
1747 digestInfo
, digestInfoLength
, sig
, sigLen
);
1750 OSStatus
SecKeySignDigest(
1751 SecKeyRef key
, /* Private key */
1752 const SecAsn1AlgId
*algId
, /* algorithm oid/params */
1753 const uint8_t *digestData
, /* signature over this digest */
1754 size_t digestDataLen
, /* length of digestData */
1755 uint8_t *sig
, /* signature, RETURNED */
1756 size_t *sigLen
) /* IN/OUT */
1758 size_t digestInfoLength
= DER_MAX_DIGEST_INFO_LEN
;
1759 uint8_t digestInfo
[digestInfoLength
];
1762 status
= SecKeyGetDigestInfo(key
, algId
, digestData
, digestDataLen
, false,
1763 digestInfo
, &digestInfoLength
);
1766 return SecKeyRawSign(key
, kSecPaddingPKCS1
,
1767 digestInfo
, digestInfoLength
, sig
, sigLen
);
1770 /* It's debatable whether this belongs here or in the ssl code since the
1771 curve values come from a tls related rfc4492. */
1772 SecECNamedCurve
SecECKeyGetNamedCurve(SecKeyRef key
)
1775 SecPointer
<KeyItem
> keyItem(KeyItem::required(key
));
1776 switch (keyItem
->key().header().LogicalKeySizeInBits
) {
1779 return kSecECCurveSecp192r1
;
1781 return kSecECCurveSecp224r1
;
1784 return kSecECCurveSecp256r1
;
1786 return kSecECCurveSecp384r1
;
1788 return kSecECCurveSecp521r1
;
1792 return kSecECCurveNone
;
1795 static inline CFDataRef
_CFDataCreateReferenceFromRange(CFAllocatorRef allocator
, CFDataRef sourceData
, CFRange range
)
1797 return CFDataCreateWithBytesNoCopy(allocator
,
1798 CFDataGetBytePtr(sourceData
) + range
.location
, range
.length
,
1802 static inline CFDataRef
_CFDataCreateCopyFromRange(CFAllocatorRef allocator
, CFDataRef sourceData
, CFRange range
)
1804 return CFDataCreate(allocator
, CFDataGetBytePtr(sourceData
) + range
.location
, range
.length
);
1807 #pragma clang diagnostic push
1808 #pragma clang diagnostic ignored "-Wunused-function"
1809 static inline bool _CFDataEquals(CFDataRef left
, CFDataRef right
)
1811 return (left
!= NULL
) &&
1813 (CFDataGetLength(left
) == CFDataGetLength(right
)) &&
1814 (0 == memcmp(CFDataGetBytePtr(left
), CFDataGetBytePtr(right
), (size_t)CFDataGetLength(left
)));
1816 #pragma clang diagnostic pop
1819 void secdump(const unsigned char *data
, unsigned long len
)
1828 sprintf(t
, "%04lx :", i
);
1831 sprintf(t
, " %02x", data
[i
]);
1835 syslog(LOG_NOTICE
, s
);
1840 syslog(LOG_NOTICE
, s
);
1844 OSStatus
SecKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
* publicBytes
)
1847 #if TARGET_OS_EMBEDDED
1848 keyAlgId
= SecKeyGetAlgorithmID(key
);
1850 keyAlgId
= SecKeyGetAlgorithmId(key
);
1853 OSStatus ecStatus
= errSecParam
;
1854 CFDataRef tempPublicData
= NULL
;
1855 CFDataRef headerlessPublicData
= NULL
;
1856 CFIndex headerLength
= 0;
1857 const UInt8
* pData_Ptr
= NULL
;
1859 if (kSecRSAAlgorithmID
== keyAlgId
)
1861 return SecItemExport(key
, kSecFormatBSAFE
, 0, NULL
, publicBytes
);
1864 if (kSecECDSAAlgorithmID
== keyAlgId
)
1866 // First export the key so there is access to the underlying key material
1867 ecStatus
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, &tempPublicData
);
1868 if(ecStatus
!= errSecSuccess
)
1870 secdebug("key", "SecKeyCopyPublicBytes: SecItemExport error (%d) for ECDSA public key %p",
1871 ecStatus
, (uintptr_t)key
);
1877 // Get a pointer to the first byte of the exported data
1878 pData_Ptr
= CFDataGetBytePtr(tempPublicData
);
1880 // the first byte should be a sequence 0x30
1881 if (*pData_Ptr
!= 0x30)
1883 secdebug("key", "SecKeyCopyPublicBytes: exported data is invalid");
1884 if (NULL
!= tempPublicData
)
1885 CFRelease(tempPublicData
);
1887 ecStatus
= errSecParam
;
1891 // move past the sequence byte
1894 // Check to see if the high bit is set which
1895 // indicates that the length will be at least
1896 // two bytes. If the high bit is set then
1897 // The lower seven bits specifies the number of
1898 // bytes used for the length. The additonal 1
1899 // is for the current byte. Otherwise just move past the
1900 // single length byte
1901 pData_Ptr
+= (*pData_Ptr
& 0x80) ? ((*pData_Ptr
& 0x7F) + 1) : 1;
1903 // The current byte should be a sequence 0x30
1904 if (*pData_Ptr
!= 0x30)
1906 secdebug("key", "SecKeyCopyPublicBytes: Could not find the key sequence");
1907 if (NULL
!= tempPublicData
) {
1908 CFRelease(tempPublicData
);
1910 ecStatus
= errSecParam
;
1914 // The next bytes will always be the same
1919 // ECDSA public KEY OID value 0x2a,0x86,0x48,0xce,0x3d,0x02,0x01
1921 // This is a total of 12 bytes
1924 // Next byte is the length of the ECDSA curve OID
1925 // Move past the length byte and the curve OID
1926 pData_Ptr
+= (((int)*pData_Ptr
) + 1);
1928 // Should be at a BINARY String which is specifed by a 0x3
1929 if (*pData_Ptr
!= 0x03)
1931 secdebug("key", "SecKeyCopyPublicBytes: Invalid key structure");
1932 if (NULL
!= tempPublicData
) {
1933 CFRelease(tempPublicData
);
1935 ecStatus
= errSecParam
;
1939 // Move past the BINARY String specifier 0x03
1943 // Check to see if the high bit is set which
1944 // indicates that the length will be at least
1945 // two bytes. If the high bit is set then
1946 // The lower seven bits specifies the number of
1947 // bytes used for the length. The additonal 1
1948 // is for the current byte. Otherwise just move past the
1949 // single length byte
1950 pData_Ptr
+= (*pData_Ptr
& 0x80) ? ((*pData_Ptr
& 0x7F) + 1) : 1;
1952 // Move past the beginning marker for the BINARY String 0x00
1955 // pData_Ptr now points to the first bytes of the key material
1956 headerLength
= (CFIndex
)(((intptr_t)pData_Ptr
) - ((intptr_t)CFDataGetBytePtr(tempPublicData
)));
1958 headerlessPublicData
= _CFDataCreateCopyFromRange(kCFAllocatorDefault
,
1959 tempPublicData
, CFRangeMake(headerLength
, CFDataGetLength(tempPublicData
) - headerLength
));
1961 if (!headerlessPublicData
)
1963 printf("SecKeyCopyPublicBytes: headerlessPublicData is nil (1)\n");
1964 if (NULL
!= tempPublicData
)
1965 CFRelease(tempPublicData
);
1967 ecStatus
= errSecParam
;
1974 *publicBytes
= headerlessPublicData
;
1977 ecStatus
= errSecSuccess
;
1979 if (NULL
!= tempPublicData
)
1980 CFRelease(tempPublicData
);
1989 CFDataRef
SecECKeyCopyPublicBits(SecKeyRef key
)
1991 CFDataRef exportedKey
;
1992 if(SecKeyCopyPublicBytes(key
, &exportedKey
) != errSecSuccess
) {
1998 SecKeyRef
SecKeyCreateFromPublicData(CFAllocatorRef allocator
, CFIndex algorithmID
, CFDataRef publicBytes
)
2000 SecExternalFormat externalFormat
= kSecFormatOpenSSL
;
2001 SecExternalItemType externalItemType
= kSecItemTypePublicKey
;
2002 CFDataRef workingData
= NULL
;
2003 CFArrayRef outArray
= NULL
;
2004 SecKeyRef retVal
= NULL
;
2006 if (kSecRSAAlgorithmID
== algorithmID
) {
2008 * kSecFormatBSAFE uses the original PKCS#1 definition:
2009 * RSAPublicKey ::= SEQUENCE {
2010 * modulus INTEGER, -- n
2011 * publicExponent INTEGER -- e
2013 * kSecFormatOpenSSL uses different ASN.1 encoding.
2015 externalFormat
= kSecFormatBSAFE
;
2016 workingData
= _CFDataCreateReferenceFromRange(kCFAllocatorDefault
, publicBytes
, CFRangeMake(0, CFDataGetLength(publicBytes
)));
2017 } else if (kSecECDSAAlgorithmID
== algorithmID
) {
2018 CFMutableDataRef tempData
;
2019 uint8 requiredFirstDERByte
[] = {0x04};
2020 uint8 placeholder
[1];
2021 uint8 headerBytes
[] = { 0x30,0x59,0x30,0x13,0x06,0x07,0x2a,0x86,
2022 0x48,0xce,0x3d,0x02,0x01,0x06,0x08,0x2a,
2023 0x86,0x48,0xce,0x3d,0x03,0x01,0x07,0x03,
2026 /* FIXME: this code only handles one specific curve type; need to expand this */
2027 if(CFDataGetLength(publicBytes
) != 65)
2030 CFDataGetBytes(publicBytes
, CFRangeMake(0, 1), placeholder
);
2032 if(requiredFirstDERByte
[0] != placeholder
[0])
2036 tempData
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
2037 CFDataAppendBytes(tempData
, headerBytes
, sizeof(headerBytes
));
2038 CFDataAppendBytes(tempData
, CFDataGetBytePtr(publicBytes
), CFDataGetLength(publicBytes
));
2040 workingData
= tempData
;
2042 if(SecItemImport(workingData
, NULL
, &externalFormat
, &externalItemType
, 0, NULL
, NULL
, &outArray
) != errSecSuccess
) {
2045 if(!outArray
|| CFArrayGetCount(outArray
) == 0) {
2048 retVal
= (SecKeyRef
)CFArrayGetValueAtIndex(outArray
, 0);
2052 if(workingData
) CFRelease(workingData
);
2053 if(outArray
) CFRelease(outArray
);
2057 SecKeyRef
SecKeyCreateRSAPublicKey(CFAllocatorRef allocator
,
2058 const uint8_t *keyData
, CFIndex keyDataLength
,
2059 SecKeyEncoding encoding
)
2061 CFDataRef pubKeyData
= NULL
;
2062 if(kSecKeyEncodingPkcs1
== encoding
) {
2063 /* DER-encoded according to PKCS1. */
2064 pubKeyData
= CFDataCreate(allocator
, keyData
, keyDataLength
);
2066 } else if(kSecKeyEncodingApplePkcs1
== encoding
) {
2067 /* DER-encoded according to PKCS1 with Apple Extensions. */
2068 /* FIXME: need to actually handle extensions */
2071 } else if(kSecKeyEncodingRSAPublicParams
== encoding
) {
2072 /* SecRSAPublicKeyParams format; we must encode as PKCS1. */
2073 SecRSAPublicKeyParams
*params
= (SecRSAPublicKeyParams
*)keyData
;
2074 DERSize m_size
= params
->modulusLength
;
2075 DERSize e_size
= params
->exponentLength
;
2076 const DERSize seq_size
= DERLengthOfItem(ASN1_INTEGER
, m_size
) +
2077 DERLengthOfItem(ASN1_INTEGER
, e_size
);
2078 const DERSize result_size
= DERLengthOfItem(ASN1_SEQUENCE
, seq_size
);
2079 DERSize r_size
, remaining_size
= result_size
;
2082 CFMutableDataRef pkcs1
= CFDataCreateMutable(allocator
, result_size
);
2083 if (pkcs1
== NULL
) {
2086 CFDataSetLength(pkcs1
, result_size
);
2087 uint8_t *bytes
= CFDataGetMutableBytePtr(pkcs1
);
2089 *bytes
++ = ASN1_CONSTR_SEQUENCE
;
2092 drtn
= DEREncodeLength(seq_size
, bytes
, &r_size
);
2093 if (r_size
<= remaining_size
) {
2095 remaining_size
-= r_size
;
2097 r_size
= remaining_size
;
2098 drtn
= DEREncodeItem(ASN1_INTEGER
, m_size
, (const DERByte
*)params
->modulus
, (DERByte
*)bytes
, &r_size
);
2099 if (r_size
<= remaining_size
) {
2101 remaining_size
-= r_size
;
2103 r_size
= remaining_size
;
2104 drtn
= DEREncodeItem(ASN1_INTEGER
, e_size
, (const DERByte
*)params
->exponent
, (DERByte
*)bytes
, &r_size
);
2109 /* unsupported encoding */
2112 SecKeyRef publicKey
= SecKeyCreateFromPublicData(allocator
, kSecRSAAlgorithmID
, pubKeyData
);
2113 CFRelease(pubKeyData
);
2117 #if !TARGET_OS_EMBEDDED
2119 // Given a CSSM public key, copy its modulus and/or exponent data.
2120 // Caller is responsible for releasing the returned CFDataRefs.
2123 OSStatus
_SecKeyCopyRSAPublicModulusAndExponent(SecKeyRef key
, CFDataRef
*modulus
, CFDataRef
*exponent
)
2125 const CSSM_KEY
*pubKey
;
2126 const CSSM_KEYHEADER
*hdr
;
2127 CSSM_DATA pubKeyBlob
;
2130 result
= SecKeyGetCSSMKey(key
, &pubKey
);
2131 if(result
!= errSecSuccess
) {
2134 hdr
= &pubKey
->KeyHeader
;
2135 if(hdr
->KeyClass
!= CSSM_KEYCLASS_PUBLIC_KEY
) {
2136 return errSSLInternal
;
2138 if(hdr
->AlgorithmId
!= CSSM_ALGID_RSA
) {
2139 return errSSLInternal
;
2141 switch(hdr
->BlobType
) {
2142 case CSSM_KEYBLOB_RAW
:
2143 pubKeyBlob
.Length
= pubKey
->KeyData
.Length
;
2144 pubKeyBlob
.Data
= pubKey
->KeyData
.Data
;
2146 case CSSM_KEYBLOB_REFERENCE
:
2147 // FIXME: currently SSL only uses raw public keys, obtained from the CL
2149 return errSSLInternal
;
2151 assert(hdr
->BlobType
== CSSM_KEYBLOB_RAW
);
2152 // at this point we should have a PKCS1-encoded blob
2154 DERItem keyItem
= {(DERByte
*)pubKeyBlob
.Data
, pubKeyBlob
.Length
};
2155 DERRSAPubKeyPKCS1 decodedKey
;
2156 if(DERParseSequence(&keyItem
, DERNumRSAPubKeyPKCS1ItemSpecs
,
2157 DERRSAPubKeyPKCS1ItemSpecs
,
2158 &decodedKey
, sizeof(decodedKey
)) != DR_Success
) {
2159 return errSecDecode
;
2162 *modulus
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.modulus
.data
, decodedKey
.modulus
.length
);
2163 if(*modulus
== NULL
) {
2164 return errSecDecode
;
2168 *exponent
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.pubExponent
.data
, decodedKey
.pubExponent
.length
);
2169 if(*exponent
== NULL
) {
2170 return errSecDecode
;
2174 return errSecSuccess
;
2176 #endif /* !TARGET_OS_EMBEDDED */
2178 CFDataRef
SecKeyCopyModulus(SecKeyRef key
)
2180 #if TARGET_OS_EMBEDDED
2181 ccrsa_pub_ctx_t pubkey
;
2182 pubkey
.pub
= key
->key
;
2184 size_t m_size
= ccn_write_uint_size(ccrsa_ctx_n(pubkey
), ccrsa_ctx_m(pubkey
));
2186 CFAllocatorRef allocator
= CFGetAllocator(key
);
2187 CFMutableDataRef modulusData
= CFDataCreateMutable(allocator
, m_size
);
2189 if (modulusData
== NULL
)
2192 CFDataSetLength(modulusData
, m_size
);
2194 ccn_write_uint(ccrsa_ctx_n(pubkey
), ccrsa_ctx_m(pubkey
), m_size
, CFDataGetMutableBytePtr(modulusData
));
2196 CFDataRef modulusData
;
2197 OSStatus status
= _SecKeyCopyRSAPublicModulusAndExponent(key
, &modulusData
, NULL
);
2198 if(status
!= errSecSuccess
) {
2206 CFDataRef
SecKeyCopyExponent(SecKeyRef key
)
2208 #if TARGET_OS_EMBEDDED
2209 ccrsa_pub_ctx_t pubkey
;
2210 pubkey
.pub
= key
->key
;
2212 size_t e_size
= ccn_write_uint_size(ccrsa_ctx_n(pubkey
), ccrsa_ctx_e(pubkey
));
2214 CFAllocatorRef allocator
= CFGetAllocator(key
);
2215 CFMutableDataRef exponentData
= CFDataCreateMutable(allocator
, e_size
);
2217 if (exponentData
== NULL
)
2220 CFDataSetLength(exponentData
, e_size
);
2222 ccn_write_uint(ccrsa_ctx_n(pubkey
), ccrsa_ctx_e(pubkey
), e_size
, CFDataGetMutableBytePtr(exponentData
));
2224 CFDataRef exponentData
;
2225 OSStatus status
= _SecKeyCopyRSAPublicModulusAndExponent(key
, NULL
, &exponentData
);
2226 if(status
!= errSecSuccess
) {
2227 exponentData
= NULL
;
2231 return exponentData
;
2234 SecKeyRef
SecKeyCreatePublicFromPrivate(SecKeyRef privateKey
) {
2235 OSStatus status
= errSecParam
;
2237 CFDataRef serializedPublic
= NULL
;
2239 status
= SecKeyCopyPublicBytes(privateKey
, &serializedPublic
);
2240 if ((status
== errSecSuccess
) && (serializedPublic
!= NULL
)) {
2241 SecKeyRef publicKeyRef
= SecKeyCreateFromPublicData(kCFAllocatorDefault
, SecKeyGetAlgorithmId(privateKey
), serializedPublic
);
2242 CFRelease(serializedPublic
);
2243 if (publicKeyRef
!= NULL
) {
2244 return publicKeyRef
;
2248 const void *keys
[] = { kSecClass
, kSecValueRef
, kSecReturnAttributes
};
2249 const void *values
[] = { kSecClassKey
, privateKey
, kCFBooleanTrue
};
2250 CFDictionaryRef query
= CFDictionaryCreate(NULL
, keys
, values
,
2251 (sizeof(values
) / sizeof(*values
)),
2252 &kCFTypeDictionaryKeyCallBacks
,
2253 &kCFTypeDictionaryValueCallBacks
);
2254 CFTypeRef foundItem
= NULL
;
2255 status
= SecItemCopyMatching(query
, &foundItem
);
2257 if (status
== errSecSuccess
) {
2258 if (CFGetTypeID(foundItem
) == CFDictionaryGetTypeID()) {
2259 CFMutableDictionaryRef query2
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2260 CFDictionaryAddValue(query2
, kSecClass
, kSecClassKey
);
2261 CFDictionaryAddValue(query2
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
2262 CFDictionaryAddValue(query2
, kSecAttrApplicationLabel
, CFDictionaryGetValue((CFDictionaryRef
)foundItem
, kSecAttrApplicationLabel
));
2263 CFDictionaryAddValue(query2
, kSecReturnRef
, kCFBooleanTrue
);
2265 CFTypeRef foundKey
= NULL
;
2266 status
= SecItemCopyMatching(query2
, &foundKey
);
2267 if (status
== errSecSuccess
) {
2268 if (CFGetTypeID(foundKey
) == SecKeyGetTypeID()) {
2271 CFRelease(foundItem
);
2272 return (SecKeyRef
)foundKey
;
2274 status
= errSecItemNotFound
;
2280 status
= errSecItemNotFound
;
2282 CFRelease(foundItem
);