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
);
61 SecCDSAKeyDestroy(SecKeyRef keyRef
) {
62 // Note: If this key is holding the last strong reference to its keychain, the keychain will be released during this operation.
63 // If we hold the keychain's mutex (the key's 'mutexForObject') during this destruction, pthread gets upset.
64 // Hold a reference to the keychain (if it exists) until after we release the keychain's mutex.
66 KeyItem
*keyItem
= keyRef
->key
;
67 if (keyItem
== NULL
) {
68 // KeyImpl::attachSecKeyRef disconnected us from KeyItem instance, there is nothing to do for us.
72 Keychain kc
= keyItem
->keychain();
75 StMaybeLock
<Mutex
> _(keyItem
->getMutexForObject());
76 keyItem
= keyRef
->key
;
77 if (keyItem
== NULL
) {
78 // 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.
82 keyItem
->aboutToDestruct();
86 (void) kc
; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain.
90 SecCDSAKeyGetBlockSize(SecKeyRef key
) {
92 CFErrorRef
*error
= NULL
;
93 BEGIN_SECKEYAPI(size_t,0)
95 const CssmKey::Header keyHeader
= key
->key
->unverifiedKeyHeader();
96 switch(keyHeader
.algorithm())
100 result
= keyHeader
.LogicalKeySizeInBits
/ 8;
102 case CSSM_ALGID_ECDSA
:
104 /* Block size is up to 9 bytes of DER encoding for sequence of 2 integers,
105 * plus both coordinates for the point used */
106 #define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8)
107 #define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1)
108 size_t coordSize
= ECDSA_MAX_COORD_SIZE_IN_BYTES(keyHeader
.LogicalKeySizeInBits
);
109 assert(coordSize
< 256); /* size must fit in a byte for DER */
110 size_t coordDERLen
= (coordSize
> 127) ? 2 : 1;
111 size_t coordLen
= 1 + coordDERLen
+ coordSize
;
113 size_t pointSize
= 2 * coordLen
;
114 assert(pointSize
< 256); /* size must fit in a byte for DER */
115 size_t pointDERLen
= (pointSize
> 127) ? 2 : 1;
116 size_t pointLen
= 1 + pointDERLen
+ pointSize
;
122 result
= 16; /* all AES keys use 128-bit blocks */
125 case CSSM_ALGID_3DES_3KEY
:
126 result
= 8; /* all DES keys use 64-bit blocks */
129 assert(0); /* some other key algorithm */
130 result
= 16; /* FIXME: revisit this */
138 SecCDSAKeyGetAlgorithmId(SecKeyRef key
) {
140 CFErrorRef
*error
= NULL
;
141 BEGIN_SECKEYAPI(CFIndex
, 0)
143 result
= kSecNullAlgorithmID
;
144 switch (key
->key
->unverifiedKeyHeader().AlgorithmId
) {
146 result
= kSecRSAAlgorithmID
;
149 result
= kSecDSAAlgorithmID
;
151 case CSSM_ALGID_ECDSA
:
152 result
= kSecECDSAAlgorithmID
;
155 assert(0); /* other algorithms TBA */
161 static CFDataRef
SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(CFDataRef pubKeyInfo
) {
162 // First of all, consider x509 format and try to strip SubjPubKey envelope. If it fails, do not panic
163 // and export data as is.
164 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(pubKeyInfo
), CFDataGetLength(pubKeyInfo
) }, pubKeyItem
;
166 DERSubjPubKeyInfo subjPubKey
;
167 if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
,
168 DERSubjPubKeyInfoItemSpecs
,
169 &subjPubKey
, sizeof(subjPubKey
)) == DR_Success
&&
170 DERParseBitString(&subjPubKey
.pubKey
, &pubKeyItem
, &numUnused
) == DR_Success
) {
171 return CFDataCreate(kCFAllocatorDefault
, pubKeyItem
.data
, pubKeyItem
.length
);
174 return CFDataRef(CFRetain(pubKeyInfo
));
177 static CFDataRef
SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(CSSM_ALGORITHMS algorithm
, uint32 keySizeInBits
, CFDataRef pubKeyInfo
) {
178 // First check, whether X509 pubkeyinfo is already present. If not, add it according to the key type.
179 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(pubKeyInfo
), CFDataGetLength(pubKeyInfo
) };
180 DERSubjPubKeyInfo subjPubKey
;
181 if (DERParseSequence(&keyItem
, DERNumSubjPubKeyInfoItemSpecs
,
182 DERSubjPubKeyInfoItemSpecs
,
183 &subjPubKey
, sizeof(subjPubKey
)) == DR_Success
) {
184 return CFDataRef(CFRetain(pubKeyInfo
));
187 // We have always size rounded to full bytes so bitstring encodes leading 00.
188 CFRef
<CFMutableDataRef
> bitStringPubKey
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
189 CFDataSetLength(bitStringPubKey
, 1);
190 CFDataAppendBytes(bitStringPubKey
, CFDataGetBytePtr(pubKeyInfo
), CFDataGetLength(pubKeyInfo
));
191 subjPubKey
.pubKey
.data
= static_cast<DERByte
*>(const_cast<UInt8
*>(CFDataGetBytePtr(bitStringPubKey
)));
192 subjPubKey
.pubKey
.length
= CFDataGetLength(bitStringPubKey
);
194 // Encode algId according to algorithm used.
195 static const DERByte oidRSA
[] = {
196 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
198 static const DERByte oidECsecp256
[] = {
199 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
201 static const DERByte oidECsecp384
[] = {
202 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22,
204 static const DERByte oidECsecp521
[] = {
205 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23,
207 subjPubKey
.algId
.length
= 0;
208 if (algorithm
== CSSM_ALGID_RSA
) {
209 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidRSA
);
210 subjPubKey
.algId
.length
= sizeof(oidRSA
);
211 } else if (algorithm
== CSSM_ALGID_ECDSA
) {
212 if (keySizeInBits
== 256) {
213 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidECsecp256
);
214 subjPubKey
.algId
.length
= sizeof(oidECsecp256
);
215 } else if (keySizeInBits
== 384) {
216 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidECsecp384
);
217 subjPubKey
.algId
.length
= sizeof(oidECsecp256
);
218 } if (keySizeInBits
== 521) {
219 subjPubKey
.algId
.data
= const_cast<DERByte
*>(oidECsecp521
);
220 subjPubKey
.algId
.length
= sizeof(oidECsecp256
);
223 DERSize size
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
,
224 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
);
225 CFRef
<CFMutableDataRef
> keyData
= CFDataCreateMutable(kCFAllocatorDefault
, size
);
226 CFDataSetLength(keyData
, size
);
227 if (DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, &subjPubKey
,
228 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
,
229 static_cast<DERByte
*>(CFDataGetMutableBytePtr(keyData
)), &size
) == DR_Success
) {
230 CFDataSetLength(keyData
, size
);
235 return keyData
.yield();
238 static OSStatus
SecCDSAKeyCopyPublicBytes(SecKeyRef key
, CFDataRef
*serialization
) {
240 CFErrorRef
*error
= NULL
;
241 BEGIN_SECKEYAPI(OSStatus
, errSecSuccess
)
243 const CssmKey::Header
&header
= key
->key
->key().header();
244 switch (header
.algorithm()) {
245 case CSSM_ALGID_RSA
: {
246 switch (header
.keyClass()) {
247 case CSSM_KEYCLASS_PRIVATE_KEY
: {
248 CFRef
<CFDataRef
> privKeyData
;
249 result
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, privKeyData
.take());
250 if (result
== errSecSuccess
) {
251 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(privKeyData
), CFDataGetLength(privKeyData
) };
252 DERRSAKeyPair keyPair
;
253 if (DERParseSequence(&keyItem
, DERNumRSAKeyPairItemSpecs
, DERRSAKeyPairItemSpecs
,
254 &keyPair
, sizeof(keyPair
)) == DR_Success
) {
255 DERRSAPubKeyPKCS1 pubKey
= { keyPair
.n
, keyPair
.e
};
256 DERSize size
= DERLengthOfEncodedSequence(ASN1_SEQUENCE
, &pubKey
,
257 DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
);
258 CFRef
<CFMutableDataRef
> keyData
= CFDataCreateMutable(kCFAllocatorDefault
, size
);
259 CFDataSetLength(keyData
, size
);
260 UInt8
*data
= CFDataGetMutableBytePtr(keyData
);
261 if (DEREncodeSequence(ASN1_SEQUENCE
, &pubKey
,
262 DERNumRSAPubKeyPKCS1ItemSpecs
, DERRSAPubKeyPKCS1ItemSpecs
,
263 data
, &size
) == DR_Success
) {
264 CFDataSetLength(keyData
, size
);
265 *data
= ONE_BYTE_ASN1_CONSTR_SEQUENCE
;
266 *serialization
= keyData
.yield();
268 *serialization
= NULL
;
269 result
= errSecParam
;
275 case CSSM_KEYCLASS_PUBLIC_KEY
:
276 result
= SecItemExport(key
, kSecFormatBSAFE
, 0, NULL
, serialization
);
281 case CSSM_ALGID_ECDSA
: {
282 *serialization
= NULL
;
283 CFRef
<CFDataRef
> tempPublicData
;
284 result
= SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, tempPublicData
.take());
285 if (result
== errSecSuccess
) {
286 *serialization
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(tempPublicData
);
291 result
= errSecUnimplemented
;
302 static const DERItemSpec DERECPrivateKeyItemSpecs
[] =
307 { DER_OFFSET(DERECPrivateKey
, privateKey
),
309 DER_DEC_NO_OPTS
| DER_ENC_NO_OPTS
},
311 ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0,
312 DER_DEC_SKIP
| DER_ENC_NO_OPTS
},
313 { DER_OFFSET(DERECPrivateKey
, publicKey
),
314 ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 1,
315 DER_DEC_NO_OPTS
| DER_ENC_SIGNED_INT
},
317 static const DERSize DERNumECPrivateKeyItemSpecs
=
318 sizeof(DERECPrivateKeyItemSpecs
) / sizeof(DERItemSpec
);
322 } DERECPrivateKeyPublicKey
;
324 static const DERItemSpec DERECPrivateKeyPublicKeyItemSpecs
[] =
326 { DER_OFFSET(DERECPrivateKeyPublicKey
, bitString
),
328 DER_DEC_NO_OPTS
| DER_ENC_NO_OPTS
},
330 static const DERSize DERNumECPrivateKeyPublicKeyItemSpecs
=
331 sizeof(DERECPrivateKeyPublicKeyItemSpecs
) / sizeof(DERItemSpec
);
334 SecCDSAKeyCopyExternalRepresentation(SecKeyRef key
, CFErrorRef
*error
) {
336 BEGIN_SECKEYAPI(CFDataRef
, NULL
)
339 const CssmKey::Header header
= key
->key
->unverifiedKeyHeader();
340 CFRef
<CFDataRef
> keyData
;
341 switch (header
.algorithm()) {
343 MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()));
345 case CSSM_ALGID_ECDSA
: {
346 MacOSError::check(SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()));
347 if (header
.keyClass() == CSSM_KEYCLASS_PRIVATE_KEY
) {
348 // Convert DER format into x9.63 format, which is expected for exported key.
349 DERItem keyItem
= { (DERByte
*)CFDataGetBytePtr(keyData
), CFDataGetLength(keyData
) };
350 DERECPrivateKey privateKey
;
351 DERECPrivateKeyPublicKey privateKeyPublicKey
;
354 if (DERParseSequence(&keyItem
, DERNumECPrivateKeyItemSpecs
, DERECPrivateKeyItemSpecs
,
355 &privateKey
, sizeof(privateKey
)) == DR_Success
&&
356 DERParseSequenceContent(&privateKey
.publicKey
, DERNumECPrivateKeyPublicKeyItemSpecs
,
357 DERECPrivateKeyPublicKeyItemSpecs
,
358 &privateKeyPublicKey
, sizeof(privateKeyPublicKey
)) == DR_Success
&&
359 DERParseBitString(&privateKeyPublicKey
.bitString
, &pubKeyItem
, &numUnused
) == DR_Success
) {
360 CFRef
<CFMutableDataRef
> key
= CFDataCreateMutable(kCFAllocatorDefault
,
361 pubKeyItem
.length
+ privateKey
.privateKey
.length
);
362 CFDataSetLength(key
, pubKeyItem
.length
+ privateKey
.privateKey
.length
);
363 CFDataReplaceBytes(key
, CFRangeMake(0, pubKeyItem
.length
), pubKeyItem
.data
, pubKeyItem
.length
);
364 CFDataReplaceBytes(key
, CFRangeMake(pubKeyItem
.length
, privateKey
.privateKey
.length
),
365 privateKey
.privateKey
.data
, privateKey
.privateKey
.length
);
366 keyData
= key
.as
<CFDataRef
>();
372 MacOSError::throwMe(errSecUnimplemented
);
375 if (header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
) {
376 result
= SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(keyData
);
378 result
= keyData
.yield();
384 static CFDataRef
SecCDSAKeyCopyLabel(SecKeyRef key
) {
385 CFDataRef label
= NULL
;
386 if (key
->key
->isPersistent()) {
387 UInt32 tags
[] = { kSecKeyLabel
}, formats
[] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB
};
388 SecKeychainAttributeInfo info
= { 1, tags
, formats
};
389 SecKeychainAttributeList
*list
= NULL
;
390 key
->key
->getAttributesAndData(&info
, NULL
, &list
, NULL
, NULL
);
391 if (list
->count
== 1) {
392 SecKeychainAttribute
*attr
= list
->attr
;
393 label
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)attr
->data
, (CFIndex
)attr
->length
);
395 key
->key
->freeAttributesAndData(list
, NULL
);
400 static CFDictionaryRef
401 SecCDSAKeyCopyAttributeDictionary(SecKeyRef key
) {
403 CFErrorRef
*error
= NULL
;
404 BEGIN_SECKEYAPI(CFDictionaryRef
, NULL
)
406 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
407 &kCFTypeDictionaryValueCallBacks
);
409 CFDictionarySetValue(dict
, kSecClass
, kSecClassKey
);
411 const CssmKey::Header header
= key
->key
->unverifiedKeyHeader();
412 CFIndex sizeValue
= header
.LogicalKeySizeInBits
;
413 CFRef
<CFNumberRef
> sizeInBits
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &sizeValue
);
414 CFDictionarySetValue(dict
, kSecAttrKeySizeInBits
, sizeInBits
);
415 CFDictionarySetValue(dict
, kSecAttrEffectiveKeySize
, sizeInBits
);
417 CFRef
<CFDataRef
> label
= SecCDSAKeyCopyLabel(key
);
419 // For floating keys, calculate label as SHA1 of pubkey bytes.
420 CFRef
<CFDataRef
> pubKeyBlob
;
421 if (SecCDSAKeyCopyPublicBytes(key
, pubKeyBlob
.take()) == errSecSuccess
) {
422 uint8_t pubKeyHash
[CC_SHA1_DIGEST_LENGTH
];
423 CC_SHA1(CFDataGetBytePtr(pubKeyBlob
), CC_LONG(CFDataGetLength(pubKeyBlob
)), pubKeyHash
);
424 label
.take(CFDataCreate(kCFAllocatorDefault
, pubKeyHash
, sizeof(pubKeyHash
)));
429 CFDictionarySetValue(dict
, kSecAttrApplicationLabel
, label
);
432 CSSM_KEYATTR_FLAGS attrs
= header
.attributes();
433 CFDictionarySetValue(dict
, kSecAttrIsPermanent
, (attrs
& CSSM_KEYATTR_PERMANENT
) ? kCFBooleanTrue
: kCFBooleanFalse
);
434 CFDictionarySetValue(dict
, kSecAttrIsPrivate
, (attrs
& CSSM_KEYATTR_PRIVATE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
435 CFDictionarySetValue(dict
, kSecAttrIsModifiable
, (attrs
& CSSM_KEYATTR_MODIFIABLE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
436 CFDictionarySetValue(dict
, kSecAttrIsSensitive
, (attrs
& CSSM_KEYATTR_SENSITIVE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
437 CFDictionarySetValue(dict
, kSecAttrIsExtractable
, (attrs
& CSSM_KEYATTR_EXTRACTABLE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
438 CFDictionarySetValue(dict
, kSecAttrWasAlwaysSensitive
, (attrs
& CSSM_KEYATTR_ALWAYS_SENSITIVE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
439 CFDictionarySetValue(dict
, kSecAttrWasNeverExtractable
, (attrs
& CSSM_KEYATTR_NEVER_EXTRACTABLE
) ? kCFBooleanTrue
: kCFBooleanFalse
);
441 CFDictionarySetValue(dict
, kSecAttrCanEncrypt
, (header
.useFor(CSSM_KEYUSE_ENCRYPT
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
442 CFDictionarySetValue(dict
, kSecAttrCanDecrypt
, (header
.useFor(CSSM_KEYUSE_DECRYPT
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
443 CFDictionarySetValue(dict
, kSecAttrCanSign
, (header
.useFor(CSSM_KEYUSE_SIGN
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
444 CFDictionarySetValue(dict
, kSecAttrCanVerify
, (header
.useFor(CSSM_KEYUSE_VERIFY
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
445 CFDictionarySetValue(dict
, kSecAttrCanSignRecover
, (header
.useFor(CSSM_KEYUSE_SIGN_RECOVER
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
446 CFDictionarySetValue(dict
, kSecAttrCanVerifyRecover
, (header
.useFor(CSSM_KEYUSE_VERIFY_RECOVER
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
447 CFDictionarySetValue(dict
, kSecAttrCanWrap
, (header
.useFor(CSSM_KEYUSE_WRAP
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
448 CFDictionarySetValue(dict
, kSecAttrCanUnwrap
, (header
.useFor(CSSM_KEYUSE_UNWRAP
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
449 CFDictionarySetValue(dict
, kSecAttrCanDerive
, (header
.useFor(CSSM_KEYUSE_DERIVE
)) ? kCFBooleanTrue
: kCFBooleanFalse
);
451 switch (header
.keyClass()) {
452 case CSSM_KEYCLASS_PUBLIC_KEY
:
453 CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
455 case CSSM_KEYCLASS_PRIVATE_KEY
:
456 CFDictionarySetValue(dict
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
460 switch (header
.algorithm()) {
462 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
464 case CSSM_ALGID_ECDSA
:
465 CFDictionarySetValue(dict
, kSecAttrKeyType
, kSecAttrKeyTypeECDSA
);
469 CFRef
<CFDataRef
> keyData
;
470 if (SecItemExport(key
, kSecFormatOpenSSL
, 0, NULL
, keyData
.take()) == errSecSuccess
) {
471 CFDictionarySetValue(dict
, kSecValueData
, keyData
);
474 if (header
.algorithm() == CSSM_ALGID_RSA
&& header
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
&&
475 header
.blobType() == CSSM_KEYBLOB_RAW
) {
476 const CssmData
&keyData
= key
->key
->key()->keyData();
477 DERItem keyItem
= { static_cast<DERByte
*>(keyData
.data()), keyData
.length() };
478 DERRSAPubKeyPKCS1 decodedKey
;
479 if (DERParseSequence(&keyItem
, DERNumRSAPubKeyPKCS1ItemSpecs
,
480 DERRSAPubKeyPKCS1ItemSpecs
,
481 &decodedKey
, sizeof(decodedKey
)) == DR_Success
) {
482 CFRef
<CFDataRef
> modulus
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.modulus
.data
,
483 decodedKey
.modulus
.length
);
484 CFDictionarySetValue(dict
, CFSTR("_rsam"), modulus
);
485 CFRef
<CFDataRef
> exponent
= CFDataCreate(kCFAllocatorDefault
, decodedKey
.pubExponent
.data
,
486 decodedKey
.pubExponent
.length
);
487 CFDictionarySetValue(dict
, CFSTR("_rsae"), exponent
);
496 #pragma clang diagnostic push
497 #pragma clang diagnostic ignored "-Wunused-const-variable"
498 static CSSM_DB_NAME_ATTR(kInfoKeyLabel
, kSecKeyLabel
, (char*) "Label", 0, NULL
, BLOB
);
499 #pragma clang diagnostic pop
501 static SecKeyRef
SecCDSAKeyCopyPublicKey(SecKeyRef privateKey
) {
503 BEGIN_SECKEYAPI(SecKeyRef
, NULL
)
506 KeyItem
*key
= privateKey
->key
;
507 CFRef
<CFDataRef
> label
= SecCDSAKeyCopyLabel(privateKey
);
509 // Lookup public key in the database.
510 DbUniqueRecord uniqueId
;
511 SSDb
ssDb(dynamic_cast<SSDbImpl
*>(&(*key
->keychain()->database())));
512 SSDbCursor
dbCursor(ssDb
, 1);
513 dbCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
);
514 dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, CssmData(CFDataRef(label
)));
515 if (dbCursor
->next(NULL
, NULL
, uniqueId
)) {
516 Item publicKey
= key
->keychain()->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, uniqueId
);
517 result
= reinterpret_cast<SecKeyRef
>(publicKey
->handle());
519 } else if (key
->publicKey()) {
520 KeyItem
*publicKey
= new KeyItem(key
->publicKey());
521 result
= reinterpret_cast<SecKeyRef
>(publicKey
->handle());
527 static KeyItem
*SecCDSAKeyPrepareParameters(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
,
528 CSSM_ALGORITHMS
&baseAlgorithm
, CSSM_ALGORITHMS
&secondaryAlgorithm
,
529 CSSM_ALGORITHMS
&paddingAlgorithm
) {
530 KeyItem
*keyItem
= key
->key
;
531 CSSM_KEYCLASS keyClass
= keyItem
->key()->header().keyClass();
532 baseAlgorithm
= keyItem
->key()->header().algorithm();
533 switch (baseAlgorithm
) {
535 if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeSign
) ||
536 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeVerify
)) {
537 if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureRaw
)) {
538 secondaryAlgorithm
= CSSM_ALGID_NONE
;
539 paddingAlgorithm
= CSSM_PADDING_NONE
;
540 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw
)) {
541 secondaryAlgorithm
= CSSM_ALGID_NONE
;
542 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
543 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
)) {
544 secondaryAlgorithm
= CSSM_ALGID_SHA1
;
545 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
546 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224
)) {
547 secondaryAlgorithm
= CSSM_ALGID_SHA224
;
548 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
549 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
)) {
550 secondaryAlgorithm
= CSSM_ALGID_SHA256
;
551 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
552 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
)) {
553 secondaryAlgorithm
= CSSM_ALGID_SHA384
;
554 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
555 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
)) {
556 secondaryAlgorithm
= CSSM_ALGID_SHA512
;
557 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
558 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5
)) {
559 secondaryAlgorithm
= CSSM_ALGID_MD5
;
560 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
564 } else if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeDecrypt
) ||
565 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeEncrypt
)) {
566 if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionRaw
)) {
567 secondaryAlgorithm
= CSSM_ALGID_NONE
;
568 paddingAlgorithm
= CSSM_PADDING_NONE
;
569 } else if (CFEqual(algorithm
, kSecKeyAlgorithmRSAEncryptionPKCS1
)) {
570 secondaryAlgorithm
= CSSM_ALGID_NONE
;
571 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
579 case CSSM_ALGID_ECDSA
:
580 if ((keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeSign
) ||
581 (keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
&& operation
== kSecKeyOperationTypeVerify
)) {
582 if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureRFC4754
)) {
583 secondaryAlgorithm
= CSSM_ALGID_NONE
;
584 paddingAlgorithm
= CSSM_PADDING_SIGRAW
;
585 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDSASignatureDigestX962
)) {
586 secondaryAlgorithm
= CSSM_ALGID_NONE
;
587 paddingAlgorithm
= CSSM_PADDING_PKCS1
;
591 } else if (keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
&& operation
== kSecKeyOperationTypeKeyExchange
) {
592 if (CFEqual(algorithm
,kSecKeyAlgorithmECDHKeyExchangeStandard
) ||
593 CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactor
)) {
594 baseAlgorithm
= CSSM_ALGID_ECDH
;
595 } else if (CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1
) ||
596 CFEqual(algorithm
, kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1
)) {
597 baseAlgorithm
= CSSM_ALGID_ECDH_X963_KDF
;
606 MacOSError::throwMe(errSecParam
);
612 SecCDSAKeyCopyPaddedPlaintext(SecKeyRef key
, CFDataRef plaintext
, SecKeyAlgorithm algorithm
) {
613 CFIndex blockSize
= key
->key
->key().header().LogicalKeySizeInBits
/ 8;
614 CFIndex plaintextLength
= CFDataGetLength(plaintext
);
615 if ((algorithm
== kSecKeyAlgorithmRSAEncryptionRaw
|| algorithm
== kSecKeyAlgorithmRSASignatureRaw
)
616 && plaintextLength
< blockSize
) {
617 // Pre-pad with zeroes.
618 CFMutableDataRef
result(CFDataCreateMutable(kCFAllocatorDefault
, blockSize
));
619 CFDataSetLength(result
, blockSize
);
620 CFDataReplaceBytes(result
, CFRangeMake(blockSize
- plaintextLength
, plaintextLength
),
621 CFDataGetBytePtr(plaintext
), plaintextLength
);
624 return CFDataRef(CFRetain(plaintext
));
628 static CFTypeRef
SecCDSAKeyCopyOperationResult(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
,
629 CFArrayRef allAlgorithms
, SecKeyOperationMode mode
,
630 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
631 BEGIN_SECKEYAPI(CFTypeRef
, kCFNull
)
632 CSSM_ALGORITHMS baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
;
633 KeyItem
*keyItem
= SecCDSAKeyPrepareParameters(key
, operation
, algorithm
, baseAlgorithm
, secondaryAlgorithm
, paddingAlgorithm
);
634 if (keyItem
== NULL
) {
635 // Operation/algorithm/key combination is not supported.
637 } else if (mode
== kSecKeyOperationModeCheckIfSupported
) {
638 // Operation is supported and caller wants to just know that.
639 return kCFBooleanTrue
;
643 case kSecKeyOperationTypeSign
: {
644 CssmClient::Sign
signContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
);
645 signContext
.key(keyItem
->key());
646 signContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN
, kSecCredentialTypeDefault
));
647 signContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
);
648 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
649 CssmAutoData
signature(signContext
.allocator());
650 signContext
.sign(CssmData(CFDataRef(input
)), signature
.get());
651 result
= CFDataCreate(NULL
, static_cast<const UInt8
*>(signature
.data()), CFIndex(signature
.length()));
654 case kSecKeyOperationTypeVerify
: {
655 CssmClient::Verify
verifyContext(keyItem
->csp(), baseAlgorithm
, secondaryAlgorithm
);
656 verifyContext
.key(keyItem
->key());
657 verifyContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ANY
, kSecCredentialTypeDefault
));
658 verifyContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlgorithm
);
659 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
660 verifyContext
.verify(CssmData(CFDataRef(input
)), CssmData(CFRef
<CFDataRef
>::check(in2
, errSecParam
)));
661 result
= kCFBooleanTrue
;
664 case kSecKeyOperationTypeEncrypt
: {
665 CssmClient::Encrypt
encryptContext(keyItem
->csp(), baseAlgorithm
);
666 encryptContext
.key(keyItem
->key());
667 encryptContext
.padding(paddingAlgorithm
);
668 encryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT
, kSecCredentialTypeDefault
));
669 CFRef
<CFDataRef
> input
= SecCDSAKeyCopyPaddedPlaintext(key
, CFRef
<CFDataRef
>::check(in1
, errSecParam
), algorithm
);
670 CssmAutoData
output(encryptContext
.allocator()), remainingData(encryptContext
.allocator());
671 size_t length
= encryptContext
.encrypt(CssmData(CFDataRef(input
)), output
.get(), remainingData
.get());
672 result
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length());
673 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(output
.data()), output
.length());
674 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(remainingData
.data()), remainingData
.length());
675 CFDataSetLength(CFMutableDataRef(result
), length
);
678 case kSecKeyOperationTypeDecrypt
: {
679 CssmClient::Decrypt
decryptContext(keyItem
->csp(), baseAlgorithm
);
680 decryptContext
.key(keyItem
->key());
681 decryptContext
.padding(paddingAlgorithm
);
682 decryptContext
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT
, kSecCredentialTypeDefault
));
683 CssmAutoData
output(decryptContext
.allocator()), remainingData(decryptContext
.allocator());
684 size_t length
= decryptContext
.decrypt(CssmData(CFRef
<CFDataRef
>::check(in1
, errSecParam
)),
685 output
.get(), remainingData
.get());
686 result
= CFDataCreateMutable(kCFAllocatorDefault
, output
.length() + remainingData
.length());
687 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(output
.data()), output
.length());
688 CFDataAppendBytes(CFMutableDataRef(result
), static_cast<const UInt8
*>(remainingData
.data()), remainingData
.length());
689 CFDataSetLength(CFMutableDataRef(result
), length
);
692 case kSecKeyOperationTypeKeyExchange
: {
693 CFIndex requestedLength
= 0;
695 switch (baseAlgorithm
) {
696 case CSSM_ALGID_ECDH
:
697 requestedLength
= (keyItem
->key().header().LogicalKeySizeInBits
+ 7) / 8;
699 case CSSM_ALGID_ECDH_X963_KDF
:
700 CFDictionaryRef params
= CFRef
<CFDictionaryRef
>::check(in2
, errSecParam
);
701 CFTypeRef value
= params
? CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterRequestedSize
) : NULL
;
702 if (value
== NULL
|| CFGetTypeID(value
) != CFNumberGetTypeID() ||
703 !CFNumberGetValue(CFNumberRef(value
), kCFNumberCFIndexType
, &requestedLength
)) {
704 MacOSError::throwMe(errSecParam
);
706 value
= CFDictionaryGetValue(params
, kSecKeyKeyExchangeParameterSharedInfo
);
707 if (value
!= NULL
&& CFGetTypeID(value
) == CFDataGetTypeID()) {
708 sharedInfo
= CssmData(CFDataRef(value
));
713 CssmClient::DeriveKey
derive(keyItem
->csp(), baseAlgorithm
, CSSM_ALGID_AES
, uint32(requestedLength
* 8));
714 derive
.key(keyItem
->key());
715 derive
.cred(keyItem
->getCredentials(CSSM_ACL_AUTHORIZATION_DERIVE
, kSecCredentialTypeDefault
));
716 derive
.salt(sharedInfo
);
717 CssmData
param(CFRef
<CFDataRef
>::check(in1
, errSecParam
));
718 Key derivedKey
= derive(¶m
, KeySpec(CSSM_KEYUSE_ANY
, CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
));
720 // Export raw data of newly derived key (by wrapping with an empty key).
721 CssmClient::WrapKey
wrapper(keyItem
->csp(), CSSM_ALGID_NONE
);
722 Key wrappedKey
= wrapper(derivedKey
);
723 result
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)wrappedKey
->data(), CFIndex(wrappedKey
->length()));
733 static Boolean
SecCDSAIsEqual(SecKeyRef key1
, SecKeyRef key2
) {
735 BEGIN_SECKEYAPI(Boolean
, false)
737 result
= key1
->key
->equal(*key2
->key
);
742 const SecKeyDescriptor kSecCDSAKeyDescriptor
= {
743 .version
= kSecKeyDescriptorVersion
,
746 .init
= SecCDSAKeyInit
,
747 .destroy
= SecCDSAKeyDestroy
,
748 .blockSize
= SecCDSAKeyGetBlockSize
,
749 .getAlgorithmID
= SecCDSAKeyGetAlgorithmId
,
750 .copyDictionary
= SecCDSAKeyCopyAttributeDictionary
,
751 .copyPublic
= SecCDSAKeyCopyPublicBytes
,
752 .copyExternalRepresentation
= SecCDSAKeyCopyExternalRepresentation
,
753 .copyPublicKey
= SecCDSAKeyCopyPublicKey
,
754 .copyOperationResult
= SecCDSAKeyCopyOperationResult
,
755 .isEqual
= SecCDSAIsEqual
,
759 namespace KeychainCore
{
760 SecCFObject
*KeyItem::fromSecKeyRef(CFTypeRef ptr
) {
761 if (ptr
== NULL
|| CFGetTypeID(ptr
) != SecKeyGetTypeID()) {
765 SecKeyRef key
= static_cast<SecKeyRef
>(const_cast<void *>(ptr
));
766 if (key
->key_class
== &kSecCDSAKeyDescriptor
) {
767 return static_cast<SecCFObject
*>(key
->key
);
770 if (key
->cdsaKey
== NULL
) {
771 // Create CDSA key from exported data of existing key.
772 CFRef
<CFDataRef
> keyData
= SecKeyCopyExternalRepresentation(key
, NULL
);
773 CFRef
<CFDictionaryRef
> keyAttributes
= SecKeyCopyAttributes(key
);
774 if (keyData
&& keyAttributes
) {
775 key
->cdsaKey
= SecKeyCreateFromData(keyAttributes
, keyData
, NULL
);
779 return (key
->cdsaKey
!= NULL
) ? key
->cdsaKey
->key
: NULL
;
782 // You need to hold this key's MutexForObject when you run this
783 void KeyItem::attachSecKeyRef() const {
784 SecKeyRef key
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, reinterpret_cast<const uint8_t *>(this), 0, 0);
785 key
->key
->mWeakSecKeyRef
= key
;
791 extern "C" Boolean
SecKeyIsCDSAKey(SecKeyRef ref
);
792 Boolean
SecKeyIsCDSAKey(SecKeyRef ref
) {
793 return ref
->key_class
== &kSecCDSAKeyDescriptor
;
797 static OSStatus
SecKeyCreatePairInternal(
798 SecKeychainRef keychainRef
,
799 CSSM_ALGORITHMS algorithm
,
800 uint32 keySizeInBits
,
801 CSSM_CC_HANDLE contextHandle
,
802 CSSM_KEYUSE publicKeyUsage
,
803 uint32 publicKeyAttr
,
804 CSSM_KEYUSE privateKeyUsage
,
805 uint32 privateKeyAttr
,
806 SecAccessRef initialAccess
,
807 SecKeyRef
* publicKeyRef
,
808 SecKeyRef
* privateKeyRef
)
813 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
814 SecPointer
<KeyItem
> pubItem
, privItem
;
815 if (((publicKeyAttr
| privateKeyAttr
) & CSSM_KEYATTR_PERMANENT
) != 0) {
816 keychain
= Keychain::optional(keychainRef
);
817 StLock
<Mutex
> _(*keychain
->getKeychainMutex());
818 KeyItem::createPair(keychain
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, publicKeyAttr
,
819 privateKeyUsage
, privateKeyAttr
, theAccess
, pubItem
, privItem
);
821 KeyItem::createPair(keychain
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
, publicKeyAttr
,
822 privateKeyUsage
, privateKeyAttr
, theAccess
, pubItem
, privItem
);
825 // Return the generated keys.
827 *publicKeyRef
= pubItem
->handle();
829 *privateKeyRef
= privItem
->handle();
836 SecKeychainRef keychainRef
,
837 CSSM_ALGORITHMS algorithm
,
838 uint32 keySizeInBits
,
839 CSSM_CC_HANDLE contextHandle
,
840 CSSM_KEYUSE publicKeyUsage
,
841 uint32 publicKeyAttr
,
842 CSSM_KEYUSE privateKeyUsage
,
843 uint32 privateKeyAttr
,
844 SecAccessRef initialAccess
,
845 SecKeyRef
* publicKeyRef
,
846 SecKeyRef
* privateKeyRef
)
848 OSStatus result
= SecKeyCreatePairInternal(keychainRef
, algorithm
, keySizeInBits
, contextHandle
, publicKeyUsage
,
849 publicKeyAttr
, privateKeyUsage
, privateKeyAttr
, initialAccess
, publicKeyRef
, privateKeyRef
);
857 SecKeyGetCSSMKey(SecKeyRef key
, const CSSM_KEY
**cssmKey
)
861 Required(cssmKey
) = KeyItem::required(key
)->key();
872 SecKeyGetCSPHandle(SecKeyRef keyRef
, CSSM_CSP_HANDLE
*cspHandle
)
876 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
877 Required(cspHandle
) = keyItem
->csp()->handle();
882 /* deprecated as of 10.8 */
884 SecKeyGetAlgorithmID(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
**algid
)
888 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
889 Required(algid
) = &keyItem
->algorithmIdentifier();
895 SecKeyGetStrengthInBits(SecKeyRef keyRef
, const CSSM_X509_ALGORITHM_IDENTIFIER
*algid
, unsigned int *strength
)
899 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
900 Required(strength
) = keyItem
->strengthInBits(algid
);
906 SecKeyGetCredentials(
908 CSSM_ACL_AUTHORIZATION_TAG operation
,
909 SecCredentialType credentialType
,
910 const CSSM_ACCESS_CREDENTIALS
**outCredentials
)
914 SecPointer
<KeyItem
> keyItem(KeyItem::required(keyRef
));
915 Required(outCredentials
) = keyItem
->getCredentials(operation
, credentialType
);
922 SecKeychainRef keychainRef
,
923 const CSSM_KEY
*publicCssmKey
,
924 const CSSM_KEY
*privateCssmKey
,
925 SecAccessRef initialAccess
,
926 SecKeyRef
* publicKey
,
927 SecKeyRef
* privateKey
)
931 Keychain keychain
= Keychain::optional(keychainRef
);
932 SecPointer
<Access
> theAccess(initialAccess
? Access::required(initialAccess
) : new Access("<key>"));
933 SecPointer
<KeyItem
> pubItem
, privItem
;
935 KeyItem::importPair(keychain
,
936 Required(publicCssmKey
),
937 Required(privateCssmKey
),
942 // Return the generated keys.
944 *publicKey
= pubItem
->handle();
946 *privateKey
= privItem
->handle();
952 SecKeyGenerateWithAttributes(
953 SecKeychainAttributeList
* attrList
,
954 SecKeychainRef keychainRef
,
955 CSSM_ALGORITHMS algorithm
,
956 uint32 keySizeInBits
,
957 CSSM_CC_HANDLE contextHandle
,
958 CSSM_KEYUSE keyUsage
,
960 SecAccessRef initialAccess
,
966 SecPointer
<Access
> theAccess
;
969 keychain
= KeychainImpl::required(keychainRef
);
971 theAccess
= Access::required(initialAccess
);
973 SecPointer
<KeyItem
> item
= KeyItem::generateWithAttributes(attrList
,
982 // Return the generated key.
984 *keyRef
= item
->handle();
991 SecKeychainRef keychainRef
,
992 CSSM_ALGORITHMS algorithm
,
993 uint32 keySizeInBits
,
994 CSSM_CC_HANDLE contextHandle
,
995 CSSM_KEYUSE keyUsage
,
997 SecAccessRef initialAccess
,
1000 return SecKeyGenerateWithAttributes(NULL
,
1001 keychainRef
, algorithm
, keySizeInBits
,
1002 contextHandle
, keyUsage
, keyAttr
,
1003 initialAccess
, keyRef
);
1007 /* Generate a floating key reference from a CSSM_KEY */
1009 SecKeyCreateWithCSSMKey(const CSSM_KEY
*cssmKey
,
1015 if(cssmKey
->KeyData
.Length
== 0){
1016 MacOSError::throwMe(errSecInvalidAttributeKeyLength
);
1018 if(cssmKey
->KeyData
.Data
== NULL
){
1019 MacOSError::throwMe(errSecInvalidPointer
);
1021 CssmClient::CSP
csp(cssmKey
->KeyHeader
.CspId
);
1022 CssmClient::Key
key(csp
, *cssmKey
);
1023 KeyItem
*item
= new KeyItem(key
);
1025 // Return the generated key.
1027 *keyRef
= SecKeyCreate(NULL
, &kSecCDSAKeyDescriptor
, (const uint8_t *)item
, 0, 0);
1034 static u_int32_t
ConvertCFStringToInteger(CFStringRef ref
)
1041 // figure out the size of the string
1042 CFIndex numChars
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref
), kCFStringEncodingUTF8
);
1043 char buffer
[numChars
];
1044 if (!CFStringGetCString(ref
, buffer
, numChars
, kCFStringEncodingUTF8
))
1046 MacOSError::throwMe(errSecParam
);
1049 return atoi(buffer
);
1054 static OSStatus
CheckAlgorithmType(CFDictionaryRef parameters
, CSSM_ALGORITHMS
&algorithms
)
1056 // figure out the algorithm to use
1057 CFStringRef ktype
= (CFStringRef
) CFDictionaryGetValue(parameters
, kSecAttrKeyType
);
1063 if (CFEqual(ktype
, kSecAttrKeyTypeRSA
)) {
1064 algorithms
= CSSM_ALGID_RSA
;
1065 return errSecSuccess
;
1066 } else if(CFEqual(ktype
, kSecAttrKeyTypeECDSA
) ||
1067 CFEqual(ktype
, kSecAttrKeyTypeEC
)) {
1068 algorithms
= CSSM_ALGID_ECDSA
;
1069 return errSecSuccess
;
1070 } else if(CFEqual(ktype
, kSecAttrKeyTypeAES
)) {
1071 algorithms
= CSSM_ALGID_AES
;
1072 return errSecSuccess
;
1073 } else if(CFEqual(ktype
, kSecAttrKeyType3DES
)) {
1074 algorithms
= CSSM_ALGID_3DES
;
1075 return errSecSuccess
;
1077 return errSecUnsupportedAlgorithm
;
1083 static OSStatus
GetKeySize(CFDictionaryRef parameters
, CSSM_ALGORITHMS algorithms
, uint32
&keySizeInBits
)
1086 // get the key size and check it for validity
1087 CFTypeRef ref
= CFDictionaryGetValue(parameters
, kSecAttrKeySizeInBits
);
1089 keySizeInBits
= kSecDefaultKeySize
;
1091 CFTypeID bitSizeType
= CFGetTypeID(ref
);
1092 if (bitSizeType
== CFStringGetTypeID())
1093 keySizeInBits
= ConvertCFStringToInteger((CFStringRef
) ref
);
1094 else if (bitSizeType
== CFNumberGetTypeID())
1095 CFNumberGetValue((CFNumberRef
) ref
, kCFNumberSInt32Type
, &keySizeInBits
);
1096 else return errSecParam
;
1099 switch (algorithms
) {
1100 case CSSM_ALGID_ECDSA
:
1101 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecp256r1
;
1102 if(keySizeInBits
== kSecp192r1
|| keySizeInBits
== kSecp256r1
|| keySizeInBits
== kSecp384r1
|| keySizeInBits
== kSecp521r1
) return errSecSuccess
;
1104 case CSSM_ALGID_RSA
:
1105 if(keySizeInBits
% 8) return errSecParam
;
1106 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= 2048;
1107 if(keySizeInBits
>= kSecRSAMin
&& keySizeInBits
<= kSecRSAMax
) return errSecSuccess
;
1109 case CSSM_ALGID_AES
:
1110 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSecAES128
;
1111 if(keySizeInBits
== kSecAES128
|| keySizeInBits
== kSecAES192
|| keySizeInBits
== kSecAES256
) return errSecSuccess
;
1113 case CSSM_ALGID_3DES
:
1114 if(keySizeInBits
== kSecDefaultKeySize
) keySizeInBits
= kSec3DES192
;
1115 if(keySizeInBits
== kSec3DES192
) return errSecSuccess
;
1134 struct ParameterAttribute
1136 const CFStringRef
*name
;
1142 static ParameterAttribute gAttributes
[] =
1149 &kSecAttrIsPermanent
,
1153 &kSecAttrApplicationTag
,
1157 &kSecAttrEffectiveKeySize
,
1161 &kSecAttrCanEncrypt
,
1165 &kSecAttrCanDecrypt
,
1186 const int kNumberOfAttributes
= sizeof(gAttributes
) / sizeof(ParameterAttribute
);
1188 static OSStatus
ScanDictionaryForParameters(CFDictionaryRef parameters
, void* attributePointers
[])
1191 for (i
= 0; i
< kNumberOfAttributes
; ++i
)
1193 // see if the corresponding tag exists in the dictionary
1194 CFTypeRef value
= CFDictionaryGetValue(parameters
, *(gAttributes
[i
].name
));
1197 switch (gAttributes
[i
].type
)
1200 // just return the value
1201 *(CFTypeRef
*) attributePointers
[i
] = value
;
1206 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1207 *(bool*) attributePointers
[i
] = CFBooleanGetValue(bRef
);
1213 CFNumberRef nRef
= (CFNumberRef
) value
;
1214 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, attributePointers
[i
]);
1221 return errSecSuccess
;
1226 static OSStatus
GetKeyParameters(CFDictionaryRef parameters
, int keySize
, bool isPublic
, CSSM_KEYUSE
&keyUse
, uint32
&attrs
, CFTypeRef
&labelRef
, CFDataRef
&applicationTagRef
)
1228 // establish default values
1230 bool isPermanent
= false;
1231 applicationTagRef
= NULL
;
1232 CFTypeRef effectiveKeySize
= NULL
;
1233 bool canDecrypt
= isPublic
? false : true;
1234 bool canEncrypt
= !canDecrypt
;
1235 bool canDerive
= true;
1236 bool canSign
= isPublic
? false : true;
1237 bool canVerify
= !canSign
;
1238 bool canUnwrap
= isPublic
? false : true;
1239 attrs
= CSSM_KEYATTR_EXTRACTABLE
;
1242 void* attributePointers
[] = {&labelRef
, &isPermanent
, &applicationTagRef
, &effectiveKeySize
, &canEncrypt
, &canDecrypt
,
1243 &canDerive
, &canSign
, &canVerify
, &canUnwrap
};
1245 // look for modifiers in the general dictionary
1246 OSStatus result
= ScanDictionaryForParameters(parameters
, attributePointers
);
1247 if (result
!= errSecSuccess
)
1252 // see if we have anything which modifies the defaults
1256 key
= kSecPublicKeyAttrs
;
1260 key
= kSecPrivateKeyAttrs
;
1263 CFTypeRef dType
= CFDictionaryGetValue(parameters
, key
);
1266 // this had better be a dictionary
1267 if (CFGetTypeID(dType
) != CFDictionaryGetTypeID())
1272 // pull any additional parameters out of this dictionary
1273 result
= ScanDictionaryForParameters((CFDictionaryRef
)dType
, attributePointers
);
1274 if (result
!= errSecSuccess
)
1280 // figure out the key usage
1284 keyUse
|= CSSM_KEYUSE_DECRYPT
;
1289 keyUse
|= CSSM_KEYUSE_ENCRYPT
;
1294 keyUse
|= CSSM_KEYUSE_DERIVE
;
1299 keyUse
|= CSSM_KEYUSE_SIGN
;
1304 keyUse
|= CSSM_KEYUSE_VERIFY
;
1309 keyUse
|= CSSM_KEYUSE_UNWRAP
;
1312 // public key is always extractable;
1313 // private key is extractable by default unless explicitly set to false
1314 CFTypeRef value
= NULL
;
1315 if (!isPublic
&& CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
) && value
)
1317 Boolean keyIsExtractable
= CFEqual(kCFBooleanTrue
, value
);
1318 if (!keyIsExtractable
)
1323 attrs
|= CSSM_KEYATTR_PERMANENT
;
1326 return errSecSuccess
;
1331 static OSStatus
MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters
,
1332 CSSM_ALGORITHMS
&algorithms
,
1333 uint32
&keySizeInBits
,
1334 CSSM_KEYUSE
&publicKeyUse
,
1335 uint32
&publicKeyAttr
,
1336 CFTypeRef
&publicKeyLabelRef
,
1337 CFDataRef
&publicKeyAttributeTagRef
,
1338 CSSM_KEYUSE
&privateKeyUse
,
1339 uint32
&privateKeyAttr
,
1340 CFTypeRef
&privateKeyLabelRef
,
1341 CFDataRef
&privateKeyAttributeTagRef
,
1342 SecAccessRef
&initialAccess
)
1346 result
= CheckAlgorithmType(parameters
, algorithms
);
1347 if (result
!= errSecSuccess
)
1352 result
= GetKeySize(parameters
, algorithms
, keySizeInBits
);
1353 if (result
!= errSecSuccess
)
1358 result
= GetKeyParameters(parameters
, keySizeInBits
, false, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1359 if (result
!= errSecSuccess
)
1364 result
= GetKeyParameters(parameters
, keySizeInBits
, true, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1365 if (result
!= errSecSuccess
)
1370 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&initialAccess
))
1372 initialAccess
= NULL
;
1374 else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess
))
1379 return errSecSuccess
;
1384 static OSStatus
SetKeyLabelAndTag(SecKeyRef keyRef
, CFTypeRef label
, CFDataRef tag
)
1386 int numToModify
= 0;
1397 if (numToModify
== 0)
1399 return errSecSuccess
;
1402 SecKeychainAttributeList attrList
;
1403 SecKeychainAttribute attributes
[numToModify
];
1409 if (CFStringGetTypeID() == CFGetTypeID(label
)) {
1410 CFStringRef label_string
= static_cast<CFStringRef
>(label
);
1411 attributes
[i
].tag
= kSecKeyPrintName
;
1412 attributes
[i
].data
= (void*) CFStringGetCStringPtr(label_string
, kCFStringEncodingUTF8
);
1413 if (NULL
== attributes
[i
].data
) {
1414 CFIndex buffer_length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string
), kCFStringEncodingUTF8
);
1415 attributes
[i
].data
= alloca((size_t)buffer_length
);
1416 if (NULL
== attributes
[i
].data
) {
1417 UnixError::throwMe(ENOMEM
);
1419 if (!CFStringGetCString(label_string
, static_cast<char *>(attributes
[i
].data
), buffer_length
, kCFStringEncodingUTF8
)) {
1420 MacOSError::throwMe(errSecParam
);
1423 attributes
[i
].length
= (UInt32
)strlen(static_cast<char *>(attributes
[i
].data
));
1424 } else if (CFDataGetTypeID() == CFGetTypeID(label
)) {
1425 // 10.6 bug compatibility
1426 CFDataRef label_data
= static_cast<CFDataRef
>(label
);
1427 attributes
[i
].tag
= kSecKeyLabel
;
1428 attributes
[i
].data
= (void*) CFDataGetBytePtr(label_data
);
1429 attributes
[i
].length
= (UInt32
)CFDataGetLength(label_data
);
1431 MacOSError::throwMe(errSecParam
);
1438 attributes
[i
].tag
= kSecKeyApplicationTag
;
1439 attributes
[i
].data
= (void*) CFDataGetBytePtr(tag
);
1440 attributes
[i
].length
= (UInt32
)CFDataGetLength(tag
);
1444 attrList
.count
= numToModify
;
1445 attrList
.attr
= attributes
;
1447 return SecKeychainItemModifyAttributesAndData((SecKeychainItemRef
) keyRef
, &attrList
, 0, NULL
);
1451 static CFTypeRef
GetAttributeFromParams(CFDictionaryRef parameters
, CFTypeRef attr
, CFTypeRef subParams
) {
1452 if (subParams
!= NULL
) {
1453 CFDictionaryRef subParamsDict
= (CFDictionaryRef
)CFDictionaryGetValue(parameters
, subParams
);
1454 if (subParamsDict
!= NULL
) {
1455 CFTypeRef value
= CFDictionaryGetValue(subParamsDict
, attr
);
1456 if (value
!= NULL
) {
1461 return CFDictionaryGetValue(parameters
, attr
);
1464 extern "C" OSStatus
SecKeyGeneratePair_ios(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
);
1467 /* Generate a private/public keypair. */
1469 SecKeyGeneratePairInternal(
1470 bool alwaysPermanent
,
1471 CFDictionaryRef parameters
,
1472 SecKeyRef
*publicKey
,
1473 SecKeyRef
*privateKey
)
1477 Required(parameters
);
1478 Required(publicKey
);
1479 Required(privateKey
);
1481 CFTypeRef tokenID
= GetAttributeFromParams(parameters
, kSecAttrTokenID
, NULL
);
1482 CFTypeRef noLegacy
= GetAttributeFromParams(parameters
, kSecAttrNoLegacy
, NULL
);
1483 CFTypeRef sync
= GetAttributeFromParams(parameters
, kSecAttrSynchronizable
, kSecPrivateKeyAttrs
);
1484 CFTypeRef accessControl
= GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPrivateKeyAttrs
) ?:
1485 GetAttributeFromParams(parameters
, kSecAttrAccessControl
, kSecPublicKeyAttrs
);
1486 CFTypeRef accessGroup
= GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPrivateKeyAttrs
) ?:
1487 GetAttributeFromParams(parameters
, kSecAttrAccessGroup
, kSecPublicKeyAttrs
);
1489 // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain).
1490 if (tokenID
!= NULL
||
1491 (noLegacy
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)noLegacy
)) ||
1492 (sync
!= NULL
&& CFBooleanGetValue((CFBooleanRef
)sync
)) ||
1493 accessControl
!= NULL
|| (accessGroup
!= NULL
&& CFEqual(accessGroup
, kSecAttrAccessGroupToken
))) {
1494 // Generate keys in iOS keychain.
1495 return SecKeyGeneratePair_ios(parameters
, publicKey
, privateKey
);
1498 CSSM_ALGORITHMS algorithms
;
1499 uint32 keySizeInBits
;
1500 CSSM_KEYUSE publicKeyUse
;
1501 uint32 publicKeyAttr
;
1502 CFTypeRef publicKeyLabelRef
;
1503 CFDataRef publicKeyAttributeTagRef
;
1504 CSSM_KEYUSE privateKeyUse
;
1505 uint32 privateKeyAttr
;
1506 CFTypeRef privateKeyLabelRef
;
1507 CFDataRef privateKeyAttributeTagRef
;
1508 SecAccessRef initialAccess
;
1509 SecKeychainRef keychain
;
1511 OSStatus result
= MakeKeyGenParametersFromDictionary(parameters
, algorithms
, keySizeInBits
, publicKeyUse
, publicKeyAttr
, publicKeyLabelRef
,
1512 publicKeyAttributeTagRef
, privateKeyUse
, privateKeyAttr
, privateKeyLabelRef
, privateKeyAttributeTagRef
,
1515 if (result
!= errSecSuccess
) {
1519 // verify keychain parameter
1520 keychain
= (SecKeychainRef
)CFDictionaryGetValue(parameters
, kSecUseKeychain
);
1521 if (keychain
!= NULL
&& SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1525 if (alwaysPermanent
) {
1526 publicKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1527 privateKeyAttr
|= CSSM_KEYATTR_PERMANENT
;
1530 // do the key generation
1531 result
= SecKeyCreatePair(keychain
, algorithms
, keySizeInBits
, 0, publicKeyUse
, publicKeyAttr
, privateKeyUse
, privateKeyAttr
, initialAccess
, publicKey
, privateKey
);
1532 if (result
!= errSecSuccess
) {
1536 // set the label and print attributes on the keys
1537 SetKeyLabelAndTag(*publicKey
, publicKeyLabelRef
, publicKeyAttributeTagRef
);
1538 SetKeyLabelAndTag(*privateKey
, privateKeyLabelRef
, privateKeyAttributeTagRef
);
1545 SecKeyGeneratePair(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
1546 return SecKeyGeneratePairInternal(true, parameters
, publicKey
, privateKey
);
1550 SecKeyCreateRandomKey(CFDictionaryRef parameters
, CFErrorRef
*error
) {
1551 SecKeyRef privateKey
= NULL
, publicKey
= NULL
;
1552 OSStatus status
= SecKeyGeneratePairInternal(false, parameters
, &publicKey
, &privateKey
);
1553 SecError(status
, error
, CFSTR("failed to generate asymmetric keypair"));
1554 if (publicKey
!= NULL
) {
1555 CFRelease(publicKey
);
1560 OSStatus
SecKeyRawVerifyOSX(
1561 SecKeyRef key
, /* Public key */
1562 SecPadding padding
, /* kSecPaddingNone or kSecPaddingPKCS1 */
1563 const uint8_t *signedData
, /* signature over this data */
1564 size_t signedDataLen
, /* length of dataToSign */
1565 const uint8_t *sig
, /* signature */
1568 return SecKeyRawVerify(key
,padding
,signedData
,signedDataLen
,sig
,sigLen
);
1576 utilGetStringFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, CFTypeRef defaultValue
)
1578 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1579 if (value
!= NULL
) return value
;
1580 return defaultValue
;
1584 utilGetNumberFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t defaultValue
)
1586 uint32_t integerValue
;
1587 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1588 if (value
!= NULL
) {
1589 CFNumberRef nRef
= (CFNumberRef
) value
;
1590 CFNumberGetValue(nRef
, kCFNumberSInt32Type
, &integerValue
);
1591 return integerValue
;
1593 return defaultValue
;
1597 utilGetMaskValFromCFDict(CFDictionaryRef parameters
, CFTypeRef key
, uint32_t maskValue
)
1599 CFTypeRef value
= CFDictionaryGetValue(parameters
, key
);
1600 if (value
!= NULL
) {
1601 CFBooleanRef bRef
= (CFBooleanRef
) value
;
1602 if(CFBooleanGetValue(bRef
)) return maskValue
;
1608 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters
, CSSM_ALGORITHMS
*algorithm
, uint32
*keySizeInBits
, CSSM_KEYUSE
*keyUsage
, CSSM_KEYCLASS
*keyClass
)
1610 CFTypeRef algorithmDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyType
, kSecAttrKeyTypeAES
);
1611 CFTypeRef keyClassDictValue
= utilGetStringFromCFDict(parameters
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1613 if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeAES
)) {
1614 *algorithm
= CSSM_ALGID_AES
;
1615 *keySizeInBits
= 128;
1616 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1617 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDES
)) {
1618 *algorithm
= CSSM_ALGID_DES
;
1619 *keySizeInBits
= 128;
1620 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1621 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyType3DES
)) {
1622 *algorithm
= CSSM_ALGID_3DES_3KEY_EDE
;
1623 *keySizeInBits
= 128;
1624 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1625 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC4
)) {
1626 *algorithm
= CSSM_ALGID_RC4
;
1627 *keySizeInBits
= 128;
1628 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1629 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRC2
)) {
1630 *algorithm
= CSSM_ALGID_RC2
;
1631 *keySizeInBits
= 128;
1632 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1633 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeCAST
)) {
1634 *algorithm
= CSSM_ALGID_CAST
;
1635 *keySizeInBits
= 128;
1636 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1637 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeRSA
)) {
1638 *algorithm
= CSSM_ALGID_RSA
;
1639 *keySizeInBits
= 128;
1640 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1641 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeDSA
)) {
1642 *algorithm
= CSSM_ALGID_DSA
;
1643 *keySizeInBits
= 128;
1644 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1645 } else if(CFEqual(algorithmDictValue
, kSecAttrKeyTypeECDSA
) ||
1646 CFEqual(algorithmDictValue
, kSecAttrKeyTypeEC
)) {
1647 *algorithm
= CSSM_ALGID_ECDSA
;
1648 *keySizeInBits
= 128;
1649 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1651 *algorithm
= CSSM_ALGID_AES
;
1652 *keySizeInBits
= 128;
1653 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1656 if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPublic
)) {
1657 *keyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
1658 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassPrivate
)) {
1659 *keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
1660 } else if(CFEqual(keyClassDictValue
, kSecAttrKeyClassSymmetric
)) {
1661 *keyClass
= CSSM_KEYCLASS_SESSION_KEY
;
1664 *keySizeInBits
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, *keySizeInBits
);
1665 *keyUsage
= utilGetMaskValFromCFDict(parameters
, kSecAttrCanEncrypt
, CSSM_KEYUSE_ENCRYPT
) |
1666 utilGetMaskValFromCFDict(parameters
, kSecAttrCanDecrypt
, CSSM_KEYUSE_DECRYPT
) |
1667 utilGetMaskValFromCFDict(parameters
, kSecAttrCanWrap
, CSSM_KEYUSE_WRAP
) |
1668 utilGetMaskValFromCFDict(parameters
, kSecAttrCanUnwrap
, CSSM_KEYUSE_UNWRAP
);
1671 if(*keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
|| *keyClass
== CSSM_KEYCLASS_PUBLIC_KEY
) {
1672 *keyUsage
|= utilGetMaskValFromCFDict(parameters
, kSecAttrCanSign
, CSSM_KEYUSE_SIGN
) |
1673 utilGetMaskValFromCFDict(parameters
, kSecAttrCanVerify
, CSSM_KEYUSE_VERIFY
);
1676 if(*keyUsage
== 0) {
1677 switch (*keyClass
) {
1678 case CSSM_KEYCLASS_PRIVATE_KEY
:
1679 *keyUsage
= CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
;
1681 case CSSM_KEYCLASS_PUBLIC_KEY
:
1682 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_WRAP
;
1685 *keyUsage
= CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
| CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
| CSSM_KEYUSE_SIGN
| CSSM_KEYUSE_VERIFY
;
1692 utilCopyDefaultKeyLabel(void)
1694 // generate a default label from the current date
1695 CFDateRef dateNow
= CFDateCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent());
1696 CFStringRef defaultLabel
= CFCopyDescription(dateNow
);
1699 return defaultLabel
;
1703 SecKeyGenerateSymmetric(CFDictionaryRef parameters
, CFErrorRef
*error
)
1705 OSStatus result
= errSecParam
; // default result for an early exit
1706 SecKeyRef key
= NULL
;
1707 SecKeychainRef keychain
= NULL
;
1708 SecAccessRef access
;
1710 CFStringRef appLabel
;
1712 CFStringRef dateLabel
= NULL
;
1714 CSSM_ALGORITHMS algorithm
;
1715 uint32 keySizeInBits
;
1716 CSSM_KEYUSE keyUsage
;
1717 uint32 keyAttr
= CSSM_KEYATTR_RETURN_DEFAULT
;
1718 CSSM_KEYCLASS keyClass
;
1720 Boolean isPermanent
;
1721 Boolean isExtractable
;
1723 // verify keychain parameter
1724 if (!CFDictionaryGetValueIfPresent(parameters
, kSecUseKeychain
, (const void **)&keychain
))
1726 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain
)) {
1733 // verify permanent parameter
1734 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsPermanent
, (const void **)&value
))
1735 isPermanent
= false;
1736 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1739 isPermanent
= CFEqual(kCFBooleanTrue
, value
);
1741 if (keychain
== NULL
) {
1742 // no keychain was specified, so use the default keychain
1743 result
= SecKeychainCopyDefault(&keychain
);
1745 keyAttr
|= CSSM_KEYATTR_PERMANENT
;
1748 // verify extractable parameter
1749 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrIsExtractable
, (const void **)&value
))
1750 isExtractable
= true; // default to extractable if value not specified
1751 else if (!value
|| (CFBooleanGetTypeID() != CFGetTypeID(value
)))
1754 isExtractable
= CFEqual(kCFBooleanTrue
, value
);
1756 keyAttr
|= CSSM_KEYATTR_EXTRACTABLE
;
1758 // verify access parameter
1759 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrAccess
, (const void **)&access
))
1761 else if (SecAccessGetTypeID() != CFGetTypeID(access
))
1764 // verify label parameter
1765 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrLabel
, (const void **)&label
))
1766 label
= (dateLabel
= utilCopyDefaultKeyLabel()); // no label provided, so use default
1767 else if (CFStringGetTypeID() != CFGetTypeID(label
))
1770 // verify application label parameter
1771 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationLabel
, (const void **)&appLabel
))
1772 appLabel
= (dateLabel
) ? dateLabel
: (dateLabel
= utilCopyDefaultKeyLabel());
1773 else if (CFStringGetTypeID() != CFGetTypeID(appLabel
))
1776 // verify application tag parameter
1777 if (!CFDictionaryGetValueIfPresent(parameters
, kSecAttrApplicationTag
, (const void **)&appTag
))
1779 else if (CFStringGetTypeID() != CFGetTypeID(appTag
))
1782 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1785 // the generated key will not be stored in any keychain
1786 result
= SecKeyGenerate(keychain
, algorithm
, keySizeInBits
, 0, keyUsage
, keyAttr
, access
, &key
);
1789 // we can set the label attributes on the generated key if it's a keychain item
1790 size_t labelBufLen
= (label
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label
), kCFStringEncodingUTF8
) + 1 : 0;
1791 char *labelBuf
= (char *)malloc(labelBufLen
);
1792 size_t appLabelBufLen
= (appLabel
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel
), kCFStringEncodingUTF8
) + 1 : 0;
1793 char *appLabelBuf
= (char *)malloc(appLabelBufLen
);
1794 size_t appTagBufLen
= (appTag
) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag
), kCFStringEncodingUTF8
) + 1 : 0;
1795 char *appTagBuf
= (char *)malloc(appTagBufLen
);
1797 if (label
&& !CFStringGetCString(label
, labelBuf
, labelBufLen
-1, kCFStringEncodingUTF8
))
1799 if (appLabel
&& !CFStringGetCString(appLabel
, appLabelBuf
, appLabelBufLen
-1, kCFStringEncodingUTF8
))
1801 if (appTag
&& !CFStringGetCString(appTag
, appTagBuf
, appTagBufLen
-1, kCFStringEncodingUTF8
))
1804 SecKeychainAttribute attrs
[] = {
1805 { kSecKeyPrintName
, (UInt32
)strlen(labelBuf
), (char *)labelBuf
},
1806 { kSecKeyLabel
, (UInt32
)strlen(appLabelBuf
), (char *)appLabelBuf
},
1807 { kSecKeyApplicationTag
, (UInt32
)strlen(appTagBuf
), (char *)appTagBuf
} };
1808 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
1809 if (!appTag
) --attributes
.count
;
1811 result
= SecKeyGenerateWithAttributes(&attributes
,
1812 keychain
, algorithm
, keySizeInBits
, 0,
1813 keyUsage
, keyAttr
, access
, &key
);
1821 if (result
&& error
) {
1822 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, result
, NULL
);
1825 CFRelease(dateLabel
);
1827 CFRelease(keychain
);
1835 SecKeyCreateFromData(CFDictionaryRef parameters
, CFDataRef keyData
, CFErrorRef
*error
)
1837 CSSM_ALGORITHMS algorithm
;
1838 uint32 keySizeInBits
;
1839 CSSM_KEYUSE keyUsage
;
1840 CSSM_KEYCLASS keyClass
;
1843 if(keyData
== NULL
|| CFDataGetLength(keyData
) == 0){
1844 MacOSError::throwMe(errSecUnsupportedKeySize
);
1847 utilGetKeyParametersFromCFDict(parameters
, &algorithm
, &keySizeInBits
, &keyUsage
, &keyClass
);
1849 CSSM_CSP_HANDLE cspHandle
= cuCspStartup(CSSM_FALSE
); // TRUE => CSP, FALSE => CSPDL
1851 SecKeyImportExportParameters iparam
;
1852 memset(&iparam
, 0, sizeof(iparam
));
1853 iparam
.keyUsage
= keyUsage
;
1855 CFRef
<CFDataRef
> data
;
1856 SecExternalItemType itype
;
1858 case CSSM_KEYCLASS_PRIVATE_KEY
:
1859 itype
= kSecItemTypePrivateKey
;
1861 case CSSM_KEYCLASS_PUBLIC_KEY
: {
1862 itype
= kSecItemTypePublicKey
;
1863 // Public key import expects public key in SubjPublicKey X509 format. We want to accept both bare and x509 format,
1864 // so we have to detect bare format here and extend to full X509 if detected.
1865 data
.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm
, keySizeInBits
, keyData
));
1868 case CSSM_KEYCLASS_SESSION_KEY
:
1869 itype
= kSecItemTypeSessionKey
;
1872 itype
= kSecItemTypeUnknown
;
1876 CFMutableArrayRef ka
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1877 // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful.
1878 crtn
= impExpImportRawKey(data
? CFDataRef(data
) : keyData
, kSecFormatUnknown
, itype
, algorithm
, NULL
, cspHandle
, 0, NULL
, NULL
, ka
);
1879 if (crtn
== CSSM_OK
&& CFArrayGetCount((CFArrayRef
)ka
)) {
1880 SecKeyRef sk
= (SecKeyRef
)CFArrayGetValueAtIndex((CFArrayRef
)ka
, 0);
1886 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, crtn
? crtn
: CSSM_ERRCODE_INTERNAL_ERROR
, NULL
);
1894 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable
, dispatch_queue_t deliveryQueue
,
1895 SecKeyGeneratePairBlock result
)
1897 CFDictionaryRef parameters
= CFDictionaryCreateCopy(NULL
, parametersWhichMightBeMutiable
);
1898 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
1899 SecKeyRef publicKey
= NULL
;
1900 SecKeyRef privateKey
= NULL
;
1901 OSStatus status
= SecKeyGeneratePair(parameters
, &publicKey
, &privateKey
);
1902 dispatch_async(deliveryQueue
, ^{
1903 CFErrorRef error
= NULL
;
1904 if (errSecSuccess
!= status
) {
1905 error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, status
, NULL
);
1907 result(publicKey
, privateKey
, error
);
1912 CFRelease(publicKey
);
1915 CFRelease(privateKey
);
1917 CFRelease(parameters
);
1922 static inline void utilClearAndFree(void *p
, size_t len
) {
1924 if(len
) bzero(p
, len
);
1930 SecKeyDeriveFromPassword(CFStringRef password
, CFDictionaryRef parameters
, CFErrorRef
*error
)
1932 CCPBKDFAlgorithm algorithm
;
1933 CFIndex passwordLen
= 0;
1934 CFDataRef keyData
= NULL
;
1935 char *thePassword
= NULL
;
1936 uint8_t *salt
= NULL
;
1937 uint8_t *derivedKey
= NULL
;
1938 size_t saltLen
= 0, derivedKeyLen
= 0;
1940 CFDataRef saltDictValue
, algorithmDictValue
;
1941 SecKeyRef retval
= NULL
;
1943 /* Pick Values from parameters */
1945 if((saltDictValue
= (CFDataRef
) CFDictionaryGetValue(parameters
, kSecAttrSalt
)) == NULL
) {
1946 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecMissingAlgorithmParms
, NULL
);
1950 derivedKeyLen
= utilGetNumberFromCFDict(parameters
, kSecAttrKeySizeInBits
, 128);
1951 // This value come in bits but the rest of the code treats it as bytes
1954 algorithmDictValue
= (CFDataRef
) utilGetStringFromCFDict(parameters
, kSecAttrPRF
, kSecAttrPRFHmacAlgSHA256
);
1956 rounds
= utilGetNumberFromCFDict(parameters
, kSecAttrRounds
, 0);
1958 /* Convert any remaining parameters and get the password bytes */
1960 saltLen
= CFDataGetLength(saltDictValue
);
1961 if((salt
= (uint8_t *) malloc(saltLen
)) == NULL
) {
1962 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
1966 CFDataGetBytes(saltDictValue
, CFRangeMake(0, saltLen
), (UInt8
*) salt
);
1968 passwordLen
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1;
1969 if((thePassword
= (char *) malloc(passwordLen
)) == NULL
) {
1970 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
1973 CFStringGetBytes(password
, CFRangeMake(0, CFStringGetLength(password
)), kCFStringEncodingUTF8
, '?', FALSE
, (UInt8
*)thePassword
, passwordLen
, &passwordLen
);
1975 if((derivedKey
= (uint8_t *) malloc(derivedKeyLen
)) == NULL
) {
1976 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecAllocate
, NULL
);
1980 if(algorithmDictValue
== NULL
) {
1981 algorithm
= kCCPRFHmacAlgSHA1
; /* default */
1982 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA1
)) {
1983 algorithm
= kCCPRFHmacAlgSHA1
;
1984 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA224
)) {
1985 algorithm
= kCCPRFHmacAlgSHA224
;
1986 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA256
)) {
1987 algorithm
= kCCPRFHmacAlgSHA256
;
1988 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA384
)) {
1989 algorithm
= kCCPRFHmacAlgSHA384
;
1990 } else if(CFEqual(algorithmDictValue
, kSecAttrPRFHmacAlgSHA512
)) {
1991 algorithm
= kCCPRFHmacAlgSHA512
;
1993 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidAlgorithmParms
, NULL
);
1998 rounds
= 33333; // we need to pass back a consistent value since there's no way to record the round count.
2001 if(CCKeyDerivationPBKDF(kCCPBKDF2
, thePassword
, passwordLen
, salt
, saltLen
, algorithm
, rounds
, derivedKey
, derivedKeyLen
)) {
2002 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2006 if((keyData
= CFDataCreate(NULL
, derivedKey
, derivedKeyLen
)) != NULL
) {
2007 retval
= SecKeyCreateFromData(parameters
, keyData
, error
);
2010 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInternalError
, NULL
);
2014 utilClearAndFree(salt
, saltLen
);
2015 utilClearAndFree(thePassword
, passwordLen
);
2016 utilClearAndFree(derivedKey
, derivedKeyLen
);
2021 SecKeyWrapSymmetric(SecKeyRef keyToWrap
, SecKeyRef wrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2023 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);
2028 SecKeyUnwrapSymmetric(CFDataRef
*keyToUnwrap
, SecKeyRef unwrappingKey
, CFDictionaryRef parameters
, CFErrorRef
*error
)
2030 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecUnimplemented
, NULL
);