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 SecPointer
<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;
589 } else if (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeDecrypt
&&
590 CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionRaw
)) {
591 // Raw RSA decryption is identical to raw RSA encryption, so lets use encryption instead of decryption,
592 // because CDSA keys refuses to perform decrypt using public key.
593 operation
= kSecKeyOperationTypeEncrypt
;
594 secondaryAlgorithm
= CSSM_ALGID_NONE
;
595 paddingAlgorithm
= CSSM_PADDING_NONE
;
601 case CSSM_ALGID_ECDSA
:
602 if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeSign
) ||
603 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeVerify
)) {
604 if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureRFC4754
)) {
605 secondaryAlgorithm
= CSSM_ALGID_NONE
;
606 paddingAlgorithm
= CSSM_PADDING_SIGRAW
;
607 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureDigestX962
)) {
608 secondaryAlgorithm
= CSSM_ALGID_NONE
;
609 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
613 } else if (keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeKeyExchange
) {
614 if (CFEqual(algorithm
,kSecKeyAlgorithmECDHKeyExchangeStandard
) ||
615 CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactor
)) {
616 baseAlgorithm
= CSSM_ALGID_ECDH
;
617 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1
) ||
618 CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1
)) {
619 baseAlgorithm
= CSSM_ALGID_ECDH_X963_KDF
;
628 MacOSError::throwMe(errSecParam
);
634 SecCDSAKeyCopyPaddedPlaintext(SecKeyRef key
, CFDataRef plaintext
, SecKeyAlgorithm algorithm
) {
635 CFIndex blockSize
= key
->key
->key().header().LogicalKeySizeInBits
/ 8;
636 CFIndex plaintextLength
= CFDataGetLength(plaintext
);
637 if ((algorithm
== kSecKeyAlgorithmRSAEncryptionRaw
|| algorithm
== kSecKeyAlgorithmRSASignatureRaw
)
638 && plaintextLength
< blockSize
) {
639 // Pre-pad with zeroes.
640 CFMutableDataRef
result(CFDataCreateMutable(kCFAllocatorDefault
, blockSize
));
641 CFDataSetLength(result
, blockSize
);
642 CFDataReplaceBytes(result
, CFRangeMake(blockSize
- plaintextLength
, plaintextLength
),
643 CFDataGetBytePtr(plaintext
), plaintextLength
);
646 return CFDataRef(CFRetain(plaintext
));
650 static CFTypeRef
SecCDSAKeyCopyOperationResult(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
,
651 CFArrayRef allAlgorithms
, SecKeyOperationMode mode
,
652 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
653 BEGIN_SECKEYAPI(CFTypeRef
, kCFNull
)
654 CFIndex inputSizeLimit
= 0;
655 CSSM_ALGORITHMS baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
;
656 KeyItem
*keyItem
= SecCDSAKeyPrepareParameters(key
, operation
, algorithm
, baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
, inputSizeLimit
);
657 if (keyItem
== NULL
) {
658 // Operation/algorithm/key combination is not supported.
660 } else if (mode
== kSecKeyOperationModeCheckIfSupported
) {
661 // Operation is supported and caller wants to just know that.
662 return kCFBooleanTrue
;
663 } else if (baseAlgorithm
== CSSM_ALGID_RSA
) {
664 if (inputSizeLimit
<= 0) {
665 inputSizeLimit
+= SecCDSAKeyGetBlockSize(key
);
667 if (CFDataGetLength((CFDataRef
)in1
) > inputSizeLimit
) {
668 MacOSError::throwMe(errSecParam
);
673 case kSecKeyOperationTypeSign
: {
674 CssmClient::Sign
signContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
);
675 signContext
.key(keyItem
->key());
676 signContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN
, key
->credentialType
));
677 signContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
);
678 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
679 CssmAutoData
signature(signContext
.allocator());
680 signContext
.sign(CssmData(CFDataRef(input
)), signature
.get());
681 result
= CFDataCreate(NULL
, static_cast<const UInt8
*>(signature
.data()), CFIndex(signature
.length()));
684 case kSecKeyOperationTypeVerify
: {
685 CssmClient::Verify
verifyContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
);
686 verifyContext
.key(keyItem
->key());
687 verifyContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ANY
, key
->credentialType
));
688 verifyContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
);
689 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
690 verifyContext
.verify(CssmData(CFDataRef(input
)), CssmData(CFRef
<CFDataRef
>::check(in2
, errSecParam
)));
691 result
= kCFBooleanTrue
;
694 case kSecKeyOperationTypeEncrypt
: {
695 CssmClient::Encrypt
encryptContext(keyItem
->csp(), baseAlgorithm
);
696 encryptContext
.key(keyItem
->key());
697 encryptContext
.padding(paddingAlgorithm
);
698 encryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT
, key
->credentialType
));
699 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
700 CssmAutoData
output(encryptContext
.allocator()), remainingData(encryptContext
.allocator());
701 size_t length
= encryptContext
.encrypt(CssmData(CFDataRef(input
)), output
.get(), remainingData
.get());
702 result
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length());
703 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(output
.data()), output
.length());
704 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(remainingData
.data()), remainingData
.length());
705 CFDataSetLength(CFMutableDataRef(result
), length
);
708 case kSecKeyOperationTypeDecrypt
: {
709 CssmClient::Decrypt
decryptContext(keyItem
->csp(), baseAlgorithm
);
710 decryptContext
.key(keyItem
->key());
711 decryptContext
.padding(paddingAlgorithm
);
712 decryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT
, key
->credentialType
));
713 CssmAutoData
output(decryptContext
.allocator()), remainingData(decryptContext
.allocator());
714 size_t length
= decryptContext
.decrypt(CssmData(CFRef
<CFDataRef
>::check(in1
, errSecParam
)),
715 output
.get(), remainingData
.get());
716 result
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length());
717 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(output
.data()), output
.length());
718 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(remainingData
.data()), remainingData
.length());
719 CFDataSetLength(CFMutableDataRef(result
), length
);
722 case kSecKeyOperationTypeKeyExchange
: {
723 CFIndex requestedLength
= 0;
725 switch (baseAlgorithm
) {
726 case CSSM_ALGID_ECDH
:
727 requestedLength
= (keyItem
->key().header().LogicalKeySizeInBits
+ 7) / 8;
729 case CSSM_ALGID_ECDH_X963_KDF
:
730 CFDictionaryRef params
= CFRef
<CFDictionaryRef
>::check(in2
, errSecParam
);
731 CFTypeRef value
= params
? CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterRequestedSize
) : NULL
;
732 if (value
== NULL
|| CFGetTypeID(value
) != CFNumberGetTypeID() ||
733 !CFNumberGetValue(CFNumberRef(value
), kCFNumberCFIndexType
, &requestedLength
)) {
734 MacOSError::throwMe(errSecParam
);
736 value
= CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterSharedInfo
);
737 if (value
!= NULL
&& CFGetTypeID(value
) == CFDataGetTypeID()) {
738 sharedInfo
= CssmData(CFDataRef(value
));
743 CssmClient::DeriveKey
derive(keyItem
->csp(), baseAlgorithm
, CSSM_ALGID_AES
, uint32(requestedLength
* 8));
744 derive
.key(keyItem
->key());
745 derive
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DERIVE
, kSecCredentialTypeDefault
));
746 derive
.salt(sharedInfo
);
747 CssmData
param(CFRef
<CFDataRef
>::check(in1
, errSecParam
));
748 Key derivedKey
= derive(¶m
, KeySpec(CSSM_KEYUSE_ANY
, CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
));
750 // Export raw data of newly derived key (by wrapping with an empty key).
751 CssmClient::WrapKey
wrapper(keyItem
->csp(), CSSM_ALGID_NONE
);
752 Key wrappedKey
= wrapper(derivedKey
);
753 result
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)wrappedKey
->data(), CFIndex(wrappedKey
->length()));
763 static Boolean
SecCDSAKeyIsEqual(SecKeyRef key1
, SecKeyRef key2
) {
765 BEGIN_SECKEYAPI(Boolean
, false)
767 result
= key1
->key
->equal(*key2
->key
);
772 static Boolean
SecCDSAKeySetParameter(SecKeyRef key
, CFStringRef name
, CFPropertyListRef value
, CFErrorRef
*error
) {
773 BEGIN_SECKEYAPI(Boolean
, false)
775 if (CFEqual(name
, kSecUseAuthenticationUI
)) {
776 key
->credentialType
= CFEqual(value
, kSecUseAuthenticationUIAllow
) ? kSecCredentialTypeDefault
: kSecCredentialTypeNoUI
;
779 result
= SecError(errSecUnimplemented
, error
, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name
);
785 const SecKeyDescriptor kSecCDSAKeyDescriptor
= {
786 .version
= kSecKeyDescriptorVersion
,
789 .init
= SecCDSAKeyInit
,
790 .destroy
= SecCDSAKeyDestroy
,
791 .blockSize
= SecCDSAKeyGetBlockSize
,
792 .getAlgorithmID
= SecCDSAKeyGetAlgorithmId
,
793 .copyDictionary
= SecCDSAKeyCopyAttributeDictionary
,
794 .copyPublic
= SecCDSAKeyCopyPublicBytes
,
795 .copyExternalRepresentation
= SecCDSAKeyCopyExternalRepresentation
,
796 .copyPublicKey
= SecCDSAKeyCopyPublicKey
,
797 .copyOperationResult
= SecCDSAKeyCopyOperationResult
,
798 .isEqual
= SecCDSAKeyIsEqual
,
799 .setParameter
= SecCDSAKeySetParameter
,
803 namespace KeychainCore
{
804 SecCFObject
*KeyItem::fromSecKeyRef(CFTypeRef ptr
) {
805 if (ptr
== NULL
|| CFGetTypeID(ptr
) != SecKeyGetTypeID()) {
809 SecKeyRef key
= static_cast<SecKeyRef
>(const_cast<void *>(ptr
));
810 if (key
->key_class
== &kSecCDSAKeyDescriptor
) {
811 return static_cast<SecCFObject
*>(key
->key
);
814 if (key
->cdsaKey
== NULL
) {
815 // Create CDSA key from exported data of existing key.
816 CFRef
<CFDataRef
> keyData
= SecKeyCopyExternalRepresentation(key
, NULL
);
817 CFRef
<CFDictionaryRef
> keyAttributes
= SecKeyCopyAttributes(key
);
818 if (keyData
&& keyAttributes
) {
819 key
->cdsaKey
= SecKeyCreateFromData(keyAttributes
, keyData
, NULL
);
823 return (key
->cdsaKey
!= NULL
) ? key
->cdsaKey
->key
: NULL
;
826 // You need to hold this key's MutexForObject when you run this
827 void KeyItem::attachSecKeyRef() const {
828 SecKeyRef key
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, reinterpret_cast<const uint8_t *>(this), 0, 0);
829 key
->key
->mWeakSecKeyRef
= key
;
835 extern "C" Boolean
SecKeyIsCDSAKey(SecKeyRef ref
);
836 Boolean
SecKeyIsCDSAKey(SecKeyRef ref
) {
837 return ref
->key_class
== &kSecCDSAKeyDescriptor
;
841 static OSStatus
SecKeyCreatePairInternal(
842 SecKeychainRef keychainRef
,
843 CSSM_ALGORITHMS algorithm
,
844 uint32 keySizeInBits
,
845 CSSM_CC_HANDLE contextHandle
,
846 CSSM_KEYUSE publicKeyUsage
,
847 uint32 publicKeyAttr
,
848 CSSM_KEYUSE privateKeyUsage
,
849 uint32 privateKeyAttr
,
850 SecAccessRef initialAccess
,
851 SecKeyRef
* publicKeyRef
,
852 SecKeyRef
* privateKeyRef
)
857 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
858 SecPointer
<KeyItem
> pubItem
, privItem
;
859 if (((publicKeyAttr
| privateKeyAttr
) & CSSM_KEYATTR_PERMANENT
) != 0) {
860 keychain
= Keychain::optional(keychainRef
);
862 StMaybeLock
<Mutex
> _(keychain
? keychain
->getKeychainMutex() : NULL
);
863 KeyItem::createPair(keychain
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, publicKeyAttr
,
864 privateKeyUsage
, privateKeyAttr
, theAccess
, pubItem
, privItem
);
866 // Return the generated keys.
868 *publicKeyRef
= pubItem
->handle();
870 *privateKeyRef
= privItem
->handle();
877 SecKeychainRef keychainRef
,
878 CSSM_ALGORITHMS algorithm
,
879 uint32 keySizeInBits
,
880 CSSM_CC_HANDLE contextHandle
,
881 CSSM_KEYUSE publicKeyUsage
,
882 uint32 publicKeyAttr
,
883 CSSM_KEYUSE privateKeyUsage
,
884 uint32 privateKeyAttr
,
885 SecAccessRef initialAccess
,
886 SecKeyRef
* publicKeyRef
,
887 SecKeyRef
* privateKeyRef
)
889 OSStatus result
= SecKeyCreatePairInternal(keychainRef
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
,
890 publicKeyAttr
, privateKeyUsage
, privateKeyAttr
, initialAccess
, publicKeyRef
, privateKeyRef
);
898 SecKeyGetCSSMKey(SecKeyRef key
, const CSSM_KEY
**cssmKey
)
902 Required(cssmKey
) = KeyItem::required(key
)->key();
912 static ModuleNexus
<Mutex
> gSecReturnedKeyCSPsMutex
;
913 static std::set
<CssmClient::CSP
> gSecReturnedKeyCSPs
;
916 SecKeyGetCSPHandle(SecKeyRef keyRef
, CSSM_CSP_HANDLE
*cspHandle
)
920 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
922 // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP).
923 // Keep a global pointer to it to force the CSP to stay live forever.
924 CssmClient::CSP returnedKeyCSP
= keyItem
->csp();
926 StLock
<Mutex
> _(gSecReturnedKeyCSPsMutex());
927 gSecReturnedKeyCSPs
.insert(returnedKeyCSP
);
929 Required(cspHandle
) = returnedKeyCSP
->handle();
934 /* deprecated as of 10.8 */
936 SecKeyGetAlgorithmID(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
**algid
)
940 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
941 Required(algid
) = &keyItem
->algorithmIdentifier();
947 SecKeyGetStrengthInBits(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
*algid
, unsigned int *strength
)
951 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
952 Required(strength
) = keyItem
->strengthInBits(algid
);
958 SecKeyGetCredentials(
960 CSSM_ACL_AUTHORIZATION_TAG operation
,
961 SecCredentialType credentialType
,
962 const CSSM_ACCESS_CREDENTIALS
**outCredentials
)
966 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
967 Required(outCredentials
) = keyItem
->getCredentials(operation
, credentialType
);
974 SecKeychainRef keychainRef
,
975 const CSSM_KEY
*publicCssmKey
,
976 const CSSM_KEY
*privateCssmKey
,
977 SecAccessRef initialAccess
,
978 SecKeyRef
* publicKey
,
979 SecKeyRef
* privateKey
)
983 Keychain keychain
= Keychain::optional(keychainRef
);
984 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
985 SecPointer
<KeyItem
> pubItem
, privItem
;
987 KeyItem::importPair(keychain
,
988 Required(publicCssmKey
),
989 Required(privateCssmKey
),
994 // Return the generated keys.
996 *publicKey
= pubItem
->handle();
998 *privateKey
= privItem
->handle();
1004 SecKeyGenerateWithAttributes(
1005 SecKeychainAttributeList
* attrList
,
1006 SecKeychainRef keychainRef
,
1007 CSSM_ALGORITHMS algorithm
,
1008 uint32 keySizeInBits
,
1009 CSSM_CC_HANDLE contextHandle
,
1010 CSSM_KEYUSE keyUsage
,
1012 SecAccessRef initialAccess
,
1018 SecPointer
<Access
> theAccess
;
1021 keychain
= KeychainImpl::required(keychainRef
);
1023 theAccess
= Access::required(initialAccess
);
1025 SecPointer
<KeyItem
> item
= KeyItem::generateWithAttributes(attrList
,
1034 // Return the generated key.
1036 *keyRef
= item
->handle();
1043 SecKeychainRef keychainRef
,
1044 CSSM_ALGORITHMS algorithm
,
1045 uint32 keySizeInBits
,
1046 CSSM_CC_HANDLE contextHandle
,
1047 CSSM_KEYUSE keyUsage
,
1049 SecAccessRef initialAccess
,
1052 return SecKeyGenerateWithAttributes(NULL
,
1053 keychainRef
, algorithm
, keySizeInBits
,
1054 contextHandle
, keyUsage
, keyAttr
,
1055 initialAccess
, keyRef
);
1059 /* Generate a floating key reference from a CSSM_KEY */
1061 SecKeyCreateWithCSSMKey(const CSSM_KEY
*cssmKey
,
1067 if(cssmKey
->KeyData
.Length
== 0){
1068 MacOSError::throwMe(errSecInvalidAttributeKeyLength
);
1070 if(cssmKey
->KeyData
.Data
== NULL
){
1071 MacOSError::throwMe(errSecInvalidPointer
);
1073 CssmClient::CSP
csp(cssmKey
->KeyHeader
.CspId
);
1074 CssmClient::Key
key(csp
, *cssmKey
);
1075 KeyItem
*item
= new KeyItem(key
);
1077 // Return the generated key.
1079 *keyRef
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, (const uint8_t *)item
, 0, 0);
1086 static u_int32_t
ConvertCFStringToInteger(CFStringRef ref
)
1093 // figure out the size of the string
1094 CFIndex numChars
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref
), kCFStringEncodingUTF8
);
1095 char *buffer
= (char *)malloc(numChars
);
1096 if (NULL
== buffer
) {
1097 UnixError::throwMe(ENOMEM
);
1099 if (!CFStringGetCString(ref
, buffer
, numChars
, kCFStringEncodingUTF8
))
1102 MacOSError::throwMe(errSecParam
);
1105 u_int32_t result
= atoi(buffer
);
1112 static OSStatus
CheckAlgorithmType(CFDictionaryRef parameters
, CSSM_ALGORITHMS
&algorithms
)
1114 // figure out the algorithm to use
1115 CFStringRef ktype
= (CFStringRef
) CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
1121 if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
1122 algorithms
= CSSM_ALGID_RSA
;
1123 return errSecSuccess
;
1124 } else if(CFEqual(ktype
, kSecAttrKeyTypeECDSA
) ||
1125 CFEqual(ktype
, kSecAttrKeyTypeEC
)) {
1126 algorithms
= CSSM_ALGID_ECDSA
;
1127 return errSecSuccess
;
1128 } else if(CFEqual(ktype
, kSecAttrKeyTypeAES
)) {
1129 algorithms
= CSSM_ALGID_AES
;
1130 return errSecSuccess
;
1131 } else if(CFEqual(ktype
, kSecAttrKeyType3DES
)) {
1132 algorithms
= CSSM_ALGID_3DES
;
1133 return errSecSuccess
;
1135 return errSecUnsupportedAlgorithm
;
1141 static OSStatus
GetKeySize(CFDictionaryRef parameters
, CSSM_ALGORITHMS algorithms
, uint32
&keySizeInBits
)
1144 // get the key size and check it for validity
1145 CFTypeRef ref
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
1147 keySizeInBits
= kSecDefaultKeySize
;
1149 CFTypeID bitSizeType
= CFGetTypeID(ref
);
1150 if (bitSizeType
== CFStringGetTypeID())
1151 keySizeInBits
= ConvertCFStringToInteger((CFStringRef
) ref
);
1152 else if (bitSizeType
== CFNumberGetTypeID())
1153 CFNumberGetValue((CFNumberRef
) ref
, kCFNumberSInt32Type
, &keySizeInBits
);
1154 else return errSecParam
;
1157 switch (algorithms
) {
1158 case CSSM_ALGID_ECDSA
:
1159 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecp256r1
;
1160 if(keySizeInBits
== kSecp192r1
|| keySizeInBits
== kSecp256r1
|| keySizeInBits
== kSecp384r1
|| keySizeInBits
== kSecp521r1
) return errSecSuccess
;
1162 case CSSM_ALGID_RSA
:
1163 if(keySizeInBits
% 8) return errSecParam
;
1164 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= 2048;
1165 if(keySizeInBits
>= kSecRSAMin
&& keySizeInBits
<= kSecRSAMax
) return errSecSuccess
;
1167 case CSSM_ALGID_AES
:
1168 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecAES128
;
1169 if(keySizeInBits
== kSecAES128
|| keySizeInBits
== kSecAES192
|| keySizeInBits
== kSecAES256
) return errSecSuccess
;
1171 case CSSM_ALGID_3DES
:
1172 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSec3DES192
;
1173 if(keySizeInBits
== kSec3DES192
) return errSecSuccess
;
1192 struct ParameterAttribute
1194 const CFStringRef
*name
;
1200 static ParameterAttribute gAttributes
[] =
1207 &kSecAttrIsPermanent
,
1211 &kSecAttrApplicationTag
,
1215 &kSecAttrEffectiveKeySize
,
1219 &kSecAttrCanEncrypt
,
1223 &kSecAttrCanDecrypt
,
1244 const int kNumberOfAttributes
= sizeof(gAttributes
) / sizeof(ParameterAttribute
);
1246 static OSStatus
ScanDictionaryForParameters(CFDictionaryRef parameters
, void* attributePointers
[])
1249 for (i
= 0; i
< kNumberOfAttributes
; ++i
)
1251 // see if the corresponding tag exists in the dictionary
1252 CFTypeRef value
= CFDictionaryGetValue(parameters
, *(gAttributes
[i
].name
));
1255 switch (gAttributes
[i
].type
)
1258 // just return the value
1259 *(CFTypeRef
*) attributePointers
[i
] = value
;
1264 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1265 *(bool*) attributePointers
[i
] = CFBooleanGetValue(bRef
);
1271 CFNumberRef nRef
= (CFNumberRef
) value
;
1272 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, attributePointers
[i
]);
1279 return errSecSuccess
;
1284 static OSStatus
GetKeyParameters(CFDictionaryRef parameters
, int keySize
, bool isPublic
, CSSM_KEYUSE
&keyUse
, uint32
&attrs
, CFTypeRef
&labelRef
, CFDataRef
&applicationTagRef
)
1286 // establish default values
1288 bool isPermanent
= false;
1289 applicationTagRef
= NULL
;
1290 CFTypeRef effectiveKeySize
= NULL
;
1291 bool canDecrypt
= isPublic
? false : true;
1292 bool canEncrypt
= !canDecrypt
;
1293 bool canDerive
= true;
1294 bool canSign
= isPublic
? false : true;
1295 bool canVerify
= !canSign
;
1296 bool canUnwrap
= isPublic
? false : true;
1297 attrs
= CSSM_KEYATTR_EXTRACTABLE
;
1300 void* attributePointers
[] = {&labelRef
, &isPermanent
, &applicationTagRef
, &effectiveKeySize
, &canEncrypt
, &canDecrypt
,
1301 &canDerive
, &canSign
, &canVerify
, &canUnwrap
};
1303 // look for modifiers in the general dictionary
1304 OSStatus result
= ScanDictionaryForParameters(parameters
, attributePointers
);
1305 if (result
!= errSecSuccess
)
1310 // see if we have anything which modifies the defaults
1314 key
= kSecPublicKeyAttrs
;
1318 key
= kSecPrivateKeyAttrs
;
1321 CFTypeRef dType
= CFDictionaryGetValue(parameters
, key
);
1324 // this had better be a dictionary
1325 if (CFGetTypeID(dType
) != CFDictionaryGetTypeID())
1330 // pull any additional parameters out of this dictionary
1331 result
= ScanDictionaryForParameters((CFDictionaryRef
)dType
, attributePointers
);
1332 if (result
!= errSecSuccess
)
1338 // figure out the key usage
1342 keyUse
|= CSSM_KEYUSE_DECRYPT
;
1347 keyUse
|= CSSM_KEYUSE_ENCRYPT
;
1352 keyUse
|= CSSM_KEYUSE_DERIVE
;
1357 keyUse
|= CSSM_KEYUSE_SIGN
;
1362 keyUse
|= CSSM_KEYUSE_VERIFY
;
1367 keyUse
|= CSSM_KEYUSE_UNWRAP
;
1370 // public key is always extractable;
1371 // private key is extractable by default unless explicitly set to false
1372 CFTypeRef value
= NULL
;
1373 if (!isPublic
&& CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
) && value
)
1375 Boolean keyIsExtractable
= CFEqual(kCFBooleanTrue
, value
);
1376 if (!keyIsExtractable
)
1381 attrs
|= CSSM_KEYATTR_PERMANENT
;
1384 return errSecSuccess
;
1389 static OSStatus
MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters
,
1390 CSSM_ALGORITHMS
&algorithms
,
1391 uint32
&keySizeInBits
,
1392 CSSM_KEYUSE
&publicKeyUse
,
1393 uint32
&publicKeyAttr
,
1394 CFTypeRef
&publicKeyLabelRef
,
1395 CFDataRef
&publicKeyAttributeTagRef
,
1396 CSSM_KEYUSE
&privateKeyUse
,
1397 uint32
&privateKeyAttr
,
1398 CFTypeRef
&privateKeyLabelRef
,
1399 CFDataRef
&privateKeyAttributeTagRef
,
1400 SecAccessRef
&initialAccess
)
1404 result
= CheckAlgorithmType(parameters
, algorithms
);
1405 if (result
!= errSecSuccess
)
1410 result
= GetKeySize(parameters
, algorithms
, keySizeInBits
);
1411 if (result
!= errSecSuccess
)
1416 result
= GetKeyParameters(parameters
, keySizeInBits
, false, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1417 if (result
!= errSecSuccess
)
1422 result
= GetKeyParameters(parameters
, keySizeInBits
, true, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1423 if (result
!= errSecSuccess
)
1428 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&initialAccess
))
1430 initialAccess
= NULL
;
1432 else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess
))
1437 return errSecSuccess
;
1442 static OSStatus
SetKeyLabelAndTag(SecKeyRef keyRef
, CFTypeRef label
, CFDataRef tag
)
1444 int numToModify
= 0;
1455 if (numToModify
== 0)
1457 return errSecSuccess
;
1460 SecKeychainAttributeList attrList
;
1461 SecKeychainAttribute attributes
[numToModify
];
1468 if (CFStringGetTypeID() == CFGetTypeID(label
)) {
1469 CFStringRef label_string
= static_cast<CFStringRef
>(label
);
1470 attributes
[i
].tag
= kSecKeyPrintName
;
1471 attributes
[i
].data
= (void*) CFStringGetCStringPtr(label_string
, kCFStringEncodingUTF8
);
1472 if (NULL
== attributes
[i
].data
) {
1473 CFIndex buffer_length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string
), kCFStringEncodingUTF8
);
1474 data
= attributes
[i
].data
= malloc((size_t)buffer_length
);
1475 if (NULL
== attributes
[i
].data
) {
1476 UnixError::throwMe(ENOMEM
);
1478 if (!CFStringGetCString(label_string
, static_cast<char *>(attributes
[i
].data
), buffer_length
, kCFStringEncodingUTF8
)) {
1480 MacOSError::throwMe(errSecParam
);
1483 attributes
[i
].length
= (UInt32
)strlen(static_cast<char *>(attributes
[i
].data
));
1484 } else if (CFDataGetTypeID() == CFGetTypeID(label
)) {
1485 // 10.6 bug compatibility
1486 CFDataRef label_data
= static_cast<CFDataRef
>(label
);
1487 attributes
[i
].tag
= kSecKeyLabel
;
1488 attributes
[i
].data
= (void*) CFDataGetBytePtr(label_data
);
1489 attributes
[i
].length
= (UInt32
)CFDataGetLength(label_data
);
1491 MacOSError::throwMe(errSecParam
);
1498 attributes
[i
].tag
= kSecKeyApplicationTag
;
1499 attributes
[i
].data
= (void*) CFDataGetBytePtr(tag
);
1500 attributes
[i
].length
= (UInt32
)CFDataGetLength(tag
);
1504 attrList
.count
= numToModify
;
1505 attrList
.attr
= attributes
;
1507 OSStatus result
= SecKeychainItemModifyAttributesAndData((SecKeychainItemRef
) keyRef
, &attrList
, 0, NULL
);
1517 static CFTypeRef
GetAttributeFromParams(CFDictionaryRef parameters
, CFTypeRef attr
, CFTypeRef subParams
) {
1518 if (subParams
!= NULL
) {
1519 CFDictionaryRef subParamsDict
= (CFDictionaryRef
)CFDictionaryGetValue(parameters
, subParams
);
1520 if (subParamsDict
!= NULL
) {
1521 CFTypeRef value
= CFDictionaryGetValue(subParamsDict
, attr
);
1522 if (value
!= NULL
) {
1527 return CFDictionaryGetValue(parameters
, attr
);
1530 extern "C" OSStatus
SecKeyGeneratePair_ios(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
);
1533 /* Generate a private/public keypair. */
1535 SecKeyGeneratePairInternal(
1536 bool alwaysPermanent
,
1537 CFDictionaryRef parameters
,
1538 SecKeyRef
*publicKey
,
1539 SecKeyRef
*privateKey
)
1543 Required(parameters
);
1544 Required(publicKey
);
1545 Required(privateKey
);
1547 CFTypeRef tokenID
= GetAttributeFromParams(parameters
, kSecAttrTokenID
, NULL
);
1548 CFTypeRef noLegacy
= GetAttributeFromParams(parameters
, kSecAttrNoLegacy
, NULL
);
1549 CFTypeRef sync
= GetAttributeFromParams(parameters
, kSecAttrSynchronizable
, kSecPrivateKeyAttrs
);
1550 CFTypeRef accessControl
= GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPrivateKeyAttrs
) ?:
1551 GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPublicKeyAttrs
);
1552 CFTypeRef accessGroup
= GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPrivateKeyAttrs
) ?:
1553 GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPublicKeyAttrs
);
1555 // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain).
1556 if (tokenID
!= NULL
||
1557 (noLegacy
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)noLegacy
)) ||
1558 (sync
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)sync
)) ||
1559 accessControl
!= NULL
|| (accessGroup
!= NULL
&& CFEqual(accessGroup
, kSecAttrAccessGroupToken
))) {
1560 // Generate keys in iOS keychain.
1561 return SecKeyGeneratePair_ios(parameters
, publicKey
, privateKey
);
1564 CSSM_ALGORITHMS algorithms
;
1565 uint32 keySizeInBits
;
1566 CSSM_KEYUSE publicKeyUse
;
1567 uint32 publicKeyAttr
;
1568 CFTypeRef publicKeyLabelRef
;
1569 CFDataRef publicKeyAttributeTagRef
;
1570 CSSM_KEYUSE privateKeyUse
;
1571 uint32 privateKeyAttr
;
1572 CFTypeRef privateKeyLabelRef
;
1573 CFDataRef privateKeyAttributeTagRef
;
1574 SecAccessRef initialAccess
;
1575 SecKeychainRef keychain
;
1577 OSStatus result
= MakeKeyGenParametersFromDictionary(parameters
, algorithms
, keySizeInBits
, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
,
1578 publicKeyAttributeTagRef
, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
,
1581 if (result
!= errSecSuccess
) {
1585 // verify keychain parameter
1586 keychain
= (SecKeychainRef
)CFDictionaryGetValue(parameters
, kSecUseKeychain
);
1587 if (keychain
!= NULL
&& SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1591 if (alwaysPermanent
) {
1592 publicKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1593 privateKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1596 // do the key generation
1597 result
= SecKeyCreatePair(keychain
, algorithms
, keySizeInBits
, 0, publicKeyUse
, publicKeyAttr
, privateKeyUse
, privateKeyAttr
, initialAccess
, publicKey
, privateKey
);
1598 if (result
!= errSecSuccess
) {
1602 // set the label and print attributes on the keys
1603 SetKeyLabelAndTag(*publicKey
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1604 SetKeyLabelAndTag(*privateKey
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1611 SecKeyGeneratePair(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
1612 return SecKeyGeneratePairInternal(true, parameters
, publicKey
, privateKey
);
1616 SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef
*error
) {
1617 SecKeyRef privateKey
= NULL
, publicKey
= NULL
;
1618 OSStatus status
= SecKeyGeneratePairInternal(false, parameters
, &publicKey
, &privateKey
);
1619 SecError(status
, error
, CFSTR("failed to generate asymmetric keypair"));
1620 if (publicKey
!= NULL
) {
1621 CFRelease(publicKey
);
1626 OSStatus
SecKeyRawVerifyOSX(
1627 SecKeyRef key
, /* Public key */
1628 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
1629 const uint8_t *signedData
, /* signature over this data */
1630 size_t signedDataLen
, /* length of dataToSign */
1631 const uint8_t *sig
, /* signature */
1634 return SecKeyRawVerify(key
,padding
,signedData
,signedDataLen
,sig
,sigLen
);
1642 utilGetStringFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, CFTypeRef defaultValue
)
1644 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1645 if (value
!= NULL
) return value
;
1646 return defaultValue
;
1650 utilGetNumberFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t defaultValue
)
1652 uint32_t integerValue
;
1653 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1654 if (value
!= NULL
) {
1655 CFNumberRef nRef
= (CFNumberRef
) value
;
1656 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, &integerValue
);
1657 return integerValue
;
1659 return defaultValue
;
1663 utilGetMaskValFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t maskValue
)
1665 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1666 if (value
!= NULL
) {
1667 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1668 if(CFBooleanGetValue(bRef
)) return maskValue
;
1674 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters
, CSSM_ALGORITHMS
*algorithm
, uint32
*keySizeInBits
, CSSM_KEYUSE
*keyUsage
, CSSM_KEYCLASS
*keyClass
)
1676 CFTypeRef algorithmDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeAES
);
1677 CFTypeRef keyClassDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1679 if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeAES
)) {
1680 *algorithm
= CSSM_ALGID_AES
;
1681 *keySizeInBits
= 128;
1682 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1683 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDES
)) {
1684 *algorithm
= CSSM_ALGID_DES
;
1685 *keySizeInBits
= 128;
1686 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1687 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyType3DES
)) {
1688 *algorithm
= CSSM_ALGID_3DES_3KEY_EDE
;
1689 *keySizeInBits
= 128;
1690 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1691 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC4
)) {
1692 *algorithm
= CSSM_ALGID_RC4
;
1693 *keySizeInBits
= 128;
1694 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1695 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC2
)) {
1696 *algorithm
= CSSM_ALGID_RC2
;
1697 *keySizeInBits
= 128;
1698 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1699 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeCAST
)) {
1700 *algorithm
= CSSM_ALGID_CAST
;
1701 *keySizeInBits
= 128;
1702 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1703 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRSA
)) {
1704 *algorithm
= CSSM_ALGID_RSA
;
1705 *keySizeInBits
= 128;
1706 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1707 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDSA
)) {
1708 *algorithm
= CSSM_ALGID_DSA
;
1709 *keySizeInBits
= 128;
1710 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1711 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeECDSA
) ||
1712 CFEqual(algorithmDictValue
, kSecAttrKeyTypeEC
)) {
1713 *algorithm
= CSSM_ALGID_ECDSA
;
1714 *keySizeInBits
= 128;
1715 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1717 *algorithm
= CSSM_ALGID_AES
;
1718 *keySizeInBits
= 128;
1719 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1722 if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPublic
)) {
1723 *keyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
1724 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPrivate
)) {
1725 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1726 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassSymmetric
)) {
1727 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1730 *keySizeInBits
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, *keySizeInBits
);
1731 *keyUsage
= utilGetMaskValFromCFDict(parameters
, kSecAttrCanEncrypt
, CSSM_KEYUSE_ENCRYPT
) |
1732 utilGetMaskValFromCFDict(parameters
, kSecAttrCanDecrypt
, CSSM_KEYUSE_DECRYPT
) |
1733 utilGetMaskValFromCFDict(parameters
, kSecAttrCanWrap
, CSSM_KEYUSE_WRAP
) |
1734 utilGetMaskValFromCFDict(parameters
, kSecAttrCanUnwrap
, CSSM_KEYUSE_UNWRAP
);
1737 if(*keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
|| *keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
) {
1738 *keyUsage
|= utilGetMaskValFromCFDict(parameters
, kSecAttrCanSign
, CSSM_KEYUSE_SIGN
) |
1739 utilGetMaskValFromCFDict(parameters
, kSecAttrCanVerify
, CSSM_KEYUSE_VERIFY
);
1742 if(*keyUsage
== 0) {
1743 switch (*keyClass
) {
1744 case CSSM_KEYCLASS_PRIVATE_KEY
:
1745 *keyUsage
= CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
;
1747 case CSSM_KEYCLASS_PUBLIC_KEY
:
1748 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
;
1751 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
;
1758 utilCopyDefaultKeyLabel(void)
1760 // generate a default label from the current date
1761 CFDateRef dateNow
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent());
1762 CFStringRef defaultLabel
= CFCopyDescription(dateNow
);
1765 return defaultLabel
;
1769 SecKeyGenerateSymmetric(CFDictionaryRef parameters
, CFErrorRef
*error
)
1771 OSStatus result
= errSecParam
; // default result for an early exit
1772 SecKeyRef key
= NULL
;
1773 SecKeychainRef keychain
= NULL
;
1774 SecAccessRef access
;
1776 CFStringRef appLabel
;
1778 CFStringRef dateLabel
= NULL
;
1780 CSSM_ALGORITHMS algorithm
;
1781 uint32 keySizeInBits
;
1782 CSSM_KEYUSE keyUsage
;
1783 uint32 keyAttr
= CSSM_KEYATTR_RETURN_DEFAULT
;
1784 CSSM_KEYCLASS keyClass
;
1786 Boolean isPermanent
;
1787 Boolean isExtractable
;
1789 // verify keychain parameter
1790 if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
))
1792 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1799 // verify permanent parameter
1800 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsPermanent
, (const void **)&value
))
1801 isPermanent
= false;
1802 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1805 isPermanent
= CFEqual(kCFBooleanTrue
, value
);
1807 if (keychain
== NULL
) {
1808 // no keychain was specified, so use the default keychain
1809 result
= SecKeychainCopyDefault(&keychain
);
1811 keyAttr
|= CSSM_KEYATTR_PERMANENT
;
1814 // verify extractable parameter
1815 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
))
1816 isExtractable
= true; // default to extractable if value not specified
1817 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1820 isExtractable
= CFEqual(kCFBooleanTrue
, value
);
1822 keyAttr
|= CSSM_KEYATTR_EXTRACTABLE
;
1824 // verify access parameter
1825 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&access
))
1827 else if (SecAccessGetTypeID() != CFGetTypeID(access
))
1830 // verify label parameter
1831 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrLabel
, (const void **)&label
))
1832 label
= (dateLabel
= utilCopyDefaultKeyLabel()); // no label provided, so use default
1833 else if (CFStringGetTypeID() != CFGetTypeID(label
))
1836 // verify application label parameter
1837 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationLabel
, (const void **)&appLabel
))
1838 appLabel
= (dateLabel
) ? dateLabel
: (dateLabel
= utilCopyDefaultKeyLabel());
1839 else if (CFStringGetTypeID() != CFGetTypeID(appLabel
))
1842 // verify application tag parameter
1843 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationTag
, (const void **)&appTag
))
1845 else if (CFStringGetTypeID() != CFGetTypeID(appTag
))
1848 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1851 // the generated key will not be stored in any keychain
1852 result
= SecKeyGenerate(keychain
, algorithm
, keySizeInBits
, 0, keyUsage
, keyAttr
, access
, &key
);
1855 // we can set the label attributes on the generated key if it's a keychain item
1856 size_t labelBufLen
= (label
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label
), kCFStringEncodingUTF8
) + 1 : 1;
1857 char *labelBuf
= (char *)malloc(labelBufLen
);
1858 size_t appLabelBufLen
= (appLabel
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel
), kCFStringEncodingUTF8
) + 1 : 1;
1859 char *appLabelBuf
= (char *)malloc(appLabelBufLen
);
1860 size_t appTagBufLen
= (appTag
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag
), kCFStringEncodingUTF8
) + 1 : 1;
1861 char *appTagBuf
= (char *)malloc(appTagBufLen
);
1863 if (!label
|| !CFStringGetCString(label
, labelBuf
, labelBufLen
-1, kCFStringEncodingUTF8
))
1865 if (!appLabel
|| !CFStringGetCString(appLabel
, appLabelBuf
, appLabelBufLen
-1, kCFStringEncodingUTF8
))
1867 if (!appTag
|| !CFStringGetCString(appTag
, appTagBuf
, appTagBufLen
-1, kCFStringEncodingUTF8
))
1870 SecKeychainAttribute attrs
[] = {
1871 { kSecKeyPrintName
, (UInt32
)strlen(labelBuf
), (char *)labelBuf
},
1872 { kSecKeyLabel
, (UInt32
)strlen(appLabelBuf
), (char *)appLabelBuf
},
1873 { kSecKeyApplicationTag
, (UInt32
)strlen(appTagBuf
), (char *)appTagBuf
} };
1874 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
1875 if (!appTag
) --attributes
.count
;
1877 result
= SecKeyGenerateWithAttributes(&attributes
,
1878 keychain
, algorithm
, keySizeInBits
, 0,
1879 keyUsage
, keyAttr
, access
, &key
);
1887 if (result
&& error
) {
1888 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, result
, NULL
);
1891 CFRelease(dateLabel
);
1893 CFRelease(keychain
);
1901 SecKeyCreateFromData(CFDictionaryRef parameters
, CFDataRef keyData
, CFErrorRef
*error
)
1903 CSSM_ALGORITHMS algorithm
;
1904 uint32 keySizeInBits
;
1905 CSSM_KEYUSE keyUsage
;
1906 CSSM_KEYCLASS keyClass
;
1909 if(keyData
== NULL
|| CFDataGetLength(keyData
) == 0){
1910 MacOSError::throwMe(errSecUnsupportedKeySize
);
1913 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1915 CSSM_CSP_HANDLE cspHandle
= cuCspStartup(CSSM_FALSE
); // TRUE => CSP, FALSE => CSPDL
1917 SecKeyImportExportParameters iparam
;
1918 memset(&iparam
, 0, sizeof(iparam
));
1919 iparam
.keyUsage
= keyUsage
;
1921 CFRef
<CFDataRef
> data
;
1922 SecExternalItemType itype
;
1924 case CSSM_KEYCLASS_PRIVATE_KEY
:
1925 itype
= kSecItemTypePrivateKey
;
1927 case CSSM_KEYCLASS_PUBLIC_KEY
: {
1928 itype
= kSecItemTypePublicKey
;
1929 // Public key import expects public key in SubjPublicKey X509 format. We want to accept both bare and x509 format,
1930 // so we have to detect bare format here and extend to full X509 if detected.
1931 data
.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm
, keySizeInBits
, keyData
));
1934 case CSSM_KEYCLASS_SESSION_KEY
:
1935 itype
= kSecItemTypeSessionKey
;
1938 itype
= kSecItemTypeUnknown
;
1942 CFMutableArrayRef ka
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1943 // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful.
1944 crtn
= impExpImportRawKey(data
? CFDataRef(data
) : keyData
, kSecFormatUnknown
, itype
, algorithm
, NULL
, cspHandle
, 0, NULL
, NULL
, ka
);
1945 if (crtn
== CSSM_OK
&& CFArrayGetCount((CFArrayRef
)ka
)) {
1946 SecKeyRef sk
= (SecKeyRef
)CFArrayGetValueAtIndex((CFArrayRef
)ka
, 0);
1953 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, crtn
? crtn
: CSSM_ERRCODE_INTERNAL_ERROR
, NULL
);
1961 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable
, dispatch_queue_t deliveryQueue
,
1962 SecKeyGeneratePairBlock result
)
1964 CFDictionaryRef parameters
= CFDictionaryCreateCopy(NULL
, parametersWhichMightBeMutiable
);
1965 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
1966 SecKeyRef publicKey
= NULL
;
1967 SecKeyRef privateKey
= NULL
;
1968 OSStatus status
= SecKeyGeneratePair(parameters
, &publicKey
, &privateKey
);
1969 dispatch_async(deliveryQueue
, ^{
1970 CFErrorRef error
= NULL
;
1971 if (errSecSuccess
!= status
) {
1972 error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, NULL
);
1974 result(publicKey
, privateKey
, error
);
1979 CFRelease(publicKey
);
1982 CFRelease(privateKey
);
1984 CFRelease(parameters
);
1989 static inline void utilClearAndFree(void *p
, size_t len
) {
1991 if(len
) bzero(p
, len
);
1997 SecKeyDeriveFromPassword(CFStringRef password
, CFDictionaryRef parameters
, CFErrorRef
*error
)
1999 CCPBKDFAlgorithm algorithm
;
2000 CFIndex passwordLen
= 0;
2001 CFDataRef keyData
= NULL
;
2002 char *thePassword
= NULL
;
2003 uint8_t *salt
= NULL
;
2004 uint8_t *derivedKey
= NULL
;
2005 size_t saltLen
= 0, derivedKeyLen
= 0;
2007 CFDataRef saltDictValue
, algorithmDictValue
;
2008 SecKeyRef retval
= NULL
;
2010 /* Pick Values from parameters */
2012 if((saltDictValue
= (CFDataRef
) CFDictionaryGetValue(parameters
, kSecAttrSalt
)) == NULL
) {
2014 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecMissingAlgorithmParms
, NULL
);
2019 derivedKeyLen
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, 128);
2020 // This value come in bits but the rest of the code treats it as bytes
2023 algorithmDictValue
= (CFDataRef
) utilGetStringFromCFDict(parameters
, kSecAttrPRF
, kSecAttrPRFHmacAlgSHA256
);
2025 rounds
= utilGetNumberFromCFDict(parameters
, kSecAttrRounds
, 0);
2027 /* Convert any remaining parameters and get the password bytes */
2029 saltLen
= CFDataGetLength(saltDictValue
);
2030 if((salt
= (uint8_t *) malloc(saltLen
)) == NULL
) {
2032 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2037 CFDataGetBytes(saltDictValue
, CFRangeMake(0, saltLen
), (UInt8
*) salt
);
2039 passwordLen
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1;
2040 if((thePassword
= (char *) malloc(passwordLen
)) == NULL
) {
2042 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2046 CFStringGetBytes(password
, CFRangeMake(0, CFStringGetLength(password
)), kCFStringEncodingUTF8
, '?', FALSE
, (UInt8
*)thePassword
, passwordLen
, &passwordLen
);
2048 if((derivedKey
= (uint8_t *) malloc(derivedKeyLen
)) == NULL
) {
2050 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2055 if(algorithmDictValue
== NULL
) {
2056 algorithm
= kCCPRFHmacAlgSHA1
; /* default */
2057 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA1
)) {
2058 algorithm
= kCCPRFHmacAlgSHA1
;
2059 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA224
)) {
2060 algorithm
= kCCPRFHmacAlgSHA224
;
2061 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA256
)) {
2062 algorithm
= kCCPRFHmacAlgSHA256
;
2063 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA384
)) {
2064 algorithm
= kCCPRFHmacAlgSHA384
;
2065 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA512
)) {
2066 algorithm
= kCCPRFHmacAlgSHA512
;
2069 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidAlgorithmParms
, NULL
);
2075 rounds
= 33333; // we need to pass back a consistent value since there's no way to record the round count.
2078 if(CCKeyDerivationPBKDF(kCCPBKDF2
, thePassword
, passwordLen
, salt
, saltLen
, algorithm
, rounds
, derivedKey
, derivedKeyLen
)) {
2080 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2085 if((keyData
= CFDataCreate(NULL
, derivedKey
, derivedKeyLen
)) != NULL
) {
2086 retval
= SecKeyCreateFromData(parameters
, keyData
, error
);
2090 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2095 utilClearAndFree(salt
, saltLen
);
2096 utilClearAndFree(thePassword
, passwordLen
);
2097 utilClearAndFree(derivedKey
, derivedKeyLen
);
2102 SecKeyWrapSymmetric(SecKeyRef keyToWrap
, SecKeyRef wrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2105 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);
2111 SecKeyUnwrapSymmetric(CFDataRef
*keyToUnwrap
, SecKeyRef unwrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2114 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);