]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecKey.cpp
Security-59306.41.2.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
808 .init = SecCDSAKeyInit,
809 .destroy = SecCDSAKeyDestroy,
810 .blockSize = SecCDSAKeyGetBlockSize,
811 .getAlgorithmID = SecCDSAKeyGetAlgorithmId,
812 .copyDictionary = SecCDSAKeyCopyAttributeDictionary,
813 .copyPublic = SecCDSAKeyCopyPublicBytes,
814 .copyExternalRepresentation = SecCDSAKeyCopyExternalRepresentation,
815 .copyPublicKey = SecCDSAKeyCopyPublicKey,
816 .copyOperationResult = SecCDSAKeyCopyOperationResult,
817 .isEqual = SecCDSAKeyIsEqual,
818 .setParameter = SecCDSAKeySetParameter,
819
820 .extraBytes = (sizeof(class CDSASecKey) > sizeof(struct __SecKey) ? (sizeof(class CDSASecKey) - sizeof(struct __SecKey)) : 0),
821 };
822
823 namespace Security {
824 namespace KeychainCore {
825 SecCFObject *KeyItem::fromSecKeyRef(CFTypeRef ptr) {
826 if (ptr == NULL || CFGetTypeID(ptr) != SecKeyGetTypeID()) {
827 return NULL;
828 }
829
830 SecKeyRef key = static_cast<SecKeyRef>(const_cast<void *>(ptr));
831 if (key->key_class == &kSecCDSAKeyDescriptor) {
832 return static_cast<SecCFObject *>(key->key);
833 }
834
835 CFRef<SecKeyRef> cdsaKey = SecKeyCopyAuxilliaryCDSAKeyForKey(key);
836 if (!cdsaKey) {
837 // Create CDSA key from exported data of existing key.
838 CFRef<CFDictionaryRef> keyAttributes = SecKeyCopyAttributes(key);
839 if (keyAttributes) {
840 CFRef<CFDataRef> keyData = SecKeyCopyExternalRepresentation(key, NULL);
841 if (!keyData) {
842 CFTypeRef pubKeyHash = CFDictionaryGetValue(keyAttributes, kSecAttrApplicationLabel);
843 const void *keys[] = { kSecClass, kSecUseDataProtectionKeychain, kSecReturnRef, kSecMatchLimit };
844 const void *values[] = { kSecClassIdentity, kCFBooleanFalse, kCFBooleanTrue, kSecMatchLimitAll };
845 CFRef<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, keys, values,
846 sizeof(keys) / sizeof(*keys),
847 &kCFTypeDictionaryKeyCallBacks,
848 &kCFTypeDictionaryValueCallBacks);
849 CFRef<CFArrayRef> identities;
850 OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)identities.take());
851 if (status == errSecSuccess) {
852 for (int i = 0; i < CFArrayGetCount(identities); ++i) {
853 CFRef<SecKeyRef> privateKey;
854 if (SecIdentityCopyPrivateKey((SecIdentityRef)CFArrayGetValueAtIndex(identities, i), privateKey.take()) != errSecSuccess) {
855 continue;
856 }
857 CFRef<CFDictionaryRef> attrs = SecKeyCopyAttributes(privateKey);
858 if (CFEqual(CFDictionaryGetValue(attrs, kSecAttrApplicationLabel), pubKeyHash)) {
859 cdsaKey = privateKey;
860 SecKeySetAuxilliaryCDSAKeyForKey(key, cdsaKey.get());
861 break;
862 }
863 }
864 }
865 } else {
866 cdsaKey.take(SecKeyCreateFromData(keyAttributes, keyData, NULL));
867 if (cdsaKey) {
868 SecKeySetAuxilliaryCDSAKeyForKey(key, cdsaKey.get());
869 }
870 }
871 }
872 }
873
874 return cdsaKey ? CDSASecKey::keyItem(cdsaKey.get()) : NULL;
875 }
876
877 // You need to hold this key's MutexForObject when you run this
878 void KeyItem::attachSecKeyRef() const {
879 SecKeyRef key = SecKeyCreate(NULL, &kSecCDSAKeyDescriptor, reinterpret_cast<const uint8_t *>(this), 0, 0);
880 CDSASecKey::keyItem(key)->mWeakSecKeyRef = key;
881 }
882
883 }
884 }
885
886 extern "C" Boolean SecKeyIsCDSAKey(SecKeyRef ref);
887 Boolean SecKeyIsCDSAKey(SecKeyRef ref) {
888 return ref->key_class == &kSecCDSAKeyDescriptor;
889 }
890
891
892 static OSStatus SecKeyCreatePairInternal(
893 SecKeychainRef keychainRef,
894 CSSM_ALGORITHMS algorithm,
895 uint32 keySizeInBits,
896 CSSM_CC_HANDLE contextHandle,
897 CSSM_KEYUSE publicKeyUsage,
898 uint32 publicKeyAttr,
899 CSSM_KEYUSE privateKeyUsage,
900 uint32 privateKeyAttr,
901 SecAccessRef initialAccess,
902 SecKeyRef* publicKeyRef,
903 SecKeyRef* privateKeyRef)
904 {
905 BEGIN_SECAPI
906
907 Keychain keychain;
908 SecPointer<Access> theAccess(initialAccess ? Access::required(initialAccess) : new Access("<key>"));
909 SecPointer<KeyItem> pubItem, privItem;
910 if (((publicKeyAttr | privateKeyAttr) & CSSM_KEYATTR_PERMANENT) != 0) {
911 keychain = Keychain::optional(keychainRef);
912 }
913 StMaybeLock<Mutex> _(keychain ? keychain->getKeychainMutex() : NULL);
914 KeyItem::createPair(keychain, algorithm, keySizeInBits, contextHandle, publicKeyUsage, publicKeyAttr,
915 privateKeyUsage, privateKeyAttr, theAccess, pubItem, privItem);
916
917 // Return the generated keys.
918 if (publicKeyRef)
919 *publicKeyRef = pubItem->handle();
920 if (privateKeyRef)
921 *privateKeyRef = privItem->handle();
922
923 END_SECAPI
924 }
925
926 OSStatus
927 SecKeyCreatePair(
928 SecKeychainRef keychainRef,
929 CSSM_ALGORITHMS algorithm,
930 uint32 keySizeInBits,
931 CSSM_CC_HANDLE contextHandle,
932 CSSM_KEYUSE publicKeyUsage,
933 uint32 publicKeyAttr,
934 CSSM_KEYUSE privateKeyUsage,
935 uint32 privateKeyAttr,
936 SecAccessRef initialAccess,
937 SecKeyRef* publicKeyRef,
938 SecKeyRef* privateKeyRef)
939 {
940 OSStatus result = SecKeyCreatePairInternal(keychainRef, algorithm, keySizeInBits, contextHandle, publicKeyUsage,
941 publicKeyAttr, privateKeyUsage, privateKeyAttr, initialAccess, publicKeyRef, privateKeyRef);
942
943 return result;
944 }
945
946
947
948 OSStatus
949 SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY **cssmKey)
950 {
951 BEGIN_SECAPI
952
953 Required(cssmKey) = KeyItem::required(key)->key();
954
955 END_SECAPI
956 }
957
958
959 //
960 // Private APIs
961 //
962
963 static ModuleNexus<Mutex> gSecReturnedKeyCSPsMutex;
964 static ModuleNexus<std::set<CssmClient::CSP>> gSecReturnedKeyCSPs;
965
966 OSStatus
967 SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle)
968 {
969 BEGIN_SECAPI
970
971 SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
972
973 // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP).
974 // Keep a global pointer to it to force the CSP to stay live forever.
975 CssmClient::CSP returnedKeyCSP = keyItem->csp();
976 {
977 StLock<Mutex> _(gSecReturnedKeyCSPsMutex());
978 gSecReturnedKeyCSPs().insert(returnedKeyCSP);
979 }
980 Required(cspHandle) = returnedKeyCSP->handle();
981
982 END_SECAPI
983 }
984
985 /* deprecated as of 10.8 */
986 OSStatus
987 SecKeyGetAlgorithmID(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER **algid)
988 {
989 BEGIN_SECAPI
990
991 SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
992 Required(algid) = &keyItem->algorithmIdentifier();
993
994 END_SECAPI
995 }
996
997 OSStatus
998 SecKeyGetStrengthInBits(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER *algid, unsigned int *strength)
999 {
1000 BEGIN_SECAPI
1001
1002 SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
1003 Required(strength) = keyItem->strengthInBits(algid);
1004
1005 END_SECAPI
1006 }
1007
1008 OSStatus
1009 SecKeyGetCredentials(
1010 SecKeyRef keyRef,
1011 CSSM_ACL_AUTHORIZATION_TAG operation,
1012 SecCredentialType credentialType,
1013 const CSSM_ACCESS_CREDENTIALS **outCredentials)
1014 {
1015 BEGIN_SECAPI
1016
1017 SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
1018 Required(outCredentials) = keyItem->getCredentials(operation, credentialType);
1019
1020 END_SECAPI
1021 }
1022
1023 OSStatus
1024 SecKeyImportPair(
1025 SecKeychainRef keychainRef,
1026 const CSSM_KEY *publicCssmKey,
1027 const CSSM_KEY *privateCssmKey,
1028 SecAccessRef initialAccess,
1029 SecKeyRef* publicKey,
1030 SecKeyRef* privateKey)
1031 {
1032 BEGIN_SECAPI
1033
1034 Keychain keychain = Keychain::optional(keychainRef);
1035 SecPointer<Access> theAccess(initialAccess ? Access::required(initialAccess) : new Access("<key>"));
1036 SecPointer<KeyItem> pubItem, privItem;
1037
1038 KeyItem::importPair(keychain,
1039 Required(publicCssmKey),
1040 Required(privateCssmKey),
1041 theAccess,
1042 pubItem,
1043 privItem);
1044
1045 // Return the generated keys.
1046 if (publicKey)
1047 *publicKey = pubItem->handle();
1048 if (privateKey)
1049 *privateKey = privItem->handle();
1050
1051 END_SECAPI
1052 }
1053
1054 static OSStatus
1055 SecKeyGenerateWithAttributes(
1056 SecKeychainAttributeList* attrList,
1057 SecKeychainRef keychainRef,
1058 CSSM_ALGORITHMS algorithm,
1059 uint32 keySizeInBits,
1060 CSSM_CC_HANDLE contextHandle,
1061 CSSM_KEYUSE keyUsage,
1062 uint32 keyAttr,
1063 SecAccessRef initialAccess,
1064 SecKeyRef* keyRef)
1065 {
1066 BEGIN_SECAPI
1067
1068 Keychain keychain;
1069 SecPointer<Access> theAccess;
1070
1071 if (keychainRef)
1072 keychain = KeychainImpl::required(keychainRef);
1073 if (initialAccess)
1074 theAccess = Access::required(initialAccess);
1075
1076 SecPointer<KeyItem> item = KeyItem::generateWithAttributes(attrList,
1077 keychain,
1078 algorithm,
1079 keySizeInBits,
1080 contextHandle,
1081 keyUsage,
1082 keyAttr,
1083 theAccess);
1084
1085 // Return the generated key.
1086 if (keyRef)
1087 *keyRef = item->handle();
1088
1089 END_SECAPI
1090 }
1091
1092 OSStatus
1093 SecKeyGenerate(
1094 SecKeychainRef keychainRef,
1095 CSSM_ALGORITHMS algorithm,
1096 uint32 keySizeInBits,
1097 CSSM_CC_HANDLE contextHandle,
1098 CSSM_KEYUSE keyUsage,
1099 uint32 keyAttr,
1100 SecAccessRef initialAccess,
1101 SecKeyRef* keyRef)
1102 {
1103 return SecKeyGenerateWithAttributes(NULL,
1104 keychainRef, algorithm, keySizeInBits,
1105 contextHandle, keyUsage, keyAttr,
1106 initialAccess, keyRef);
1107 }
1108
1109 /* new in 10.6 */
1110 /* Generate a floating key reference from a CSSM_KEY */
1111 OSStatus
1112 SecKeyCreateWithCSSMKey(const CSSM_KEY *cssmKey,
1113 SecKeyRef *keyRef)
1114 {
1115 BEGIN_SECAPI
1116
1117 Required(cssmKey);
1118 if(cssmKey->KeyData.Length == 0){
1119 MacOSError::throwMe(errSecInvalidAttributeKeyLength);
1120 }
1121 if(cssmKey->KeyData.Data == NULL){
1122 MacOSError::throwMe(errSecInvalidPointer);
1123 }
1124 CssmClient::CSP csp(cssmKey->KeyHeader.CspId);
1125 CssmClient::Key key(csp, *cssmKey);
1126 KeyItem *item = new KeyItem(key);
1127
1128 // Return the generated key.
1129 if (keyRef)
1130 *keyRef = SecKeyCreate(NULL, &kSecCDSAKeyDescriptor, (const uint8_t *)item, 0, 0);
1131
1132 END_SECAPI
1133 }
1134
1135
1136
1137 static u_int32_t ConvertCFStringToInteger(CFStringRef ref)
1138 {
1139 if (ref == NULL)
1140 {
1141 return 0;
1142 }
1143
1144 // figure out the size of the string
1145 CFIndex numChars = CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref), kCFStringEncodingUTF8);
1146 char *buffer = (char *)malloc(numChars);
1147 if (NULL == buffer) {
1148 UnixError::throwMe(ENOMEM);
1149 }
1150 if (!CFStringGetCString(ref, buffer, numChars, kCFStringEncodingUTF8))
1151 {
1152 free(buffer);
1153 MacOSError::throwMe(errSecParam);
1154 }
1155
1156 u_int32_t result = atoi(buffer);
1157 free(buffer);
1158 return result;
1159 }
1160
1161
1162
1163 static OSStatus CheckAlgorithmType(CFDictionaryRef parameters, CSSM_ALGORITHMS &algorithms)
1164 {
1165 // figure out the algorithm to use
1166 CFStringRef ktype = (CFStringRef) CFDictionaryGetValue(parameters, kSecAttrKeyType);
1167 if (ktype == NULL)
1168 {
1169 return errSecParam;
1170 }
1171
1172 if (CFEqual(ktype, kSecAttrKeyTypeRSA)) {
1173 algorithms = CSSM_ALGID_RSA;
1174 return errSecSuccess;
1175 } else if(CFEqual(ktype, kSecAttrKeyTypeECDSA) ||
1176 CFEqual(ktype, kSecAttrKeyTypeEC)) {
1177 algorithms = CSSM_ALGID_ECDSA;
1178 return errSecSuccess;
1179 } else if(CFEqual(ktype, kSecAttrKeyTypeAES)) {
1180 algorithms = CSSM_ALGID_AES;
1181 return errSecSuccess;
1182 } else if(CFEqual(ktype, kSecAttrKeyType3DES)) {
1183 algorithms = CSSM_ALGID_3DES;
1184 return errSecSuccess;
1185 } else {
1186 return errSecUnsupportedAlgorithm;
1187 }
1188 }
1189
1190
1191
1192 static OSStatus GetKeySize(CFDictionaryRef parameters, CSSM_ALGORITHMS algorithms, uint32 &keySizeInBits)
1193 {
1194
1195 // get the key size and check it for validity
1196 CFTypeRef ref = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits);
1197
1198 keySizeInBits = kSecDefaultKeySize;
1199
1200 CFTypeID bitSizeType = CFGetTypeID(ref);
1201 if (bitSizeType == CFStringGetTypeID())
1202 keySizeInBits = ConvertCFStringToInteger((CFStringRef) ref);
1203 else if (bitSizeType == CFNumberGetTypeID())
1204 CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &keySizeInBits);
1205 else return errSecParam;
1206
1207
1208 switch (algorithms) {
1209 case CSSM_ALGID_ECDSA:
1210 if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSecp256r1;
1211 if(keySizeInBits == kSecp192r1 || keySizeInBits == kSecp256r1 || keySizeInBits == kSecp384r1 || keySizeInBits == kSecp521r1 ) return errSecSuccess;
1212 break;
1213 case CSSM_ALGID_RSA:
1214 if(keySizeInBits % 8) return errSecParam;
1215 if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = 2048;
1216 if(keySizeInBits >= kSecRSAMin && keySizeInBits <= kSecRSAMax) return errSecSuccess;
1217 break;
1218 case CSSM_ALGID_AES:
1219 if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSecAES128;
1220 if(keySizeInBits == kSecAES128 || keySizeInBits == kSecAES192 || keySizeInBits == kSecAES256) return errSecSuccess;
1221 break;
1222 case CSSM_ALGID_3DES:
1223 if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSec3DES192;
1224 if(keySizeInBits == kSec3DES192) return errSecSuccess;
1225 break;
1226 default:
1227 break;
1228 }
1229 return errSecParam;
1230 }
1231
1232
1233
1234 enum AttributeType
1235 {
1236 kStringType,
1237 kBooleanType,
1238 kIntegerType
1239 };
1240
1241
1242
1243 struct ParameterAttribute
1244 {
1245 const CFStringRef *name;
1246 AttributeType type;
1247 };
1248
1249
1250
1251 static ParameterAttribute gAttributes[] =
1252 {
1253 {
1254 &kSecAttrLabel,
1255 kStringType
1256 },
1257 {
1258 &kSecAttrIsPermanent,
1259 kBooleanType
1260 },
1261 {
1262 &kSecAttrApplicationTag,
1263 kStringType
1264 },
1265 {
1266 &kSecAttrEffectiveKeySize,
1267 kBooleanType
1268 },
1269 {
1270 &kSecAttrCanEncrypt,
1271 kBooleanType
1272 },
1273 {
1274 &kSecAttrCanDecrypt,
1275 kBooleanType
1276 },
1277 {
1278 &kSecAttrCanDerive,
1279 kBooleanType
1280 },
1281 {
1282 &kSecAttrCanSign,
1283 kBooleanType
1284 },
1285 {
1286 &kSecAttrCanVerify,
1287 kBooleanType
1288 },
1289 {
1290 &kSecAttrCanUnwrap,
1291 kBooleanType
1292 }
1293 };
1294
1295 const int kNumberOfAttributes = sizeof(gAttributes) / sizeof(ParameterAttribute);
1296
1297 static OSStatus ScanDictionaryForParameters(CFDictionaryRef parameters, void* attributePointers[])
1298 {
1299 int i;
1300 for (i = 0; i < kNumberOfAttributes; ++i)
1301 {
1302 // see if the corresponding tag exists in the dictionary
1303 CFTypeRef value = CFDictionaryGetValue(parameters, *(gAttributes[i].name));
1304 if (value != NULL)
1305 {
1306 switch (gAttributes[i].type)
1307 {
1308 case kStringType:
1309 // just return the value
1310 *(CFTypeRef*) attributePointers[i] = value;
1311 break;
1312
1313 case kBooleanType:
1314 {
1315 CFBooleanRef bRef = (CFBooleanRef) value;
1316 *(bool*) attributePointers[i] = CFBooleanGetValue(bRef);
1317 }
1318 break;
1319
1320 case kIntegerType:
1321 {
1322 CFNumberRef nRef = (CFNumberRef) value;
1323 CFNumberGetValue(nRef, kCFNumberSInt32Type, attributePointers[i]);
1324 }
1325 break;
1326 }
1327 }
1328 }
1329
1330 return errSecSuccess;
1331 }
1332
1333
1334
1335 static OSStatus GetKeyParameters(CFDictionaryRef parameters, int keySize, bool isPublic, CSSM_KEYUSE &keyUse, uint32 &attrs, CFTypeRef &labelRef, CFDataRef &applicationTagRef)
1336 {
1337 // establish default values
1338 labelRef = NULL;
1339 bool isPermanent = false;
1340 applicationTagRef = NULL;
1341 CFTypeRef effectiveKeySize = NULL;
1342 bool canDecrypt = isPublic ? false : true;
1343 bool canEncrypt = !canDecrypt;
1344 bool canDerive = true;
1345 bool canSign = isPublic ? false : true;
1346 bool canVerify = !canSign;
1347 bool canUnwrap = isPublic ? false : true;
1348 attrs = CSSM_KEYATTR_EXTRACTABLE;
1349 keyUse = 0;
1350
1351 void* attributePointers[] = {&labelRef, &isPermanent, &applicationTagRef, &effectiveKeySize, &canEncrypt, &canDecrypt,
1352 &canDerive, &canSign, &canVerify, &canUnwrap};
1353
1354 // look for modifiers in the general dictionary
1355 OSStatus result = ScanDictionaryForParameters(parameters, attributePointers);
1356 if (result != errSecSuccess)
1357 {
1358 return result;
1359 }
1360
1361 // see if we have anything which modifies the defaults
1362 CFTypeRef key;
1363 if (isPublic)
1364 {
1365 key = kSecPublicKeyAttrs;
1366 }
1367 else
1368 {
1369 key = kSecPrivateKeyAttrs;
1370 }
1371
1372 CFTypeRef dType = CFDictionaryGetValue(parameters, key);
1373 if (dType != NULL)
1374 {
1375 // this had better be a dictionary
1376 if (CFGetTypeID(dType) != CFDictionaryGetTypeID())
1377 {
1378 return errSecParam;
1379 }
1380
1381 // pull any additional parameters out of this dictionary
1382 result = ScanDictionaryForParameters((CFDictionaryRef)dType, attributePointers);
1383 if (result != errSecSuccess)
1384 {
1385 return result;
1386 }
1387 }
1388
1389 // figure out the key usage
1390 keyUse = 0;
1391 if (canDecrypt)
1392 {
1393 keyUse |= CSSM_KEYUSE_DECRYPT;
1394 }
1395
1396 if (canEncrypt)
1397 {
1398 keyUse |= CSSM_KEYUSE_ENCRYPT;
1399 }
1400
1401 if (canDerive)
1402 {
1403 keyUse |= CSSM_KEYUSE_DERIVE;
1404 }
1405
1406 if (canSign)
1407 {
1408 keyUse |= CSSM_KEYUSE_SIGN;
1409 }
1410
1411 if (canVerify)
1412 {
1413 keyUse |= CSSM_KEYUSE_VERIFY;
1414 }
1415
1416 if (canUnwrap)
1417 {
1418 keyUse |= CSSM_KEYUSE_UNWRAP;
1419 }
1420
1421 // public key is always extractable;
1422 // private key is extractable by default unless explicitly set to false
1423 CFTypeRef value = NULL;
1424 if (!isPublic && CFDictionaryGetValueIfPresent(parameters, kSecAttrIsExtractable, (const void **)&value) && value)
1425 {
1426 Boolean keyIsExtractable = CFEqual(kCFBooleanTrue, value);
1427 if (!keyIsExtractable)
1428 attrs = 0;
1429 }
1430
1431 if (isPermanent) {
1432 attrs |= CSSM_KEYATTR_PERMANENT;
1433 }
1434
1435 return errSecSuccess;
1436 }
1437
1438
1439
1440 static OSStatus MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters,
1441 CSSM_ALGORITHMS &algorithms,
1442 uint32 &keySizeInBits,
1443 CSSM_KEYUSE &publicKeyUse,
1444 uint32 &publicKeyAttr,
1445 CFTypeRef &publicKeyLabelRef,
1446 CFDataRef &publicKeyAttributeTagRef,
1447 CSSM_KEYUSE &privateKeyUse,
1448 uint32 &privateKeyAttr,
1449 CFTypeRef &privateKeyLabelRef,
1450 CFDataRef &privateKeyAttributeTagRef,
1451 SecAccessRef &initialAccess)
1452 {
1453 OSStatus result;
1454
1455 result = CheckAlgorithmType(parameters, algorithms);
1456 if (result != errSecSuccess)
1457 {
1458 return result;
1459 }
1460
1461 result = GetKeySize(parameters, algorithms, keySizeInBits);
1462 if (result != errSecSuccess)
1463 {
1464 return result;
1465 }
1466
1467 result = GetKeyParameters(parameters, keySizeInBits, false, privateKeyUse, privateKeyAttr, privateKeyLabelRef, privateKeyAttributeTagRef);
1468 if (result != errSecSuccess)
1469 {
1470 return result;
1471 }
1472
1473 result = GetKeyParameters(parameters, keySizeInBits, true, publicKeyUse, publicKeyAttr, publicKeyLabelRef, publicKeyAttributeTagRef);
1474 if (result != errSecSuccess)
1475 {
1476 return result;
1477 }
1478
1479 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrAccess, (const void **)&initialAccess))
1480 {
1481 initialAccess = NULL;
1482 }
1483 else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess))
1484 {
1485 return errSecParam;
1486 }
1487
1488 return errSecSuccess;
1489 }
1490
1491
1492
1493 static OSStatus SetKeyLabelAndTag(SecKeyRef keyRef, CFTypeRef label, CFDataRef tag)
1494 {
1495 int numToModify = 0;
1496 if (label != NULL)
1497 {
1498 numToModify += 1;
1499 }
1500
1501 if (tag != NULL)
1502 {
1503 numToModify += 1;
1504 }
1505
1506 if (numToModify == 0)
1507 {
1508 return errSecSuccess;
1509 }
1510
1511 SecKeychainAttributeList attrList;
1512 SecKeychainAttribute attributes[numToModify];
1513
1514 int i = 0;
1515 void *data = NULL;
1516
1517 if (label != NULL)
1518 {
1519 if (CFStringGetTypeID() == CFGetTypeID(label)) {
1520 CFStringRef label_string = static_cast<CFStringRef>(label);
1521 attributes[i].tag = kSecKeyPrintName;
1522 attributes[i].data = (void*) CFStringGetCStringPtr(label_string, kCFStringEncodingUTF8);
1523 if (NULL == attributes[i].data) {
1524 CFIndex buffer_length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string), kCFStringEncodingUTF8);
1525 data = attributes[i].data = malloc((size_t)buffer_length);
1526 if (NULL == attributes[i].data) {
1527 UnixError::throwMe(ENOMEM);
1528 }
1529 if (!CFStringGetCString(label_string, static_cast<char *>(attributes[i].data), buffer_length, kCFStringEncodingUTF8)) {
1530 free(data);
1531 MacOSError::throwMe(errSecParam);
1532 }
1533 }
1534 attributes[i].length = (UInt32)strlen(static_cast<char *>(attributes[i].data));
1535 } else if (CFDataGetTypeID() == CFGetTypeID(label)) {
1536 // 10.6 bug compatibility
1537 CFDataRef label_data = static_cast<CFDataRef>(label);
1538 attributes[i].tag = kSecKeyLabel;
1539 attributes[i].data = (void*) CFDataGetBytePtr(label_data);
1540 attributes[i].length = (UInt32)CFDataGetLength(label_data);
1541 } else {
1542 MacOSError::throwMe(errSecParam);
1543 }
1544 i++;
1545 }
1546
1547 if (tag != NULL)
1548 {
1549 attributes[i].tag = kSecKeyApplicationTag;
1550 attributes[i].data = (void*) CFDataGetBytePtr(tag);
1551 attributes[i].length = (UInt32)CFDataGetLength(tag);
1552 i++;
1553 }
1554
1555 attrList.count = numToModify;
1556 attrList.attr = attributes;
1557
1558 OSStatus result = SecKeychainItemModifyAttributesAndData((SecKeychainItemRef) keyRef, &attrList, 0, NULL);
1559 if (data)
1560 {
1561 free(data);
1562 }
1563
1564 return result;
1565 }
1566
1567
1568 static CFTypeRef GetAttributeFromParams(CFDictionaryRef parameters, CFTypeRef attr, CFTypeRef subParams) {
1569 if (subParams != NULL) {
1570 CFDictionaryRef subParamsDict = (CFDictionaryRef)CFDictionaryGetValue(parameters, subParams);
1571 if (subParamsDict != NULL) {
1572 CFTypeRef value = CFDictionaryGetValue(subParamsDict, attr);
1573 if (value != NULL) {
1574 return value;
1575 }
1576 }
1577 }
1578 return CFDictionaryGetValue(parameters, attr);
1579 }
1580
1581 extern "C" OSStatus SecKeyGeneratePair_ios(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey);
1582
1583 /* new in 10.6 */
1584 /* Generate a private/public keypair. */
1585 static OSStatus
1586 SecKeyGeneratePairInternal(
1587 bool alwaysPermanent,
1588 CFDictionaryRef parameters,
1589 SecKeyRef *publicKey,
1590 SecKeyRef *privateKey)
1591 {
1592 BEGIN_SECAPI
1593
1594 Required(parameters);
1595 Required(publicKey);
1596 Required(privateKey);
1597
1598 bool forceIOSKey = false;
1599 if (_CFMZEnabled()) {
1600 // On Marzipan, always go iOS SecItem/SecKey route, do not drag CSSM keys in.
1601 forceIOSKey = true;
1602 } else {
1603 CFTypeRef tokenID = GetAttributeFromParams(parameters, kSecAttrTokenID, NULL);
1604 CFTypeRef noLegacy = GetAttributeFromParams(parameters, kSecUseDataProtectionKeychain, NULL);
1605 #pragma clang diagnostic push
1606 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1607 if (!noLegacy) { // Also lookup via deprecated symbol because we do CFDictionaryGetValue and your CFDict might be an idiot
1608 noLegacy = GetAttributeFromParams(parameters, kSecAttrNoLegacy, NULL);
1609 }
1610 #pragma clang diagnostic pop
1611 CFTypeRef sync = GetAttributeFromParams(parameters, kSecAttrSynchronizable, kSecPrivateKeyAttrs);
1612 CFTypeRef accessControl = GetAttributeFromParams(parameters, kSecAttrAccessControl, kSecPrivateKeyAttrs) ?:
1613 GetAttributeFromParams(parameters, kSecAttrAccessControl, kSecPublicKeyAttrs);
1614 CFTypeRef accessGroup = GetAttributeFromParams(parameters, kSecAttrAccessGroup, kSecPrivateKeyAttrs) ?:
1615 GetAttributeFromParams(parameters, kSecAttrAccessGroup, kSecPublicKeyAttrs);
1616 // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain).
1617 forceIOSKey = (tokenID != NULL ||
1618 (noLegacy != NULL && CFBooleanGetValue((CFBooleanRef)noLegacy)) ||
1619 (sync != NULL && CFBooleanGetValue((CFBooleanRef)sync)) ||
1620 accessControl != NULL || (accessGroup != NULL && CFEqual(accessGroup, kSecAttrAccessGroupToken)));
1621 }
1622
1623 if (forceIOSKey) {
1624 // Generate keys in iOS keychain.
1625 return SecKeyGeneratePair_ios(parameters, publicKey, privateKey);
1626 }
1627
1628 CSSM_ALGORITHMS algorithms;
1629 uint32 keySizeInBits;
1630 CSSM_KEYUSE publicKeyUse;
1631 uint32 publicKeyAttr;
1632 CFTypeRef publicKeyLabelRef;
1633 CFDataRef publicKeyAttributeTagRef;
1634 CSSM_KEYUSE privateKeyUse;
1635 uint32 privateKeyAttr;
1636 CFTypeRef privateKeyLabelRef;
1637 CFDataRef privateKeyAttributeTagRef;
1638 SecAccessRef initialAccess;
1639 SecKeychainRef keychain;
1640
1641 OSStatus result = MakeKeyGenParametersFromDictionary(parameters, algorithms, keySizeInBits, publicKeyUse, publicKeyAttr, publicKeyLabelRef,
1642 publicKeyAttributeTagRef, privateKeyUse, privateKeyAttr, privateKeyLabelRef, privateKeyAttributeTagRef,
1643 initialAccess);
1644
1645 if (result != errSecSuccess) {
1646 return result;
1647 }
1648
1649 // verify keychain parameter
1650 keychain = (SecKeychainRef)CFDictionaryGetValue(parameters, kSecUseKeychain);
1651 if (keychain != NULL && SecKeychainGetTypeID() != CFGetTypeID(keychain)) {
1652 keychain = NULL;
1653 }
1654
1655 if (alwaysPermanent) {
1656 publicKeyAttr |= CSSM_KEYATTR_PERMANENT;
1657 privateKeyAttr |= CSSM_KEYATTR_PERMANENT;
1658 }
1659
1660 // do the key generation
1661 result = SecKeyCreatePair(keychain, algorithms, keySizeInBits, 0, publicKeyUse, publicKeyAttr, privateKeyUse, privateKeyAttr, initialAccess, publicKey, privateKey);
1662 if (result != errSecSuccess) {
1663 return result;
1664 }
1665
1666 // set the label and print attributes on the keys
1667 SetKeyLabelAndTag(*publicKey, publicKeyLabelRef, publicKeyAttributeTagRef);
1668 SetKeyLabelAndTag(*privateKey, privateKeyLabelRef, privateKeyAttributeTagRef);
1669 return result;
1670
1671 END_SECAPI
1672 }
1673
1674 OSStatus
1675 SecKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey) {
1676 return SecKeyGeneratePairInternal(true, parameters, publicKey, privateKey);
1677 }
1678
1679 SecKeyRef
1680 SecKeyCreateRandomKey(CFDictionaryRef parameters, CFErrorRef *error) {
1681 SecKeyRef privateKey = NULL, publicKey = NULL;
1682 OSStatus status = SecKeyGeneratePairInternal(false, parameters, &publicKey, &privateKey);
1683 SecError(status, error, CFSTR("failed to generate asymmetric keypair"));
1684 if (publicKey != NULL) {
1685 CFRelease(publicKey);
1686 }
1687 return privateKey;
1688 }
1689
1690 OSStatus SecKeyRawVerifyOSX(
1691 SecKeyRef key, /* Public key */
1692 SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */
1693 const uint8_t *signedData, /* signature over this data */
1694 size_t signedDataLen, /* length of dataToSign */
1695 const uint8_t *sig, /* signature */
1696 size_t sigLen)
1697 {
1698 return SecKeyRawVerify(key,padding,signedData,signedDataLen,sig,sigLen);
1699 }
1700
1701 /*
1702 M4 Additions
1703 */
1704
1705 static CFTypeRef
1706 utilGetStringFromCFDict(CFDictionaryRef parameters, CFTypeRef key, CFTypeRef defaultValue)
1707 {
1708 CFTypeRef value = CFDictionaryGetValue(parameters, key);
1709 if (value != NULL) return value;
1710 return defaultValue;
1711 }
1712
1713 static uint32_t
1714 utilGetNumberFromCFDict(CFDictionaryRef parameters, CFTypeRef key, uint32_t defaultValue)
1715 {
1716 uint32_t integerValue;
1717 CFTypeRef value = CFDictionaryGetValue(parameters, key);
1718 if (value != NULL) {
1719 CFNumberRef nRef = (CFNumberRef) value;
1720 CFNumberGetValue(nRef, kCFNumberSInt32Type, &integerValue);
1721 return integerValue;
1722 }
1723 return defaultValue;
1724 }
1725
1726 static uint32_t
1727 utilGetMaskValFromCFDict(CFDictionaryRef parameters, CFTypeRef key, uint32_t maskValue)
1728 {
1729 CFTypeRef value = CFDictionaryGetValue(parameters, key);
1730 if (value != NULL) {
1731 CFBooleanRef bRef = (CFBooleanRef) value;
1732 if(CFBooleanGetValue(bRef)) return maskValue;
1733 }
1734 return 0;
1735 }
1736
1737 static void
1738 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters, CSSM_ALGORITHMS *algorithm, uint32 *keySizeInBits, CSSM_KEYUSE *keyUsage, CSSM_KEYCLASS *keyClass)
1739 {
1740 CFTypeRef algorithmDictValue = utilGetStringFromCFDict(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES);
1741 CFTypeRef keyClassDictValue = utilGetStringFromCFDict(parameters, kSecAttrKeyClass, kSecAttrKeyClassSymmetric);
1742
1743 if(CFEqual(algorithmDictValue, kSecAttrKeyTypeAES)) {
1744 *algorithm = CSSM_ALGID_AES;
1745 *keySizeInBits = 128;
1746 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1747 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeDES)) {
1748 *algorithm = CSSM_ALGID_DES;
1749 *keySizeInBits = 128;
1750 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1751 } else if(CFEqual(algorithmDictValue, kSecAttrKeyType3DES)) {
1752 *algorithm = CSSM_ALGID_3DES_3KEY_EDE;
1753 *keySizeInBits = 128;
1754 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1755 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRC4)) {
1756 *algorithm = CSSM_ALGID_RC4;
1757 *keySizeInBits = 128;
1758 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1759 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRC2)) {
1760 *algorithm = CSSM_ALGID_RC2;
1761 *keySizeInBits = 128;
1762 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1763 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeCAST)) {
1764 *algorithm = CSSM_ALGID_CAST;
1765 *keySizeInBits = 128;
1766 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1767 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRSA)) {
1768 *algorithm = CSSM_ALGID_RSA;
1769 *keySizeInBits = 128;
1770 *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1771 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeDSA)) {
1772 *algorithm = CSSM_ALGID_DSA;
1773 *keySizeInBits = 128;
1774 *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1775 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeECDSA) ||
1776 CFEqual(algorithmDictValue, kSecAttrKeyTypeEC)) {
1777 *algorithm = CSSM_ALGID_ECDSA;
1778 *keySizeInBits = 128;
1779 *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1780 } else {
1781 *algorithm = CSSM_ALGID_AES;
1782 *keySizeInBits = 128;
1783 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1784 }
1785
1786 if(CFEqual(keyClassDictValue, kSecAttrKeyClassPublic)) {
1787 *keyClass = CSSM_KEYCLASS_PUBLIC_KEY;
1788 } else if(CFEqual(keyClassDictValue, kSecAttrKeyClassPrivate)) {
1789 *keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
1790 } else if(CFEqual(keyClassDictValue, kSecAttrKeyClassSymmetric)) {
1791 *keyClass = CSSM_KEYCLASS_SESSION_KEY;
1792 }
1793
1794 *keySizeInBits = utilGetNumberFromCFDict(parameters, kSecAttrKeySizeInBits, *keySizeInBits);
1795 *keyUsage = utilGetMaskValFromCFDict(parameters, kSecAttrCanEncrypt, CSSM_KEYUSE_ENCRYPT) |
1796 utilGetMaskValFromCFDict(parameters, kSecAttrCanDecrypt, CSSM_KEYUSE_DECRYPT) |
1797 utilGetMaskValFromCFDict(parameters, kSecAttrCanWrap, CSSM_KEYUSE_WRAP) |
1798 utilGetMaskValFromCFDict(parameters, kSecAttrCanUnwrap, CSSM_KEYUSE_UNWRAP);
1799
1800
1801 if(*keyClass == CSSM_KEYCLASS_PRIVATE_KEY || *keyClass == CSSM_KEYCLASS_PUBLIC_KEY) {
1802 *keyUsage |= utilGetMaskValFromCFDict(parameters, kSecAttrCanSign, CSSM_KEYUSE_SIGN) |
1803 utilGetMaskValFromCFDict(parameters, kSecAttrCanVerify, CSSM_KEYUSE_VERIFY);
1804 }
1805
1806 if(*keyUsage == 0) {
1807 switch (*keyClass) {
1808 case CSSM_KEYCLASS_PRIVATE_KEY:
1809 *keyUsage = CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_SIGN;
1810 break;
1811 case CSSM_KEYCLASS_PUBLIC_KEY:
1812 *keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP;
1813 break;
1814 default:
1815 *keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY;
1816 break;
1817 }
1818 }
1819 }
1820
1821 static CFStringRef
1822 utilCopyDefaultKeyLabel(void)
1823 {
1824 // generate a default label from the current date
1825 CFDateRef dateNow = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent());
1826 CFStringRef defaultLabel = CFCopyDescription(dateNow);
1827 CFRelease(dateNow);
1828
1829 return defaultLabel;
1830 }
1831
1832 SecKeyRef
1833 SecKeyGenerateSymmetric(CFDictionaryRef parameters, CFErrorRef *error)
1834 {
1835 OSStatus result = errSecParam; // default result for an early exit
1836 SecKeyRef key = NULL;
1837 SecKeychainRef keychain = NULL;
1838 SecAccessRef access;
1839 CFStringRef label;
1840 CFStringRef appLabel;
1841 CFStringRef appTag;
1842 CFStringRef dateLabel = NULL;
1843
1844 CSSM_ALGORITHMS algorithm;
1845 uint32 keySizeInBits;
1846 CSSM_KEYUSE keyUsage;
1847 uint32 keyAttr = CSSM_KEYATTR_RETURN_DEFAULT;
1848 CSSM_KEYCLASS keyClass;
1849 CFTypeRef value;
1850 Boolean isPermanent;
1851 Boolean isExtractable;
1852
1853 // verify keychain parameter
1854 if (!CFDictionaryGetValueIfPresent(parameters, kSecUseKeychain, (const void **)&keychain))
1855 keychain = NULL;
1856 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain)) {
1857 keychain = NULL;
1858 goto errorExit;
1859 }
1860 else
1861 CFRetain(keychain);
1862
1863 // verify permanent parameter
1864 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrIsPermanent, (const void **)&value))
1865 isPermanent = false;
1866 else if (!value || (CFBooleanGetTypeID() != CFGetTypeID(value)))
1867 goto errorExit;
1868 else
1869 isPermanent = CFEqual(kCFBooleanTrue, value);
1870 if (isPermanent) {
1871 if (keychain == NULL) {
1872 // no keychain was specified, so use the default keychain
1873 result = SecKeychainCopyDefault(&keychain);
1874 }
1875 keyAttr |= CSSM_KEYATTR_PERMANENT;
1876 }
1877
1878 // verify extractable parameter
1879 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrIsExtractable, (const void **)&value))
1880 isExtractable = true; // default to extractable if value not specified
1881 else if (!value || (CFBooleanGetTypeID() != CFGetTypeID(value)))
1882 goto errorExit;
1883 else
1884 isExtractable = CFEqual(kCFBooleanTrue, value);
1885 if (isExtractable)
1886 keyAttr |= CSSM_KEYATTR_EXTRACTABLE;
1887
1888 // verify access parameter
1889 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrAccess, (const void **)&access))
1890 access = NULL;
1891 else if (SecAccessGetTypeID() != CFGetTypeID(access))
1892 goto errorExit;
1893
1894 // verify label parameter
1895 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrLabel, (const void **)&label))
1896 label = (dateLabel = utilCopyDefaultKeyLabel()); // no label provided, so use default
1897 else if (CFStringGetTypeID() != CFGetTypeID(label))
1898 goto errorExit;
1899
1900 // verify application label parameter
1901 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrApplicationLabel, (const void **)&appLabel))
1902 appLabel = (dateLabel) ? dateLabel : (dateLabel = utilCopyDefaultKeyLabel());
1903 else if (CFStringGetTypeID() != CFGetTypeID(appLabel))
1904 goto errorExit;
1905
1906 // verify application tag parameter
1907 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrApplicationTag, (const void **)&appTag))
1908 appTag = NULL;
1909 else if (CFStringGetTypeID() != CFGetTypeID(appTag))
1910 goto errorExit;
1911
1912 utilGetKeyParametersFromCFDict(parameters, &algorithm, &keySizeInBits, &keyUsage, &keyClass);
1913
1914 if (!keychain) {
1915 // the generated key will not be stored in any keychain
1916 result = SecKeyGenerate(keychain, algorithm, keySizeInBits, 0, keyUsage, keyAttr, access, &key);
1917 }
1918 else {
1919 // we can set the label attributes on the generated key if it's a keychain item
1920 size_t labelBufLen = (label) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label), kCFStringEncodingUTF8) + 1 : 1;
1921 char *labelBuf = (char *)malloc(labelBufLen);
1922 size_t appLabelBufLen = (appLabel) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel), kCFStringEncodingUTF8) + 1 : 1;
1923 char *appLabelBuf = (char *)malloc(appLabelBufLen);
1924 size_t appTagBufLen = (appTag) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag), kCFStringEncodingUTF8) + 1 : 1;
1925 char *appTagBuf = (char *)malloc(appTagBufLen);
1926
1927 if (!label || !CFStringGetCString(label, labelBuf, labelBufLen-1, kCFStringEncodingUTF8))
1928 labelBuf[0]=0;
1929 if (!appLabel || !CFStringGetCString(appLabel, appLabelBuf, appLabelBufLen-1, kCFStringEncodingUTF8))
1930 appLabelBuf[0]=0;
1931 if (!appTag || !CFStringGetCString(appTag, appTagBuf, appTagBufLen-1, kCFStringEncodingUTF8))
1932 appTagBuf[0]=0;
1933
1934 SecKeychainAttribute attrs[] = {
1935 { kSecKeyPrintName, (UInt32)strlen(labelBuf), (char *)labelBuf },
1936 { kSecKeyLabel, (UInt32)strlen(appLabelBuf), (char *)appLabelBuf },
1937 { kSecKeyApplicationTag, (UInt32)strlen(appTagBuf), (char *)appTagBuf } };
1938 SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
1939 if (!appTag) --attributes.count;
1940
1941 result = SecKeyGenerateWithAttributes(&attributes,
1942 keychain, algorithm, keySizeInBits, 0,
1943 keyUsage, keyAttr, access, &key);
1944
1945 free(labelBuf);
1946 free(appLabelBuf);
1947 free(appTagBuf);
1948 }
1949
1950 errorExit:
1951 if (result && error) {
1952 *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, result, NULL);
1953 }
1954 if (dateLabel)
1955 CFRelease(dateLabel);
1956 if (keychain)
1957 CFRelease(keychain);
1958
1959 return key;
1960 }
1961
1962
1963
1964 SecKeyRef
1965 SecKeyCreateFromData(CFDictionaryRef parameters, CFDataRef keyData, CFErrorRef *error)
1966 {
1967 CSSM_ALGORITHMS algorithm;
1968 uint32 keySizeInBits;
1969 CSSM_KEYUSE keyUsage;
1970 CSSM_KEYCLASS keyClass;
1971 CSSM_RETURN crtn;
1972
1973 if(keyData == NULL || CFDataGetLength(keyData) == 0){
1974 MacOSError::throwMe(errSecUnsupportedKeySize);
1975 }
1976
1977 utilGetKeyParametersFromCFDict(parameters, &algorithm, &keySizeInBits, &keyUsage, &keyClass);
1978
1979 CSSM_CSP_HANDLE cspHandle = cuCspStartup(CSSM_FALSE); // TRUE => CSP, FALSE => CSPDL
1980
1981 SecKeyImportExportParameters iparam;
1982 memset(&iparam, 0, sizeof(iparam));
1983 iparam.keyUsage = keyUsage;
1984
1985 CFRef<CFDataRef> data;
1986 SecExternalItemType itype;
1987 switch (keyClass) {
1988 case CSSM_KEYCLASS_PRIVATE_KEY:
1989 itype = kSecItemTypePrivateKey;
1990 break;
1991 case CSSM_KEYCLASS_PUBLIC_KEY: {
1992 itype = kSecItemTypePublicKey;
1993 // Public key import expects public key in SubjPublicKey X509 format. We want to accept both bare and x509 format,
1994 // so we have to detect bare format here and extend to full X509 if detected.
1995 data.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm, keySizeInBits, keyData));
1996 break;
1997 }
1998 case CSSM_KEYCLASS_SESSION_KEY:
1999 itype = kSecItemTypeSessionKey;
2000 break;
2001 default:
2002 itype = kSecItemTypeUnknown;
2003 break;
2004 }
2005
2006 CFMutableArrayRef ka = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2007 // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful.
2008 crtn = impExpImportRawKey(data ? CFDataRef(data) : keyData, kSecFormatUnknown, itype, algorithm, NULL, cspHandle, 0, NULL, NULL, ka);
2009 if (crtn == CSSM_OK && CFArrayGetCount((CFArrayRef)ka)) {
2010 SecKeyRef sk = (SecKeyRef)CFArrayGetValueAtIndex((CFArrayRef)ka, 0);
2011 CFRetain(sk);
2012 CFRelease(ka);
2013 return sk;
2014 } else {
2015 CFRelease(ka);
2016 if (error) {
2017 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, crtn ? crtn : CSSM_ERRCODE_INTERNAL_ERROR, NULL);
2018 }
2019 return NULL;
2020 }
2021 }
2022
2023
2024 void
2025 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable, dispatch_queue_t deliveryQueue,
2026 SecKeyGeneratePairBlock result)
2027 {
2028 CFDictionaryRef parameters = CFDictionaryCreateCopy(NULL, parametersWhichMightBeMutiable);
2029 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
2030 SecKeyRef publicKey = NULL;
2031 SecKeyRef privateKey = NULL;
2032 OSStatus status = SecKeyGeneratePair(parameters, &publicKey, &privateKey);
2033 dispatch_async(deliveryQueue, ^{
2034 CFErrorRef error = NULL;
2035 if (errSecSuccess != status) {
2036 error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, NULL);
2037 }
2038 result(publicKey, privateKey, error);
2039 if (error) {
2040 CFRelease(error);
2041 }
2042 if (publicKey) {
2043 CFRelease(publicKey);
2044 }
2045 if (privateKey) {
2046 CFRelease(privateKey);
2047 }
2048 CFRelease(parameters);
2049 });
2050 });
2051 }
2052
2053 static inline void utilClearAndFree(void *p, size_t len) {
2054 if(p) {
2055 if(len) bzero(p, len);
2056 free(p);
2057 }
2058 }
2059
2060 SecKeyRef
2061 SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErrorRef *error)
2062 {
2063 CCPBKDFAlgorithm algorithm;
2064 CFIndex passwordLen = 0;
2065 CFDataRef keyData = NULL;
2066 char *thePassword = NULL;
2067 uint8_t *salt = NULL;
2068 uint8_t *derivedKey = NULL;
2069 size_t saltLen = 0, derivedKeyLen = 0;
2070 uint rounds;
2071 CFDataRef saltDictValue, algorithmDictValue;
2072 SecKeyRef retval = NULL;
2073
2074 /* Pick Values from parameters */
2075
2076 if((saltDictValue = (CFDataRef) CFDictionaryGetValue(parameters, kSecAttrSalt)) == NULL) {
2077 if(error) {
2078 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecMissingAlgorithmParms, NULL);
2079 }
2080 goto errOut;
2081 }
2082
2083 derivedKeyLen = utilGetNumberFromCFDict(parameters, kSecAttrKeySizeInBits, 128);
2084 // This value come in bits but the rest of the code treats it as bytes
2085 derivedKeyLen /= 8;
2086
2087 algorithmDictValue = (CFDataRef) utilGetStringFromCFDict(parameters, kSecAttrPRF, kSecAttrPRFHmacAlgSHA256);
2088
2089 rounds = utilGetNumberFromCFDict(parameters, kSecAttrRounds, 0);
2090
2091 /* Convert any remaining parameters and get the password bytes */
2092
2093 saltLen = CFDataGetLength(saltDictValue);
2094 if((salt = (uint8_t *) malloc(saltLen)) == NULL) {
2095 if(error) {
2096 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL);
2097 }
2098 goto errOut;
2099 }
2100
2101 CFDataGetBytes(saltDictValue, CFRangeMake(0, saltLen), (UInt8 *) salt);
2102
2103 passwordLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(password), kCFStringEncodingUTF8) + 1;
2104 if((thePassword = (char *) malloc(passwordLen)) == NULL) {
2105 if(error) {
2106 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL);
2107 }
2108 goto errOut;
2109 }
2110 CFStringGetBytes(password, CFRangeMake(0, CFStringGetLength(password)), kCFStringEncodingUTF8, '?', FALSE, (UInt8*)thePassword, passwordLen, &passwordLen);
2111
2112 if((derivedKey = (uint8_t *) malloc(derivedKeyLen)) == NULL) {
2113 if(error) {
2114 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL);
2115 }
2116 goto errOut;
2117 }
2118
2119 if(algorithmDictValue == NULL) {
2120 algorithm = kCCPRFHmacAlgSHA1; /* default */
2121 } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA1)) {
2122 algorithm = kCCPRFHmacAlgSHA1;
2123 } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA224)) {
2124 algorithm = kCCPRFHmacAlgSHA224;
2125 } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA256)) {
2126 algorithm = kCCPRFHmacAlgSHA256;
2127 } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA384)) {
2128 algorithm = kCCPRFHmacAlgSHA384;
2129 } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA512)) {
2130 algorithm = kCCPRFHmacAlgSHA512;
2131 } else {
2132 if(error) {
2133 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidAlgorithmParms, NULL);
2134 }
2135 goto errOut;
2136 }
2137
2138 if(rounds == 0) {
2139 rounds = 33333; // we need to pass back a consistent value since there's no way to record the round count.
2140 }
2141
2142 if(CCKeyDerivationPBKDF(kCCPBKDF2, thePassword, passwordLen, salt, saltLen, algorithm, rounds, derivedKey, derivedKeyLen)) {
2143 if(error) {
2144 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL);
2145 }
2146 goto errOut;
2147 }
2148
2149 if((keyData = CFDataCreate(NULL, derivedKey, derivedKeyLen)) != NULL) {
2150 retval = SecKeyCreateFromData(parameters, keyData, error);
2151 CFRelease(keyData);
2152 } else {
2153 if(error) {
2154 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL);
2155 }
2156 }
2157
2158 errOut:
2159 utilClearAndFree(salt, saltLen);
2160 utilClearAndFree(thePassword, passwordLen);
2161 utilClearAndFree(derivedKey, derivedKeyLen);
2162 return retval;
2163 }
2164
2165 CFDataRef
2166 SecKeyWrapSymmetric(SecKeyRef keyToWrap, SecKeyRef wrappingKey, CFDictionaryRef parameters, CFErrorRef *error)
2167 {
2168 if(error) {
2169 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
2170 }
2171 return NULL;
2172 }
2173
2174 SecKeyRef
2175 SecKeyUnwrapSymmetric(CFDataRef *keyToUnwrap, SecKeyRef unwrappingKey, CFDictionaryRef parameters, CFErrorRef *error)
2176 {
2177 if(error) {
2178 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
2179 }
2180 return NULL;
2181 }