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