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 "SecBridge.h"
40 #include <security_keychain/Access.h>
41 #include <security_keychain/Keychains.h>
42 #include <security_keychain/KeyItem.h>
46 #include <security_cdsa_utils/cuCdsaUtils.h>
47 #include <security_cdsa_client/wrapkey.h>
48 #include <security_cdsa_client/genkey.h>
49 #include <security_cdsa_client/signclient.h>
50 #include <security_cdsa_client/cryptoclient.h>
52 #include "SecImportExportCrypto.h"
55 SecCDSAKeyInit(SecKeyRef key
, const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) {
56 key
->key
= const_cast<KeyItem
*>(reinterpret_cast<const KeyItem
*>(keyData
));
57 key
->key
->initializeWithSecKeyRef(key
);
58 key
->credentialType
= kSecCredentialTypeDefault
;
63 SecCDSAKeyDestroy(SecKeyRef keyRef
) {
64 // Note: If this key is holding the last strong reference to its keychain, the keychain will be released during this operation.
65 // If we hold the keychain's mutex (the key's 'mutexForObject') during this destruction, pthread gets upset.
66 // Hold a reference to the keychain (if it exists) until after we release the keychain's mutex.
68 KeyItem
*keyItem
= keyRef
->key
;
69 if (keyItem
== NULL
) {
70 // KeyImpl::attachSecKeyRef disconnected us from KeyItem instance, there is nothing to do for us.
74 Keychain kc
= keyItem
->keychain();
77 StMaybeLock
<Mutex
> _(keyItem
->getMutexForObject());
78 keyItem
= keyRef
->key
;
79 if (keyItem
== NULL
) {
80 // 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.
84 keyItem
->aboutToDestruct();
88 (void) kc
; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain.
92 SecCDSAKeyGetBlockSize(SecKeyRef key
) {
94 CFErrorRef
*error
= NULL
;
95 BEGIN_SECKEYAPI(size_t,0)
97 const CssmKey::Header keyHeader
= key
->key
->unverifiedKeyHeader();
98 switch(keyHeader
.algorithm())
102 result
= keyHeader
.LogicalKeySizeInBits
/ 8;
104 case CSSM_ALGID_ECDSA
:
106 /* Block size is up to 9 bytes of DER encoding for sequence of 2 integers,
107 * plus both coordinates for the point used */
108 #define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8)
109 #define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1)
110 size_t coordSize
= ECDSA_MAX_COORD_SIZE_IN_BYTES(keyHeader
.LogicalKeySizeInBits
);
111 assert(coordSize
< 256); /* size must fit in a byte for DER */
112 size_t coordDERLen
= (coordSize
> 127) ? 2 : 1;
113 size_t coordLen
= 1 + coordDERLen
+ coordSize
;
115 size_t pointSize
= 2 * coordLen
;
116 assert(pointSize
< 256); /* size must fit in a byte for DER */
117 size_t pointDERLen
= (pointSize
> 127) ? 2 : 1;
118 size_t pointLen
= 1 + pointDERLen
+ pointSize
;
124 result
= 16; /* all AES keys use 128-bit blocks */
127 case CSSM_ALGID_3DES_3KEY
:
128 result
= 8; /* all DES keys use 64-bit blocks */
131 assert(0); /* some other key algorithm */
132 result
= 16; /* FIXME: revisit this */
140 SecCDSAKeyGetAlgorithmId(SecKeyRef key
) {
142 CFErrorRef
*error
= NULL
;
143 BEGIN_SECKEYAPI(CFIndex
, 0)
145 result
= kSecNullAlgorithmID
;
146 switch (key
->key
->unverifiedKeyHeader().AlgorithmId
) {
148 result
= kSecRSAAlgorithmID
;
151 result
= kSecDSAAlgorithmID
;
153 case CSSM_ALGID_ECDSA
:
154 result
= kSecECDSAAlgorithmID
;
157 assert(0); /* other algorithms TBA */
163 static CFDataRef
SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(CFDataRef pubKeyInfo
) {
164 // First of all, consider x509 format and try to strip SubjPubKey envelope. If it fails, do not panic
165 // and export data as is.
166 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(pubKeyInfo
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(pubKeyInfo
)) }, pubKeyItem
;
168 DERSubjPubKeyInfo subjPubKey
;
169 if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
,
170 DERSubjPubKeyInfoItemSpecs
,
171 &subjPubKey
, sizeof(subjPubKey
)) == DR_Success
&&
172 DERParseBitString(&subjPubKey
.pubKey
, &pubKeyItem
, &numUnused
) == DR_Success
) {
173 return CFDataCreate(kCFAllocatorDefault
, pubKeyItem
.data
, pubKeyItem
.length
);
176 return CFDataRef(CFRetain(pubKeyInfo
));
179 static CFDataRef
SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(CSSM_ALGORITHMS algorithm
, uint32 keySizeInBits
, CFDataRef pubKeyInfo
) {
180 // First check, whether X509 pubkeyinfo is already present. If not, add it according to the key type.
181 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(pubKeyInfo
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(pubKeyInfo
)) };
182 DERSubjPubKeyInfo subjPubKey
;
183 if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
,
184 DERSubjPubKeyInfoItemSpecs
,
185 &subjPubKey
, sizeof(subjPubKey
)) == DR_Success
) {
186 return CFDataRef(CFRetain(pubKeyInfo
));
189 // We have always size rounded to full bytes so bitstring encodes leading 00.
190 CFRef
<CFMutableDataRef
> bitStringPubKey
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
191 CFDataSetLength(bitStringPubKey
, 1);
192 CFDataAppendBytes(bitStringPubKey
, CFDataGetBytePtr(pubKeyInfo
), CFDataGetLength(pubKeyInfo
));
193 subjPubKey
.pubKey
.data
= static_cast<DERByte
*>(const_cast<UInt8
*>(CFDataGetBytePtr(bitStringPubKey
)));
194 subjPubKey
.pubKey
.length
= CFDataGetLength(bitStringPubKey
);
196 // Encode algId according to algorithm used.
197 static const DERByte oidRSA
[] = {
198 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
200 static const DERByte oidECsecp256
[] = {
201 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
203 static const DERByte oidECsecp384
[] = {
204 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22,
206 static const DERByte oidECsecp521
[] = {
207 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23,
209 subjPubKey
.algId
.length
= 0;
210 if (algorithm
== CSSM_ALGID_RSA
) {
211 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidRSA
);
212 subjPubKey
.algId
.length
= sizeof(oidRSA
);
213 } else if (algorithm
== CSSM_ALGID_ECDSA
) {
214 if (keySizeInBits
== 256) {
215 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidECsecp256
);
216 subjPubKey
.algId
.length
= sizeof(oidECsecp256
);
217 } else if (keySizeInBits
== 384) {
218 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidECsecp384
);
219 subjPubKey
.algId
.length
= sizeof(oidECsecp384
);
220 } if (keySizeInBits
== 521) {
221 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidECsecp521
);
222 subjPubKey
.algId
.length
= sizeof(oidECsecp521
);
225 DERSize size
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
,
226 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
);
227 CFRef
<CFMutableDataRef
> keyData
= CFDataCreateMutable(kCFAllocatorDefault
, size
);
228 CFDataSetLength(keyData
, size
);
229 if (DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
,
230 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
,
231 static_cast<DERByte
*>(CFDataGetMutableBytePtr(keyData
)), &size
) == DR_Success
) {
232 CFDataSetLength(keyData
, size
);
237 return keyData
.yield();
240 static OSStatus
SecCDSAKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
*serialization
) {
242 CFErrorRef
*error
= NULL
;
243 BEGIN_SECKEYAPI(OSStatus
, errSecSuccess
)
245 const CssmKey::Header
&header
= key
->key
->key().header();
246 switch (header
.algorithm()) {
247 case CSSM_ALGID_RSA
: {
248 switch (header
.keyClass()) {
249 case CSSM_KEYCLASS_PRIVATE_KEY
: {
250 CFRef
<CFDataRef
> privKeyData
;
251 result
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, privKeyData
.take());
252 if (result
== errSecSuccess
) {
253 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(privKeyData
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(privKeyData
)) };
254 DERRSAKeyPair keyPair
;
255 if (DERParseSequence(&keyItem
, DERNumRSAKeyPairItemSpecs
, DERRSAKeyPairItemSpecs
,
256 &keyPair
, sizeof(keyPair
)) == DR_Success
) {
257 DERRSAPubKeyPKCS1 pubKey
= { keyPair
.n
, keyPair
.e
};
258 DERSize size
= DERLengthOfEncodedSequence(ASN1_SEQUENCE
, &pubKey
,
259 DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
);
260 CFRef
<CFMutableDataRef
> keyData
= CFDataCreateMutable(kCFAllocatorDefault
, size
);
261 CFDataSetLength(keyData
, size
);
262 UInt8
*data
= CFDataGetMutableBytePtr(keyData
);
263 if (DEREncodeSequence(ASN1_SEQUENCE
, &pubKey
,
264 DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
,
265 data
, &size
) == DR_Success
) {
266 CFDataSetLength(keyData
, size
);
267 *data
= ONE_BYTE_ASN1_CONSTR_SEQUENCE
;
268 *serialization
= keyData
.yield();
270 *serialization
= NULL
;
271 result
= errSecParam
;
277 case CSSM_KEYCLASS_PUBLIC_KEY
:
278 result
= SecItemExport(key
, kSecFormatBSAFE
, 0, NULL
, serialization
);
283 case CSSM_ALGID_ECDSA
: {
284 *serialization
= NULL
;
285 CFRef
<CFDataRef
> tempPublicData
;
286 result
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, tempPublicData
.take());
287 if (result
== errSecSuccess
) {
288 *serialization
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(tempPublicData
);
293 result
= errSecUnimplemented
;
304 static const DERItemSpec DERECPrivateKeyItemSpecs
[] =
309 { DER_OFFSET(DERECPrivateKey
, privateKey
),
311 DER_DEC_NO_OPTS
| DER_ENC_NO_OPTS
},
313 ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0,
314 DER_DEC_SKIP
| DER_ENC_NO_OPTS
},
315 { DER_OFFSET(DERECPrivateKey
, publicKey
),
316 ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 1,
317 DER_DEC_NO_OPTS
| DER_ENC_SIGNED_INT
},
319 static const DERSize DERNumECPrivateKeyItemSpecs
=
320 sizeof(DERECPrivateKeyItemSpecs
) / sizeof(DERItemSpec
);
324 } DERECPrivateKeyPublicKey
;
326 static const DERItemSpec DERECPrivateKeyPublicKeyItemSpecs
[] =
328 { DER_OFFSET(DERECPrivateKeyPublicKey
, bitString
),
330 DER_DEC_NO_OPTS
| DER_ENC_NO_OPTS
},
332 static const DERSize DERNumECPrivateKeyPublicKeyItemSpecs
=
333 sizeof(DERECPrivateKeyPublicKeyItemSpecs
) / sizeof(DERItemSpec
);
336 SecCDSAKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef
*error
) {
338 BEGIN_SECKEYAPI(CFDataRef
, NULL
)
341 const CssmKey::Header header
= key
->key
->unverifiedKeyHeader();
342 CFRef
<CFDataRef
> keyData
;
343 switch (header
.algorithm()) {
345 MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()));
347 case CSSM_ALGID_ECDSA
: {
348 MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()));
349 if (header
.keyClass() == CSSM_KEYCLASS_PRIVATE_KEY
) {
350 // Convert DER format into x9.63 format, which is expected for exported key.
351 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(keyData
), int_cast
<CFIndex
, DERSize
>(CFDataGetLength(keyData
)) };
352 DERECPrivateKey privateKey
;
353 DERECPrivateKeyPublicKey privateKeyPublicKey
;
356 if (DERParseSequence(&keyItem
, DERNumECPrivateKeyItemSpecs
, DERECPrivateKeyItemSpecs
,
357 &privateKey
, sizeof(privateKey
)) == DR_Success
&&
358 DERParseSequenceContent(&privateKey
.publicKey
, DERNumECPrivateKeyPublicKeyItemSpecs
,
359 DERECPrivateKeyPublicKeyItemSpecs
,
360 &privateKeyPublicKey
, sizeof(privateKeyPublicKey
)) == DR_Success
&&
361 DERParseBitString(&privateKeyPublicKey
.bitString
, &pubKeyItem
, &numUnused
) == DR_Success
) {
362 CFRef
<CFMutableDataRef
> key
= CFDataCreateMutable(kCFAllocatorDefault
,
363 pubKeyItem
.length
+ privateKey
.privateKey
.length
);
364 CFDataSetLength(key
, pubKeyItem
.length
+ privateKey
.privateKey
.length
);
365 CFDataReplaceBytes(key
, CFRangeMake(0, pubKeyItem
.length
), pubKeyItem
.data
, pubKeyItem
.length
);
366 CFDataReplaceBytes(key
, CFRangeMake(pubKeyItem
.length
, privateKey
.privateKey
.length
),
367 privateKey
.privateKey
.data
, privateKey
.privateKey
.length
);
368 keyData
= key
.as
<CFDataRef
>();
374 MacOSError::throwMe(errSecUnimplemented
);
377 if (header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
) {
378 result
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(keyData
);
380 result
= keyData
.yield();
386 static CFDataRef
SecCDSAKeyCopyLabel(SecKeyRef key
) {
387 CFDataRef label
= NULL
;
388 if (key
->key
->isPersistent()) {
389 UInt32 tags
[] = { kSecKeyLabel
}, formats
[] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB
};
390 SecKeychainAttributeInfo info
= { 1, tags
, formats
};
391 SecKeychainAttributeList
*list
= NULL
;
392 key
->key
->getAttributesAndData(&info
, NULL
, &list
, NULL
, NULL
);
393 if (list
->count
== 1) {
394 SecKeychainAttribute
*attr
= list
->attr
;
395 label
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)attr
->data
, (CFIndex
)attr
->length
);
397 key
->key
->freeAttributesAndData(list
, NULL
);
402 static CFDictionaryRef
403 SecCDSAKeyCopyAttributeDictionary(SecKeyRef key
) {
405 CFErrorRef
*error
= NULL
;
406 BEGIN_SECKEYAPI(CFDictionaryRef
, NULL
)
408 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
409 &kCFTypeDictionaryValueCallBacks
);
411 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
413 const CssmKey::Header header
= key
->key
->unverifiedKeyHeader();
414 CFIndex sizeValue
= header
.LogicalKeySizeInBits
;
415 CFRef
<CFNumberRef
> sizeInBits
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &sizeValue
);
416 CFDictionarySetValue(dict
, kSecAttrKeySizeInBits
, sizeInBits
);
417 CFDictionarySetValue(dict
, kSecAttrEffectiveKeySize
, sizeInBits
);
419 CFRef
<CFDataRef
> label
= SecCDSAKeyCopyLabel(key
);
421 // For floating keys, calculate label as SHA1 of pubkey bytes.
422 CFRef
<CFDataRef
> pubKeyBlob
;
423 if (SecCDSAKeyCopyPublicBytes(key
, pubKeyBlob
.take()) == errSecSuccess
) {
424 uint8_t pubKeyHash
[CC_SHA1_DIGEST_LENGTH
];
425 CC_SHA1(CFDataGetBytePtr(pubKeyBlob
), CC_LONG(CFDataGetLength(pubKeyBlob
)), pubKeyHash
);
426 label
.take(CFDataCreate(kCFAllocatorDefault
, pubKeyHash
, sizeof(pubKeyHash
)));
431 CFDictionarySetValue(dict
, kSecAttrApplicationLabel
, label
);
434 CSSM_KEYATTR_FLAGS attrs
= header
.attributes();
435 CFDictionarySetValue(dict
, kSecAttrIsPermanent
, (attrs
& CSSM_KEYATTR_PERMANENT
) ? kCFBooleanTrue
: kCFBooleanFalse
);
436 CFDictionarySetValue(dict
, kSecAttrIsPrivate
, (attrs
& CSSM_KEYATTR_PRIVATE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
437 CFDictionarySetValue(dict
, kSecAttrIsModifiable
, (attrs
& CSSM_KEYATTR_MODIFIABLE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
438 CFDictionarySetValue(dict
, kSecAttrIsSensitive
, (attrs
& CSSM_KEYATTR_SENSITIVE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
439 CFDictionarySetValue(dict
, kSecAttrIsExtractable
, (attrs
& CSSM_KEYATTR_EXTRACTABLE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
440 CFDictionarySetValue(dict
, kSecAttrWasAlwaysSensitive
, (attrs
& CSSM_KEYATTR_ALWAYS_SENSITIVE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
441 CFDictionarySetValue(dict
, kSecAttrWasNeverExtractable
, (attrs
& CSSM_KEYATTR_NEVER_EXTRACTABLE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
443 CFDictionarySetValue(dict
, kSecAttrCanEncrypt
, (header
.useFor(CSSM_KEYUSE_ENCRYPT
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
444 CFDictionarySetValue(dict
, kSecAttrCanDecrypt
, (header
.useFor(CSSM_KEYUSE_DECRYPT
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
445 CFDictionarySetValue(dict
, kSecAttrCanSign
, (header
.useFor(CSSM_KEYUSE_SIGN
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
446 CFDictionarySetValue(dict
, kSecAttrCanVerify
, (header
.useFor(CSSM_KEYUSE_VERIFY
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
447 CFDictionarySetValue(dict
, kSecAttrCanSignRecover
, (header
.useFor(CSSM_KEYUSE_SIGN_RECOVER
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
448 CFDictionarySetValue(dict
, kSecAttrCanVerifyRecover
, (header
.useFor(CSSM_KEYUSE_VERIFY_RECOVER
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
449 CFDictionarySetValue(dict
, kSecAttrCanWrap
, (header
.useFor(CSSM_KEYUSE_WRAP
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
450 CFDictionarySetValue(dict
, kSecAttrCanUnwrap
, (header
.useFor(CSSM_KEYUSE_UNWRAP
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
451 CFDictionarySetValue(dict
, kSecAttrCanDerive
, (header
.useFor(CSSM_KEYUSE_DERIVE
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
453 switch (header
.keyClass()) {
454 case CSSM_KEYCLASS_PUBLIC_KEY
:
455 CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
457 case CSSM_KEYCLASS_PRIVATE_KEY
:
458 CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
462 switch (header
.algorithm()) {
464 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
466 case CSSM_ALGID_ECDSA
:
467 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeECDSA
);
471 CFRef
<CFDataRef
> keyData
;
472 if (SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()) == errSecSuccess
) {
473 CFDictionarySetValue(dict
, kSecValueData
, keyData
);
476 if (header
.algorithm() == CSSM_ALGID_RSA
&& header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
&&
477 header
.blobType() == CSSM_KEYBLOB_RAW
) {
478 const CssmData
&keyData
= key
->key
->key()->keyData();
479 DERItem keyItem
= { static_cast<DERByte
*>(keyData
.data()), keyData
.length() };
480 DERRSAPubKeyPKCS1 decodedKey
;
481 if (DERParseSequence(&keyItem
, DERNumRSAPubKeyPKCS1ItemSpecs
,
482 DERRSAPubKeyPKCS1ItemSpecs
,
483 &decodedKey
, sizeof(decodedKey
)) == DR_Success
) {
484 CFRef
<CFDataRef
> modulus
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.modulus
.data
,
485 decodedKey
.modulus
.length
);
486 CFDictionarySetValue(dict
, CFSTR("_rsam"), modulus
);
487 CFRef
<CFDataRef
> exponent
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.pubExponent
.data
,
488 decodedKey
.pubExponent
.length
);
489 CFDictionarySetValue(dict
, CFSTR("_rsae"), exponent
);
498 #pragma clang diagnostic push
499 #pragma clang diagnostic ignored "-Wunused-const-variable"
500 static CSSM_DB_NAME_ATTR(kInfoKeyLabel
, kSecKeyLabel
, (char*) "Label", 0, NULL
, BLOB
);
501 #pragma clang diagnostic pop
503 static SecKeyRef
SecCDSAKeyCopyPublicKey(SecKeyRef privateKey
) {
505 BEGIN_SECKEYAPI(SecKeyRef
, NULL
)
508 KeyItem
*key
= privateKey
->key
;
509 CFRef
<CFDataRef
> label
= SecCDSAKeyCopyLabel(privateKey
);
511 // Lookup public key in the database.
512 DbUniqueRecord uniqueId
;
513 SSDb
ssDb(dynamic_cast<SSDbImpl
*>(&(*key
->keychain()->database())));
514 SSDbCursor
dbCursor(ssDb
, 1);
515 dbCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
);
516 dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, CssmData(CFDataRef(label
)));
517 if (dbCursor
->next(NULL
, NULL
, uniqueId
)) {
518 Item publicKey
= key
->keychain()->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, uniqueId
);
519 result
= reinterpret_cast<SecKeyRef
>(publicKey
->handle());
523 if (result
== NULL
&& key
->publicKey()) {
524 KeyItem
*publicKey
= new KeyItem(key
->publicKey());
525 result
= reinterpret_cast<SecKeyRef
>(publicKey
->handle());
531 static KeyItem
*SecCDSAKeyPrepareParameters(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
,
532 CSSM_ALGORITHMS
&baseAlgorithm
, CSSM_ALGORITHMS
&secondaryAlgorithm
,
533 CSSM_ALGORITHMS
&paddingAlgorithm
, CFIndex
&inputSizeLimit
) {
534 KeyItem
*keyItem
= key
->key
;
535 CSSM_KEYCLASS keyClass
= keyItem
->key()->header().keyClass();
536 baseAlgorithm
= keyItem
->key()->header().algorithm();
537 switch (baseAlgorithm
) {
539 if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeSign
) ||
540 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeVerify
)) {
541 if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureRaw
)) {
542 secondaryAlgorithm
= CSSM_ALGID_NONE
;
543 paddingAlgorithm
= CSSM_PADDING_NONE
;
545 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
)) {
546 secondaryAlgorithm
= CSSM_ALGID_NONE
;
547 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
548 inputSizeLimit
= -11;
549 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
)) {
550 secondaryAlgorithm
= CSSM_ALGID_SHA1
;
551 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
553 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
)) {
554 secondaryAlgorithm
= CSSM_ALGID_SHA224
;
555 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
556 inputSizeLimit
= 224 / 8;
557 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
)) {
558 secondaryAlgorithm
= CSSM_ALGID_SHA256
;
559 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
560 inputSizeLimit
= 256 / 8;
561 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
)) {
562 secondaryAlgorithm
= CSSM_ALGID_SHA384
;
563 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
564 inputSizeLimit
= 384 / 8;
565 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
)) {
566 secondaryAlgorithm
= CSSM_ALGID_SHA512
;
567 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
568 inputSizeLimit
= 512 / 8;
569 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5
)) {
570 secondaryAlgorithm
= CSSM_ALGID_MD5
;
571 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
576 } else if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeDecrypt
) ||
577 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeEncrypt
)) {
578 if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionRaw
)) {
579 secondaryAlgorithm
= CSSM_ALGID_NONE
;
580 paddingAlgorithm
= CSSM_PADDING_NONE
;
582 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionPKCS1
)) {
583 secondaryAlgorithm
= CSSM_ALGID_NONE
;
584 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
585 inputSizeLimit
= operation
== kSecKeyOperationTypeEncrypt
? -11 : 0;
593 case CSSM_ALGID_ECDSA
:
594 if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeSign
) ||
595 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeVerify
)) {
596 if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureRFC4754
)) {
597 secondaryAlgorithm
= CSSM_ALGID_NONE
;
598 paddingAlgorithm
= CSSM_PADDING_SIGRAW
;
599 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureDigestX962
)) {
600 secondaryAlgorithm
= CSSM_ALGID_NONE
;
601 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
605 } else if (keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeKeyExchange
) {
606 if (CFEqual(algorithm
,kSecKeyAlgorithmECDHKeyExchangeStandard
) ||
607 CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactor
)) {
608 baseAlgorithm
= CSSM_ALGID_ECDH
;
609 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1
) ||
610 CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1
)) {
611 baseAlgorithm
= CSSM_ALGID_ECDH_X963_KDF
;
620 MacOSError::throwMe(errSecParam
);
626 SecCDSAKeyCopyPaddedPlaintext(SecKeyRef key
, CFDataRef plaintext
, SecKeyAlgorithm algorithm
) {
627 CFIndex blockSize
= key
->key
->key().header().LogicalKeySizeInBits
/ 8;
628 CFIndex plaintextLength
= CFDataGetLength(plaintext
);
629 if ((algorithm
== kSecKeyAlgorithmRSAEncryptionRaw
|| algorithm
== kSecKeyAlgorithmRSASignatureRaw
)
630 && plaintextLength
< blockSize
) {
631 // Pre-pad with zeroes.
632 CFMutableDataRef
result(CFDataCreateMutable(kCFAllocatorDefault
, blockSize
));
633 CFDataSetLength(result
, blockSize
);
634 CFDataReplaceBytes(result
, CFRangeMake(blockSize
- plaintextLength
, plaintextLength
),
635 CFDataGetBytePtr(plaintext
), plaintextLength
);
638 return CFDataRef(CFRetain(plaintext
));
642 static CFTypeRef
SecCDSAKeyCopyOperationResult(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
,
643 CFArrayRef allAlgorithms
, SecKeyOperationMode mode
,
644 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
645 BEGIN_SECKEYAPI(CFTypeRef
, kCFNull
)
646 CFIndex inputSizeLimit
= 0;
647 CSSM_ALGORITHMS baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
;
648 KeyItem
*keyItem
= SecCDSAKeyPrepareParameters(key
, operation
, algorithm
, baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
, inputSizeLimit
);
649 if (keyItem
== NULL
) {
650 // Operation/algorithm/key combination is not supported.
652 } else if (mode
== kSecKeyOperationModeCheckIfSupported
) {
653 // Operation is supported and caller wants to just know that.
654 return kCFBooleanTrue
;
655 } else if (baseAlgorithm
== CSSM_ALGID_RSA
) {
656 if (inputSizeLimit
<= 0) {
657 inputSizeLimit
+= SecCDSAKeyGetBlockSize(key
);
659 if (CFDataGetLength((CFDataRef
)in1
) > inputSizeLimit
) {
660 MacOSError::throwMe(errSecParam
);
665 case kSecKeyOperationTypeSign
: {
666 CssmClient::Sign
signContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
);
667 signContext
.key(keyItem
->key());
668 signContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN
, key
->credentialType
));
669 signContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
);
670 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
671 CssmAutoData
signature(signContext
.allocator());
672 signContext
.sign(CssmData(CFDataRef(input
)), signature
.get());
673 result
= CFDataCreate(NULL
, static_cast<const UInt8
*>(signature
.data()), CFIndex(signature
.length()));
676 case kSecKeyOperationTypeVerify
: {
677 CssmClient::Verify
verifyContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
);
678 verifyContext
.key(keyItem
->key());
679 verifyContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ANY
, key
->credentialType
));
680 verifyContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
);
681 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
682 verifyContext
.verify(CssmData(CFDataRef(input
)), CssmData(CFRef
<CFDataRef
>::check(in2
, errSecParam
)));
683 result
= kCFBooleanTrue
;
686 case kSecKeyOperationTypeEncrypt
: {
687 CssmClient::Encrypt
encryptContext(keyItem
->csp(), baseAlgorithm
);
688 encryptContext
.key(keyItem
->key());
689 encryptContext
.padding(paddingAlgorithm
);
690 encryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT
, key
->credentialType
));
691 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
692 CssmAutoData
output(encryptContext
.allocator()), remainingData(encryptContext
.allocator());
693 size_t length
= encryptContext
.encrypt(CssmData(CFDataRef(input
)), output
.get(), remainingData
.get());
694 result
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length());
695 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(output
.data()), output
.length());
696 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(remainingData
.data()), remainingData
.length());
697 CFDataSetLength(CFMutableDataRef(result
), length
);
700 case kSecKeyOperationTypeDecrypt
: {
701 CssmClient::Decrypt
decryptContext(keyItem
->csp(), baseAlgorithm
);
702 decryptContext
.key(keyItem
->key());
703 decryptContext
.padding(paddingAlgorithm
);
704 decryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT
, key
->credentialType
));
705 CssmAutoData
output(decryptContext
.allocator()), remainingData(decryptContext
.allocator());
706 size_t length
= decryptContext
.decrypt(CssmData(CFRef
<CFDataRef
>::check(in1
, errSecParam
)),
707 output
.get(), remainingData
.get());
708 result
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length());
709 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(output
.data()), output
.length());
710 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(remainingData
.data()), remainingData
.length());
711 CFDataSetLength(CFMutableDataRef(result
), length
);
714 case kSecKeyOperationTypeKeyExchange
: {
715 CFIndex requestedLength
= 0;
717 switch (baseAlgorithm
) {
718 case CSSM_ALGID_ECDH
:
719 requestedLength
= (keyItem
->key().header().LogicalKeySizeInBits
+ 7) / 8;
721 case CSSM_ALGID_ECDH_X963_KDF
:
722 CFDictionaryRef params
= CFRef
<CFDictionaryRef
>::check(in2
, errSecParam
);
723 CFTypeRef value
= params
? CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterRequestedSize
) : NULL
;
724 if (value
== NULL
|| CFGetTypeID(value
) != CFNumberGetTypeID() ||
725 !CFNumberGetValue(CFNumberRef(value
), kCFNumberCFIndexType
, &requestedLength
)) {
726 MacOSError::throwMe(errSecParam
);
728 value
= CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterSharedInfo
);
729 if (value
!= NULL
&& CFGetTypeID(value
) == CFDataGetTypeID()) {
730 sharedInfo
= CssmData(CFDataRef(value
));
735 CssmClient::DeriveKey
derive(keyItem
->csp(), baseAlgorithm
, CSSM_ALGID_AES
, uint32(requestedLength
* 8));
736 derive
.key(keyItem
->key());
737 derive
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DERIVE
, kSecCredentialTypeDefault
));
738 derive
.salt(sharedInfo
);
739 CssmData
param(CFRef
<CFDataRef
>::check(in1
, errSecParam
));
740 Key derivedKey
= derive(¶m
, KeySpec(CSSM_KEYUSE_ANY
, CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
));
742 // Export raw data of newly derived key (by wrapping with an empty key).
743 CssmClient::WrapKey
wrapper(keyItem
->csp(), CSSM_ALGID_NONE
);
744 Key wrappedKey
= wrapper(derivedKey
);
745 result
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)wrappedKey
->data(), CFIndex(wrappedKey
->length()));
755 static Boolean
SecCDSAKeyIsEqual(SecKeyRef key1
, SecKeyRef key2
) {
757 BEGIN_SECKEYAPI(Boolean
, false)
759 result
= key1
->key
->equal(*key2
->key
);
764 static Boolean
SecCDSAKeySetParameter(SecKeyRef key
, CFStringRef name
, CFPropertyListRef value
, CFErrorRef
*error
) {
765 BEGIN_SECKEYAPI(Boolean
, false)
767 if (CFEqual(name
, kSecUseAuthenticationUI
)) {
768 key
->credentialType
= CFEqual(value
, kSecUseAuthenticationUIAllow
) ? kSecCredentialTypeDefault
: kSecCredentialTypeNoUI
;
771 result
= SecError(errSecUnimplemented
, error
, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name
);
777 const SecKeyDescriptor kSecCDSAKeyDescriptor
= {
778 .version
= kSecKeyDescriptorVersion
,
781 .init
= SecCDSAKeyInit
,
782 .destroy
= SecCDSAKeyDestroy
,
783 .blockSize
= SecCDSAKeyGetBlockSize
,
784 .getAlgorithmID
= SecCDSAKeyGetAlgorithmId
,
785 .copyDictionary
= SecCDSAKeyCopyAttributeDictionary
,
786 .copyPublic
= SecCDSAKeyCopyPublicBytes
,
787 .copyExternalRepresentation
= SecCDSAKeyCopyExternalRepresentation
,
788 .copyPublicKey
= SecCDSAKeyCopyPublicKey
,
789 .copyOperationResult
= SecCDSAKeyCopyOperationResult
,
790 .isEqual
= SecCDSAKeyIsEqual
,
791 .setParameter
= SecCDSAKeySetParameter
,
795 namespace KeychainCore
{
796 SecCFObject
*KeyItem::fromSecKeyRef(CFTypeRef ptr
) {
797 if (ptr
== NULL
|| CFGetTypeID(ptr
) != SecKeyGetTypeID()) {
801 SecKeyRef key
= static_cast<SecKeyRef
>(const_cast<void *>(ptr
));
802 if (key
->key_class
== &kSecCDSAKeyDescriptor
) {
803 return static_cast<SecCFObject
*>(key
->key
);
806 if (key
->cdsaKey
== NULL
) {
807 // Create CDSA key from exported data of existing key.
808 CFRef
<CFDataRef
> keyData
= SecKeyCopyExternalRepresentation(key
, NULL
);
809 CFRef
<CFDictionaryRef
> keyAttributes
= SecKeyCopyAttributes(key
);
810 if (keyData
&& keyAttributes
) {
811 key
->cdsaKey
= SecKeyCreateFromData(keyAttributes
, keyData
, NULL
);
815 return (key
->cdsaKey
!= NULL
) ? key
->cdsaKey
->key
: NULL
;
818 // You need to hold this key's MutexForObject when you run this
819 void KeyItem::attachSecKeyRef() const {
820 SecKeyRef key
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, reinterpret_cast<const uint8_t *>(this), 0, 0);
821 key
->key
->mWeakSecKeyRef
= key
;
827 extern "C" Boolean
SecKeyIsCDSAKey(SecKeyRef ref
);
828 Boolean
SecKeyIsCDSAKey(SecKeyRef ref
) {
829 return ref
->key_class
== &kSecCDSAKeyDescriptor
;
833 static OSStatus
SecKeyCreatePairInternal(
834 SecKeychainRef keychainRef
,
835 CSSM_ALGORITHMS algorithm
,
836 uint32 keySizeInBits
,
837 CSSM_CC_HANDLE contextHandle
,
838 CSSM_KEYUSE publicKeyUsage
,
839 uint32 publicKeyAttr
,
840 CSSM_KEYUSE privateKeyUsage
,
841 uint32 privateKeyAttr
,
842 SecAccessRef initialAccess
,
843 SecKeyRef
* publicKeyRef
,
844 SecKeyRef
* privateKeyRef
)
849 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
850 SecPointer
<KeyItem
> pubItem
, privItem
;
851 if (((publicKeyAttr
| privateKeyAttr
) & CSSM_KEYATTR_PERMANENT
) != 0) {
852 keychain
= Keychain::optional(keychainRef
);
853 StLock
<Mutex
> _(*keychain
->getKeychainMutex());
854 KeyItem::createPair(keychain
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, publicKeyAttr
,
855 privateKeyUsage
, privateKeyAttr
, theAccess
, pubItem
, privItem
);
857 KeyItem::createPair(keychain
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, publicKeyAttr
,
858 privateKeyUsage
, privateKeyAttr
, theAccess
, pubItem
, privItem
);
861 // Return the generated keys.
863 *publicKeyRef
= pubItem
->handle();
865 *privateKeyRef
= privItem
->handle();
872 SecKeychainRef keychainRef
,
873 CSSM_ALGORITHMS algorithm
,
874 uint32 keySizeInBits
,
875 CSSM_CC_HANDLE contextHandle
,
876 CSSM_KEYUSE publicKeyUsage
,
877 uint32 publicKeyAttr
,
878 CSSM_KEYUSE privateKeyUsage
,
879 uint32 privateKeyAttr
,
880 SecAccessRef initialAccess
,
881 SecKeyRef
* publicKeyRef
,
882 SecKeyRef
* privateKeyRef
)
884 OSStatus result
= SecKeyCreatePairInternal(keychainRef
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
,
885 publicKeyAttr
, privateKeyUsage
, privateKeyAttr
, initialAccess
, publicKeyRef
, privateKeyRef
);
893 SecKeyGetCSSMKey(SecKeyRef key
, const CSSM_KEY
**cssmKey
)
897 Required(cssmKey
) = KeyItem::required(key
)->key();
908 SecKeyGetCSPHandle(SecKeyRef keyRef
, CSSM_CSP_HANDLE
*cspHandle
)
912 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
913 Required(cspHandle
) = keyItem
->csp()->handle();
918 /* deprecated as of 10.8 */
920 SecKeyGetAlgorithmID(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
**algid
)
924 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
925 Required(algid
) = &keyItem
->algorithmIdentifier();
931 SecKeyGetStrengthInBits(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
*algid
, unsigned int *strength
)
935 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
936 Required(strength
) = keyItem
->strengthInBits(algid
);
942 SecKeyGetCredentials(
944 CSSM_ACL_AUTHORIZATION_TAG operation
,
945 SecCredentialType credentialType
,
946 const CSSM_ACCESS_CREDENTIALS
**outCredentials
)
950 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
951 Required(outCredentials
) = keyItem
->getCredentials(operation
, credentialType
);
958 SecKeychainRef keychainRef
,
959 const CSSM_KEY
*publicCssmKey
,
960 const CSSM_KEY
*privateCssmKey
,
961 SecAccessRef initialAccess
,
962 SecKeyRef
* publicKey
,
963 SecKeyRef
* privateKey
)
967 Keychain keychain
= Keychain::optional(keychainRef
);
968 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
969 SecPointer
<KeyItem
> pubItem
, privItem
;
971 KeyItem::importPair(keychain
,
972 Required(publicCssmKey
),
973 Required(privateCssmKey
),
978 // Return the generated keys.
980 *publicKey
= pubItem
->handle();
982 *privateKey
= privItem
->handle();
988 SecKeyGenerateWithAttributes(
989 SecKeychainAttributeList
* attrList
,
990 SecKeychainRef keychainRef
,
991 CSSM_ALGORITHMS algorithm
,
992 uint32 keySizeInBits
,
993 CSSM_CC_HANDLE contextHandle
,
994 CSSM_KEYUSE keyUsage
,
996 SecAccessRef initialAccess
,
1002 SecPointer
<Access
> theAccess
;
1005 keychain
= KeychainImpl::required(keychainRef
);
1007 theAccess
= Access::required(initialAccess
);
1009 SecPointer
<KeyItem
> item
= KeyItem::generateWithAttributes(attrList
,
1018 // Return the generated key.
1020 *keyRef
= item
->handle();
1027 SecKeychainRef keychainRef
,
1028 CSSM_ALGORITHMS algorithm
,
1029 uint32 keySizeInBits
,
1030 CSSM_CC_HANDLE contextHandle
,
1031 CSSM_KEYUSE keyUsage
,
1033 SecAccessRef initialAccess
,
1036 return SecKeyGenerateWithAttributes(NULL
,
1037 keychainRef
, algorithm
, keySizeInBits
,
1038 contextHandle
, keyUsage
, keyAttr
,
1039 initialAccess
, keyRef
);
1043 /* Generate a floating key reference from a CSSM_KEY */
1045 SecKeyCreateWithCSSMKey(const CSSM_KEY
*cssmKey
,
1051 if(cssmKey
->KeyData
.Length
== 0){
1052 MacOSError::throwMe(errSecInvalidAttributeKeyLength
);
1054 if(cssmKey
->KeyData
.Data
== NULL
){
1055 MacOSError::throwMe(errSecInvalidPointer
);
1057 CssmClient::CSP
csp(cssmKey
->KeyHeader
.CspId
);
1058 CssmClient::Key
key(csp
, *cssmKey
);
1059 KeyItem
*item
= new KeyItem(key
);
1061 // Return the generated key.
1063 *keyRef
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, (const uint8_t *)item
, 0, 0);
1070 static u_int32_t
ConvertCFStringToInteger(CFStringRef ref
)
1077 // figure out the size of the string
1078 CFIndex numChars
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref
), kCFStringEncodingUTF8
);
1079 char buffer
[numChars
];
1080 if (!CFStringGetCString(ref
, buffer
, numChars
, kCFStringEncodingUTF8
))
1082 MacOSError::throwMe(errSecParam
);
1085 return atoi(buffer
);
1090 static OSStatus
CheckAlgorithmType(CFDictionaryRef parameters
, CSSM_ALGORITHMS
&algorithms
)
1092 // figure out the algorithm to use
1093 CFStringRef ktype
= (CFStringRef
) CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
1099 if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
1100 algorithms
= CSSM_ALGID_RSA
;
1101 return errSecSuccess
;
1102 } else if(CFEqual(ktype
, kSecAttrKeyTypeECDSA
) ||
1103 CFEqual(ktype
, kSecAttrKeyTypeEC
)) {
1104 algorithms
= CSSM_ALGID_ECDSA
;
1105 return errSecSuccess
;
1106 } else if(CFEqual(ktype
, kSecAttrKeyTypeAES
)) {
1107 algorithms
= CSSM_ALGID_AES
;
1108 return errSecSuccess
;
1109 } else if(CFEqual(ktype
, kSecAttrKeyType3DES
)) {
1110 algorithms
= CSSM_ALGID_3DES
;
1111 return errSecSuccess
;
1113 return errSecUnsupportedAlgorithm
;
1119 static OSStatus
GetKeySize(CFDictionaryRef parameters
, CSSM_ALGORITHMS algorithms
, uint32
&keySizeInBits
)
1122 // get the key size and check it for validity
1123 CFTypeRef ref
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
1125 keySizeInBits
= kSecDefaultKeySize
;
1127 CFTypeID bitSizeType
= CFGetTypeID(ref
);
1128 if (bitSizeType
== CFStringGetTypeID())
1129 keySizeInBits
= ConvertCFStringToInteger((CFStringRef
) ref
);
1130 else if (bitSizeType
== CFNumberGetTypeID())
1131 CFNumberGetValue((CFNumberRef
) ref
, kCFNumberSInt32Type
, &keySizeInBits
);
1132 else return errSecParam
;
1135 switch (algorithms
) {
1136 case CSSM_ALGID_ECDSA
:
1137 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecp256r1
;
1138 if(keySizeInBits
== kSecp192r1
|| keySizeInBits
== kSecp256r1
|| keySizeInBits
== kSecp384r1
|| keySizeInBits
== kSecp521r1
) return errSecSuccess
;
1140 case CSSM_ALGID_RSA
:
1141 if(keySizeInBits
% 8) return errSecParam
;
1142 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= 2048;
1143 if(keySizeInBits
>= kSecRSAMin
&& keySizeInBits
<= kSecRSAMax
) return errSecSuccess
;
1145 case CSSM_ALGID_AES
:
1146 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecAES128
;
1147 if(keySizeInBits
== kSecAES128
|| keySizeInBits
== kSecAES192
|| keySizeInBits
== kSecAES256
) return errSecSuccess
;
1149 case CSSM_ALGID_3DES
:
1150 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSec3DES192
;
1151 if(keySizeInBits
== kSec3DES192
) return errSecSuccess
;
1170 struct ParameterAttribute
1172 const CFStringRef
*name
;
1178 static ParameterAttribute gAttributes
[] =
1185 &kSecAttrIsPermanent
,
1189 &kSecAttrApplicationTag
,
1193 &kSecAttrEffectiveKeySize
,
1197 &kSecAttrCanEncrypt
,
1201 &kSecAttrCanDecrypt
,
1222 const int kNumberOfAttributes
= sizeof(gAttributes
) / sizeof(ParameterAttribute
);
1224 static OSStatus
ScanDictionaryForParameters(CFDictionaryRef parameters
, void* attributePointers
[])
1227 for (i
= 0; i
< kNumberOfAttributes
; ++i
)
1229 // see if the corresponding tag exists in the dictionary
1230 CFTypeRef value
= CFDictionaryGetValue(parameters
, *(gAttributes
[i
].name
));
1233 switch (gAttributes
[i
].type
)
1236 // just return the value
1237 *(CFTypeRef
*) attributePointers
[i
] = value
;
1242 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1243 *(bool*) attributePointers
[i
] = CFBooleanGetValue(bRef
);
1249 CFNumberRef nRef
= (CFNumberRef
) value
;
1250 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, attributePointers
[i
]);
1257 return errSecSuccess
;
1262 static OSStatus
GetKeyParameters(CFDictionaryRef parameters
, int keySize
, bool isPublic
, CSSM_KEYUSE
&keyUse
, uint32
&attrs
, CFTypeRef
&labelRef
, CFDataRef
&applicationTagRef
)
1264 // establish default values
1266 bool isPermanent
= false;
1267 applicationTagRef
= NULL
;
1268 CFTypeRef effectiveKeySize
= NULL
;
1269 bool canDecrypt
= isPublic
? false : true;
1270 bool canEncrypt
= !canDecrypt
;
1271 bool canDerive
= true;
1272 bool canSign
= isPublic
? false : true;
1273 bool canVerify
= !canSign
;
1274 bool canUnwrap
= isPublic
? false : true;
1275 attrs
= CSSM_KEYATTR_EXTRACTABLE
;
1278 void* attributePointers
[] = {&labelRef
, &isPermanent
, &applicationTagRef
, &effectiveKeySize
, &canEncrypt
, &canDecrypt
,
1279 &canDerive
, &canSign
, &canVerify
, &canUnwrap
};
1281 // look for modifiers in the general dictionary
1282 OSStatus result
= ScanDictionaryForParameters(parameters
, attributePointers
);
1283 if (result
!= errSecSuccess
)
1288 // see if we have anything which modifies the defaults
1292 key
= kSecPublicKeyAttrs
;
1296 key
= kSecPrivateKeyAttrs
;
1299 CFTypeRef dType
= CFDictionaryGetValue(parameters
, key
);
1302 // this had better be a dictionary
1303 if (CFGetTypeID(dType
) != CFDictionaryGetTypeID())
1308 // pull any additional parameters out of this dictionary
1309 result
= ScanDictionaryForParameters((CFDictionaryRef
)dType
, attributePointers
);
1310 if (result
!= errSecSuccess
)
1316 // figure out the key usage
1320 keyUse
|= CSSM_KEYUSE_DECRYPT
;
1325 keyUse
|= CSSM_KEYUSE_ENCRYPT
;
1330 keyUse
|= CSSM_KEYUSE_DERIVE
;
1335 keyUse
|= CSSM_KEYUSE_SIGN
;
1340 keyUse
|= CSSM_KEYUSE_VERIFY
;
1345 keyUse
|= CSSM_KEYUSE_UNWRAP
;
1348 // public key is always extractable;
1349 // private key is extractable by default unless explicitly set to false
1350 CFTypeRef value
= NULL
;
1351 if (!isPublic
&& CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
) && value
)
1353 Boolean keyIsExtractable
= CFEqual(kCFBooleanTrue
, value
);
1354 if (!keyIsExtractable
)
1359 attrs
|= CSSM_KEYATTR_PERMANENT
;
1362 return errSecSuccess
;
1367 static OSStatus
MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters
,
1368 CSSM_ALGORITHMS
&algorithms
,
1369 uint32
&keySizeInBits
,
1370 CSSM_KEYUSE
&publicKeyUse
,
1371 uint32
&publicKeyAttr
,
1372 CFTypeRef
&publicKeyLabelRef
,
1373 CFDataRef
&publicKeyAttributeTagRef
,
1374 CSSM_KEYUSE
&privateKeyUse
,
1375 uint32
&privateKeyAttr
,
1376 CFTypeRef
&privateKeyLabelRef
,
1377 CFDataRef
&privateKeyAttributeTagRef
,
1378 SecAccessRef
&initialAccess
)
1382 result
= CheckAlgorithmType(parameters
, algorithms
);
1383 if (result
!= errSecSuccess
)
1388 result
= GetKeySize(parameters
, algorithms
, keySizeInBits
);
1389 if (result
!= errSecSuccess
)
1394 result
= GetKeyParameters(parameters
, keySizeInBits
, false, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1395 if (result
!= errSecSuccess
)
1400 result
= GetKeyParameters(parameters
, keySizeInBits
, true, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1401 if (result
!= errSecSuccess
)
1406 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&initialAccess
))
1408 initialAccess
= NULL
;
1410 else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess
))
1415 return errSecSuccess
;
1420 static OSStatus
SetKeyLabelAndTag(SecKeyRef keyRef
, CFTypeRef label
, CFDataRef tag
)
1422 int numToModify
= 0;
1433 if (numToModify
== 0)
1435 return errSecSuccess
;
1438 SecKeychainAttributeList attrList
;
1439 SecKeychainAttribute attributes
[numToModify
];
1445 if (CFStringGetTypeID() == CFGetTypeID(label
)) {
1446 CFStringRef label_string
= static_cast<CFStringRef
>(label
);
1447 attributes
[i
].tag
= kSecKeyPrintName
;
1448 attributes
[i
].data
= (void*) CFStringGetCStringPtr(label_string
, kCFStringEncodingUTF8
);
1449 if (NULL
== attributes
[i
].data
) {
1450 CFIndex buffer_length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string
), kCFStringEncodingUTF8
);
1451 attributes
[i
].data
= alloca((size_t)buffer_length
);
1452 if (NULL
== attributes
[i
].data
) {
1453 UnixError::throwMe(ENOMEM
);
1455 if (!CFStringGetCString(label_string
, static_cast<char *>(attributes
[i
].data
), buffer_length
, kCFStringEncodingUTF8
)) {
1456 MacOSError::throwMe(errSecParam
);
1459 attributes
[i
].length
= (UInt32
)strlen(static_cast<char *>(attributes
[i
].data
));
1460 } else if (CFDataGetTypeID() == CFGetTypeID(label
)) {
1461 // 10.6 bug compatibility
1462 CFDataRef label_data
= static_cast<CFDataRef
>(label
);
1463 attributes
[i
].tag
= kSecKeyLabel
;
1464 attributes
[i
].data
= (void*) CFDataGetBytePtr(label_data
);
1465 attributes
[i
].length
= (UInt32
)CFDataGetLength(label_data
);
1467 MacOSError::throwMe(errSecParam
);
1474 attributes
[i
].tag
= kSecKeyApplicationTag
;
1475 attributes
[i
].data
= (void*) CFDataGetBytePtr(tag
);
1476 attributes
[i
].length
= (UInt32
)CFDataGetLength(tag
);
1480 attrList
.count
= numToModify
;
1481 attrList
.attr
= attributes
;
1483 return SecKeychainItemModifyAttributesAndData((SecKeychainItemRef
) keyRef
, &attrList
, 0, NULL
);
1487 static CFTypeRef
GetAttributeFromParams(CFDictionaryRef parameters
, CFTypeRef attr
, CFTypeRef subParams
) {
1488 if (subParams
!= NULL
) {
1489 CFDictionaryRef subParamsDict
= (CFDictionaryRef
)CFDictionaryGetValue(parameters
, subParams
);
1490 if (subParamsDict
!= NULL
) {
1491 CFTypeRef value
= CFDictionaryGetValue(subParamsDict
, attr
);
1492 if (value
!= NULL
) {
1497 return CFDictionaryGetValue(parameters
, attr
);
1500 extern "C" OSStatus
SecKeyGeneratePair_ios(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
);
1503 /* Generate a private/public keypair. */
1505 SecKeyGeneratePairInternal(
1506 bool alwaysPermanent
,
1507 CFDictionaryRef parameters
,
1508 SecKeyRef
*publicKey
,
1509 SecKeyRef
*privateKey
)
1513 Required(parameters
);
1514 Required(publicKey
);
1515 Required(privateKey
);
1517 CFTypeRef tokenID
= GetAttributeFromParams(parameters
, kSecAttrTokenID
, NULL
);
1518 CFTypeRef noLegacy
= GetAttributeFromParams(parameters
, kSecAttrNoLegacy
, NULL
);
1519 CFTypeRef sync
= GetAttributeFromParams(parameters
, kSecAttrSynchronizable
, kSecPrivateKeyAttrs
);
1520 CFTypeRef accessControl
= GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPrivateKeyAttrs
) ?:
1521 GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPublicKeyAttrs
);
1522 CFTypeRef accessGroup
= GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPrivateKeyAttrs
) ?:
1523 GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPublicKeyAttrs
);
1525 // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain).
1526 if (tokenID
!= NULL
||
1527 (noLegacy
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)noLegacy
)) ||
1528 (sync
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)sync
)) ||
1529 accessControl
!= NULL
|| (accessGroup
!= NULL
&& CFEqual(accessGroup
, kSecAttrAccessGroupToken
))) {
1530 // Generate keys in iOS keychain.
1531 return SecKeyGeneratePair_ios(parameters
, publicKey
, privateKey
);
1534 CSSM_ALGORITHMS algorithms
;
1535 uint32 keySizeInBits
;
1536 CSSM_KEYUSE publicKeyUse
;
1537 uint32 publicKeyAttr
;
1538 CFTypeRef publicKeyLabelRef
;
1539 CFDataRef publicKeyAttributeTagRef
;
1540 CSSM_KEYUSE privateKeyUse
;
1541 uint32 privateKeyAttr
;
1542 CFTypeRef privateKeyLabelRef
;
1543 CFDataRef privateKeyAttributeTagRef
;
1544 SecAccessRef initialAccess
;
1545 SecKeychainRef keychain
;
1547 OSStatus result
= MakeKeyGenParametersFromDictionary(parameters
, algorithms
, keySizeInBits
, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
,
1548 publicKeyAttributeTagRef
, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
,
1551 if (result
!= errSecSuccess
) {
1555 // verify keychain parameter
1556 keychain
= (SecKeychainRef
)CFDictionaryGetValue(parameters
, kSecUseKeychain
);
1557 if (keychain
!= NULL
&& SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1561 if (alwaysPermanent
) {
1562 publicKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1563 privateKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1566 // do the key generation
1567 result
= SecKeyCreatePair(keychain
, algorithms
, keySizeInBits
, 0, publicKeyUse
, publicKeyAttr
, privateKeyUse
, privateKeyAttr
, initialAccess
, publicKey
, privateKey
);
1568 if (result
!= errSecSuccess
) {
1572 // set the label and print attributes on the keys
1573 SetKeyLabelAndTag(*publicKey
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1574 SetKeyLabelAndTag(*privateKey
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1581 SecKeyGeneratePair(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
1582 return SecKeyGeneratePairInternal(true, parameters
, publicKey
, privateKey
);
1586 SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef
*error
) {
1587 SecKeyRef privateKey
= NULL
, publicKey
= NULL
;
1588 OSStatus status
= SecKeyGeneratePairInternal(false, parameters
, &publicKey
, &privateKey
);
1589 SecError(status
, error
, CFSTR("failed to generate asymmetric keypair"));
1590 if (publicKey
!= NULL
) {
1591 CFRelease(publicKey
);
1596 OSStatus
SecKeyRawVerifyOSX(
1597 SecKeyRef key
, /* Public key */
1598 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
1599 const uint8_t *signedData
, /* signature over this data */
1600 size_t signedDataLen
, /* length of dataToSign */
1601 const uint8_t *sig
, /* signature */
1604 return SecKeyRawVerify(key
,padding
,signedData
,signedDataLen
,sig
,sigLen
);
1612 utilGetStringFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, CFTypeRef defaultValue
)
1614 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1615 if (value
!= NULL
) return value
;
1616 return defaultValue
;
1620 utilGetNumberFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t defaultValue
)
1622 uint32_t integerValue
;
1623 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1624 if (value
!= NULL
) {
1625 CFNumberRef nRef
= (CFNumberRef
) value
;
1626 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, &integerValue
);
1627 return integerValue
;
1629 return defaultValue
;
1633 utilGetMaskValFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t maskValue
)
1635 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1636 if (value
!= NULL
) {
1637 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1638 if(CFBooleanGetValue(bRef
)) return maskValue
;
1644 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters
, CSSM_ALGORITHMS
*algorithm
, uint32
*keySizeInBits
, CSSM_KEYUSE
*keyUsage
, CSSM_KEYCLASS
*keyClass
)
1646 CFTypeRef algorithmDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeAES
);
1647 CFTypeRef keyClassDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1649 if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeAES
)) {
1650 *algorithm
= CSSM_ALGID_AES
;
1651 *keySizeInBits
= 128;
1652 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1653 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDES
)) {
1654 *algorithm
= CSSM_ALGID_DES
;
1655 *keySizeInBits
= 128;
1656 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1657 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyType3DES
)) {
1658 *algorithm
= CSSM_ALGID_3DES_3KEY_EDE
;
1659 *keySizeInBits
= 128;
1660 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1661 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC4
)) {
1662 *algorithm
= CSSM_ALGID_RC4
;
1663 *keySizeInBits
= 128;
1664 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1665 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC2
)) {
1666 *algorithm
= CSSM_ALGID_RC2
;
1667 *keySizeInBits
= 128;
1668 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1669 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeCAST
)) {
1670 *algorithm
= CSSM_ALGID_CAST
;
1671 *keySizeInBits
= 128;
1672 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1673 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRSA
)) {
1674 *algorithm
= CSSM_ALGID_RSA
;
1675 *keySizeInBits
= 128;
1676 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1677 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDSA
)) {
1678 *algorithm
= CSSM_ALGID_DSA
;
1679 *keySizeInBits
= 128;
1680 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1681 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeECDSA
) ||
1682 CFEqual(algorithmDictValue
, kSecAttrKeyTypeEC
)) {
1683 *algorithm
= CSSM_ALGID_ECDSA
;
1684 *keySizeInBits
= 128;
1685 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1687 *algorithm
= CSSM_ALGID_AES
;
1688 *keySizeInBits
= 128;
1689 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1692 if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPublic
)) {
1693 *keyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
1694 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPrivate
)) {
1695 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1696 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassSymmetric
)) {
1697 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1700 *keySizeInBits
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, *keySizeInBits
);
1701 *keyUsage
= utilGetMaskValFromCFDict(parameters
, kSecAttrCanEncrypt
, CSSM_KEYUSE_ENCRYPT
) |
1702 utilGetMaskValFromCFDict(parameters
, kSecAttrCanDecrypt
, CSSM_KEYUSE_DECRYPT
) |
1703 utilGetMaskValFromCFDict(parameters
, kSecAttrCanWrap
, CSSM_KEYUSE_WRAP
) |
1704 utilGetMaskValFromCFDict(parameters
, kSecAttrCanUnwrap
, CSSM_KEYUSE_UNWRAP
);
1707 if(*keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
|| *keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
) {
1708 *keyUsage
|= utilGetMaskValFromCFDict(parameters
, kSecAttrCanSign
, CSSM_KEYUSE_SIGN
) |
1709 utilGetMaskValFromCFDict(parameters
, kSecAttrCanVerify
, CSSM_KEYUSE_VERIFY
);
1712 if(*keyUsage
== 0) {
1713 switch (*keyClass
) {
1714 case CSSM_KEYCLASS_PRIVATE_KEY
:
1715 *keyUsage
= CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
;
1717 case CSSM_KEYCLASS_PUBLIC_KEY
:
1718 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
;
1721 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
;
1728 utilCopyDefaultKeyLabel(void)
1730 // generate a default label from the current date
1731 CFDateRef dateNow
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent());
1732 CFStringRef defaultLabel
= CFCopyDescription(dateNow
);
1735 return defaultLabel
;
1739 SecKeyGenerateSymmetric(CFDictionaryRef parameters
, CFErrorRef
*error
)
1741 OSStatus result
= errSecParam
; // default result for an early exit
1742 SecKeyRef key
= NULL
;
1743 SecKeychainRef keychain
= NULL
;
1744 SecAccessRef access
;
1746 CFStringRef appLabel
;
1748 CFStringRef dateLabel
= NULL
;
1750 CSSM_ALGORITHMS algorithm
;
1751 uint32 keySizeInBits
;
1752 CSSM_KEYUSE keyUsage
;
1753 uint32 keyAttr
= CSSM_KEYATTR_RETURN_DEFAULT
;
1754 CSSM_KEYCLASS keyClass
;
1756 Boolean isPermanent
;
1757 Boolean isExtractable
;
1759 // verify keychain parameter
1760 if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
))
1762 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1769 // verify permanent parameter
1770 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsPermanent
, (const void **)&value
))
1771 isPermanent
= false;
1772 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1775 isPermanent
= CFEqual(kCFBooleanTrue
, value
);
1777 if (keychain
== NULL
) {
1778 // no keychain was specified, so use the default keychain
1779 result
= SecKeychainCopyDefault(&keychain
);
1781 keyAttr
|= CSSM_KEYATTR_PERMANENT
;
1784 // verify extractable parameter
1785 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
))
1786 isExtractable
= true; // default to extractable if value not specified
1787 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1790 isExtractable
= CFEqual(kCFBooleanTrue
, value
);
1792 keyAttr
|= CSSM_KEYATTR_EXTRACTABLE
;
1794 // verify access parameter
1795 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&access
))
1797 else if (SecAccessGetTypeID() != CFGetTypeID(access
))
1800 // verify label parameter
1801 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrLabel
, (const void **)&label
))
1802 label
= (dateLabel
= utilCopyDefaultKeyLabel()); // no label provided, so use default
1803 else if (CFStringGetTypeID() != CFGetTypeID(label
))
1806 // verify application label parameter
1807 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationLabel
, (const void **)&appLabel
))
1808 appLabel
= (dateLabel
) ? dateLabel
: (dateLabel
= utilCopyDefaultKeyLabel());
1809 else if (CFStringGetTypeID() != CFGetTypeID(appLabel
))
1812 // verify application tag parameter
1813 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationTag
, (const void **)&appTag
))
1815 else if (CFStringGetTypeID() != CFGetTypeID(appTag
))
1818 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1821 // the generated key will not be stored in any keychain
1822 result
= SecKeyGenerate(keychain
, algorithm
, keySizeInBits
, 0, keyUsage
, keyAttr
, access
, &key
);
1825 // we can set the label attributes on the generated key if it's a keychain item
1826 size_t labelBufLen
= (label
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label
), kCFStringEncodingUTF8
) + 1 : 0;
1827 char *labelBuf
= (char *)malloc(labelBufLen
);
1828 size_t appLabelBufLen
= (appLabel
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel
), kCFStringEncodingUTF8
) + 1 : 0;
1829 char *appLabelBuf
= (char *)malloc(appLabelBufLen
);
1830 size_t appTagBufLen
= (appTag
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag
), kCFStringEncodingUTF8
) + 1 : 0;
1831 char *appTagBuf
= (char *)malloc(appTagBufLen
);
1833 if (label
&& !CFStringGetCString(label
, labelBuf
, labelBufLen
-1, kCFStringEncodingUTF8
))
1835 if (appLabel
&& !CFStringGetCString(appLabel
, appLabelBuf
, appLabelBufLen
-1, kCFStringEncodingUTF8
))
1837 if (appTag
&& !CFStringGetCString(appTag
, appTagBuf
, appTagBufLen
-1, kCFStringEncodingUTF8
))
1840 SecKeychainAttribute attrs
[] = {
1841 { kSecKeyPrintName
, (UInt32
)strlen(labelBuf
), (char *)labelBuf
},
1842 { kSecKeyLabel
, (UInt32
)strlen(appLabelBuf
), (char *)appLabelBuf
},
1843 { kSecKeyApplicationTag
, (UInt32
)strlen(appTagBuf
), (char *)appTagBuf
} };
1844 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
1845 if (!appTag
) --attributes
.count
;
1847 result
= SecKeyGenerateWithAttributes(&attributes
,
1848 keychain
, algorithm
, keySizeInBits
, 0,
1849 keyUsage
, keyAttr
, access
, &key
);
1857 if (result
&& error
) {
1858 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, result
, NULL
);
1861 CFRelease(dateLabel
);
1863 CFRelease(keychain
);
1871 SecKeyCreateFromData(CFDictionaryRef parameters
, CFDataRef keyData
, CFErrorRef
*error
)
1873 CSSM_ALGORITHMS algorithm
;
1874 uint32 keySizeInBits
;
1875 CSSM_KEYUSE keyUsage
;
1876 CSSM_KEYCLASS keyClass
;
1879 if(keyData
== NULL
|| CFDataGetLength(keyData
) == 0){
1880 MacOSError::throwMe(errSecUnsupportedKeySize
);
1883 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1885 CSSM_CSP_HANDLE cspHandle
= cuCspStartup(CSSM_FALSE
); // TRUE => CSP, FALSE => CSPDL
1887 SecKeyImportExportParameters iparam
;
1888 memset(&iparam
, 0, sizeof(iparam
));
1889 iparam
.keyUsage
= keyUsage
;
1891 CFRef
<CFDataRef
> data
;
1892 SecExternalItemType itype
;
1894 case CSSM_KEYCLASS_PRIVATE_KEY
:
1895 itype
= kSecItemTypePrivateKey
;
1897 case CSSM_KEYCLASS_PUBLIC_KEY
: {
1898 itype
= kSecItemTypePublicKey
;
1899 // Public key import expects public key in SubjPublicKey X509 format. We want to accept both bare and x509 format,
1900 // so we have to detect bare format here and extend to full X509 if detected.
1901 data
.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm
, keySizeInBits
, keyData
));
1904 case CSSM_KEYCLASS_SESSION_KEY
:
1905 itype
= kSecItemTypeSessionKey
;
1908 itype
= kSecItemTypeUnknown
;
1912 CFMutableArrayRef ka
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1913 // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful.
1914 crtn
= impExpImportRawKey(data
? CFDataRef(data
) : keyData
, kSecFormatUnknown
, itype
, algorithm
, NULL
, cspHandle
, 0, NULL
, NULL
, ka
);
1915 if (crtn
== CSSM_OK
&& CFArrayGetCount((CFArrayRef
)ka
)) {
1916 SecKeyRef sk
= (SecKeyRef
)CFArrayGetValueAtIndex((CFArrayRef
)ka
, 0);
1922 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, crtn
? crtn
: CSSM_ERRCODE_INTERNAL_ERROR
, NULL
);
1930 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable
, dispatch_queue_t deliveryQueue
,
1931 SecKeyGeneratePairBlock result
)
1933 CFDictionaryRef parameters
= CFDictionaryCreateCopy(NULL
, parametersWhichMightBeMutiable
);
1934 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
1935 SecKeyRef publicKey
= NULL
;
1936 SecKeyRef privateKey
= NULL
;
1937 OSStatus status
= SecKeyGeneratePair(parameters
, &publicKey
, &privateKey
);
1938 dispatch_async(deliveryQueue
, ^{
1939 CFErrorRef error
= NULL
;
1940 if (errSecSuccess
!= status
) {
1941 error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, NULL
);
1943 result(publicKey
, privateKey
, error
);
1948 CFRelease(publicKey
);
1951 CFRelease(privateKey
);
1953 CFRelease(parameters
);
1958 static inline void utilClearAndFree(void *p
, size_t len
) {
1960 if(len
) bzero(p
, len
);
1966 SecKeyDeriveFromPassword(CFStringRef password
, CFDictionaryRef parameters
, CFErrorRef
*error
)
1968 CCPBKDFAlgorithm algorithm
;
1969 CFIndex passwordLen
= 0;
1970 CFDataRef keyData
= NULL
;
1971 char *thePassword
= NULL
;
1972 uint8_t *salt
= NULL
;
1973 uint8_t *derivedKey
= NULL
;
1974 size_t saltLen
= 0, derivedKeyLen
= 0;
1976 CFDataRef saltDictValue
, algorithmDictValue
;
1977 SecKeyRef retval
= NULL
;
1979 /* Pick Values from parameters */
1981 if((saltDictValue
= (CFDataRef
) CFDictionaryGetValue(parameters
, kSecAttrSalt
)) == NULL
) {
1982 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecMissingAlgorithmParms
, NULL
);
1986 derivedKeyLen
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, 128);
1987 // This value come in bits but the rest of the code treats it as bytes
1990 algorithmDictValue
= (CFDataRef
) utilGetStringFromCFDict(parameters
, kSecAttrPRF
, kSecAttrPRFHmacAlgSHA256
);
1992 rounds
= utilGetNumberFromCFDict(parameters
, kSecAttrRounds
, 0);
1994 /* Convert any remaining parameters and get the password bytes */
1996 saltLen
= CFDataGetLength(saltDictValue
);
1997 if((salt
= (uint8_t *) malloc(saltLen
)) == NULL
) {
1998 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2002 CFDataGetBytes(saltDictValue
, CFRangeMake(0, saltLen
), (UInt8
*) salt
);
2004 passwordLen
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1;
2005 if((thePassword
= (char *) malloc(passwordLen
)) == NULL
) {
2006 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2009 CFStringGetBytes(password
, CFRangeMake(0, CFStringGetLength(password
)), kCFStringEncodingUTF8
, '?', FALSE
, (UInt8
*)thePassword
, passwordLen
, &passwordLen
);
2011 if((derivedKey
= (uint8_t *) malloc(derivedKeyLen
)) == NULL
) {
2012 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2016 if(algorithmDictValue
== NULL
) {
2017 algorithm
= kCCPRFHmacAlgSHA1
; /* default */
2018 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA1
)) {
2019 algorithm
= kCCPRFHmacAlgSHA1
;
2020 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA224
)) {
2021 algorithm
= kCCPRFHmacAlgSHA224
;
2022 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA256
)) {
2023 algorithm
= kCCPRFHmacAlgSHA256
;
2024 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA384
)) {
2025 algorithm
= kCCPRFHmacAlgSHA384
;
2026 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA512
)) {
2027 algorithm
= kCCPRFHmacAlgSHA512
;
2030 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidAlgorithmParms
, NULL
);
2036 rounds
= 33333; // we need to pass back a consistent value since there's no way to record the round count.
2039 if(CCKeyDerivationPBKDF(kCCPBKDF2
, thePassword
, passwordLen
, salt
, saltLen
, algorithm
, rounds
, derivedKey
, derivedKeyLen
)) {
2040 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2044 if((keyData
= CFDataCreate(NULL
, derivedKey
, derivedKeyLen
)) != NULL
) {
2045 retval
= SecKeyCreateFromData(parameters
, keyData
, error
);
2049 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2054 utilClearAndFree(salt
, saltLen
);
2055 utilClearAndFree(thePassword
, passwordLen
);
2056 utilClearAndFree(derivedKey
, derivedKeyLen
);
2061 SecKeyWrapSymmetric(SecKeyRef keyToWrap
, SecKeyRef wrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2064 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);
2070 SecKeyUnwrapSymmetric(CFDataRef
*keyToUnwrap
, SecKeyRef unwrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2073 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);