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 <CommonCrypto/CommonKeyDerivation.h>
37 #include "SecBridge.h"
39 #include <security_keychain/Access.h>
40 #include <security_keychain/Keychains.h>
41 #include <security_keychain/KeyItem.h>
45 #include <security_cdsa_utils/cuCdsaUtils.h>
46 #include <security_cdsa_client/wrapkey.h>
47 #include <security_cdsa_client/genkey.h>
48 #include <security_cdsa_client/signclient.h>
49 #include <security_cdsa_client/cryptoclient.h>
51 #include "SecImportExportCrypto.h"
54 SecCDSAKeyInit(SecKeyRef key
, const uint8_t *keyData
, CFIndex keyDataLength
, SecKeyEncoding encoding
) {
55 key
->key
= const_cast<KeyItem
*>(reinterpret_cast<const KeyItem
*>(keyData
));
56 key
->key
->initializeWithSecKeyRef(key
);
57 key
->credentialType
= kSecCredentialTypeDefault
;
62 SecCDSAKeyDestroy(SecKeyRef keyRef
) {
63 // Note: If this key is holding the last strong reference to its keychain, the keychain will be released during this operation.
64 // If we hold the keychain's mutex (the key's 'mutexForObject') during this destruction, pthread gets upset.
65 // Hold a reference to the keychain (if it exists) until after we release the keychain's mutex.
67 KeyItem
*keyItem
= keyRef
->key
;
68 if (keyItem
== NULL
) {
69 // KeyImpl::attachSecKeyRef disconnected us from KeyItem instance, there is nothing to do for us.
73 Keychain kc
= keyItem
->keychain();
76 StMaybeLock
<Mutex
> _(keyItem
->getMutexForObject());
77 keyItem
= keyRef
->key
;
78 if (keyItem
== NULL
) {
79 // 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.
83 keyItem
->aboutToDestruct();
87 (void) kc
; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain.
91 SecCDSAKeyGetBlockSize(SecKeyRef key
) {
93 CFErrorRef
*error
= NULL
;
94 BEGIN_SECKEYAPI(size_t,0)
96 const CssmKey::Header keyHeader
= key
->key
->unverifiedKeyHeader();
97 switch(keyHeader
.algorithm())
101 result
= keyHeader
.LogicalKeySizeInBits
/ 8;
103 case CSSM_ALGID_ECDSA
:
105 /* Block size is up to 9 bytes of DER encoding for sequence of 2 integers,
106 * plus both coordinates for the point used */
107 #define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8)
108 #define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1)
109 size_t coordSize
= ECDSA_MAX_COORD_SIZE_IN_BYTES(keyHeader
.LogicalKeySizeInBits
);
110 assert(coordSize
< 256); /* size must fit in a byte for DER */
111 size_t coordDERLen
= (coordSize
> 127) ? 2 : 1;
112 size_t coordLen
= 1 + coordDERLen
+ coordSize
;
114 size_t pointSize
= 2 * coordLen
;
115 assert(pointSize
< 256); /* size must fit in a byte for DER */
116 size_t pointDERLen
= (pointSize
> 127) ? 2 : 1;
117 size_t pointLen
= 1 + pointDERLen
+ pointSize
;
123 result
= 16; /* all AES keys use 128-bit blocks */
126 case CSSM_ALGID_3DES_3KEY
:
127 result
= 8; /* all DES keys use 64-bit blocks */
130 assert(0); /* some other key algorithm */
131 result
= 16; /* FIXME: revisit this */
139 SecCDSAKeyGetAlgorithmId(SecKeyRef key
) {
141 CFErrorRef
*error
= NULL
;
142 BEGIN_SECKEYAPI(CFIndex
, 0)
144 result
= kSecNullAlgorithmID
;
145 switch (key
->key
->unverifiedKeyHeader().AlgorithmId
) {
147 result
= kSecRSAAlgorithmID
;
150 result
= kSecDSAAlgorithmID
;
152 case CSSM_ALGID_ECDSA
:
153 result
= kSecECDSAAlgorithmID
;
156 assert(0); /* other algorithms TBA */
162 static CFDataRef
SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(CFDataRef pubKeyInfo
) {
163 // First of all, consider x509 format and try to strip SubjPubKey envelope. If it fails, do not panic
164 // and export data as is.
165 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(pubKeyInfo
), CFDataGetLength(pubKeyInfo
) }, pubKeyItem
;
167 DERSubjPubKeyInfo subjPubKey
;
168 if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
,
169 DERSubjPubKeyInfoItemSpecs
,
170 &subjPubKey
, sizeof(subjPubKey
)) == DR_Success
&&
171 DERParseBitString(&subjPubKey
.pubKey
, &pubKeyItem
, &numUnused
) == DR_Success
) {
172 return CFDataCreate(kCFAllocatorDefault
, pubKeyItem
.data
, pubKeyItem
.length
);
175 return CFDataRef(CFRetain(pubKeyInfo
));
178 static CFDataRef
SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(CSSM_ALGORITHMS algorithm
, uint32 keySizeInBits
, CFDataRef pubKeyInfo
) {
179 // First check, whether X509 pubkeyinfo is already present. If not, add it according to the key type.
180 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(pubKeyInfo
), CFDataGetLength(pubKeyInfo
) };
181 DERSubjPubKeyInfo subjPubKey
;
182 if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
,
183 DERSubjPubKeyInfoItemSpecs
,
184 &subjPubKey
, sizeof(subjPubKey
)) == DR_Success
) {
185 return CFDataRef(CFRetain(pubKeyInfo
));
188 // We have always size rounded to full bytes so bitstring encodes leading 00.
189 CFRef
<CFMutableDataRef
> bitStringPubKey
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
190 CFDataSetLength(bitStringPubKey
, 1);
191 CFDataAppendBytes(bitStringPubKey
, CFDataGetBytePtr(pubKeyInfo
), CFDataGetLength(pubKeyInfo
));
192 subjPubKey
.pubKey
.data
= static_cast<DERByte
*>(const_cast<UInt8
*>(CFDataGetBytePtr(bitStringPubKey
)));
193 subjPubKey
.pubKey
.length
= CFDataGetLength(bitStringPubKey
);
195 // Encode algId according to algorithm used.
196 static const DERByte oidRSA
[] = {
197 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
199 static const DERByte oidECsecp256
[] = {
200 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
202 static const DERByte oidECsecp384
[] = {
203 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22,
205 static const DERByte oidECsecp521
[] = {
206 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23,
208 subjPubKey
.algId
.length
= 0;
209 if (algorithm
== CSSM_ALGID_RSA
) {
210 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidRSA
);
211 subjPubKey
.algId
.length
= sizeof(oidRSA
);
212 } else if (algorithm
== CSSM_ALGID_ECDSA
) {
213 if (keySizeInBits
== 256) {
214 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidECsecp256
);
215 subjPubKey
.algId
.length
= sizeof(oidECsecp256
);
216 } else if (keySizeInBits
== 384) {
217 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidECsecp384
);
218 subjPubKey
.algId
.length
= sizeof(oidECsecp256
);
219 } if (keySizeInBits
== 521) {
220 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidECsecp521
);
221 subjPubKey
.algId
.length
= sizeof(oidECsecp256
);
224 DERSize size
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
,
225 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
);
226 CFRef
<CFMutableDataRef
> keyData
= CFDataCreateMutable(kCFAllocatorDefault
, size
);
227 CFDataSetLength(keyData
, size
);
228 if (DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
,
229 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
,
230 static_cast<DERByte
*>(CFDataGetMutableBytePtr(keyData
)), &size
) == DR_Success
) {
231 CFDataSetLength(keyData
, size
);
236 return keyData
.yield();
239 static OSStatus
SecCDSAKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
*serialization
) {
241 CFErrorRef
*error
= NULL
;
242 BEGIN_SECKEYAPI(OSStatus
, errSecSuccess
)
244 const CssmKey::Header
&header
= key
->key
->key().header();
245 switch (header
.algorithm()) {
246 case CSSM_ALGID_RSA
: {
247 switch (header
.keyClass()) {
248 case CSSM_KEYCLASS_PRIVATE_KEY
: {
249 CFRef
<CFDataRef
> privKeyData
;
250 result
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, privKeyData
.take());
251 if (result
== errSecSuccess
) {
252 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(privKeyData
), CFDataGetLength(privKeyData
) };
253 DERRSAKeyPair keyPair
;
254 if (DERParseSequence(&keyItem
, DERNumRSAKeyPairItemSpecs
, DERRSAKeyPairItemSpecs
,
255 &keyPair
, sizeof(keyPair
)) == DR_Success
) {
256 DERRSAPubKeyPKCS1 pubKey
= { keyPair
.n
, keyPair
.e
};
257 DERSize size
= DERLengthOfEncodedSequence(ASN1_SEQUENCE
, &pubKey
,
258 DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
);
259 CFRef
<CFMutableDataRef
> keyData
= CFDataCreateMutable(kCFAllocatorDefault
, size
);
260 CFDataSetLength(keyData
, size
);
261 UInt8
*data
= CFDataGetMutableBytePtr(keyData
);
262 if (DEREncodeSequence(ASN1_SEQUENCE
, &pubKey
,
263 DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
,
264 data
, &size
) == DR_Success
) {
265 CFDataSetLength(keyData
, size
);
266 *data
= ONE_BYTE_ASN1_CONSTR_SEQUENCE
;
267 *serialization
= keyData
.yield();
269 *serialization
= NULL
;
270 result
= errSecParam
;
276 case CSSM_KEYCLASS_PUBLIC_KEY
:
277 result
= SecItemExport(key
, kSecFormatBSAFE
, 0, NULL
, serialization
);
282 case CSSM_ALGID_ECDSA
: {
283 *serialization
= NULL
;
284 CFRef
<CFDataRef
> tempPublicData
;
285 result
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, tempPublicData
.take());
286 if (result
== errSecSuccess
) {
287 *serialization
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(tempPublicData
);
292 result
= errSecUnimplemented
;
303 static const DERItemSpec DERECPrivateKeyItemSpecs
[] =
308 { DER_OFFSET(DERECPrivateKey
, privateKey
),
310 DER_DEC_NO_OPTS
| DER_ENC_NO_OPTS
},
312 ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0,
313 DER_DEC_SKIP
| DER_ENC_NO_OPTS
},
314 { DER_OFFSET(DERECPrivateKey
, publicKey
),
315 ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 1,
316 DER_DEC_NO_OPTS
| DER_ENC_SIGNED_INT
},
318 static const DERSize DERNumECPrivateKeyItemSpecs
=
319 sizeof(DERECPrivateKeyItemSpecs
) / sizeof(DERItemSpec
);
323 } DERECPrivateKeyPublicKey
;
325 static const DERItemSpec DERECPrivateKeyPublicKeyItemSpecs
[] =
327 { DER_OFFSET(DERECPrivateKeyPublicKey
, bitString
),
329 DER_DEC_NO_OPTS
| DER_ENC_NO_OPTS
},
331 static const DERSize DERNumECPrivateKeyPublicKeyItemSpecs
=
332 sizeof(DERECPrivateKeyPublicKeyItemSpecs
) / sizeof(DERItemSpec
);
335 SecCDSAKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef
*error
) {
337 BEGIN_SECKEYAPI(CFDataRef
, NULL
)
340 const CssmKey::Header header
= key
->key
->unverifiedKeyHeader();
341 CFRef
<CFDataRef
> keyData
;
342 switch (header
.algorithm()) {
344 MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()));
346 case CSSM_ALGID_ECDSA
: {
347 MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()));
348 if (header
.keyClass() == CSSM_KEYCLASS_PRIVATE_KEY
) {
349 // Convert DER format into x9.63 format, which is expected for exported key.
350 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
) };
351 DERECPrivateKey privateKey
;
352 DERECPrivateKeyPublicKey privateKeyPublicKey
;
355 if (DERParseSequence(&keyItem
, DERNumECPrivateKeyItemSpecs
, DERECPrivateKeyItemSpecs
,
356 &privateKey
, sizeof(privateKey
)) == DR_Success
&&
357 DERParseSequenceContent(&privateKey
.publicKey
, DERNumECPrivateKeyPublicKeyItemSpecs
,
358 DERECPrivateKeyPublicKeyItemSpecs
,
359 &privateKeyPublicKey
, sizeof(privateKeyPublicKey
)) == DR_Success
&&
360 DERParseBitString(&privateKeyPublicKey
.bitString
, &pubKeyItem
, &numUnused
) == DR_Success
) {
361 CFRef
<CFMutableDataRef
> key
= CFDataCreateMutable(kCFAllocatorDefault
,
362 pubKeyItem
.length
+ privateKey
.privateKey
.length
);
363 CFDataSetLength(key
, pubKeyItem
.length
+ privateKey
.privateKey
.length
);
364 CFDataReplaceBytes(key
, CFRangeMake(0, pubKeyItem
.length
), pubKeyItem
.data
, pubKeyItem
.length
);
365 CFDataReplaceBytes(key
, CFRangeMake(pubKeyItem
.length
, privateKey
.privateKey
.length
),
366 privateKey
.privateKey
.data
, privateKey
.privateKey
.length
);
367 keyData
= key
.as
<CFDataRef
>();
373 MacOSError::throwMe(errSecUnimplemented
);
376 if (header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
) {
377 result
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(keyData
);
379 result
= keyData
.yield();
385 static CFDataRef
SecCDSAKeyCopyLabel(SecKeyRef key
) {
386 CFDataRef label
= NULL
;
387 if (key
->key
->isPersistent()) {
388 UInt32 tags
[] = { kSecKeyLabel
}, formats
[] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB
};
389 SecKeychainAttributeInfo info
= { 1, tags
, formats
};
390 SecKeychainAttributeList
*list
= NULL
;
391 key
->key
->getAttributesAndData(&info
, NULL
, &list
, NULL
, NULL
);
392 if (list
->count
== 1) {
393 SecKeychainAttribute
*attr
= list
->attr
;
394 label
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)attr
->data
, (CFIndex
)attr
->length
);
396 key
->key
->freeAttributesAndData(list
, NULL
);
401 static CFDictionaryRef
402 SecCDSAKeyCopyAttributeDictionary(SecKeyRef key
) {
404 CFErrorRef
*error
= NULL
;
405 BEGIN_SECKEYAPI(CFDictionaryRef
, NULL
)
407 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
408 &kCFTypeDictionaryValueCallBacks
);
410 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
412 const CssmKey::Header header
= key
->key
->unverifiedKeyHeader();
413 CFIndex sizeValue
= header
.LogicalKeySizeInBits
;
414 CFRef
<CFNumberRef
> sizeInBits
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &sizeValue
);
415 CFDictionarySetValue(dict
, kSecAttrKeySizeInBits
, sizeInBits
);
416 CFDictionarySetValue(dict
, kSecAttrEffectiveKeySize
, sizeInBits
);
418 CFRef
<CFDataRef
> label
= SecCDSAKeyCopyLabel(key
);
420 // For floating keys, calculate label as SHA1 of pubkey bytes.
421 CFRef
<CFDataRef
> pubKeyBlob
;
422 if (SecCDSAKeyCopyPublicBytes(key
, pubKeyBlob
.take()) == errSecSuccess
) {
423 uint8_t pubKeyHash
[CC_SHA1_DIGEST_LENGTH
];
424 CC_SHA1(CFDataGetBytePtr(pubKeyBlob
), CC_LONG(CFDataGetLength(pubKeyBlob
)), pubKeyHash
);
425 label
.take(CFDataCreate(kCFAllocatorDefault
, pubKeyHash
, sizeof(pubKeyHash
)));
430 CFDictionarySetValue(dict
, kSecAttrApplicationLabel
, label
);
433 CSSM_KEYATTR_FLAGS attrs
= header
.attributes();
434 CFDictionarySetValue(dict
, kSecAttrIsPermanent
, (attrs
& CSSM_KEYATTR_PERMANENT
) ? kCFBooleanTrue
: kCFBooleanFalse
);
435 CFDictionarySetValue(dict
, kSecAttrIsPrivate
, (attrs
& CSSM_KEYATTR_PRIVATE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
436 CFDictionarySetValue(dict
, kSecAttrIsModifiable
, (attrs
& CSSM_KEYATTR_MODIFIABLE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
437 CFDictionarySetValue(dict
, kSecAttrIsSensitive
, (attrs
& CSSM_KEYATTR_SENSITIVE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
438 CFDictionarySetValue(dict
, kSecAttrIsExtractable
, (attrs
& CSSM_KEYATTR_EXTRACTABLE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
439 CFDictionarySetValue(dict
, kSecAttrWasAlwaysSensitive
, (attrs
& CSSM_KEYATTR_ALWAYS_SENSITIVE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
440 CFDictionarySetValue(dict
, kSecAttrWasNeverExtractable
, (attrs
& CSSM_KEYATTR_NEVER_EXTRACTABLE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
442 CFDictionarySetValue(dict
, kSecAttrCanEncrypt
, (header
.useFor(CSSM_KEYUSE_ENCRYPT
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
443 CFDictionarySetValue(dict
, kSecAttrCanDecrypt
, (header
.useFor(CSSM_KEYUSE_DECRYPT
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
444 CFDictionarySetValue(dict
, kSecAttrCanSign
, (header
.useFor(CSSM_KEYUSE_SIGN
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
445 CFDictionarySetValue(dict
, kSecAttrCanVerify
, (header
.useFor(CSSM_KEYUSE_VERIFY
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
446 CFDictionarySetValue(dict
, kSecAttrCanSignRecover
, (header
.useFor(CSSM_KEYUSE_SIGN_RECOVER
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
447 CFDictionarySetValue(dict
, kSecAttrCanVerifyRecover
, (header
.useFor(CSSM_KEYUSE_VERIFY_RECOVER
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
448 CFDictionarySetValue(dict
, kSecAttrCanWrap
, (header
.useFor(CSSM_KEYUSE_WRAP
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
449 CFDictionarySetValue(dict
, kSecAttrCanUnwrap
, (header
.useFor(CSSM_KEYUSE_UNWRAP
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
450 CFDictionarySetValue(dict
, kSecAttrCanDerive
, (header
.useFor(CSSM_KEYUSE_DERIVE
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
452 switch (header
.keyClass()) {
453 case CSSM_KEYCLASS_PUBLIC_KEY
:
454 CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
456 case CSSM_KEYCLASS_PRIVATE_KEY
:
457 CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
461 switch (header
.algorithm()) {
463 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
465 case CSSM_ALGID_ECDSA
:
466 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeECDSA
);
470 CFRef
<CFDataRef
> keyData
;
471 if (SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()) == errSecSuccess
) {
472 CFDictionarySetValue(dict
, kSecValueData
, keyData
);
475 if (header
.algorithm() == CSSM_ALGID_RSA
&& header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
&&
476 header
.blobType() == CSSM_KEYBLOB_RAW
) {
477 const CssmData
&keyData
= key
->key
->key()->keyData();
478 DERItem keyItem
= { static_cast<DERByte
*>(keyData
.data()), keyData
.length() };
479 DERRSAPubKeyPKCS1 decodedKey
;
480 if (DERParseSequence(&keyItem
, DERNumRSAPubKeyPKCS1ItemSpecs
,
481 DERRSAPubKeyPKCS1ItemSpecs
,
482 &decodedKey
, sizeof(decodedKey
)) == DR_Success
) {
483 CFRef
<CFDataRef
> modulus
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.modulus
.data
,
484 decodedKey
.modulus
.length
);
485 CFDictionarySetValue(dict
, CFSTR("_rsam"), modulus
);
486 CFRef
<CFDataRef
> exponent
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.pubExponent
.data
,
487 decodedKey
.pubExponent
.length
);
488 CFDictionarySetValue(dict
, CFSTR("_rsae"), exponent
);
497 #pragma clang diagnostic push
498 #pragma clang diagnostic ignored "-Wunused-const-variable"
499 static CSSM_DB_NAME_ATTR(kInfoKeyLabel
, kSecKeyLabel
, (char*) "Label", 0, NULL
, BLOB
);
500 #pragma clang diagnostic pop
502 static SecKeyRef
SecCDSAKeyCopyPublicKey(SecKeyRef privateKey
) {
504 BEGIN_SECKEYAPI(SecKeyRef
, NULL
)
507 KeyItem
*key
= privateKey
->key
;
508 CFRef
<CFDataRef
> label
= SecCDSAKeyCopyLabel(privateKey
);
510 // Lookup public key in the database.
511 DbUniqueRecord uniqueId
;
512 SSDb
ssDb(dynamic_cast<SSDbImpl
*>(&(*key
->keychain()->database())));
513 SSDbCursor
dbCursor(ssDb
, 1);
514 dbCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
);
515 dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, CssmData(CFDataRef(label
)));
516 if (dbCursor
->next(NULL
, NULL
, uniqueId
)) {
517 Item publicKey
= key
->keychain()->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, uniqueId
);
518 result
= reinterpret_cast<SecKeyRef
>(publicKey
->handle());
520 } else if (key
->publicKey()) {
521 KeyItem
*publicKey
= new KeyItem(key
->publicKey());
522 result
= reinterpret_cast<SecKeyRef
>(publicKey
->handle());
528 static KeyItem
*SecCDSAKeyPrepareParameters(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
,
529 CSSM_ALGORITHMS
&baseAlgorithm
, CSSM_ALGORITHMS
&secondaryAlgorithm
,
530 CSSM_ALGORITHMS
&paddingAlgorithm
, CFIndex
&inputSizeLimit
) {
531 KeyItem
*keyItem
= key
->key
;
532 CSSM_KEYCLASS keyClass
= keyItem
->key()->header().keyClass();
533 baseAlgorithm
= keyItem
->key()->header().algorithm();
534 switch (baseAlgorithm
) {
536 if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeSign
) ||
537 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeVerify
)) {
538 if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureRaw
)) {
539 secondaryAlgorithm
= CSSM_ALGID_NONE
;
540 paddingAlgorithm
= CSSM_PADDING_NONE
;
542 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
)) {
543 secondaryAlgorithm
= CSSM_ALGID_NONE
;
544 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
545 inputSizeLimit
= -11;
546 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
)) {
547 secondaryAlgorithm
= CSSM_ALGID_SHA1
;
548 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
550 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
)) {
551 secondaryAlgorithm
= CSSM_ALGID_SHA224
;
552 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
553 inputSizeLimit
= 224 / 8;
554 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
)) {
555 secondaryAlgorithm
= CSSM_ALGID_SHA256
;
556 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
557 inputSizeLimit
= 256 / 8;
558 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
)) {
559 secondaryAlgorithm
= CSSM_ALGID_SHA384
;
560 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
561 inputSizeLimit
= 384 / 8;
562 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
)) {
563 secondaryAlgorithm
= CSSM_ALGID_SHA512
;
564 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
565 inputSizeLimit
= 512 / 8;
566 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5
)) {
567 secondaryAlgorithm
= CSSM_ALGID_MD5
;
568 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
573 } else if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeDecrypt
) ||
574 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeEncrypt
)) {
575 if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionRaw
)) {
576 secondaryAlgorithm
= CSSM_ALGID_NONE
;
577 paddingAlgorithm
= CSSM_PADDING_NONE
;
579 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionPKCS1
)) {
580 secondaryAlgorithm
= CSSM_ALGID_NONE
;
581 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
582 inputSizeLimit
= operation
== kSecKeyOperationTypeEncrypt
? -11 : 0;
590 case CSSM_ALGID_ECDSA
:
591 if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeSign
) ||
592 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeVerify
)) {
593 if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureRFC4754
)) {
594 secondaryAlgorithm
= CSSM_ALGID_NONE
;
595 paddingAlgorithm
= CSSM_PADDING_SIGRAW
;
596 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureDigestX962
)) {
597 secondaryAlgorithm
= CSSM_ALGID_NONE
;
598 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
602 } else if (keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeKeyExchange
) {
603 if (CFEqual(algorithm
,kSecKeyAlgorithmECDHKeyExchangeStandard
) ||
604 CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactor
)) {
605 baseAlgorithm
= CSSM_ALGID_ECDH
;
606 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1
) ||
607 CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1
)) {
608 baseAlgorithm
= CSSM_ALGID_ECDH_X963_KDF
;
617 MacOSError::throwMe(errSecParam
);
623 SecCDSAKeyCopyPaddedPlaintext(SecKeyRef key
, CFDataRef plaintext
, SecKeyAlgorithm algorithm
) {
624 CFIndex blockSize
= key
->key
->key().header().LogicalKeySizeInBits
/ 8;
625 CFIndex plaintextLength
= CFDataGetLength(plaintext
);
626 if ((algorithm
== kSecKeyAlgorithmRSAEncryptionRaw
|| algorithm
== kSecKeyAlgorithmRSASignatureRaw
)
627 && plaintextLength
< blockSize
) {
628 // Pre-pad with zeroes.
629 CFMutableDataRef
result(CFDataCreateMutable(kCFAllocatorDefault
, blockSize
));
630 CFDataSetLength(result
, blockSize
);
631 CFDataReplaceBytes(result
, CFRangeMake(blockSize
- plaintextLength
, plaintextLength
),
632 CFDataGetBytePtr(plaintext
), plaintextLength
);
635 return CFDataRef(CFRetain(plaintext
));
639 static CFTypeRef
SecCDSAKeyCopyOperationResult(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
,
640 CFArrayRef allAlgorithms
, SecKeyOperationMode mode
,
641 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
642 BEGIN_SECKEYAPI(CFTypeRef
, kCFNull
)
643 CFIndex inputSizeLimit
= 0;
644 CSSM_ALGORITHMS baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
;
645 KeyItem
*keyItem
= SecCDSAKeyPrepareParameters(key
, operation
, algorithm
, baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
, inputSizeLimit
);
646 if (keyItem
== NULL
) {
647 // Operation/algorithm/key combination is not supported.
649 } else if (mode
== kSecKeyOperationModeCheckIfSupported
) {
650 // Operation is supported and caller wants to just know that.
651 return kCFBooleanTrue
;
652 } else if (baseAlgorithm
== CSSM_ALGID_RSA
) {
653 if (inputSizeLimit
<= 0) {
654 inputSizeLimit
+= SecCDSAKeyGetBlockSize(key
);
656 if (CFDataGetLength((CFDataRef
)in1
) > inputSizeLimit
) {
657 MacOSError::throwMe(errSecParam
);
662 case kSecKeyOperationTypeSign
: {
663 CssmClient::Sign
signContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
);
664 signContext
.key(keyItem
->key());
665 signContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN
, key
->credentialType
));
666 signContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
);
667 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
668 CssmAutoData
signature(signContext
.allocator());
669 signContext
.sign(CssmData(CFDataRef(input
)), signature
.get());
670 result
= CFDataCreate(NULL
, static_cast<const UInt8
*>(signature
.data()), CFIndex(signature
.length()));
673 case kSecKeyOperationTypeVerify
: {
674 CssmClient::Verify
verifyContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
);
675 verifyContext
.key(keyItem
->key());
676 verifyContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ANY
, key
->credentialType
));
677 verifyContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
);
678 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
679 verifyContext
.verify(CssmData(CFDataRef(input
)), CssmData(CFRef
<CFDataRef
>::check(in2
, errSecParam
)));
680 result
= kCFBooleanTrue
;
683 case kSecKeyOperationTypeEncrypt
: {
684 CssmClient::Encrypt
encryptContext(keyItem
->csp(), baseAlgorithm
);
685 encryptContext
.key(keyItem
->key());
686 encryptContext
.padding(paddingAlgorithm
);
687 encryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT
, key
->credentialType
));
688 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
689 CssmAutoData
output(encryptContext
.allocator()), remainingData(encryptContext
.allocator());
690 size_t length
= encryptContext
.encrypt(CssmData(CFDataRef(input
)), output
.get(), remainingData
.get());
691 result
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length());
692 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(output
.data()), output
.length());
693 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(remainingData
.data()), remainingData
.length());
694 CFDataSetLength(CFMutableDataRef(result
), length
);
697 case kSecKeyOperationTypeDecrypt
: {
698 CssmClient::Decrypt
decryptContext(keyItem
->csp(), baseAlgorithm
);
699 decryptContext
.key(keyItem
->key());
700 decryptContext
.padding(paddingAlgorithm
);
701 decryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT
, key
->credentialType
));
702 CssmAutoData
output(decryptContext
.allocator()), remainingData(decryptContext
.allocator());
703 size_t length
= decryptContext
.decrypt(CssmData(CFRef
<CFDataRef
>::check(in1
, errSecParam
)),
704 output
.get(), remainingData
.get());
705 result
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length());
706 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(output
.data()), output
.length());
707 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(remainingData
.data()), remainingData
.length());
708 CFDataSetLength(CFMutableDataRef(result
), length
);
711 case kSecKeyOperationTypeKeyExchange
: {
712 CFIndex requestedLength
= 0;
714 switch (baseAlgorithm
) {
715 case CSSM_ALGID_ECDH
:
716 requestedLength
= (keyItem
->key().header().LogicalKeySizeInBits
+ 7) / 8;
718 case CSSM_ALGID_ECDH_X963_KDF
:
719 CFDictionaryRef params
= CFRef
<CFDictionaryRef
>::check(in2
, errSecParam
);
720 CFTypeRef value
= params
? CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterRequestedSize
) : NULL
;
721 if (value
== NULL
|| CFGetTypeID(value
) != CFNumberGetTypeID() ||
722 !CFNumberGetValue(CFNumberRef(value
), kCFNumberCFIndexType
, &requestedLength
)) {
723 MacOSError::throwMe(errSecParam
);
725 value
= CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterSharedInfo
);
726 if (value
!= NULL
&& CFGetTypeID(value
) == CFDataGetTypeID()) {
727 sharedInfo
= CssmData(CFDataRef(value
));
732 CssmClient::DeriveKey
derive(keyItem
->csp(), baseAlgorithm
, CSSM_ALGID_AES
, uint32(requestedLength
* 8));
733 derive
.key(keyItem
->key());
734 derive
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DERIVE
, kSecCredentialTypeDefault
));
735 derive
.salt(sharedInfo
);
736 CssmData
param(CFRef
<CFDataRef
>::check(in1
, errSecParam
));
737 Key derivedKey
= derive(¶m
, KeySpec(CSSM_KEYUSE_ANY
, CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
));
739 // Export raw data of newly derived key (by wrapping with an empty key).
740 CssmClient::WrapKey
wrapper(keyItem
->csp(), CSSM_ALGID_NONE
);
741 Key wrappedKey
= wrapper(derivedKey
);
742 result
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)wrappedKey
->data(), CFIndex(wrappedKey
->length()));
752 static Boolean
SecCDSAKeyIsEqual(SecKeyRef key1
, SecKeyRef key2
) {
754 BEGIN_SECKEYAPI(Boolean
, false)
756 result
= key1
->key
->equal(*key2
->key
);
761 static Boolean
SecCDSAKeySetParameter(SecKeyRef key
, CFStringRef name
, CFPropertyListRef value
, CFErrorRef
*error
) {
762 BEGIN_SECKEYAPI(Boolean
, false)
764 if (CFEqual(name
, kSecUseAuthenticationUI
)) {
765 key
->credentialType
= CFEqual(value
, kSecUseAuthenticationUIAllow
) ? kSecCredentialTypeDefault
: kSecCredentialTypeNoUI
;
768 result
= SecError(errSecUnimplemented
, error
, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name
);
774 const SecKeyDescriptor kSecCDSAKeyDescriptor
= {
775 .version
= kSecKeyDescriptorVersion
,
778 .init
= SecCDSAKeyInit
,
779 .destroy
= SecCDSAKeyDestroy
,
780 .blockSize
= SecCDSAKeyGetBlockSize
,
781 .getAlgorithmID
= SecCDSAKeyGetAlgorithmId
,
782 .copyDictionary
= SecCDSAKeyCopyAttributeDictionary
,
783 .copyPublic
= SecCDSAKeyCopyPublicBytes
,
784 .copyExternalRepresentation
= SecCDSAKeyCopyExternalRepresentation
,
785 .copyPublicKey
= SecCDSAKeyCopyPublicKey
,
786 .copyOperationResult
= SecCDSAKeyCopyOperationResult
,
787 .isEqual
= SecCDSAKeyIsEqual
,
788 .setParameter
= SecCDSAKeySetParameter
,
792 namespace KeychainCore
{
793 SecCFObject
*KeyItem::fromSecKeyRef(CFTypeRef ptr
) {
794 if (ptr
== NULL
|| CFGetTypeID(ptr
) != SecKeyGetTypeID()) {
798 SecKeyRef key
= static_cast<SecKeyRef
>(const_cast<void *>(ptr
));
799 if (key
->key_class
== &kSecCDSAKeyDescriptor
) {
800 return static_cast<SecCFObject
*>(key
->key
);
803 if (key
->cdsaKey
== NULL
) {
804 // Create CDSA key from exported data of existing key.
805 CFRef
<CFDataRef
> keyData
= SecKeyCopyExternalRepresentation(key
, NULL
);
806 CFRef
<CFDictionaryRef
> keyAttributes
= SecKeyCopyAttributes(key
);
807 if (keyData
&& keyAttributes
) {
808 key
->cdsaKey
= SecKeyCreateFromData(keyAttributes
, keyData
, NULL
);
812 return (key
->cdsaKey
!= NULL
) ? key
->cdsaKey
->key
: NULL
;
815 // You need to hold this key's MutexForObject when you run this
816 void KeyItem::attachSecKeyRef() const {
817 SecKeyRef key
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, reinterpret_cast<const uint8_t *>(this), 0, 0);
818 key
->key
->mWeakSecKeyRef
= key
;
824 extern "C" Boolean
SecKeyIsCDSAKey(SecKeyRef ref
);
825 Boolean
SecKeyIsCDSAKey(SecKeyRef ref
) {
826 return ref
->key_class
== &kSecCDSAKeyDescriptor
;
830 static OSStatus
SecKeyCreatePairInternal(
831 SecKeychainRef keychainRef
,
832 CSSM_ALGORITHMS algorithm
,
833 uint32 keySizeInBits
,
834 CSSM_CC_HANDLE contextHandle
,
835 CSSM_KEYUSE publicKeyUsage
,
836 uint32 publicKeyAttr
,
837 CSSM_KEYUSE privateKeyUsage
,
838 uint32 privateKeyAttr
,
839 SecAccessRef initialAccess
,
840 SecKeyRef
* publicKeyRef
,
841 SecKeyRef
* privateKeyRef
)
846 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
847 SecPointer
<KeyItem
> pubItem
, privItem
;
848 if (((publicKeyAttr
| privateKeyAttr
) & CSSM_KEYATTR_PERMANENT
) != 0) {
849 keychain
= Keychain::optional(keychainRef
);
850 StLock
<Mutex
> _(*keychain
->getKeychainMutex());
851 KeyItem::createPair(keychain
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, publicKeyAttr
,
852 privateKeyUsage
, privateKeyAttr
, theAccess
, pubItem
, privItem
);
854 KeyItem::createPair(keychain
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, publicKeyAttr
,
855 privateKeyUsage
, privateKeyAttr
, theAccess
, pubItem
, privItem
);
858 // Return the generated keys.
860 *publicKeyRef
= pubItem
->handle();
862 *privateKeyRef
= privItem
->handle();
869 SecKeychainRef keychainRef
,
870 CSSM_ALGORITHMS algorithm
,
871 uint32 keySizeInBits
,
872 CSSM_CC_HANDLE contextHandle
,
873 CSSM_KEYUSE publicKeyUsage
,
874 uint32 publicKeyAttr
,
875 CSSM_KEYUSE privateKeyUsage
,
876 uint32 privateKeyAttr
,
877 SecAccessRef initialAccess
,
878 SecKeyRef
* publicKeyRef
,
879 SecKeyRef
* privateKeyRef
)
881 OSStatus result
= SecKeyCreatePairInternal(keychainRef
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
,
882 publicKeyAttr
, privateKeyUsage
, privateKeyAttr
, initialAccess
, publicKeyRef
, privateKeyRef
);
890 SecKeyGetCSSMKey(SecKeyRef key
, const CSSM_KEY
**cssmKey
)
894 Required(cssmKey
) = KeyItem::required(key
)->key();
905 SecKeyGetCSPHandle(SecKeyRef keyRef
, CSSM_CSP_HANDLE
*cspHandle
)
909 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
910 Required(cspHandle
) = keyItem
->csp()->handle();
915 /* deprecated as of 10.8 */
917 SecKeyGetAlgorithmID(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
**algid
)
921 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
922 Required(algid
) = &keyItem
->algorithmIdentifier();
928 SecKeyGetStrengthInBits(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
*algid
, unsigned int *strength
)
932 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
933 Required(strength
) = keyItem
->strengthInBits(algid
);
939 SecKeyGetCredentials(
941 CSSM_ACL_AUTHORIZATION_TAG operation
,
942 SecCredentialType credentialType
,
943 const CSSM_ACCESS_CREDENTIALS
**outCredentials
)
947 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
948 Required(outCredentials
) = keyItem
->getCredentials(operation
, credentialType
);
955 SecKeychainRef keychainRef
,
956 const CSSM_KEY
*publicCssmKey
,
957 const CSSM_KEY
*privateCssmKey
,
958 SecAccessRef initialAccess
,
959 SecKeyRef
* publicKey
,
960 SecKeyRef
* privateKey
)
964 Keychain keychain
= Keychain::optional(keychainRef
);
965 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
966 SecPointer
<KeyItem
> pubItem
, privItem
;
968 KeyItem::importPair(keychain
,
969 Required(publicCssmKey
),
970 Required(privateCssmKey
),
975 // Return the generated keys.
977 *publicKey
= pubItem
->handle();
979 *privateKey
= privItem
->handle();
985 SecKeyGenerateWithAttributes(
986 SecKeychainAttributeList
* attrList
,
987 SecKeychainRef keychainRef
,
988 CSSM_ALGORITHMS algorithm
,
989 uint32 keySizeInBits
,
990 CSSM_CC_HANDLE contextHandle
,
991 CSSM_KEYUSE keyUsage
,
993 SecAccessRef initialAccess
,
999 SecPointer
<Access
> theAccess
;
1002 keychain
= KeychainImpl::required(keychainRef
);
1004 theAccess
= Access::required(initialAccess
);
1006 SecPointer
<KeyItem
> item
= KeyItem::generateWithAttributes(attrList
,
1015 // Return the generated key.
1017 *keyRef
= item
->handle();
1024 SecKeychainRef keychainRef
,
1025 CSSM_ALGORITHMS algorithm
,
1026 uint32 keySizeInBits
,
1027 CSSM_CC_HANDLE contextHandle
,
1028 CSSM_KEYUSE keyUsage
,
1030 SecAccessRef initialAccess
,
1033 return SecKeyGenerateWithAttributes(NULL
,
1034 keychainRef
, algorithm
, keySizeInBits
,
1035 contextHandle
, keyUsage
, keyAttr
,
1036 initialAccess
, keyRef
);
1040 /* Generate a floating key reference from a CSSM_KEY */
1042 SecKeyCreateWithCSSMKey(const CSSM_KEY
*cssmKey
,
1048 if(cssmKey
->KeyData
.Length
== 0){
1049 MacOSError::throwMe(errSecInvalidAttributeKeyLength
);
1051 if(cssmKey
->KeyData
.Data
== NULL
){
1052 MacOSError::throwMe(errSecInvalidPointer
);
1054 CssmClient::CSP
csp(cssmKey
->KeyHeader
.CspId
);
1055 CssmClient::Key
key(csp
, *cssmKey
);
1056 KeyItem
*item
= new KeyItem(key
);
1058 // Return the generated key.
1060 *keyRef
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, (const uint8_t *)item
, 0, 0);
1067 static u_int32_t
ConvertCFStringToInteger(CFStringRef ref
)
1074 // figure out the size of the string
1075 CFIndex numChars
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref
), kCFStringEncodingUTF8
);
1076 char buffer
[numChars
];
1077 if (!CFStringGetCString(ref
, buffer
, numChars
, kCFStringEncodingUTF8
))
1079 MacOSError::throwMe(errSecParam
);
1082 return atoi(buffer
);
1087 static OSStatus
CheckAlgorithmType(CFDictionaryRef parameters
, CSSM_ALGORITHMS
&algorithms
)
1089 // figure out the algorithm to use
1090 CFStringRef ktype
= (CFStringRef
) CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
1096 if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
1097 algorithms
= CSSM_ALGID_RSA
;
1098 return errSecSuccess
;
1099 } else if(CFEqual(ktype
, kSecAttrKeyTypeECDSA
) ||
1100 CFEqual(ktype
, kSecAttrKeyTypeEC
)) {
1101 algorithms
= CSSM_ALGID_ECDSA
;
1102 return errSecSuccess
;
1103 } else if(CFEqual(ktype
, kSecAttrKeyTypeAES
)) {
1104 algorithms
= CSSM_ALGID_AES
;
1105 return errSecSuccess
;
1106 } else if(CFEqual(ktype
, kSecAttrKeyType3DES
)) {
1107 algorithms
= CSSM_ALGID_3DES
;
1108 return errSecSuccess
;
1110 return errSecUnsupportedAlgorithm
;
1116 static OSStatus
GetKeySize(CFDictionaryRef parameters
, CSSM_ALGORITHMS algorithms
, uint32
&keySizeInBits
)
1119 // get the key size and check it for validity
1120 CFTypeRef ref
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
1122 keySizeInBits
= kSecDefaultKeySize
;
1124 CFTypeID bitSizeType
= CFGetTypeID(ref
);
1125 if (bitSizeType
== CFStringGetTypeID())
1126 keySizeInBits
= ConvertCFStringToInteger((CFStringRef
) ref
);
1127 else if (bitSizeType
== CFNumberGetTypeID())
1128 CFNumberGetValue((CFNumberRef
) ref
, kCFNumberSInt32Type
, &keySizeInBits
);
1129 else return errSecParam
;
1132 switch (algorithms
) {
1133 case CSSM_ALGID_ECDSA
:
1134 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecp256r1
;
1135 if(keySizeInBits
== kSecp192r1
|| keySizeInBits
== kSecp256r1
|| keySizeInBits
== kSecp384r1
|| keySizeInBits
== kSecp521r1
) return errSecSuccess
;
1137 case CSSM_ALGID_RSA
:
1138 if(keySizeInBits
% 8) return errSecParam
;
1139 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= 2048;
1140 if(keySizeInBits
>= kSecRSAMin
&& keySizeInBits
<= kSecRSAMax
) return errSecSuccess
;
1142 case CSSM_ALGID_AES
:
1143 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecAES128
;
1144 if(keySizeInBits
== kSecAES128
|| keySizeInBits
== kSecAES192
|| keySizeInBits
== kSecAES256
) return errSecSuccess
;
1146 case CSSM_ALGID_3DES
:
1147 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSec3DES192
;
1148 if(keySizeInBits
== kSec3DES192
) return errSecSuccess
;
1167 struct ParameterAttribute
1169 const CFStringRef
*name
;
1175 static ParameterAttribute gAttributes
[] =
1182 &kSecAttrIsPermanent
,
1186 &kSecAttrApplicationTag
,
1190 &kSecAttrEffectiveKeySize
,
1194 &kSecAttrCanEncrypt
,
1198 &kSecAttrCanDecrypt
,
1219 const int kNumberOfAttributes
= sizeof(gAttributes
) / sizeof(ParameterAttribute
);
1221 static OSStatus
ScanDictionaryForParameters(CFDictionaryRef parameters
, void* attributePointers
[])
1224 for (i
= 0; i
< kNumberOfAttributes
; ++i
)
1226 // see if the corresponding tag exists in the dictionary
1227 CFTypeRef value
= CFDictionaryGetValue(parameters
, *(gAttributes
[i
].name
));
1230 switch (gAttributes
[i
].type
)
1233 // just return the value
1234 *(CFTypeRef
*) attributePointers
[i
] = value
;
1239 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1240 *(bool*) attributePointers
[i
] = CFBooleanGetValue(bRef
);
1246 CFNumberRef nRef
= (CFNumberRef
) value
;
1247 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, attributePointers
[i
]);
1254 return errSecSuccess
;
1259 static OSStatus
GetKeyParameters(CFDictionaryRef parameters
, int keySize
, bool isPublic
, CSSM_KEYUSE
&keyUse
, uint32
&attrs
, CFTypeRef
&labelRef
, CFDataRef
&applicationTagRef
)
1261 // establish default values
1263 bool isPermanent
= false;
1264 applicationTagRef
= NULL
;
1265 CFTypeRef effectiveKeySize
= NULL
;
1266 bool canDecrypt
= isPublic
? false : true;
1267 bool canEncrypt
= !canDecrypt
;
1268 bool canDerive
= true;
1269 bool canSign
= isPublic
? false : true;
1270 bool canVerify
= !canSign
;
1271 bool canUnwrap
= isPublic
? false : true;
1272 attrs
= CSSM_KEYATTR_EXTRACTABLE
;
1275 void* attributePointers
[] = {&labelRef
, &isPermanent
, &applicationTagRef
, &effectiveKeySize
, &canEncrypt
, &canDecrypt
,
1276 &canDerive
, &canSign
, &canVerify
, &canUnwrap
};
1278 // look for modifiers in the general dictionary
1279 OSStatus result
= ScanDictionaryForParameters(parameters
, attributePointers
);
1280 if (result
!= errSecSuccess
)
1285 // see if we have anything which modifies the defaults
1289 key
= kSecPublicKeyAttrs
;
1293 key
= kSecPrivateKeyAttrs
;
1296 CFTypeRef dType
= CFDictionaryGetValue(parameters
, key
);
1299 // this had better be a dictionary
1300 if (CFGetTypeID(dType
) != CFDictionaryGetTypeID())
1305 // pull any additional parameters out of this dictionary
1306 result
= ScanDictionaryForParameters((CFDictionaryRef
)dType
, attributePointers
);
1307 if (result
!= errSecSuccess
)
1313 // figure out the key usage
1317 keyUse
|= CSSM_KEYUSE_DECRYPT
;
1322 keyUse
|= CSSM_KEYUSE_ENCRYPT
;
1327 keyUse
|= CSSM_KEYUSE_DERIVE
;
1332 keyUse
|= CSSM_KEYUSE_SIGN
;
1337 keyUse
|= CSSM_KEYUSE_VERIFY
;
1342 keyUse
|= CSSM_KEYUSE_UNWRAP
;
1345 // public key is always extractable;
1346 // private key is extractable by default unless explicitly set to false
1347 CFTypeRef value
= NULL
;
1348 if (!isPublic
&& CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
) && value
)
1350 Boolean keyIsExtractable
= CFEqual(kCFBooleanTrue
, value
);
1351 if (!keyIsExtractable
)
1356 attrs
|= CSSM_KEYATTR_PERMANENT
;
1359 return errSecSuccess
;
1364 static OSStatus
MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters
,
1365 CSSM_ALGORITHMS
&algorithms
,
1366 uint32
&keySizeInBits
,
1367 CSSM_KEYUSE
&publicKeyUse
,
1368 uint32
&publicKeyAttr
,
1369 CFTypeRef
&publicKeyLabelRef
,
1370 CFDataRef
&publicKeyAttributeTagRef
,
1371 CSSM_KEYUSE
&privateKeyUse
,
1372 uint32
&privateKeyAttr
,
1373 CFTypeRef
&privateKeyLabelRef
,
1374 CFDataRef
&privateKeyAttributeTagRef
,
1375 SecAccessRef
&initialAccess
)
1379 result
= CheckAlgorithmType(parameters
, algorithms
);
1380 if (result
!= errSecSuccess
)
1385 result
= GetKeySize(parameters
, algorithms
, keySizeInBits
);
1386 if (result
!= errSecSuccess
)
1391 result
= GetKeyParameters(parameters
, keySizeInBits
, false, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1392 if (result
!= errSecSuccess
)
1397 result
= GetKeyParameters(parameters
, keySizeInBits
, true, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1398 if (result
!= errSecSuccess
)
1403 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&initialAccess
))
1405 initialAccess
= NULL
;
1407 else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess
))
1412 return errSecSuccess
;
1417 static OSStatus
SetKeyLabelAndTag(SecKeyRef keyRef
, CFTypeRef label
, CFDataRef tag
)
1419 int numToModify
= 0;
1430 if (numToModify
== 0)
1432 return errSecSuccess
;
1435 SecKeychainAttributeList attrList
;
1436 SecKeychainAttribute attributes
[numToModify
];
1442 if (CFStringGetTypeID() == CFGetTypeID(label
)) {
1443 CFStringRef label_string
= static_cast<CFStringRef
>(label
);
1444 attributes
[i
].tag
= kSecKeyPrintName
;
1445 attributes
[i
].data
= (void*) CFStringGetCStringPtr(label_string
, kCFStringEncodingUTF8
);
1446 if (NULL
== attributes
[i
].data
) {
1447 CFIndex buffer_length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string
), kCFStringEncodingUTF8
);
1448 attributes
[i
].data
= alloca((size_t)buffer_length
);
1449 if (NULL
== attributes
[i
].data
) {
1450 UnixError::throwMe(ENOMEM
);
1452 if (!CFStringGetCString(label_string
, static_cast<char *>(attributes
[i
].data
), buffer_length
, kCFStringEncodingUTF8
)) {
1453 MacOSError::throwMe(errSecParam
);
1456 attributes
[i
].length
= (UInt32
)strlen(static_cast<char *>(attributes
[i
].data
));
1457 } else if (CFDataGetTypeID() == CFGetTypeID(label
)) {
1458 // 10.6 bug compatibility
1459 CFDataRef label_data
= static_cast<CFDataRef
>(label
);
1460 attributes
[i
].tag
= kSecKeyLabel
;
1461 attributes
[i
].data
= (void*) CFDataGetBytePtr(label_data
);
1462 attributes
[i
].length
= (UInt32
)CFDataGetLength(label_data
);
1464 MacOSError::throwMe(errSecParam
);
1471 attributes
[i
].tag
= kSecKeyApplicationTag
;
1472 attributes
[i
].data
= (void*) CFDataGetBytePtr(tag
);
1473 attributes
[i
].length
= (UInt32
)CFDataGetLength(tag
);
1477 attrList
.count
= numToModify
;
1478 attrList
.attr
= attributes
;
1480 return SecKeychainItemModifyAttributesAndData((SecKeychainItemRef
) keyRef
, &attrList
, 0, NULL
);
1484 static CFTypeRef
GetAttributeFromParams(CFDictionaryRef parameters
, CFTypeRef attr
, CFTypeRef subParams
) {
1485 if (subParams
!= NULL
) {
1486 CFDictionaryRef subParamsDict
= (CFDictionaryRef
)CFDictionaryGetValue(parameters
, subParams
);
1487 if (subParamsDict
!= NULL
) {
1488 CFTypeRef value
= CFDictionaryGetValue(subParamsDict
, attr
);
1489 if (value
!= NULL
) {
1494 return CFDictionaryGetValue(parameters
, attr
);
1497 extern "C" OSStatus
SecKeyGeneratePair_ios(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
);
1500 /* Generate a private/public keypair. */
1502 SecKeyGeneratePairInternal(
1503 bool alwaysPermanent
,
1504 CFDictionaryRef parameters
,
1505 SecKeyRef
*publicKey
,
1506 SecKeyRef
*privateKey
)
1510 Required(parameters
);
1511 Required(publicKey
);
1512 Required(privateKey
);
1514 CFTypeRef tokenID
= GetAttributeFromParams(parameters
, kSecAttrTokenID
, NULL
);
1515 CFTypeRef noLegacy
= GetAttributeFromParams(parameters
, kSecAttrNoLegacy
, NULL
);
1516 CFTypeRef sync
= GetAttributeFromParams(parameters
, kSecAttrSynchronizable
, kSecPrivateKeyAttrs
);
1517 CFTypeRef accessControl
= GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPrivateKeyAttrs
) ?:
1518 GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPublicKeyAttrs
);
1519 CFTypeRef accessGroup
= GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPrivateKeyAttrs
) ?:
1520 GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPublicKeyAttrs
);
1522 // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain).
1523 if (tokenID
!= NULL
||
1524 (noLegacy
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)noLegacy
)) ||
1525 (sync
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)sync
)) ||
1526 accessControl
!= NULL
|| (accessGroup
!= NULL
&& CFEqual(accessGroup
, kSecAttrAccessGroupToken
))) {
1527 // Generate keys in iOS keychain.
1528 return SecKeyGeneratePair_ios(parameters
, publicKey
, privateKey
);
1531 CSSM_ALGORITHMS algorithms
;
1532 uint32 keySizeInBits
;
1533 CSSM_KEYUSE publicKeyUse
;
1534 uint32 publicKeyAttr
;
1535 CFTypeRef publicKeyLabelRef
;
1536 CFDataRef publicKeyAttributeTagRef
;
1537 CSSM_KEYUSE privateKeyUse
;
1538 uint32 privateKeyAttr
;
1539 CFTypeRef privateKeyLabelRef
;
1540 CFDataRef privateKeyAttributeTagRef
;
1541 SecAccessRef initialAccess
;
1542 SecKeychainRef keychain
;
1544 OSStatus result
= MakeKeyGenParametersFromDictionary(parameters
, algorithms
, keySizeInBits
, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
,
1545 publicKeyAttributeTagRef
, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
,
1548 if (result
!= errSecSuccess
) {
1552 // verify keychain parameter
1553 keychain
= (SecKeychainRef
)CFDictionaryGetValue(parameters
, kSecUseKeychain
);
1554 if (keychain
!= NULL
&& SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1558 if (alwaysPermanent
) {
1559 publicKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1560 privateKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1563 // do the key generation
1564 result
= SecKeyCreatePair(keychain
, algorithms
, keySizeInBits
, 0, publicKeyUse
, publicKeyAttr
, privateKeyUse
, privateKeyAttr
, initialAccess
, publicKey
, privateKey
);
1565 if (result
!= errSecSuccess
) {
1569 // set the label and print attributes on the keys
1570 SetKeyLabelAndTag(*publicKey
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1571 SetKeyLabelAndTag(*privateKey
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1578 SecKeyGeneratePair(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
1579 return SecKeyGeneratePairInternal(true, parameters
, publicKey
, privateKey
);
1583 SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef
*error
) {
1584 SecKeyRef privateKey
= NULL
, publicKey
= NULL
;
1585 OSStatus status
= SecKeyGeneratePairInternal(false, parameters
, &publicKey
, &privateKey
);
1586 SecError(status
, error
, CFSTR("failed to generate asymmetric keypair"));
1587 if (publicKey
!= NULL
) {
1588 CFRelease(publicKey
);
1593 OSStatus
SecKeyRawVerifyOSX(
1594 SecKeyRef key
, /* Public key */
1595 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
1596 const uint8_t *signedData
, /* signature over this data */
1597 size_t signedDataLen
, /* length of dataToSign */
1598 const uint8_t *sig
, /* signature */
1601 return SecKeyRawVerify(key
,padding
,signedData
,signedDataLen
,sig
,sigLen
);
1609 utilGetStringFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, CFTypeRef defaultValue
)
1611 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1612 if (value
!= NULL
) return value
;
1613 return defaultValue
;
1617 utilGetNumberFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t defaultValue
)
1619 uint32_t integerValue
;
1620 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1621 if (value
!= NULL
) {
1622 CFNumberRef nRef
= (CFNumberRef
) value
;
1623 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, &integerValue
);
1624 return integerValue
;
1626 return defaultValue
;
1630 utilGetMaskValFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t maskValue
)
1632 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1633 if (value
!= NULL
) {
1634 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1635 if(CFBooleanGetValue(bRef
)) return maskValue
;
1641 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters
, CSSM_ALGORITHMS
*algorithm
, uint32
*keySizeInBits
, CSSM_KEYUSE
*keyUsage
, CSSM_KEYCLASS
*keyClass
)
1643 CFTypeRef algorithmDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeAES
);
1644 CFTypeRef keyClassDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1646 if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeAES
)) {
1647 *algorithm
= CSSM_ALGID_AES
;
1648 *keySizeInBits
= 128;
1649 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1650 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDES
)) {
1651 *algorithm
= CSSM_ALGID_DES
;
1652 *keySizeInBits
= 128;
1653 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1654 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyType3DES
)) {
1655 *algorithm
= CSSM_ALGID_3DES_3KEY_EDE
;
1656 *keySizeInBits
= 128;
1657 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1658 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC4
)) {
1659 *algorithm
= CSSM_ALGID_RC4
;
1660 *keySizeInBits
= 128;
1661 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1662 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC2
)) {
1663 *algorithm
= CSSM_ALGID_RC2
;
1664 *keySizeInBits
= 128;
1665 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1666 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeCAST
)) {
1667 *algorithm
= CSSM_ALGID_CAST
;
1668 *keySizeInBits
= 128;
1669 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1670 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRSA
)) {
1671 *algorithm
= CSSM_ALGID_RSA
;
1672 *keySizeInBits
= 128;
1673 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1674 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDSA
)) {
1675 *algorithm
= CSSM_ALGID_DSA
;
1676 *keySizeInBits
= 128;
1677 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1678 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeECDSA
) ||
1679 CFEqual(algorithmDictValue
, kSecAttrKeyTypeEC
)) {
1680 *algorithm
= CSSM_ALGID_ECDSA
;
1681 *keySizeInBits
= 128;
1682 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1684 *algorithm
= CSSM_ALGID_AES
;
1685 *keySizeInBits
= 128;
1686 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1689 if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPublic
)) {
1690 *keyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
1691 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPrivate
)) {
1692 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1693 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassSymmetric
)) {
1694 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1697 *keySizeInBits
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, *keySizeInBits
);
1698 *keyUsage
= utilGetMaskValFromCFDict(parameters
, kSecAttrCanEncrypt
, CSSM_KEYUSE_ENCRYPT
) |
1699 utilGetMaskValFromCFDict(parameters
, kSecAttrCanDecrypt
, CSSM_KEYUSE_DECRYPT
) |
1700 utilGetMaskValFromCFDict(parameters
, kSecAttrCanWrap
, CSSM_KEYUSE_WRAP
) |
1701 utilGetMaskValFromCFDict(parameters
, kSecAttrCanUnwrap
, CSSM_KEYUSE_UNWRAP
);
1704 if(*keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
|| *keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
) {
1705 *keyUsage
|= utilGetMaskValFromCFDict(parameters
, kSecAttrCanSign
, CSSM_KEYUSE_SIGN
) |
1706 utilGetMaskValFromCFDict(parameters
, kSecAttrCanVerify
, CSSM_KEYUSE_VERIFY
);
1709 if(*keyUsage
== 0) {
1710 switch (*keyClass
) {
1711 case CSSM_KEYCLASS_PRIVATE_KEY
:
1712 *keyUsage
= CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
;
1714 case CSSM_KEYCLASS_PUBLIC_KEY
:
1715 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
;
1718 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
;
1725 utilCopyDefaultKeyLabel(void)
1727 // generate a default label from the current date
1728 CFDateRef dateNow
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent());
1729 CFStringRef defaultLabel
= CFCopyDescription(dateNow
);
1732 return defaultLabel
;
1736 SecKeyGenerateSymmetric(CFDictionaryRef parameters
, CFErrorRef
*error
)
1738 OSStatus result
= errSecParam
; // default result for an early exit
1739 SecKeyRef key
= NULL
;
1740 SecKeychainRef keychain
= NULL
;
1741 SecAccessRef access
;
1743 CFStringRef appLabel
;
1745 CFStringRef dateLabel
= NULL
;
1747 CSSM_ALGORITHMS algorithm
;
1748 uint32 keySizeInBits
;
1749 CSSM_KEYUSE keyUsage
;
1750 uint32 keyAttr
= CSSM_KEYATTR_RETURN_DEFAULT
;
1751 CSSM_KEYCLASS keyClass
;
1753 Boolean isPermanent
;
1754 Boolean isExtractable
;
1756 // verify keychain parameter
1757 if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
))
1759 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1766 // verify permanent parameter
1767 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsPermanent
, (const void **)&value
))
1768 isPermanent
= false;
1769 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1772 isPermanent
= CFEqual(kCFBooleanTrue
, value
);
1774 if (keychain
== NULL
) {
1775 // no keychain was specified, so use the default keychain
1776 result
= SecKeychainCopyDefault(&keychain
);
1778 keyAttr
|= CSSM_KEYATTR_PERMANENT
;
1781 // verify extractable parameter
1782 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
))
1783 isExtractable
= true; // default to extractable if value not specified
1784 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1787 isExtractable
= CFEqual(kCFBooleanTrue
, value
);
1789 keyAttr
|= CSSM_KEYATTR_EXTRACTABLE
;
1791 // verify access parameter
1792 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&access
))
1794 else if (SecAccessGetTypeID() != CFGetTypeID(access
))
1797 // verify label parameter
1798 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrLabel
, (const void **)&label
))
1799 label
= (dateLabel
= utilCopyDefaultKeyLabel()); // no label provided, so use default
1800 else if (CFStringGetTypeID() != CFGetTypeID(label
))
1803 // verify application label parameter
1804 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationLabel
, (const void **)&appLabel
))
1805 appLabel
= (dateLabel
) ? dateLabel
: (dateLabel
= utilCopyDefaultKeyLabel());
1806 else if (CFStringGetTypeID() != CFGetTypeID(appLabel
))
1809 // verify application tag parameter
1810 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationTag
, (const void **)&appTag
))
1812 else if (CFStringGetTypeID() != CFGetTypeID(appTag
))
1815 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1818 // the generated key will not be stored in any keychain
1819 result
= SecKeyGenerate(keychain
, algorithm
, keySizeInBits
, 0, keyUsage
, keyAttr
, access
, &key
);
1822 // we can set the label attributes on the generated key if it's a keychain item
1823 size_t labelBufLen
= (label
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label
), kCFStringEncodingUTF8
) + 1 : 0;
1824 char *labelBuf
= (char *)malloc(labelBufLen
);
1825 size_t appLabelBufLen
= (appLabel
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel
), kCFStringEncodingUTF8
) + 1 : 0;
1826 char *appLabelBuf
= (char *)malloc(appLabelBufLen
);
1827 size_t appTagBufLen
= (appTag
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag
), kCFStringEncodingUTF8
) + 1 : 0;
1828 char *appTagBuf
= (char *)malloc(appTagBufLen
);
1830 if (label
&& !CFStringGetCString(label
, labelBuf
, labelBufLen
-1, kCFStringEncodingUTF8
))
1832 if (appLabel
&& !CFStringGetCString(appLabel
, appLabelBuf
, appLabelBufLen
-1, kCFStringEncodingUTF8
))
1834 if (appTag
&& !CFStringGetCString(appTag
, appTagBuf
, appTagBufLen
-1, kCFStringEncodingUTF8
))
1837 SecKeychainAttribute attrs
[] = {
1838 { kSecKeyPrintName
, (UInt32
)strlen(labelBuf
), (char *)labelBuf
},
1839 { kSecKeyLabel
, (UInt32
)strlen(appLabelBuf
), (char *)appLabelBuf
},
1840 { kSecKeyApplicationTag
, (UInt32
)strlen(appTagBuf
), (char *)appTagBuf
} };
1841 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
1842 if (!appTag
) --attributes
.count
;
1844 result
= SecKeyGenerateWithAttributes(&attributes
,
1845 keychain
, algorithm
, keySizeInBits
, 0,
1846 keyUsage
, keyAttr
, access
, &key
);
1854 if (result
&& error
) {
1855 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, result
, NULL
);
1858 CFRelease(dateLabel
);
1860 CFRelease(keychain
);
1868 SecKeyCreateFromData(CFDictionaryRef parameters
, CFDataRef keyData
, CFErrorRef
*error
)
1870 CSSM_ALGORITHMS algorithm
;
1871 uint32 keySizeInBits
;
1872 CSSM_KEYUSE keyUsage
;
1873 CSSM_KEYCLASS keyClass
;
1876 if(keyData
== NULL
|| CFDataGetLength(keyData
) == 0){
1877 MacOSError::throwMe(errSecUnsupportedKeySize
);
1880 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1882 CSSM_CSP_HANDLE cspHandle
= cuCspStartup(CSSM_FALSE
); // TRUE => CSP, FALSE => CSPDL
1884 SecKeyImportExportParameters iparam
;
1885 memset(&iparam
, 0, sizeof(iparam
));
1886 iparam
.keyUsage
= keyUsage
;
1888 CFRef
<CFDataRef
> data
;
1889 SecExternalItemType itype
;
1891 case CSSM_KEYCLASS_PRIVATE_KEY
:
1892 itype
= kSecItemTypePrivateKey
;
1894 case CSSM_KEYCLASS_PUBLIC_KEY
: {
1895 itype
= kSecItemTypePublicKey
;
1896 // Public key import expects public key in SubjPublicKey X509 format. We want to accept both bare and x509 format,
1897 // so we have to detect bare format here and extend to full X509 if detected.
1898 data
.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm
, keySizeInBits
, keyData
));
1901 case CSSM_KEYCLASS_SESSION_KEY
:
1902 itype
= kSecItemTypeSessionKey
;
1905 itype
= kSecItemTypeUnknown
;
1909 CFMutableArrayRef ka
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1910 // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful.
1911 crtn
= impExpImportRawKey(data
? CFDataRef(data
) : keyData
, kSecFormatUnknown
, itype
, algorithm
, NULL
, cspHandle
, 0, NULL
, NULL
, ka
);
1912 if (crtn
== CSSM_OK
&& CFArrayGetCount((CFArrayRef
)ka
)) {
1913 SecKeyRef sk
= (SecKeyRef
)CFArrayGetValueAtIndex((CFArrayRef
)ka
, 0);
1919 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, crtn
? crtn
: CSSM_ERRCODE_INTERNAL_ERROR
, NULL
);
1927 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable
, dispatch_queue_t deliveryQueue
,
1928 SecKeyGeneratePairBlock result
)
1930 CFDictionaryRef parameters
= CFDictionaryCreateCopy(NULL
, parametersWhichMightBeMutiable
);
1931 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
1932 SecKeyRef publicKey
= NULL
;
1933 SecKeyRef privateKey
= NULL
;
1934 OSStatus status
= SecKeyGeneratePair(parameters
, &publicKey
, &privateKey
);
1935 dispatch_async(deliveryQueue
, ^{
1936 CFErrorRef error
= NULL
;
1937 if (errSecSuccess
!= status
) {
1938 error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, NULL
);
1940 result(publicKey
, privateKey
, error
);
1945 CFRelease(publicKey
);
1948 CFRelease(privateKey
);
1950 CFRelease(parameters
);
1955 static inline void utilClearAndFree(void *p
, size_t len
) {
1957 if(len
) bzero(p
, len
);
1963 SecKeyDeriveFromPassword(CFStringRef password
, CFDictionaryRef parameters
, CFErrorRef
*error
)
1965 CCPBKDFAlgorithm algorithm
;
1966 CFIndex passwordLen
= 0;
1967 CFDataRef keyData
= NULL
;
1968 char *thePassword
= NULL
;
1969 uint8_t *salt
= NULL
;
1970 uint8_t *derivedKey
= NULL
;
1971 size_t saltLen
= 0, derivedKeyLen
= 0;
1973 CFDataRef saltDictValue
, algorithmDictValue
;
1974 SecKeyRef retval
= NULL
;
1976 /* Pick Values from parameters */
1978 if((saltDictValue
= (CFDataRef
) CFDictionaryGetValue(parameters
, kSecAttrSalt
)) == NULL
) {
1979 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecMissingAlgorithmParms
, NULL
);
1983 derivedKeyLen
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, 128);
1984 // This value come in bits but the rest of the code treats it as bytes
1987 algorithmDictValue
= (CFDataRef
) utilGetStringFromCFDict(parameters
, kSecAttrPRF
, kSecAttrPRFHmacAlgSHA256
);
1989 rounds
= utilGetNumberFromCFDict(parameters
, kSecAttrRounds
, 0);
1991 /* Convert any remaining parameters and get the password bytes */
1993 saltLen
= CFDataGetLength(saltDictValue
);
1994 if((salt
= (uint8_t *) malloc(saltLen
)) == NULL
) {
1995 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
1999 CFDataGetBytes(saltDictValue
, CFRangeMake(0, saltLen
), (UInt8
*) salt
);
2001 passwordLen
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1;
2002 if((thePassword
= (char *) malloc(passwordLen
)) == NULL
) {
2003 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2006 CFStringGetBytes(password
, CFRangeMake(0, CFStringGetLength(password
)), kCFStringEncodingUTF8
, '?', FALSE
, (UInt8
*)thePassword
, passwordLen
, &passwordLen
);
2008 if((derivedKey
= (uint8_t *) malloc(derivedKeyLen
)) == NULL
) {
2009 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
2013 if(algorithmDictValue
== NULL
) {
2014 algorithm
= kCCPRFHmacAlgSHA1
; /* default */
2015 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA1
)) {
2016 algorithm
= kCCPRFHmacAlgSHA1
;
2017 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA224
)) {
2018 algorithm
= kCCPRFHmacAlgSHA224
;
2019 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA256
)) {
2020 algorithm
= kCCPRFHmacAlgSHA256
;
2021 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA384
)) {
2022 algorithm
= kCCPRFHmacAlgSHA384
;
2023 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA512
)) {
2024 algorithm
= kCCPRFHmacAlgSHA512
;
2026 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidAlgorithmParms
, NULL
);
2031 rounds
= 33333; // we need to pass back a consistent value since there's no way to record the round count.
2034 if(CCKeyDerivationPBKDF(kCCPBKDF2
, thePassword
, passwordLen
, salt
, saltLen
, algorithm
, rounds
, derivedKey
, derivedKeyLen
)) {
2035 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2039 if((keyData
= CFDataCreate(NULL
, derivedKey
, derivedKeyLen
)) != NULL
) {
2040 retval
= SecKeyCreateFromData(parameters
, keyData
, error
);
2043 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2047 utilClearAndFree(salt
, saltLen
);
2048 utilClearAndFree(thePassword
, passwordLen
);
2049 utilClearAndFree(derivedKey
, derivedKeyLen
);
2054 SecKeyWrapSymmetric(SecKeyRef keyToWrap
, SecKeyRef wrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2056 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);
2061 SecKeyUnwrapSymmetric(CFDataRef
*keyToUnwrap
, SecKeyRef unwrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2063 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);