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
<CFDataRef
> keyData
= SecKeyCopyExternalRepresentation(key
, NULL
);
834 CFRef
<CFDictionaryRef
> keyAttributes
= SecKeyCopyAttributes(key
);
835 if (keyData
&& keyAttributes
) {
836 key
->cdsaKey
= SecKeyCreateFromData(keyAttributes
, keyData
, NULL
);
840 return (key
->cdsaKey
!= NULL
) ? key
->cdsaKey
->key
: NULL
;
843 // You need to hold this key's MutexForObject when you run this
844 void KeyItem::attachSecKeyRef() const {
845 SecKeyRef key
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, reinterpret_cast<const uint8_t *>(this), 0, 0);
846 key
->key
->mWeakSecKeyRef
= key
;
852 extern "C" Boolean
SecKeyIsCDSAKey(SecKeyRef ref
);
853 Boolean
SecKeyIsCDSAKey(SecKeyRef ref
) {
854 return ref
->key_class
== &kSecCDSAKeyDescriptor
;
858 static OSStatus
SecKeyCreatePairInternal(
859 SecKeychainRef keychainRef
,
860 CSSM_ALGORITHMS algorithm
,
861 uint32 keySizeInBits
,
862 CSSM_CC_HANDLE contextHandle
,
863 CSSM_KEYUSE publicKeyUsage
,
864 uint32 publicKeyAttr
,
865 CSSM_KEYUSE privateKeyUsage
,
866 uint32 privateKeyAttr
,
867 SecAccessRef initialAccess
,
868 SecKeyRef
* publicKeyRef
,
869 SecKeyRef
* privateKeyRef
)
874 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
875 SecPointer
<KeyItem
> pubItem
, privItem
;
876 if (((publicKeyAttr
| privateKeyAttr
) & CSSM_KEYATTR_PERMANENT
) != 0) {
877 keychain
= Keychain::optional(keychainRef
);
879 StMaybeLock
<Mutex
> _(keychain
? keychain
->getKeychainMutex() : NULL
);
880 KeyItem::createPair(keychain
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, publicKeyAttr
,
881 privateKeyUsage
, privateKeyAttr
, theAccess
, pubItem
, privItem
);
883 // Return the generated keys.
885 *publicKeyRef
= pubItem
->handle();
887 *privateKeyRef
= privItem
->handle();
894 SecKeychainRef keychainRef
,
895 CSSM_ALGORITHMS algorithm
,
896 uint32 keySizeInBits
,
897 CSSM_CC_HANDLE contextHandle
,
898 CSSM_KEYUSE publicKeyUsage
,
899 uint32 publicKeyAttr
,
900 CSSM_KEYUSE privateKeyUsage
,
901 uint32 privateKeyAttr
,
902 SecAccessRef initialAccess
,
903 SecKeyRef
* publicKeyRef
,
904 SecKeyRef
* privateKeyRef
)
906 OSStatus result
= SecKeyCreatePairInternal(keychainRef
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
,
907 publicKeyAttr
, privateKeyUsage
, privateKeyAttr
, initialAccess
, publicKeyRef
, privateKeyRef
);
915 SecKeyGetCSSMKey(SecKeyRef key
, const CSSM_KEY
**cssmKey
)
919 Required(cssmKey
) = KeyItem::required(key
)->key();
929 static ModuleNexus
<Mutex
> gSecReturnedKeyCSPsMutex
;
930 static ModuleNexus
<std::set
<CssmClient::CSP
>> gSecReturnedKeyCSPs
;
933 SecKeyGetCSPHandle(SecKeyRef keyRef
, CSSM_CSP_HANDLE
*cspHandle
)
937 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
939 // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP).
940 // Keep a global pointer to it to force the CSP to stay live forever.
941 CssmClient::CSP returnedKeyCSP
= keyItem
->csp();
943 StLock
<Mutex
> _(gSecReturnedKeyCSPsMutex());
944 gSecReturnedKeyCSPs().insert(returnedKeyCSP
);
946 Required(cspHandle
) = returnedKeyCSP
->handle();
951 /* deprecated as of 10.8 */
953 SecKeyGetAlgorithmID(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
**algid
)
957 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
958 Required(algid
) = &keyItem
->algorithmIdentifier();
964 SecKeyGetStrengthInBits(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
*algid
, unsigned int *strength
)
968 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
969 Required(strength
) = keyItem
->strengthInBits(algid
);
975 SecKeyGetCredentials(
977 CSSM_ACL_AUTHORIZATION_TAG operation
,
978 SecCredentialType credentialType
,
979 const CSSM_ACCESS_CREDENTIALS
**outCredentials
)
983 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
984 Required(outCredentials
) = keyItem
->getCredentials(operation
, credentialType
);
991 SecKeychainRef keychainRef
,
992 const CSSM_KEY
*publicCssmKey
,
993 const CSSM_KEY
*privateCssmKey
,
994 SecAccessRef initialAccess
,
995 SecKeyRef
* publicKey
,
996 SecKeyRef
* privateKey
)
1000 Keychain keychain
= Keychain::optional(keychainRef
);
1001 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
1002 SecPointer
<KeyItem
> pubItem
, privItem
;
1004 KeyItem::importPair(keychain
,
1005 Required(publicCssmKey
),
1006 Required(privateCssmKey
),
1011 // Return the generated keys.
1013 *publicKey
= pubItem
->handle();
1015 *privateKey
= privItem
->handle();
1021 SecKeyGenerateWithAttributes(
1022 SecKeychainAttributeList
* attrList
,
1023 SecKeychainRef keychainRef
,
1024 CSSM_ALGORITHMS algorithm
,
1025 uint32 keySizeInBits
,
1026 CSSM_CC_HANDLE contextHandle
,
1027 CSSM_KEYUSE keyUsage
,
1029 SecAccessRef initialAccess
,
1035 SecPointer
<Access
> theAccess
;
1038 keychain
= KeychainImpl::required(keychainRef
);
1040 theAccess
= Access::required(initialAccess
);
1042 SecPointer
<KeyItem
> item
= KeyItem::generateWithAttributes(attrList
,
1051 // Return the generated key.
1053 *keyRef
= item
->handle();
1060 SecKeychainRef keychainRef
,
1061 CSSM_ALGORITHMS algorithm
,
1062 uint32 keySizeInBits
,
1063 CSSM_CC_HANDLE contextHandle
,
1064 CSSM_KEYUSE keyUsage
,
1066 SecAccessRef initialAccess
,
1069 return SecKeyGenerateWithAttributes(NULL
,
1070 keychainRef
, algorithm
, keySizeInBits
,
1071 contextHandle
, keyUsage
, keyAttr
,
1072 initialAccess
, keyRef
);
1076 /* Generate a floating key reference from a CSSM_KEY */
1078 SecKeyCreateWithCSSMKey(const CSSM_KEY
*cssmKey
,
1084 if(cssmKey
->KeyData
.Length
== 0){
1085 MacOSError::throwMe(errSecInvalidAttributeKeyLength
);
1087 if(cssmKey
->KeyData
.Data
== NULL
){
1088 MacOSError::throwMe(errSecInvalidPointer
);
1090 CssmClient::CSP
csp(cssmKey
->KeyHeader
.CspId
);
1091 CssmClient::Key
key(csp
, *cssmKey
);
1092 KeyItem
*item
= new KeyItem(key
);
1094 // Return the generated key.
1096 *keyRef
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, (const uint8_t *)item
, 0, 0);
1103 static u_int32_t
ConvertCFStringToInteger(CFStringRef ref
)
1110 // figure out the size of the string
1111 CFIndex numChars
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref
), kCFStringEncodingUTF8
);
1112 char *buffer
= (char *)malloc(numChars
);
1113 if (NULL
== buffer
) {
1114 UnixError::throwMe(ENOMEM
);
1116 if (!CFStringGetCString(ref
, buffer
, numChars
, kCFStringEncodingUTF8
))
1119 MacOSError::throwMe(errSecParam
);
1122 u_int32_t result
= atoi(buffer
);
1129 static OSStatus
CheckAlgorithmType(CFDictionaryRef parameters
, CSSM_ALGORITHMS
&algorithms
)
1131 // figure out the algorithm to use
1132 CFStringRef ktype
= (CFStringRef
) CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
1138 if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
1139 algorithms
= CSSM_ALGID_RSA
;
1140 return errSecSuccess
;
1141 } else if(CFEqual(ktype
, kSecAttrKeyTypeECDSA
) ||
1142 CFEqual(ktype
, kSecAttrKeyTypeEC
)) {
1143 algorithms
= CSSM_ALGID_ECDSA
;
1144 return errSecSuccess
;
1145 } else if(CFEqual(ktype
, kSecAttrKeyTypeAES
)) {
1146 algorithms
= CSSM_ALGID_AES
;
1147 return errSecSuccess
;
1148 } else if(CFEqual(ktype
, kSecAttrKeyType3DES
)) {
1149 algorithms
= CSSM_ALGID_3DES
;
1150 return errSecSuccess
;
1152 return errSecUnsupportedAlgorithm
;
1158 static OSStatus
GetKeySize(CFDictionaryRef parameters
, CSSM_ALGORITHMS algorithms
, uint32
&keySizeInBits
)
1161 // get the key size and check it for validity
1162 CFTypeRef ref
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
1164 keySizeInBits
= kSecDefaultKeySize
;
1166 CFTypeID bitSizeType
= CFGetTypeID(ref
);
1167 if (bitSizeType
== CFStringGetTypeID())
1168 keySizeInBits
= ConvertCFStringToInteger((CFStringRef
) ref
);
1169 else if (bitSizeType
== CFNumberGetTypeID())
1170 CFNumberGetValue((CFNumberRef
) ref
, kCFNumberSInt32Type
, &keySizeInBits
);
1171 else return errSecParam
;
1174 switch (algorithms
) {
1175 case CSSM_ALGID_ECDSA
:
1176 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecp256r1
;
1177 if(keySizeInBits
== kSecp192r1
|| keySizeInBits
== kSecp256r1
|| keySizeInBits
== kSecp384r1
|| keySizeInBits
== kSecp521r1
) return errSecSuccess
;
1179 case CSSM_ALGID_RSA
:
1180 if(keySizeInBits
% 8) return errSecParam
;
1181 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= 2048;
1182 if(keySizeInBits
>= kSecRSAMin
&& keySizeInBits
<= kSecRSAMax
) return errSecSuccess
;
1184 case CSSM_ALGID_AES
:
1185 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecAES128
;
1186 if(keySizeInBits
== kSecAES128
|| keySizeInBits
== kSecAES192
|| keySizeInBits
== kSecAES256
) return errSecSuccess
;
1188 case CSSM_ALGID_3DES
:
1189 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSec3DES192
;
1190 if(keySizeInBits
== kSec3DES192
) return errSecSuccess
;
1209 struct ParameterAttribute
1211 const CFStringRef
*name
;
1217 static ParameterAttribute gAttributes
[] =
1224 &kSecAttrIsPermanent
,
1228 &kSecAttrApplicationTag
,
1232 &kSecAttrEffectiveKeySize
,
1236 &kSecAttrCanEncrypt
,
1240 &kSecAttrCanDecrypt
,
1261 const int kNumberOfAttributes
= sizeof(gAttributes
) / sizeof(ParameterAttribute
);
1263 static OSStatus
ScanDictionaryForParameters(CFDictionaryRef parameters
, void* attributePointers
[])
1266 for (i
= 0; i
< kNumberOfAttributes
; ++i
)
1268 // see if the corresponding tag exists in the dictionary
1269 CFTypeRef value
= CFDictionaryGetValue(parameters
, *(gAttributes
[i
].name
));
1272 switch (gAttributes
[i
].type
)
1275 // just return the value
1276 *(CFTypeRef
*) attributePointers
[i
] = value
;
1281 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1282 *(bool*) attributePointers
[i
] = CFBooleanGetValue(bRef
);
1288 CFNumberRef nRef
= (CFNumberRef
) value
;
1289 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, attributePointers
[i
]);
1296 return errSecSuccess
;
1301 static OSStatus
GetKeyParameters(CFDictionaryRef parameters
, int keySize
, bool isPublic
, CSSM_KEYUSE
&keyUse
, uint32
&attrs
, CFTypeRef
&labelRef
, CFDataRef
&applicationTagRef
)
1303 // establish default values
1305 bool isPermanent
= false;
1306 applicationTagRef
= NULL
;
1307 CFTypeRef effectiveKeySize
= NULL
;
1308 bool canDecrypt
= isPublic
? false : true;
1309 bool canEncrypt
= !canDecrypt
;
1310 bool canDerive
= true;
1311 bool canSign
= isPublic
? false : true;
1312 bool canVerify
= !canSign
;
1313 bool canUnwrap
= isPublic
? false : true;
1314 attrs
= CSSM_KEYATTR_EXTRACTABLE
;
1317 void* attributePointers
[] = {&labelRef
, &isPermanent
, &applicationTagRef
, &effectiveKeySize
, &canEncrypt
, &canDecrypt
,
1318 &canDerive
, &canSign
, &canVerify
, &canUnwrap
};
1320 // look for modifiers in the general dictionary
1321 OSStatus result
= ScanDictionaryForParameters(parameters
, attributePointers
);
1322 if (result
!= errSecSuccess
)
1327 // see if we have anything which modifies the defaults
1331 key
= kSecPublicKeyAttrs
;
1335 key
= kSecPrivateKeyAttrs
;
1338 CFTypeRef dType
= CFDictionaryGetValue(parameters
, key
);
1341 // this had better be a dictionary
1342 if (CFGetTypeID(dType
) != CFDictionaryGetTypeID())
1347 // pull any additional parameters out of this dictionary
1348 result
= ScanDictionaryForParameters((CFDictionaryRef
)dType
, attributePointers
);
1349 if (result
!= errSecSuccess
)
1355 // figure out the key usage
1359 keyUse
|= CSSM_KEYUSE_DECRYPT
;
1364 keyUse
|= CSSM_KEYUSE_ENCRYPT
;
1369 keyUse
|= CSSM_KEYUSE_DERIVE
;
1374 keyUse
|= CSSM_KEYUSE_SIGN
;
1379 keyUse
|= CSSM_KEYUSE_VERIFY
;
1384 keyUse
|= CSSM_KEYUSE_UNWRAP
;
1387 // public key is always extractable;
1388 // private key is extractable by default unless explicitly set to false
1389 CFTypeRef value
= NULL
;
1390 if (!isPublic
&& CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
) && value
)
1392 Boolean keyIsExtractable
= CFEqual(kCFBooleanTrue
, value
);
1393 if (!keyIsExtractable
)
1398 attrs
|= CSSM_KEYATTR_PERMANENT
;
1401 return errSecSuccess
;
1406 static OSStatus
MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters
,
1407 CSSM_ALGORITHMS
&algorithms
,
1408 uint32
&keySizeInBits
,
1409 CSSM_KEYUSE
&publicKeyUse
,
1410 uint32
&publicKeyAttr
,
1411 CFTypeRef
&publicKeyLabelRef
,
1412 CFDataRef
&publicKeyAttributeTagRef
,
1413 CSSM_KEYUSE
&privateKeyUse
,
1414 uint32
&privateKeyAttr
,
1415 CFTypeRef
&privateKeyLabelRef
,
1416 CFDataRef
&privateKeyAttributeTagRef
,
1417 SecAccessRef
&initialAccess
)
1421 result
= CheckAlgorithmType(parameters
, algorithms
);
1422 if (result
!= errSecSuccess
)
1427 result
= GetKeySize(parameters
, algorithms
, keySizeInBits
);
1428 if (result
!= errSecSuccess
)
1433 result
= GetKeyParameters(parameters
, keySizeInBits
, false, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1434 if (result
!= errSecSuccess
)
1439 result
= GetKeyParameters(parameters
, keySizeInBits
, true, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1440 if (result
!= errSecSuccess
)
1445 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&initialAccess
))
1447 initialAccess
= NULL
;
1449 else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess
))
1454 return errSecSuccess
;
1459 static OSStatus
SetKeyLabelAndTag(SecKeyRef keyRef
, CFTypeRef label
, CFDataRef tag
)
1461 int numToModify
= 0;
1472 if (numToModify
== 0)
1474 return errSecSuccess
;
1477 SecKeychainAttributeList attrList
;
1478 SecKeychainAttribute attributes
[numToModify
];
1485 if (CFStringGetTypeID() == CFGetTypeID(label
)) {
1486 CFStringRef label_string
= static_cast<CFStringRef
>(label
);
1487 attributes
[i
].tag
= kSecKeyPrintName
;
1488 attributes
[i
].data
= (void*) CFStringGetCStringPtr(label_string
, kCFStringEncodingUTF8
);
1489 if (NULL
== attributes
[i
].data
) {
1490 CFIndex buffer_length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string
), kCFStringEncodingUTF8
);
1491 data
= attributes
[i
].data
= malloc((size_t)buffer_length
);
1492 if (NULL
== attributes
[i
].data
) {
1493 UnixError::throwMe(ENOMEM
);
1495 if (!CFStringGetCString(label_string
, static_cast<char *>(attributes
[i
].data
), buffer_length
, kCFStringEncodingUTF8
)) {
1497 MacOSError::throwMe(errSecParam
);
1500 attributes
[i
].length
= (UInt32
)strlen(static_cast<char *>(attributes
[i
].data
));
1501 } else if (CFDataGetTypeID() == CFGetTypeID(label
)) {
1502 // 10.6 bug compatibility
1503 CFDataRef label_data
= static_cast<CFDataRef
>(label
);
1504 attributes
[i
].tag
= kSecKeyLabel
;
1505 attributes
[i
].data
= (void*) CFDataGetBytePtr(label_data
);
1506 attributes
[i
].length
= (UInt32
)CFDataGetLength(label_data
);
1508 MacOSError::throwMe(errSecParam
);
1515 attributes
[i
].tag
= kSecKeyApplicationTag
;
1516 attributes
[i
].data
= (void*) CFDataGetBytePtr(tag
);
1517 attributes
[i
].length
= (UInt32
)CFDataGetLength(tag
);
1521 attrList
.count
= numToModify
;
1522 attrList
.attr
= attributes
;
1524 OSStatus result
= SecKeychainItemModifyAttributesAndData((SecKeychainItemRef
) keyRef
, &attrList
, 0, NULL
);
1534 static CFTypeRef
GetAttributeFromParams(CFDictionaryRef parameters
, CFTypeRef attr
, CFTypeRef subParams
) {
1535 if (subParams
!= NULL
) {
1536 CFDictionaryRef subParamsDict
= (CFDictionaryRef
)CFDictionaryGetValue(parameters
, subParams
);
1537 if (subParamsDict
!= NULL
) {
1538 CFTypeRef value
= CFDictionaryGetValue(subParamsDict
, attr
);
1539 if (value
!= NULL
) {
1544 return CFDictionaryGetValue(parameters
, attr
);
1547 extern "C" OSStatus
SecKeyGeneratePair_ios(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
);
1550 /* Generate a private/public keypair. */
1552 SecKeyGeneratePairInternal(
1553 bool alwaysPermanent
,
1554 CFDictionaryRef parameters
,
1555 SecKeyRef
*publicKey
,
1556 SecKeyRef
*privateKey
)
1560 Required(parameters
);
1561 Required(publicKey
);
1562 Required(privateKey
);
1564 bool forceIOSKey
= false;
1565 if (_CFMZEnabled()) {
1566 // On Marzipan, always go iOS SecItem/SecKey route, do not drag CSSM keys in.
1569 CFTypeRef tokenID
= GetAttributeFromParams(parameters
, kSecAttrTokenID
, NULL
);
1570 CFTypeRef noLegacy
= GetAttributeFromParams(parameters
, kSecAttrNoLegacy
, NULL
);
1571 CFTypeRef sync
= GetAttributeFromParams(parameters
, kSecAttrSynchronizable
, kSecPrivateKeyAttrs
);
1572 CFTypeRef accessControl
= GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPrivateKeyAttrs
) ?:
1573 GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPublicKeyAttrs
);
1574 CFTypeRef accessGroup
= GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPrivateKeyAttrs
) ?:
1575 GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPublicKeyAttrs
);
1576 // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain).
1577 forceIOSKey
= (tokenID
!= NULL
||
1578 (noLegacy
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)noLegacy
)) ||
1579 (sync
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)sync
)) ||
1580 accessControl
!= NULL
|| (accessGroup
!= NULL
&& CFEqual(accessGroup
, kSecAttrAccessGroupToken
)));
1584 // Generate keys in iOS keychain.
1585 return SecKeyGeneratePair_ios(parameters
, publicKey
, privateKey
);
1588 CSSM_ALGORITHMS algorithms
;
1589 uint32 keySizeInBits
;
1590 CSSM_KEYUSE publicKeyUse
;
1591 uint32 publicKeyAttr
;
1592 CFTypeRef publicKeyLabelRef
;
1593 CFDataRef publicKeyAttributeTagRef
;
1594 CSSM_KEYUSE privateKeyUse
;
1595 uint32 privateKeyAttr
;
1596 CFTypeRef privateKeyLabelRef
;
1597 CFDataRef privateKeyAttributeTagRef
;
1598 SecAccessRef initialAccess
;
1599 SecKeychainRef keychain
;
1601 OSStatus result
= MakeKeyGenParametersFromDictionary(parameters
, algorithms
, keySizeInBits
, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
,
1602 publicKeyAttributeTagRef
, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
,
1605 if (result
!= errSecSuccess
) {
1609 // verify keychain parameter
1610 keychain
= (SecKeychainRef
)CFDictionaryGetValue(parameters
, kSecUseKeychain
);
1611 if (keychain
!= NULL
&& SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1615 if (alwaysPermanent
) {
1616 publicKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1617 privateKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1620 // do the key generation
1621 result
= SecKeyCreatePair(keychain
, algorithms
, keySizeInBits
, 0, publicKeyUse
, publicKeyAttr
, privateKeyUse
, privateKeyAttr
, initialAccess
, publicKey
, privateKey
);
1622 if (result
!= errSecSuccess
) {
1626 // set the label and print attributes on the keys
1627 SetKeyLabelAndTag(*publicKey
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1628 SetKeyLabelAndTag(*privateKey
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1635 SecKeyGeneratePair(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
1636 return SecKeyGeneratePairInternal(true, parameters
, publicKey
, privateKey
);
1640 SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef
*error
) {
1641 SecKeyRef privateKey
= NULL
, publicKey
= NULL
;
1642 OSStatus status
= SecKeyGeneratePairInternal(false, parameters
, &publicKey
, &privateKey
);
1643 SecError(status
, error
, CFSTR("failed to generate asymmetric keypair"));
1644 if (publicKey
!= NULL
) {
1645 CFRelease(publicKey
);
1650 OSStatus
SecKeyRawVerifyOSX(
1651 SecKeyRef key
, /* Public key */
1652 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
1653 const uint8_t *signedData
, /* signature over this data */
1654 size_t signedDataLen
, /* length of dataToSign */
1655 const uint8_t *sig
, /* signature */
1658 return SecKeyRawVerify(key
,padding
,signedData
,signedDataLen
,sig
,sigLen
);
1666 utilGetStringFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, CFTypeRef defaultValue
)
1668 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1669 if (value
!= NULL
) return value
;
1670 return defaultValue
;
1674 utilGetNumberFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t defaultValue
)
1676 uint32_t integerValue
;
1677 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1678 if (value
!= NULL
) {
1679 CFNumberRef nRef
= (CFNumberRef
) value
;
1680 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, &integerValue
);
1681 return integerValue
;
1683 return defaultValue
;
1687 utilGetMaskValFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t maskValue
)
1689 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1690 if (value
!= NULL
) {
1691 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1692 if(CFBooleanGetValue(bRef
)) return maskValue
;
1698 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters
, CSSM_ALGORITHMS
*algorithm
, uint32
*keySizeInBits
, CSSM_KEYUSE
*keyUsage
, CSSM_KEYCLASS
*keyClass
)
1700 CFTypeRef algorithmDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeAES
);
1701 CFTypeRef keyClassDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1703 if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeAES
)) {
1704 *algorithm
= CSSM_ALGID_AES
;
1705 *keySizeInBits
= 128;
1706 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1707 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDES
)) {
1708 *algorithm
= CSSM_ALGID_DES
;
1709 *keySizeInBits
= 128;
1710 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1711 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyType3DES
)) {
1712 *algorithm
= CSSM_ALGID_3DES_3KEY_EDE
;
1713 *keySizeInBits
= 128;
1714 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1715 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC4
)) {
1716 *algorithm
= CSSM_ALGID_RC4
;
1717 *keySizeInBits
= 128;
1718 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1719 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC2
)) {
1720 *algorithm
= CSSM_ALGID_RC2
;
1721 *keySizeInBits
= 128;
1722 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1723 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeCAST
)) {
1724 *algorithm
= CSSM_ALGID_CAST
;
1725 *keySizeInBits
= 128;
1726 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1727 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRSA
)) {
1728 *algorithm
= CSSM_ALGID_RSA
;
1729 *keySizeInBits
= 128;
1730 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1731 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDSA
)) {
1732 *algorithm
= CSSM_ALGID_DSA
;
1733 *keySizeInBits
= 128;
1734 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1735 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeECDSA
) ||
1736 CFEqual(algorithmDictValue
, kSecAttrKeyTypeEC
)) {
1737 *algorithm
= CSSM_ALGID_ECDSA
;
1738 *keySizeInBits
= 128;
1739 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1741 *algorithm
= CSSM_ALGID_AES
;
1742 *keySizeInBits
= 128;
1743 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1746 if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPublic
)) {
1747 *keyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
1748 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPrivate
)) {
1749 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1750 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassSymmetric
)) {
1751 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1754 *keySizeInBits
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, *keySizeInBits
);
1755 *keyUsage
= utilGetMaskValFromCFDict(parameters
, kSecAttrCanEncrypt
, CSSM_KEYUSE_ENCRYPT
) |
1756 utilGetMaskValFromCFDict(parameters
, kSecAttrCanDecrypt
, CSSM_KEYUSE_DECRYPT
) |
1757 utilGetMaskValFromCFDict(parameters
, kSecAttrCanWrap
, CSSM_KEYUSE_WRAP
) |
1758 utilGetMaskValFromCFDict(parameters
, kSecAttrCanUnwrap
, CSSM_KEYUSE_UNWRAP
);
1761 if(*keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
|| *keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
) {
1762 *keyUsage
|= utilGetMaskValFromCFDict(parameters
, kSecAttrCanSign
, CSSM_KEYUSE_SIGN
) |
1763 utilGetMaskValFromCFDict(parameters
, kSecAttrCanVerify
, CSSM_KEYUSE_VERIFY
);
1766 if(*keyUsage
== 0) {
1767 switch (*keyClass
) {
1768 case CSSM_KEYCLASS_PRIVATE_KEY
:
1769 *keyUsage
= CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
;
1771 case CSSM_KEYCLASS_PUBLIC_KEY
:
1772 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
;
1775 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
;
1782 utilCopyDefaultKeyLabel(void)
1784 // generate a default label from the current date
1785 CFDateRef dateNow
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent());
1786 CFStringRef defaultLabel
= CFCopyDescription(dateNow
);
1789 return defaultLabel
;
1793 SecKeyGenerateSymmetric(CFDictionaryRef parameters
, CFErrorRef
*error
)
1795 OSStatus result
= errSecParam
; // default result for an early exit
1796 SecKeyRef key
= NULL
;
1797 SecKeychainRef keychain
= NULL
;
1798 SecAccessRef access
;
1800 CFStringRef appLabel
;
1802 CFStringRef dateLabel
= NULL
;
1804 CSSM_ALGORITHMS algorithm
;
1805 uint32 keySizeInBits
;
1806 CSSM_KEYUSE keyUsage
;
1807 uint32 keyAttr
= CSSM_KEYATTR_RETURN_DEFAULT
;
1808 CSSM_KEYCLASS keyClass
;
1810 Boolean isPermanent
;
1811 Boolean isExtractable
;
1813 // verify keychain parameter
1814 if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
))
1816 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1823 // verify permanent parameter
1824 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsPermanent
, (const void **)&value
))
1825 isPermanent
= false;
1826 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1829 isPermanent
= CFEqual(kCFBooleanTrue
, value
);
1831 if (keychain
== NULL
) {
1832 // no keychain was specified, so use the default keychain
1833 result
= SecKeychainCopyDefault(&keychain
);
1835 keyAttr
|= CSSM_KEYATTR_PERMANENT
;
1838 // verify extractable parameter
1839 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
))
1840 isExtractable
= true; // default to extractable if value not specified
1841 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1844 isExtractable
= CFEqual(kCFBooleanTrue
, value
);
1846 keyAttr
|= CSSM_KEYATTR_EXTRACTABLE
;
1848 // verify access parameter
1849 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&access
))
1851 else if (SecAccessGetTypeID() != CFGetTypeID(access
))
1854 // verify label parameter
1855 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrLabel
, (const void **)&label
))
1856 label
= (dateLabel
= utilCopyDefaultKeyLabel()); // no label provided, so use default
1857 else if (CFStringGetTypeID() != CFGetTypeID(label
))
1860 // verify application label parameter
1861 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationLabel
, (const void **)&appLabel
))
1862 appLabel
= (dateLabel
) ? dateLabel
: (dateLabel
= utilCopyDefaultKeyLabel());
1863 else if (CFStringGetTypeID() != CFGetTypeID(appLabel
))
1866 // verify application tag parameter
1867 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationTag
, (const void **)&appTag
))
1869 else if (CFStringGetTypeID() != CFGetTypeID(appTag
))
1872 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1875 // the generated key will not be stored in any keychain
1876 result
= SecKeyGenerate(keychain
, algorithm
, keySizeInBits
, 0, keyUsage
, keyAttr
, access
, &key
);
1879 // we can set the label attributes on the generated key if it's a keychain item
1880 size_t labelBufLen
= (label
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label
), kCFStringEncodingUTF8
) + 1 : 1;
1881 char *labelBuf
= (char *)malloc(labelBufLen
);
1882 size_t appLabelBufLen
= (appLabel
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel
), kCFStringEncodingUTF8
) + 1 : 1;
1883 char *appLabelBuf
= (char *)malloc(appLabelBufLen
);
1884 size_t appTagBufLen
= (appTag
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag
), kCFStringEncodingUTF8
) + 1 : 1;
1885 char *appTagBuf
= (char *)malloc(appTagBufLen
);
1887 if (!label
|| !CFStringGetCString(label
, labelBuf
, labelBufLen
-1, kCFStringEncodingUTF8
))
1889 if (!appLabel
|| !CFStringGetCString(appLabel
, appLabelBuf
, appLabelBufLen
-1, kCFStringEncodingUTF8
))
1891 if (!appTag
|| !CFStringGetCString(appTag
, appTagBuf
, appTagBufLen
-1, kCFStringEncodingUTF8
))
1894 SecKeychainAttribute attrs
[] = {
1895 { kSecKeyPrintName
, (UInt32
)strlen(labelBuf
), (char *)labelBuf
},
1896 { kSecKeyLabel
, (UInt32
)strlen(appLabelBuf
), (char *)appLabelBuf
},
1897 { kSecKeyApplicationTag
, (UInt32
)strlen(appTagBuf
), (char *)appTagBuf
} };
1898 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
1899 if (!appTag
) --attributes
.count
;
1901 result
= SecKeyGenerateWithAttributes(&attributes
,
1902 keychain
, algorithm
, keySizeInBits
, 0,
1903 keyUsage
, keyAttr
, access
, &key
);
1911 if (result
&& error
) {
1912 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, result
, NULL
);
1915 CFRelease(dateLabel
);
1917 CFRelease(keychain
);
1925 SecKeyCreateFromData(CFDictionaryRef parameters
, CFDataRef keyData
, CFErrorRef
*error
)
1927 CSSM_ALGORITHMS algorithm
;
1928 uint32 keySizeInBits
;
1929 CSSM_KEYUSE keyUsage
;
1930 CSSM_KEYCLASS keyClass
;
1933 if(keyData
== NULL
|| CFDataGetLength(keyData
) == 0){
1934 MacOSError::throwMe(errSecUnsupportedKeySize
);
1937 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1939 CSSM_CSP_HANDLE cspHandle
= cuCspStartup(CSSM_FALSE
); // TRUE => CSP, FALSE => CSPDL
1941 SecKeyImportExportParameters iparam
;
1942 memset(&iparam
, 0, sizeof(iparam
));
1943 iparam
.keyUsage
= keyUsage
;
1945 CFRef
<CFDataRef
> data
;
1946 SecExternalItemType itype
;
1948 case CSSM_KEYCLASS_PRIVATE_KEY
:
1949 itype
= kSecItemTypePrivateKey
;
1951 case CSSM_KEYCLASS_PUBLIC_KEY
: {
1952 itype
= kSecItemTypePublicKey
;
1953 // Public key import expects public key in SubjPublicKey X509 format. We want to accept both bare and x509 format,
1954 // so we have to detect bare format here and extend to full X509 if detected.
1955 data
.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm
, keySizeInBits
, keyData
));
1958 case CSSM_KEYCLASS_SESSION_KEY
:
1959 itype
= kSecItemTypeSessionKey
;
1962 itype
= kSecItemTypeUnknown
;
1966 CFMutableArrayRef ka
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1967 // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful.
1968 crtn
= impExpImportRawKey(data
? CFDataRef(data
) : keyData
, kSecFormatUnknown
, itype
, algorithm
, NULL
, cspHandle
, 0, NULL
, NULL
, ka
);
1969 if (crtn
== CSSM_OK
&& CFArrayGetCount((CFArrayRef
)ka
)) {
1970 SecKeyRef sk
= (SecKeyRef
)CFArrayGetValueAtIndex((CFArrayRef
)ka
, 0);
1977 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, crtn
? crtn
: CSSM_ERRCODE_INTERNAL_ERROR
, NULL
);
1985 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable
, dispatch_queue_t deliveryQueue
,
1986 SecKeyGeneratePairBlock result
)
1988 CFDictionaryRef parameters
= CFDictionaryCreateCopy(NULL
, parametersWhichMightBeMutiable
);
1989 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
1990 SecKeyRef publicKey
= NULL
;
1991 SecKeyRef privateKey
= NULL
;
1992 OSStatus status
= SecKeyGeneratePair(parameters
, &publicKey
, &privateKey
);
1993 dispatch_async(deliveryQueue
, ^{
1994 CFErrorRef error
= NULL
;
1995 if (errSecSuccess
!= status
) {
1996 error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, NULL
);
1998 result(publicKey
, privateKey
, error
);
2003 CFRelease(publicKey
);
2006 CFRelease(privateKey
);
2008 CFRelease(parameters
);
2013 static inline void utilClearAndFree(void *p
, size_t len
) {
2015 if(len
) bzero(p
, len
);
2021 SecKeyDeriveFromPassword(CFStringRef password
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2023 CCPBKDFAlgorithm algorithm
;
2024 CFIndex passwordLen
= 0;
2025 CFDataRef keyData
= NULL
;
2026 char *thePassword
= NULL
;
2027 uint8_t *salt
= NULL
;
2028 uint8_t *derivedKey
= NULL
;
2029 size_t saltLen
= 0, derivedKeyLen
= 0;
2031 CFDataRef saltDictValue
, algorithmDictValue
;
2032 SecKeyRef retval
= NULL
;
2034 /* Pick Values from parameters */
2036 if((saltDictValue
= (CFDataRef
) CFDictionaryGetValue(parameters
, kSecAttrSalt
)) == NULL
) {
2038 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecMissingAlgorithmParms
, NULL
);
2043 derivedKeyLen
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, 128);
2044 // This value come in bits but the rest of the code treats it as bytes
2047 algorithmDictValue
= (CFDataRef
) utilGetStringFromCFDict(parameters
, kSecAttrPRF
, kSecAttrPRFHmacAlgSHA256
);
2049 rounds
= utilGetNumberFromCFDict(parameters
, kSecAttrRounds
, 0);
2051 /* Convert any remaining parameters and get the password bytes */
2053 saltLen
= CFDataGetLength(saltDictValue
);
2054 if((salt
= (uint8_t *) malloc(saltLen
)) == NULL
) {
2056 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2061 CFDataGetBytes(saltDictValue
, CFRangeMake(0, saltLen
), (UInt8
*) salt
);
2063 passwordLen
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1;
2064 if((thePassword
= (char *) malloc(passwordLen
)) == NULL
) {
2066 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2070 CFStringGetBytes(password
, CFRangeMake(0, CFStringGetLength(password
)), kCFStringEncodingUTF8
, '?', FALSE
, (UInt8
*)thePassword
, passwordLen
, &passwordLen
);
2072 if((derivedKey
= (uint8_t *) malloc(derivedKeyLen
)) == NULL
) {
2074 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2079 if(algorithmDictValue
== NULL
) {
2080 algorithm
= kCCPRFHmacAlgSHA1
; /* default */
2081 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA1
)) {
2082 algorithm
= kCCPRFHmacAlgSHA1
;
2083 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA224
)) {
2084 algorithm
= kCCPRFHmacAlgSHA224
;
2085 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA256
)) {
2086 algorithm
= kCCPRFHmacAlgSHA256
;
2087 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA384
)) {
2088 algorithm
= kCCPRFHmacAlgSHA384
;
2089 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA512
)) {
2090 algorithm
= kCCPRFHmacAlgSHA512
;
2093 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidAlgorithmParms
, NULL
);
2099 rounds
= 33333; // we need to pass back a consistent value since there's no way to record the round count.
2102 if(CCKeyDerivationPBKDF(kCCPBKDF2
, thePassword
, passwordLen
, salt
, saltLen
, algorithm
, rounds
, derivedKey
, derivedKeyLen
)) {
2104 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2109 if((keyData
= CFDataCreate(NULL
, derivedKey
, derivedKeyLen
)) != NULL
) {
2110 retval
= SecKeyCreateFromData(parameters
, keyData
, error
);
2114 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2119 utilClearAndFree(salt
, saltLen
);
2120 utilClearAndFree(thePassword
, passwordLen
);
2121 utilClearAndFree(derivedKey
, derivedKeyLen
);
2126 SecKeyWrapSymmetric(SecKeyRef keyToWrap
, SecKeyRef wrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2129 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);
2135 SecKeyUnwrapSymmetric(CFDataRef
*keyToUnwrap
, SecKeyRef unwrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2138 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);