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