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
,
807 .extraBytes
= (sizeof(class CDSASecKey
) > sizeof(struct __SecKey
) ? (sizeof(class CDSASecKey
) - sizeof(struct __SecKey
)) : 0),
809 .init
= SecCDSAKeyInit
,
810 .destroy
= SecCDSAKeyDestroy
,
811 .blockSize
= SecCDSAKeyGetBlockSize
,
812 .copyDictionary
= SecCDSAKeyCopyAttributeDictionary
,
813 .getAlgorithmID
= SecCDSAKeyGetAlgorithmId
,
814 .copyPublic
= SecCDSAKeyCopyPublicBytes
,
815 .copyExternalRepresentation
= SecCDSAKeyCopyExternalRepresentation
,
816 .copyPublicKey
= SecCDSAKeyCopyPublicKey
,
817 .copyOperationResult
= SecCDSAKeyCopyOperationResult
,
818 .isEqual
= SecCDSAKeyIsEqual
,
819 .setParameter
= SecCDSAKeySetParameter
,
823 namespace KeychainCore
{
824 SecCFObject
*KeyItem::fromSecKeyRef(CFTypeRef ptr
) {
825 if (ptr
== NULL
|| CFGetTypeID(ptr
) != SecKeyGetTypeID()) {
829 SecKeyRef key
= static_cast<SecKeyRef
>(const_cast<void *>(ptr
));
830 if (key
->key_class
== &kSecCDSAKeyDescriptor
) {
831 return static_cast<SecCFObject
*>(key
->key
);
834 CFRef
<SecKeyRef
> cdsaKey
= SecKeyCopyAuxilliaryCDSAKeyForKey(key
);
836 // Create CDSA key from exported data of existing key.
837 CFRef
<CFDictionaryRef
> keyAttributes
= SecKeyCopyAttributes(key
);
839 CFRef
<CFDataRef
> keyData
= SecKeyCopyExternalRepresentation(key
, NULL
);
841 CFTypeRef pubKeyHash
= CFDictionaryGetValue(keyAttributes
, kSecAttrApplicationLabel
);
842 const void *keys
[] = { kSecClass
, kSecUseDataProtectionKeychain
, kSecReturnRef
, kSecMatchLimit
};
843 const void *values
[] = { kSecClassIdentity
, kCFBooleanFalse
, kCFBooleanTrue
, kSecMatchLimitAll
};
844 CFRef
<CFDictionaryRef
> query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
,
845 sizeof(keys
) / sizeof(*keys
),
846 &kCFTypeDictionaryKeyCallBacks
,
847 &kCFTypeDictionaryValueCallBacks
);
848 CFRef
<CFArrayRef
> identities
;
849 OSStatus status
= SecItemCopyMatching(query
, (CFTypeRef
*)identities
.take());
850 if (status
== errSecSuccess
) {
851 for (int i
= 0; i
< CFArrayGetCount(identities
); ++i
) {
852 CFRef
<SecKeyRef
> privateKey
;
853 if (SecIdentityCopyPrivateKey((SecIdentityRef
)CFArrayGetValueAtIndex(identities
, i
), privateKey
.take()) != errSecSuccess
) {
856 CFRef
<CFDictionaryRef
> attrs
= SecKeyCopyAttributes(privateKey
);
857 if (CFEqual(CFDictionaryGetValue(attrs
, kSecAttrApplicationLabel
), pubKeyHash
)) {
858 cdsaKey
= privateKey
;
859 SecKeySetAuxilliaryCDSAKeyForKey(key
, cdsaKey
.get());
865 cdsaKey
.take(SecKeyCreateFromData(keyAttributes
, keyData
, NULL
));
867 SecKeySetAuxilliaryCDSAKeyForKey(key
, cdsaKey
.get());
873 return cdsaKey
? CDSASecKey::keyItem(cdsaKey
.get()) : NULL
;
876 // You need to hold this key's MutexForObject when you run this
877 void KeyItem::attachSecKeyRef() const {
878 SecKeyRef key
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, reinterpret_cast<const uint8_t *>(this), 0, 0);
879 CDSASecKey::keyItem(key
)->mWeakSecKeyRef
= key
;
885 extern "C" Boolean
SecKeyIsCDSAKey(SecKeyRef ref
);
886 Boolean
SecKeyIsCDSAKey(SecKeyRef ref
) {
887 return ref
->key_class
== &kSecCDSAKeyDescriptor
;
891 static OSStatus
SecKeyCreatePairInternal(
892 SecKeychainRef keychainRef
,
893 CSSM_ALGORITHMS algorithm
,
894 uint32 keySizeInBits
,
895 CSSM_CC_HANDLE contextHandle
,
896 CSSM_KEYUSE publicKeyUsage
,
897 uint32 publicKeyAttr
,
898 CSSM_KEYUSE privateKeyUsage
,
899 uint32 privateKeyAttr
,
900 SecAccessRef initialAccess
,
901 SecKeyRef
* publicKeyRef
,
902 SecKeyRef
* privateKeyRef
)
907 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
908 SecPointer
<KeyItem
> pubItem
, privItem
;
909 if (((publicKeyAttr
| privateKeyAttr
) & CSSM_KEYATTR_PERMANENT
) != 0) {
910 keychain
= Keychain::optional(keychainRef
);
912 StMaybeLock
<Mutex
> _(keychain
? keychain
->getKeychainMutex() : NULL
);
913 KeyItem::createPair(keychain
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, publicKeyAttr
,
914 privateKeyUsage
, privateKeyAttr
, theAccess
, pubItem
, privItem
);
916 // Return the generated keys.
918 *publicKeyRef
= pubItem
->handle();
920 *privateKeyRef
= privItem
->handle();
927 SecKeychainRef keychainRef
,
928 CSSM_ALGORITHMS algorithm
,
929 uint32 keySizeInBits
,
930 CSSM_CC_HANDLE contextHandle
,
931 CSSM_KEYUSE publicKeyUsage
,
932 uint32 publicKeyAttr
,
933 CSSM_KEYUSE privateKeyUsage
,
934 uint32 privateKeyAttr
,
935 SecAccessRef initialAccess
,
936 SecKeyRef
* publicKeyRef
,
937 SecKeyRef
* privateKeyRef
)
939 OSStatus result
= SecKeyCreatePairInternal(keychainRef
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
,
940 publicKeyAttr
, privateKeyUsage
, privateKeyAttr
, initialAccess
, publicKeyRef
, privateKeyRef
);
948 SecKeyGetCSSMKey(SecKeyRef key
, const CSSM_KEY
**cssmKey
)
952 Required(cssmKey
) = KeyItem::required(key
)->key();
962 static ModuleNexus
<Mutex
> gSecReturnedKeyCSPsMutex
;
963 static ModuleNexus
<std::set
<CssmClient::CSP
>> gSecReturnedKeyCSPs
;
966 SecKeyGetCSPHandle(SecKeyRef keyRef
, CSSM_CSP_HANDLE
*cspHandle
)
970 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
972 // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP).
973 // Keep a global pointer to it to force the CSP to stay live forever.
974 CssmClient::CSP returnedKeyCSP
= keyItem
->csp();
976 StLock
<Mutex
> _(gSecReturnedKeyCSPsMutex());
977 gSecReturnedKeyCSPs().insert(returnedKeyCSP
);
979 Required(cspHandle
) = returnedKeyCSP
->handle();
984 /* deprecated as of 10.8 */
986 SecKeyGetAlgorithmID(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
**algid
)
990 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
991 Required(algid
) = &keyItem
->algorithmIdentifier();
997 SecKeyGetStrengthInBits(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
*algid
, unsigned int *strength
)
1001 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
1002 Required(strength
) = keyItem
->strengthInBits(algid
);
1008 SecKeyGetCredentials(
1010 CSSM_ACL_AUTHORIZATION_TAG operation
,
1011 SecCredentialType credentialType
,
1012 const CSSM_ACCESS_CREDENTIALS
**outCredentials
)
1016 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
1017 Required(outCredentials
) = keyItem
->getCredentials(operation
, credentialType
);
1024 SecKeychainRef keychainRef
,
1025 const CSSM_KEY
*publicCssmKey
,
1026 const CSSM_KEY
*privateCssmKey
,
1027 SecAccessRef initialAccess
,
1028 SecKeyRef
* publicKey
,
1029 SecKeyRef
* privateKey
)
1033 Keychain keychain
= Keychain::optional(keychainRef
);
1034 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
1035 SecPointer
<KeyItem
> pubItem
, privItem
;
1037 KeyItem::importPair(keychain
,
1038 Required(publicCssmKey
),
1039 Required(privateCssmKey
),
1044 // Return the generated keys.
1046 *publicKey
= pubItem
->handle();
1048 *privateKey
= privItem
->handle();
1054 SecKeyGenerateWithAttributes(
1055 SecKeychainAttributeList
* attrList
,
1056 SecKeychainRef keychainRef
,
1057 CSSM_ALGORITHMS algorithm
,
1058 uint32 keySizeInBits
,
1059 CSSM_CC_HANDLE contextHandle
,
1060 CSSM_KEYUSE keyUsage
,
1062 SecAccessRef initialAccess
,
1068 SecPointer
<Access
> theAccess
;
1071 keychain
= KeychainImpl::required(keychainRef
);
1073 theAccess
= Access::required(initialAccess
);
1075 SecPointer
<KeyItem
> item
= KeyItem::generateWithAttributes(attrList
,
1084 // Return the generated key.
1086 *keyRef
= item
->handle();
1093 SecKeychainRef keychainRef
,
1094 CSSM_ALGORITHMS algorithm
,
1095 uint32 keySizeInBits
,
1096 CSSM_CC_HANDLE contextHandle
,
1097 CSSM_KEYUSE keyUsage
,
1099 SecAccessRef initialAccess
,
1102 return SecKeyGenerateWithAttributes(NULL
,
1103 keychainRef
, algorithm
, keySizeInBits
,
1104 contextHandle
, keyUsage
, keyAttr
,
1105 initialAccess
, keyRef
);
1109 /* Generate a floating key reference from a CSSM_KEY */
1111 SecKeyCreateWithCSSMKey(const CSSM_KEY
*cssmKey
,
1117 if(cssmKey
->KeyData
.Length
== 0){
1118 MacOSError::throwMe(errSecInvalidAttributeKeyLength
);
1120 if(cssmKey
->KeyData
.Data
== NULL
){
1121 MacOSError::throwMe(errSecInvalidPointer
);
1123 CssmClient::CSP
csp(cssmKey
->KeyHeader
.CspId
);
1124 CssmClient::Key
key(csp
, *cssmKey
);
1125 KeyItem
*item
= new KeyItem(key
);
1127 // Return the generated key.
1129 *keyRef
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, (const uint8_t *)item
, 0, 0);
1136 static u_int32_t
ConvertCFStringToInteger(CFStringRef ref
)
1143 // figure out the size of the string
1144 CFIndex numChars
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref
), kCFStringEncodingUTF8
);
1145 char *buffer
= (char *)malloc(numChars
);
1146 if (NULL
== buffer
) {
1147 UnixError::throwMe(ENOMEM
);
1149 if (!CFStringGetCString(ref
, buffer
, numChars
, kCFStringEncodingUTF8
))
1152 MacOSError::throwMe(errSecParam
);
1155 u_int32_t result
= atoi(buffer
);
1162 static OSStatus
CheckAlgorithmType(CFDictionaryRef parameters
, CSSM_ALGORITHMS
&algorithms
)
1164 // figure out the algorithm to use
1165 CFStringRef ktype
= (CFStringRef
) CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
1171 if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
1172 algorithms
= CSSM_ALGID_RSA
;
1173 return errSecSuccess
;
1174 } else if(CFEqual(ktype
, kSecAttrKeyTypeECDSA
) ||
1175 CFEqual(ktype
, kSecAttrKeyTypeEC
)) {
1176 algorithms
= CSSM_ALGID_ECDSA
;
1177 return errSecSuccess
;
1178 } else if(CFEqual(ktype
, kSecAttrKeyTypeAES
)) {
1179 algorithms
= CSSM_ALGID_AES
;
1180 return errSecSuccess
;
1181 } else if(CFEqual(ktype
, kSecAttrKeyType3DES
)) {
1182 algorithms
= CSSM_ALGID_3DES
;
1183 return errSecSuccess
;
1185 return errSecUnsupportedAlgorithm
;
1191 static OSStatus
GetKeySize(CFDictionaryRef parameters
, CSSM_ALGORITHMS algorithms
, uint32
&keySizeInBits
)
1194 // get the key size and check it for validity
1195 CFTypeRef ref
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
1197 keySizeInBits
= kSecDefaultKeySize
;
1199 CFTypeID bitSizeType
= CFGetTypeID(ref
);
1200 if (bitSizeType
== CFStringGetTypeID())
1201 keySizeInBits
= ConvertCFStringToInteger((CFStringRef
) ref
);
1202 else if (bitSizeType
== CFNumberGetTypeID())
1203 CFNumberGetValue((CFNumberRef
) ref
, kCFNumberSInt32Type
, &keySizeInBits
);
1204 else return errSecParam
;
1207 switch (algorithms
) {
1208 case CSSM_ALGID_ECDSA
:
1209 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecp256r1
;
1210 if(keySizeInBits
== kSecp192r1
|| keySizeInBits
== kSecp256r1
|| keySizeInBits
== kSecp384r1
|| keySizeInBits
== kSecp521r1
) return errSecSuccess
;
1212 case CSSM_ALGID_RSA
:
1213 if(keySizeInBits
% 8) return errSecParam
;
1214 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= 2048;
1215 if(keySizeInBits
>= kSecRSAMin
&& keySizeInBits
<= kSecRSAMax
) return errSecSuccess
;
1217 case CSSM_ALGID_AES
:
1218 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecAES128
;
1219 if(keySizeInBits
== kSecAES128
|| keySizeInBits
== kSecAES192
|| keySizeInBits
== kSecAES256
) return errSecSuccess
;
1221 case CSSM_ALGID_3DES
:
1222 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSec3DES192
;
1223 if(keySizeInBits
== kSec3DES192
) return errSecSuccess
;
1242 struct ParameterAttribute
1244 const CFStringRef
*name
;
1250 static ParameterAttribute gAttributes
[] =
1257 &kSecAttrIsPermanent
,
1261 &kSecAttrApplicationTag
,
1265 &kSecAttrEffectiveKeySize
,
1269 &kSecAttrCanEncrypt
,
1273 &kSecAttrCanDecrypt
,
1294 const int kNumberOfAttributes
= sizeof(gAttributes
) / sizeof(ParameterAttribute
);
1296 static OSStatus
ScanDictionaryForParameters(CFDictionaryRef parameters
, void* attributePointers
[])
1299 for (i
= 0; i
< kNumberOfAttributes
; ++i
)
1301 // see if the corresponding tag exists in the dictionary
1302 CFTypeRef value
= CFDictionaryGetValue(parameters
, *(gAttributes
[i
].name
));
1305 switch (gAttributes
[i
].type
)
1308 // just return the value
1309 *(CFTypeRef
*) attributePointers
[i
] = value
;
1314 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1315 *(bool*) attributePointers
[i
] = CFBooleanGetValue(bRef
);
1321 CFNumberRef nRef
= (CFNumberRef
) value
;
1322 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, attributePointers
[i
]);
1329 return errSecSuccess
;
1334 static OSStatus
GetKeyParameters(CFDictionaryRef parameters
, int keySize
, bool isPublic
, CSSM_KEYUSE
&keyUse
, uint32
&attrs
, CFTypeRef
&labelRef
, CFDataRef
&applicationTagRef
)
1336 // establish default values
1338 bool isPermanent
= false;
1339 applicationTagRef
= NULL
;
1340 CFTypeRef effectiveKeySize
= NULL
;
1341 bool canDecrypt
= isPublic
? false : true;
1342 bool canEncrypt
= !canDecrypt
;
1343 bool canDerive
= true;
1344 bool canSign
= isPublic
? false : true;
1345 bool canVerify
= !canSign
;
1346 bool canUnwrap
= isPublic
? false : true;
1347 attrs
= CSSM_KEYATTR_EXTRACTABLE
;
1350 void* attributePointers
[] = {&labelRef
, &isPermanent
, &applicationTagRef
, &effectiveKeySize
, &canEncrypt
, &canDecrypt
,
1351 &canDerive
, &canSign
, &canVerify
, &canUnwrap
};
1353 // look for modifiers in the general dictionary
1354 OSStatus result
= ScanDictionaryForParameters(parameters
, attributePointers
);
1355 if (result
!= errSecSuccess
)
1360 // see if we have anything which modifies the defaults
1364 key
= kSecPublicKeyAttrs
;
1368 key
= kSecPrivateKeyAttrs
;
1371 CFTypeRef dType
= CFDictionaryGetValue(parameters
, key
);
1374 // this had better be a dictionary
1375 if (CFGetTypeID(dType
) != CFDictionaryGetTypeID())
1380 // pull any additional parameters out of this dictionary
1381 result
= ScanDictionaryForParameters((CFDictionaryRef
)dType
, attributePointers
);
1382 if (result
!= errSecSuccess
)
1388 // figure out the key usage
1392 keyUse
|= CSSM_KEYUSE_DECRYPT
;
1397 keyUse
|= CSSM_KEYUSE_ENCRYPT
;
1402 keyUse
|= CSSM_KEYUSE_DERIVE
;
1407 keyUse
|= CSSM_KEYUSE_SIGN
;
1412 keyUse
|= CSSM_KEYUSE_VERIFY
;
1417 keyUse
|= CSSM_KEYUSE_UNWRAP
;
1420 // public key is always extractable;
1421 // private key is extractable by default unless explicitly set to false
1422 CFTypeRef value
= NULL
;
1423 if (!isPublic
&& CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
) && value
)
1425 Boolean keyIsExtractable
= CFEqual(kCFBooleanTrue
, value
);
1426 if (!keyIsExtractable
)
1431 attrs
|= CSSM_KEYATTR_PERMANENT
;
1434 return errSecSuccess
;
1439 static OSStatus
MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters
,
1440 CSSM_ALGORITHMS
&algorithms
,
1441 uint32
&keySizeInBits
,
1442 CSSM_KEYUSE
&publicKeyUse
,
1443 uint32
&publicKeyAttr
,
1444 CFTypeRef
&publicKeyLabelRef
,
1445 CFDataRef
&publicKeyAttributeTagRef
,
1446 CSSM_KEYUSE
&privateKeyUse
,
1447 uint32
&privateKeyAttr
,
1448 CFTypeRef
&privateKeyLabelRef
,
1449 CFDataRef
&privateKeyAttributeTagRef
,
1450 SecAccessRef
&initialAccess
)
1454 result
= CheckAlgorithmType(parameters
, algorithms
);
1455 if (result
!= errSecSuccess
)
1460 result
= GetKeySize(parameters
, algorithms
, keySizeInBits
);
1461 if (result
!= errSecSuccess
)
1466 result
= GetKeyParameters(parameters
, keySizeInBits
, false, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1467 if (result
!= errSecSuccess
)
1472 result
= GetKeyParameters(parameters
, keySizeInBits
, true, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1473 if (result
!= errSecSuccess
)
1478 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&initialAccess
))
1480 initialAccess
= NULL
;
1482 else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess
))
1487 return errSecSuccess
;
1492 static OSStatus
SetKeyLabelAndTag(SecKeyRef keyRef
, CFTypeRef label
, CFDataRef tag
)
1494 int numToModify
= 0;
1505 if (numToModify
== 0)
1507 return errSecSuccess
;
1510 SecKeychainAttributeList attrList
;
1511 SecKeychainAttribute attributes
[numToModify
];
1518 if (CFStringGetTypeID() == CFGetTypeID(label
)) {
1519 CFStringRef label_string
= static_cast<CFStringRef
>(label
);
1520 attributes
[i
].tag
= kSecKeyPrintName
;
1521 attributes
[i
].data
= (void*) CFStringGetCStringPtr(label_string
, kCFStringEncodingUTF8
);
1522 if (NULL
== attributes
[i
].data
) {
1523 CFIndex buffer_length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string
), kCFStringEncodingUTF8
);
1524 data
= attributes
[i
].data
= malloc((size_t)buffer_length
);
1525 if (NULL
== attributes
[i
].data
) {
1526 UnixError::throwMe(ENOMEM
);
1528 if (!CFStringGetCString(label_string
, static_cast<char *>(attributes
[i
].data
), buffer_length
, kCFStringEncodingUTF8
)) {
1530 MacOSError::throwMe(errSecParam
);
1533 attributes
[i
].length
= (UInt32
)strlen(static_cast<char *>(attributes
[i
].data
));
1534 } else if (CFDataGetTypeID() == CFGetTypeID(label
)) {
1535 // 10.6 bug compatibility
1536 CFDataRef label_data
= static_cast<CFDataRef
>(label
);
1537 attributes
[i
].tag
= kSecKeyLabel
;
1538 attributes
[i
].data
= (void*) CFDataGetBytePtr(label_data
);
1539 attributes
[i
].length
= (UInt32
)CFDataGetLength(label_data
);
1541 MacOSError::throwMe(errSecParam
);
1548 attributes
[i
].tag
= kSecKeyApplicationTag
;
1549 attributes
[i
].data
= (void*) CFDataGetBytePtr(tag
);
1550 attributes
[i
].length
= (UInt32
)CFDataGetLength(tag
);
1554 attrList
.count
= numToModify
;
1555 attrList
.attr
= attributes
;
1557 OSStatus result
= SecKeychainItemModifyAttributesAndData((SecKeychainItemRef
) keyRef
, &attrList
, 0, NULL
);
1567 static CFTypeRef
GetAttributeFromParams(CFDictionaryRef parameters
, CFTypeRef attr
, CFTypeRef subParams
) {
1568 if (subParams
!= NULL
) {
1569 CFDictionaryRef subParamsDict
= (CFDictionaryRef
)CFDictionaryGetValue(parameters
, subParams
);
1570 if (subParamsDict
!= NULL
) {
1571 CFTypeRef value
= CFDictionaryGetValue(subParamsDict
, attr
);
1572 if (value
!= NULL
) {
1577 return CFDictionaryGetValue(parameters
, attr
);
1580 extern "C" OSStatus
SecKeyGeneratePair_ios(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
);
1583 /* Generate a private/public keypair. */
1585 SecKeyGeneratePairInternal(
1586 bool alwaysPermanent
,
1587 CFDictionaryRef parameters
,
1588 SecKeyRef
*publicKey
,
1589 SecKeyRef
*privateKey
)
1593 Required(parameters
);
1594 Required(publicKey
);
1595 Required(privateKey
);
1597 bool forceIOSKey
= false;
1598 if (_CFMZEnabled()) {
1599 // On Marzipan, always go iOS SecItem/SecKey route, do not drag CSSM keys in.
1602 CFTypeRef tokenID
= GetAttributeFromParams(parameters
, kSecAttrTokenID
, NULL
);
1603 CFTypeRef noLegacy
= GetAttributeFromParams(parameters
, kSecUseDataProtectionKeychain
, NULL
);
1604 #pragma clang diagnostic push
1605 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1606 if (!noLegacy
) { // Also lookup via deprecated symbol because we do CFDictionaryGetValue and your CFDict might be an idiot
1607 noLegacy
= GetAttributeFromParams(parameters
, kSecAttrNoLegacy
, NULL
);
1609 #pragma clang diagnostic pop
1610 CFTypeRef sync
= GetAttributeFromParams(parameters
, kSecAttrSynchronizable
, kSecPrivateKeyAttrs
);
1611 CFTypeRef accessControl
= GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPrivateKeyAttrs
) ?:
1612 GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPublicKeyAttrs
);
1613 CFTypeRef accessGroup
= GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPrivateKeyAttrs
) ?:
1614 GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPublicKeyAttrs
);
1615 // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain).
1616 forceIOSKey
= (tokenID
!= NULL
||
1617 (noLegacy
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)noLegacy
)) ||
1618 (sync
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)sync
)) ||
1619 accessControl
!= NULL
|| (accessGroup
!= NULL
&& CFEqual(accessGroup
, kSecAttrAccessGroupToken
)));
1623 // Generate keys in iOS keychain.
1624 return SecKeyGeneratePair_ios(parameters
, publicKey
, privateKey
);
1627 CSSM_ALGORITHMS algorithms
;
1628 uint32 keySizeInBits
;
1629 CSSM_KEYUSE publicKeyUse
;
1630 uint32 publicKeyAttr
;
1631 CFTypeRef publicKeyLabelRef
;
1632 CFDataRef publicKeyAttributeTagRef
;
1633 CSSM_KEYUSE privateKeyUse
;
1634 uint32 privateKeyAttr
;
1635 CFTypeRef privateKeyLabelRef
;
1636 CFDataRef privateKeyAttributeTagRef
;
1637 SecAccessRef initialAccess
;
1638 SecKeychainRef keychain
;
1640 OSStatus result
= MakeKeyGenParametersFromDictionary(parameters
, algorithms
, keySizeInBits
, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
,
1641 publicKeyAttributeTagRef
, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
,
1644 if (result
!= errSecSuccess
) {
1648 // verify keychain parameter
1649 keychain
= (SecKeychainRef
)CFDictionaryGetValue(parameters
, kSecUseKeychain
);
1650 if (keychain
!= NULL
&& SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1654 if (alwaysPermanent
) {
1655 publicKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1656 privateKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1659 // do the key generation
1660 result
= SecKeyCreatePair(keychain
, algorithms
, keySizeInBits
, 0, publicKeyUse
, publicKeyAttr
, privateKeyUse
, privateKeyAttr
, initialAccess
, publicKey
, privateKey
);
1661 if (result
!= errSecSuccess
) {
1665 // set the label and print attributes on the keys
1666 SetKeyLabelAndTag(*publicKey
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1667 SetKeyLabelAndTag(*privateKey
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1674 SecKeyGeneratePair(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
1675 return SecKeyGeneratePairInternal(true, parameters
, publicKey
, privateKey
);
1679 SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef
*error
) {
1680 SecKeyRef privateKey
= NULL
, publicKey
= NULL
;
1681 OSStatus status
= SecKeyGeneratePairInternal(false, parameters
, &publicKey
, &privateKey
);
1682 SecError(status
, error
, CFSTR("failed to generate asymmetric keypair"));
1683 if (publicKey
!= NULL
) {
1684 CFRelease(publicKey
);
1689 OSStatus
SecKeyRawVerifyOSX(
1690 SecKeyRef key
, /* Public key */
1691 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
1692 const uint8_t *signedData
, /* signature over this data */
1693 size_t signedDataLen
, /* length of dataToSign */
1694 const uint8_t *sig
, /* signature */
1697 return SecKeyRawVerify(key
,padding
,signedData
,signedDataLen
,sig
,sigLen
);
1705 utilGetStringFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, CFTypeRef defaultValue
)
1707 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1708 if (value
!= NULL
) return value
;
1709 return defaultValue
;
1713 utilGetNumberFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t defaultValue
)
1715 uint32_t integerValue
;
1716 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1717 if (value
!= NULL
) {
1718 CFNumberRef nRef
= (CFNumberRef
) value
;
1719 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, &integerValue
);
1720 return integerValue
;
1722 return defaultValue
;
1726 utilGetMaskValFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t maskValue
)
1728 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1729 if (value
!= NULL
) {
1730 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1731 if(CFBooleanGetValue(bRef
)) return maskValue
;
1737 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters
, CSSM_ALGORITHMS
*algorithm
, uint32
*keySizeInBits
, CSSM_KEYUSE
*keyUsage
, CSSM_KEYCLASS
*keyClass
)
1739 CFTypeRef algorithmDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeAES
);
1740 CFTypeRef keyClassDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1742 if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeAES
)) {
1743 *algorithm
= CSSM_ALGID_AES
;
1744 *keySizeInBits
= 128;
1745 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1746 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDES
)) {
1747 *algorithm
= CSSM_ALGID_DES
;
1748 *keySizeInBits
= 128;
1749 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1750 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyType3DES
)) {
1751 *algorithm
= CSSM_ALGID_3DES_3KEY_EDE
;
1752 *keySizeInBits
= 128;
1753 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1754 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC4
)) {
1755 *algorithm
= CSSM_ALGID_RC4
;
1756 *keySizeInBits
= 128;
1757 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1758 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC2
)) {
1759 *algorithm
= CSSM_ALGID_RC2
;
1760 *keySizeInBits
= 128;
1761 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1762 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeCAST
)) {
1763 *algorithm
= CSSM_ALGID_CAST
;
1764 *keySizeInBits
= 128;
1765 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1766 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRSA
)) {
1767 *algorithm
= CSSM_ALGID_RSA
;
1768 *keySizeInBits
= 128;
1769 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1770 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDSA
)) {
1771 *algorithm
= CSSM_ALGID_DSA
;
1772 *keySizeInBits
= 128;
1773 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1774 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeECDSA
) ||
1775 CFEqual(algorithmDictValue
, kSecAttrKeyTypeEC
)) {
1776 *algorithm
= CSSM_ALGID_ECDSA
;
1777 *keySizeInBits
= 128;
1778 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1780 *algorithm
= CSSM_ALGID_AES
;
1781 *keySizeInBits
= 128;
1782 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1785 if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPublic
)) {
1786 *keyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
1787 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPrivate
)) {
1788 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1789 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassSymmetric
)) {
1790 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1793 *keySizeInBits
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, *keySizeInBits
);
1794 *keyUsage
= utilGetMaskValFromCFDict(parameters
, kSecAttrCanEncrypt
, CSSM_KEYUSE_ENCRYPT
) |
1795 utilGetMaskValFromCFDict(parameters
, kSecAttrCanDecrypt
, CSSM_KEYUSE_DECRYPT
) |
1796 utilGetMaskValFromCFDict(parameters
, kSecAttrCanWrap
, CSSM_KEYUSE_WRAP
) |
1797 utilGetMaskValFromCFDict(parameters
, kSecAttrCanUnwrap
, CSSM_KEYUSE_UNWRAP
);
1800 if(*keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
|| *keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
) {
1801 *keyUsage
|= utilGetMaskValFromCFDict(parameters
, kSecAttrCanSign
, CSSM_KEYUSE_SIGN
) |
1802 utilGetMaskValFromCFDict(parameters
, kSecAttrCanVerify
, CSSM_KEYUSE_VERIFY
);
1805 if(*keyUsage
== 0) {
1806 switch (*keyClass
) {
1807 case CSSM_KEYCLASS_PRIVATE_KEY
:
1808 *keyUsage
= CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
;
1810 case CSSM_KEYCLASS_PUBLIC_KEY
:
1811 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
;
1814 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
;
1821 utilCopyDefaultKeyLabel(void)
1823 // generate a default label from the current date
1824 CFDateRef dateNow
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent());
1825 CFStringRef defaultLabel
= CFCopyDescription(dateNow
);
1828 return defaultLabel
;
1832 SecKeyGenerateSymmetric(CFDictionaryRef parameters
, CFErrorRef
*error
)
1834 OSStatus result
= errSecParam
; // default result for an early exit
1835 SecKeyRef key
= NULL
;
1836 SecKeychainRef keychain
= NULL
;
1837 SecAccessRef access
;
1839 CFStringRef appLabel
;
1841 CFStringRef dateLabel
= NULL
;
1843 CSSM_ALGORITHMS algorithm
;
1844 uint32 keySizeInBits
;
1845 CSSM_KEYUSE keyUsage
;
1846 uint32 keyAttr
= CSSM_KEYATTR_RETURN_DEFAULT
;
1847 CSSM_KEYCLASS keyClass
;
1849 Boolean isPermanent
;
1850 Boolean isExtractable
;
1852 // verify keychain parameter
1853 if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
))
1855 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1862 // verify permanent parameter
1863 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsPermanent
, (const void **)&value
))
1864 isPermanent
= false;
1865 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1868 isPermanent
= CFEqual(kCFBooleanTrue
, value
);
1870 if (keychain
== NULL
) {
1871 // no keychain was specified, so use the default keychain
1872 result
= SecKeychainCopyDefault(&keychain
);
1874 keyAttr
|= CSSM_KEYATTR_PERMANENT
;
1877 // verify extractable parameter
1878 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
))
1879 isExtractable
= true; // default to extractable if value not specified
1880 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1883 isExtractable
= CFEqual(kCFBooleanTrue
, value
);
1885 keyAttr
|= CSSM_KEYATTR_EXTRACTABLE
;
1887 // verify access parameter
1888 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&access
))
1890 else if (SecAccessGetTypeID() != CFGetTypeID(access
))
1893 // verify label parameter
1894 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrLabel
, (const void **)&label
))
1895 label
= (dateLabel
= utilCopyDefaultKeyLabel()); // no label provided, so use default
1896 else if (CFStringGetTypeID() != CFGetTypeID(label
))
1899 // verify application label parameter
1900 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationLabel
, (const void **)&appLabel
))
1901 appLabel
= (dateLabel
) ? dateLabel
: (dateLabel
= utilCopyDefaultKeyLabel());
1902 else if (CFStringGetTypeID() != CFGetTypeID(appLabel
))
1905 // verify application tag parameter
1906 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationTag
, (const void **)&appTag
))
1908 else if (CFStringGetTypeID() != CFGetTypeID(appTag
))
1911 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1914 // the generated key will not be stored in any keychain
1915 result
= SecKeyGenerate(keychain
, algorithm
, keySizeInBits
, 0, keyUsage
, keyAttr
, access
, &key
);
1918 // we can set the label attributes on the generated key if it's a keychain item
1919 size_t labelBufLen
= (label
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label
), kCFStringEncodingUTF8
) + 1 : 1;
1920 char *labelBuf
= (char *)malloc(labelBufLen
);
1921 size_t appLabelBufLen
= (appLabel
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel
), kCFStringEncodingUTF8
) + 1 : 1;
1922 char *appLabelBuf
= (char *)malloc(appLabelBufLen
);
1923 size_t appTagBufLen
= (appTag
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag
), kCFStringEncodingUTF8
) + 1 : 1;
1924 char *appTagBuf
= (char *)malloc(appTagBufLen
);
1926 if (!label
|| !CFStringGetCString(label
, labelBuf
, labelBufLen
-1, kCFStringEncodingUTF8
))
1928 if (!appLabel
|| !CFStringGetCString(appLabel
, appLabelBuf
, appLabelBufLen
-1, kCFStringEncodingUTF8
))
1930 if (!appTag
|| !CFStringGetCString(appTag
, appTagBuf
, appTagBufLen
-1, kCFStringEncodingUTF8
))
1933 SecKeychainAttribute attrs
[] = {
1934 { kSecKeyPrintName
, (UInt32
)strlen(labelBuf
), (char *)labelBuf
},
1935 { kSecKeyLabel
, (UInt32
)strlen(appLabelBuf
), (char *)appLabelBuf
},
1936 { kSecKeyApplicationTag
, (UInt32
)strlen(appTagBuf
), (char *)appTagBuf
} };
1937 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
1938 if (!appTag
) --attributes
.count
;
1940 result
= SecKeyGenerateWithAttributes(&attributes
,
1941 keychain
, algorithm
, keySizeInBits
, 0,
1942 keyUsage
, keyAttr
, access
, &key
);
1950 if (result
&& error
) {
1951 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, result
, NULL
);
1954 CFRelease(dateLabel
);
1956 CFRelease(keychain
);
1964 SecKeyCreateFromData(CFDictionaryRef parameters
, CFDataRef keyData
, CFErrorRef
*error
)
1966 CSSM_ALGORITHMS algorithm
;
1967 uint32 keySizeInBits
;
1968 CSSM_KEYUSE keyUsage
;
1969 CSSM_KEYCLASS keyClass
;
1972 if(keyData
== NULL
|| CFDataGetLength(keyData
) == 0){
1973 MacOSError::throwMe(errSecUnsupportedKeySize
);
1976 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1978 CSSM_CSP_HANDLE cspHandle
= cuCspStartup(CSSM_FALSE
); // TRUE => CSP, FALSE => CSPDL
1980 SecKeyImportExportParameters iparam
;
1981 memset(&iparam
, 0, sizeof(iparam
));
1982 iparam
.keyUsage
= keyUsage
;
1984 CFRef
<CFDataRef
> data
;
1985 SecExternalItemType itype
;
1987 case CSSM_KEYCLASS_PRIVATE_KEY
:
1988 itype
= kSecItemTypePrivateKey
;
1990 case CSSM_KEYCLASS_PUBLIC_KEY
: {
1991 itype
= kSecItemTypePublicKey
;
1992 // Public key import expects public key in SubjPublicKey X509 format. We want to accept both bare and x509 format,
1993 // so we have to detect bare format here and extend to full X509 if detected.
1994 data
.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm
, keySizeInBits
, keyData
));
1997 case CSSM_KEYCLASS_SESSION_KEY
:
1998 itype
= kSecItemTypeSessionKey
;
2001 itype
= kSecItemTypeUnknown
;
2005 CFMutableArrayRef ka
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2006 // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful.
2007 crtn
= impExpImportRawKey(data
? CFDataRef(data
) : keyData
, kSecFormatUnknown
, itype
, algorithm
, NULL
, cspHandle
, 0, NULL
, NULL
, ka
);
2008 if (crtn
== CSSM_OK
&& CFArrayGetCount((CFArrayRef
)ka
)) {
2009 SecKeyRef sk
= (SecKeyRef
)CFArrayGetValueAtIndex((CFArrayRef
)ka
, 0);
2016 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, crtn
? crtn
: CSSM_ERRCODE_INTERNAL_ERROR
, NULL
);
2024 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable
, dispatch_queue_t deliveryQueue
,
2025 SecKeyGeneratePairBlock result
)
2027 CFDictionaryRef parameters
= CFDictionaryCreateCopy(NULL
, parametersWhichMightBeMutiable
);
2028 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
2029 SecKeyRef publicKey
= NULL
;
2030 SecKeyRef privateKey
= NULL
;
2031 OSStatus status
= SecKeyGeneratePair(parameters
, &publicKey
, &privateKey
);
2032 dispatch_async(deliveryQueue
, ^{
2033 CFErrorRef error
= NULL
;
2034 if (errSecSuccess
!= status
) {
2035 error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, NULL
);
2037 result(publicKey
, privateKey
, error
);
2042 CFRelease(publicKey
);
2045 CFRelease(privateKey
);
2047 CFRelease(parameters
);
2052 static inline void utilClearAndFree(void *p
, size_t len
) {
2054 if(len
) bzero(p
, len
);
2060 SecKeyDeriveFromPassword(CFStringRef password
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2062 CCPBKDFAlgorithm algorithm
;
2063 CFIndex passwordLen
= 0;
2064 CFDataRef keyData
= NULL
;
2065 char *thePassword
= NULL
;
2066 uint8_t *salt
= NULL
;
2067 uint8_t *derivedKey
= NULL
;
2068 size_t saltLen
= 0, derivedKeyLen
= 0;
2070 CFDataRef saltDictValue
, algorithmDictValue
;
2071 SecKeyRef retval
= NULL
;
2073 /* Pick Values from parameters */
2075 if((saltDictValue
= (CFDataRef
) CFDictionaryGetValue(parameters
, kSecAttrSalt
)) == NULL
) {
2077 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecMissingAlgorithmParms
, NULL
);
2082 derivedKeyLen
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, 128);
2083 // This value come in bits but the rest of the code treats it as bytes
2086 algorithmDictValue
= (CFDataRef
) utilGetStringFromCFDict(parameters
, kSecAttrPRF
, kSecAttrPRFHmacAlgSHA256
);
2088 rounds
= utilGetNumberFromCFDict(parameters
, kSecAttrRounds
, 0);
2090 /* Convert any remaining parameters and get the password bytes */
2092 saltLen
= CFDataGetLength(saltDictValue
);
2093 if((salt
= (uint8_t *) malloc(saltLen
)) == NULL
) {
2095 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2100 CFDataGetBytes(saltDictValue
, CFRangeMake(0, saltLen
), (UInt8
*) salt
);
2102 passwordLen
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1;
2103 if((thePassword
= (char *) malloc(passwordLen
)) == NULL
) {
2105 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2109 CFStringGetBytes(password
, CFRangeMake(0, CFStringGetLength(password
)), kCFStringEncodingUTF8
, '?', FALSE
, (UInt8
*)thePassword
, passwordLen
, &passwordLen
);
2111 if((derivedKey
= (uint8_t *) malloc(derivedKeyLen
)) == NULL
) {
2113 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2118 if(algorithmDictValue
== NULL
) {
2119 algorithm
= kCCPRFHmacAlgSHA1
; /* default */
2120 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA1
)) {
2121 algorithm
= kCCPRFHmacAlgSHA1
;
2122 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA224
)) {
2123 algorithm
= kCCPRFHmacAlgSHA224
;
2124 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA256
)) {
2125 algorithm
= kCCPRFHmacAlgSHA256
;
2126 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA384
)) {
2127 algorithm
= kCCPRFHmacAlgSHA384
;
2128 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA512
)) {
2129 algorithm
= kCCPRFHmacAlgSHA512
;
2132 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidAlgorithmParms
, NULL
);
2138 rounds
= 33333; // we need to pass back a consistent value since there's no way to record the round count.
2141 if(CCKeyDerivationPBKDF(kCCPBKDF2
, thePassword
, passwordLen
, salt
, saltLen
, algorithm
, rounds
, derivedKey
, derivedKeyLen
)) {
2143 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2148 if((keyData
= CFDataCreate(NULL
, derivedKey
, derivedKeyLen
)) != NULL
) {
2149 retval
= SecKeyCreateFromData(parameters
, keyData
, error
);
2153 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2158 utilClearAndFree(salt
, saltLen
);
2159 utilClearAndFree(thePassword
, passwordLen
);
2160 utilClearAndFree(derivedKey
, derivedKeyLen
);
2165 SecKeyWrapSymmetric(SecKeyRef keyToWrap
, SecKeyRef wrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2168 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);
2174 SecKeyUnwrapSymmetric(CFDataRef
*keyToUnwrap
, SecKeyRef unwrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2177 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);