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>
46 * Key attrribute names and values.
48 * This is where the public key hash goes.
50 #define SEC_KEY_HASH_ATTR_NAME "Label"
53 * This is where the publicly visible name goes.
55 #define SEC_KEY_PRINT_NAME_ATTR_NAME "PrintName"
58 * Default values we ultimately assign to the PrintName attr.
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"
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.
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
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
82 CSSM_DATA keyDigest
= {0, NULL
};
84 crtn
= impExpKeyDigest(cspHand
, cssmKey
, &keyDigest
);
89 /* caller needs this for subsequent DL lookup */
90 newLabel
.copy(keyDigest
);
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
;
100 SecKeychainItemRef itemRef
= NULL
;
102 ortn
= SecKeychainSearchCreateFromAttributes(kcRef
, itemClass
,
103 &kcAttrList
, &srchRef
);
105 SecImpExpDbg("SecKeychainSearchCreateFromAttributes error");
109 ortn
= SecKeychainSearchCopyNext(srchRef
, &itemRef
);
111 SecImpExpDbg("SecKeychainSearchCopyNext error");
116 ortn
= SecKeychainSearchCopyNext(srchRef
, &itemRef
);
117 if(ortn
== errSecSuccess
) {
118 SecImpExpDbg("impExpSetKeyLabel: found second key with same label!");
119 crtn
= errSecInternalComponent
;
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
,
137 SecImpExpDbg("SecKeychainItemModifyAttributesAndData error");
141 *secKey
= (SecKeyRef
)itemRef
;
145 impExpFreeCssmMemory(cspHand
, keyDigest
.Data
);
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.
158 OSStatus
impExpImportRawKey(
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
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
;
178 /* First convert external format and types to CSSM style. */
179 crtn
= impExpKeyForm(externForm
, itemType
, keyAlg
, &format
, &keyClass
);
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
);
186 hdr
.HeaderVersion
= CSSM_KEYHEADER_VERSION
;
187 /* CspId don't care */
188 hdr
.BlobType
= CSSM_KEYBLOB_RAW
;
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
;
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.
204 rawCspHand
= cuCspStartup(CSSM_TRUE
);
205 if(rawCspHand
== 0) {
206 return CSSMERR_CSSM_ADDIN_LOAD_FAILED
;
208 crtn
= CSSM_QueryKeySizeInBits(rawCspHand
, CSSM_INVALID_HANDLE
, &wrappedKey
, &keySize
);
209 cuCspDetachUnload(rawCspHand
, CSSM_TRUE
);
211 SecImpExpDbg("CSSM_QueryKeySizeInBits error");
214 hdr
.LogicalKeySizeInBits
= keySize
.LogicalKeySizeInBits
;
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
;
223 return impExpImportKeyCommon(
234 using namespace KeychainCore
;
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.
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
247 * Look up key in the DLDB by label, key class, algorithm, and key size.
249 CSSM_DB_RECORDTYPE recordType
;
250 const CSSM_KEYHEADER
&hdr
= cssmKey
.KeyHeader
;
252 switch(hdr
.KeyClass
) {
253 case CSSM_KEYCLASS_PUBLIC_KEY
:
254 recordType
= CSSM_DL_DB_RECORD_PUBLIC_KEY
;
256 case CSSM_KEYCLASS_PRIVATE_KEY
:
257 recordType
= CSSM_DL_DB_RECORD_PRIVATE_KEY
;
259 case CSSM_KEYCLASS_SESSION_KEY
:
260 recordType
= CSSM_DL_DB_RECORD_SYMMETRIC_KEY
;
265 assert(importKeychain
!= NULL
);
266 Keychain keychain
= KeychainImpl::required(importKeychain
);
268 SSDbImpl
* impl
= dynamic_cast<CssmClient::SSDbImpl
*>(&(*keychain
->database()));
269 if (impl
== NULL
) // did we go bad?
271 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
274 CssmClient::SSDb
ssDb(impl
);
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
);
284 if (!dbCursor
->nextKey(&dbAttributes
, key
, uniqueId
)) {
285 SecImpExpDbg("impExpKeyNotify: key not found");
286 return errSecItemNotFound
;
290 * Get a Keychain-style Item, post notification.
292 Item keyItem
= keychain
->item(recordType
, uniqueId
);
293 keychain
->postEvent(kSecAddEvent
, keyItem
);
295 return errSecSuccess
;
299 * Size of random label string in ASCII chars to facilitate DL lookup.
301 #define SEC_RANDOM_LABEL_LEN 16
303 #define SEC_KEYATTR_RETURN_MASK \
304 (CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_RETURN_NONE)
307 * Common code to unwrap a key, used for raw keys (which do a NULL unwrap) and
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
321 CSSM_CC_HANDLE ccHand
= 0;
324 CSSM_KEY unwrappedKey
;
325 CSSM_DL_DB_HANDLE dlDbHandle
;
326 CSSM_DL_DB_HANDLE
*dlDbPtr
= NULL
;
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;
342 assert(unwrapParams
!= NULL
);
343 assert(cspHand
!= 0);
346 ortn
= SecKeychainGetDLDBHandle(importKeychain
, &dlDbHandle
);
350 dlDbPtr
= &dlDbHandle
;
353 memset(&unwrappedKey
, 0, sizeof(CSSM_KEY
));
354 memset(&nullCreds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
356 /* context for unwrap */
357 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
358 unwrapParams
->encrAlg
,
359 unwrapParams
->encrMode
,
361 unwrapParams
->unwrappingKey
,
362 unwrapParams
->iv
.Data
? &unwrapParams
->iv
: NULL
,
363 unwrapParams
->encrPad
,
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
),
376 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
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
;
388 rng
.random(randBinary
, randBinaryLen
);
389 for(unsigned i
=0; i
<randBinaryLen
; i
++) {
390 sprintf(randAscii
, "%02X", randBinary
[i
]);
393 labelData
.Data
= randLabel
;
394 labelData
.Length
= SEC_RANDOM_LABEL_LEN
;
395 /* actual keyLabel value set later */
398 labelData
.Data
= (uint8
*)SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE
;
399 labelData
.Length
= strlen(SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE
);
400 keyLabel
.copy(labelData
);
404 * key attr flags and usage. First the defaults.
407 keyUsage
= keyParams
->keyUsage
;
408 keyAttributes
= keyParams
->keyAttributes
;
412 keyUsage
= CSSM_KEYUSE_ANY
;
414 if(keyAttributes
== 0) {
416 keyAttributes
= CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
;
418 keyAttributes
|= CSSM_KEYATTR_PERMANENT
;
420 if(hdr
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) {
421 keyAttributes
|= (CSSM_KEYATTR_SENSITIVE
| CSSM_KEYATTR_EXTRACTABLE
);
425 /* caller-supplied; ensure we're generating a reference key */
426 keyAttributes
&= ~SEC_KEYATTR_RETURN_MASK
;
427 keyAttributes
|= CSSM_KEYATTR_RETURN_REF
;
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
437 * Prepare to set up either a default ACL or one provided by caller via
438 * keyParams->accessRef.
440 memset(&rcc
, 0, sizeof(rcc
));
441 maker
.initialOwner(rcc
);
446 * Additional optional parameters: block size, rounds,
448 * WARNING: block size and rounds, used for RC5, have not been tested.
449 * OpenSSL, as of Panther ship, did not support RC5 encryption.
451 if(unwrapParams
->effectiveKeySizeInBits
!= 0) {
452 assert(unwrapParams
->unwrappingKey
->KeyHeader
.AlgorithmId
==
454 SecImpExpDbg("impExpImportKeyCommon: setting effectiveKeySizeInBits to %lu",
455 (unsigned long)unwrapParams
->effectiveKeySizeInBits
);
456 crtn
= impExpAddContextAttribute(ccHand
,
457 CSSM_ATTRIBUTE_EFFECTIVE_BITS
,
459 (void *)((size_t) unwrapParams
->effectiveKeySizeInBits
));
461 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
466 if(unwrapParams
->rounds
!= 0) {
467 assert(unwrapParams
->unwrappingKey
->KeyHeader
.AlgorithmId
==
469 SecImpExpDbg("impExpImportKeyCommon: setting rounds to %lu",
470 (unsigned long)unwrapParams
->rounds
);
471 crtn
= impExpAddContextAttribute(ccHand
,
472 CSSM_ATTRIBUTE_ROUNDS
,
474 (void *)((size_t)unwrapParams
->rounds
));
476 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
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
);
487 * With the current CSP this will actually be ignored
489 crtn
= impExpAddContextAttribute(ccHand
,
490 CSSM_ATTRIBUTE_BLOCK_SIZE
,
492 (void *)((size_t)unwrapParams
->blockSizeInBits
));
494 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
501 crtn
= CSSM_UnwrapKey(ccHand
,
503 (const CSSM_WRAP_KEY
*)wrappedKey
,
507 rccPtr
, // CredAndAclEntry
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
;
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
;
523 /* caller specified */
524 newPrintName
.Data
= (uint8
*)printName
;
528 if(hdr
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) {
529 newPrintName
.Data
= (uint8
*)SEC_PRIVKEY_PRINT_NAME_ATTR_VALUE
;
532 newPrintName
.Data
= (uint8
*)SEC_PUBKEY_PRINT_NAME_ATTR_VALUE
;
535 newPrintName
.Length
= strlen((char *)newPrintName
.Data
);
537 crtn
= impExpSetKeyLabel(cspHand
, *dlDbPtr
, &unwrappedKey
,
538 &labelData
, &newPrintName
, keyLabel
);
540 crtn
= impExpSetKeyLabel(cspHand
, *dlDbPtr
, importKeychain
,
541 &unwrappedKey
, &labelData
, &newPrintName
, keyLabel
, &secKeyRef
);
548 /* Private key: adjust ACL as appropriate */
550 SecPointer
<KeychainCore::Access
> theAccess(accessRef
?
551 KeychainCore::Access::required(accessRef
) :
552 new KeychainCore::Access("Imported Private Key"));
554 CssmClient::KeyAclBearer
bearer(cspHand
, unwrappedKey
, Allocator::standard());
555 theAccess
->setAccess(bearer
, maker
);
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
) {
565 SecImpExpDbg("keyImport: exception on setAccess\n");
566 crtn
= errSecAuthFailed
; /* ??? */
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*.
576 if(secKeyRef
== NULL
) {
577 assert(importKeychain
== NULL
);
578 ortn
= SecKeyCreateWithCSSMKey(&unwrappedKey
, &secKeyRef
);
580 SecImpExpDbg("SecKeyCreateWithCSSMKey failure");
584 /* don't CSSM_FreeKey() this key */
585 usedSecKeyCreate
= true;
587 CFArrayAppendValue(outArray
, secKeyRef
);
591 impExpKeyNotify(importKeychain
, keyLabel
.get(), unwrappedKey
);
596 CSSM_DeleteContext(ccHand
);
599 CFRelease(secKeyRef
);
601 if((unwrappedKey
.KeyData
.Data
!= NULL
) && !usedSecKeyCreate
) {
602 /* skip this free if we used SecKeyCreateWithCSSMKey() */
603 CSSM_FreeKey(cspHand
, NULL
, &unwrappedKey
, CSSM_FALSE
);
609 * Common code to wrap a key for export.
611 CSSM_RETURN
impExpExportKeyCommon(
612 CSSM_CSP_HANDLE cspHand
, // for all three keys
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
628 const CSSM_KEY
*unwrappedKey
;
629 ortn
= SecKeyGetCSSMKey(secKey
, &unwrappedKey
);
631 SecImpExpDbg("impExpExportKeyCommon SecKeyGetCSSMKey error");
634 else if(!(unwrappedKey
->KeyHeader
.KeyAttr
& CSSM_KEYATTR_EXTRACTABLE
)) {
635 SecImpExpDbg("impExpExportKeyCommon: CSSM key is non-extractable");
636 return errSecDataNotAvailable
;
640 * Creds needed only for wrapping private keys.
641 * We bother checking in case we ever want to use this to wrap
644 CSSM_ACCESS_CREDENTIALS nullCreds
;
645 memset(&nullCreds
, 0, sizeof(nullCreds
));
646 const CSSM_ACCESS_CREDENTIALS
*creds
= &nullCreds
; // default
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
,
655 SecImpExpDbg("impExpExportKeyCommon SecKeyGetCredentials error");
660 CSSM_CC_HANDLE ccHand
;
661 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
664 &nullCreds
, // creds for wrapping key, never a private key here
671 SecImpExpDbg("impExpExportKeyCommon CSSM_CSP_CreateSymmetricContext error");
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
,
680 (void *)((size_t)wrapFormat
));
682 SecImpExpDbg("impExpExportKeyCommon AddContextAttribute error (1)");
683 CSSM_DeleteContext(ccHand
);
688 if(blobAttrType
!= CSSM_ATTRIBUTE_NONE
) {
689 crtn
= impExpAddContextAttribute(ccHand
,
692 (void *)((size_t)blobForm
));
694 SecImpExpDbg("impExpExportKeyCommon AddContextAttribute error");
699 CSSM_DATA dData
= {0, 0};
704 crtn
= CSSM_WrapKey(ccHand
,
709 CSSM_DeleteContext(ccHand
);
713 case CSSMERR_CSP_INVALID_KEYATTR_MASK
:
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
720 CSSM_KEYATTR_FLAGS attr
= unwrappedKey
->KeyHeader
.KeyAttr
;
721 if(!(attr
& CSSM_KEYATTR_EXTRACTABLE
)) {
722 SecImpExpDbg("impExpExportKeyCommon !EXTRACTABLE");
723 return errSecDataNotAvailable
;
725 if((attr
& CSSM_KEYATTR_SENSITIVE
) && (wrappingKey
== NULL
)) {
726 SecImpExpDbg("impExpExportKeyCommon !SENSITIVE, NULL wrap");
727 return errSecPassphraseRequired
;
732 SecImpExpDbg("impExpExportKeyCommon CSSM_WrapKey error");