2 * Copyright (c) 2000-2004,2011-2014 Apple 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 <Security/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 <security_keychain/KeyItem.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
;
95 switch (cssmKey
->KeyHeader
.KeyClass
) {
96 case CSSM_KEYCLASS_PRIVATE_KEY
:
97 itemClass
= kSecPrivateKeyItemClass
;
99 case CSSM_KEYCLASS_PUBLIC_KEY
:
100 itemClass
= kSecPublicKeyItemClass
;
102 case CSSM_KEYCLASS_SESSION_KEY
:
103 itemClass
= kSecSymmetricKeyItemClass
;
106 itemClass
= (SecItemClass
) 0;
108 SecKeychainAttribute kcAttr
= {kSecKeyLabel
, (UInt32
)existKeyLabel
->Length
, existKeyLabel
->Data
};
109 SecKeychainAttributeList kcAttrList
= {1, &kcAttr
};
110 SecKeychainSearchRef srchRef
= NULL
;
112 SecKeychainItemRef itemRef
= NULL
;
114 ortn
= SecKeychainSearchCreateFromAttributes(kcRef
, itemClass
,
115 &kcAttrList
, &srchRef
);
117 SecImpExpDbg("SecKeychainSearchCreateFromAttributes error");
121 ortn
= SecKeychainSearchCopyNext(srchRef
, &itemRef
);
123 SecImpExpDbg("SecKeychainSearchCopyNext error");
128 ortn
= SecKeychainSearchCopyNext(srchRef
, &itemRef
);
129 if(ortn
== errSecSuccess
) {
130 SecImpExpDbg("impExpSetKeyLabel: found second key with same label!");
131 crtn
= errSecInternalComponent
;
136 /* modify two attributes... */
137 SecKeychainAttribute modAttrs
[2];
138 modAttrs
[0].tag
= kSecKeyLabel
;
139 modAttrs
[0].length
= (UInt32
)keyDigest
.Length
;
140 modAttrs
[0].data
= keyDigest
.Data
;
141 modAttrs
[1].tag
= kSecKeyPrintName
;
142 modAttrs
[1].length
= (UInt32
)newPrintName
->Length
;
143 modAttrs
[1].data
= newPrintName
->Data
;
144 kcAttrList
.count
= 2;
145 kcAttrList
.attr
= modAttrs
;
146 ortn
= SecKeychainItemModifyAttributesAndData(itemRef
, &kcAttrList
,
149 SecImpExpDbg("SecKeychainItemModifyAttributesAndData error");
153 *secKey
= (SecKeyRef
)itemRef
;
157 impExpFreeCssmMemory(cspHand
, keyDigest
.Data
);
166 * Import a raw key. This can be used as a lightweight "guess" evaluator
167 * if a handle to the raw CSP is passed in (with no keychain), or as
168 * the real thing which does full keychain import.
170 OSStatus
impExpImportRawKey(
172 SecExternalFormat externForm
,
173 SecExternalItemType itemType
,
174 CSSM_ALGORITHMS keyAlg
,
175 SecKeychainRef importKeychain
, // optional
176 CSSM_CSP_HANDLE cspHand
, // required
177 SecItemImportExportFlags flags
,
178 const SecKeyImportExportParameters
*keyParams
, // optional
179 const char *printName
, // optional
180 CFMutableArrayRef outArray
) // optional, append here
184 CSSM_KEYHEADER
&hdr
= wrappedKey
.KeyHeader
;
185 CSSM_CSP_HANDLE rawCspHand
= 0;
186 CSSM_KEY_SIZE keySize
;
187 CSSM_KEYBLOB_FORMAT format
;
188 CSSM_KEYCLASS keyClass
;
190 /* First convert external format and types to CSSM style. */
191 crtn
= impExpKeyForm(externForm
, itemType
, keyAlg
, &format
, &keyClass
);
193 /* cook up key to be null-unwrapped */
194 memset(&wrappedKey
, 0, sizeof(CSSM_KEY
));
195 wrappedKey
.KeyData
.Length
= CFDataGetLength(inData
);
196 wrappedKey
.KeyData
.Data
= (uint8
*)CFDataGetBytePtr(inData
);
198 hdr
.HeaderVersion
= CSSM_KEYHEADER_VERSION
;
199 /* CspId don't care */
200 hdr
.BlobType
= CSSM_KEYBLOB_RAW
;
202 hdr
.AlgorithmId
= keyAlg
;
203 hdr
.KeyClass
= keyClass
;
204 /* LogicalKeySizeInBits calculated below */
205 /* attr and usage are for the incoming unwrapped key... */
206 hdr
.KeyAttr
= CSSM_KEYATTR_EXTRACTABLE
;
207 hdr
.KeyUsage
= CSSM_KEYUSE_ANY
;
210 * Get key size in bits from raw CSP. Doing this right now is a good
211 * optimization for the "guessing" case; getting the key size from the
212 * raw CSP involves a full decode on an alg- and format-specific manner.
213 * If we've been given the wrong params, we'll fail right here without
214 * the complication of a full UnwrapKey op.
216 rawCspHand
= cuCspStartup(CSSM_TRUE
);
217 if(rawCspHand
== 0) {
218 return CSSMERR_CSSM_ADDIN_LOAD_FAILED
;
220 crtn
= CSSM_QueryKeySizeInBits(rawCspHand
, CSSM_INVALID_HANDLE
, &wrappedKey
, &keySize
);
221 cuCspDetachUnload(rawCspHand
, CSSM_TRUE
);
223 SecImpExpDbg("CSSM_QueryKeySizeInBits error");
226 hdr
.LogicalKeySizeInBits
= keySize
.LogicalKeySizeInBits
;
228 impExpKeyUnwrapParams unwrapParams
;
229 memset(&unwrapParams
, 0, sizeof(unwrapParams
));
230 unwrapParams
.encrAlg
= CSSM_ALGID_NONE
;
231 unwrapParams
.encrMode
= CSSM_ALGMODE_NONE
;
232 unwrapParams
.unwrappingKey
= NULL
;
233 unwrapParams
.encrPad
= CSSM_PADDING_NONE
;
235 return impExpImportKeyCommon(
246 using namespace KeychainCore
;
249 * Post notification of a "new key added" event.
250 * If you know of another way to do this, other than a dlclient-based lookup of the
251 * existing key in order to get a KeychainCore::Item, by all means have at it.
253 OSStatus
impExpKeyNotify(
254 SecKeychainRef importKeychain
,
255 const CssmData
&keyLabel
, // stored with this, we use it to do a lookup
256 const CSSM_KEY
&cssmKey
) // unwrapped key in CSSM format
259 * Look up key in the DLDB by label, key class, algorithm, and key size.
261 CSSM_DB_RECORDTYPE recordType
;
262 const CSSM_KEYHEADER
&hdr
= cssmKey
.KeyHeader
;
264 switch(hdr
.KeyClass
) {
265 case CSSM_KEYCLASS_PUBLIC_KEY
:
266 recordType
= CSSM_DL_DB_RECORD_PUBLIC_KEY
;
268 case CSSM_KEYCLASS_PRIVATE_KEY
:
269 recordType
= CSSM_DL_DB_RECORD_PRIVATE_KEY
;
271 case CSSM_KEYCLASS_SESSION_KEY
:
272 recordType
= CSSM_DL_DB_RECORD_SYMMETRIC_KEY
;
277 assert(importKeychain
!= NULL
);
278 Keychain keychain
= KeychainImpl::required(importKeychain
);
280 SSDbImpl
* impl
= dynamic_cast<CssmClient::SSDbImpl
*>(&(*keychain
->database()));
281 if (impl
== NULL
) // did we go bad?
283 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
286 CssmClient::SSDb
ssDb(impl
);
288 CssmClient::DbAttributes dbAttributes
;
289 CssmClient::DbUniqueRecord uniqueId
;
290 CssmClient::SSDbCursor
dbCursor(ssDb
, 3); // three attributes
291 dbCursor
->recordType(recordType
);
292 dbCursor
->add(CSSM_DB_EQUAL
, KeySchema::Label
, keyLabel
);
293 dbCursor
->add(CSSM_DB_EQUAL
, KeySchema::KeyType
, hdr
.AlgorithmId
);
294 dbCursor
->add(CSSM_DB_EQUAL
, KeySchema::KeySizeInBits
, hdr
.LogicalKeySizeInBits
);
296 if (!dbCursor
->nextKey(&dbAttributes
, key
, uniqueId
)) {
297 SecImpExpDbg("impExpKeyNotify: key not found");
298 return errSecItemNotFound
;
302 * Get a Keychain-style Item, post notification.
304 Item keyItem
= keychain
->item(recordType
, uniqueId
);
305 keychain
->postEvent(kSecAddEvent
, keyItem
);
307 return errSecSuccess
;
311 * Size of random label string in ASCII chars to facilitate DL lookup.
313 #define SEC_RANDOM_LABEL_LEN 16
315 #define SEC_KEYATTR_RETURN_MASK \
316 (CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_RETURN_NONE)
319 * Common code to unwrap a key, used for raw keys (which do a NULL unwrap) and
322 OSStatus
impExpImportKeyCommon(
323 const CSSM_KEY
*wrappedKey
,
324 SecKeychainRef importKeychain
, // optional
325 CSSM_CSP_HANDLE cspHand
, // required, if importKeychain is
326 // present, must be from there
327 SecItemImportExportFlags flags
,
328 const SecKeyImportExportParameters
*keyParams
, // optional
329 const impExpKeyUnwrapParams
*unwrapParams
,
330 const char *printName
, // optional
331 CFMutableArrayRef outArray
) // optional, append here
333 CSSM_CC_HANDLE ccHand
= 0;
336 CSSM_KEY unwrappedKey
;
337 CSSM_DL_DB_HANDLE dlDbHandle
;
338 CSSM_DL_DB_HANDLE
*dlDbPtr
= NULL
;
340 CSSM_ACCESS_CREDENTIALS nullCreds
;
341 uint8 randLabel
[SEC_RANDOM_LABEL_LEN
+ 1];
342 CSSM_KEYUSE keyUsage
= 0; // default
343 CSSM_KEYATTR_FLAGS keyAttributes
= 0; // default
344 const CSSM_KEYHEADER
&hdr
= wrappedKey
->KeyHeader
;
345 CSSM_DATA descrData
= {0, NULL
};
346 ResourceControlContext rcc
;
347 Security::KeychainCore::Access::Maker maker
;
348 ResourceControlContext
*rccPtr
= NULL
;
349 SecAccessRef accessRef
= keyParams
? keyParams
->accessRef
: NULL
;
350 CssmAutoData
keyLabel(Allocator::standard());
351 SecKeyRef secKeyRef
= NULL
;
352 bool usedSecKeyCreate
= false;
354 assert(unwrapParams
!= NULL
);
355 assert(cspHand
!= 0);
358 ortn
= SecKeychainGetDLDBHandle(importKeychain
, &dlDbHandle
);
362 dlDbPtr
= &dlDbHandle
;
365 memset(&unwrappedKey
, 0, sizeof(CSSM_KEY
));
366 memset(&nullCreds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
368 /* context for unwrap */
369 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
370 unwrapParams
->encrAlg
,
371 unwrapParams
->encrMode
,
373 unwrapParams
->unwrappingKey
,
374 unwrapParams
->iv
.Data
? &unwrapParams
->iv
: NULL
,
375 unwrapParams
->encrPad
,
382 /* Importing to a keychain - add DLDB to context */
383 crtn
= impExpAddContextAttribute(ccHand
,
384 CSSM_ATTRIBUTE_DL_DB_HANDLE
,
385 sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE
),
388 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
393 if((hdr
.KeyClass
!= CSSM_KEYCLASS_SESSION_KEY
) && (dlDbPtr
!= NULL
)) {
394 /* Generate random 16-char label to facilitate DL lookup */
395 char *randAscii
= (char *)randLabel
;
396 uint8 randBinary
[SEC_RANDOM_LABEL_LEN
/ 2];
397 unsigned randBinaryLen
= SEC_RANDOM_LABEL_LEN
/ 2;
398 DevRandomGenerator rng
;
400 rng
.random(randBinary
, randBinaryLen
);
401 for(unsigned i
=0; i
<randBinaryLen
; i
++) {
402 sprintf(randAscii
, "%02X", randBinary
[i
]);
405 labelData
.Data
= randLabel
;
406 labelData
.Length
= SEC_RANDOM_LABEL_LEN
;
407 /* actual keyLabel value set later */
410 labelData
.Data
= (uint8
*)SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE
;
411 labelData
.Length
= strlen(SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE
);
412 keyLabel
.copy(labelData
);
416 * key attr flags and usage. First the defaults.
419 keyUsage
= keyParams
->keyUsage
;
420 keyAttributes
= keyParams
->keyAttributes
;
424 keyUsage
= CSSM_KEYUSE_ANY
;
426 if(keyAttributes
== 0) {
428 keyAttributes
= CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
;
430 keyAttributes
|= CSSM_KEYATTR_PERMANENT
;
432 if(hdr
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) {
433 keyAttributes
|= (CSSM_KEYATTR_SENSITIVE
| CSSM_KEYATTR_EXTRACTABLE
);
437 /* caller-supplied; ensure we're generating a reference key */
438 keyAttributes
&= ~SEC_KEYATTR_RETURN_MASK
;
439 keyAttributes
|= CSSM_KEYATTR_RETURN_REF
;
442 if( (dlDbPtr
!= NULL
) && // not permanent, no ACL
443 (hdr
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) && // ACLs only for private key
444 ( (keyParams
== NULL
) || // NULL --> default ACL
445 !(keyParams
->flags
& kSecKeyNoAccessControl
) // explicity request no ACL
449 * Prepare to set up either a default ACL or one provided by caller via
450 * keyParams->accessRef.
452 memset(&rcc
, 0, sizeof(rcc
));
453 maker
.initialOwner(rcc
);
458 * Additional optional parameters: block size, rounds,
460 * WARNING: block size and rounds, used for RC5, have not been tested.
461 * OpenSSL, as of Panther ship, did not support RC5 encryption.
463 if(unwrapParams
->effectiveKeySizeInBits
!= 0) {
464 assert(unwrapParams
->unwrappingKey
->KeyHeader
.AlgorithmId
==
466 SecImpExpDbg("impExpImportKeyCommon: setting effectiveKeySizeInBits to %lu",
467 (unsigned long)unwrapParams
->effectiveKeySizeInBits
);
468 crtn
= impExpAddContextAttribute(ccHand
,
469 CSSM_ATTRIBUTE_EFFECTIVE_BITS
,
471 (void *)((size_t) unwrapParams
->effectiveKeySizeInBits
));
473 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
478 if(unwrapParams
->rounds
!= 0) {
479 assert(unwrapParams
->unwrappingKey
->KeyHeader
.AlgorithmId
==
481 SecImpExpDbg("impExpImportKeyCommon: setting rounds to %lu",
482 (unsigned long)unwrapParams
->rounds
);
483 crtn
= impExpAddContextAttribute(ccHand
,
484 CSSM_ATTRIBUTE_ROUNDS
,
486 (void *)((size_t)unwrapParams
->rounds
));
488 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
493 if(unwrapParams
->blockSizeInBits
!= 0) {
494 /* Our RC5 implementation has a fixed block size */
495 if(unwrapParams
->blockSizeInBits
!= 64) {
496 SecImpExpDbg("WARNING impExpImportKeyCommon: setting block size to %lu",
497 (unsigned long)unwrapParams
->blockSizeInBits
);
499 * With the current CSP this will actually be ignored
501 crtn
= impExpAddContextAttribute(ccHand
,
502 CSSM_ATTRIBUTE_BLOCK_SIZE
,
504 (void *)((size_t)unwrapParams
->blockSizeInBits
));
506 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
513 crtn
= CSSM_UnwrapKey(ccHand
,
515 (const CSSM_WRAP_KEY
*)wrappedKey
,
519 rccPtr
, // CredAndAclEntry
521 &descrData
); // required
522 if(crtn
!= CSSM_OK
) {
523 SecImpExpDbg("CSSM_UnwrapKey failure");
524 if(crtn
== CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA
) {
525 /* report in a keychain-friendly way */
526 crtn
= errSecDuplicateItem
;
531 /* Private and public keys: update Label as public key hash */
532 if((hdr
.KeyClass
!= CSSM_KEYCLASS_SESSION_KEY
) && (dlDbPtr
!= NULL
)) {
533 CSSM_DATA newPrintName
;
535 /* caller specified */
536 newPrintName
.Data
= (uint8
*)printName
;
540 if(hdr
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) {
541 newPrintName
.Data
= (uint8
*)SEC_PRIVKEY_PRINT_NAME_ATTR_VALUE
;
544 newPrintName
.Data
= (uint8
*)SEC_PUBKEY_PRINT_NAME_ATTR_VALUE
;
547 newPrintName
.Length
= strlen((char *)newPrintName
.Data
);
549 crtn
= impExpSetKeyLabel(cspHand
, *dlDbPtr
, &unwrappedKey
,
550 &labelData
, &newPrintName
, keyLabel
);
552 crtn
= impExpSetKeyLabel(cspHand
, *dlDbPtr
, importKeychain
,
553 &unwrappedKey
, &labelData
, &newPrintName
, keyLabel
, &secKeyRef
);
560 /* Private key: adjust ACL as appropriate */
562 SecPointer
<KeychainCore::Access
> theAccess(accessRef
?
563 KeychainCore::Access::required(accessRef
) :
564 new KeychainCore::Access("Imported Private Key"));
566 if(secKeyRef
!= NULL
) {
567 // setAccess using the new secKeyRef, not the old unwrappedKey.
568 // At this point, we might have duplicate keys registered with securityd. Use the newest one.
569 theAccess
->setAccess(*KeyItem::required(secKeyRef
)->key(), maker
);
571 CssmClient::KeyAclBearer
bearer(cspHand
, unwrappedKey
, Allocator::standard());
572 theAccess
->setAccess(bearer
, maker
);
575 catch (const CssmError
&e
) {
576 /* not implemented means we're talking to the raw CSP which does
577 * not implement ACLs */
578 if(e
.error
!= CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED
) {
583 SecImpExpDbg("keyImport: exception on setAccess\n");
584 crtn
= errSecAuthFailed
; /* ??? */
589 * If importKeychain is non-NULL we've already added the key to the keychain.
590 * If importKeychain is NULL, and outArray is non-NULL, we have to use the
591 * half-baked SecKeyCreateWithCSSMKey to give the caller *something*.
594 if(secKeyRef
== NULL
) {
595 assert(importKeychain
== NULL
);
596 ortn
= SecKeyCreateWithCSSMKey(&unwrappedKey
, &secKeyRef
);
598 SecImpExpDbg("SecKeyCreateWithCSSMKey failure");
602 /* don't CSSM_FreeKey() this key */
603 usedSecKeyCreate
= true;
605 CFArrayAppendValue(outArray
, secKeyRef
);
609 impExpKeyNotify(importKeychain
, keyLabel
.get(), unwrappedKey
);
614 CSSM_DeleteContext(ccHand
);
617 CFRelease(secKeyRef
);
619 if((unwrappedKey
.KeyData
.Data
!= NULL
) && !usedSecKeyCreate
) {
620 /* skip this free if we used SecKeyCreateWithCSSMKey() */
621 CSSM_FreeKey(cspHand
, NULL
, &unwrappedKey
, CSSM_FALSE
);
627 * Common code to wrap a key for export.
629 CSSM_RETURN
impExpExportKeyCommon(
630 CSSM_CSP_HANDLE cspHand
, // for all three keys
632 CSSM_KEY_PTR wrappingKey
,
633 CSSM_KEY_PTR wrappedKey
, // RETURNED
634 CSSM_ALGORITHMS wrapAlg
,
635 CSSM_ENCRYPT_MODE wrapMode
,
636 CSSM_PADDING wrapPad
,
637 CSSM_KEYBLOB_FORMAT wrapFormat
, // NONE, PKCS7, PKCS8, OPENSSL
638 CSSM_ATTRIBUTE_TYPE blobAttrType
, // optional raw key format attr
639 CSSM_KEYBLOB_FORMAT blobForm
, // ditto
640 const CSSM_DATA
*descData
, // optional descriptive data
646 const CSSM_KEY
*unwrappedKey
;
647 ortn
= SecKeyGetCSSMKey(secKey
, &unwrappedKey
);
649 SecImpExpDbg("impExpExportKeyCommon SecKeyGetCSSMKey error");
652 else if(!(unwrappedKey
->KeyHeader
.KeyAttr
& CSSM_KEYATTR_EXTRACTABLE
)) {
653 SecImpExpDbg("impExpExportKeyCommon: CSSM key is non-extractable");
654 return errSecDataNotAvailable
;
658 * Creds are needed for wrapping private and session keys.
660 CSSM_ACCESS_CREDENTIALS nullCreds
;
661 memset(&nullCreds
, 0, sizeof(nullCreds
));
662 const CSSM_ACCESS_CREDENTIALS
*creds
= &nullCreds
; // default
664 CSSM_KEYCLASS keyClass
= unwrappedKey
->KeyHeader
.KeyClass
;
665 if(keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
|| keyClass
== CSSM_KEYCLASS_SESSION_KEY
) {
666 ortn
= SecKeyGetCredentials(secKey
,
667 CSSM_ACL_AUTHORIZATION_DECRYPT
,
668 kSecCredentialTypeDefault
,
671 SecImpExpDbg("impExpExportKeyCommon SecKeyGetCredentials error");
676 CSSM_CC_HANDLE ccHand
;
677 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
680 &nullCreds
, // creds for wrapping key, never a private key here
687 SecImpExpDbg("impExpExportKeyCommon CSSM_CSP_CreateSymmetricContext error");
691 /* a couple of optional caller-specified attributes */
692 if(wrapFormat
!= CSSM_KEYBLOB_WRAPPED_FORMAT_NONE
) {
693 crtn
= impExpAddContextAttribute(ccHand
,
694 CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT
,
696 (void *)((size_t)wrapFormat
));
698 SecImpExpDbg("impExpExportKeyCommon AddContextAttribute error (1)");
699 CSSM_DeleteContext(ccHand
);
704 if(blobAttrType
!= CSSM_ATTRIBUTE_NONE
) {
705 crtn
= impExpAddContextAttribute(ccHand
,
708 (void *)((size_t)blobForm
));
710 SecImpExpDbg("impExpExportKeyCommon AddContextAttribute error");
715 CSSM_DATA dData
= {0, 0};
720 crtn
= CSSM_WrapKey(ccHand
,
725 CSSM_DeleteContext(ccHand
);
729 case CSSMERR_CSP_INVALID_KEYATTR_MASK
:
732 * This is what comes back when we try to wrap an unextractable
733 * key, or when we null wrap a sensitive key. Give the caller
736 CSSM_KEYATTR_FLAGS attr
= unwrappedKey
->KeyHeader
.KeyAttr
;
737 if(!(attr
& CSSM_KEYATTR_EXTRACTABLE
)) {
738 SecImpExpDbg("impExpExportKeyCommon !EXTRACTABLE");
739 return errSecDataNotAvailable
;
741 if((attr
& CSSM_KEYATTR_SENSITIVE
) && (wrappingKey
== NULL
)) {
742 SecImpExpDbg("impExpExportKeyCommon !SENSITIVE, NULL wrap");
743 return errSecPassphraseRequired
;
748 SecImpExpDbg("impExpExportKeyCommon CSSM_WrapKey error");