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