]> git.saurik.com Git - apple/security.git/blob - libsecurity_keychain/lib/SecImportExportCrypto.cpp
Security-55471.14.18.tar.gz
[apple/security.git] / libsecurity_keychain / lib / SecImportExportCrypto.cpp
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, 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 * SecImportExportCrypto.cpp - low-level crypto routines for wrapping and unwrapping
25 * keys.
26 */
27
28 #include "SecImportExport.h"
29 #include "SecImportExportCrypto.h"
30 #include "SecImportExportUtils.h"
31 #include "Keychains.h"
32 #include "Access.h"
33 #include "Item.h"
34 #include "SecKeyPriv.h"
35 #include "KCEventNotifier.h"
36 #include <security_cdsa_utilities/cssmacl.h>
37 #include <security_cdsa_utilities/KeySchema.h>
38 #include <security_cdsa_utilities/cssmdata.h>
39 #include <security_cdsa_utils/cuCdsaUtils.h>
40 #include <security_utilities/devrandom.h>
41 #include <security_cdsa_client/securestorage.h>
42 #include <security_cdsa_client/dlclient.h>
43 #include <Security/cssmapi.h>
44
45 /*
46 * Key attrribute names and values.
47 *
48 * This is where the public key hash goes.
49 */
50 #define SEC_KEY_HASH_ATTR_NAME "Label"
51
52 /*
53 * This is where the publicly visible name goes.
54 */
55 #define SEC_KEY_PRINT_NAME_ATTR_NAME "PrintName"
56
57 /*
58 * Default values we ultimately assign to the PrintName attr.
59 */
60 #define SEC_PRIVKEY_PRINT_NAME_ATTR_VALUE "Imported Private Key"
61 #define SEC_PUBKEY_PRINT_NAME_ATTR_VALUE "Imported Public Key"
62 #define SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE "Imported Key"
63
64 /*
65 * Set private key's Label and PrintName attributes. On entry Label
66 * is typically a random string to faciliate finding the key in a DL;
67 * the PrintName is currently set to the same value by the DL. We
68 * replace the Label attr with the public key hash and the PrintName
69 * attr with a caller-supplied value.
70 */
71 static CSSM_RETURN impExpSetKeyLabel(
72 CSSM_CSP_HANDLE cspHand, // where the key lives
73 CSSM_DL_DB_HANDLE dlDbHand, // ditto
74 SecKeychainRef kcRef, // ditto
75 CSSM_KEY_PTR cssmKey,
76 const CSSM_DATA *existKeyLabel, // existing label, a random string
77 const CSSM_DATA *newPrintName,
78 CssmOwnedData &newLabel, // RETURNED as what we set
79 SecKeyRef *secKey) // RETURNED
80 {
81 CSSM_RETURN crtn;
82 CSSM_DATA keyDigest = {0, NULL};
83
84 crtn = impExpKeyDigest(cspHand, cssmKey, &keyDigest);
85 if(crtn) {
86 return crtn;
87 }
88
89 /* caller needs this for subsequent DL lookup */
90 newLabel.copy(keyDigest);
91
92 /* Find this key as a SecKeychainItem */
93 SecItemClass itemClass = (cssmKey->KeyHeader.KeyClass ==
94 CSSM_KEYCLASS_PRIVATE_KEY) ? kSecPrivateKeyItemClass :
95 kSecPublicKeyItemClass;
96 SecKeychainAttribute kcAttr = {kSecKeyLabel, (UInt32)existKeyLabel->Length, existKeyLabel->Data};
97 SecKeychainAttributeList kcAttrList = {1, &kcAttr};
98 SecKeychainSearchRef srchRef = NULL;
99 OSStatus ortn;
100 SecKeychainItemRef itemRef = NULL;
101
102 ortn = SecKeychainSearchCreateFromAttributes(kcRef, itemClass,
103 &kcAttrList, &srchRef);
104 if(ortn) {
105 SecImpExpDbg("SecKeychainSearchCreateFromAttributes error");
106 crtn = ortn;
107 goto errOut;
108 }
109 ortn = SecKeychainSearchCopyNext(srchRef, &itemRef);
110 if(ortn) {
111 SecImpExpDbg("SecKeychainSearchCopyNext error");
112 crtn = ortn;
113 goto errOut;
114 }
115 #ifndef NDEBUG
116 ortn = SecKeychainSearchCopyNext(srchRef, &itemRef);
117 if(ortn == errSecSuccess) {
118 SecImpExpDbg("impExpSetKeyLabel: found second key with same label!");
119 crtn = errSecInternalComponent;
120 goto errOut;
121 }
122 #endif /* NDEBUG */
123
124 /* modify two attributes... */
125 SecKeychainAttribute modAttrs[2];
126 modAttrs[0].tag = kSecKeyLabel;
127 modAttrs[0].length = (UInt32)keyDigest.Length;
128 modAttrs[0].data = keyDigest.Data;
129 modAttrs[1].tag = kSecKeyPrintName;
130 modAttrs[1].length = (UInt32)newPrintName->Length;
131 modAttrs[1].data = newPrintName->Data;
132 kcAttrList.count = 2;
133 kcAttrList.attr = modAttrs;
134 ortn = SecKeychainItemModifyAttributesAndData(itemRef, &kcAttrList,
135 0, NULL);
136 if(ortn) {
137 SecImpExpDbg("SecKeychainItemModifyAttributesAndData error");
138 crtn = ortn;
139 goto errOut;
140 }
141 *secKey = (SecKeyRef)itemRef;
142 errOut:
143 if(keyDigest.Data) {
144 /* mallocd by CSP */
145 impExpFreeCssmMemory(cspHand, keyDigest.Data);
146 }
147 if(srchRef) {
148 CFRelease(srchRef);
149 }
150 return crtn;
151 }
152
153 /*
154 * Import a raw key. This can be used as a lightweight "guess" evaluator
155 * if a handle to the raw CSP is passed in (with no keychain), or as
156 * the real thing which does full keychain import.
157 */
158 OSStatus impExpImportRawKey(
159 CFDataRef inData,
160 SecExternalFormat externForm,
161 SecExternalItemType itemType,
162 CSSM_ALGORITHMS keyAlg,
163 SecKeychainRef importKeychain, // optional
164 CSSM_CSP_HANDLE cspHand, // required
165 SecItemImportExportFlags flags,
166 const SecKeyImportExportParameters *keyParams, // optional
167 const char *printName, // optional
168 CFMutableArrayRef outArray) // optional, append here
169 {
170 CSSM_RETURN crtn;
171 CSSM_KEY wrappedKey;
172 CSSM_KEYHEADER &hdr = wrappedKey.KeyHeader;
173 CSSM_CSP_HANDLE rawCspHand = 0;
174 CSSM_KEY_SIZE keySize;
175 CSSM_KEYBLOB_FORMAT format;
176 CSSM_KEYCLASS keyClass;
177
178 /* First convert external format and types to CSSM style. */
179 crtn = impExpKeyForm(externForm, itemType, keyAlg, &format, &keyClass);
180
181 /* cook up key to be null-unwrapped */
182 memset(&wrappedKey, 0, sizeof(CSSM_KEY));
183 wrappedKey.KeyData.Length = CFDataGetLength(inData);
184 wrappedKey.KeyData.Data = (uint8 *)CFDataGetBytePtr(inData);
185
186 hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
187 /* CspId don't care */
188 hdr.BlobType = CSSM_KEYBLOB_RAW;
189 hdr.Format = format;
190 hdr.AlgorithmId = keyAlg;
191 hdr.KeyClass = keyClass;
192 /* LogicalKeySizeInBits calculated below */
193 /* attr and usage are for the incoming unwrapped key... */
194 hdr.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
195 hdr.KeyUsage = CSSM_KEYUSE_ANY;
196
197 /*
198 * Get key size in bits from raw CSP. Doing this right now is a good
199 * optimization for the "guessing" case; getting the key size from the
200 * raw CSP involves a full decode on an alg- and format-specific manner.
201 * If we've been given the wrong params, we'll fail right here without
202 * the complication of a full UnwrapKey op.
203 */
204 rawCspHand = cuCspStartup(CSSM_TRUE);
205 if(rawCspHand == 0) {
206 return CSSMERR_CSSM_ADDIN_LOAD_FAILED;
207 }
208 crtn = CSSM_QueryKeySizeInBits(rawCspHand, CSSM_INVALID_HANDLE, &wrappedKey, &keySize);
209 cuCspDetachUnload(rawCspHand, CSSM_TRUE);
210 if(crtn) {
211 SecImpExpDbg("CSSM_QueryKeySizeInBits error");
212 return crtn;
213 }
214 hdr.LogicalKeySizeInBits = keySize.LogicalKeySizeInBits;
215
216 impExpKeyUnwrapParams unwrapParams;
217 memset(&unwrapParams, 0, sizeof(unwrapParams));
218 unwrapParams.encrAlg = CSSM_ALGID_NONE;
219 unwrapParams.encrMode = CSSM_ALGMODE_NONE;
220 unwrapParams.unwrappingKey = NULL;
221 unwrapParams.encrPad = CSSM_PADDING_NONE;
222
223 return impExpImportKeyCommon(
224 &wrappedKey,
225 importKeychain,
226 cspHand,
227 flags,
228 keyParams,
229 &unwrapParams,
230 printName,
231 outArray);
232 }
233
234 using namespace KeychainCore;
235
236 /*
237 * Post notification of a "new key added" event.
238 * If you know of another way to do this, other than a dlclient-based lookup of the
239 * existing key in order to get a KeychainCore::Item, by all means have at it.
240 */
241 OSStatus impExpKeyNotify(
242 SecKeychainRef importKeychain,
243 const CssmData &keyLabel, // stored with this, we use it to do a lookup
244 const CSSM_KEY &cssmKey) // unwrapped key in CSSM format
245 {
246 /*
247 * Look up key in the DLDB by label, key class, algorithm, and key size.
248 */
249 CSSM_DB_RECORDTYPE recordType;
250 const CSSM_KEYHEADER &hdr = cssmKey.KeyHeader;
251
252 switch(hdr.KeyClass) {
253 case CSSM_KEYCLASS_PUBLIC_KEY:
254 recordType = CSSM_DL_DB_RECORD_PUBLIC_KEY;
255 break;
256 case CSSM_KEYCLASS_PRIVATE_KEY:
257 recordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
258 break;
259 case CSSM_KEYCLASS_SESSION_KEY:
260 recordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
261 break;
262 default:
263 return errSecParam;
264 }
265 assert(importKeychain != NULL);
266 Keychain keychain = KeychainImpl::required(importKeychain);
267
268 SSDbImpl* impl = dynamic_cast<CssmClient::SSDbImpl *>(&(*keychain->database()));
269 if (impl == NULL) // did we go bad?
270 {
271 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
272 }
273
274 CssmClient::SSDb ssDb(impl);
275
276 CssmClient::DbAttributes dbAttributes;
277 CssmClient::DbUniqueRecord uniqueId;
278 CssmClient::SSDbCursor dbCursor(ssDb, 3); // three attributes
279 dbCursor->recordType(recordType);
280 dbCursor->add(CSSM_DB_EQUAL, KeySchema::Label, keyLabel);
281 dbCursor->add(CSSM_DB_EQUAL, KeySchema::KeyType, hdr.AlgorithmId);
282 dbCursor->add(CSSM_DB_EQUAL, KeySchema::KeySizeInBits, hdr.LogicalKeySizeInBits);
283 CssmClient::Key key;
284 if (!dbCursor->nextKey(&dbAttributes, key, uniqueId)) {
285 SecImpExpDbg("impExpKeyNotify: key not found");
286 return errSecItemNotFound;
287 }
288
289 /*
290 * Get a Keychain-style Item, post notification.
291 */
292 Item keyItem = keychain->item(recordType, uniqueId);
293 keychain->postEvent(kSecAddEvent, keyItem);
294
295 return errSecSuccess;
296 }
297
298 /*
299 * Size of random label string in ASCII chars to facilitate DL lookup.
300 */
301 #define SEC_RANDOM_LABEL_LEN 16
302
303 #define SEC_KEYATTR_RETURN_MASK \
304 (CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_RETURN_NONE)
305
306 /*
307 * Common code to unwrap a key, used for raw keys (which do a NULL unwrap) and
308 * wrapped keys.
309 */
310 OSStatus impExpImportKeyCommon(
311 const CSSM_KEY *wrappedKey,
312 SecKeychainRef importKeychain, // optional
313 CSSM_CSP_HANDLE cspHand, // required, if importKeychain is
314 // present, must be from there
315 SecItemImportExportFlags flags,
316 const SecKeyImportExportParameters *keyParams, // optional
317 const impExpKeyUnwrapParams *unwrapParams,
318 const char *printName, // optional
319 CFMutableArrayRef outArray) // optional, append here
320 {
321 CSSM_CC_HANDLE ccHand = 0;
322 CSSM_RETURN crtn;
323 CSSM_DATA labelData;
324 CSSM_KEY unwrappedKey;
325 CSSM_DL_DB_HANDLE dlDbHandle;
326 CSSM_DL_DB_HANDLE *dlDbPtr = NULL;
327 OSStatus ortn;
328 CSSM_ACCESS_CREDENTIALS nullCreds;
329 uint8 randLabel[SEC_RANDOM_LABEL_LEN + 1];
330 CSSM_KEYUSE keyUsage = 0; // default
331 CSSM_KEYATTR_FLAGS keyAttributes = 0; // default
332 const CSSM_KEYHEADER &hdr = wrappedKey->KeyHeader;
333 CSSM_DATA descrData = {0, NULL};
334 ResourceControlContext rcc;
335 Security::KeychainCore::Access::Maker maker;
336 ResourceControlContext *rccPtr = NULL;
337 SecAccessRef accessRef = keyParams ? keyParams->accessRef : NULL;
338 CssmAutoData keyLabel(Allocator::standard());
339 SecKeyRef secKeyRef = NULL;
340 bool usedSecKeyCreate = false;
341
342 assert(unwrapParams != NULL);
343 assert(cspHand != 0);
344
345 if(importKeychain) {
346 ortn = SecKeychainGetDLDBHandle(importKeychain, &dlDbHandle);
347 if(ortn) {
348 return ortn;
349 }
350 dlDbPtr = &dlDbHandle;
351 }
352
353 memset(&unwrappedKey, 0, sizeof(CSSM_KEY));
354 memset(&nullCreds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
355
356 /* context for unwrap */
357 crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
358 unwrapParams->encrAlg,
359 unwrapParams->encrMode,
360 &nullCreds,
361 unwrapParams->unwrappingKey,
362 unwrapParams->iv.Data ? &unwrapParams->iv : NULL,
363 unwrapParams->encrPad,
364 0, // Params
365 &ccHand);
366 if(crtn) {
367 goto errOut;
368 }
369 if(dlDbPtr) {
370 /* Importing to a keychain - add DLDB to context */
371 crtn = impExpAddContextAttribute(ccHand,
372 CSSM_ATTRIBUTE_DL_DB_HANDLE,
373 sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE),
374 dlDbPtr);
375 if(crtn) {
376 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
377 goto errOut;
378 }
379 }
380
381 if((hdr.KeyClass != CSSM_KEYCLASS_SESSION_KEY) && (dlDbPtr != NULL)) {
382 /* Generate random 16-char label to facilitate DL lookup */
383 char *randAscii = (char *)randLabel;
384 uint8 randBinary[SEC_RANDOM_LABEL_LEN / 2];
385 unsigned randBinaryLen = SEC_RANDOM_LABEL_LEN / 2;
386 DevRandomGenerator rng;
387
388 rng.random(randBinary, randBinaryLen);
389 for(unsigned i=0; i<randBinaryLen; i++) {
390 sprintf(randAscii, "%02X", randBinary[i]);
391 randAscii += 2;
392 }
393 labelData.Data = randLabel;
394 labelData.Length = SEC_RANDOM_LABEL_LEN;
395 /* actual keyLabel value set later */
396 }
397 else {
398 labelData.Data = (uint8 *)SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE;
399 labelData.Length = strlen(SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE);
400 keyLabel.copy(labelData);
401 }
402
403 /*
404 * key attr flags and usage. First the defaults.
405 */
406 if(keyParams) {
407 keyUsage = keyParams->keyUsage;
408 keyAttributes = keyParams->keyAttributes;
409 }
410 if(keyUsage == 0) {
411 /* default */
412 keyUsage = CSSM_KEYUSE_ANY;
413 }
414 if(keyAttributes == 0) {
415 /* default */
416 keyAttributes = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
417 if(dlDbPtr) {
418 keyAttributes |= CSSM_KEYATTR_PERMANENT;
419 }
420 if(hdr.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY) {
421 keyAttributes |= (CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE);
422 }
423 }
424 else {
425 /* caller-supplied; ensure we're generating a reference key */
426 keyAttributes &= ~SEC_KEYATTR_RETURN_MASK;
427 keyAttributes |= CSSM_KEYATTR_RETURN_REF;
428 }
429
430 if( (dlDbPtr != NULL) && // not permanent, no ACL
431 (hdr.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY) && // ACLs only for private key
432 ( (keyParams == NULL) || // NULL --> default ACL
433 !(keyParams->flags & kSecKeyNoAccessControl) // explicity request no ACL
434 )
435 ) {
436 /*
437 * Prepare to set up either a default ACL or one provided by caller via
438 * keyParams->accessRef.
439 */
440 memset(&rcc, 0, sizeof(rcc));
441 maker.initialOwner(rcc);
442 rccPtr = &rcc;
443 }
444
445 /*
446 * Additional optional parameters: block size, rounds,
447 * effectiveKeySize.
448 * WARNING: block size and rounds, used for RC5, have not been tested.
449 * OpenSSL, as of Panther ship, did not support RC5 encryption.
450 */
451 if(unwrapParams->effectiveKeySizeInBits != 0) {
452 assert(unwrapParams->unwrappingKey->KeyHeader.AlgorithmId ==
453 CSSM_ALGID_RC2);
454 SecImpExpDbg("impExpImportKeyCommon: setting effectiveKeySizeInBits to %lu",
455 (unsigned long)unwrapParams->effectiveKeySizeInBits);
456 crtn = impExpAddContextAttribute(ccHand,
457 CSSM_ATTRIBUTE_EFFECTIVE_BITS,
458 sizeof(uint32),
459 (void *)((size_t) unwrapParams->effectiveKeySizeInBits));
460 if(crtn) {
461 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
462 goto errOut;
463 }
464 }
465
466 if(unwrapParams->rounds != 0) {
467 assert(unwrapParams->unwrappingKey->KeyHeader.AlgorithmId ==
468 CSSM_ALGID_RC5);
469 SecImpExpDbg("impExpImportKeyCommon: setting rounds to %lu",
470 (unsigned long)unwrapParams->rounds);
471 crtn = impExpAddContextAttribute(ccHand,
472 CSSM_ATTRIBUTE_ROUNDS,
473 sizeof(uint32),
474 (void *)((size_t)unwrapParams->rounds));
475 if(crtn) {
476 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
477 goto errOut;
478 }
479 }
480
481 if(unwrapParams->blockSizeInBits != 0) {
482 /* Our RC5 implementation has a fixed block size */
483 if(unwrapParams->blockSizeInBits != 64) {
484 SecImpExpDbg("WARNING impExpImportKeyCommon: setting block size to %lu",
485 (unsigned long)unwrapParams->blockSizeInBits);
486 /*
487 * With the current CSP this will actually be ignored
488 */
489 crtn = impExpAddContextAttribute(ccHand,
490 CSSM_ATTRIBUTE_BLOCK_SIZE,
491 sizeof(uint32),
492 (void *)((size_t)unwrapParams->blockSizeInBits));
493 if(crtn) {
494 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
495 goto errOut;
496 }
497 }
498 }
499
500 /* Here we go */
501 crtn = CSSM_UnwrapKey(ccHand,
502 NULL, // public key
503 (const CSSM_WRAP_KEY *)wrappedKey,
504 keyUsage,
505 keyAttributes,
506 &labelData,
507 rccPtr, // CredAndAclEntry
508 &unwrappedKey,
509 &descrData); // required
510 if(crtn != CSSM_OK) {
511 SecImpExpDbg("CSSM_UnwrapKey failure");
512 if(crtn == CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA) {
513 /* report in a keychain-friendly way */
514 crtn = errSecDuplicateItem;
515 }
516 goto errOut;
517 }
518
519 /* Private and public keys: update Label as public key hash */
520 if((hdr.KeyClass != CSSM_KEYCLASS_SESSION_KEY) && (dlDbPtr != NULL)) {
521 CSSM_DATA newPrintName;
522 if(printName) {
523 /* caller specified */
524 newPrintName.Data = (uint8 *)printName;
525 }
526 else {
527 /* use defaults */
528 if(hdr.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY) {
529 newPrintName.Data = (uint8 *)SEC_PRIVKEY_PRINT_NAME_ATTR_VALUE;
530 }
531 else {
532 newPrintName.Data = (uint8 *)SEC_PUBKEY_PRINT_NAME_ATTR_VALUE;
533 }
534 }
535 newPrintName.Length = strlen((char *)newPrintName.Data);
536 #if old_way
537 crtn = impExpSetKeyLabel(cspHand, *dlDbPtr, &unwrappedKey,
538 &labelData, &newPrintName, keyLabel);
539 #else
540 crtn = impExpSetKeyLabel(cspHand, *dlDbPtr, importKeychain,
541 &unwrappedKey, &labelData, &newPrintName, keyLabel, &secKeyRef);
542 #endif
543 if(crtn) {
544 goto errOut;
545 }
546 }
547
548 /* Private key: adjust ACL as appropriate */
549 if(rccPtr != NULL) {
550 SecPointer<KeychainCore::Access> theAccess(accessRef ?
551 KeychainCore::Access::required(accessRef) :
552 new KeychainCore::Access("Imported Private Key"));
553 try {
554 CssmClient::KeyAclBearer bearer(cspHand, unwrappedKey, Allocator::standard());
555 theAccess->setAccess(bearer, maker);
556 }
557 catch (const CssmError &e) {
558 /* not implemented means we're talking to the raw CSP which does
559 * not implement ACLs */
560 if(e.error != CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED) {
561 crtn = e.error;
562 }
563 }
564 catch(...) {
565 SecImpExpDbg("keyImport: exception on setAccess\n");
566 crtn = errSecAuthFailed; /* ??? */
567 }
568 }
569
570 /*
571 * If importKeychain is non-NULL we've already added the key to the keychain.
572 * If importKeychain is NULL, and outArray is non-NULL, we have to use the
573 * half-baked SecKeyCreateWithCSSMKey to give the caller *something*.
574 */
575 if(outArray) {
576 if(secKeyRef == NULL) {
577 assert(importKeychain == NULL);
578 ortn = SecKeyCreateWithCSSMKey(&unwrappedKey, &secKeyRef);
579 if(ortn) {
580 SecImpExpDbg("SecKeyCreateWithCSSMKey failure");
581 crtn = ortn;
582 goto errOut;
583 }
584 /* don't CSSM_FreeKey() this key */
585 usedSecKeyCreate = true;
586 }
587 CFArrayAppendValue(outArray, secKeyRef);
588 }
589
590 if(importKeychain) {
591 impExpKeyNotify(importKeychain, keyLabel.get(), unwrappedKey);
592 }
593
594 errOut:
595 if(ccHand != 0) {
596 CSSM_DeleteContext(ccHand);
597 }
598 if(secKeyRef) {
599 CFRelease(secKeyRef);
600 }
601 if((unwrappedKey.KeyData.Data != NULL) && !usedSecKeyCreate) {
602 /* skip this free if we used SecKeyCreateWithCSSMKey() */
603 CSSM_FreeKey(cspHand, NULL, &unwrappedKey, CSSM_FALSE);
604 }
605 return crtn;
606 }
607
608 /*
609 * Common code to wrap a key for export.
610 */
611 CSSM_RETURN impExpExportKeyCommon(
612 CSSM_CSP_HANDLE cspHand, // for all three keys
613 SecKeyRef secKey,
614 CSSM_KEY_PTR wrappingKey,
615 CSSM_KEY_PTR wrappedKey, // RETURNED
616 CSSM_ALGORITHMS wrapAlg,
617 CSSM_ENCRYPT_MODE wrapMode,
618 CSSM_PADDING wrapPad,
619 CSSM_KEYBLOB_FORMAT wrapFormat, // NONE, PKCS7, PKCS8, OPENSSL
620 CSSM_ATTRIBUTE_TYPE blobAttrType, // optional raw key format attr
621 CSSM_KEYBLOB_FORMAT blobForm, // ditto
622 const CSSM_DATA *descData, // optional descriptive data
623 const CSSM_DATA *iv)
624 {
625 OSStatus ortn;
626 CSSM_RETURN crtn;
627
628 const CSSM_KEY *unwrappedKey;
629 ortn = SecKeyGetCSSMKey(secKey, &unwrappedKey);
630 if(ortn) {
631 SecImpExpDbg("impExpExportKeyCommon SecKeyGetCSSMKey error");
632 return ortn;
633 }
634 else if(!(unwrappedKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
635 SecImpExpDbg("impExpExportKeyCommon: CSSM key is non-extractable");
636 return errSecDataNotAvailable;
637 }
638
639 /*
640 * Creds needed only for wrapping private keys.
641 * We bother checking in case we ever want to use this to wrap
642 * session keys.
643 */
644 CSSM_ACCESS_CREDENTIALS nullCreds;
645 memset(&nullCreds, 0, sizeof(nullCreds));
646 const CSSM_ACCESS_CREDENTIALS *creds = &nullCreds; // default
647
648 CSSM_KEYCLASS keyClass = unwrappedKey->KeyHeader.KeyClass;
649 if(keyClass == CSSM_KEYCLASS_PRIVATE_KEY) {
650 ortn = SecKeyGetCredentials(secKey,
651 CSSM_ACL_AUTHORIZATION_DECRYPT, // HACK will change!
652 kSecCredentialTypeDefault,
653 &creds);
654 if(ortn) {
655 SecImpExpDbg("impExpExportKeyCommon SecKeyGetCredentials error");
656 return ortn;
657 }
658 }
659
660 CSSM_CC_HANDLE ccHand;
661 crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
662 wrapAlg,
663 wrapMode,
664 &nullCreds, // creds for wrapping key, never a private key here
665 wrappingKey,
666 iv,
667 wrapPad,
668 0, // Params
669 &ccHand);
670 if(ortn) {
671 SecImpExpDbg("impExpExportKeyCommon CSSM_CSP_CreateSymmetricContext error");
672 return crtn;
673 }
674
675 /* a couple of optional caller-specified attributes */
676 if(wrapFormat != CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) {
677 crtn = impExpAddContextAttribute(ccHand,
678 CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT,
679 sizeof(uint32),
680 (void *)((size_t)wrapFormat));
681 if(crtn) {
682 SecImpExpDbg("impExpExportKeyCommon AddContextAttribute error (1)");
683 CSSM_DeleteContext(ccHand);
684 return crtn;
685 }
686 }
687
688 if(blobAttrType != CSSM_ATTRIBUTE_NONE) {
689 crtn = impExpAddContextAttribute(ccHand,
690 blobAttrType,
691 sizeof(uint32),
692 (void *)((size_t)blobForm));
693 if(crtn) {
694 SecImpExpDbg("impExpExportKeyCommon AddContextAttribute error");
695 return crtn;
696 }
697 }
698
699 CSSM_DATA dData = {0, 0};
700 if(descData) {
701 dData = *descData;
702 }
703
704 crtn = CSSM_WrapKey(ccHand,
705 creds,
706 unwrappedKey,
707 &dData,
708 wrappedKey);
709 CSSM_DeleteContext(ccHand);
710 switch(crtn) {
711 case CSSM_OK:
712 break;
713 case CSSMERR_CSP_INVALID_KEYATTR_MASK:
714 {
715 /*
716 * This is what comes back when we try to wrap an unextractable
717 * key, or when we null wrap a sensitive key. Give the caller
718 * some useful info.
719 */
720 CSSM_KEYATTR_FLAGS attr = unwrappedKey->KeyHeader.KeyAttr;
721 if(!(attr & CSSM_KEYATTR_EXTRACTABLE)) {
722 SecImpExpDbg("impExpExportKeyCommon !EXTRACTABLE");
723 return errSecDataNotAvailable;
724 }
725 if((attr & CSSM_KEYATTR_SENSITIVE) && (wrappingKey == NULL)) {
726 SecImpExpDbg("impExpExportKeyCommon !SENSITIVE, NULL wrap");
727 return errSecPassphraseRequired;
728 }
729
730 }
731 default:
732 SecImpExpDbg("impExpExportKeyCommon CSSM_WrapKey error");
733 }
734 return crtn;
735 }