2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 * SecImportExportCrypto.cpp - low-level crypto routines for wrapping and unwrapping
28 #include "SecImportExport.h"
29 #include "SecImportExportCrypto.h"
30 #include "SecImportExportUtils.h"
31 #include "Keychains.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 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
47 * Key attrribute names and values.
49 * This is where the public key hash goes.
51 #define SEC_KEY_HASH_ATTR_NAME "Label"
54 * This is where the publicly visible name goes.
56 #define SEC_KEY_PRINT_NAME_ATTR_NAME "PrintName"
59 * Default values we ultimately assign to the PrintName attr.
61 #define SEC_PRIVKEY_PRINT_NAME_ATTR_VALUE "Imported Private Key"
62 #define SEC_PUBKEY_PRINT_NAME_ATTR_VALUE "Imported Public Key"
63 #define SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE "Imported Key"
66 * Set private key's Label and PrintName attributes. On entry Label
67 * is typically a random string to faciliate finding the key in a DL;
68 * the PrintName is currently set to the same value by the DL. We
69 * replace the Label attr with the public key hash and the PrintName
70 * attr with a caller-supplied value.
72 static CSSM_RETURN
impExpSetKeyLabel(
73 CSSM_CSP_HANDLE cspHand
, // where the key lives
74 CSSM_DL_DB_HANDLE dlDbHand
, // ditto
75 SecKeychainRef kcRef
, // ditto
77 const CSSM_DATA
*existKeyLabel
, // existing label, a random string
78 const CSSM_DATA
*newPrintName
,
79 CssmOwnedData
&newLabel
, // RETURNED as what we set
80 SecKeyRef
*secKey
) // RETURNED
83 CSSM_DATA keyDigest
= {0, NULL
};
85 crtn
= impExpKeyDigest(cspHand
, cssmKey
, &keyDigest
);
90 /* caller needs this for subsequent DL lookup */
91 newLabel
.copy(keyDigest
);
93 /* Find this key as a SecKeychainItem */
94 SecItemClass itemClass
= (cssmKey
->KeyHeader
.KeyClass
==
95 CSSM_KEYCLASS_PRIVATE_KEY
) ? kSecPrivateKeyItemClass
:
96 kSecPublicKeyItemClass
;
97 SecKeychainAttribute kcAttr
= {kSecKeyLabel
, existKeyLabel
->Length
, existKeyLabel
->Data
};
98 SecKeychainAttributeList kcAttrList
= {1, &kcAttr
};
99 SecKeychainSearchRef srchRef
= NULL
;
101 SecKeychainItemRef itemRef
= NULL
;
103 ortn
= SecKeychainSearchCreateFromAttributes(kcRef
, itemClass
,
104 &kcAttrList
, &srchRef
);
106 SecImpExpDbg("SecKeychainSearchCreateFromAttributes error");
110 ortn
= SecKeychainSearchCopyNext(srchRef
, &itemRef
);
112 SecImpExpDbg("SecKeychainSearchCopyNext error");
117 ortn
= SecKeychainSearchCopyNext(srchRef
, &itemRef
);
119 SecImpExpDbg("impExpSetKeyLabel: found second key with same label!");
120 crtn
= internalComponentErr
;
125 /* modify two attributes... */
126 SecKeychainAttribute modAttrs
[2];
127 modAttrs
[0].tag
= kSecKeyLabel
;
128 modAttrs
[0].length
= keyDigest
.Length
;
129 modAttrs
[0].data
= keyDigest
.Data
;
130 modAttrs
[1].tag
= kSecKeyPrintName
;
131 modAttrs
[1].length
= newPrintName
->Length
;
132 modAttrs
[1].data
= newPrintName
->Data
;
133 kcAttrList
.count
= 2;
134 kcAttrList
.attr
= modAttrs
;
135 ortn
= SecKeychainItemModifyAttributesAndData(itemRef
, &kcAttrList
,
138 SecImpExpDbg("SecKeychainItemModifyAttributesAndData error");
142 *secKey
= (SecKeyRef
)itemRef
;
146 impExpFreeCssmMemory(cspHand
, keyDigest
.Data
);
155 * Import a raw key. This can be used as a lightweight "guess" evaluator
156 * if a handle to the raw CSP is passed in (with no keychain), or as
157 * the real thing which does full keychain import.
159 OSStatus
impExpImportRawKey(
161 SecExternalFormat externForm
,
162 SecExternalItemType itemType
,
163 CSSM_ALGORITHMS keyAlg
,
164 SecKeychainRef importKeychain
, // optional
165 CSSM_CSP_HANDLE cspHand
, // required
166 SecItemImportExportFlags flags
,
167 const SecKeyImportExportParameters
*keyParams
, // optional
168 const char *printName
, // optional
169 CFMutableArrayRef outArray
) // optional, append here
173 CSSM_KEYHEADER
&hdr
= wrappedKey
.KeyHeader
;
174 CSSM_CSP_HANDLE rawCspHand
= 0;
175 CSSM_KEY_SIZE keySize
;
176 CSSM_KEYBLOB_FORMAT format
;
177 CSSM_KEYCLASS keyClass
;
179 /* First convert external format and types to CSSM style. */
180 crtn
= impExpKeyForm(externForm
, itemType
, keyAlg
, &format
, &keyClass
);
182 /* cook up key to be null-unwrapped */
183 memset(&wrappedKey
, 0, sizeof(CSSM_KEY
));
184 wrappedKey
.KeyData
.Length
= CFDataGetLength(inData
);
185 wrappedKey
.KeyData
.Data
= (uint8
*)CFDataGetBytePtr(inData
);
187 hdr
.HeaderVersion
= CSSM_KEYHEADER_VERSION
;
188 /* CspId don't care */
189 hdr
.BlobType
= CSSM_KEYBLOB_RAW
;
191 hdr
.AlgorithmId
= keyAlg
;
192 hdr
.KeyClass
= keyClass
;
193 /* LogicalKeySizeInBits calculated below */
194 /* attr and usage are for the incoming unwrapped key... */
195 hdr
.KeyAttr
= CSSM_KEYATTR_EXTRACTABLE
;
196 hdr
.KeyUsage
= CSSM_KEYUSE_ANY
;
199 * Get key size in bits from raw CSP. Doing this right now is a good
200 * optimization for the "guessing" case; getting the key size from the
201 * raw CSP involves a full decode on an alg- and format-specific manner.
202 * If we've been given the wrong params, we'll fail right here without
203 * the complication of a full UnwrapKey op.
205 rawCspHand
= cuCspStartup(CSSM_TRUE
);
206 if(rawCspHand
== 0) {
207 return CSSMERR_CSSM_ADDIN_LOAD_FAILED
;
209 crtn
= CSSM_QueryKeySizeInBits(rawCspHand
, CSSM_INVALID_HANDLE
, &wrappedKey
, &keySize
);
210 cuCspDetachUnload(rawCspHand
, CSSM_TRUE
);
212 SecImpExpDbg("CSSM_QueryKeySizeInBits error");
215 hdr
.LogicalKeySizeInBits
= keySize
.LogicalKeySizeInBits
;
217 impExpKeyUnwrapParams unwrapParams
;
218 memset(&unwrapParams
, 0, sizeof(unwrapParams
));
219 unwrapParams
.encrAlg
= CSSM_ALGID_NONE
;
220 unwrapParams
.encrMode
= CSSM_ALGMODE_NONE
;
221 unwrapParams
.unwrappingKey
= NULL
;
222 unwrapParams
.encrPad
= CSSM_PADDING_NONE
;
224 return impExpImportKeyCommon(
235 using namespace KeychainCore
;
238 * Post notification of a "new key added" event.
239 * If you know of another way to do this, other than a dlclient-based lookup of the
240 * existing key in order to get a KeychainCore::Item, by all means have at it.
242 OSStatus
impExpKeyNotify(
243 SecKeychainRef importKeychain
,
244 const CssmData
&keyLabel
, // stored with this, we use it to do a lookup
245 const CSSM_KEY
&cssmKey
) // unwrapped key in CSSM format
248 * Look up key in the DLDB by label, key class, algorithm, and key size.
250 CSSM_DB_RECORDTYPE recordType
;
251 const CSSM_KEYHEADER
&hdr
= cssmKey
.KeyHeader
;
253 switch(hdr
.KeyClass
) {
254 case CSSM_KEYCLASS_PUBLIC_KEY
:
255 recordType
= CSSM_DL_DB_RECORD_PUBLIC_KEY
;
257 case CSSM_KEYCLASS_PRIVATE_KEY
:
258 recordType
= CSSM_DL_DB_RECORD_PRIVATE_KEY
;
260 case CSSM_KEYCLASS_SESSION_KEY
:
261 recordType
= CSSM_DL_DB_RECORD_SYMMETRIC_KEY
;
266 assert(importKeychain
!= NULL
);
267 Keychain keychain
= KeychainImpl::required(importKeychain
);
269 SSDbImpl
* impl
= dynamic_cast<CssmClient::SSDbImpl
*>(&(*keychain
->database()));
270 if (impl
== NULL
) // did we go bad?
272 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
275 CssmClient::SSDb
ssDb(impl
);
277 CssmClient::DbAttributes dbAttributes
;
278 CssmClient::DbUniqueRecord uniqueId
;
279 CssmClient::SSDbCursor
dbCursor(ssDb
, 3); // three attributes
280 dbCursor
->recordType(recordType
);
281 dbCursor
->add(CSSM_DB_EQUAL
, KeySchema::Label
, keyLabel
);
282 dbCursor
->add(CSSM_DB_EQUAL
, KeySchema::KeyType
, hdr
.AlgorithmId
);
283 dbCursor
->add(CSSM_DB_EQUAL
, KeySchema::KeySizeInBits
, hdr
.LogicalKeySizeInBits
);
285 if (!dbCursor
->nextKey(&dbAttributes
, key
, uniqueId
)) {
286 SecImpExpDbg("impExpKeyNotify: key not found");
287 return errSecItemNotFound
;
291 * Get a Keychain-style Item, post notification.
293 Item keyItem
= keychain
->item(recordType
, uniqueId
);
294 keychain
->postEvent(kSecAddEvent
, keyItem
);
300 * Size of random label string in ASCII chars to facilitate DL lookup.
302 #define SEC_RANDOM_LABEL_LEN 16
304 #define SEC_KEYATTR_RETURN_MASK \
305 (CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_RETURN_NONE)
308 * Common code to unwrap a key, used for raw keys (which do a NULL unwrap) and
311 OSStatus
impExpImportKeyCommon(
312 const CSSM_KEY
*wrappedKey
,
313 SecKeychainRef importKeychain
, // optional
314 CSSM_CSP_HANDLE cspHand
, // required, if importKeychain is
315 // present, must be from there
316 SecItemImportExportFlags flags
,
317 const SecKeyImportExportParameters
*keyParams
, // optional
318 const impExpKeyUnwrapParams
*unwrapParams
,
319 const char *printName
, // optional
320 CFMutableArrayRef outArray
) // optional, append here
322 CSSM_CC_HANDLE ccHand
= 0;
325 CSSM_KEY unwrappedKey
;
326 CSSM_DL_DB_HANDLE dlDbHandle
;
327 CSSM_DL_DB_HANDLE
*dlDbPtr
= NULL
;
329 CSSM_ACCESS_CREDENTIALS nullCreds
;
330 uint8 randLabel
[SEC_RANDOM_LABEL_LEN
+ 1];
331 CSSM_KEYUSE keyUsage
= 0; // default
332 CSSM_KEYATTR_FLAGS keyAttributes
= 0; // default
333 const CSSM_KEYHEADER
&hdr
= wrappedKey
->KeyHeader
;
334 CSSM_DATA descrData
= {0, NULL
};
335 ResourceControlContext rcc
;
336 Security::KeychainCore::Access::Maker maker
;
337 ResourceControlContext
*rccPtr
= NULL
;
338 SecAccessRef accessRef
= keyParams
? keyParams
->accessRef
: NULL
;
339 CssmAutoData
keyLabel(Allocator::standard());
340 SecKeyRef secKeyRef
= NULL
;
341 bool usedSecKeyCreate
= false;
343 assert(unwrapParams
!= NULL
);
344 assert(cspHand
!= 0);
347 ortn
= SecKeychainGetDLDBHandle(importKeychain
, &dlDbHandle
);
351 dlDbPtr
= &dlDbHandle
;
354 memset(&unwrappedKey
, 0, sizeof(CSSM_KEY
));
355 memset(&nullCreds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
357 /* context for unwrap */
358 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
359 unwrapParams
->encrAlg
,
360 unwrapParams
->encrMode
,
362 unwrapParams
->unwrappingKey
,
363 unwrapParams
->iv
.Data
? &unwrapParams
->iv
: NULL
,
364 unwrapParams
->encrPad
,
371 /* Importing to a keychain - add DLDB to context */
372 crtn
= impExpAddContextAttribute(ccHand
,
373 CSSM_ATTRIBUTE_DL_DB_HANDLE
,
374 sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE
),
377 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
382 if((hdr
.KeyClass
!= CSSM_KEYCLASS_SESSION_KEY
) && (dlDbPtr
!= NULL
)) {
383 /* Generate random 16-char label to facilitate DL lookup */
384 char *randAscii
= (char *)randLabel
;
385 uint8 randBinary
[SEC_RANDOM_LABEL_LEN
/ 2];
386 unsigned randBinaryLen
= SEC_RANDOM_LABEL_LEN
/ 2;
387 DevRandomGenerator rng
;
389 rng
.random(randBinary
, randBinaryLen
);
390 for(unsigned i
=0; i
<randBinaryLen
; i
++) {
391 sprintf(randAscii
, "%02X", randBinary
[i
]);
394 labelData
.Data
= randLabel
;
395 labelData
.Length
= SEC_RANDOM_LABEL_LEN
;
396 /* actual keyLabel value set later */
399 labelData
.Data
= (uint8
*)SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE
;
400 labelData
.Length
= strlen(SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE
);
401 keyLabel
.copy(labelData
);
405 * key attr flags and usage. First the defaults.
408 keyUsage
= keyParams
->keyUsage
;
409 keyAttributes
= keyParams
->keyAttributes
;
413 keyUsage
= CSSM_KEYUSE_ANY
;
415 if(keyAttributes
== 0) {
417 keyAttributes
= CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
;
419 keyAttributes
|= CSSM_KEYATTR_PERMANENT
;
421 if(hdr
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) {
422 keyAttributes
|= (CSSM_KEYATTR_SENSITIVE
| CSSM_KEYATTR_EXTRACTABLE
);
426 /* caller-supplied; ensure we're generating a reference key */
427 keyAttributes
&= ~SEC_KEYATTR_RETURN_MASK
;
428 keyAttributes
|= CSSM_KEYATTR_RETURN_REF
;
431 if( (dlDbPtr
!= NULL
) && // not permanent, no ACL
432 (hdr
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) && // ACLs only for private key
433 ( (keyParams
== NULL
) || // NULL --> default ACL
434 !(keyParams
->flags
& kSecKeyNoAccessControl
) // explicity request no ACL
438 * Prepare to set up either a default ACL or one provided by caller via
439 * keyParams->accessRef.
441 memset(&rcc
, 0, sizeof(rcc
));
442 maker
.initialOwner(rcc
);
447 * Additional optional parameters: block size, rounds,
449 * WARNING: block size and rounds, used for RC5, have not been tested.
450 * OpenSSL, as of Panther ship, did not support RC5 encryption.
452 if(unwrapParams
->effectiveKeySizeInBits
!= 0) {
453 assert(unwrapParams
->unwrappingKey
->KeyHeader
.AlgorithmId
==
455 SecImpExpDbg("impExpImportKeyCommon: setting effectiveKeySizeInBits to %lu",
456 (unsigned long)unwrapParams
->effectiveKeySizeInBits
);
457 crtn
= impExpAddContextAttribute(ccHand
,
458 CSSM_ATTRIBUTE_EFFECTIVE_BITS
,
460 (void *)unwrapParams
->effectiveKeySizeInBits
);
462 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
467 if(unwrapParams
->rounds
!= 0) {
468 assert(unwrapParams
->unwrappingKey
->KeyHeader
.AlgorithmId
==
470 SecImpExpDbg("impExpImportKeyCommon: setting rounds to %lu",
471 (unsigned long)unwrapParams
->rounds
);
472 crtn
= impExpAddContextAttribute(ccHand
,
473 CSSM_ATTRIBUTE_ROUNDS
,
475 (void *)unwrapParams
->rounds
);
477 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
482 if(unwrapParams
->blockSizeInBits
!= 0) {
483 /* Our RC5 implementation has a fixed block size */
484 if(unwrapParams
->blockSizeInBits
!= 64) {
485 SecImpExpDbg("WARNING impExpImportKeyCommon: setting block size to %lu",
486 (unsigned long)unwrapParams
->blockSizeInBits
);
488 * With the current CSP this will actually be ignored
490 crtn
= impExpAddContextAttribute(ccHand
,
491 CSSM_ATTRIBUTE_BLOCK_SIZE
,
493 (void *)unwrapParams
->blockSizeInBits
);
495 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
502 crtn
= CSSM_UnwrapKey(ccHand
,
504 (const CSSM_WRAP_KEY
*)wrappedKey
,
508 rccPtr
, // CredAndAclEntry
510 &descrData
); // required
511 if(crtn
!= CSSM_OK
) {
512 SecImpExpDbg("CSSM_UnwrapKey failure");
513 if(crtn
== CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA
) {
514 /* report in a keychain-friendly way */
515 crtn
= errSecDuplicateItem
;
520 /* Private and public keys: update Label as public key hash */
521 if((hdr
.KeyClass
!= CSSM_KEYCLASS_SESSION_KEY
) && (dlDbPtr
!= NULL
)) {
522 CSSM_DATA newPrintName
;
524 /* caller specified */
525 newPrintName
.Data
= (uint8
*)printName
;
529 if(hdr
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) {
530 newPrintName
.Data
= (uint8
*)SEC_PRIVKEY_PRINT_NAME_ATTR_VALUE
;
533 newPrintName
.Data
= (uint8
*)SEC_PUBKEY_PRINT_NAME_ATTR_VALUE
;
536 newPrintName
.Length
= strlen((char *)newPrintName
.Data
);
538 crtn
= impExpSetKeyLabel(cspHand
, *dlDbPtr
, &unwrappedKey
,
539 &labelData
, &newPrintName
, keyLabel
);
541 crtn
= impExpSetKeyLabel(cspHand
, *dlDbPtr
, importKeychain
,
542 &unwrappedKey
, &labelData
, &newPrintName
, keyLabel
, &secKeyRef
);
549 /* Private key: adjust ACL as appropriate */
551 SecPointer
<KeychainCore::Access
> theAccess(accessRef
?
552 KeychainCore::Access::required(accessRef
) :
553 new KeychainCore::Access("Imported Private Key"));
555 CssmClient::KeyAclBearer
bearer(cspHand
, unwrappedKey
, Allocator::standard());
556 theAccess
->setAccess(bearer
, maker
);
558 catch (const CssmError
&e
) {
559 /* not implemented means we're talking to the raw CSP which does
560 * not implement ACLs */
561 if(e
.error
!= CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED
) {
566 SecImpExpDbg("keyImport: exception on setAccess\n");
567 crtn
= errSecAuthFailed
; /* ??? */
572 * If importKeychain is non-NULL we've already added the key to the keychain.
573 * If importKeychain is NULL, and outArray is non-NULL, we have to use the
574 * half-baked SecKeyCreateWithCSSMKey to give the caller *something*.
577 if(secKeyRef
== NULL
) {
578 assert(importKeychain
== NULL
);
579 ortn
= SecKeyCreateWithCSSMKey(&unwrappedKey
, &secKeyRef
);
581 SecImpExpDbg("SecKeyCreateWithCSSMKey failure");
585 /* don't CSSM_FreeKey() this key */
586 usedSecKeyCreate
= true;
588 CFArrayAppendValue(outArray
, secKeyRef
);
592 impExpKeyNotify(importKeychain
, keyLabel
.get(), unwrappedKey
);
597 CSSM_DeleteContext(ccHand
);
600 CFRelease(secKeyRef
);
602 if((unwrappedKey
.KeyData
.Data
!= NULL
) && !usedSecKeyCreate
) {
603 /* skip this free if we used SecKeyCreateWithCSSMKey() */
604 CSSM_FreeKey(cspHand
, NULL
, &unwrappedKey
, CSSM_FALSE
);
610 * Common code to wrap a key for export.
612 CSSM_RETURN
impExpExportKeyCommon(
613 CSSM_CSP_HANDLE cspHand
, // for all three keys
615 CSSM_KEY_PTR wrappingKey
,
616 CSSM_KEY_PTR wrappedKey
, // RETURNED
617 CSSM_ALGORITHMS wrapAlg
,
618 CSSM_ENCRYPT_MODE wrapMode
,
619 CSSM_PADDING wrapPad
,
620 CSSM_KEYBLOB_FORMAT wrapFormat
, // NONE, PKCS7, PKCS8, OPENSSL
621 CSSM_ATTRIBUTE_TYPE blobAttrType
, // optional raw key format attr
622 CSSM_KEYBLOB_FORMAT blobForm
, // ditto
623 const CSSM_DATA
*descData
, // optional descriptive data
629 const CSSM_KEY
*unwrappedKey
;
630 ortn
= SecKeyGetCSSMKey(secKey
, &unwrappedKey
);
632 SecImpExpDbg("impExpExportKeyCommon SecKeyGetCSSMKey error");
635 else if(!(unwrappedKey
->KeyHeader
.KeyAttr
& CSSM_KEYATTR_EXTRACTABLE
)) {
636 SecImpExpDbg("impExpExportKeyCommon: CSSM key is non-extractable");
637 return errSecDataNotAvailable
;
641 * Creds needed only for wrapping private keys.
642 * We bother checking in case we ever want to use this to wrap
645 CSSM_ACCESS_CREDENTIALS nullCreds
;
646 memset(&nullCreds
, 0, sizeof(nullCreds
));
647 const CSSM_ACCESS_CREDENTIALS
*creds
= &nullCreds
; // default
649 CSSM_KEYCLASS keyClass
= unwrappedKey
->KeyHeader
.KeyClass
;
650 if(keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) {
651 ortn
= SecKeyGetCredentials(secKey
,
652 CSSM_ACL_AUTHORIZATION_DECRYPT
, // HACK will change!
653 kSecCredentialTypeDefault
,
656 SecImpExpDbg("impExpExportKeyCommon SecKeyGetCredentials error");
661 CSSM_CC_HANDLE ccHand
;
662 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
665 &nullCreds
, // creds for wrapping key, never a private key here
672 SecImpExpDbg("impExpExportKeyCommon CSSM_CSP_CreateSymmetricContext error");
676 /* a couple of optional caller-specified attributes */
677 if(wrapFormat
!= CSSM_KEYBLOB_WRAPPED_FORMAT_NONE
) {
678 crtn
= impExpAddContextAttribute(ccHand
,
679 CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT
,
683 SecImpExpDbg("impExpExportKeyCommon AddContextAttribute error (1)");
684 CSSM_DeleteContext(ccHand
);
689 if(blobAttrType
!= CSSM_ATTRIBUTE_NONE
) {
690 crtn
= impExpAddContextAttribute(ccHand
,
695 SecImpExpDbg("impExpExportKeyCommon AddContextAttribute error");
700 CSSM_DATA dData
= {0, 0};
704 memset(wrappedKey
, 0, sizeof(wrappedKey
));
706 crtn
= CSSM_WrapKey(ccHand
,
711 CSSM_DeleteContext(ccHand
);
715 case CSSMERR_CSP_INVALID_KEYATTR_MASK
:
718 * This is what comes back when we try to wrap an unextractable
719 * key, or when we null wrap a sensitive key. Give the caller
722 CSSM_KEYATTR_FLAGS attr
= unwrappedKey
->KeyHeader
.KeyAttr
;
723 if(!(attr
& CSSM_KEYATTR_EXTRACTABLE
)) {
724 SecImpExpDbg("impExpExportKeyCommon !EXTRACTABLE");
725 return errSecDataNotAvailable
;
727 if((attr
& CSSM_KEYATTR_SENSITIVE
) && (wrappingKey
== NULL
)) {
728 SecImpExpDbg("impExpExportKeyCommon !SENSITIVE, NULL wrap");
729 return errSecPassphraseRequired
;
734 SecImpExpDbg("impExpExportKeyCommon CSSM_WrapKey error");