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