]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecKey.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecKey.cpp
1 /*
2 * Copyright (c) 2002-2015 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <Security/SecKey.h>
25 #include <Security/SecKeyPriv.h>
26 #include <Security/SecKeyInternal.h>
27 #include <Security/SecItem.h>
28 #include <Security/SecItemPriv.h>
29 #include <libDER/asn1Types.h>
30 #include <libDER/DER_Encode.h>
31 #include <libDER/DER_Decode.h>
32 #include <libDER/DER_Keys.h>
33 #include <Security/SecAsn1Types.h>
34 #include <Security/SecAsn1Coder.h>
35 #include <security_keychain/KeyItem.h>
36 #include <security_utilities/casts.h>
37 #include <CommonCrypto/CommonKeyDerivation.h>
38
39 #include <CoreFoundation/CFPriv.h>
40 // 'verify' macro is somehow dragged in from CFPriv.h and breaks compilation of signclient.h, so undef it, we don't need it.
41 #undef verify
42
43 #include "SecBridge.h"
44
45 #include <security_keychain/Access.h>
46 #include <security_keychain/Keychains.h>
47 #include <security_keychain/KeyItem.h>
48 #include <string.h>
49 #include <syslog.h>
50
51 #include <security_cdsa_utils/cuCdsaUtils.h>
52 #include <security_cdsa_client/wrapkey.h>
53 #include <security_cdsa_client/genkey.h>
54 #include <security_cdsa_client/signclient.h>
55 #include <security_cdsa_client/cryptoclient.h>
56
57 #include "SecImportExportCrypto.h"
58
59 static OSStatus
60 SecCDSAKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) {
61 CDSASecKey *cdsaKey = (CDSASecKey *)key;
62 cdsaKey->key = const_cast<KeyItem *>(reinterpret_cast<const KeyItem *>(keyData));
63 CDSASecKey::keyItem(key)->initializeWithSecKeyRef(key);
64 cdsaKey->credentialType = kSecCredentialTypeDefault;
65 cdsaKey->cdsaKeyMutex = new Mutex();
66 return errSecSuccess;
67 }
68
69 static void
70 SecCDSAKeyDestroy(SecKeyRef keyRef) {
71 // Note: If this key is holding the last strong reference to its keychain, the keychain will be released during this operation.
72 // If we hold the keychain's mutex (the key's 'mutexForObject') during this destruction, pthread gets upset.
73 // Hold a reference to the keychain (if it exists) until after we release the keychain's mutex.
74
75 CDSASecKey *cdsaKey = static_cast<CDSASecKey *>(keyRef);
76 StMaybeLock<Mutex> cdsaMutex(cdsaKey->cdsaKeyMutex);
77
78 KeyItem *keyItem = static_cast<KeyItem *>(keyRef->key);
79
80 if (keyItem == NULL) {
81 // KeyImpl::attachSecKeyRef disconnected us from KeyItem instance, there is nothing to do for us.
82 cdsaMutex.unlock();
83 delete cdsaKey->cdsaKeyMutex;
84 return;
85 }
86
87 Keychain kc = keyItem->keychain();
88
89 // We have a +1 reference to the KeyItem now; no need to protect our storage any more
90 cdsaMutex.unlock();
91
92 {
93 StMaybeLock<Mutex> _(keyItem->getMutexForObject());
94 keyItem = static_cast<KeyItem *>(keyRef->key);
95 if (keyItem == NULL) {
96 // Second version of the check above, the definitive one because this one is performed with locked object's mutex, therefore we can be sure that KeyImpl is still connected to this keyRef instance.
97 return;
98 }
99
100 keyItem->aboutToDestruct();
101 delete keyItem;
102 }
103
104 delete cdsaKey->cdsaKeyMutex;
105
106 (void) kc; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain.
107 }
108
109 static size_t
110 SecCDSAKeyGetBlockSize(SecKeyRef key) {
111
112 CFErrorRef *error = NULL;
113 BEGIN_SECKEYAPI(size_t,0)
114
115 const CssmKey::Header keyHeader = CDSASecKey::keyItem(key)->unverifiedKeyHeader();
116 switch(keyHeader.algorithm())
117 {
118 case CSSM_ALGID_RSA:
119 case CSSM_ALGID_DSA:
120 result = keyHeader.LogicalKeySizeInBits / 8;
121 break;
122 case CSSM_ALGID_ECDSA:
123 {
124 /* Block size is up to 9 bytes of DER encoding for sequence of 2 integers,
125 * plus both coordinates for the point used */
126 #define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8)
127 #define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1)
128 size_t coordSize = ECDSA_MAX_COORD_SIZE_IN_BYTES(keyHeader.LogicalKeySizeInBits);
129 assert(coordSize < 256); /* size must fit in a byte for DER */
130 size_t coordDERLen = (coordSize > 127) ? 2 : 1;
131 size_t coordLen = 1 + coordDERLen + coordSize;
132
133 size_t pointSize = 2 * coordLen;
134 assert(pointSize < 256); /* size must fit in a byte for DER */
135 size_t pointDERLen = (pointSize > 127) ? 2 : 1;
136 size_t pointLen = 1 + pointDERLen + pointSize;
137
138 result = pointLen;
139 }
140 break;
141 case CSSM_ALGID_AES:
142 result = 16; /* all AES keys use 128-bit blocks */
143 break;
144 case CSSM_ALGID_DES:
145 case CSSM_ALGID_3DES_3KEY:
146 result = 8; /* all DES keys use 64-bit blocks */
147 break;
148 default:
149 assert(0); /* some other key algorithm */
150 result = 16; /* FIXME: revisit this */
151 break;
152 }
153
154 END_SECKEYAPI
155 }
156
157 static CFIndex
158 SecCDSAKeyGetAlgorithmId(SecKeyRef key) {
159
160 CFErrorRef *error = NULL;
161 BEGIN_SECKEYAPI(CFIndex, 0)
162
163 result = kSecNullAlgorithmID;
164 switch (CDSASecKey::keyItem(key)->unverifiedKeyHeader().AlgorithmId) {
165 case CSSM_ALGID_RSA:
166 result = kSecRSAAlgorithmID;
167 break;
168 case CSSM_ALGID_DSA:
169 result = kSecDSAAlgorithmID;
170 break;
171 case CSSM_ALGID_ECDSA:
172 result = kSecECDSAAlgorithmID;
173 break;
174 default:
175 assert(0); /* other algorithms TBA */
176 }
177
178 END_SECKEYAPI
179 }
180
181 static CFDataRef SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(CFDataRef pubKeyInfo) {
182 // First of all, consider x509 format and try to strip SubjPubKey envelope. If it fails, do not panic
183 // and export data as is.
184 DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), int_cast<CFIndex, DERSize>(CFDataGetLength(pubKeyInfo)) }, pubKeyItem;
185 DERByte numUnused;
186 DERSubjPubKeyInfo subjPubKey;
187 if (DERParseSequence(&keyItem, DERNumSubjPubKeyInfoItemSpecs,
188 DERSubjPubKeyInfoItemSpecs,
189 &subjPubKey, sizeof(subjPubKey)) == DR_Success &&
190 DERParseBitString(&subjPubKey.pubKey, &pubKeyItem, &numUnused) == DR_Success) {
191 return CFDataCreate(kCFAllocatorDefault, pubKeyItem.data, pubKeyItem.length);
192 }
193
194 return CFDataRef(CFRetain(pubKeyInfo));
195 }
196
197 static CFDataRef SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(CSSM_ALGORITHMS algorithm, uint32 keySizeInBits, CFDataRef pubKeyInfo) {
198 // First check, whether X509 pubkeyinfo is already present. If not, add it according to the key type.
199 DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), int_cast<CFIndex, DERSize>(CFDataGetLength(pubKeyInfo)) };
200 DERSubjPubKeyInfo subjPubKey;
201 if (DERParseSequence(&keyItem, DERNumSubjPubKeyInfoItemSpecs,
202 DERSubjPubKeyInfoItemSpecs,
203 &subjPubKey, sizeof(subjPubKey)) == DR_Success) {
204 return CFDataRef(CFRetain(pubKeyInfo));
205 }
206
207 // We have always size rounded to full bytes so bitstring encodes leading 00.
208 CFRef<CFMutableDataRef> bitStringPubKey = CFDataCreateMutable(kCFAllocatorDefault, 0);
209 CFDataSetLength(bitStringPubKey, 1);
210 CFDataAppendBytes(bitStringPubKey, CFDataGetBytePtr(pubKeyInfo), CFDataGetLength(pubKeyInfo));
211 subjPubKey.pubKey.data = static_cast<DERByte *>(const_cast<UInt8 *>(CFDataGetBytePtr(bitStringPubKey)));
212 subjPubKey.pubKey.length = CFDataGetLength(bitStringPubKey);
213
214 // Encode algId according to algorithm used.
215 static const DERByte oidRSA[] = {
216 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
217 };
218 static const DERByte oidECsecp256[] = {
219 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
220 };
221 static const DERByte oidECsecp384[] = {
222 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22,
223 };
224 static const DERByte oidECsecp521[] = {
225 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23,
226 };
227 subjPubKey.algId.length = 0;
228 if (algorithm == CSSM_ALGID_RSA) {
229 subjPubKey.algId.data = const_cast<DERByte *>(oidRSA);
230 subjPubKey.algId.length = sizeof(oidRSA);
231 } else if (algorithm == CSSM_ALGID_ECDSA) {
232 if (keySizeInBits == 256) {
233 subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp256);
234 subjPubKey.algId.length = sizeof(oidECsecp256);
235 } else if (keySizeInBits == 384) {
236 subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp384);
237 subjPubKey.algId.length = sizeof(oidECsecp384);
238 } if (keySizeInBits == 521) {
239 subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp521);
240 subjPubKey.algId.length = sizeof(oidECsecp521);
241 }
242 }
243 DERSize size = DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE, &subjPubKey,
244 DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs);
245 CFRef<CFMutableDataRef> keyData = CFDataCreateMutable(kCFAllocatorDefault, size);
246 CFDataSetLength(keyData, size);
247 if (DEREncodeSequence(ASN1_CONSTR_SEQUENCE, &subjPubKey,
248 DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs,
249 static_cast<DERByte *>(CFDataGetMutableBytePtr(keyData)), &size) == DR_Success) {
250 CFDataSetLength(keyData, size);
251 } else {
252 keyData.release();
253 }
254
255 return keyData.yield();
256 }
257
258 static OSStatus SecCDSAKeyCopyPublicBytes(SecKeyRef key, CFDataRef *serialization) {
259
260 CFErrorRef *error = NULL;
261 BEGIN_SECKEYAPI(OSStatus, errSecSuccess)
262
263 const CssmKey::Header &header = CDSASecKey::keyItem(key)->key().header();
264 switch (header.algorithm()) {
265 case CSSM_ALGID_RSA: {
266 switch (header.keyClass()) {
267 case CSSM_KEYCLASS_PRIVATE_KEY: {
268 CFRef<CFDataRef> privKeyData;
269 result = SecItemExport(key, kSecFormatOpenSSL, 0, NULL, privKeyData.take());
270 if (result == errSecSuccess) {
271 DERItem keyItem = { (DERByte *)CFDataGetBytePtr(privKeyData), int_cast<CFIndex, DERSize>(CFDataGetLength(privKeyData)) };
272 DERRSAKeyPair keyPair;
273 if (DERParseSequence(&keyItem, DERNumRSAKeyPairItemSpecs, DERRSAKeyPairItemSpecs,
274 &keyPair, sizeof(keyPair)) == DR_Success) {
275 DERRSAPubKeyPKCS1 pubKey = { keyPair.n, keyPair.e };
276 DERSize size = DERLengthOfEncodedSequence(ASN1_SEQUENCE, &pubKey,
277 DERNumRSAPubKeyPKCS1ItemSpecs, DERRSAPubKeyPKCS1ItemSpecs);
278 CFRef<CFMutableDataRef> keyData = CFDataCreateMutable(kCFAllocatorDefault, size);
279 CFDataSetLength(keyData, size);
280 UInt8 *data = CFDataGetMutableBytePtr(keyData);
281 if (DEREncodeSequence(ASN1_SEQUENCE, &pubKey,
282 DERNumRSAPubKeyPKCS1ItemSpecs, DERRSAPubKeyPKCS1ItemSpecs,
283 data, &size) == DR_Success) {
284 CFDataSetLength(keyData, size);
285 *data = ONE_BYTE_ASN1_CONSTR_SEQUENCE;
286 *serialization = keyData.yield();
287 } else {
288 *serialization = NULL;
289 result = errSecParam;
290 }
291 }
292 }
293 break;
294 }
295 case CSSM_KEYCLASS_PUBLIC_KEY:
296 result = SecItemExport(key, kSecFormatBSAFE, 0, NULL, serialization);
297 break;
298 }
299 break;
300 }
301 case CSSM_ALGID_ECDSA: {
302 *serialization = NULL;
303 CFRef<CFDataRef> tempPublicData;
304 result = SecItemExport(key, kSecFormatOpenSSL, 0, NULL, tempPublicData.take());
305 if (result == errSecSuccess) {
306 *serialization = SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(tempPublicData);
307 }
308 break;
309 }
310 default:
311 result = errSecUnimplemented;
312 }
313
314 END_SECKEYAPI
315 }
316
317 typedef struct {
318 DERItem privateKey;
319 DERItem publicKey;
320 } DERECPrivateKey;
321
322 static const DERItemSpec DERECPrivateKeyItemSpecs[] =
323 {
324 { 0,
325 ASN1_INTEGER,
326 DER_DEC_SKIP },
327 { DER_OFFSET(DERECPrivateKey, privateKey),
328 ASN1_OCTET_STRING,
329 DER_DEC_NO_OPTS | DER_ENC_NO_OPTS },
330 { 0,
331 ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0,
332 DER_DEC_SKIP | DER_ENC_NO_OPTS },
333 { DER_OFFSET(DERECPrivateKey, publicKey),
334 ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1,
335 DER_DEC_NO_OPTS | DER_ENC_SIGNED_INT },
336 };
337 static const DERSize DERNumECPrivateKeyItemSpecs =
338 sizeof(DERECPrivateKeyItemSpecs) / sizeof(DERItemSpec);
339
340 typedef struct {
341 DERItem bitString;
342 } DERECPrivateKeyPublicKey;
343
344 static const DERItemSpec DERECPrivateKeyPublicKeyItemSpecs[] =
345 {
346 { DER_OFFSET(DERECPrivateKeyPublicKey, bitString),
347 ASN1_BIT_STRING,
348 DER_DEC_NO_OPTS | DER_ENC_NO_OPTS },
349 };
350 static const DERSize DERNumECPrivateKeyPublicKeyItemSpecs =
351 sizeof(DERECPrivateKeyPublicKeyItemSpecs) / sizeof(DERItemSpec);
352
353 static CFDataRef
354 SecCDSAKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) {
355
356 BEGIN_SECKEYAPI(CFDataRef, NULL)
357
358 result = NULL;
359 const CssmKey::Header header = CDSASecKey::keyItem(key)->unverifiedKeyHeader();
360 CFRef<CFDataRef> keyData;
361 switch (header.algorithm()) {
362 case CSSM_ALGID_RSA:
363 MacOSError::check(SecItemExport(key, kSecFormatOpenSSL, 0, NULL, keyData.take()));
364 break;
365 case CSSM_ALGID_ECDSA: {
366 MacOSError::check(SecItemExport(key, kSecFormatOpenSSL, 0, NULL, keyData.take()));
367 if (header.keyClass() == CSSM_KEYCLASS_PRIVATE_KEY) {
368 // Convert DER format into x9.63 format, which is expected for exported key.
369 DERItem keyItem = { (DERByte *)CFDataGetBytePtr(keyData), int_cast<CFIndex, DERSize>(CFDataGetLength(keyData)) };
370 DERECPrivateKey privateKey;
371 DERECPrivateKeyPublicKey privateKeyPublicKey;
372 DERByte numUnused;
373 DERItem pubKeyItem;
374 if (DERParseSequence(&keyItem, DERNumECPrivateKeyItemSpecs, DERECPrivateKeyItemSpecs,
375 &privateKey, sizeof(privateKey)) == DR_Success &&
376 DERParseSequenceContent(&privateKey.publicKey, DERNumECPrivateKeyPublicKeyItemSpecs,
377 DERECPrivateKeyPublicKeyItemSpecs,
378 &privateKeyPublicKey, sizeof(privateKeyPublicKey)) == DR_Success &&
379 DERParseBitString(&privateKeyPublicKey.bitString, &pubKeyItem, &numUnused) == DR_Success) {
380 CFRef<CFMutableDataRef> key = CFDataCreateMutable(kCFAllocatorDefault,
381 pubKeyItem.length + privateKey.privateKey.length);
382 CFDataSetLength(key, pubKeyItem.length + privateKey.privateKey.length);
383 CFDataReplaceBytes(key, CFRangeMake(0, pubKeyItem.length), pubKeyItem.data, pubKeyItem.length);
384 CFDataReplaceBytes(key, CFRangeMake(pubKeyItem.length, privateKey.privateKey.length),
385 privateKey.privateKey.data, privateKey.privateKey.length);
386 keyData = key.as<CFDataRef>();
387 }
388 }
389 break;
390 }
391 default:
392 MacOSError::throwMe(errSecUnimplemented);
393 }
394
395 if (header.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY) {
396 result = SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(keyData);
397 } else {
398 result = keyData.yield();
399 }
400
401 END_SECKEYAPI
402 }
403
404 static CFDataRef SecCDSAKeyCopyLabel(SecKeyRef key) {
405 CFDataRef label = NULL;
406 if (CDSASecKey::keyItem(key)->isPersistent()) {
407 UInt32 tags[] = { kSecKeyLabel }, formats[] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB };
408 SecKeychainAttributeInfo info = { 1, tags, formats };
409 SecKeychainAttributeList *list = NULL;
410 CDSASecKey::keyItem(key)->getAttributesAndData(&info, NULL, &list, NULL, NULL);
411 if (list->count == 1) {
412 SecKeychainAttribute *attr = list->attr;
413 label = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)attr->data, (CFIndex)attr->length);
414 }
415 CDSASecKey::keyItem(key)->freeAttributesAndData(list, NULL);
416 }
417 return label;
418 }
419
420 static CFDictionaryRef
421 SecCDSAKeyCopyAttributeDictionary(SecKeyRef key) {
422
423 CFErrorRef *error = NULL;
424 BEGIN_SECKEYAPI(CFDictionaryRef, NULL)
425
426 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
427 &kCFTypeDictionaryValueCallBacks);
428
429 CFDictionarySetValue(dict, kSecClass, kSecClassKey);
430
431 const CssmKey::Header header = CDSASecKey::keyItem(key)->unverifiedKeyHeader();
432 CFIndex sizeValue = header.LogicalKeySizeInBits;
433 CFRef<CFNumberRef> sizeInBits = CFNumberCreate(NULL, kCFNumberCFIndexType, &sizeValue);
434 CFDictionarySetValue(dict, kSecAttrKeySizeInBits, sizeInBits);
435 CFDictionarySetValue(dict, kSecAttrEffectiveKeySize, sizeInBits);
436
437 CFRef<CFDataRef> label = SecCDSAKeyCopyLabel(key);
438 if (!label) {
439 // For floating keys, calculate label as SHA1 of pubkey bytes.
440 CFRef<CFDataRef> pubKeyBlob;
441 if (SecCDSAKeyCopyPublicBytes(key, pubKeyBlob.take()) == errSecSuccess) {
442 uint8_t pubKeyHash[CC_SHA1_DIGEST_LENGTH];
443 CC_SHA1(CFDataGetBytePtr(pubKeyBlob), CC_LONG(CFDataGetLength(pubKeyBlob)), pubKeyHash);
444 label.take(CFDataCreate(kCFAllocatorDefault, pubKeyHash, sizeof(pubKeyHash)));
445 }
446 }
447
448 if (label) {
449 CFDictionarySetValue(dict, kSecAttrApplicationLabel, label);
450 }
451
452 CSSM_KEYATTR_FLAGS attrs = header.attributes();
453 CFDictionarySetValue(dict, kSecAttrIsPermanent, (attrs & CSSM_KEYATTR_PERMANENT) ? kCFBooleanTrue : kCFBooleanFalse);
454 CFDictionarySetValue(dict, kSecAttrIsPrivate, (attrs & CSSM_KEYATTR_PRIVATE) ? kCFBooleanTrue : kCFBooleanFalse);
455 CFDictionarySetValue(dict, kSecAttrIsModifiable, (attrs & CSSM_KEYATTR_MODIFIABLE) ? kCFBooleanTrue : kCFBooleanFalse);
456 CFDictionarySetValue(dict, kSecAttrIsSensitive, (attrs & CSSM_KEYATTR_SENSITIVE) ? kCFBooleanTrue : kCFBooleanFalse);
457 CFDictionarySetValue(dict, kSecAttrIsExtractable, (attrs & CSSM_KEYATTR_EXTRACTABLE) ? kCFBooleanTrue : kCFBooleanFalse);
458 CFDictionarySetValue(dict, kSecAttrWasAlwaysSensitive, (attrs & CSSM_KEYATTR_ALWAYS_SENSITIVE) ? kCFBooleanTrue : kCFBooleanFalse);
459 CFDictionarySetValue(dict, kSecAttrWasNeverExtractable, (attrs & CSSM_KEYATTR_NEVER_EXTRACTABLE) ? kCFBooleanTrue : kCFBooleanFalse);
460
461 CFDictionarySetValue(dict, kSecAttrCanEncrypt, (header.useFor(CSSM_KEYUSE_ENCRYPT)) ? kCFBooleanTrue : kCFBooleanFalse);
462 CFDictionarySetValue(dict, kSecAttrCanDecrypt, (header.useFor(CSSM_KEYUSE_DECRYPT)) ? kCFBooleanTrue : kCFBooleanFalse);
463 CFDictionarySetValue(dict, kSecAttrCanSign, (header.useFor(CSSM_KEYUSE_SIGN)) ? kCFBooleanTrue : kCFBooleanFalse);
464 CFDictionarySetValue(dict, kSecAttrCanVerify, (header.useFor(CSSM_KEYUSE_VERIFY)) ? kCFBooleanTrue : kCFBooleanFalse);
465 CFDictionarySetValue(dict, kSecAttrCanSignRecover, (header.useFor(CSSM_KEYUSE_SIGN_RECOVER)) ? kCFBooleanTrue : kCFBooleanFalse);
466 CFDictionarySetValue(dict, kSecAttrCanVerifyRecover, (header.useFor(CSSM_KEYUSE_VERIFY_RECOVER)) ? kCFBooleanTrue : kCFBooleanFalse);
467 CFDictionarySetValue(dict, kSecAttrCanWrap, (header.useFor(CSSM_KEYUSE_WRAP)) ? kCFBooleanTrue : kCFBooleanFalse);
468 CFDictionarySetValue(dict, kSecAttrCanUnwrap, (header.useFor(CSSM_KEYUSE_UNWRAP)) ? kCFBooleanTrue : kCFBooleanFalse);
469 CFDictionarySetValue(dict, kSecAttrCanDerive, (header.useFor(CSSM_KEYUSE_DERIVE)) ? kCFBooleanTrue : kCFBooleanFalse);
470
471 switch (header.keyClass()) {
472 case CSSM_KEYCLASS_PUBLIC_KEY:
473 CFDictionarySetValue(dict, kSecAttrKeyClass, kSecAttrKeyClassPublic);
474 break;
475 case CSSM_KEYCLASS_PRIVATE_KEY:
476 CFDictionarySetValue(dict, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
477 break;
478 }
479
480 switch (header.algorithm()) {
481 case CSSM_ALGID_RSA:
482 CFDictionarySetValue(dict, kSecAttrKeyType, kSecAttrKeyTypeRSA);
483 break;
484 case CSSM_ALGID_ECDSA:
485 CFDictionarySetValue(dict, kSecAttrKeyType, kSecAttrKeyTypeECDSA);
486 break;
487 }
488
489 CFRef<CFDataRef> keyData;
490 if (SecItemExport(key, kSecFormatOpenSSL, 0, NULL, keyData.take()) == errSecSuccess) {
491 CFDictionarySetValue(dict, kSecValueData, keyData);
492 }
493
494 if (header.algorithm() == CSSM_ALGID_RSA && header.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY &&
495 header.blobType() == CSSM_KEYBLOB_RAW) {
496 const CssmData &keyData = CDSASecKey::keyItem(key)->key()->keyData();
497 DERItem keyItem = { static_cast<DERByte *>(keyData.data()), keyData.length() };
498 DERRSAPubKeyPKCS1 decodedKey;
499 if (DERParseSequence(&keyItem, DERNumRSAPubKeyPKCS1ItemSpecs,
500 DERRSAPubKeyPKCS1ItemSpecs,
501 &decodedKey, sizeof(decodedKey)) == DR_Success) {
502 CFRef<CFDataRef> modulus = CFDataCreate(kCFAllocatorDefault, decodedKey.modulus.data,
503 decodedKey.modulus.length);
504 CFDictionarySetValue(dict, CFSTR("_rsam"), modulus);
505 CFRef<CFDataRef> exponent = CFDataCreate(kCFAllocatorDefault, decodedKey.pubExponent.data,
506 decodedKey.pubExponent.length);
507 CFDictionarySetValue(dict, CFSTR("_rsae"), exponent);
508 }
509 }
510
511 result = dict;
512
513 END_SECKEYAPI
514 }
515
516 #pragma clang diagnostic push
517 #pragma clang diagnostic ignored "-Wunused-const-variable"
518 static CSSM_DB_NAME_ATTR(kInfoKeyLabel, kSecKeyLabel, (char*) "Label", 0, NULL, BLOB);
519 #pragma clang diagnostic pop
520
521 static SecKeyRef SecCDSAKeyCopyPublicKey(SecKeyRef privateKey) {
522 CFErrorRef *error = NULL;
523 BEGIN_SECKEYAPI(SecKeyRef, NULL)
524
525 result = NULL;
526 KeyItem *key = CDSASecKey::keyItem(privateKey);
527 CFRef<CFDataRef> label = SecCDSAKeyCopyLabel(privateKey);
528 if (label) {
529 // Lookup public key in the database.
530 DbUniqueRecord uniqueId;
531 SSDb ssDb(dynamic_cast<SSDbImpl *>(&(*key->keychain()->database())));
532 SSDbCursor dbCursor(ssDb, 1);
533 dbCursor->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY);
534 dbCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, CssmData(CFDataRef(label)));
535 if (dbCursor->next(NULL, NULL, uniqueId)) {
536 Item publicKey = key->keychain()->item(CSSM_DL_DB_RECORD_PUBLIC_KEY, uniqueId);
537 result = reinterpret_cast<SecKeyRef>(publicKey->handle());
538 }
539 }
540
541 if (result == NULL && key->publicKey()) {
542 SecPointer<KeyItem> publicKey(new KeyItem(key->publicKey()));
543 result = reinterpret_cast<SecKeyRef>(publicKey->handle());
544 }
545
546 END_SECKEYAPI
547 }
548
549 static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType &operation, SecKeyAlgorithm algorithm,
550 CSSM_ALGORITHMS &baseAlgorithm, CSSM_ALGORITHMS &secondaryAlgorithm,
551 CSSM_ALGORITHMS &paddingAlgorithm, CFIndex &inputSizeLimit) {
552 KeyItem *keyItem = CDSASecKey::keyItem(key);
553 CSSM_KEYCLASS keyClass = keyItem->key()->header().keyClass();
554 baseAlgorithm = keyItem->key()->header().algorithm();
555 switch (baseAlgorithm) {
556 case CSSM_ALGID_RSA:
557 if ((keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeSign) ||
558 (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeVerify)) {
559 if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureRaw)) {
560 secondaryAlgorithm = CSSM_ALGID_NONE;
561 paddingAlgorithm = CSSM_PADDING_NONE;
562 inputSizeLimit = 0;
563 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw)) {
564 secondaryAlgorithm = CSSM_ALGID_NONE;
565 paddingAlgorithm = CSSM_PADDING_PKCS1;
566 inputSizeLimit = -11;
567 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1)) {
568 secondaryAlgorithm = CSSM_ALGID_SHA1;
569 paddingAlgorithm = CSSM_PADDING_PKCS1;
570 inputSizeLimit = 20;
571 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224)) {
572 secondaryAlgorithm = CSSM_ALGID_SHA224;
573 paddingAlgorithm = CSSM_PADDING_PKCS1;
574 inputSizeLimit = 224 / 8;
575 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256)) {
576 secondaryAlgorithm = CSSM_ALGID_SHA256;
577 paddingAlgorithm = CSSM_PADDING_PKCS1;
578 inputSizeLimit = 256 / 8;
579 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384)) {
580 secondaryAlgorithm = CSSM_ALGID_SHA384;
581 paddingAlgorithm = CSSM_PADDING_PKCS1;
582 inputSizeLimit = 384 / 8;
583 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512)) {
584 secondaryAlgorithm = CSSM_ALGID_SHA512;
585 paddingAlgorithm = CSSM_PADDING_PKCS1;
586 inputSizeLimit = 512 / 8;
587 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5)) {
588 secondaryAlgorithm = CSSM_ALGID_MD5;
589 paddingAlgorithm = CSSM_PADDING_PKCS1;
590 inputSizeLimit = 16;
591 } else {
592 return NULL;
593 }
594 } else if ((keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeDecrypt) ||
595 (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeEncrypt)) {
596 if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) {
597 secondaryAlgorithm = CSSM_ALGID_NONE;
598 paddingAlgorithm = CSSM_PADDING_NONE;
599 inputSizeLimit = 0;
600 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionPKCS1)) {
601 secondaryAlgorithm = CSSM_ALGID_NONE;
602 paddingAlgorithm = CSSM_PADDING_PKCS1;
603 inputSizeLimit = operation == kSecKeyOperationTypeEncrypt ? -11 : 0;
604 } else {
605 return NULL;
606 }
607 } else if (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeDecrypt &&
608 CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) {
609 // Raw RSA decryption is identical to raw RSA encryption, so lets use encryption instead of decryption,
610 // because CDSA keys refuses to perform decrypt using public key.
611 operation = kSecKeyOperationTypeEncrypt;
612 secondaryAlgorithm = CSSM_ALGID_NONE;
613 paddingAlgorithm = CSSM_PADDING_NONE;
614 inputSizeLimit = 0;
615 } else {
616 return NULL;
617 }
618 break;
619 case CSSM_ALGID_ECDSA:
620 if ((keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeSign) ||
621 (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeVerify)) {
622 if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureRFC4754)) {
623 secondaryAlgorithm = CSSM_ALGID_NONE;
624 paddingAlgorithm = CSSM_PADDING_SIGRAW;
625 } else if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureDigestX962)) {
626 secondaryAlgorithm = CSSM_ALGID_NONE;
627 paddingAlgorithm = CSSM_PADDING_PKCS1;
628 } else {
629 return NULL;
630 }
631 } else if (keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeKeyExchange) {
632 if (CFEqual(algorithm,kSecKeyAlgorithmECDHKeyExchangeStandard) ||
633 CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeCofactor)) {
634 baseAlgorithm = CSSM_ALGID_ECDH;
635 } else if (CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1) ||
636 CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1)) {
637 baseAlgorithm = CSSM_ALGID_ECDH_X963_KDF;
638 } else {
639 return NULL;
640 }
641 } else {
642 return NULL;
643 }
644 break;
645 default:
646 MacOSError::throwMe(errSecParam);
647 }
648 return keyItem;
649 }
650
651 static CFDataRef
652 SecCDSAKeyCopyPaddedPlaintext(SecKeyRef key, CFDataRef plaintext, SecKeyAlgorithm algorithm) {
653 CFIndex blockSize = CDSASecKey::keyItem(key)->key().header().LogicalKeySizeInBits / 8;
654 CFIndex plaintextLength = CFDataGetLength(plaintext);
655 if ((algorithm == kSecKeyAlgorithmRSAEncryptionRaw || algorithm == kSecKeyAlgorithmRSASignatureRaw)
656 && plaintextLength < blockSize) {
657 // Pre-pad with zeroes.
658 CFMutableDataRef result(CFDataCreateMutable(kCFAllocatorDefault, blockSize));
659 CFDataSetLength(result, blockSize);
660 CFDataReplaceBytes(result, CFRangeMake(blockSize - plaintextLength, plaintextLength),
661 CFDataGetBytePtr(plaintext), plaintextLength);
662 return result;
663 } else {
664 return CFDataRef(CFRetain(plaintext));
665 }
666 }
667
668 static CFTypeRef SecCDSAKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm,
669 CFArrayRef allAlgorithms, SecKeyOperationMode mode,
670 CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
671 BEGIN_SECKEYAPI(CFTypeRef, kCFNull)
672 CFIndex inputSizeLimit = 0;
673 CSSM_ALGORITHMS baseAlgorithm, secondaryAlgorithm, paddingAlgorithm;
674 KeyItem *keyItem = SecCDSAKeyPrepareParameters(key, operation, algorithm, baseAlgorithm, secondaryAlgorithm, paddingAlgorithm, inputSizeLimit);
675 if (keyItem == NULL) {
676 // Operation/algorithm/key combination is not supported.
677 return kCFNull;
678 } else if (mode == kSecKeyOperationModeCheckIfSupported) {
679 // Operation is supported and caller wants to just know that.
680 return kCFBooleanTrue;
681 } else if (baseAlgorithm == CSSM_ALGID_RSA) {
682 if (inputSizeLimit <= 0) {
683 inputSizeLimit += SecCDSAKeyGetBlockSize(key);
684 }
685 if (CFDataGetLength((CFDataRef)in1) > inputSizeLimit) {
686 MacOSError::throwMe(errSecParam);
687 }
688 }
689
690 CDSASecKey *cdsaKey = static_cast<CDSASecKey *>(key);
691 switch (operation) {
692 case kSecKeyOperationTypeSign: {
693 CssmClient::Sign signContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm);
694 signContext.key(keyItem->key());
695 signContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN, cdsaKey->credentialType));
696 signContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm);
697 CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
698 CssmAutoData signature(signContext.allocator());
699 signContext.sign(CssmData(CFDataRef(input)), signature.get());
700 result = CFDataCreate(NULL, static_cast<const UInt8 *>(signature.data()), CFIndex(signature.length()));
701 break;
702 }
703 case kSecKeyOperationTypeVerify: {
704 CssmClient::Verify verifyContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm);
705 verifyContext.key(keyItem->key());
706 verifyContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ANY, cdsaKey->credentialType));
707 verifyContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm);
708 CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
709 verifyContext.verify(CssmData(CFDataRef(input)), CssmData(CFRef<CFDataRef>::check(in2, errSecParam)));
710 result = kCFBooleanTrue;
711 break;
712 }
713 case kSecKeyOperationTypeEncrypt: {
714 CssmClient::Encrypt encryptContext(keyItem->csp(), baseAlgorithm);
715 encryptContext.key(keyItem->key());
716 encryptContext.padding(paddingAlgorithm);
717 encryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT, cdsaKey->credentialType));
718 CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
719 CssmAutoData output(encryptContext.allocator()), remainingData(encryptContext.allocator());
720 size_t length = encryptContext.encrypt(CssmData(CFDataRef(input)), output.get(), remainingData.get());
721 result = CFDataCreateMutable(kCFAllocatorDefault, output.length() + remainingData.length());
722 CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(output.data()), output.length());
723 CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(remainingData.data()), remainingData.length());
724 CFDataSetLength(CFMutableDataRef(result), length);
725 break;
726 }
727 case kSecKeyOperationTypeDecrypt: {
728 CssmClient::Decrypt decryptContext(keyItem->csp(), baseAlgorithm);
729 decryptContext.key(keyItem->key());
730 decryptContext.padding(paddingAlgorithm);
731 decryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT, cdsaKey->credentialType));
732 CssmAutoData output(decryptContext.allocator()), remainingData(decryptContext.allocator());
733 size_t length = decryptContext.decrypt(CssmData(CFRef<CFDataRef>::check(in1, errSecParam)),
734 output.get(), remainingData.get());
735 result = CFDataCreateMutable(kCFAllocatorDefault, output.length() + remainingData.length());
736 CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(output.data()), output.length());
737 CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(remainingData.data()), remainingData.length());
738 CFDataSetLength(CFMutableDataRef(result), length);
739 break;
740 }
741 case kSecKeyOperationTypeKeyExchange: {
742 CFIndex requestedLength = 0;
743 CssmData sharedInfo;
744 switch (baseAlgorithm) {
745 case CSSM_ALGID_ECDH:
746 requestedLength = (keyItem->key().header().LogicalKeySizeInBits + 7) / 8;
747 break;
748 case CSSM_ALGID_ECDH_X963_KDF:
749 CFDictionaryRef params = CFRef<CFDictionaryRef>::check(in2, errSecParam);
750 CFTypeRef value = params ? CFDictionaryGetValue(params, kSecKeyKeyExchangeParameterRequestedSize) : NULL;
751 if (value == NULL || CFGetTypeID(value) != CFNumberGetTypeID() ||
752 !CFNumberGetValue(CFNumberRef(value), kCFNumberCFIndexType, &requestedLength)) {
753 MacOSError::throwMe(errSecParam);
754 }
755 value = CFDictionaryGetValue(params, kSecKeyKeyExchangeParameterSharedInfo);
756 if (value != NULL && CFGetTypeID(value) == CFDataGetTypeID()) {
757 sharedInfo = CssmData(CFDataRef(value));
758 }
759 break;
760 }
761
762 CssmClient::DeriveKey derive(keyItem->csp(), baseAlgorithm, CSSM_ALGID_AES, uint32(requestedLength * 8));
763 derive.key(keyItem->key());
764 derive.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DERIVE, kSecCredentialTypeDefault));
765 derive.salt(sharedInfo);
766 CssmData param(CFRef<CFDataRef>::check(in1, errSecParam));
767 Key derivedKey = derive(&param, KeySpec(CSSM_KEYUSE_ANY, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE));
768
769 // Export raw data of newly derived key (by wrapping with an empty key).
770 CssmClient::WrapKey wrapper(keyItem->csp(), CSSM_ALGID_NONE);
771 Key wrappedKey = wrapper(derivedKey);
772 result = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)wrappedKey->data(), CFIndex(wrappedKey->length()));
773 break;
774 }
775 default:
776 break;
777 }
778
779 END_SECKEYAPI
780 }
781
782 static Boolean SecCDSAKeyIsEqual(SecKeyRef key1, SecKeyRef key2) {
783 CFErrorRef *error = NULL;
784 BEGIN_SECKEYAPI(Boolean, false)
785
786 result = CDSASecKey::keyItem(key1)->equal(*CDSASecKey::keyItem(key2));
787
788 END_SECKEYAPI
789 }
790
791 static Boolean SecCDSAKeySetParameter(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error) {
792 BEGIN_SECKEYAPI(Boolean, false)
793
794 if (CFEqual(name, kSecUseAuthenticationUI)) {
795 static_cast<CDSASecKey *>(key)->credentialType = CFEqual(value, kSecUseAuthenticationUIAllow) ? kSecCredentialTypeDefault : kSecCredentialTypeNoUI;
796 result = true;
797 } else {
798 result = SecError(errSecUnimplemented, error, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name);
799 }
800
801 END_SECKEYAPI
802 }
803
804 const SecKeyDescriptor kSecCDSAKeyDescriptor = {
805 .version = kSecKeyDescriptorVersion,
806 .name = "CDSAKey",
807 .extraBytes = (sizeof(class CDSASecKey) > sizeof(struct __SecKey) ? (sizeof(class CDSASecKey) - sizeof(struct __SecKey)) : 0),
808
809 .init = SecCDSAKeyInit,
810 .destroy = SecCDSAKeyDestroy,
811 .blockSize = SecCDSAKeyGetBlockSize,
812 .copyDictionary = SecCDSAKeyCopyAttributeDictionary,
813 .getAlgorithmID = SecCDSAKeyGetAlgorithmId,
814 .copyPublic = SecCDSAKeyCopyPublicBytes,
815 .copyExternalRepresentation = SecCDSAKeyCopyExternalRepresentation,
816 .copyPublicKey = SecCDSAKeyCopyPublicKey,
817 .copyOperationResult = SecCDSAKeyCopyOperationResult,
818 .isEqual = SecCDSAKeyIsEqual,
819 .setParameter = SecCDSAKeySetParameter,
820 };
821
822 namespace Security {
823 namespace KeychainCore {
824 SecCFObject *KeyItem::fromSecKeyRef(CFTypeRef ptr) {
825 if (ptr == NULL || CFGetTypeID(ptr) != SecKeyGetTypeID()) {
826 return NULL;
827 }
828
829 SecKeyRef key = static_cast<SecKeyRef>(const_cast<void *>(ptr));
830 if (key->key_class == &kSecCDSAKeyDescriptor) {
831 return static_cast<SecCFObject *>(key->key);
832 }
833
834 CFRef<SecKeyRef> cdsaKey = SecKeyCopyAuxilliaryCDSAKeyForKey(key);
835 if (!cdsaKey) {
836 // Create CDSA key from exported data of existing key.
837 CFRef<CFDictionaryRef> keyAttributes = SecKeyCopyAttributes(key);
838 if (keyAttributes) {
839 CFRef<CFDataRef> keyData = SecKeyCopyExternalRepresentation(key, NULL);
840 if (!keyData) {
841 CFTypeRef pubKeyHash = CFDictionaryGetValue(keyAttributes, kSecAttrApplicationLabel);
842 const void *keys[] = { kSecClass, kSecUseDataProtectionKeychain, kSecReturnRef, kSecMatchLimit };
843 const void *values[] = { kSecClassIdentity, kCFBooleanFalse, kCFBooleanTrue, kSecMatchLimitAll };
844 CFRef<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, keys, values,
845 sizeof(keys) / sizeof(*keys),
846 &kCFTypeDictionaryKeyCallBacks,
847 &kCFTypeDictionaryValueCallBacks);
848 CFRef<CFArrayRef> identities;
849 OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)identities.take());
850 if (status == errSecSuccess) {
851 for (int i = 0; i < CFArrayGetCount(identities); ++i) {
852 CFRef<SecKeyRef> privateKey;
853 if (SecIdentityCopyPrivateKey((SecIdentityRef)CFArrayGetValueAtIndex(identities, i), privateKey.take()) != errSecSuccess) {
854 continue;
855 }
856 CFRef<CFDictionaryRef> attrs = SecKeyCopyAttributes(privateKey);
857 if (CFEqual(CFDictionaryGetValue(attrs, kSecAttrApplicationLabel), pubKeyHash)) {
858 cdsaKey = privateKey;
859 SecKeySetAuxilliaryCDSAKeyForKey(key, cdsaKey.get());
860 break;
861 }
862 }
863 }
864 } else {
865 cdsaKey.take(SecKeyCreateFromData(keyAttributes, keyData, NULL));
866 if (cdsaKey) {
867 SecKeySetAuxilliaryCDSAKeyForKey(key, cdsaKey.get());
868 }
869 }
870 }
871 }
872
873 return cdsaKey ? CDSASecKey::keyItem(cdsaKey.get()) : NULL;
874 }
875
876 // You need to hold this key's MutexForObject when you run this
877 void KeyItem::attachSecKeyRef() const {
878 SecKeyRef key = SecKeyCreate(NULL, &kSecCDSAKeyDescriptor, reinterpret_cast<const uint8_t *>(this), 0, 0);
879 CDSASecKey::keyItem(key)->mWeakSecKeyRef = key;
880 }
881
882 }
883 }
884
885 extern "C" Boolean SecKeyIsCDSAKey(SecKeyRef ref);
886 Boolean SecKeyIsCDSAKey(SecKeyRef ref) {
887 return ref->key_class == &kSecCDSAKeyDescriptor;
888 }
889
890
891 static OSStatus SecKeyCreatePairInternal(
892 SecKeychainRef keychainRef,
893 CSSM_ALGORITHMS algorithm,
894 uint32 keySizeInBits,
895 CSSM_CC_HANDLE contextHandle,
896 CSSM_KEYUSE publicKeyUsage,
897 uint32 publicKeyAttr,
898 CSSM_KEYUSE privateKeyUsage,
899 uint32 privateKeyAttr,
900 SecAccessRef initialAccess,
901 SecKeyRef* publicKeyRef,
902 SecKeyRef* privateKeyRef)
903 {
904 BEGIN_SECAPI
905
906 Keychain keychain;
907 SecPointer<Access> theAccess(initialAccess ? Access::required(initialAccess) : new Access("<key>"));
908 SecPointer<KeyItem> pubItem, privItem;
909 if (((publicKeyAttr | privateKeyAttr) & CSSM_KEYATTR_PERMANENT) != 0) {
910 keychain = Keychain::optional(keychainRef);
911 }
912 StMaybeLock<Mutex> _(keychain ? keychain->getKeychainMutex() : NULL);
913 KeyItem::createPair(keychain, algorithm, keySizeInBits, contextHandle, publicKeyUsage, publicKeyAttr,
914 privateKeyUsage, privateKeyAttr, theAccess, pubItem, privItem);
915
916 // Return the generated keys.
917 if (publicKeyRef)
918 *publicKeyRef = pubItem->handle();
919 if (privateKeyRef)
920 *privateKeyRef = privItem->handle();
921
922 END_SECAPI
923 }
924
925 OSStatus
926 SecKeyCreatePair(
927 SecKeychainRef keychainRef,
928 CSSM_ALGORITHMS algorithm,
929 uint32 keySizeInBits,
930 CSSM_CC_HANDLE contextHandle,
931 CSSM_KEYUSE publicKeyUsage,
932 uint32 publicKeyAttr,
933 CSSM_KEYUSE privateKeyUsage,
934 uint32 privateKeyAttr,
935 SecAccessRef initialAccess,
936 SecKeyRef* publicKeyRef,
937 SecKeyRef* privateKeyRef)
938 {
939 OSStatus result = SecKeyCreatePairInternal(keychainRef, algorithm, keySizeInBits, contextHandle, publicKeyUsage,
940 publicKeyAttr, privateKeyUsage, privateKeyAttr, initialAccess, publicKeyRef, privateKeyRef);
941
942 return result;
943 }
944
945
946
947 OSStatus
948 SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY **cssmKey)
949 {
950 BEGIN_SECAPI
951
952 Required(cssmKey) = KeyItem::required(key)->key();
953
954 END_SECAPI
955 }
956
957
958 //
959 // Private APIs
960 //
961
962 static ModuleNexus<Mutex> gSecReturnedKeyCSPsMutex;
963 static ModuleNexus<std::set<CssmClient::CSP>> gSecReturnedKeyCSPs;
964
965 OSStatus
966 SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle)
967 {
968 BEGIN_SECAPI
969
970 SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
971
972 // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP).
973 // Keep a global pointer to it to force the CSP to stay live forever.
974 CssmClient::CSP returnedKeyCSP = keyItem->csp();
975 {
976 StLock<Mutex> _(gSecReturnedKeyCSPsMutex());
977 gSecReturnedKeyCSPs().insert(returnedKeyCSP);
978 }
979 Required(cspHandle) = returnedKeyCSP->handle();
980
981 END_SECAPI
982 }
983
984 /* deprecated as of 10.8 */
985 OSStatus
986 SecKeyGetAlgorithmID(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER **algid)
987 {
988 BEGIN_SECAPI
989
990 SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
991 Required(algid) = &keyItem->algorithmIdentifier();
992
993 END_SECAPI
994 }
995
996 OSStatus
997 SecKeyGetStrengthInBits(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER *algid, unsigned int *strength)
998 {
999 BEGIN_SECAPI
1000
1001 SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
1002 Required(strength) = keyItem->strengthInBits(algid);
1003
1004 END_SECAPI
1005 }
1006
1007 OSStatus
1008 SecKeyGetCredentials(
1009 SecKeyRef keyRef,
1010 CSSM_ACL_AUTHORIZATION_TAG operation,
1011 SecCredentialType credentialType,
1012 const CSSM_ACCESS_CREDENTIALS **outCredentials)
1013 {
1014 BEGIN_SECAPI
1015
1016 SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
1017 Required(outCredentials) = keyItem->getCredentials(operation, credentialType);
1018
1019 END_SECAPI
1020 }
1021
1022 OSStatus
1023 SecKeyImportPair(
1024 SecKeychainRef keychainRef,
1025 const CSSM_KEY *publicCssmKey,
1026 const CSSM_KEY *privateCssmKey,
1027 SecAccessRef initialAccess,
1028 SecKeyRef* publicKey,
1029 SecKeyRef* privateKey)
1030 {
1031 BEGIN_SECAPI
1032
1033 Keychain keychain = Keychain::optional(keychainRef);
1034 SecPointer<Access> theAccess(initialAccess ? Access::required(initialAccess) : new Access("<key>"));
1035 SecPointer<KeyItem> pubItem, privItem;
1036
1037 KeyItem::importPair(keychain,
1038 Required(publicCssmKey),
1039 Required(privateCssmKey),
1040 theAccess,
1041 pubItem,
1042 privItem);
1043
1044 // Return the generated keys.
1045 if (publicKey)
1046 *publicKey = pubItem->handle();
1047 if (privateKey)
1048 *privateKey = privItem->handle();
1049
1050 END_SECAPI
1051 }
1052
1053 static OSStatus
1054 SecKeyGenerateWithAttributes(
1055 SecKeychainAttributeList* attrList,
1056 SecKeychainRef keychainRef,
1057 CSSM_ALGORITHMS algorithm,
1058 uint32 keySizeInBits,
1059 CSSM_CC_HANDLE contextHandle,
1060 CSSM_KEYUSE keyUsage,
1061 uint32 keyAttr,
1062 SecAccessRef initialAccess,
1063 SecKeyRef* keyRef)
1064 {
1065 BEGIN_SECAPI
1066
1067 Keychain keychain;
1068 SecPointer<Access> theAccess;
1069
1070 if (keychainRef)
1071 keychain = KeychainImpl::required(keychainRef);
1072 if (initialAccess)
1073 theAccess = Access::required(initialAccess);
1074
1075 SecPointer<KeyItem> item = KeyItem::generateWithAttributes(attrList,
1076 keychain,
1077 algorithm,
1078 keySizeInBits,
1079 contextHandle,
1080 keyUsage,
1081 keyAttr,
1082 theAccess);
1083
1084 // Return the generated key.
1085 if (keyRef)
1086 *keyRef = item->handle();
1087
1088 END_SECAPI
1089 }
1090
1091 OSStatus
1092 SecKeyGenerate(
1093 SecKeychainRef keychainRef,
1094 CSSM_ALGORITHMS algorithm,
1095 uint32 keySizeInBits,
1096 CSSM_CC_HANDLE contextHandle,
1097 CSSM_KEYUSE keyUsage,
1098 uint32 keyAttr,
1099 SecAccessRef initialAccess,
1100 SecKeyRef* keyRef)
1101 {
1102 return SecKeyGenerateWithAttributes(NULL,
1103 keychainRef, algorithm, keySizeInBits,
1104 contextHandle, keyUsage, keyAttr,
1105 initialAccess, keyRef);
1106 }
1107
1108 /* new in 10.6 */
1109 /* Generate a floating key reference from a CSSM_KEY */
1110 OSStatus
1111 SecKeyCreateWithCSSMKey(const CSSM_KEY *cssmKey,
1112 SecKeyRef *keyRef)
1113 {
1114 BEGIN_SECAPI
1115
1116 Required(cssmKey);
1117 if(cssmKey->KeyData.Length == 0){
1118 MacOSError::throwMe(errSecInvalidAttributeKeyLength);
1119 }
1120 if(cssmKey->KeyData.Data == NULL){
1121 MacOSError::throwMe(errSecInvalidPointer);
1122 }
1123 CssmClient::CSP csp(cssmKey->KeyHeader.CspId);
1124 CssmClient::Key key(csp, *cssmKey);
1125 KeyItem *item = new KeyItem(key);
1126
1127 // Return the generated key.
1128 if (keyRef)
1129 *keyRef = SecKeyCreate(NULL, &kSecCDSAKeyDescriptor, (const uint8_t *)item, 0, 0);
1130
1131 END_SECAPI
1132 }
1133
1134
1135
1136 static u_int32_t ConvertCFStringToInteger(CFStringRef ref)
1137 {
1138 if (ref == NULL)
1139 {
1140 return 0;
1141 }
1142
1143 // figure out the size of the string
1144 CFIndex numChars = CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref), kCFStringEncodingUTF8);
1145 char *buffer = (char *)malloc(numChars);
1146 if (NULL == buffer) {
1147 UnixError::throwMe(ENOMEM);
1148 }
1149 if (!CFStringGetCString(ref, buffer, numChars, kCFStringEncodingUTF8))
1150 {
1151 free(buffer);
1152 MacOSError::throwMe(errSecParam);
1153 }
1154
1155 u_int32_t result = atoi(buffer);
1156 free(buffer);
1157 return result;
1158 }
1159
1160
1161
1162 static OSStatus CheckAlgorithmType(CFDictionaryRef parameters, CSSM_ALGORITHMS &algorithms)
1163 {
1164 // figure out the algorithm to use
1165 CFStringRef ktype = (CFStringRef) CFDictionaryGetValue(parameters, kSecAttrKeyType);
1166 if (ktype == NULL)
1167 {
1168 return errSecParam;
1169 }
1170
1171 if (CFEqual(ktype, kSecAttrKeyTypeRSA)) {
1172 algorithms = CSSM_ALGID_RSA;
1173 return errSecSuccess;
1174 } else if(CFEqual(ktype, kSecAttrKeyTypeECDSA) ||
1175 CFEqual(ktype, kSecAttrKeyTypeEC)) {
1176 algorithms = CSSM_ALGID_ECDSA;
1177 return errSecSuccess;
1178 } else if(CFEqual(ktype, kSecAttrKeyTypeAES)) {
1179 algorithms = CSSM_ALGID_AES;
1180 return errSecSuccess;
1181 } else if(CFEqual(ktype, kSecAttrKeyType3DES)) {
1182 algorithms = CSSM_ALGID_3DES;
1183 return errSecSuccess;
1184 } else {
1185 return errSecUnsupportedAlgorithm;
1186 }
1187 }
1188
1189
1190
1191 static OSStatus GetKeySize(CFDictionaryRef parameters, CSSM_ALGORITHMS algorithms, uint32 &keySizeInBits)
1192 {
1193
1194 // get the key size and check it for validity
1195 CFTypeRef ref = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits);
1196
1197 keySizeInBits = kSecDefaultKeySize;
1198
1199 CFTypeID bitSizeType = CFGetTypeID(ref);
1200 if (bitSizeType == CFStringGetTypeID())
1201 keySizeInBits = ConvertCFStringToInteger((CFStringRef) ref);
1202 else if (bitSizeType == CFNumberGetTypeID())
1203 CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &keySizeInBits);
1204 else return errSecParam;
1205
1206
1207 switch (algorithms) {
1208 case CSSM_ALGID_ECDSA:
1209 if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSecp256r1;
1210 if(keySizeInBits == kSecp192r1 || keySizeInBits == kSecp256r1 || keySizeInBits == kSecp384r1 || keySizeInBits == kSecp521r1 ) return errSecSuccess;
1211 break;
1212 case CSSM_ALGID_RSA:
1213 if(keySizeInBits % 8) return errSecParam;
1214 if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = 2048;
1215 if(keySizeInBits >= kSecRSAMin && keySizeInBits <= kSecRSAMax) return errSecSuccess;
1216 break;
1217 case CSSM_ALGID_AES:
1218 if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSecAES128;
1219 if(keySizeInBits == kSecAES128 || keySizeInBits == kSecAES192 || keySizeInBits == kSecAES256) return errSecSuccess;
1220 break;
1221 case CSSM_ALGID_3DES:
1222 if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSec3DES192;
1223 if(keySizeInBits == kSec3DES192) return errSecSuccess;
1224 break;
1225 default:
1226 break;
1227 }
1228 return errSecParam;
1229 }
1230
1231
1232
1233 enum AttributeType
1234 {
1235 kStringType,
1236 kBooleanType,
1237 kIntegerType
1238 };
1239
1240
1241
1242 struct ParameterAttribute
1243 {
1244 const CFStringRef *name;
1245 AttributeType type;
1246 };
1247
1248
1249
1250 static ParameterAttribute gAttributes[] =
1251 {
1252 {
1253 &kSecAttrLabel,
1254 kStringType
1255 },
1256 {
1257 &kSecAttrIsPermanent,
1258 kBooleanType
1259 },
1260 {
1261 &kSecAttrApplicationTag,
1262 kStringType
1263 },
1264 {
1265 &kSecAttrEffectiveKeySize,
1266 kBooleanType
1267 },
1268 {
1269 &kSecAttrCanEncrypt,
1270 kBooleanType
1271 },
1272 {
1273 &kSecAttrCanDecrypt,
1274 kBooleanType
1275 },
1276 {
1277 &kSecAttrCanDerive,
1278 kBooleanType
1279 },
1280 {
1281 &kSecAttrCanSign,
1282 kBooleanType
1283 },
1284 {
1285 &kSecAttrCanVerify,
1286 kBooleanType
1287 },
1288 {
1289 &kSecAttrCanUnwrap,
1290 kBooleanType
1291 }
1292 };
1293
1294 const int kNumberOfAttributes = sizeof(gAttributes) / sizeof(ParameterAttribute);
1295
1296 static OSStatus ScanDictionaryForParameters(CFDictionaryRef parameters, void* attributePointers[])
1297 {
1298 int i;
1299 for (i = 0; i < kNumberOfAttributes; ++i)
1300 {
1301 // see if the corresponding tag exists in the dictionary
1302 CFTypeRef value = CFDictionaryGetValue(parameters, *(gAttributes[i].name));
1303 if (value != NULL)
1304 {
1305 switch (gAttributes[i].type)
1306 {
1307 case kStringType:
1308 // just return the value
1309 *(CFTypeRef*) attributePointers[i] = value;
1310 break;
1311
1312 case kBooleanType:
1313 {
1314 CFBooleanRef bRef = (CFBooleanRef) value;
1315 *(bool*) attributePointers[i] = CFBooleanGetValue(bRef);
1316 }
1317 break;
1318
1319 case kIntegerType:
1320 {
1321 CFNumberRef nRef = (CFNumberRef) value;
1322 CFNumberGetValue(nRef, kCFNumberSInt32Type, attributePointers[i]);
1323 }
1324 break;
1325 }
1326 }
1327 }
1328
1329 return errSecSuccess;
1330 }
1331
1332
1333
1334 static OSStatus GetKeyParameters(CFDictionaryRef parameters, int keySize, bool isPublic, CSSM_KEYUSE &keyUse, uint32 &attrs, CFTypeRef &labelRef, CFDataRef &applicationTagRef)
1335 {
1336 // establish default values
1337 labelRef = NULL;
1338 bool isPermanent = false;
1339 applicationTagRef = NULL;
1340 CFTypeRef effectiveKeySize = NULL;
1341 bool canDecrypt = isPublic ? false : true;
1342 bool canEncrypt = !canDecrypt;
1343 bool canDerive = true;
1344 bool canSign = isPublic ? false : true;
1345 bool canVerify = !canSign;
1346 bool canUnwrap = isPublic ? false : true;
1347 attrs = CSSM_KEYATTR_EXTRACTABLE;
1348 keyUse = 0;
1349
1350 void* attributePointers[] = {&labelRef, &isPermanent, &applicationTagRef, &effectiveKeySize, &canEncrypt, &canDecrypt,
1351 &canDerive, &canSign, &canVerify, &canUnwrap};
1352
1353 // look for modifiers in the general dictionary
1354 OSStatus result = ScanDictionaryForParameters(parameters, attributePointers);
1355 if (result != errSecSuccess)
1356 {
1357 return result;
1358 }
1359
1360 // see if we have anything which modifies the defaults
1361 CFTypeRef key;
1362 if (isPublic)
1363 {
1364 key = kSecPublicKeyAttrs;
1365 }
1366 else
1367 {
1368 key = kSecPrivateKeyAttrs;
1369 }
1370
1371 CFTypeRef dType = CFDictionaryGetValue(parameters, key);
1372 if (dType != NULL)
1373 {
1374 // this had better be a dictionary
1375 if (CFGetTypeID(dType) != CFDictionaryGetTypeID())
1376 {
1377 return errSecParam;
1378 }
1379
1380 // pull any additional parameters out of this dictionary
1381 result = ScanDictionaryForParameters((CFDictionaryRef)dType, attributePointers);
1382 if (result != errSecSuccess)
1383 {
1384 return result;
1385 }
1386 }
1387
1388 // figure out the key usage
1389 keyUse = 0;
1390 if (canDecrypt)
1391 {
1392 keyUse |= CSSM_KEYUSE_DECRYPT;
1393 }
1394
1395 if (canEncrypt)
1396 {
1397 keyUse |= CSSM_KEYUSE_ENCRYPT;
1398 }
1399
1400 if (canDerive)
1401 {
1402 keyUse |= CSSM_KEYUSE_DERIVE;
1403 }
1404
1405 if (canSign)
1406 {
1407 keyUse |= CSSM_KEYUSE_SIGN;
1408 }
1409
1410 if (canVerify)
1411 {
1412 keyUse |= CSSM_KEYUSE_VERIFY;
1413 }
1414
1415 if (canUnwrap)
1416 {
1417 keyUse |= CSSM_KEYUSE_UNWRAP;
1418 }
1419
1420 // public key is always extractable;
1421 // private key is extractable by default unless explicitly set to false
1422 CFTypeRef value = NULL;
1423 if (!isPublic && CFDictionaryGetValueIfPresent(parameters, kSecAttrIsExtractable, (const void **)&value) && value)
1424 {
1425 Boolean keyIsExtractable = CFEqual(kCFBooleanTrue, value);
1426 if (!keyIsExtractable)
1427 attrs = 0;
1428 }
1429
1430 if (isPermanent) {
1431 attrs |= CSSM_KEYATTR_PERMANENT;
1432 }
1433
1434 return errSecSuccess;
1435 }
1436
1437
1438
1439 static OSStatus MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters,
1440 CSSM_ALGORITHMS &algorithms,
1441 uint32 &keySizeInBits,
1442 CSSM_KEYUSE &publicKeyUse,
1443 uint32 &publicKeyAttr,
1444 CFTypeRef &publicKeyLabelRef,
1445 CFDataRef &publicKeyAttributeTagRef,
1446 CSSM_KEYUSE &privateKeyUse,
1447 uint32 &privateKeyAttr,
1448 CFTypeRef &privateKeyLabelRef,
1449 CFDataRef &privateKeyAttributeTagRef,
1450 SecAccessRef &initialAccess)
1451 {
1452 OSStatus result;
1453
1454 result = CheckAlgorithmType(parameters, algorithms);
1455 if (result != errSecSuccess)
1456 {
1457 return result;
1458 }
1459
1460 result = GetKeySize(parameters, algorithms, keySizeInBits);
1461 if (result != errSecSuccess)
1462 {
1463 return result;
1464 }
1465
1466 result = GetKeyParameters(parameters, keySizeInBits, false, privateKeyUse, privateKeyAttr, privateKeyLabelRef, privateKeyAttributeTagRef);
1467 if (result != errSecSuccess)
1468 {
1469 return result;
1470 }
1471
1472 result = GetKeyParameters(parameters, keySizeInBits, true, publicKeyUse, publicKeyAttr, publicKeyLabelRef, publicKeyAttributeTagRef);
1473 if (result != errSecSuccess)
1474 {
1475 return result;
1476 }
1477
1478 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrAccess, (const void **)&initialAccess))
1479 {
1480 initialAccess = NULL;
1481 }
1482 else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess))
1483 {
1484 return errSecParam;
1485 }
1486
1487 return errSecSuccess;
1488 }
1489
1490
1491
1492 static OSStatus SetKeyLabelAndTag(SecKeyRef keyRef, CFTypeRef label, CFDataRef tag)
1493 {
1494 int numToModify = 0;
1495 if (label != NULL)
1496 {
1497 numToModify += 1;
1498 }
1499
1500 if (tag != NULL)
1501 {
1502 numToModify += 1;
1503 }
1504
1505 if (numToModify == 0)
1506 {
1507 return errSecSuccess;
1508 }
1509
1510 SecKeychainAttributeList attrList;
1511 SecKeychainAttribute attributes[numToModify];
1512
1513 int i = 0;
1514 void *data = NULL;
1515
1516 if (label != NULL)
1517 {
1518 if (CFStringGetTypeID() == CFGetTypeID(label)) {
1519 CFStringRef label_string = static_cast<CFStringRef>(label);
1520 attributes[i].tag = kSecKeyPrintName;
1521 attributes[i].data = (void*) CFStringGetCStringPtr(label_string, kCFStringEncodingUTF8);
1522 if (NULL == attributes[i].data) {
1523 CFIndex buffer_length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string), kCFStringEncodingUTF8);
1524 data = attributes[i].data = malloc((size_t)buffer_length);
1525 if (NULL == attributes[i].data) {
1526 UnixError::throwMe(ENOMEM);
1527 }
1528 if (!CFStringGetCString(label_string, static_cast<char *>(attributes[i].data), buffer_length, kCFStringEncodingUTF8)) {
1529 free(data);
1530 MacOSError::throwMe(errSecParam);
1531 }
1532 }
1533 attributes[i].length = (UInt32)strlen(static_cast<char *>(attributes[i].data));
1534 } else if (CFDataGetTypeID() == CFGetTypeID(label)) {
1535 // 10.6 bug compatibility
1536 CFDataRef label_data = static_cast<CFDataRef>(label);
1537 attributes[i].tag = kSecKeyLabel;
1538 attributes[i].data = (void*) CFDataGetBytePtr(label_data);
1539 attributes[i].length = (UInt32)CFDataGetLength(label_data);
1540 } else {
1541 MacOSError::throwMe(errSecParam);
1542 }
1543 i++;
1544 }
1545
1546 if (tag != NULL)
1547 {
1548 attributes[i].tag = kSecKeyApplicationTag;
1549 attributes[i].data = (void*) CFDataGetBytePtr(tag);
1550 attributes[i].length = (UInt32)CFDataGetLength(tag);
1551 i++;
1552 }
1553
1554 attrList.count = numToModify;
1555 attrList.attr = attributes;
1556
1557 OSStatus result = SecKeychainItemModifyAttributesAndData((SecKeychainItemRef) keyRef, &attrList, 0, NULL);
1558 if (data)
1559 {
1560 free(data);
1561 }
1562
1563 return result;
1564 }
1565
1566
1567 static CFTypeRef GetAttributeFromParams(CFDictionaryRef parameters, CFTypeRef attr, CFTypeRef subParams) {
1568 if (subParams != NULL) {
1569 CFDictionaryRef subParamsDict = (CFDictionaryRef)CFDictionaryGetValue(parameters, subParams);
1570 if (subParamsDict != NULL) {
1571 CFTypeRef value = CFDictionaryGetValue(subParamsDict, attr);
1572 if (value != NULL) {
1573 return value;
1574 }
1575 }
1576 }
1577 return CFDictionaryGetValue(parameters, attr);
1578 }
1579
1580 extern "C" OSStatus SecKeyGeneratePair_ios(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey);
1581
1582 /* new in 10.6 */
1583 /* Generate a private/public keypair. */
1584 static OSStatus
1585 SecKeyGeneratePairInternal(
1586 bool alwaysPermanent,
1587 CFDictionaryRef parameters,
1588 SecKeyRef *publicKey,
1589 SecKeyRef *privateKey)
1590 {
1591 BEGIN_SECAPI
1592
1593 Required(parameters);
1594 Required(publicKey);
1595 Required(privateKey);
1596
1597 bool forceIOSKey = false;
1598 if (_CFMZEnabled()) {
1599 // On Marzipan, always go iOS SecItem/SecKey route, do not drag CSSM keys in.
1600 forceIOSKey = true;
1601 } else {
1602 CFTypeRef tokenID = GetAttributeFromParams(parameters, kSecAttrTokenID, NULL);
1603 CFTypeRef noLegacy = GetAttributeFromParams(parameters, kSecUseDataProtectionKeychain, NULL);
1604 #pragma clang diagnostic push
1605 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1606 if (!noLegacy) { // Also lookup via deprecated symbol because we do CFDictionaryGetValue and your CFDict might be an idiot
1607 noLegacy = GetAttributeFromParams(parameters, kSecAttrNoLegacy, NULL);
1608 }
1609 #pragma clang diagnostic pop
1610 CFTypeRef sync = GetAttributeFromParams(parameters, kSecAttrSynchronizable, kSecPrivateKeyAttrs);
1611 CFTypeRef accessControl = GetAttributeFromParams(parameters, kSecAttrAccessControl, kSecPrivateKeyAttrs) ?:
1612 GetAttributeFromParams(parameters, kSecAttrAccessControl, kSecPublicKeyAttrs);
1613 CFTypeRef accessGroup = GetAttributeFromParams(parameters, kSecAttrAccessGroup, kSecPrivateKeyAttrs) ?:
1614 GetAttributeFromParams(parameters, kSecAttrAccessGroup, kSecPublicKeyAttrs);
1615 // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain).
1616 forceIOSKey = (tokenID != NULL ||
1617 (noLegacy != NULL && CFBooleanGetValue((CFBooleanRef)noLegacy)) ||
1618 (sync != NULL && CFBooleanGetValue((CFBooleanRef)sync)) ||
1619 accessControl != NULL || (accessGroup != NULL && CFEqual(accessGroup, kSecAttrAccessGroupToken)));
1620 }
1621
1622 if (forceIOSKey) {
1623 // Generate keys in iOS keychain.
1624 return SecKeyGeneratePair_ios(parameters, publicKey, privateKey);
1625 }
1626
1627 CSSM_ALGORITHMS algorithms;
1628 uint32 keySizeInBits;
1629 CSSM_KEYUSE publicKeyUse;
1630 uint32 publicKeyAttr;
1631 CFTypeRef publicKeyLabelRef;
1632 CFDataRef publicKeyAttributeTagRef;
1633 CSSM_KEYUSE privateKeyUse;
1634 uint32 privateKeyAttr;
1635 CFTypeRef privateKeyLabelRef;
1636 CFDataRef privateKeyAttributeTagRef;
1637 SecAccessRef initialAccess;
1638 SecKeychainRef keychain;
1639
1640 OSStatus result = MakeKeyGenParametersFromDictionary(parameters, algorithms, keySizeInBits, publicKeyUse, publicKeyAttr, publicKeyLabelRef,
1641 publicKeyAttributeTagRef, privateKeyUse, privateKeyAttr, privateKeyLabelRef, privateKeyAttributeTagRef,
1642 initialAccess);
1643
1644 if (result != errSecSuccess) {
1645 return result;
1646 }
1647
1648 // verify keychain parameter
1649 keychain = (SecKeychainRef)CFDictionaryGetValue(parameters, kSecUseKeychain);
1650 if (keychain != NULL && SecKeychainGetTypeID() != CFGetTypeID(keychain)) {
1651 keychain = NULL;
1652 }
1653
1654 if (alwaysPermanent) {
1655 publicKeyAttr |= CSSM_KEYATTR_PERMANENT;
1656 privateKeyAttr |= CSSM_KEYATTR_PERMANENT;
1657 }
1658
1659 // do the key generation
1660 result = SecKeyCreatePair(keychain, algorithms, keySizeInBits, 0, publicKeyUse, publicKeyAttr, privateKeyUse, privateKeyAttr, initialAccess, publicKey, privateKey);
1661 if (result != errSecSuccess) {
1662 return result;
1663 }
1664
1665 // set the label and print attributes on the keys
1666 SetKeyLabelAndTag(*publicKey, publicKeyLabelRef, publicKeyAttributeTagRef);
1667 SetKeyLabelAndTag(*privateKey, privateKeyLabelRef, privateKeyAttributeTagRef);
1668 return result;
1669
1670 END_SECAPI
1671 }
1672
1673 OSStatus
1674 SecKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey) {
1675 return SecKeyGeneratePairInternal(true, parameters, publicKey, privateKey);
1676 }
1677
1678 SecKeyRef
1679 SecKeyCreateRandomKey(CFDictionaryRef parameters, CFErrorRef *error) {
1680 SecKeyRef privateKey = NULL, publicKey = NULL;
1681 OSStatus status = SecKeyGeneratePairInternal(false, parameters, &publicKey, &privateKey);
1682 SecError(status, error, CFSTR("failed to generate asymmetric keypair"));
1683 if (publicKey != NULL) {
1684 CFRelease(publicKey);
1685 }
1686 return privateKey;
1687 }
1688
1689 OSStatus SecKeyRawVerifyOSX(
1690 SecKeyRef key, /* Public key */
1691 SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */
1692 const uint8_t *signedData, /* signature over this data */
1693 size_t signedDataLen, /* length of dataToSign */
1694 const uint8_t *sig, /* signature */
1695 size_t sigLen)
1696 {
1697 return SecKeyRawVerify(key,padding,signedData,signedDataLen,sig,sigLen);
1698 }
1699
1700 /*
1701 M4 Additions
1702 */
1703
1704 static CFTypeRef
1705 utilGetStringFromCFDict(CFDictionaryRef parameters, CFTypeRef key, CFTypeRef defaultValue)
1706 {
1707 CFTypeRef value = CFDictionaryGetValue(parameters, key);
1708 if (value != NULL) return value;
1709 return defaultValue;
1710 }
1711
1712 static uint32_t
1713 utilGetNumberFromCFDict(CFDictionaryRef parameters, CFTypeRef key, uint32_t defaultValue)
1714 {
1715 uint32_t integerValue;
1716 CFTypeRef value = CFDictionaryGetValue(parameters, key);
1717 if (value != NULL) {
1718 CFNumberRef nRef = (CFNumberRef) value;
1719 CFNumberGetValue(nRef, kCFNumberSInt32Type, &integerValue);
1720 return integerValue;
1721 }
1722 return defaultValue;
1723 }
1724
1725 static uint32_t
1726 utilGetMaskValFromCFDict(CFDictionaryRef parameters, CFTypeRef key, uint32_t maskValue)
1727 {
1728 CFTypeRef value = CFDictionaryGetValue(parameters, key);
1729 if (value != NULL) {
1730 CFBooleanRef bRef = (CFBooleanRef) value;
1731 if(CFBooleanGetValue(bRef)) return maskValue;
1732 }
1733 return 0;
1734 }
1735
1736 static void
1737 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters, CSSM_ALGORITHMS *algorithm, uint32 *keySizeInBits, CSSM_KEYUSE *keyUsage, CSSM_KEYCLASS *keyClass)
1738 {
1739 CFTypeRef algorithmDictValue = utilGetStringFromCFDict(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES);
1740 CFTypeRef keyClassDictValue = utilGetStringFromCFDict(parameters, kSecAttrKeyClass, kSecAttrKeyClassSymmetric);
1741
1742 if(CFEqual(algorithmDictValue, kSecAttrKeyTypeAES)) {
1743 *algorithm = CSSM_ALGID_AES;
1744 *keySizeInBits = 128;
1745 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1746 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeDES)) {
1747 *algorithm = CSSM_ALGID_DES;
1748 *keySizeInBits = 128;
1749 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1750 } else if(CFEqual(algorithmDictValue, kSecAttrKeyType3DES)) {
1751 *algorithm = CSSM_ALGID_3DES_3KEY_EDE;
1752 *keySizeInBits = 128;
1753 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1754 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRC4)) {
1755 *algorithm = CSSM_ALGID_RC4;
1756 *keySizeInBits = 128;
1757 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1758 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRC2)) {
1759 *algorithm = CSSM_ALGID_RC2;
1760 *keySizeInBits = 128;
1761 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1762 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeCAST)) {
1763 *algorithm = CSSM_ALGID_CAST;
1764 *keySizeInBits = 128;
1765 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1766 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRSA)) {
1767 *algorithm = CSSM_ALGID_RSA;
1768 *keySizeInBits = 128;
1769 *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1770 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeDSA)) {
1771 *algorithm = CSSM_ALGID_DSA;
1772 *keySizeInBits = 128;
1773 *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1774 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeECDSA) ||
1775 CFEqual(algorithmDictValue, kSecAttrKeyTypeEC)) {
1776 *algorithm = CSSM_ALGID_ECDSA;
1777 *keySizeInBits = 128;
1778 *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1779 } else {
1780 *algorithm = CSSM_ALGID_AES;
1781 *keySizeInBits = 128;
1782 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1783 }
1784
1785 if(CFEqual(keyClassDictValue, kSecAttrKeyClassPublic)) {
1786 *keyClass = CSSM_KEYCLASS_PUBLIC_KEY;
1787 } else if(CFEqual(keyClassDictValue, kSecAttrKeyClassPrivate)) {
1788 *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1789 } else if(CFEqual(keyClassDictValue, kSecAttrKeyClassSymmetric)) {
1790 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1791 }
1792
1793 *keySizeInBits = utilGetNumberFromCFDict(parameters, kSecAttrKeySizeInBits, *keySizeInBits);
1794 *keyUsage = utilGetMaskValFromCFDict(parameters, kSecAttrCanEncrypt, CSSM_KEYUSE_ENCRYPT) |
1795 utilGetMaskValFromCFDict(parameters, kSecAttrCanDecrypt, CSSM_KEYUSE_DECRYPT) |
1796 utilGetMaskValFromCFDict(parameters, kSecAttrCanWrap, CSSM_KEYUSE_WRAP) |
1797 utilGetMaskValFromCFDict(parameters, kSecAttrCanUnwrap, CSSM_KEYUSE_UNWRAP);
1798
1799
1800 if(*keyClass == CSSM_KEYCLASS_PRIVATE_KEY || *keyClass == CSSM_KEYCLASS_PUBLIC_KEY) {
1801 *keyUsage |= utilGetMaskValFromCFDict(parameters, kSecAttrCanSign, CSSM_KEYUSE_SIGN) |
1802 utilGetMaskValFromCFDict(parameters, kSecAttrCanVerify, CSSM_KEYUSE_VERIFY);
1803 }
1804
1805 if(*keyUsage == 0) {
1806 switch (*keyClass) {
1807 case CSSM_KEYCLASS_PRIVATE_KEY:
1808 *keyUsage = CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_SIGN;
1809 break;
1810 case CSSM_KEYCLASS_PUBLIC_KEY:
1811 *keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP;
1812 break;
1813 default:
1814 *keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY;
1815 break;
1816 }
1817 }
1818 }
1819
1820 static CFStringRef
1821 utilCopyDefaultKeyLabel(void)
1822 {
1823 // generate a default label from the current date
1824 CFDateRef dateNow = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent());
1825 CFStringRef defaultLabel = CFCopyDescription(dateNow);
1826 CFRelease(dateNow);
1827
1828 return defaultLabel;
1829 }
1830
1831 SecKeyRef
1832 SecKeyGenerateSymmetric(CFDictionaryRef parameters, CFErrorRef *error)
1833 {
1834 OSStatus result = errSecParam; // default result for an early exit
1835 SecKeyRef key = NULL;
1836 SecKeychainRef keychain = NULL;
1837 SecAccessRef access;
1838 CFStringRef label;
1839 CFStringRef appLabel;
1840 CFStringRef appTag;
1841 CFStringRef dateLabel = NULL;
1842
1843 CSSM_ALGORITHMS algorithm;
1844 uint32 keySizeInBits;
1845 CSSM_KEYUSE keyUsage;
1846 uint32 keyAttr = CSSM_KEYATTR_RETURN_DEFAULT;
1847 CSSM_KEYCLASS keyClass;
1848 CFTypeRef value;
1849 Boolean isPermanent;
1850 Boolean isExtractable;
1851
1852 // verify keychain parameter
1853 if (!CFDictionaryGetValueIfPresent(parameters, kSecUseKeychain, (const void **)&keychain))
1854 keychain = NULL;
1855 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain)) {
1856 keychain = NULL;
1857 goto errorExit;
1858 }
1859 else
1860 CFRetain(keychain);
1861
1862 // verify permanent parameter
1863 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrIsPermanent, (const void **)&value))
1864 isPermanent = false;
1865 else if (!value || (CFBooleanGetTypeID() != CFGetTypeID(value)))
1866 goto errorExit;
1867 else
1868 isPermanent = CFEqual(kCFBooleanTrue, value);
1869 if (isPermanent) {
1870 if (keychain == NULL) {
1871 // no keychain was specified, so use the default keychain
1872 result = SecKeychainCopyDefault(&keychain);
1873 }
1874 keyAttr |= CSSM_KEYATTR_PERMANENT;
1875 }
1876
1877 // verify extractable parameter
1878 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrIsExtractable, (const void **)&value))
1879 isExtractable = true; // default to extractable if value not specified
1880 else if (!value || (CFBooleanGetTypeID() != CFGetTypeID(value)))
1881 goto errorExit;
1882 else
1883 isExtractable = CFEqual(kCFBooleanTrue, value);
1884 if (isExtractable)
1885 keyAttr |= CSSM_KEYATTR_EXTRACTABLE;
1886
1887 // verify access parameter
1888 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrAccess, (const void **)&access))
1889 access = NULL;
1890 else if (SecAccessGetTypeID() != CFGetTypeID(access))
1891 goto errorExit;
1892
1893 // verify label parameter
1894 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrLabel, (const void **)&label))
1895 label = (dateLabel = utilCopyDefaultKeyLabel()); // no label provided, so use default
1896 else if (CFStringGetTypeID() != CFGetTypeID(label))
1897 goto errorExit;
1898
1899 // verify application label parameter
1900 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrApplicationLabel, (const void **)&appLabel))
1901 appLabel = (dateLabel) ? dateLabel : (dateLabel = utilCopyDefaultKeyLabel());
1902 else if (CFStringGetTypeID() != CFGetTypeID(appLabel))
1903 goto errorExit;
1904
1905 // verify application tag parameter
1906 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrApplicationTag, (const void **)&appTag))
1907 appTag = NULL;
1908 else if (CFStringGetTypeID() != CFGetTypeID(appTag))
1909 goto errorExit;
1910
1911 utilGetKeyParametersFromCFDict(parameters, &algorithm, &keySizeInBits, &keyUsage, &keyClass);
1912
1913 if (!keychain) {
1914 // the generated key will not be stored in any keychain
1915 result = SecKeyGenerate(keychain, algorithm, keySizeInBits, 0, keyUsage, keyAttr, access, &key);
1916 }
1917 else {
1918 // we can set the label attributes on the generated key if it's a keychain item
1919 size_t labelBufLen = (label) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label), kCFStringEncodingUTF8) + 1 : 1;
1920 char *labelBuf = (char *)malloc(labelBufLen);
1921 size_t appLabelBufLen = (appLabel) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel), kCFStringEncodingUTF8) + 1 : 1;
1922 char *appLabelBuf = (char *)malloc(appLabelBufLen);
1923 size_t appTagBufLen = (appTag) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag), kCFStringEncodingUTF8) + 1 : 1;
1924 char *appTagBuf = (char *)malloc(appTagBufLen);
1925
1926 if (!label || !CFStringGetCString(label, labelBuf, labelBufLen-1, kCFStringEncodingUTF8))
1927 labelBuf[0]=0;
1928 if (!appLabel || !CFStringGetCString(appLabel, appLabelBuf, appLabelBufLen-1, kCFStringEncodingUTF8))
1929 appLabelBuf[0]=0;
1930 if (!appTag || !CFStringGetCString(appTag, appTagBuf, appTagBufLen-1, kCFStringEncodingUTF8))
1931 appTagBuf[0]=0;
1932
1933 SecKeychainAttribute attrs[] = {
1934 { kSecKeyPrintName, (UInt32)strlen(labelBuf), (char *)labelBuf },
1935 { kSecKeyLabel, (UInt32)strlen(appLabelBuf), (char *)appLabelBuf },
1936 { kSecKeyApplicationTag, (UInt32)strlen(appTagBuf), (char *)appTagBuf } };
1937 SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
1938 if (!appTag) --attributes.count;
1939
1940 result = SecKeyGenerateWithAttributes(&attributes,
1941 keychain, algorithm, keySizeInBits, 0,
1942 keyUsage, keyAttr, access, &key);
1943
1944 free(labelBuf);
1945 free(appLabelBuf);
1946 free(appTagBuf);
1947 }
1948
1949 errorExit:
1950 if (result && error) {
1951 *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, result, NULL);
1952 }
1953 if (dateLabel)
1954 CFRelease(dateLabel);
1955 if (keychain)
1956 CFRelease(keychain);
1957
1958 return key;
1959 }
1960
1961
1962
1963 SecKeyRef
1964 SecKeyCreateFromData(CFDictionaryRef parameters, CFDataRef keyData, CFErrorRef *error)
1965 {
1966 CSSM_ALGORITHMS algorithm;
1967 uint32 keySizeInBits;
1968 CSSM_KEYUSE keyUsage;
1969 CSSM_KEYCLASS keyClass;
1970 CSSM_RETURN crtn;
1971
1972 if(keyData == NULL || CFDataGetLength(keyData) == 0){
1973 MacOSError::throwMe(errSecUnsupportedKeySize);
1974 }
1975
1976 utilGetKeyParametersFromCFDict(parameters, &algorithm, &keySizeInBits, &keyUsage, &keyClass);
1977
1978 CSSM_CSP_HANDLE cspHandle = cuCspStartup(CSSM_FALSE); // TRUE => CSP, FALSE => CSPDL
1979
1980 SecKeyImportExportParameters iparam;
1981 memset(&iparam, 0, sizeof(iparam));
1982 iparam.keyUsage = keyUsage;
1983
1984 CFRef<CFDataRef> data;
1985 SecExternalItemType itype;
1986 switch (keyClass) {
1987 case CSSM_KEYCLASS_PRIVATE_KEY:
1988 itype = kSecItemTypePrivateKey;
1989 break;
1990 case CSSM_KEYCLASS_PUBLIC_KEY: {
1991 itype = kSecItemTypePublicKey;
1992 // Public key import expects public key in SubjPublicKey X509 format. We want to accept both bare and x509 format,
1993 // so we have to detect bare format here and extend to full X509 if detected.
1994 data.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm, keySizeInBits, keyData));
1995 break;
1996 }
1997 case CSSM_KEYCLASS_SESSION_KEY:
1998 itype = kSecItemTypeSessionKey;
1999 break;
2000 default:
2001 itype = kSecItemTypeUnknown;
2002 break;
2003 }
2004
2005 CFMutableArrayRef ka = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2006 // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful.
2007 crtn = impExpImportRawKey(data ? CFDataRef(data) : keyData, kSecFormatUnknown, itype, algorithm, NULL, cspHandle, 0, NULL, NULL, ka);
2008 if (crtn == CSSM_OK && CFArrayGetCount((CFArrayRef)ka)) {
2009 SecKeyRef sk = (SecKeyRef)CFArrayGetValueAtIndex((CFArrayRef)ka, 0);
2010 CFRetain(sk);
2011 CFRelease(ka);
2012 return sk;
2013 } else {
2014 CFRelease(ka);
2015 if (error) {
2016 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, crtn ? crtn : CSSM_ERRCODE_INTERNAL_ERROR, NULL);
2017 }
2018 return NULL;
2019 }
2020 }
2021
2022
2023 void
2024 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable, dispatch_queue_t deliveryQueue,
2025 SecKeyGeneratePairBlock result)
2026 {
2027 CFDictionaryRef parameters = CFDictionaryCreateCopy(NULL, parametersWhichMightBeMutiable);
2028 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
2029 SecKeyRef publicKey = NULL;
2030 SecKeyRef privateKey = NULL;
2031 OSStatus status = SecKeyGeneratePair(parameters, &publicKey, &privateKey);
2032 dispatch_async(deliveryQueue, ^{
2033 CFErrorRef error = NULL;
2034 if (errSecSuccess != status) {
2035 error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, NULL);
2036 }
2037 result(publicKey, privateKey, error);
2038 if (error) {
2039 CFRelease(error);
2040 }
2041 if (publicKey) {
2042 CFRelease(publicKey);
2043 }
2044 if (privateKey) {
2045 CFRelease(privateKey);
2046 }
2047 CFRelease(parameters);
2048 });
2049 });
2050 }
2051
2052 static inline void utilClearAndFree(void *p, size_t len) {
2053 if(p) {
2054 if(len) bzero(p, len);
2055 free(p);
2056 }
2057 }
2058
2059 SecKeyRef
2060 SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErrorRef *error)
2061 {
2062 CCPBKDFAlgorithm algorithm;
2063 CFIndex passwordLen = 0;
2064 CFDataRef keyData = NULL;
2065 char *thePassword = NULL;
2066 uint8_t *salt = NULL;
2067 uint8_t *derivedKey = NULL;
2068 size_t saltLen = 0, derivedKeyLen = 0;
2069 uint rounds;
2070 CFDataRef saltDictValue, algorithmDictValue;
2071 SecKeyRef retval = NULL;
2072
2073 /* Pick Values from parameters */
2074
2075 if((saltDictValue = (CFDataRef) CFDictionaryGetValue(parameters, kSecAttrSalt)) == NULL) {
2076 if(error) {
2077 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecMissingAlgorithmParms, NULL);
2078 }
2079 goto errOut;
2080 }
2081
2082 derivedKeyLen = utilGetNumberFromCFDict(parameters, kSecAttrKeySizeInBits, 128);
2083 // This value come in bits but the rest of the code treats it as bytes
2084 derivedKeyLen /= 8;
2085
2086 algorithmDictValue = (CFDataRef) utilGetStringFromCFDict(parameters, kSecAttrPRF, kSecAttrPRFHmacAlgSHA256);
2087
2088 rounds = utilGetNumberFromCFDict(parameters, kSecAttrRounds, 0);
2089
2090 /* Convert any remaining parameters and get the password bytes */
2091
2092 saltLen = CFDataGetLength(saltDictValue);
2093 if((salt = (uint8_t *) malloc(saltLen)) == NULL) {
2094 if(error) {
2095 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL);
2096 }
2097 goto errOut;
2098 }
2099
2100 CFDataGetBytes(saltDictValue, CFRangeMake(0, saltLen), (UInt8 *) salt);
2101
2102 passwordLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(password), kCFStringEncodingUTF8) + 1;
2103 if((thePassword = (char *) malloc(passwordLen)) == NULL) {
2104 if(error) {
2105 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL);
2106 }
2107 goto errOut;
2108 }
2109 CFStringGetBytes(password, CFRangeMake(0, CFStringGetLength(password)), kCFStringEncodingUTF8, '?', FALSE, (UInt8*)thePassword, passwordLen, &passwordLen);
2110
2111 if((derivedKey = (uint8_t *) malloc(derivedKeyLen)) == NULL) {
2112 if(error) {
2113 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL);
2114 }
2115 goto errOut;
2116 }
2117
2118 if(algorithmDictValue == NULL) {
2119 algorithm = kCCPRFHmacAlgSHA1; /* default */
2120 } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA1)) {
2121 algorithm = kCCPRFHmacAlgSHA1;
2122 } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA224)) {
2123 algorithm = kCCPRFHmacAlgSHA224;
2124 } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA256)) {
2125 algorithm = kCCPRFHmacAlgSHA256;
2126 } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA384)) {
2127 algorithm = kCCPRFHmacAlgSHA384;
2128 } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA512)) {
2129 algorithm = kCCPRFHmacAlgSHA512;
2130 } else {
2131 if(error) {
2132 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidAlgorithmParms, NULL);
2133 }
2134 goto errOut;
2135 }
2136
2137 if(rounds == 0) {
2138 rounds = 33333; // we need to pass back a consistent value since there's no way to record the round count.
2139 }
2140
2141 if(CCKeyDerivationPBKDF(kCCPBKDF2, thePassword, passwordLen, salt, saltLen, algorithm, rounds, derivedKey, derivedKeyLen)) {
2142 if(error) {
2143 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL);
2144 }
2145 goto errOut;
2146 }
2147
2148 if((keyData = CFDataCreate(NULL, derivedKey, derivedKeyLen)) != NULL) {
2149 retval = SecKeyCreateFromData(parameters, keyData, error);
2150 CFRelease(keyData);
2151 } else {
2152 if(error) {
2153 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL);
2154 }
2155 }
2156
2157 errOut:
2158 utilClearAndFree(salt, saltLen);
2159 utilClearAndFree(thePassword, passwordLen);
2160 utilClearAndFree(derivedKey, derivedKeyLen);
2161 return retval;
2162 }
2163
2164 CFDataRef
2165 SecKeyWrapSymmetric(SecKeyRef keyToWrap, SecKeyRef wrappingKey, CFDictionaryRef parameters, CFErrorRef *error)
2166 {
2167 if(error) {
2168 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
2169 }
2170 return NULL;
2171 }
2172
2173 SecKeyRef
2174 SecKeyUnwrapSymmetric(CFDataRef *keyToUnwrap, SecKeyRef unwrappingKey, CFDictionaryRef parameters, CFErrorRef *error)
2175 {
2176 if(error) {
2177 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
2178 }
2179 return NULL;
2180 }