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@
24 #include <Security/SecKey.h>
25 #include <Security/SecKeyPriv.h>
26 #include <Security/SecKeyInternal.h>
27 #include <Security/SecItem.h>
28 #include <Security/SecItemPriv.h>
29 #include <libDER/asn1Types.h>
30 #include <libDER/DER_Encode.h>
31 #include <libDER/DER_Decode.h>
32 #include <libDER/DER_Keys.h>
33 #include <Security/SecAsn1Types.h>
34 #include <Security/SecAsn1Coder.h>
35 #include <security_keychain/KeyItem.h>
36 #include <security_utilities/casts.h>
37 #include <CommonCrypto/CommonKeyDerivation.h>
39 #include <CoreFoundation/CFPriv.h>
40 // 'verify' macro is somehow dragged in from CFPriv.h and breaks compilation of signclient.h, so undef it, we don't need it.
43 #include "SecBridge.h"
45 #include <security_keychain/Access.h>
46 #include <security_keychain/Keychains.h>
47 #include <security_keychain/KeyItem.h>
51 #include <security_cdsa_utils/cuCdsaUtils.h>
52 #include <security_cdsa_client/wrapkey.h>
53 #include <security_cdsa_client/genkey.h>
54 #include <security_cdsa_client/signclient.h>
55 #include <security_cdsa_client/cryptoclient.h>
57 #include "SecImportExportCrypto.h"
60 SecCDSAKeyInit(SecKeyRef key
, const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) {
61 CDSASecKey
*cdsaKey
= (CDSASecKey
*)key
;
62 cdsaKey
->key
= const_cast<KeyItem
*>(reinterpret_cast<const KeyItem
*>(keyData
));
63 CDSASecKey::keyItem(key
)->initializeWithSecKeyRef(key
);
64 cdsaKey
->credentialType
= kSecCredentialTypeDefault
;
65 cdsaKey
->cdsaKeyMutex
= new Mutex();
70 SecCDSAKeyDestroy(SecKeyRef keyRef
) {
71 // Note: If this key is holding the last strong reference to its keychain, the keychain will be released during this operation.
72 // If we hold the keychain's mutex (the key's 'mutexForObject') during this destruction, pthread gets upset.
73 // Hold a reference to the keychain (if it exists) until after we release the keychain's mutex.
75 CDSASecKey
*cdsaKey
= static_cast<CDSASecKey
*>(keyRef
);
76 StMaybeLock
<Mutex
> cdsaMutex(cdsaKey
->cdsaKeyMutex
);
78 KeyItem
*keyItem
= static_cast<KeyItem
*>(keyRef
->key
);
80 if (keyItem
== NULL
) {
81 // KeyImpl::attachSecKeyRef disconnected us from KeyItem instance, there is nothing to do for us.
83 delete cdsaKey
->cdsaKeyMutex
;
87 Keychain kc
= keyItem
->keychain();
89 // We have a +1 reference to the KeyItem now; no need to protect our storage any more
93 StMaybeLock
<Mutex
> _(keyItem
->getMutexForObject());
94 keyItem
= static_cast<KeyItem
*>(keyRef
->key
);
95 if (keyItem
== NULL
) {
96 // Second version of the check above, the definitive one because this one is performed with locked object's mutex, therefore we can be sure that KeyImpl is still connected to this keyRef instance.
100 keyItem
->aboutToDestruct();
104 delete cdsaKey
->cdsaKeyMutex
;
106 (void) kc
; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain.
110 SecCDSAKeyGetBlockSize(SecKeyRef key
) {
112 CFErrorRef
*error
= NULL
;
113 BEGIN_SECKEYAPI(size_t,0)
115 const CssmKey::Header keyHeader
= CDSASecKey::keyItem(key
)->unverifiedKeyHeader();
116 switch(keyHeader
.algorithm())
120 result
= keyHeader
.LogicalKeySizeInBits
/ 8;
122 case CSSM_ALGID_ECDSA
:
124 /* Block size is up to 9 bytes of DER encoding for sequence of 2 integers,
125 * plus both coordinates for the point used */
126 #define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8)
127 #define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1)
128 size_t coordSize
= ECDSA_MAX_COORD_SIZE_IN_BYTES(keyHeader
.LogicalKeySizeInBits
);
129 assert(coordSize
< 256); /* size must fit in a byte for DER */
130 size_t coordDERLen
= (coordSize
> 127) ? 2 : 1;
131 size_t coordLen
= 1 + coordDERLen
+ coordSize
;
133 size_t pointSize
= 2 * coordLen
;
134 assert(pointSize
< 256); /* size must fit in a byte for DER */
135 size_t pointDERLen
= (pointSize
> 127) ? 2 : 1;
136 size_t pointLen
= 1 + pointDERLen
+ pointSize
;
142 result
= 16; /* all AES keys use 128-bit blocks */
145 case CSSM_ALGID_3DES_3KEY
:
146 result
= 8; /* all DES keys use 64-bit blocks */
149 assert(0); /* some other key algorithm */
150 result
= 16; /* FIXME: revisit this */
158 SecCDSAKeyGetAlgorithmId(SecKeyRef key
) {
160 CFErrorRef
*error
= NULL
;
161 BEGIN_SECKEYAPI(CFIndex
, 0)
163 result
= kSecNullAlgorithmID
;
164 switch (CDSASecKey::keyItem(key
)->unverifiedKeyHeader().AlgorithmId
) {
166 result
= kSecRSAAlgorithmID
;
169 result
= kSecDSAAlgorithmID
;
171 case CSSM_ALGID_ECDSA
:
172 result
= kSecECDSAAlgorithmID
;
175 assert(0); /* other algorithms TBA */
181 static CFDataRef
SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(CFDataRef pubKeyInfo
) {
182 // First of all, consider x509 format and try to strip SubjPubKey envelope. If it fails, do not panic
183 // and export data as is.
184 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(pubKeyInfo
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(pubKeyInfo
)) }, pubKeyItem
;
186 DERSubjPubKeyInfo subjPubKey
;
187 if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
,
188 DERSubjPubKeyInfoItemSpecs
,
189 &subjPubKey
, sizeof(subjPubKey
)) == DR_Success
&&
190 DERParseBitString(&subjPubKey
.pubKey
, &pubKeyItem
, &numUnused
) == DR_Success
) {
191 return CFDataCreate(kCFAllocatorDefault
, pubKeyItem
.data
, pubKeyItem
.length
);
194 return CFDataRef(CFRetain(pubKeyInfo
));
197 static CFDataRef
SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(CSSM_ALGORITHMS algorithm
, uint32 keySizeInBits
, CFDataRef pubKeyInfo
) {
198 // First check, whether X509 pubkeyinfo is already present. If not, add it according to the key type.
199 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(pubKeyInfo
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(pubKeyInfo
)) };
200 DERSubjPubKeyInfo subjPubKey
;
201 if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
,
202 DERSubjPubKeyInfoItemSpecs
,
203 &subjPubKey
, sizeof(subjPubKey
)) == DR_Success
) {
204 return CFDataRef(CFRetain(pubKeyInfo
));
207 // We have always size rounded to full bytes so bitstring encodes leading 00.
208 CFRef
<CFMutableDataRef
> bitStringPubKey
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
209 CFDataSetLength(bitStringPubKey
, 1);
210 CFDataAppendBytes(bitStringPubKey
, CFDataGetBytePtr(pubKeyInfo
), CFDataGetLength(pubKeyInfo
));
211 subjPubKey
.pubKey
.data
= static_cast<DERByte
*>(const_cast<UInt8
*>(CFDataGetBytePtr(bitStringPubKey
)));
212 subjPubKey
.pubKey
.length
= CFDataGetLength(bitStringPubKey
);
214 // Encode algId according to algorithm used.
215 static const DERByte oidRSA
[] = {
216 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
218 static const DERByte oidECsecp256
[] = {
219 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
221 static const DERByte oidECsecp384
[] = {
222 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22,
224 static const DERByte oidECsecp521
[] = {
225 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23,
227 subjPubKey
.algId
.length
= 0;
228 if (algorithm
== CSSM_ALGID_RSA
) {
229 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidRSA
);
230 subjPubKey
.algId
.length
= sizeof(oidRSA
);
231 } else if (algorithm
== CSSM_ALGID_ECDSA
) {
232 if (keySizeInBits
== 256) {
233 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidECsecp256
);
234 subjPubKey
.algId
.length
= sizeof(oidECsecp256
);
235 } else if (keySizeInBits
== 384) {
236 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidECsecp384
);
237 subjPubKey
.algId
.length
= sizeof(oidECsecp384
);
238 } if (keySizeInBits
== 521) {
239 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidECsecp521
);
240 subjPubKey
.algId
.length
= sizeof(oidECsecp521
);
243 DERSize size
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
,
244 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
);
245 CFRef
<CFMutableDataRef
> keyData
= CFDataCreateMutable(kCFAllocatorDefault
, size
);
246 CFDataSetLength(keyData
, size
);
247 if (DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
,
248 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
,
249 static_cast<DERByte
*>(CFDataGetMutableBytePtr(keyData
)), &size
) == DR_Success
) {
250 CFDataSetLength(keyData
, size
);
255 return keyData
.yield();
258 static OSStatus
SecCDSAKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
*serialization
) {
260 CFErrorRef
*error
= NULL
;
261 BEGIN_SECKEYAPI(OSStatus
, errSecSuccess
)
263 const CssmKey::Header
&header
= CDSASecKey::keyItem(key
)->key().header();
264 switch (header
.algorithm()) {
265 case CSSM_ALGID_RSA
: {
266 switch (header
.keyClass()) {
267 case CSSM_KEYCLASS_PRIVATE_KEY
: {
268 CFRef
<CFDataRef
> privKeyData
;
269 result
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, privKeyData
.take());
270 if (result
== errSecSuccess
) {
271 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(privKeyData
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(privKeyData
)) };
272 DERRSAKeyPair keyPair
;
273 if (DERParseSequence(&keyItem
, DERNumRSAKeyPairItemSpecs
, DERRSAKeyPairItemSpecs
,
274 &keyPair
, sizeof(keyPair
)) == DR_Success
) {
275 DERRSAPubKeyPKCS1 pubKey
= { keyPair
.n
, keyPair
.e
};
276 DERSize size
= DERLengthOfEncodedSequence(ASN1_SEQUENCE
, &pubKey
,
277 DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
);
278 CFRef
<CFMutableDataRef
> keyData
= CFDataCreateMutable(kCFAllocatorDefault
, size
);
279 CFDataSetLength(keyData
, size
);
280 UInt8
*data
= CFDataGetMutableBytePtr(keyData
);
281 if (DEREncodeSequence(ASN1_SEQUENCE
, &pubKey
,
282 DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
,
283 data
, &size
) == DR_Success
) {
284 CFDataSetLength(keyData
, size
);
285 *data
= ONE_BYTE_ASN1_CONSTR_SEQUENCE
;
286 *serialization
= keyData
.yield();
288 *serialization
= NULL
;
289 result
= errSecParam
;
295 case CSSM_KEYCLASS_PUBLIC_KEY
:
296 result
= SecItemExport(key
, kSecFormatBSAFE
, 0, NULL
, serialization
);
301 case CSSM_ALGID_ECDSA
: {
302 *serialization
= NULL
;
303 CFRef
<CFDataRef
> tempPublicData
;
304 result
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, tempPublicData
.take());
305 if (result
== errSecSuccess
) {
306 *serialization
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(tempPublicData
);
311 result
= errSecUnimplemented
;
322 static const DERItemSpec DERECPrivateKeyItemSpecs
[] =
327 { DER_OFFSET(DERECPrivateKey
, privateKey
),
329 DER_DEC_NO_OPTS
| DER_ENC_NO_OPTS
},
331 ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0,
332 DER_DEC_SKIP
| DER_ENC_NO_OPTS
},
333 { DER_OFFSET(DERECPrivateKey
, publicKey
),
334 ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 1,
335 DER_DEC_NO_OPTS
| DER_ENC_SIGNED_INT
},
337 static const DERSize DERNumECPrivateKeyItemSpecs
=
338 sizeof(DERECPrivateKeyItemSpecs
) / sizeof(DERItemSpec
);
342 } DERECPrivateKeyPublicKey
;
344 static const DERItemSpec DERECPrivateKeyPublicKeyItemSpecs
[] =
346 { DER_OFFSET(DERECPrivateKeyPublicKey
, bitString
),
348 DER_DEC_NO_OPTS
| DER_ENC_NO_OPTS
},
350 static const DERSize DERNumECPrivateKeyPublicKeyItemSpecs
=
351 sizeof(DERECPrivateKeyPublicKeyItemSpecs
) / sizeof(DERItemSpec
);
354 SecCDSAKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef
*error
) {
356 BEGIN_SECKEYAPI(CFDataRef
, NULL
)
359 const CssmKey::Header header
= CDSASecKey::keyItem(key
)->unverifiedKeyHeader();
360 CFRef
<CFDataRef
> keyData
;
361 switch (header
.algorithm()) {
363 MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()));
365 case CSSM_ALGID_ECDSA
: {
366 MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()));
367 if (header
.keyClass() == CSSM_KEYCLASS_PRIVATE_KEY
) {
368 // Convert DER format into x9.63 format, which is expected for exported key.
369 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(keyData
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(keyData
)) };
370 DERECPrivateKey privateKey
;
371 DERECPrivateKeyPublicKey privateKeyPublicKey
;
374 if (DERParseSequence(&keyItem
, DERNumECPrivateKeyItemSpecs
, DERECPrivateKeyItemSpecs
,
375 &privateKey
, sizeof(privateKey
)) == DR_Success
&&
376 DERParseSequenceContent(&privateKey
.publicKey
, DERNumECPrivateKeyPublicKeyItemSpecs
,
377 DERECPrivateKeyPublicKeyItemSpecs
,
378 &privateKeyPublicKey
, sizeof(privateKeyPublicKey
)) == DR_Success
&&
379 DERParseBitString(&privateKeyPublicKey
.bitString
, &pubKeyItem
, &numUnused
) == DR_Success
) {
380 CFRef
<CFMutableDataRef
> key
= CFDataCreateMutable(kCFAllocatorDefault
,
381 pubKeyItem
.length
+ privateKey
.privateKey
.length
);
382 CFDataSetLength(key
, pubKeyItem
.length
+ privateKey
.privateKey
.length
);
383 CFDataReplaceBytes(key
, CFRangeMake(0, pubKeyItem
.length
), pubKeyItem
.data
, pubKeyItem
.length
);
384 CFDataReplaceBytes(key
, CFRangeMake(pubKeyItem
.length
, privateKey
.privateKey
.length
),
385 privateKey
.privateKey
.data
, privateKey
.privateKey
.length
);
386 keyData
= key
.as
<CFDataRef
>();
392 MacOSError::throwMe(errSecUnimplemented
);
395 if (header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
) {
396 result
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(keyData
);
398 result
= keyData
.yield();
404 static CFDataRef
SecCDSAKeyCopyLabel(SecKeyRef key
) {
405 CFDataRef label
= NULL
;
406 if (CDSASecKey::keyItem(key
)->isPersistent()) {
407 UInt32 tags
[] = { kSecKeyLabel
}, formats
[] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB
};
408 SecKeychainAttributeInfo info
= { 1, tags
, formats
};
409 SecKeychainAttributeList
*list
= NULL
;
410 CDSASecKey::keyItem(key
)->getAttributesAndData(&info
, NULL
, &list
, NULL
, NULL
);
411 if (list
->count
== 1) {
412 SecKeychainAttribute
*attr
= list
->attr
;
413 label
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)attr
->data
, (CFIndex
)attr
->length
);
415 CDSASecKey::keyItem(key
)->freeAttributesAndData(list
, NULL
);
420 static CFDictionaryRef
421 SecCDSAKeyCopyAttributeDictionary(SecKeyRef key
) {
423 CFErrorRef
*error
= NULL
;
424 BEGIN_SECKEYAPI(CFDictionaryRef
, NULL
)
426 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
427 &kCFTypeDictionaryValueCallBacks
);
429 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
431 const CssmKey::Header header
= CDSASecKey::keyItem(key
)->unverifiedKeyHeader();
432 CFIndex sizeValue
= header
.LogicalKeySizeInBits
;
433 CFRef
<CFNumberRef
> sizeInBits
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &sizeValue
);
434 CFDictionarySetValue(dict
, kSecAttrKeySizeInBits
, sizeInBits
);
435 CFDictionarySetValue(dict
, kSecAttrEffectiveKeySize
, sizeInBits
);
437 CFRef
<CFDataRef
> label
= SecCDSAKeyCopyLabel(key
);
439 // For floating keys, calculate label as SHA1 of pubkey bytes.
440 CFRef
<CFDataRef
> pubKeyBlob
;
441 if (SecCDSAKeyCopyPublicBytes(key
, pubKeyBlob
.take()) == errSecSuccess
) {
442 uint8_t pubKeyHash
[CC_SHA1_DIGEST_LENGTH
];
443 CC_SHA1(CFDataGetBytePtr(pubKeyBlob
), CC_LONG(CFDataGetLength(pubKeyBlob
)), pubKeyHash
);
444 label
.take(CFDataCreate(kCFAllocatorDefault
, pubKeyHash
, sizeof(pubKeyHash
)));
449 CFDictionarySetValue(dict
, kSecAttrApplicationLabel
, label
);
452 CSSM_KEYATTR_FLAGS attrs
= header
.attributes();
453 CFDictionarySetValue(dict
, kSecAttrIsPermanent
, (attrs
& CSSM_KEYATTR_PERMANENT
) ? kCFBooleanTrue
: kCFBooleanFalse
);
454 CFDictionarySetValue(dict
, kSecAttrIsPrivate
, (attrs
& CSSM_KEYATTR_PRIVATE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
455 CFDictionarySetValue(dict
, kSecAttrIsModifiable
, (attrs
& CSSM_KEYATTR_MODIFIABLE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
456 CFDictionarySetValue(dict
, kSecAttrIsSensitive
, (attrs
& CSSM_KEYATTR_SENSITIVE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
457 CFDictionarySetValue(dict
, kSecAttrIsExtractable
, (attrs
& CSSM_KEYATTR_EXTRACTABLE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
458 CFDictionarySetValue(dict
, kSecAttrWasAlwaysSensitive
, (attrs
& CSSM_KEYATTR_ALWAYS_SENSITIVE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
459 CFDictionarySetValue(dict
, kSecAttrWasNeverExtractable
, (attrs
& CSSM_KEYATTR_NEVER_EXTRACTABLE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
461 CFDictionarySetValue(dict
, kSecAttrCanEncrypt
, (header
.useFor(CSSM_KEYUSE_ENCRYPT
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
462 CFDictionarySetValue(dict
, kSecAttrCanDecrypt
, (header
.useFor(CSSM_KEYUSE_DECRYPT
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
463 CFDictionarySetValue(dict
, kSecAttrCanSign
, (header
.useFor(CSSM_KEYUSE_SIGN
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
464 CFDictionarySetValue(dict
, kSecAttrCanVerify
, (header
.useFor(CSSM_KEYUSE_VERIFY
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
465 CFDictionarySetValue(dict
, kSecAttrCanSignRecover
, (header
.useFor(CSSM_KEYUSE_SIGN_RECOVER
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
466 CFDictionarySetValue(dict
, kSecAttrCanVerifyRecover
, (header
.useFor(CSSM_KEYUSE_VERIFY_RECOVER
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
467 CFDictionarySetValue(dict
, kSecAttrCanWrap
, (header
.useFor(CSSM_KEYUSE_WRAP
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
468 CFDictionarySetValue(dict
, kSecAttrCanUnwrap
, (header
.useFor(CSSM_KEYUSE_UNWRAP
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
469 CFDictionarySetValue(dict
, kSecAttrCanDerive
, (header
.useFor(CSSM_KEYUSE_DERIVE
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
471 switch (header
.keyClass()) {
472 case CSSM_KEYCLASS_PUBLIC_KEY
:
473 CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
475 case CSSM_KEYCLASS_PRIVATE_KEY
:
476 CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
480 switch (header
.algorithm()) {
482 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
484 case CSSM_ALGID_ECDSA
:
485 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeECDSA
);
489 CFRef
<CFDataRef
> keyData
;
490 if (SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()) == errSecSuccess
) {
491 CFDictionarySetValue(dict
, kSecValueData
, keyData
);
494 if (header
.algorithm() == CSSM_ALGID_RSA
&& header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
&&
495 header
.blobType() == CSSM_KEYBLOB_RAW
) {
496 const CssmData
&keyData
= CDSASecKey::keyItem(key
)->key()->keyData();
497 DERItem keyItem
= { static_cast<DERByte
*>(keyData
.data()), keyData
.length() };
498 DERRSAPubKeyPKCS1 decodedKey
;
499 if (DERParseSequence(&keyItem
, DERNumRSAPubKeyPKCS1ItemSpecs
,
500 DERRSAPubKeyPKCS1ItemSpecs
,
501 &decodedKey
, sizeof(decodedKey
)) == DR_Success
) {
502 CFRef
<CFDataRef
> modulus
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.modulus
.data
,
503 decodedKey
.modulus
.length
);
504 CFDictionarySetValue(dict
, CFSTR("_rsam"), modulus
);
505 CFRef
<CFDataRef
> exponent
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.pubExponent
.data
,
506 decodedKey
.pubExponent
.length
);
507 CFDictionarySetValue(dict
, CFSTR("_rsae"), exponent
);
516 #pragma clang diagnostic push
517 #pragma clang diagnostic ignored "-Wunused-const-variable"
518 static CSSM_DB_NAME_ATTR(kInfoKeyLabel
, kSecKeyLabel
, (char*) "Label", 0, NULL
, BLOB
);
519 #pragma clang diagnostic pop
521 static SecKeyRef
SecCDSAKeyCopyPublicKey(SecKeyRef privateKey
) {
522 CFErrorRef
*error
= NULL
;
523 BEGIN_SECKEYAPI(SecKeyRef
, NULL
)
526 KeyItem
*key
= CDSASecKey::keyItem(privateKey
);
527 CFRef
<CFDataRef
> label
= SecCDSAKeyCopyLabel(privateKey
);
529 // Lookup public key in the database.
530 DbUniqueRecord uniqueId
;
531 SSDb
ssDb(dynamic_cast<SSDbImpl
*>(&(*key
->keychain()->database())));
532 SSDbCursor
dbCursor(ssDb
, 1);
533 dbCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
);
534 dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, CssmData(CFDataRef(label
)));
535 if (dbCursor
->next(NULL
, NULL
, uniqueId
)) {
536 Item publicKey
= key
->keychain()->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, uniqueId
);
537 result
= reinterpret_cast<SecKeyRef
>(publicKey
->handle());
541 if (result
== NULL
&& key
->publicKey()) {
542 SecPointer
<KeyItem
> publicKey(new KeyItem(key
->publicKey()));
543 result
= reinterpret_cast<SecKeyRef
>(publicKey
->handle());
549 static KeyItem
*SecCDSAKeyPrepareParameters(SecKeyRef key
, SecKeyOperationType
&operation
, SecKeyAlgorithm algorithm
,
550 CSSM_ALGORITHMS
&baseAlgorithm
, CSSM_ALGORITHMS
&secondaryAlgorithm
,
551 CSSM_ALGORITHMS
&paddingAlgorithm
, CFIndex
&inputSizeLimit
) {
552 KeyItem
*keyItem
= CDSASecKey::keyItem(key
);
553 CSSM_KEYCLASS keyClass
= keyItem
->key()->header().keyClass();
554 baseAlgorithm
= keyItem
->key()->header().algorithm();
555 switch (baseAlgorithm
) {
557 if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeSign
) ||
558 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeVerify
)) {
559 if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureRaw
)) {
560 secondaryAlgorithm
= CSSM_ALGID_NONE
;
561 paddingAlgorithm
= CSSM_PADDING_NONE
;
563 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
)) {
564 secondaryAlgorithm
= CSSM_ALGID_NONE
;
565 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
566 inputSizeLimit
= -11;
567 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
)) {
568 secondaryAlgorithm
= CSSM_ALGID_SHA1
;
569 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
571 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
)) {
572 secondaryAlgorithm
= CSSM_ALGID_SHA224
;
573 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
574 inputSizeLimit
= 224 / 8;
575 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
)) {
576 secondaryAlgorithm
= CSSM_ALGID_SHA256
;
577 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
578 inputSizeLimit
= 256 / 8;
579 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
)) {
580 secondaryAlgorithm
= CSSM_ALGID_SHA384
;
581 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
582 inputSizeLimit
= 384 / 8;
583 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
)) {
584 secondaryAlgorithm
= CSSM_ALGID_SHA512
;
585 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
586 inputSizeLimit
= 512 / 8;
587 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5
)) {
588 secondaryAlgorithm
= CSSM_ALGID_MD5
;
589 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
594 } else if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeDecrypt
) ||
595 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeEncrypt
)) {
596 if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionRaw
)) {
597 secondaryAlgorithm
= CSSM_ALGID_NONE
;
598 paddingAlgorithm
= CSSM_PADDING_NONE
;
600 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionPKCS1
)) {
601 secondaryAlgorithm
= CSSM_ALGID_NONE
;
602 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
603 inputSizeLimit
= operation
== kSecKeyOperationTypeEncrypt
? -11 : 0;
607 } else if (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeDecrypt
&&
608 CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionRaw
)) {
609 // Raw RSA decryption is identical to raw RSA encryption, so lets use encryption instead of decryption,
610 // because CDSA keys refuses to perform decrypt using public key.
611 operation
= kSecKeyOperationTypeEncrypt
;
612 secondaryAlgorithm
= CSSM_ALGID_NONE
;
613 paddingAlgorithm
= CSSM_PADDING_NONE
;
619 case CSSM_ALGID_ECDSA
:
620 if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeSign
) ||
621 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeVerify
)) {
622 if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureRFC4754
)) {
623 secondaryAlgorithm
= CSSM_ALGID_NONE
;
624 paddingAlgorithm
= CSSM_PADDING_SIGRAW
;
625 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureDigestX962
)) {
626 secondaryAlgorithm
= CSSM_ALGID_NONE
;
627 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
631 } else if (keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeKeyExchange
) {
632 if (CFEqual(algorithm
,kSecKeyAlgorithmECDHKeyExchangeStandard
) ||
633 CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactor
)) {
634 baseAlgorithm
= CSSM_ALGID_ECDH
;
635 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1
) ||
636 CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1
)) {
637 baseAlgorithm
= CSSM_ALGID_ECDH_X963_KDF
;
646 MacOSError::throwMe(errSecParam
);
652 SecCDSAKeyCopyPaddedPlaintext(SecKeyRef key
, CFDataRef plaintext
, SecKeyAlgorithm algorithm
) {
653 CFIndex blockSize
= CDSASecKey::keyItem(key
)->key().header().LogicalKeySizeInBits
/ 8;
654 CFIndex plaintextLength
= CFDataGetLength(plaintext
);
655 if ((algorithm
== kSecKeyAlgorithmRSAEncryptionRaw
|| algorithm
== kSecKeyAlgorithmRSASignatureRaw
)
656 && plaintextLength
< blockSize
) {
657 // Pre-pad with zeroes.
658 CFMutableDataRef
result(CFDataCreateMutable(kCFAllocatorDefault
, blockSize
));
659 CFDataSetLength(result
, blockSize
);
660 CFDataReplaceBytes(result
, CFRangeMake(blockSize
- plaintextLength
, plaintextLength
),
661 CFDataGetBytePtr(plaintext
), plaintextLength
);
664 return CFDataRef(CFRetain(plaintext
));
668 static CFTypeRef
SecCDSAKeyCopyOperationResult(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
,
669 CFArrayRef allAlgorithms
, SecKeyOperationMode mode
,
670 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
671 BEGIN_SECKEYAPI(CFTypeRef
, kCFNull
)
672 CFIndex inputSizeLimit
= 0;
673 CSSM_ALGORITHMS baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
;
674 KeyItem
*keyItem
= SecCDSAKeyPrepareParameters(key
, operation
, algorithm
, baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
, inputSizeLimit
);
675 if (keyItem
== NULL
) {
676 // Operation/algorithm/key combination is not supported.
678 } else if (mode
== kSecKeyOperationModeCheckIfSupported
) {
679 // Operation is supported and caller wants to just know that.
680 return kCFBooleanTrue
;
681 } else if (baseAlgorithm
== CSSM_ALGID_RSA
) {
682 if (inputSizeLimit
<= 0) {
683 inputSizeLimit
+= SecCDSAKeyGetBlockSize(key
);
685 if (CFDataGetLength((CFDataRef
)in1
) > inputSizeLimit
) {
686 MacOSError::throwMe(errSecParam
);
690 CDSASecKey
*cdsaKey
= static_cast<CDSASecKey
*>(key
);
692 case kSecKeyOperationTypeSign
: {
693 CssmClient::Sign
signContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
);
694 signContext
.key(keyItem
->key());
695 signContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN
, cdsaKey
->credentialType
));
696 signContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
);
697 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
698 CssmAutoData
signature(signContext
.allocator());
699 signContext
.sign(CssmData(CFDataRef(input
)), signature
.get());
700 result
= CFDataCreate(NULL
, static_cast<const UInt8
*>(signature
.data()), CFIndex(signature
.length()));
703 case kSecKeyOperationTypeVerify
: {
704 CssmClient::Verify
verifyContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
);
705 verifyContext
.key(keyItem
->key());
706 verifyContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ANY
, cdsaKey
->credentialType
));
707 verifyContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
);
708 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
709 verifyContext
.verify(CssmData(CFDataRef(input
)), CssmData(CFRef
<CFDataRef
>::check(in2
, errSecParam
)));
710 result
= kCFBooleanTrue
;
713 case kSecKeyOperationTypeEncrypt
: {
714 CssmClient::Encrypt
encryptContext(keyItem
->csp(), baseAlgorithm
);
715 encryptContext
.key(keyItem
->key());
716 encryptContext
.padding(paddingAlgorithm
);
717 encryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT
, cdsaKey
->credentialType
));
718 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
719 CssmAutoData
output(encryptContext
.allocator()), remainingData(encryptContext
.allocator());
720 size_t length
= encryptContext
.encrypt(CssmData(CFDataRef(input
)), output
.get(), remainingData
.get());
721 result
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length());
722 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(output
.data()), output
.length());
723 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(remainingData
.data()), remainingData
.length());
724 CFDataSetLength(CFMutableDataRef(result
), length
);
727 case kSecKeyOperationTypeDecrypt
: {
728 CssmClient::Decrypt
decryptContext(keyItem
->csp(), baseAlgorithm
);
729 decryptContext
.key(keyItem
->key());
730 decryptContext
.padding(paddingAlgorithm
);
731 decryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT
, cdsaKey
->credentialType
));
732 CssmAutoData
output(decryptContext
.allocator()), remainingData(decryptContext
.allocator());
733 size_t length
= decryptContext
.decrypt(CssmData(CFRef
<CFDataRef
>::check(in1
, errSecParam
)),
734 output
.get(), remainingData
.get());
735 result
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length());
736 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(output
.data()), output
.length());
737 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(remainingData
.data()), remainingData
.length());
738 CFDataSetLength(CFMutableDataRef(result
), length
);
741 case kSecKeyOperationTypeKeyExchange
: {
742 CFIndex requestedLength
= 0;
744 switch (baseAlgorithm
) {
745 case CSSM_ALGID_ECDH
:
746 requestedLength
= (keyItem
->key().header().LogicalKeySizeInBits
+ 7) / 8;
748 case CSSM_ALGID_ECDH_X963_KDF
:
749 CFDictionaryRef params
= CFRef
<CFDictionaryRef
>::check(in2
, errSecParam
);
750 CFTypeRef value
= params
? CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterRequestedSize
) : NULL
;
751 if (value
== NULL
|| CFGetTypeID(value
) != CFNumberGetTypeID() ||
752 !CFNumberGetValue(CFNumberRef(value
), kCFNumberCFIndexType
, &requestedLength
)) {
753 MacOSError::throwMe(errSecParam
);
755 value
= CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterSharedInfo
);
756 if (value
!= NULL
&& CFGetTypeID(value
) == CFDataGetTypeID()) {
757 sharedInfo
= CssmData(CFDataRef(value
));
762 CssmClient::DeriveKey
derive(keyItem
->csp(), baseAlgorithm
, CSSM_ALGID_AES
, uint32(requestedLength
* 8));
763 derive
.key(keyItem
->key());
764 derive
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DERIVE
, kSecCredentialTypeDefault
));
765 derive
.salt(sharedInfo
);
766 CssmData
param(CFRef
<CFDataRef
>::check(in1
, errSecParam
));
767 Key derivedKey
= derive(¶m
, KeySpec(CSSM_KEYUSE_ANY
, CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
));
769 // Export raw data of newly derived key (by wrapping with an empty key).
770 CssmClient::WrapKey
wrapper(keyItem
->csp(), CSSM_ALGID_NONE
);
771 Key wrappedKey
= wrapper(derivedKey
);
772 result
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)wrappedKey
->data(), CFIndex(wrappedKey
->length()));
782 static Boolean
SecCDSAKeyIsEqual(SecKeyRef key1
, SecKeyRef key2
) {
783 CFErrorRef
*error
= NULL
;
784 BEGIN_SECKEYAPI(Boolean
, false)
786 result
= CDSASecKey::keyItem(key1
)->equal(*CDSASecKey::keyItem(key2
));
791 static Boolean
SecCDSAKeySetParameter(SecKeyRef key
, CFStringRef name
, CFPropertyListRef value
, CFErrorRef
*error
) {
792 BEGIN_SECKEYAPI(Boolean
, false)
794 if (CFEqual(name
, kSecUseAuthenticationUI
)) {
795 static_cast<CDSASecKey
*>(key
)->credentialType
= CFEqual(value
, kSecUseAuthenticationUIAllow
) ? kSecCredentialTypeDefault
: kSecCredentialTypeNoUI
;
798 result
= SecError(errSecUnimplemented
, error
, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name
);
804 const SecKeyDescriptor kSecCDSAKeyDescriptor
= {
805 .version
= kSecKeyDescriptorVersion
,
808 .init
= SecCDSAKeyInit
,
809 .destroy
= SecCDSAKeyDestroy
,
810 .blockSize
= SecCDSAKeyGetBlockSize
,
811 .getAlgorithmID
= SecCDSAKeyGetAlgorithmId
,
812 .copyDictionary
= SecCDSAKeyCopyAttributeDictionary
,
813 .copyPublic
= SecCDSAKeyCopyPublicBytes
,
814 .copyExternalRepresentation
= SecCDSAKeyCopyExternalRepresentation
,
815 .copyPublicKey
= SecCDSAKeyCopyPublicKey
,
816 .copyOperationResult
= SecCDSAKeyCopyOperationResult
,
817 .isEqual
= SecCDSAKeyIsEqual
,
818 .setParameter
= SecCDSAKeySetParameter
,
820 .extraBytes
= (sizeof(class CDSASecKey
) > sizeof(struct __SecKey
) ? (sizeof(class CDSASecKey
) - sizeof(struct __SecKey
)) : 0),
824 namespace KeychainCore
{
825 SecCFObject
*KeyItem::fromSecKeyRef(CFTypeRef ptr
) {
826 if (ptr
== NULL
|| CFGetTypeID(ptr
) != SecKeyGetTypeID()) {
830 SecKeyRef key
= static_cast<SecKeyRef
>(const_cast<void *>(ptr
));
831 if (key
->key_class
== &kSecCDSAKeyDescriptor
) {
832 return static_cast<SecCFObject
*>(key
->key
);
835 CFRef
<SecKeyRef
> cdsaKey
= SecKeyCopyAuxilliaryCDSAKeyForKey(key
);
837 // Create CDSA key from exported data of existing key.
838 CFRef
<CFDictionaryRef
> keyAttributes
= SecKeyCopyAttributes(key
);
840 CFRef
<CFDataRef
> keyData
= SecKeyCopyExternalRepresentation(key
, NULL
);
842 CFTypeRef pubKeyHash
= CFDictionaryGetValue(keyAttributes
, kSecAttrApplicationLabel
);
843 const void *keys
[] = { kSecClass
, kSecUseDataProtectionKeychain
, kSecReturnRef
, kSecMatchLimit
};
844 const void *values
[] = { kSecClassIdentity
, kCFBooleanFalse
, kCFBooleanTrue
, kSecMatchLimitAll
};
845 CFRef
<CFDictionaryRef
> query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
,
846 sizeof(keys
) / sizeof(*keys
),
847 &kCFTypeDictionaryKeyCallBacks
,
848 &kCFTypeDictionaryValueCallBacks
);
849 CFRef
<CFArrayRef
> identities
;
850 OSStatus status
= SecItemCopyMatching(query
, (CFTypeRef
*)identities
.take());
851 if (status
== errSecSuccess
) {
852 for (int i
= 0; i
< CFArrayGetCount(identities
); ++i
) {
853 CFRef
<SecKeyRef
> privateKey
;
854 if (SecIdentityCopyPrivateKey((SecIdentityRef
)CFArrayGetValueAtIndex(identities
, i
), privateKey
.take()) != errSecSuccess
) {
857 CFRef
<CFDictionaryRef
> attrs
= SecKeyCopyAttributes(privateKey
);
858 if (CFEqual(CFDictionaryGetValue(attrs
, kSecAttrApplicationLabel
), pubKeyHash
)) {
859 cdsaKey
= privateKey
;
860 SecKeySetAuxilliaryCDSAKeyForKey(key
, cdsaKey
.get());
866 cdsaKey
.take(SecKeyCreateFromData(keyAttributes
, keyData
, NULL
));
868 SecKeySetAuxilliaryCDSAKeyForKey(key
, cdsaKey
.get());
874 return cdsaKey
? CDSASecKey::keyItem(cdsaKey
.get()) : NULL
;
877 // You need to hold this key's MutexForObject when you run this
878 void KeyItem::attachSecKeyRef() const {
879 SecKeyRef key
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, reinterpret_cast<const uint8_t *>(this), 0, 0);
880 CDSASecKey::keyItem(key
)->mWeakSecKeyRef
= key
;
886 extern "C" Boolean
SecKeyIsCDSAKey(SecKeyRef ref
);
887 Boolean
SecKeyIsCDSAKey(SecKeyRef ref
) {
888 return ref
->key_class
== &kSecCDSAKeyDescriptor
;
892 static OSStatus
SecKeyCreatePairInternal(
893 SecKeychainRef keychainRef
,
894 CSSM_ALGORITHMS algorithm
,
895 uint32 keySizeInBits
,
896 CSSM_CC_HANDLE contextHandle
,
897 CSSM_KEYUSE publicKeyUsage
,
898 uint32 publicKeyAttr
,
899 CSSM_KEYUSE privateKeyUsage
,
900 uint32 privateKeyAttr
,
901 SecAccessRef initialAccess
,
902 SecKeyRef
* publicKeyRef
,
903 SecKeyRef
* privateKeyRef
)
908 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
909 SecPointer
<KeyItem
> pubItem
, privItem
;
910 if (((publicKeyAttr
| privateKeyAttr
) & CSSM_KEYATTR_PERMANENT
) != 0) {
911 keychain
= Keychain::optional(keychainRef
);
913 StMaybeLock
<Mutex
> _(keychain
? keychain
->getKeychainMutex() : NULL
);
914 KeyItem::createPair(keychain
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, publicKeyAttr
,
915 privateKeyUsage
, privateKeyAttr
, theAccess
, pubItem
, privItem
);
917 // Return the generated keys.
919 *publicKeyRef
= pubItem
->handle();
921 *privateKeyRef
= privItem
->handle();
928 SecKeychainRef keychainRef
,
929 CSSM_ALGORITHMS algorithm
,
930 uint32 keySizeInBits
,
931 CSSM_CC_HANDLE contextHandle
,
932 CSSM_KEYUSE publicKeyUsage
,
933 uint32 publicKeyAttr
,
934 CSSM_KEYUSE privateKeyUsage
,
935 uint32 privateKeyAttr
,
936 SecAccessRef initialAccess
,
937 SecKeyRef
* publicKeyRef
,
938 SecKeyRef
* privateKeyRef
)
940 OSStatus result
= SecKeyCreatePairInternal(keychainRef
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
,
941 publicKeyAttr
, privateKeyUsage
, privateKeyAttr
, initialAccess
, publicKeyRef
, privateKeyRef
);
949 SecKeyGetCSSMKey(SecKeyRef key
, const CSSM_KEY
**cssmKey
)
953 Required(cssmKey
) = KeyItem::required(key
)->key();
963 static ModuleNexus
<Mutex
> gSecReturnedKeyCSPsMutex
;
964 static ModuleNexus
<std::set
<CssmClient::CSP
>> gSecReturnedKeyCSPs
;
967 SecKeyGetCSPHandle(SecKeyRef keyRef
, CSSM_CSP_HANDLE
*cspHandle
)
971 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
973 // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP).
974 // Keep a global pointer to it to force the CSP to stay live forever.
975 CssmClient::CSP returnedKeyCSP
= keyItem
->csp();
977 StLock
<Mutex
> _(gSecReturnedKeyCSPsMutex());
978 gSecReturnedKeyCSPs().insert(returnedKeyCSP
);
980 Required(cspHandle
) = returnedKeyCSP
->handle();
985 /* deprecated as of 10.8 */
987 SecKeyGetAlgorithmID(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
**algid
)
991 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
992 Required(algid
) = &keyItem
->algorithmIdentifier();
998 SecKeyGetStrengthInBits(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
*algid
, unsigned int *strength
)
1002 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
1003 Required(strength
) = keyItem
->strengthInBits(algid
);
1009 SecKeyGetCredentials(
1011 CSSM_ACL_AUTHORIZATION_TAG operation
,
1012 SecCredentialType credentialType
,
1013 const CSSM_ACCESS_CREDENTIALS
**outCredentials
)
1017 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
1018 Required(outCredentials
) = keyItem
->getCredentials(operation
, credentialType
);
1025 SecKeychainRef keychainRef
,
1026 const CSSM_KEY
*publicCssmKey
,
1027 const CSSM_KEY
*privateCssmKey
,
1028 SecAccessRef initialAccess
,
1029 SecKeyRef
* publicKey
,
1030 SecKeyRef
* privateKey
)
1034 Keychain keychain
= Keychain::optional(keychainRef
);
1035 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
1036 SecPointer
<KeyItem
> pubItem
, privItem
;
1038 KeyItem::importPair(keychain
,
1039 Required(publicCssmKey
),
1040 Required(privateCssmKey
),
1045 // Return the generated keys.
1047 *publicKey
= pubItem
->handle();
1049 *privateKey
= privItem
->handle();
1055 SecKeyGenerateWithAttributes(
1056 SecKeychainAttributeList
* attrList
,
1057 SecKeychainRef keychainRef
,
1058 CSSM_ALGORITHMS algorithm
,
1059 uint32 keySizeInBits
,
1060 CSSM_CC_HANDLE contextHandle
,
1061 CSSM_KEYUSE keyUsage
,
1063 SecAccessRef initialAccess
,
1069 SecPointer
<Access
> theAccess
;
1072 keychain
= KeychainImpl::required(keychainRef
);
1074 theAccess
= Access::required(initialAccess
);
1076 SecPointer
<KeyItem
> item
= KeyItem::generateWithAttributes(attrList
,
1085 // Return the generated key.
1087 *keyRef
= item
->handle();
1094 SecKeychainRef keychainRef
,
1095 CSSM_ALGORITHMS algorithm
,
1096 uint32 keySizeInBits
,
1097 CSSM_CC_HANDLE contextHandle
,
1098 CSSM_KEYUSE keyUsage
,
1100 SecAccessRef initialAccess
,
1103 return SecKeyGenerateWithAttributes(NULL
,
1104 keychainRef
, algorithm
, keySizeInBits
,
1105 contextHandle
, keyUsage
, keyAttr
,
1106 initialAccess
, keyRef
);
1110 /* Generate a floating key reference from a CSSM_KEY */
1112 SecKeyCreateWithCSSMKey(const CSSM_KEY
*cssmKey
,
1118 if(cssmKey
->KeyData
.Length
== 0){
1119 MacOSError::throwMe(errSecInvalidAttributeKeyLength
);
1121 if(cssmKey
->KeyData
.Data
== NULL
){
1122 MacOSError::throwMe(errSecInvalidPointer
);
1124 CssmClient::CSP
csp(cssmKey
->KeyHeader
.CspId
);
1125 CssmClient::Key
key(csp
, *cssmKey
);
1126 KeyItem
*item
= new KeyItem(key
);
1128 // Return the generated key.
1130 *keyRef
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, (const uint8_t *)item
, 0, 0);
1137 static u_int32_t
ConvertCFStringToInteger(CFStringRef ref
)
1144 // figure out the size of the string
1145 CFIndex numChars
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref
), kCFStringEncodingUTF8
);
1146 char *buffer
= (char *)malloc(numChars
);
1147 if (NULL
== buffer
) {
1148 UnixError::throwMe(ENOMEM
);
1150 if (!CFStringGetCString(ref
, buffer
, numChars
, kCFStringEncodingUTF8
))
1153 MacOSError::throwMe(errSecParam
);
1156 u_int32_t result
= atoi(buffer
);
1163 static OSStatus
CheckAlgorithmType(CFDictionaryRef parameters
, CSSM_ALGORITHMS
&algorithms
)
1165 // figure out the algorithm to use
1166 CFStringRef ktype
= (CFStringRef
) CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
1172 if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
1173 algorithms
= CSSM_ALGID_RSA
;
1174 return errSecSuccess
;
1175 } else if(CFEqual(ktype
, kSecAttrKeyTypeECDSA
) ||
1176 CFEqual(ktype
, kSecAttrKeyTypeEC
)) {
1177 algorithms
= CSSM_ALGID_ECDSA
;
1178 return errSecSuccess
;
1179 } else if(CFEqual(ktype
, kSecAttrKeyTypeAES
)) {
1180 algorithms
= CSSM_ALGID_AES
;
1181 return errSecSuccess
;
1182 } else if(CFEqual(ktype
, kSecAttrKeyType3DES
)) {
1183 algorithms
= CSSM_ALGID_3DES
;
1184 return errSecSuccess
;
1186 return errSecUnsupportedAlgorithm
;
1192 static OSStatus
GetKeySize(CFDictionaryRef parameters
, CSSM_ALGORITHMS algorithms
, uint32
&keySizeInBits
)
1195 // get the key size and check it for validity
1196 CFTypeRef ref
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
1198 keySizeInBits
= kSecDefaultKeySize
;
1200 CFTypeID bitSizeType
= CFGetTypeID(ref
);
1201 if (bitSizeType
== CFStringGetTypeID())
1202 keySizeInBits
= ConvertCFStringToInteger((CFStringRef
) ref
);
1203 else if (bitSizeType
== CFNumberGetTypeID())
1204 CFNumberGetValue((CFNumberRef
) ref
, kCFNumberSInt32Type
, &keySizeInBits
);
1205 else return errSecParam
;
1208 switch (algorithms
) {
1209 case CSSM_ALGID_ECDSA
:
1210 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecp256r1
;
1211 if(keySizeInBits
== kSecp192r1
|| keySizeInBits
== kSecp256r1
|| keySizeInBits
== kSecp384r1
|| keySizeInBits
== kSecp521r1
) return errSecSuccess
;
1213 case CSSM_ALGID_RSA
:
1214 if(keySizeInBits
% 8) return errSecParam
;
1215 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= 2048;
1216 if(keySizeInBits
>= kSecRSAMin
&& keySizeInBits
<= kSecRSAMax
) return errSecSuccess
;
1218 case CSSM_ALGID_AES
:
1219 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecAES128
;
1220 if(keySizeInBits
== kSecAES128
|| keySizeInBits
== kSecAES192
|| keySizeInBits
== kSecAES256
) return errSecSuccess
;
1222 case CSSM_ALGID_3DES
:
1223 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSec3DES192
;
1224 if(keySizeInBits
== kSec3DES192
) return errSecSuccess
;
1243 struct ParameterAttribute
1245 const CFStringRef
*name
;
1251 static ParameterAttribute gAttributes
[] =
1258 &kSecAttrIsPermanent
,
1262 &kSecAttrApplicationTag
,
1266 &kSecAttrEffectiveKeySize
,
1270 &kSecAttrCanEncrypt
,
1274 &kSecAttrCanDecrypt
,
1295 const int kNumberOfAttributes
= sizeof(gAttributes
) / sizeof(ParameterAttribute
);
1297 static OSStatus
ScanDictionaryForParameters(CFDictionaryRef parameters
, void* attributePointers
[])
1300 for (i
= 0; i
< kNumberOfAttributes
; ++i
)
1302 // see if the corresponding tag exists in the dictionary
1303 CFTypeRef value
= CFDictionaryGetValue(parameters
, *(gAttributes
[i
].name
));
1306 switch (gAttributes
[i
].type
)
1309 // just return the value
1310 *(CFTypeRef
*) attributePointers
[i
] = value
;
1315 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1316 *(bool*) attributePointers
[i
] = CFBooleanGetValue(bRef
);
1322 CFNumberRef nRef
= (CFNumberRef
) value
;
1323 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, attributePointers
[i
]);
1330 return errSecSuccess
;
1335 static OSStatus
GetKeyParameters(CFDictionaryRef parameters
, int keySize
, bool isPublic
, CSSM_KEYUSE
&keyUse
, uint32
&attrs
, CFTypeRef
&labelRef
, CFDataRef
&applicationTagRef
)
1337 // establish default values
1339 bool isPermanent
= false;
1340 applicationTagRef
= NULL
;
1341 CFTypeRef effectiveKeySize
= NULL
;
1342 bool canDecrypt
= isPublic
? false : true;
1343 bool canEncrypt
= !canDecrypt
;
1344 bool canDerive
= true;
1345 bool canSign
= isPublic
? false : true;
1346 bool canVerify
= !canSign
;
1347 bool canUnwrap
= isPublic
? false : true;
1348 attrs
= CSSM_KEYATTR_EXTRACTABLE
;
1351 void* attributePointers
[] = {&labelRef
, &isPermanent
, &applicationTagRef
, &effectiveKeySize
, &canEncrypt
, &canDecrypt
,
1352 &canDerive
, &canSign
, &canVerify
, &canUnwrap
};
1354 // look for modifiers in the general dictionary
1355 OSStatus result
= ScanDictionaryForParameters(parameters
, attributePointers
);
1356 if (result
!= errSecSuccess
)
1361 // see if we have anything which modifies the defaults
1365 key
= kSecPublicKeyAttrs
;
1369 key
= kSecPrivateKeyAttrs
;
1372 CFTypeRef dType
= CFDictionaryGetValue(parameters
, key
);
1375 // this had better be a dictionary
1376 if (CFGetTypeID(dType
) != CFDictionaryGetTypeID())
1381 // pull any additional parameters out of this dictionary
1382 result
= ScanDictionaryForParameters((CFDictionaryRef
)dType
, attributePointers
);
1383 if (result
!= errSecSuccess
)
1389 // figure out the key usage
1393 keyUse
|= CSSM_KEYUSE_DECRYPT
;
1398 keyUse
|= CSSM_KEYUSE_ENCRYPT
;
1403 keyUse
|= CSSM_KEYUSE_DERIVE
;
1408 keyUse
|= CSSM_KEYUSE_SIGN
;
1413 keyUse
|= CSSM_KEYUSE_VERIFY
;
1418 keyUse
|= CSSM_KEYUSE_UNWRAP
;
1421 // public key is always extractable;
1422 // private key is extractable by default unless explicitly set to false
1423 CFTypeRef value
= NULL
;
1424 if (!isPublic
&& CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
) && value
)
1426 Boolean keyIsExtractable
= CFEqual(kCFBooleanTrue
, value
);
1427 if (!keyIsExtractable
)
1432 attrs
|= CSSM_KEYATTR_PERMANENT
;
1435 return errSecSuccess
;
1440 static OSStatus
MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters
,
1441 CSSM_ALGORITHMS
&algorithms
,
1442 uint32
&keySizeInBits
,
1443 CSSM_KEYUSE
&publicKeyUse
,
1444 uint32
&publicKeyAttr
,
1445 CFTypeRef
&publicKeyLabelRef
,
1446 CFDataRef
&publicKeyAttributeTagRef
,
1447 CSSM_KEYUSE
&privateKeyUse
,
1448 uint32
&privateKeyAttr
,
1449 CFTypeRef
&privateKeyLabelRef
,
1450 CFDataRef
&privateKeyAttributeTagRef
,
1451 SecAccessRef
&initialAccess
)
1455 result
= CheckAlgorithmType(parameters
, algorithms
);
1456 if (result
!= errSecSuccess
)
1461 result
= GetKeySize(parameters
, algorithms
, keySizeInBits
);
1462 if (result
!= errSecSuccess
)
1467 result
= GetKeyParameters(parameters
, keySizeInBits
, false, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1468 if (result
!= errSecSuccess
)
1473 result
= GetKeyParameters(parameters
, keySizeInBits
, true, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1474 if (result
!= errSecSuccess
)
1479 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&initialAccess
))
1481 initialAccess
= NULL
;
1483 else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess
))
1488 return errSecSuccess
;
1493 static OSStatus
SetKeyLabelAndTag(SecKeyRef keyRef
, CFTypeRef label
, CFDataRef tag
)
1495 int numToModify
= 0;
1506 if (numToModify
== 0)
1508 return errSecSuccess
;
1511 SecKeychainAttributeList attrList
;
1512 SecKeychainAttribute attributes
[numToModify
];
1519 if (CFStringGetTypeID() == CFGetTypeID(label
)) {
1520 CFStringRef label_string
= static_cast<CFStringRef
>(label
);
1521 attributes
[i
].tag
= kSecKeyPrintName
;
1522 attributes
[i
].data
= (void*) CFStringGetCStringPtr(label_string
, kCFStringEncodingUTF8
);
1523 if (NULL
== attributes
[i
].data
) {
1524 CFIndex buffer_length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string
), kCFStringEncodingUTF8
);
1525 data
= attributes
[i
].data
= malloc((size_t)buffer_length
);
1526 if (NULL
== attributes
[i
].data
) {
1527 UnixError::throwMe(ENOMEM
);
1529 if (!CFStringGetCString(label_string
, static_cast<char *>(attributes
[i
].data
), buffer_length
, kCFStringEncodingUTF8
)) {
1531 MacOSError::throwMe(errSecParam
);
1534 attributes
[i
].length
= (UInt32
)strlen(static_cast<char *>(attributes
[i
].data
));
1535 } else if (CFDataGetTypeID() == CFGetTypeID(label
)) {
1536 // 10.6 bug compatibility
1537 CFDataRef label_data
= static_cast<CFDataRef
>(label
);
1538 attributes
[i
].tag
= kSecKeyLabel
;
1539 attributes
[i
].data
= (void*) CFDataGetBytePtr(label_data
);
1540 attributes
[i
].length
= (UInt32
)CFDataGetLength(label_data
);
1542 MacOSError::throwMe(errSecParam
);
1549 attributes
[i
].tag
= kSecKeyApplicationTag
;
1550 attributes
[i
].data
= (void*) CFDataGetBytePtr(tag
);
1551 attributes
[i
].length
= (UInt32
)CFDataGetLength(tag
);
1555 attrList
.count
= numToModify
;
1556 attrList
.attr
= attributes
;
1558 OSStatus result
= SecKeychainItemModifyAttributesAndData((SecKeychainItemRef
) keyRef
, &attrList
, 0, NULL
);
1568 static CFTypeRef
GetAttributeFromParams(CFDictionaryRef parameters
, CFTypeRef attr
, CFTypeRef subParams
) {
1569 if (subParams
!= NULL
) {
1570 CFDictionaryRef subParamsDict
= (CFDictionaryRef
)CFDictionaryGetValue(parameters
, subParams
);
1571 if (subParamsDict
!= NULL
) {
1572 CFTypeRef value
= CFDictionaryGetValue(subParamsDict
, attr
);
1573 if (value
!= NULL
) {
1578 return CFDictionaryGetValue(parameters
, attr
);
1581 extern "C" OSStatus
SecKeyGeneratePair_ios(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
);
1584 /* Generate a private/public keypair. */
1586 SecKeyGeneratePairInternal(
1587 bool alwaysPermanent
,
1588 CFDictionaryRef parameters
,
1589 SecKeyRef
*publicKey
,
1590 SecKeyRef
*privateKey
)
1594 Required(parameters
);
1595 Required(publicKey
);
1596 Required(privateKey
);
1598 bool forceIOSKey
= false;
1599 if (_CFMZEnabled()) {
1600 // On Marzipan, always go iOS SecItem/SecKey route, do not drag CSSM keys in.
1603 CFTypeRef tokenID
= GetAttributeFromParams(parameters
, kSecAttrTokenID
, NULL
);
1604 CFTypeRef noLegacy
= GetAttributeFromParams(parameters
, kSecUseDataProtectionKeychain
, NULL
);
1605 #pragma clang diagnostic push
1606 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1607 if (!noLegacy
) { // Also lookup via deprecated symbol because we do CFDictionaryGetValue and your CFDict might be an idiot
1608 noLegacy
= GetAttributeFromParams(parameters
, kSecAttrNoLegacy
, NULL
);
1610 #pragma clang diagnostic pop
1611 CFTypeRef sync
= GetAttributeFromParams(parameters
, kSecAttrSynchronizable
, kSecPrivateKeyAttrs
);
1612 CFTypeRef accessControl
= GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPrivateKeyAttrs
) ?:
1613 GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPublicKeyAttrs
);
1614 CFTypeRef accessGroup
= GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPrivateKeyAttrs
) ?:
1615 GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPublicKeyAttrs
);
1616 // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain).
1617 forceIOSKey
= (tokenID
!= NULL
||
1618 (noLegacy
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)noLegacy
)) ||
1619 (sync
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)sync
)) ||
1620 accessControl
!= NULL
|| (accessGroup
!= NULL
&& CFEqual(accessGroup
, kSecAttrAccessGroupToken
)));
1624 // Generate keys in iOS keychain.
1625 return SecKeyGeneratePair_ios(parameters
, publicKey
, privateKey
);
1628 CSSM_ALGORITHMS algorithms
;
1629 uint32 keySizeInBits
;
1630 CSSM_KEYUSE publicKeyUse
;
1631 uint32 publicKeyAttr
;
1632 CFTypeRef publicKeyLabelRef
;
1633 CFDataRef publicKeyAttributeTagRef
;
1634 CSSM_KEYUSE privateKeyUse
;
1635 uint32 privateKeyAttr
;
1636 CFTypeRef privateKeyLabelRef
;
1637 CFDataRef privateKeyAttributeTagRef
;
1638 SecAccessRef initialAccess
;
1639 SecKeychainRef keychain
;
1641 OSStatus result
= MakeKeyGenParametersFromDictionary(parameters
, algorithms
, keySizeInBits
, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
,
1642 publicKeyAttributeTagRef
, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
,
1645 if (result
!= errSecSuccess
) {
1649 // verify keychain parameter
1650 keychain
= (SecKeychainRef
)CFDictionaryGetValue(parameters
, kSecUseKeychain
);
1651 if (keychain
!= NULL
&& SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1655 if (alwaysPermanent
) {
1656 publicKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1657 privateKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1660 // do the key generation
1661 result
= SecKeyCreatePair(keychain
, algorithms
, keySizeInBits
, 0, publicKeyUse
, publicKeyAttr
, privateKeyUse
, privateKeyAttr
, initialAccess
, publicKey
, privateKey
);
1662 if (result
!= errSecSuccess
) {
1666 // set the label and print attributes on the keys
1667 SetKeyLabelAndTag(*publicKey
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1668 SetKeyLabelAndTag(*privateKey
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1675 SecKeyGeneratePair(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
1676 return SecKeyGeneratePairInternal(true, parameters
, publicKey
, privateKey
);
1680 SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef
*error
) {
1681 SecKeyRef privateKey
= NULL
, publicKey
= NULL
;
1682 OSStatus status
= SecKeyGeneratePairInternal(false, parameters
, &publicKey
, &privateKey
);
1683 SecError(status
, error
, CFSTR("failed to generate asymmetric keypair"));
1684 if (publicKey
!= NULL
) {
1685 CFRelease(publicKey
);
1690 OSStatus
SecKeyRawVerifyOSX(
1691 SecKeyRef key
, /* Public key */
1692 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
1693 const uint8_t *signedData
, /* signature over this data */
1694 size_t signedDataLen
, /* length of dataToSign */
1695 const uint8_t *sig
, /* signature */
1698 return SecKeyRawVerify(key
,padding
,signedData
,signedDataLen
,sig
,sigLen
);
1706 utilGetStringFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, CFTypeRef defaultValue
)
1708 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1709 if (value
!= NULL
) return value
;
1710 return defaultValue
;
1714 utilGetNumberFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t defaultValue
)
1716 uint32_t integerValue
;
1717 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1718 if (value
!= NULL
) {
1719 CFNumberRef nRef
= (CFNumberRef
) value
;
1720 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, &integerValue
);
1721 return integerValue
;
1723 return defaultValue
;
1727 utilGetMaskValFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t maskValue
)
1729 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1730 if (value
!= NULL
) {
1731 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1732 if(CFBooleanGetValue(bRef
)) return maskValue
;
1738 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters
, CSSM_ALGORITHMS
*algorithm
, uint32
*keySizeInBits
, CSSM_KEYUSE
*keyUsage
, CSSM_KEYCLASS
*keyClass
)
1740 CFTypeRef algorithmDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeAES
);
1741 CFTypeRef keyClassDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1743 if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeAES
)) {
1744 *algorithm
= CSSM_ALGID_AES
;
1745 *keySizeInBits
= 128;
1746 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1747 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDES
)) {
1748 *algorithm
= CSSM_ALGID_DES
;
1749 *keySizeInBits
= 128;
1750 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1751 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyType3DES
)) {
1752 *algorithm
= CSSM_ALGID_3DES_3KEY_EDE
;
1753 *keySizeInBits
= 128;
1754 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1755 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC4
)) {
1756 *algorithm
= CSSM_ALGID_RC4
;
1757 *keySizeInBits
= 128;
1758 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1759 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC2
)) {
1760 *algorithm
= CSSM_ALGID_RC2
;
1761 *keySizeInBits
= 128;
1762 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1763 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeCAST
)) {
1764 *algorithm
= CSSM_ALGID_CAST
;
1765 *keySizeInBits
= 128;
1766 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1767 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRSA
)) {
1768 *algorithm
= CSSM_ALGID_RSA
;
1769 *keySizeInBits
= 128;
1770 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1771 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDSA
)) {
1772 *algorithm
= CSSM_ALGID_DSA
;
1773 *keySizeInBits
= 128;
1774 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1775 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeECDSA
) ||
1776 CFEqual(algorithmDictValue
, kSecAttrKeyTypeEC
)) {
1777 *algorithm
= CSSM_ALGID_ECDSA
;
1778 *keySizeInBits
= 128;
1779 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1781 *algorithm
= CSSM_ALGID_AES
;
1782 *keySizeInBits
= 128;
1783 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1786 if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPublic
)) {
1787 *keyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
1788 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPrivate
)) {
1789 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1790 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassSymmetric
)) {
1791 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1794 *keySizeInBits
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, *keySizeInBits
);
1795 *keyUsage
= utilGetMaskValFromCFDict(parameters
, kSecAttrCanEncrypt
, CSSM_KEYUSE_ENCRYPT
) |
1796 utilGetMaskValFromCFDict(parameters
, kSecAttrCanDecrypt
, CSSM_KEYUSE_DECRYPT
) |
1797 utilGetMaskValFromCFDict(parameters
, kSecAttrCanWrap
, CSSM_KEYUSE_WRAP
) |
1798 utilGetMaskValFromCFDict(parameters
, kSecAttrCanUnwrap
, CSSM_KEYUSE_UNWRAP
);
1801 if(*keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
|| *keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
) {
1802 *keyUsage
|= utilGetMaskValFromCFDict(parameters
, kSecAttrCanSign
, CSSM_KEYUSE_SIGN
) |
1803 utilGetMaskValFromCFDict(parameters
, kSecAttrCanVerify
, CSSM_KEYUSE_VERIFY
);
1806 if(*keyUsage
== 0) {
1807 switch (*keyClass
) {
1808 case CSSM_KEYCLASS_PRIVATE_KEY
:
1809 *keyUsage
= CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
;
1811 case CSSM_KEYCLASS_PUBLIC_KEY
:
1812 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
;
1815 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
;
1822 utilCopyDefaultKeyLabel(void)
1824 // generate a default label from the current date
1825 CFDateRef dateNow
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent());
1826 CFStringRef defaultLabel
= CFCopyDescription(dateNow
);
1829 return defaultLabel
;
1833 SecKeyGenerateSymmetric(CFDictionaryRef parameters
, CFErrorRef
*error
)
1835 OSStatus result
= errSecParam
; // default result for an early exit
1836 SecKeyRef key
= NULL
;
1837 SecKeychainRef keychain
= NULL
;
1838 SecAccessRef access
;
1840 CFStringRef appLabel
;
1842 CFStringRef dateLabel
= NULL
;
1844 CSSM_ALGORITHMS algorithm
;
1845 uint32 keySizeInBits
;
1846 CSSM_KEYUSE keyUsage
;
1847 uint32 keyAttr
= CSSM_KEYATTR_RETURN_DEFAULT
;
1848 CSSM_KEYCLASS keyClass
;
1850 Boolean isPermanent
;
1851 Boolean isExtractable
;
1853 // verify keychain parameter
1854 if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
))
1856 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1863 // verify permanent parameter
1864 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsPermanent
, (const void **)&value
))
1865 isPermanent
= false;
1866 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1869 isPermanent
= CFEqual(kCFBooleanTrue
, value
);
1871 if (keychain
== NULL
) {
1872 // no keychain was specified, so use the default keychain
1873 result
= SecKeychainCopyDefault(&keychain
);
1875 keyAttr
|= CSSM_KEYATTR_PERMANENT
;
1878 // verify extractable parameter
1879 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
))
1880 isExtractable
= true; // default to extractable if value not specified
1881 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1884 isExtractable
= CFEqual(kCFBooleanTrue
, value
);
1886 keyAttr
|= CSSM_KEYATTR_EXTRACTABLE
;
1888 // verify access parameter
1889 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&access
))
1891 else if (SecAccessGetTypeID() != CFGetTypeID(access
))
1894 // verify label parameter
1895 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrLabel
, (const void **)&label
))
1896 label
= (dateLabel
= utilCopyDefaultKeyLabel()); // no label provided, so use default
1897 else if (CFStringGetTypeID() != CFGetTypeID(label
))
1900 // verify application label parameter
1901 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationLabel
, (const void **)&appLabel
))
1902 appLabel
= (dateLabel
) ? dateLabel
: (dateLabel
= utilCopyDefaultKeyLabel());
1903 else if (CFStringGetTypeID() != CFGetTypeID(appLabel
))
1906 // verify application tag parameter
1907 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationTag
, (const void **)&appTag
))
1909 else if (CFStringGetTypeID() != CFGetTypeID(appTag
))
1912 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1915 // the generated key will not be stored in any keychain
1916 result
= SecKeyGenerate(keychain
, algorithm
, keySizeInBits
, 0, keyUsage
, keyAttr
, access
, &key
);
1919 // we can set the label attributes on the generated key if it's a keychain item
1920 size_t labelBufLen
= (label
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label
), kCFStringEncodingUTF8
) + 1 : 1;
1921 char *labelBuf
= (char *)malloc(labelBufLen
);
1922 size_t appLabelBufLen
= (appLabel
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel
), kCFStringEncodingUTF8
) + 1 : 1;
1923 char *appLabelBuf
= (char *)malloc(appLabelBufLen
);
1924 size_t appTagBufLen
= (appTag
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag
), kCFStringEncodingUTF8
) + 1 : 1;
1925 char *appTagBuf
= (char *)malloc(appTagBufLen
);
1927 if (!label
|| !CFStringGetCString(label
, labelBuf
, labelBufLen
-1, kCFStringEncodingUTF8
))
1929 if (!appLabel
|| !CFStringGetCString(appLabel
, appLabelBuf
, appLabelBufLen
-1, kCFStringEncodingUTF8
))
1931 if (!appTag
|| !CFStringGetCString(appTag
, appTagBuf
, appTagBufLen
-1, kCFStringEncodingUTF8
))
1934 SecKeychainAttribute attrs
[] = {
1935 { kSecKeyPrintName
, (UInt32
)strlen(labelBuf
), (char *)labelBuf
},
1936 { kSecKeyLabel
, (UInt32
)strlen(appLabelBuf
), (char *)appLabelBuf
},
1937 { kSecKeyApplicationTag
, (UInt32
)strlen(appTagBuf
), (char *)appTagBuf
} };
1938 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
1939 if (!appTag
) --attributes
.count
;
1941 result
= SecKeyGenerateWithAttributes(&attributes
,
1942 keychain
, algorithm
, keySizeInBits
, 0,
1943 keyUsage
, keyAttr
, access
, &key
);
1951 if (result
&& error
) {
1952 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, result
, NULL
);
1955 CFRelease(dateLabel
);
1957 CFRelease(keychain
);
1965 SecKeyCreateFromData(CFDictionaryRef parameters
, CFDataRef keyData
, CFErrorRef
*error
)
1967 CSSM_ALGORITHMS algorithm
;
1968 uint32 keySizeInBits
;
1969 CSSM_KEYUSE keyUsage
;
1970 CSSM_KEYCLASS keyClass
;
1973 if(keyData
== NULL
|| CFDataGetLength(keyData
) == 0){
1974 MacOSError::throwMe(errSecUnsupportedKeySize
);
1977 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1979 CSSM_CSP_HANDLE cspHandle
= cuCspStartup(CSSM_FALSE
); // TRUE => CSP, FALSE => CSPDL
1981 SecKeyImportExportParameters iparam
;
1982 memset(&iparam
, 0, sizeof(iparam
));
1983 iparam
.keyUsage
= keyUsage
;
1985 CFRef
<CFDataRef
> data
;
1986 SecExternalItemType itype
;
1988 case CSSM_KEYCLASS_PRIVATE_KEY
:
1989 itype
= kSecItemTypePrivateKey
;
1991 case CSSM_KEYCLASS_PUBLIC_KEY
: {
1992 itype
= kSecItemTypePublicKey
;
1993 // Public key import expects public key in SubjPublicKey X509 format. We want to accept both bare and x509 format,
1994 // so we have to detect bare format here and extend to full X509 if detected.
1995 data
.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm
, keySizeInBits
, keyData
));
1998 case CSSM_KEYCLASS_SESSION_KEY
:
1999 itype
= kSecItemTypeSessionKey
;
2002 itype
= kSecItemTypeUnknown
;
2006 CFMutableArrayRef ka
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2007 // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful.
2008 crtn
= impExpImportRawKey(data
? CFDataRef(data
) : keyData
, kSecFormatUnknown
, itype
, algorithm
, NULL
, cspHandle
, 0, NULL
, NULL
, ka
);
2009 if (crtn
== CSSM_OK
&& CFArrayGetCount((CFArrayRef
)ka
)) {
2010 SecKeyRef sk
= (SecKeyRef
)CFArrayGetValueAtIndex((CFArrayRef
)ka
, 0);
2017 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, crtn
? crtn
: CSSM_ERRCODE_INTERNAL_ERROR
, NULL
);
2025 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable
, dispatch_queue_t deliveryQueue
,
2026 SecKeyGeneratePairBlock result
)
2028 CFDictionaryRef parameters
= CFDictionaryCreateCopy(NULL
, parametersWhichMightBeMutiable
);
2029 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
2030 SecKeyRef publicKey
= NULL
;
2031 SecKeyRef privateKey
= NULL
;
2032 OSStatus status
= SecKeyGeneratePair(parameters
, &publicKey
, &privateKey
);
2033 dispatch_async(deliveryQueue
, ^{
2034 CFErrorRef error
= NULL
;
2035 if (errSecSuccess
!= status
) {
2036 error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, NULL
);
2038 result(publicKey
, privateKey
, error
);
2043 CFRelease(publicKey
);
2046 CFRelease(privateKey
);
2048 CFRelease(parameters
);
2053 static inline void utilClearAndFree(void *p
, size_t len
) {
2055 if(len
) bzero(p
, len
);
2061 SecKeyDeriveFromPassword(CFStringRef password
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2063 CCPBKDFAlgorithm algorithm
;
2064 CFIndex passwordLen
= 0;
2065 CFDataRef keyData
= NULL
;
2066 char *thePassword
= NULL
;
2067 uint8_t *salt
= NULL
;
2068 uint8_t *derivedKey
= NULL
;
2069 size_t saltLen
= 0, derivedKeyLen
= 0;
2071 CFDataRef saltDictValue
, algorithmDictValue
;
2072 SecKeyRef retval
= NULL
;
2074 /* Pick Values from parameters */
2076 if((saltDictValue
= (CFDataRef
) CFDictionaryGetValue(parameters
, kSecAttrSalt
)) == NULL
) {
2078 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecMissingAlgorithmParms
, NULL
);
2083 derivedKeyLen
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, 128);
2084 // This value come in bits but the rest of the code treats it as bytes
2087 algorithmDictValue
= (CFDataRef
) utilGetStringFromCFDict(parameters
, kSecAttrPRF
, kSecAttrPRFHmacAlgSHA256
);
2089 rounds
= utilGetNumberFromCFDict(parameters
, kSecAttrRounds
, 0);
2091 /* Convert any remaining parameters and get the password bytes */
2093 saltLen
= CFDataGetLength(saltDictValue
);
2094 if((salt
= (uint8_t *) malloc(saltLen
)) == NULL
) {
2096 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2101 CFDataGetBytes(saltDictValue
, CFRangeMake(0, saltLen
), (UInt8
*) salt
);
2103 passwordLen
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1;
2104 if((thePassword
= (char *) malloc(passwordLen
)) == NULL
) {
2106 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2110 CFStringGetBytes(password
, CFRangeMake(0, CFStringGetLength(password
)), kCFStringEncodingUTF8
, '?', FALSE
, (UInt8
*)thePassword
, passwordLen
, &passwordLen
);
2112 if((derivedKey
= (uint8_t *) malloc(derivedKeyLen
)) == NULL
) {
2114 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2119 if(algorithmDictValue
== NULL
) {
2120 algorithm
= kCCPRFHmacAlgSHA1
; /* default */
2121 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA1
)) {
2122 algorithm
= kCCPRFHmacAlgSHA1
;
2123 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA224
)) {
2124 algorithm
= kCCPRFHmacAlgSHA224
;
2125 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA256
)) {
2126 algorithm
= kCCPRFHmacAlgSHA256
;
2127 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA384
)) {
2128 algorithm
= kCCPRFHmacAlgSHA384
;
2129 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA512
)) {
2130 algorithm
= kCCPRFHmacAlgSHA512
;
2133 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidAlgorithmParms
, NULL
);
2139 rounds
= 33333; // we need to pass back a consistent value since there's no way to record the round count.
2142 if(CCKeyDerivationPBKDF(kCCPBKDF2
, thePassword
, passwordLen
, salt
, saltLen
, algorithm
, rounds
, derivedKey
, derivedKeyLen
)) {
2144 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2149 if((keyData
= CFDataCreate(NULL
, derivedKey
, derivedKeyLen
)) != NULL
) {
2150 retval
= SecKeyCreateFromData(parameters
, keyData
, error
);
2154 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2159 utilClearAndFree(salt
, saltLen
);
2160 utilClearAndFree(thePassword
, passwordLen
);
2161 utilClearAndFree(derivedKey
, derivedKeyLen
);
2166 SecKeyWrapSymmetric(SecKeyRef keyToWrap
, SecKeyRef wrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2169 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);
2175 SecKeyUnwrapSymmetric(CFDataRef
*keyToUnwrap
, SecKeyRef unwrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2178 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);