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