2 * Copyright (c) 2002-2015 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 #include "SecKeyPriv.h"
27 #include "SecItemPriv.h"
28 #include <libDER/asn1Types.h>
29 #include <libDER/DER_Encode.h>
30 #include <libDER/DER_Decode.h>
31 #include <libDER/DER_Keys.h>
32 #include <Security/SecAsn1Types.h>
33 #include <Security/SecAsn1Coder.h>
34 #include <security_keychain/KeyItem.h>
35 #include <security_utilities/casts.h>
36 #include <CommonCrypto/CommonKeyDerivation.h>
38 #include <CoreFoundation/CFPriv.h>
39 // 'verify' macro is somehow dragged in from CFPriv.h and breaks compilation of signclient.h, so undef it, we don't need it.
42 #include "SecBridge.h"
44 #include <security_keychain/Access.h>
45 #include <security_keychain/Keychains.h>
46 #include <security_keychain/KeyItem.h>
50 #include <security_cdsa_utils/cuCdsaUtils.h>
51 #include <security_cdsa_client/wrapkey.h>
52 #include <security_cdsa_client/genkey.h>
53 #include <security_cdsa_client/signclient.h>
54 #include <security_cdsa_client/cryptoclient.h>
56 #include "SecImportExportCrypto.h"
59 SecCDSAKeyInit(SecKeyRef key
, const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) {
60 key
->key
= const_cast<KeyItem
*>(reinterpret_cast<const KeyItem
*>(keyData
));
61 key
->key
->initializeWithSecKeyRef(key
);
62 key
->credentialType
= kSecCredentialTypeDefault
;
63 key
->cdsaKeyMutex
= new Mutex();
68 SecCDSAKeyDestroy(SecKeyRef keyRef
) {
69 // Note: If this key is holding the last strong reference to its keychain, the keychain will be released during this operation.
70 // If we hold the keychain's mutex (the key's 'mutexForObject') during this destruction, pthread gets upset.
71 // Hold a reference to the keychain (if it exists) until after we release the keychain's mutex.
73 StMaybeLock
<Mutex
> cdsaMutex(keyRef
->cdsaKeyMutex
);
75 KeyItem
*keyItem
= keyRef
->key
;
77 if (keyItem
== NULL
) {
78 // KeyImpl::attachSecKeyRef disconnected us from KeyItem instance, there is nothing to do for us.
80 delete keyRef
->cdsaKeyMutex
;
84 Keychain kc
= keyItem
->keychain();
86 // We have a +1 reference to the KeyItem now; no need to protect our storage any more
90 StMaybeLock
<Mutex
> _(keyItem
->getMutexForObject());
91 keyItem
= keyRef
->key
;
92 if (keyItem
== NULL
) {
93 // 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.
97 keyItem
->aboutToDestruct();
101 delete keyRef
->cdsaKeyMutex
;
103 (void) kc
; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain.
107 SecCDSAKeyGetBlockSize(SecKeyRef key
) {
109 CFErrorRef
*error
= NULL
;
110 BEGIN_SECKEYAPI(size_t,0)
112 const CssmKey::Header keyHeader
= key
->key
->unverifiedKeyHeader();
113 switch(keyHeader
.algorithm())
117 result
= keyHeader
.LogicalKeySizeInBits
/ 8;
119 case CSSM_ALGID_ECDSA
:
121 /* Block size is up to 9 bytes of DER encoding for sequence of 2 integers,
122 * plus both coordinates for the point used */
123 #define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8)
124 #define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1)
125 size_t coordSize
= ECDSA_MAX_COORD_SIZE_IN_BYTES(keyHeader
.LogicalKeySizeInBits
);
126 assert(coordSize
< 256); /* size must fit in a byte for DER */
127 size_t coordDERLen
= (coordSize
> 127) ? 2 : 1;
128 size_t coordLen
= 1 + coordDERLen
+ coordSize
;
130 size_t pointSize
= 2 * coordLen
;
131 assert(pointSize
< 256); /* size must fit in a byte for DER */
132 size_t pointDERLen
= (pointSize
> 127) ? 2 : 1;
133 size_t pointLen
= 1 + pointDERLen
+ pointSize
;
139 result
= 16; /* all AES keys use 128-bit blocks */
142 case CSSM_ALGID_3DES_3KEY
:
143 result
= 8; /* all DES keys use 64-bit blocks */
146 assert(0); /* some other key algorithm */
147 result
= 16; /* FIXME: revisit this */
155 SecCDSAKeyGetAlgorithmId(SecKeyRef key
) {
157 CFErrorRef
*error
= NULL
;
158 BEGIN_SECKEYAPI(CFIndex
, 0)
160 result
= kSecNullAlgorithmID
;
161 switch (key
->key
->unverifiedKeyHeader().AlgorithmId
) {
163 result
= kSecRSAAlgorithmID
;
166 result
= kSecDSAAlgorithmID
;
168 case CSSM_ALGID_ECDSA
:
169 result
= kSecECDSAAlgorithmID
;
172 assert(0); /* other algorithms TBA */
178 static CFDataRef
SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(CFDataRef pubKeyInfo
) {
179 // First of all, consider x509 format and try to strip SubjPubKey envelope. If it fails, do not panic
180 // and export data as is.
181 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(pubKeyInfo
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(pubKeyInfo
)) }, pubKeyItem
;
183 DERSubjPubKeyInfo subjPubKey
;
184 if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
,
185 DERSubjPubKeyInfoItemSpecs
,
186 &subjPubKey
, sizeof(subjPubKey
)) == DR_Success
&&
187 DERParseBitString(&subjPubKey
.pubKey
, &pubKeyItem
, &numUnused
) == DR_Success
) {
188 return CFDataCreate(kCFAllocatorDefault
, pubKeyItem
.data
, pubKeyItem
.length
);
191 return CFDataRef(CFRetain(pubKeyInfo
));
194 static CFDataRef
SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(CSSM_ALGORITHMS algorithm
, uint32 keySizeInBits
, CFDataRef pubKeyInfo
) {
195 // First check, whether X509 pubkeyinfo is already present. If not, add it according to the key type.
196 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(pubKeyInfo
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(pubKeyInfo
)) };
197 DERSubjPubKeyInfo subjPubKey
;
198 if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
,
199 DERSubjPubKeyInfoItemSpecs
,
200 &subjPubKey
, sizeof(subjPubKey
)) == DR_Success
) {
201 return CFDataRef(CFRetain(pubKeyInfo
));
204 // We have always size rounded to full bytes so bitstring encodes leading 00.
205 CFRef
<CFMutableDataRef
> bitStringPubKey
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
206 CFDataSetLength(bitStringPubKey
, 1);
207 CFDataAppendBytes(bitStringPubKey
, CFDataGetBytePtr(pubKeyInfo
), CFDataGetLength(pubKeyInfo
));
208 subjPubKey
.pubKey
.data
= static_cast<DERByte
*>(const_cast<UInt8
*>(CFDataGetBytePtr(bitStringPubKey
)));
209 subjPubKey
.pubKey
.length
= CFDataGetLength(bitStringPubKey
);
211 // Encode algId according to algorithm used.
212 static const DERByte oidRSA
[] = {
213 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
215 static const DERByte oidECsecp256
[] = {
216 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
218 static const DERByte oidECsecp384
[] = {
219 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22,
221 static const DERByte oidECsecp521
[] = {
222 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23,
224 subjPubKey
.algId
.length
= 0;
225 if (algorithm
== CSSM_ALGID_RSA
) {
226 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidRSA
);
227 subjPubKey
.algId
.length
= sizeof(oidRSA
);
228 } else if (algorithm
== CSSM_ALGID_ECDSA
) {
229 if (keySizeInBits
== 256) {
230 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidECsecp256
);
231 subjPubKey
.algId
.length
= sizeof(oidECsecp256
);
232 } else if (keySizeInBits
== 384) {
233 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidECsecp384
);
234 subjPubKey
.algId
.length
= sizeof(oidECsecp384
);
235 } if (keySizeInBits
== 521) {
236 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidECsecp521
);
237 subjPubKey
.algId
.length
= sizeof(oidECsecp521
);
240 DERSize size
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
,
241 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
);
242 CFRef
<CFMutableDataRef
> keyData
= CFDataCreateMutable(kCFAllocatorDefault
, size
);
243 CFDataSetLength(keyData
, size
);
244 if (DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
,
245 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
,
246 static_cast<DERByte
*>(CFDataGetMutableBytePtr(keyData
)), &size
) == DR_Success
) {
247 CFDataSetLength(keyData
, size
);
252 return keyData
.yield();
255 static OSStatus
SecCDSAKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
*serialization
) {
257 CFErrorRef
*error
= NULL
;
258 BEGIN_SECKEYAPI(OSStatus
, errSecSuccess
)
260 const CssmKey::Header
&header
= key
->key
->key().header();
261 switch (header
.algorithm()) {
262 case CSSM_ALGID_RSA
: {
263 switch (header
.keyClass()) {
264 case CSSM_KEYCLASS_PRIVATE_KEY
: {
265 CFRef
<CFDataRef
> privKeyData
;
266 result
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, privKeyData
.take());
267 if (result
== errSecSuccess
) {
268 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(privKeyData
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(privKeyData
)) };
269 DERRSAKeyPair keyPair
;
270 if (DERParseSequence(&keyItem
, DERNumRSAKeyPairItemSpecs
, DERRSAKeyPairItemSpecs
,
271 &keyPair
, sizeof(keyPair
)) == DR_Success
) {
272 DERRSAPubKeyPKCS1 pubKey
= { keyPair
.n
, keyPair
.e
};
273 DERSize size
= DERLengthOfEncodedSequence(ASN1_SEQUENCE
, &pubKey
,
274 DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
);
275 CFRef
<CFMutableDataRef
> keyData
= CFDataCreateMutable(kCFAllocatorDefault
, size
);
276 CFDataSetLength(keyData
, size
);
277 UInt8
*data
= CFDataGetMutableBytePtr(keyData
);
278 if (DEREncodeSequence(ASN1_SEQUENCE
, &pubKey
,
279 DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
,
280 data
, &size
) == DR_Success
) {
281 CFDataSetLength(keyData
, size
);
282 *data
= ONE_BYTE_ASN1_CONSTR_SEQUENCE
;
283 *serialization
= keyData
.yield();
285 *serialization
= NULL
;
286 result
= errSecParam
;
292 case CSSM_KEYCLASS_PUBLIC_KEY
:
293 result
= SecItemExport(key
, kSecFormatBSAFE
, 0, NULL
, serialization
);
298 case CSSM_ALGID_ECDSA
: {
299 *serialization
= NULL
;
300 CFRef
<CFDataRef
> tempPublicData
;
301 result
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, tempPublicData
.take());
302 if (result
== errSecSuccess
) {
303 *serialization
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(tempPublicData
);
308 result
= errSecUnimplemented
;
319 static const DERItemSpec DERECPrivateKeyItemSpecs
[] =
324 { DER_OFFSET(DERECPrivateKey
, privateKey
),
326 DER_DEC_NO_OPTS
| DER_ENC_NO_OPTS
},
328 ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0,
329 DER_DEC_SKIP
| DER_ENC_NO_OPTS
},
330 { DER_OFFSET(DERECPrivateKey
, publicKey
),
331 ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 1,
332 DER_DEC_NO_OPTS
| DER_ENC_SIGNED_INT
},
334 static const DERSize DERNumECPrivateKeyItemSpecs
=
335 sizeof(DERECPrivateKeyItemSpecs
) / sizeof(DERItemSpec
);
339 } DERECPrivateKeyPublicKey
;
341 static const DERItemSpec DERECPrivateKeyPublicKeyItemSpecs
[] =
343 { DER_OFFSET(DERECPrivateKeyPublicKey
, bitString
),
345 DER_DEC_NO_OPTS
| DER_ENC_NO_OPTS
},
347 static const DERSize DERNumECPrivateKeyPublicKeyItemSpecs
=
348 sizeof(DERECPrivateKeyPublicKeyItemSpecs
) / sizeof(DERItemSpec
);
351 SecCDSAKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef
*error
) {
353 BEGIN_SECKEYAPI(CFDataRef
, NULL
)
356 const CssmKey::Header header
= key
->key
->unverifiedKeyHeader();
357 CFRef
<CFDataRef
> keyData
;
358 switch (header
.algorithm()) {
360 MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()));
362 case CSSM_ALGID_ECDSA
: {
363 MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()));
364 if (header
.keyClass() == CSSM_KEYCLASS_PRIVATE_KEY
) {
365 // Convert DER format into x9.63 format, which is expected for exported key.
366 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(keyData
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(keyData
)) };
367 DERECPrivateKey privateKey
;
368 DERECPrivateKeyPublicKey privateKeyPublicKey
;
371 if (DERParseSequence(&keyItem
, DERNumECPrivateKeyItemSpecs
, DERECPrivateKeyItemSpecs
,
372 &privateKey
, sizeof(privateKey
)) == DR_Success
&&
373 DERParseSequenceContent(&privateKey
.publicKey
, DERNumECPrivateKeyPublicKeyItemSpecs
,
374 DERECPrivateKeyPublicKeyItemSpecs
,
375 &privateKeyPublicKey
, sizeof(privateKeyPublicKey
)) == DR_Success
&&
376 DERParseBitString(&privateKeyPublicKey
.bitString
, &pubKeyItem
, &numUnused
) == DR_Success
) {
377 CFRef
<CFMutableDataRef
> key
= CFDataCreateMutable(kCFAllocatorDefault
,
378 pubKeyItem
.length
+ privateKey
.privateKey
.length
);
379 CFDataSetLength(key
, pubKeyItem
.length
+ privateKey
.privateKey
.length
);
380 CFDataReplaceBytes(key
, CFRangeMake(0, pubKeyItem
.length
), pubKeyItem
.data
, pubKeyItem
.length
);
381 CFDataReplaceBytes(key
, CFRangeMake(pubKeyItem
.length
, privateKey
.privateKey
.length
),
382 privateKey
.privateKey
.data
, privateKey
.privateKey
.length
);
383 keyData
= key
.as
<CFDataRef
>();
389 MacOSError::throwMe(errSecUnimplemented
);
392 if (header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
) {
393 result
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(keyData
);
395 result
= keyData
.yield();
401 static CFDataRef
SecCDSAKeyCopyLabel(SecKeyRef key
) {
402 CFDataRef label
= NULL
;
403 if (key
->key
->isPersistent()) {
404 UInt32 tags
[] = { kSecKeyLabel
}, formats
[] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB
};
405 SecKeychainAttributeInfo info
= { 1, tags
, formats
};
406 SecKeychainAttributeList
*list
= NULL
;
407 key
->key
->getAttributesAndData(&info
, NULL
, &list
, NULL
, NULL
);
408 if (list
->count
== 1) {
409 SecKeychainAttribute
*attr
= list
->attr
;
410 label
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)attr
->data
, (CFIndex
)attr
->length
);
412 key
->key
->freeAttributesAndData(list
, NULL
);
417 static CFDictionaryRef
418 SecCDSAKeyCopyAttributeDictionary(SecKeyRef key
) {
420 CFErrorRef
*error
= NULL
;
421 BEGIN_SECKEYAPI(CFDictionaryRef
, NULL
)
423 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
424 &kCFTypeDictionaryValueCallBacks
);
426 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
428 const CssmKey::Header header
= key
->key
->unverifiedKeyHeader();
429 CFIndex sizeValue
= header
.LogicalKeySizeInBits
;
430 CFRef
<CFNumberRef
> sizeInBits
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &sizeValue
);
431 CFDictionarySetValue(dict
, kSecAttrKeySizeInBits
, sizeInBits
);
432 CFDictionarySetValue(dict
, kSecAttrEffectiveKeySize
, sizeInBits
);
434 CFRef
<CFDataRef
> label
= SecCDSAKeyCopyLabel(key
);
436 // For floating keys, calculate label as SHA1 of pubkey bytes.
437 CFRef
<CFDataRef
> pubKeyBlob
;
438 if (SecCDSAKeyCopyPublicBytes(key
, pubKeyBlob
.take()) == errSecSuccess
) {
439 uint8_t pubKeyHash
[CC_SHA1_DIGEST_LENGTH
];
440 CC_SHA1(CFDataGetBytePtr(pubKeyBlob
), CC_LONG(CFDataGetLength(pubKeyBlob
)), pubKeyHash
);
441 label
.take(CFDataCreate(kCFAllocatorDefault
, pubKeyHash
, sizeof(pubKeyHash
)));
446 CFDictionarySetValue(dict
, kSecAttrApplicationLabel
, label
);
449 CSSM_KEYATTR_FLAGS attrs
= header
.attributes();
450 CFDictionarySetValue(dict
, kSecAttrIsPermanent
, (attrs
& CSSM_KEYATTR_PERMANENT
) ? kCFBooleanTrue
: kCFBooleanFalse
);
451 CFDictionarySetValue(dict
, kSecAttrIsPrivate
, (attrs
& CSSM_KEYATTR_PRIVATE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
452 CFDictionarySetValue(dict
, kSecAttrIsModifiable
, (attrs
& CSSM_KEYATTR_MODIFIABLE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
453 CFDictionarySetValue(dict
, kSecAttrIsSensitive
, (attrs
& CSSM_KEYATTR_SENSITIVE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
454 CFDictionarySetValue(dict
, kSecAttrIsExtractable
, (attrs
& CSSM_KEYATTR_EXTRACTABLE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
455 CFDictionarySetValue(dict
, kSecAttrWasAlwaysSensitive
, (attrs
& CSSM_KEYATTR_ALWAYS_SENSITIVE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
456 CFDictionarySetValue(dict
, kSecAttrWasNeverExtractable
, (attrs
& CSSM_KEYATTR_NEVER_EXTRACTABLE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
458 CFDictionarySetValue(dict
, kSecAttrCanEncrypt
, (header
.useFor(CSSM_KEYUSE_ENCRYPT
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
459 CFDictionarySetValue(dict
, kSecAttrCanDecrypt
, (header
.useFor(CSSM_KEYUSE_DECRYPT
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
460 CFDictionarySetValue(dict
, kSecAttrCanSign
, (header
.useFor(CSSM_KEYUSE_SIGN
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
461 CFDictionarySetValue(dict
, kSecAttrCanVerify
, (header
.useFor(CSSM_KEYUSE_VERIFY
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
462 CFDictionarySetValue(dict
, kSecAttrCanSignRecover
, (header
.useFor(CSSM_KEYUSE_SIGN_RECOVER
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
463 CFDictionarySetValue(dict
, kSecAttrCanVerifyRecover
, (header
.useFor(CSSM_KEYUSE_VERIFY_RECOVER
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
464 CFDictionarySetValue(dict
, kSecAttrCanWrap
, (header
.useFor(CSSM_KEYUSE_WRAP
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
465 CFDictionarySetValue(dict
, kSecAttrCanUnwrap
, (header
.useFor(CSSM_KEYUSE_UNWRAP
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
466 CFDictionarySetValue(dict
, kSecAttrCanDerive
, (header
.useFor(CSSM_KEYUSE_DERIVE
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
468 switch (header
.keyClass()) {
469 case CSSM_KEYCLASS_PUBLIC_KEY
:
470 CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
472 case CSSM_KEYCLASS_PRIVATE_KEY
:
473 CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
477 switch (header
.algorithm()) {
479 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
481 case CSSM_ALGID_ECDSA
:
482 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeECDSA
);
486 CFRef
<CFDataRef
> keyData
;
487 if (SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()) == errSecSuccess
) {
488 CFDictionarySetValue(dict
, kSecValueData
, keyData
);
491 if (header
.algorithm() == CSSM_ALGID_RSA
&& header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
&&
492 header
.blobType() == CSSM_KEYBLOB_RAW
) {
493 const CssmData
&keyData
= key
->key
->key()->keyData();
494 DERItem keyItem
= { static_cast<DERByte
*>(keyData
.data()), keyData
.length() };
495 DERRSAPubKeyPKCS1 decodedKey
;
496 if (DERParseSequence(&keyItem
, DERNumRSAPubKeyPKCS1ItemSpecs
,
497 DERRSAPubKeyPKCS1ItemSpecs
,
498 &decodedKey
, sizeof(decodedKey
)) == DR_Success
) {
499 CFRef
<CFDataRef
> modulus
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.modulus
.data
,
500 decodedKey
.modulus
.length
);
501 CFDictionarySetValue(dict
, CFSTR("_rsam"), modulus
);
502 CFRef
<CFDataRef
> exponent
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.pubExponent
.data
,
503 decodedKey
.pubExponent
.length
);
504 CFDictionarySetValue(dict
, CFSTR("_rsae"), exponent
);
513 #pragma clang diagnostic push
514 #pragma clang diagnostic ignored "-Wunused-const-variable"
515 static CSSM_DB_NAME_ATTR(kInfoKeyLabel
, kSecKeyLabel
, (char*) "Label", 0, NULL
, BLOB
);
516 #pragma clang diagnostic pop
518 static SecKeyRef
SecCDSAKeyCopyPublicKey(SecKeyRef privateKey
) {
519 CFErrorRef
*error
= NULL
;
520 BEGIN_SECKEYAPI(SecKeyRef
, NULL
)
523 KeyItem
*key
= privateKey
->key
;
524 CFRef
<CFDataRef
> label
= SecCDSAKeyCopyLabel(privateKey
);
526 // Lookup public key in the database.
527 DbUniqueRecord uniqueId
;
528 SSDb
ssDb(dynamic_cast<SSDbImpl
*>(&(*key
->keychain()->database())));
529 SSDbCursor
dbCursor(ssDb
, 1);
530 dbCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
);
531 dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, CssmData(CFDataRef(label
)));
532 if (dbCursor
->next(NULL
, NULL
, uniqueId
)) {
533 Item publicKey
= key
->keychain()->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, uniqueId
);
534 result
= reinterpret_cast<SecKeyRef
>(publicKey
->handle());
538 if (result
== NULL
&& key
->publicKey()) {
539 SecPointer
<KeyItem
> publicKey(new KeyItem(key
->publicKey()));
540 result
= reinterpret_cast<SecKeyRef
>(publicKey
->handle());
546 static KeyItem
*SecCDSAKeyPrepareParameters(SecKeyRef key
, SecKeyOperationType
&operation
, SecKeyAlgorithm algorithm
,
547 CSSM_ALGORITHMS
&baseAlgorithm
, CSSM_ALGORITHMS
&secondaryAlgorithm
,
548 CSSM_ALGORITHMS
&paddingAlgorithm
, CFIndex
&inputSizeLimit
) {
549 KeyItem
*keyItem
= key
->key
;
550 CSSM_KEYCLASS keyClass
= keyItem
->key()->header().keyClass();
551 baseAlgorithm
= keyItem
->key()->header().algorithm();
552 switch (baseAlgorithm
) {
554 if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeSign
) ||
555 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeVerify
)) {
556 if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureRaw
)) {
557 secondaryAlgorithm
= CSSM_ALGID_NONE
;
558 paddingAlgorithm
= CSSM_PADDING_NONE
;
560 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
)) {
561 secondaryAlgorithm
= CSSM_ALGID_NONE
;
562 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
563 inputSizeLimit
= -11;
564 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
)) {
565 secondaryAlgorithm
= CSSM_ALGID_SHA1
;
566 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
568 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
)) {
569 secondaryAlgorithm
= CSSM_ALGID_SHA224
;
570 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
571 inputSizeLimit
= 224 / 8;
572 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
)) {
573 secondaryAlgorithm
= CSSM_ALGID_SHA256
;
574 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
575 inputSizeLimit
= 256 / 8;
576 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
)) {
577 secondaryAlgorithm
= CSSM_ALGID_SHA384
;
578 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
579 inputSizeLimit
= 384 / 8;
580 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
)) {
581 secondaryAlgorithm
= CSSM_ALGID_SHA512
;
582 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
583 inputSizeLimit
= 512 / 8;
584 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5
)) {
585 secondaryAlgorithm
= CSSM_ALGID_MD5
;
586 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
591 } else if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeDecrypt
) ||
592 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeEncrypt
)) {
593 if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionRaw
)) {
594 secondaryAlgorithm
= CSSM_ALGID_NONE
;
595 paddingAlgorithm
= CSSM_PADDING_NONE
;
597 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionPKCS1
)) {
598 secondaryAlgorithm
= CSSM_ALGID_NONE
;
599 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
600 inputSizeLimit
= operation
== kSecKeyOperationTypeEncrypt
? -11 : 0;
604 } else if (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeDecrypt
&&
605 CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionRaw
)) {
606 // Raw RSA decryption is identical to raw RSA encryption, so lets use encryption instead of decryption,
607 // because CDSA keys refuses to perform decrypt using public key.
608 operation
= kSecKeyOperationTypeEncrypt
;
609 secondaryAlgorithm
= CSSM_ALGID_NONE
;
610 paddingAlgorithm
= CSSM_PADDING_NONE
;
616 case CSSM_ALGID_ECDSA
:
617 if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeSign
) ||
618 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeVerify
)) {
619 if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureRFC4754
)) {
620 secondaryAlgorithm
= CSSM_ALGID_NONE
;
621 paddingAlgorithm
= CSSM_PADDING_SIGRAW
;
622 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureDigestX962
)) {
623 secondaryAlgorithm
= CSSM_ALGID_NONE
;
624 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
628 } else if (keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeKeyExchange
) {
629 if (CFEqual(algorithm
,kSecKeyAlgorithmECDHKeyExchangeStandard
) ||
630 CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactor
)) {
631 baseAlgorithm
= CSSM_ALGID_ECDH
;
632 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1
) ||
633 CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1
)) {
634 baseAlgorithm
= CSSM_ALGID_ECDH_X963_KDF
;
643 MacOSError::throwMe(errSecParam
);
649 SecCDSAKeyCopyPaddedPlaintext(SecKeyRef key
, CFDataRef plaintext
, SecKeyAlgorithm algorithm
) {
650 CFIndex blockSize
= key
->key
->key().header().LogicalKeySizeInBits
/ 8;
651 CFIndex plaintextLength
= CFDataGetLength(plaintext
);
652 if ((algorithm
== kSecKeyAlgorithmRSAEncryptionRaw
|| algorithm
== kSecKeyAlgorithmRSASignatureRaw
)
653 && plaintextLength
< blockSize
) {
654 // Pre-pad with zeroes.
655 CFMutableDataRef
result(CFDataCreateMutable(kCFAllocatorDefault
, blockSize
));
656 CFDataSetLength(result
, blockSize
);
657 CFDataReplaceBytes(result
, CFRangeMake(blockSize
- plaintextLength
, plaintextLength
),
658 CFDataGetBytePtr(plaintext
), plaintextLength
);
661 return CFDataRef(CFRetain(plaintext
));
665 static CFTypeRef
SecCDSAKeyCopyOperationResult(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
,
666 CFArrayRef allAlgorithms
, SecKeyOperationMode mode
,
667 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
668 BEGIN_SECKEYAPI(CFTypeRef
, kCFNull
)
669 CFIndex inputSizeLimit
= 0;
670 CSSM_ALGORITHMS baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
;
671 KeyItem
*keyItem
= SecCDSAKeyPrepareParameters(key
, operation
, algorithm
, baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
, inputSizeLimit
);
672 if (keyItem
== NULL
) {
673 // Operation/algorithm/key combination is not supported.
675 } else if (mode
== kSecKeyOperationModeCheckIfSupported
) {
676 // Operation is supported and caller wants to just know that.
677 return kCFBooleanTrue
;
678 } else if (baseAlgorithm
== CSSM_ALGID_RSA
) {
679 if (inputSizeLimit
<= 0) {
680 inputSizeLimit
+= SecCDSAKeyGetBlockSize(key
);
682 if (CFDataGetLength((CFDataRef
)in1
) > inputSizeLimit
) {
683 MacOSError::throwMe(errSecParam
);
688 case kSecKeyOperationTypeSign
: {
689 CssmClient::Sign
signContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
);
690 signContext
.key(keyItem
->key());
691 signContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN
, key
->credentialType
));
692 signContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
);
693 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
694 CssmAutoData
signature(signContext
.allocator());
695 signContext
.sign(CssmData(CFDataRef(input
)), signature
.get());
696 result
= CFDataCreate(NULL
, static_cast<const UInt8
*>(signature
.data()), CFIndex(signature
.length()));
699 case kSecKeyOperationTypeVerify
: {
700 CssmClient::Verify
verifyContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
);
701 verifyContext
.key(keyItem
->key());
702 verifyContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ANY
, key
->credentialType
));
703 verifyContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
);
704 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
705 verifyContext
.verify(CssmData(CFDataRef(input
)), CssmData(CFRef
<CFDataRef
>::check(in2
, errSecParam
)));
706 result
= kCFBooleanTrue
;
709 case kSecKeyOperationTypeEncrypt
: {
710 CssmClient::Encrypt
encryptContext(keyItem
->csp(), baseAlgorithm
);
711 encryptContext
.key(keyItem
->key());
712 encryptContext
.padding(paddingAlgorithm
);
713 encryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT
, key
->credentialType
));
714 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
715 CssmAutoData
output(encryptContext
.allocator()), remainingData(encryptContext
.allocator());
716 size_t length
= encryptContext
.encrypt(CssmData(CFDataRef(input
)), output
.get(), remainingData
.get());
717 result
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length());
718 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(output
.data()), output
.length());
719 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(remainingData
.data()), remainingData
.length());
720 CFDataSetLength(CFMutableDataRef(result
), length
);
723 case kSecKeyOperationTypeDecrypt
: {
724 CssmClient::Decrypt
decryptContext(keyItem
->csp(), baseAlgorithm
);
725 decryptContext
.key(keyItem
->key());
726 decryptContext
.padding(paddingAlgorithm
);
727 decryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT
, key
->credentialType
));
728 CssmAutoData
output(decryptContext
.allocator()), remainingData(decryptContext
.allocator());
729 size_t length
= decryptContext
.decrypt(CssmData(CFRef
<CFDataRef
>::check(in1
, errSecParam
)),
730 output
.get(), remainingData
.get());
731 result
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length());
732 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(output
.data()), output
.length());
733 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(remainingData
.data()), remainingData
.length());
734 CFDataSetLength(CFMutableDataRef(result
), length
);
737 case kSecKeyOperationTypeKeyExchange
: {
738 CFIndex requestedLength
= 0;
740 switch (baseAlgorithm
) {
741 case CSSM_ALGID_ECDH
:
742 requestedLength
= (keyItem
->key().header().LogicalKeySizeInBits
+ 7) / 8;
744 case CSSM_ALGID_ECDH_X963_KDF
:
745 CFDictionaryRef params
= CFRef
<CFDictionaryRef
>::check(in2
, errSecParam
);
746 CFTypeRef value
= params
? CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterRequestedSize
) : NULL
;
747 if (value
== NULL
|| CFGetTypeID(value
) != CFNumberGetTypeID() ||
748 !CFNumberGetValue(CFNumberRef(value
), kCFNumberCFIndexType
, &requestedLength
)) {
749 MacOSError::throwMe(errSecParam
);
751 value
= CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterSharedInfo
);
752 if (value
!= NULL
&& CFGetTypeID(value
) == CFDataGetTypeID()) {
753 sharedInfo
= CssmData(CFDataRef(value
));
758 CssmClient::DeriveKey
derive(keyItem
->csp(), baseAlgorithm
, CSSM_ALGID_AES
, uint32(requestedLength
* 8));
759 derive
.key(keyItem
->key());
760 derive
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DERIVE
, kSecCredentialTypeDefault
));
761 derive
.salt(sharedInfo
);
762 CssmData
param(CFRef
<CFDataRef
>::check(in1
, errSecParam
));
763 Key derivedKey
= derive(¶m
, KeySpec(CSSM_KEYUSE_ANY
, CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
));
765 // Export raw data of newly derived key (by wrapping with an empty key).
766 CssmClient::WrapKey
wrapper(keyItem
->csp(), CSSM_ALGID_NONE
);
767 Key wrappedKey
= wrapper(derivedKey
);
768 result
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)wrappedKey
->data(), CFIndex(wrappedKey
->length()));
778 static Boolean
SecCDSAKeyIsEqual(SecKeyRef key1
, SecKeyRef key2
) {
779 CFErrorRef
*error
= NULL
;
780 BEGIN_SECKEYAPI(Boolean
, false)
782 result
= key1
->key
->equal(*key2
->key
);
787 static Boolean
SecCDSAKeySetParameter(SecKeyRef key
, CFStringRef name
, CFPropertyListRef value
, CFErrorRef
*error
) {
788 BEGIN_SECKEYAPI(Boolean
, false)
790 if (CFEqual(name
, kSecUseAuthenticationUI
)) {
791 key
->credentialType
= CFEqual(value
, kSecUseAuthenticationUIAllow
) ? kSecCredentialTypeDefault
: kSecCredentialTypeNoUI
;
794 result
= SecError(errSecUnimplemented
, error
, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name
);
800 const SecKeyDescriptor kSecCDSAKeyDescriptor
= {
801 .version
= kSecKeyDescriptorVersion
,
804 .init
= SecCDSAKeyInit
,
805 .destroy
= SecCDSAKeyDestroy
,
806 .blockSize
= SecCDSAKeyGetBlockSize
,
807 .getAlgorithmID
= SecCDSAKeyGetAlgorithmId
,
808 .copyDictionary
= SecCDSAKeyCopyAttributeDictionary
,
809 .copyPublic
= SecCDSAKeyCopyPublicBytes
,
810 .copyExternalRepresentation
= SecCDSAKeyCopyExternalRepresentation
,
811 .copyPublicKey
= SecCDSAKeyCopyPublicKey
,
812 .copyOperationResult
= SecCDSAKeyCopyOperationResult
,
813 .isEqual
= SecCDSAKeyIsEqual
,
814 .setParameter
= SecCDSAKeySetParameter
,
816 .extraBytes
= (sizeof(struct OpaqueSecKeyRef
) > sizeof(struct __SecKey
) ? (sizeof(struct OpaqueSecKeyRef
) - sizeof(struct __SecKey
)) : 0),
820 namespace KeychainCore
{
821 SecCFObject
*KeyItem::fromSecKeyRef(CFTypeRef ptr
) {
822 if (ptr
== NULL
|| CFGetTypeID(ptr
) != SecKeyGetTypeID()) {
826 SecKeyRef key
= static_cast<SecKeyRef
>(const_cast<void *>(ptr
));
827 if (key
->key_class
== &kSecCDSAKeyDescriptor
) {
828 return static_cast<SecCFObject
*>(key
->key
);
831 if (key
->cdsaKey
== NULL
) {
832 // Create CDSA key from exported data of existing key.
833 CFRef
<CFDictionaryRef
> keyAttributes
= SecKeyCopyAttributes(key
);
835 CFRef
<CFDataRef
> keyData
= SecKeyCopyExternalRepresentation(key
, NULL
);
837 CFTypeRef pubKeyHash
= CFDictionaryGetValue(keyAttributes
, kSecAttrApplicationLabel
);
838 const void *keys
[] = { kSecClass
, kSecAttrNoLegacy
, kSecReturnRef
, kSecMatchLimit
};
839 const void *values
[] = { kSecClassIdentity
, kCFBooleanFalse
, kCFBooleanTrue
, kSecMatchLimitAll
};
840 CFRef
<CFDictionaryRef
> query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
,
841 sizeof(keys
) / sizeof(*keys
),
842 &kCFTypeDictionaryKeyCallBacks
,
843 &kCFTypeDictionaryValueCallBacks
);
844 CFRef
<CFArrayRef
> identities
;
845 OSStatus status
= SecItemCopyMatching(query
, (CFTypeRef
*)identities
.take());
846 if (status
== errSecSuccess
) {
847 for (int i
= 0; i
< CFArrayGetCount(identities
); ++i
) {
848 CFRef
<SecKeyRef
> privateKey
;
849 if (SecIdentityCopyPrivateKey((SecIdentityRef
)CFArrayGetValueAtIndex(identities
, i
), privateKey
.take()) != errSecSuccess
) {
852 CFRef
<CFDictionaryRef
> attrs
= SecKeyCopyAttributes(privateKey
);
853 if (CFEqual(CFDictionaryGetValue(attrs
, kSecAttrApplicationLabel
), pubKeyHash
)) {
854 key
->cdsaKey
= privateKey
.retain();
860 key
->cdsaKey
= SecKeyCreateFromData(keyAttributes
, keyData
, NULL
);
865 return (key
->cdsaKey
!= NULL
) ? key
->cdsaKey
->key
: NULL
;
868 // You need to hold this key's MutexForObject when you run this
869 void KeyItem::attachSecKeyRef() const {
870 SecKeyRef key
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, reinterpret_cast<const uint8_t *>(this), 0, 0);
871 key
->key
->mWeakSecKeyRef
= key
;
877 extern "C" Boolean
SecKeyIsCDSAKey(SecKeyRef ref
);
878 Boolean
SecKeyIsCDSAKey(SecKeyRef ref
) {
879 return ref
->key_class
== &kSecCDSAKeyDescriptor
;
883 static OSStatus
SecKeyCreatePairInternal(
884 SecKeychainRef keychainRef
,
885 CSSM_ALGORITHMS algorithm
,
886 uint32 keySizeInBits
,
887 CSSM_CC_HANDLE contextHandle
,
888 CSSM_KEYUSE publicKeyUsage
,
889 uint32 publicKeyAttr
,
890 CSSM_KEYUSE privateKeyUsage
,
891 uint32 privateKeyAttr
,
892 SecAccessRef initialAccess
,
893 SecKeyRef
* publicKeyRef
,
894 SecKeyRef
* privateKeyRef
)
899 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
900 SecPointer
<KeyItem
> pubItem
, privItem
;
901 if (((publicKeyAttr
| privateKeyAttr
) & CSSM_KEYATTR_PERMANENT
) != 0) {
902 keychain
= Keychain::optional(keychainRef
);
904 StMaybeLock
<Mutex
> _(keychain
? keychain
->getKeychainMutex() : NULL
);
905 KeyItem::createPair(keychain
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, publicKeyAttr
,
906 privateKeyUsage
, privateKeyAttr
, theAccess
, pubItem
, privItem
);
908 // Return the generated keys.
910 *publicKeyRef
= pubItem
->handle();
912 *privateKeyRef
= privItem
->handle();
919 SecKeychainRef keychainRef
,
920 CSSM_ALGORITHMS algorithm
,
921 uint32 keySizeInBits
,
922 CSSM_CC_HANDLE contextHandle
,
923 CSSM_KEYUSE publicKeyUsage
,
924 uint32 publicKeyAttr
,
925 CSSM_KEYUSE privateKeyUsage
,
926 uint32 privateKeyAttr
,
927 SecAccessRef initialAccess
,
928 SecKeyRef
* publicKeyRef
,
929 SecKeyRef
* privateKeyRef
)
931 OSStatus result
= SecKeyCreatePairInternal(keychainRef
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
,
932 publicKeyAttr
, privateKeyUsage
, privateKeyAttr
, initialAccess
, publicKeyRef
, privateKeyRef
);
940 SecKeyGetCSSMKey(SecKeyRef key
, const CSSM_KEY
**cssmKey
)
944 Required(cssmKey
) = KeyItem::required(key
)->key();
954 static ModuleNexus
<Mutex
> gSecReturnedKeyCSPsMutex
;
955 static ModuleNexus
<std::set
<CssmClient::CSP
>> gSecReturnedKeyCSPs
;
958 SecKeyGetCSPHandle(SecKeyRef keyRef
, CSSM_CSP_HANDLE
*cspHandle
)
962 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
964 // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP).
965 // Keep a global pointer to it to force the CSP to stay live forever.
966 CssmClient::CSP returnedKeyCSP
= keyItem
->csp();
968 StLock
<Mutex
> _(gSecReturnedKeyCSPsMutex());
969 gSecReturnedKeyCSPs().insert(returnedKeyCSP
);
971 Required(cspHandle
) = returnedKeyCSP
->handle();
976 /* deprecated as of 10.8 */
978 SecKeyGetAlgorithmID(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
**algid
)
982 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
983 Required(algid
) = &keyItem
->algorithmIdentifier();
989 SecKeyGetStrengthInBits(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
*algid
, unsigned int *strength
)
993 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
994 Required(strength
) = keyItem
->strengthInBits(algid
);
1000 SecKeyGetCredentials(
1002 CSSM_ACL_AUTHORIZATION_TAG operation
,
1003 SecCredentialType credentialType
,
1004 const CSSM_ACCESS_CREDENTIALS
**outCredentials
)
1008 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
1009 Required(outCredentials
) = keyItem
->getCredentials(operation
, credentialType
);
1016 SecKeychainRef keychainRef
,
1017 const CSSM_KEY
*publicCssmKey
,
1018 const CSSM_KEY
*privateCssmKey
,
1019 SecAccessRef initialAccess
,
1020 SecKeyRef
* publicKey
,
1021 SecKeyRef
* privateKey
)
1025 Keychain keychain
= Keychain::optional(keychainRef
);
1026 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
1027 SecPointer
<KeyItem
> pubItem
, privItem
;
1029 KeyItem::importPair(keychain
,
1030 Required(publicCssmKey
),
1031 Required(privateCssmKey
),
1036 // Return the generated keys.
1038 *publicKey
= pubItem
->handle();
1040 *privateKey
= privItem
->handle();
1046 SecKeyGenerateWithAttributes(
1047 SecKeychainAttributeList
* attrList
,
1048 SecKeychainRef keychainRef
,
1049 CSSM_ALGORITHMS algorithm
,
1050 uint32 keySizeInBits
,
1051 CSSM_CC_HANDLE contextHandle
,
1052 CSSM_KEYUSE keyUsage
,
1054 SecAccessRef initialAccess
,
1060 SecPointer
<Access
> theAccess
;
1063 keychain
= KeychainImpl::required(keychainRef
);
1065 theAccess
= Access::required(initialAccess
);
1067 SecPointer
<KeyItem
> item
= KeyItem::generateWithAttributes(attrList
,
1076 // Return the generated key.
1078 *keyRef
= item
->handle();
1085 SecKeychainRef keychainRef
,
1086 CSSM_ALGORITHMS algorithm
,
1087 uint32 keySizeInBits
,
1088 CSSM_CC_HANDLE contextHandle
,
1089 CSSM_KEYUSE keyUsage
,
1091 SecAccessRef initialAccess
,
1094 return SecKeyGenerateWithAttributes(NULL
,
1095 keychainRef
, algorithm
, keySizeInBits
,
1096 contextHandle
, keyUsage
, keyAttr
,
1097 initialAccess
, keyRef
);
1101 /* Generate a floating key reference from a CSSM_KEY */
1103 SecKeyCreateWithCSSMKey(const CSSM_KEY
*cssmKey
,
1109 if(cssmKey
->KeyData
.Length
== 0){
1110 MacOSError::throwMe(errSecInvalidAttributeKeyLength
);
1112 if(cssmKey
->KeyData
.Data
== NULL
){
1113 MacOSError::throwMe(errSecInvalidPointer
);
1115 CssmClient::CSP
csp(cssmKey
->KeyHeader
.CspId
);
1116 CssmClient::Key
key(csp
, *cssmKey
);
1117 KeyItem
*item
= new KeyItem(key
);
1119 // Return the generated key.
1121 *keyRef
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, (const uint8_t *)item
, 0, 0);
1128 static u_int32_t
ConvertCFStringToInteger(CFStringRef ref
)
1135 // figure out the size of the string
1136 CFIndex numChars
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref
), kCFStringEncodingUTF8
);
1137 char *buffer
= (char *)malloc(numChars
);
1138 if (NULL
== buffer
) {
1139 UnixError::throwMe(ENOMEM
);
1141 if (!CFStringGetCString(ref
, buffer
, numChars
, kCFStringEncodingUTF8
))
1144 MacOSError::throwMe(errSecParam
);
1147 u_int32_t result
= atoi(buffer
);
1154 static OSStatus
CheckAlgorithmType(CFDictionaryRef parameters
, CSSM_ALGORITHMS
&algorithms
)
1156 // figure out the algorithm to use
1157 CFStringRef ktype
= (CFStringRef
) CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
1163 if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
1164 algorithms
= CSSM_ALGID_RSA
;
1165 return errSecSuccess
;
1166 } else if(CFEqual(ktype
, kSecAttrKeyTypeECDSA
) ||
1167 CFEqual(ktype
, kSecAttrKeyTypeEC
)) {
1168 algorithms
= CSSM_ALGID_ECDSA
;
1169 return errSecSuccess
;
1170 } else if(CFEqual(ktype
, kSecAttrKeyTypeAES
)) {
1171 algorithms
= CSSM_ALGID_AES
;
1172 return errSecSuccess
;
1173 } else if(CFEqual(ktype
, kSecAttrKeyType3DES
)) {
1174 algorithms
= CSSM_ALGID_3DES
;
1175 return errSecSuccess
;
1177 return errSecUnsupportedAlgorithm
;
1183 static OSStatus
GetKeySize(CFDictionaryRef parameters
, CSSM_ALGORITHMS algorithms
, uint32
&keySizeInBits
)
1186 // get the key size and check it for validity
1187 CFTypeRef ref
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
1189 keySizeInBits
= kSecDefaultKeySize
;
1191 CFTypeID bitSizeType
= CFGetTypeID(ref
);
1192 if (bitSizeType
== CFStringGetTypeID())
1193 keySizeInBits
= ConvertCFStringToInteger((CFStringRef
) ref
);
1194 else if (bitSizeType
== CFNumberGetTypeID())
1195 CFNumberGetValue((CFNumberRef
) ref
, kCFNumberSInt32Type
, &keySizeInBits
);
1196 else return errSecParam
;
1199 switch (algorithms
) {
1200 case CSSM_ALGID_ECDSA
:
1201 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecp256r1
;
1202 if(keySizeInBits
== kSecp192r1
|| keySizeInBits
== kSecp256r1
|| keySizeInBits
== kSecp384r1
|| keySizeInBits
== kSecp521r1
) return errSecSuccess
;
1204 case CSSM_ALGID_RSA
:
1205 if(keySizeInBits
% 8) return errSecParam
;
1206 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= 2048;
1207 if(keySizeInBits
>= kSecRSAMin
&& keySizeInBits
<= kSecRSAMax
) return errSecSuccess
;
1209 case CSSM_ALGID_AES
:
1210 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecAES128
;
1211 if(keySizeInBits
== kSecAES128
|| keySizeInBits
== kSecAES192
|| keySizeInBits
== kSecAES256
) return errSecSuccess
;
1213 case CSSM_ALGID_3DES
:
1214 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSec3DES192
;
1215 if(keySizeInBits
== kSec3DES192
) return errSecSuccess
;
1234 struct ParameterAttribute
1236 const CFStringRef
*name
;
1242 static ParameterAttribute gAttributes
[] =
1249 &kSecAttrIsPermanent
,
1253 &kSecAttrApplicationTag
,
1257 &kSecAttrEffectiveKeySize
,
1261 &kSecAttrCanEncrypt
,
1265 &kSecAttrCanDecrypt
,
1286 const int kNumberOfAttributes
= sizeof(gAttributes
) / sizeof(ParameterAttribute
);
1288 static OSStatus
ScanDictionaryForParameters(CFDictionaryRef parameters
, void* attributePointers
[])
1291 for (i
= 0; i
< kNumberOfAttributes
; ++i
)
1293 // see if the corresponding tag exists in the dictionary
1294 CFTypeRef value
= CFDictionaryGetValue(parameters
, *(gAttributes
[i
].name
));
1297 switch (gAttributes
[i
].type
)
1300 // just return the value
1301 *(CFTypeRef
*) attributePointers
[i
] = value
;
1306 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1307 *(bool*) attributePointers
[i
] = CFBooleanGetValue(bRef
);
1313 CFNumberRef nRef
= (CFNumberRef
) value
;
1314 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, attributePointers
[i
]);
1321 return errSecSuccess
;
1326 static OSStatus
GetKeyParameters(CFDictionaryRef parameters
, int keySize
, bool isPublic
, CSSM_KEYUSE
&keyUse
, uint32
&attrs
, CFTypeRef
&labelRef
, CFDataRef
&applicationTagRef
)
1328 // establish default values
1330 bool isPermanent
= false;
1331 applicationTagRef
= NULL
;
1332 CFTypeRef effectiveKeySize
= NULL
;
1333 bool canDecrypt
= isPublic
? false : true;
1334 bool canEncrypt
= !canDecrypt
;
1335 bool canDerive
= true;
1336 bool canSign
= isPublic
? false : true;
1337 bool canVerify
= !canSign
;
1338 bool canUnwrap
= isPublic
? false : true;
1339 attrs
= CSSM_KEYATTR_EXTRACTABLE
;
1342 void* attributePointers
[] = {&labelRef
, &isPermanent
, &applicationTagRef
, &effectiveKeySize
, &canEncrypt
, &canDecrypt
,
1343 &canDerive
, &canSign
, &canVerify
, &canUnwrap
};
1345 // look for modifiers in the general dictionary
1346 OSStatus result
= ScanDictionaryForParameters(parameters
, attributePointers
);
1347 if (result
!= errSecSuccess
)
1352 // see if we have anything which modifies the defaults
1356 key
= kSecPublicKeyAttrs
;
1360 key
= kSecPrivateKeyAttrs
;
1363 CFTypeRef dType
= CFDictionaryGetValue(parameters
, key
);
1366 // this had better be a dictionary
1367 if (CFGetTypeID(dType
) != CFDictionaryGetTypeID())
1372 // pull any additional parameters out of this dictionary
1373 result
= ScanDictionaryForParameters((CFDictionaryRef
)dType
, attributePointers
);
1374 if (result
!= errSecSuccess
)
1380 // figure out the key usage
1384 keyUse
|= CSSM_KEYUSE_DECRYPT
;
1389 keyUse
|= CSSM_KEYUSE_ENCRYPT
;
1394 keyUse
|= CSSM_KEYUSE_DERIVE
;
1399 keyUse
|= CSSM_KEYUSE_SIGN
;
1404 keyUse
|= CSSM_KEYUSE_VERIFY
;
1409 keyUse
|= CSSM_KEYUSE_UNWRAP
;
1412 // public key is always extractable;
1413 // private key is extractable by default unless explicitly set to false
1414 CFTypeRef value
= NULL
;
1415 if (!isPublic
&& CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
) && value
)
1417 Boolean keyIsExtractable
= CFEqual(kCFBooleanTrue
, value
);
1418 if (!keyIsExtractable
)
1423 attrs
|= CSSM_KEYATTR_PERMANENT
;
1426 return errSecSuccess
;
1431 static OSStatus
MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters
,
1432 CSSM_ALGORITHMS
&algorithms
,
1433 uint32
&keySizeInBits
,
1434 CSSM_KEYUSE
&publicKeyUse
,
1435 uint32
&publicKeyAttr
,
1436 CFTypeRef
&publicKeyLabelRef
,
1437 CFDataRef
&publicKeyAttributeTagRef
,
1438 CSSM_KEYUSE
&privateKeyUse
,
1439 uint32
&privateKeyAttr
,
1440 CFTypeRef
&privateKeyLabelRef
,
1441 CFDataRef
&privateKeyAttributeTagRef
,
1442 SecAccessRef
&initialAccess
)
1446 result
= CheckAlgorithmType(parameters
, algorithms
);
1447 if (result
!= errSecSuccess
)
1452 result
= GetKeySize(parameters
, algorithms
, keySizeInBits
);
1453 if (result
!= errSecSuccess
)
1458 result
= GetKeyParameters(parameters
, keySizeInBits
, false, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1459 if (result
!= errSecSuccess
)
1464 result
= GetKeyParameters(parameters
, keySizeInBits
, true, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1465 if (result
!= errSecSuccess
)
1470 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&initialAccess
))
1472 initialAccess
= NULL
;
1474 else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess
))
1479 return errSecSuccess
;
1484 static OSStatus
SetKeyLabelAndTag(SecKeyRef keyRef
, CFTypeRef label
, CFDataRef tag
)
1486 int numToModify
= 0;
1497 if (numToModify
== 0)
1499 return errSecSuccess
;
1502 SecKeychainAttributeList attrList
;
1503 SecKeychainAttribute attributes
[numToModify
];
1510 if (CFStringGetTypeID() == CFGetTypeID(label
)) {
1511 CFStringRef label_string
= static_cast<CFStringRef
>(label
);
1512 attributes
[i
].tag
= kSecKeyPrintName
;
1513 attributes
[i
].data
= (void*) CFStringGetCStringPtr(label_string
, kCFStringEncodingUTF8
);
1514 if (NULL
== attributes
[i
].data
) {
1515 CFIndex buffer_length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string
), kCFStringEncodingUTF8
);
1516 data
= attributes
[i
].data
= malloc((size_t)buffer_length
);
1517 if (NULL
== attributes
[i
].data
) {
1518 UnixError::throwMe(ENOMEM
);
1520 if (!CFStringGetCString(label_string
, static_cast<char *>(attributes
[i
].data
), buffer_length
, kCFStringEncodingUTF8
)) {
1522 MacOSError::throwMe(errSecParam
);
1525 attributes
[i
].length
= (UInt32
)strlen(static_cast<char *>(attributes
[i
].data
));
1526 } else if (CFDataGetTypeID() == CFGetTypeID(label
)) {
1527 // 10.6 bug compatibility
1528 CFDataRef label_data
= static_cast<CFDataRef
>(label
);
1529 attributes
[i
].tag
= kSecKeyLabel
;
1530 attributes
[i
].data
= (void*) CFDataGetBytePtr(label_data
);
1531 attributes
[i
].length
= (UInt32
)CFDataGetLength(label_data
);
1533 MacOSError::throwMe(errSecParam
);
1540 attributes
[i
].tag
= kSecKeyApplicationTag
;
1541 attributes
[i
].data
= (void*) CFDataGetBytePtr(tag
);
1542 attributes
[i
].length
= (UInt32
)CFDataGetLength(tag
);
1546 attrList
.count
= numToModify
;
1547 attrList
.attr
= attributes
;
1549 OSStatus result
= SecKeychainItemModifyAttributesAndData((SecKeychainItemRef
) keyRef
, &attrList
, 0, NULL
);
1559 static CFTypeRef
GetAttributeFromParams(CFDictionaryRef parameters
, CFTypeRef attr
, CFTypeRef subParams
) {
1560 if (subParams
!= NULL
) {
1561 CFDictionaryRef subParamsDict
= (CFDictionaryRef
)CFDictionaryGetValue(parameters
, subParams
);
1562 if (subParamsDict
!= NULL
) {
1563 CFTypeRef value
= CFDictionaryGetValue(subParamsDict
, attr
);
1564 if (value
!= NULL
) {
1569 return CFDictionaryGetValue(parameters
, attr
);
1572 extern "C" OSStatus
SecKeyGeneratePair_ios(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
);
1575 /* Generate a private/public keypair. */
1577 SecKeyGeneratePairInternal(
1578 bool alwaysPermanent
,
1579 CFDictionaryRef parameters
,
1580 SecKeyRef
*publicKey
,
1581 SecKeyRef
*privateKey
)
1585 Required(parameters
);
1586 Required(publicKey
);
1587 Required(privateKey
);
1589 bool forceIOSKey
= false;
1590 if (_CFMZEnabled()) {
1591 // On Marzipan, always go iOS SecItem/SecKey route, do not drag CSSM keys in.
1594 CFTypeRef tokenID
= GetAttributeFromParams(parameters
, kSecAttrTokenID
, NULL
);
1595 CFTypeRef noLegacy
= GetAttributeFromParams(parameters
, kSecAttrNoLegacy
, NULL
);
1596 CFTypeRef sync
= GetAttributeFromParams(parameters
, kSecAttrSynchronizable
, kSecPrivateKeyAttrs
);
1597 CFTypeRef accessControl
= GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPrivateKeyAttrs
) ?:
1598 GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPublicKeyAttrs
);
1599 CFTypeRef accessGroup
= GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPrivateKeyAttrs
) ?:
1600 GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPublicKeyAttrs
);
1601 // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain).
1602 forceIOSKey
= (tokenID
!= NULL
||
1603 (noLegacy
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)noLegacy
)) ||
1604 (sync
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)sync
)) ||
1605 accessControl
!= NULL
|| (accessGroup
!= NULL
&& CFEqual(accessGroup
, kSecAttrAccessGroupToken
)));
1609 // Generate keys in iOS keychain.
1610 return SecKeyGeneratePair_ios(parameters
, publicKey
, privateKey
);
1613 CSSM_ALGORITHMS algorithms
;
1614 uint32 keySizeInBits
;
1615 CSSM_KEYUSE publicKeyUse
;
1616 uint32 publicKeyAttr
;
1617 CFTypeRef publicKeyLabelRef
;
1618 CFDataRef publicKeyAttributeTagRef
;
1619 CSSM_KEYUSE privateKeyUse
;
1620 uint32 privateKeyAttr
;
1621 CFTypeRef privateKeyLabelRef
;
1622 CFDataRef privateKeyAttributeTagRef
;
1623 SecAccessRef initialAccess
;
1624 SecKeychainRef keychain
;
1626 OSStatus result
= MakeKeyGenParametersFromDictionary(parameters
, algorithms
, keySizeInBits
, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
,
1627 publicKeyAttributeTagRef
, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
,
1630 if (result
!= errSecSuccess
) {
1634 // verify keychain parameter
1635 keychain
= (SecKeychainRef
)CFDictionaryGetValue(parameters
, kSecUseKeychain
);
1636 if (keychain
!= NULL
&& SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1640 if (alwaysPermanent
) {
1641 publicKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1642 privateKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1645 // do the key generation
1646 result
= SecKeyCreatePair(keychain
, algorithms
, keySizeInBits
, 0, publicKeyUse
, publicKeyAttr
, privateKeyUse
, privateKeyAttr
, initialAccess
, publicKey
, privateKey
);
1647 if (result
!= errSecSuccess
) {
1651 // set the label and print attributes on the keys
1652 SetKeyLabelAndTag(*publicKey
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1653 SetKeyLabelAndTag(*privateKey
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1660 SecKeyGeneratePair(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
1661 return SecKeyGeneratePairInternal(true, parameters
, publicKey
, privateKey
);
1665 SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef
*error
) {
1666 SecKeyRef privateKey
= NULL
, publicKey
= NULL
;
1667 OSStatus status
= SecKeyGeneratePairInternal(false, parameters
, &publicKey
, &privateKey
);
1668 SecError(status
, error
, CFSTR("failed to generate asymmetric keypair"));
1669 if (publicKey
!= NULL
) {
1670 CFRelease(publicKey
);
1675 OSStatus
SecKeyRawVerifyOSX(
1676 SecKeyRef key
, /* Public key */
1677 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
1678 const uint8_t *signedData
, /* signature over this data */
1679 size_t signedDataLen
, /* length of dataToSign */
1680 const uint8_t *sig
, /* signature */
1683 return SecKeyRawVerify(key
,padding
,signedData
,signedDataLen
,sig
,sigLen
);
1691 utilGetStringFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, CFTypeRef defaultValue
)
1693 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1694 if (value
!= NULL
) return value
;
1695 return defaultValue
;
1699 utilGetNumberFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t defaultValue
)
1701 uint32_t integerValue
;
1702 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1703 if (value
!= NULL
) {
1704 CFNumberRef nRef
= (CFNumberRef
) value
;
1705 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, &integerValue
);
1706 return integerValue
;
1708 return defaultValue
;
1712 utilGetMaskValFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t maskValue
)
1714 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1715 if (value
!= NULL
) {
1716 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1717 if(CFBooleanGetValue(bRef
)) return maskValue
;
1723 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters
, CSSM_ALGORITHMS
*algorithm
, uint32
*keySizeInBits
, CSSM_KEYUSE
*keyUsage
, CSSM_KEYCLASS
*keyClass
)
1725 CFTypeRef algorithmDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeAES
);
1726 CFTypeRef keyClassDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1728 if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeAES
)) {
1729 *algorithm
= CSSM_ALGID_AES
;
1730 *keySizeInBits
= 128;
1731 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1732 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDES
)) {
1733 *algorithm
= CSSM_ALGID_DES
;
1734 *keySizeInBits
= 128;
1735 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1736 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyType3DES
)) {
1737 *algorithm
= CSSM_ALGID_3DES_3KEY_EDE
;
1738 *keySizeInBits
= 128;
1739 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1740 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC4
)) {
1741 *algorithm
= CSSM_ALGID_RC4
;
1742 *keySizeInBits
= 128;
1743 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1744 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC2
)) {
1745 *algorithm
= CSSM_ALGID_RC2
;
1746 *keySizeInBits
= 128;
1747 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1748 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeCAST
)) {
1749 *algorithm
= CSSM_ALGID_CAST
;
1750 *keySizeInBits
= 128;
1751 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1752 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRSA
)) {
1753 *algorithm
= CSSM_ALGID_RSA
;
1754 *keySizeInBits
= 128;
1755 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1756 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDSA
)) {
1757 *algorithm
= CSSM_ALGID_DSA
;
1758 *keySizeInBits
= 128;
1759 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1760 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeECDSA
) ||
1761 CFEqual(algorithmDictValue
, kSecAttrKeyTypeEC
)) {
1762 *algorithm
= CSSM_ALGID_ECDSA
;
1763 *keySizeInBits
= 128;
1764 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1766 *algorithm
= CSSM_ALGID_AES
;
1767 *keySizeInBits
= 128;
1768 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1771 if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPublic
)) {
1772 *keyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
1773 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPrivate
)) {
1774 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1775 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassSymmetric
)) {
1776 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1779 *keySizeInBits
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, *keySizeInBits
);
1780 *keyUsage
= utilGetMaskValFromCFDict(parameters
, kSecAttrCanEncrypt
, CSSM_KEYUSE_ENCRYPT
) |
1781 utilGetMaskValFromCFDict(parameters
, kSecAttrCanDecrypt
, CSSM_KEYUSE_DECRYPT
) |
1782 utilGetMaskValFromCFDict(parameters
, kSecAttrCanWrap
, CSSM_KEYUSE_WRAP
) |
1783 utilGetMaskValFromCFDict(parameters
, kSecAttrCanUnwrap
, CSSM_KEYUSE_UNWRAP
);
1786 if(*keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
|| *keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
) {
1787 *keyUsage
|= utilGetMaskValFromCFDict(parameters
, kSecAttrCanSign
, CSSM_KEYUSE_SIGN
) |
1788 utilGetMaskValFromCFDict(parameters
, kSecAttrCanVerify
, CSSM_KEYUSE_VERIFY
);
1791 if(*keyUsage
== 0) {
1792 switch (*keyClass
) {
1793 case CSSM_KEYCLASS_PRIVATE_KEY
:
1794 *keyUsage
= CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
;
1796 case CSSM_KEYCLASS_PUBLIC_KEY
:
1797 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
;
1800 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
;
1807 utilCopyDefaultKeyLabel(void)
1809 // generate a default label from the current date
1810 CFDateRef dateNow
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent());
1811 CFStringRef defaultLabel
= CFCopyDescription(dateNow
);
1814 return defaultLabel
;
1818 SecKeyGenerateSymmetric(CFDictionaryRef parameters
, CFErrorRef
*error
)
1820 OSStatus result
= errSecParam
; // default result for an early exit
1821 SecKeyRef key
= NULL
;
1822 SecKeychainRef keychain
= NULL
;
1823 SecAccessRef access
;
1825 CFStringRef appLabel
;
1827 CFStringRef dateLabel
= NULL
;
1829 CSSM_ALGORITHMS algorithm
;
1830 uint32 keySizeInBits
;
1831 CSSM_KEYUSE keyUsage
;
1832 uint32 keyAttr
= CSSM_KEYATTR_RETURN_DEFAULT
;
1833 CSSM_KEYCLASS keyClass
;
1835 Boolean isPermanent
;
1836 Boolean isExtractable
;
1838 // verify keychain parameter
1839 if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
))
1841 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1848 // verify permanent parameter
1849 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsPermanent
, (const void **)&value
))
1850 isPermanent
= false;
1851 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1854 isPermanent
= CFEqual(kCFBooleanTrue
, value
);
1856 if (keychain
== NULL
) {
1857 // no keychain was specified, so use the default keychain
1858 result
= SecKeychainCopyDefault(&keychain
);
1860 keyAttr
|= CSSM_KEYATTR_PERMANENT
;
1863 // verify extractable parameter
1864 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
))
1865 isExtractable
= true; // default to extractable if value not specified
1866 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1869 isExtractable
= CFEqual(kCFBooleanTrue
, value
);
1871 keyAttr
|= CSSM_KEYATTR_EXTRACTABLE
;
1873 // verify access parameter
1874 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&access
))
1876 else if (SecAccessGetTypeID() != CFGetTypeID(access
))
1879 // verify label parameter
1880 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrLabel
, (const void **)&label
))
1881 label
= (dateLabel
= utilCopyDefaultKeyLabel()); // no label provided, so use default
1882 else if (CFStringGetTypeID() != CFGetTypeID(label
))
1885 // verify application label parameter
1886 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationLabel
, (const void **)&appLabel
))
1887 appLabel
= (dateLabel
) ? dateLabel
: (dateLabel
= utilCopyDefaultKeyLabel());
1888 else if (CFStringGetTypeID() != CFGetTypeID(appLabel
))
1891 // verify application tag parameter
1892 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationTag
, (const void **)&appTag
))
1894 else if (CFStringGetTypeID() != CFGetTypeID(appTag
))
1897 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1900 // the generated key will not be stored in any keychain
1901 result
= SecKeyGenerate(keychain
, algorithm
, keySizeInBits
, 0, keyUsage
, keyAttr
, access
, &key
);
1904 // we can set the label attributes on the generated key if it's a keychain item
1905 size_t labelBufLen
= (label
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label
), kCFStringEncodingUTF8
) + 1 : 1;
1906 char *labelBuf
= (char *)malloc(labelBufLen
);
1907 size_t appLabelBufLen
= (appLabel
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel
), kCFStringEncodingUTF8
) + 1 : 1;
1908 char *appLabelBuf
= (char *)malloc(appLabelBufLen
);
1909 size_t appTagBufLen
= (appTag
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag
), kCFStringEncodingUTF8
) + 1 : 1;
1910 char *appTagBuf
= (char *)malloc(appTagBufLen
);
1912 if (!label
|| !CFStringGetCString(label
, labelBuf
, labelBufLen
-1, kCFStringEncodingUTF8
))
1914 if (!appLabel
|| !CFStringGetCString(appLabel
, appLabelBuf
, appLabelBufLen
-1, kCFStringEncodingUTF8
))
1916 if (!appTag
|| !CFStringGetCString(appTag
, appTagBuf
, appTagBufLen
-1, kCFStringEncodingUTF8
))
1919 SecKeychainAttribute attrs
[] = {
1920 { kSecKeyPrintName
, (UInt32
)strlen(labelBuf
), (char *)labelBuf
},
1921 { kSecKeyLabel
, (UInt32
)strlen(appLabelBuf
), (char *)appLabelBuf
},
1922 { kSecKeyApplicationTag
, (UInt32
)strlen(appTagBuf
), (char *)appTagBuf
} };
1923 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
1924 if (!appTag
) --attributes
.count
;
1926 result
= SecKeyGenerateWithAttributes(&attributes
,
1927 keychain
, algorithm
, keySizeInBits
, 0,
1928 keyUsage
, keyAttr
, access
, &key
);
1936 if (result
&& error
) {
1937 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, result
, NULL
);
1940 CFRelease(dateLabel
);
1942 CFRelease(keychain
);
1950 SecKeyCreateFromData(CFDictionaryRef parameters
, CFDataRef keyData
, CFErrorRef
*error
)
1952 CSSM_ALGORITHMS algorithm
;
1953 uint32 keySizeInBits
;
1954 CSSM_KEYUSE keyUsage
;
1955 CSSM_KEYCLASS keyClass
;
1958 if(keyData
== NULL
|| CFDataGetLength(keyData
) == 0){
1959 MacOSError::throwMe(errSecUnsupportedKeySize
);
1962 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1964 CSSM_CSP_HANDLE cspHandle
= cuCspStartup(CSSM_FALSE
); // TRUE => CSP, FALSE => CSPDL
1966 SecKeyImportExportParameters iparam
;
1967 memset(&iparam
, 0, sizeof(iparam
));
1968 iparam
.keyUsage
= keyUsage
;
1970 CFRef
<CFDataRef
> data
;
1971 SecExternalItemType itype
;
1973 case CSSM_KEYCLASS_PRIVATE_KEY
:
1974 itype
= kSecItemTypePrivateKey
;
1976 case CSSM_KEYCLASS_PUBLIC_KEY
: {
1977 itype
= kSecItemTypePublicKey
;
1978 // Public key import expects public key in SubjPublicKey X509 format. We want to accept both bare and x509 format,
1979 // so we have to detect bare format here and extend to full X509 if detected.
1980 data
.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm
, keySizeInBits
, keyData
));
1983 case CSSM_KEYCLASS_SESSION_KEY
:
1984 itype
= kSecItemTypeSessionKey
;
1987 itype
= kSecItemTypeUnknown
;
1991 CFMutableArrayRef ka
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1992 // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful.
1993 crtn
= impExpImportRawKey(data
? CFDataRef(data
) : keyData
, kSecFormatUnknown
, itype
, algorithm
, NULL
, cspHandle
, 0, NULL
, NULL
, ka
);
1994 if (crtn
== CSSM_OK
&& CFArrayGetCount((CFArrayRef
)ka
)) {
1995 SecKeyRef sk
= (SecKeyRef
)CFArrayGetValueAtIndex((CFArrayRef
)ka
, 0);
2002 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, crtn
? crtn
: CSSM_ERRCODE_INTERNAL_ERROR
, NULL
);
2010 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable
, dispatch_queue_t deliveryQueue
,
2011 SecKeyGeneratePairBlock result
)
2013 CFDictionaryRef parameters
= CFDictionaryCreateCopy(NULL
, parametersWhichMightBeMutiable
);
2014 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
2015 SecKeyRef publicKey
= NULL
;
2016 SecKeyRef privateKey
= NULL
;
2017 OSStatus status
= SecKeyGeneratePair(parameters
, &publicKey
, &privateKey
);
2018 dispatch_async(deliveryQueue
, ^{
2019 CFErrorRef error
= NULL
;
2020 if (errSecSuccess
!= status
) {
2021 error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, NULL
);
2023 result(publicKey
, privateKey
, error
);
2028 CFRelease(publicKey
);
2031 CFRelease(privateKey
);
2033 CFRelease(parameters
);
2038 static inline void utilClearAndFree(void *p
, size_t len
) {
2040 if(len
) bzero(p
, len
);
2046 SecKeyDeriveFromPassword(CFStringRef password
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2048 CCPBKDFAlgorithm algorithm
;
2049 CFIndex passwordLen
= 0;
2050 CFDataRef keyData
= NULL
;
2051 char *thePassword
= NULL
;
2052 uint8_t *salt
= NULL
;
2053 uint8_t *derivedKey
= NULL
;
2054 size_t saltLen
= 0, derivedKeyLen
= 0;
2056 CFDataRef saltDictValue
, algorithmDictValue
;
2057 SecKeyRef retval
= NULL
;
2059 /* Pick Values from parameters */
2061 if((saltDictValue
= (CFDataRef
) CFDictionaryGetValue(parameters
, kSecAttrSalt
)) == NULL
) {
2063 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecMissingAlgorithmParms
, NULL
);
2068 derivedKeyLen
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, 128);
2069 // This value come in bits but the rest of the code treats it as bytes
2072 algorithmDictValue
= (CFDataRef
) utilGetStringFromCFDict(parameters
, kSecAttrPRF
, kSecAttrPRFHmacAlgSHA256
);
2074 rounds
= utilGetNumberFromCFDict(parameters
, kSecAttrRounds
, 0);
2076 /* Convert any remaining parameters and get the password bytes */
2078 saltLen
= CFDataGetLength(saltDictValue
);
2079 if((salt
= (uint8_t *) malloc(saltLen
)) == NULL
) {
2081 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2086 CFDataGetBytes(saltDictValue
, CFRangeMake(0, saltLen
), (UInt8
*) salt
);
2088 passwordLen
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1;
2089 if((thePassword
= (char *) malloc(passwordLen
)) == NULL
) {
2091 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2095 CFStringGetBytes(password
, CFRangeMake(0, CFStringGetLength(password
)), kCFStringEncodingUTF8
, '?', FALSE
, (UInt8
*)thePassword
, passwordLen
, &passwordLen
);
2097 if((derivedKey
= (uint8_t *) malloc(derivedKeyLen
)) == NULL
) {
2099 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2104 if(algorithmDictValue
== NULL
) {
2105 algorithm
= kCCPRFHmacAlgSHA1
; /* default */
2106 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA1
)) {
2107 algorithm
= kCCPRFHmacAlgSHA1
;
2108 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA224
)) {
2109 algorithm
= kCCPRFHmacAlgSHA224
;
2110 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA256
)) {
2111 algorithm
= kCCPRFHmacAlgSHA256
;
2112 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA384
)) {
2113 algorithm
= kCCPRFHmacAlgSHA384
;
2114 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA512
)) {
2115 algorithm
= kCCPRFHmacAlgSHA512
;
2118 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidAlgorithmParms
, NULL
);
2124 rounds
= 33333; // we need to pass back a consistent value since there's no way to record the round count.
2127 if(CCKeyDerivationPBKDF(kCCPBKDF2
, thePassword
, passwordLen
, salt
, saltLen
, algorithm
, rounds
, derivedKey
, derivedKeyLen
)) {
2129 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2134 if((keyData
= CFDataCreate(NULL
, derivedKey
, derivedKeyLen
)) != NULL
) {
2135 retval
= SecKeyCreateFromData(parameters
, keyData
, error
);
2139 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2144 utilClearAndFree(salt
, saltLen
);
2145 utilClearAndFree(thePassword
, passwordLen
);
2146 utilClearAndFree(derivedKey
, derivedKeyLen
);
2151 SecKeyWrapSymmetric(SecKeyRef keyToWrap
, SecKeyRef wrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2154 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);
2160 SecKeyUnwrapSymmetric(CFDataRef
*keyToUnwrap
, SecKeyRef unwrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2163 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);