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 <Security/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_cdsa_client/securestorage.h>
41 #include <security_cdsa_client/dlclient.h>
42 #include <Security/cssmapi.h>
43 #include <security_keychain/KeyItem.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
;
94 switch (cssmKey
->KeyHeader
.KeyClass
) {
95 case CSSM_KEYCLASS_PRIVATE_KEY
:
96 itemClass
= kSecPrivateKeyItemClass
;
98 case CSSM_KEYCLASS_PUBLIC_KEY
:
99 itemClass
= kSecPublicKeyItemClass
;
101 case CSSM_KEYCLASS_SESSION_KEY
:
102 itemClass
= kSecSymmetricKeyItemClass
;
105 itemClass
= (SecItemClass
) 0;
107 SecKeychainAttribute kcAttr
= {kSecKeyLabel
, (UInt32
)existKeyLabel
->Length
, existKeyLabel
->Data
};
108 SecKeychainAttributeList kcAttrList
= {1, &kcAttr
};
109 SecKeychainSearchRef srchRef
= NULL
;
111 SecKeychainItemRef itemRef
= NULL
;
113 ortn
= SecKeychainSearchCreateFromAttributes(kcRef
, itemClass
,
114 &kcAttrList
, &srchRef
);
116 SecImpExpDbg("SecKeychainSearchCreateFromAttributes error");
120 ortn
= SecKeychainSearchCopyNext(srchRef
, &itemRef
);
122 SecImpExpDbg("SecKeychainSearchCopyNext error");
127 ortn
= SecKeychainSearchCopyNext(srchRef
, &itemRef
);
128 if(ortn
== errSecSuccess
) {
129 SecImpExpDbg("impExpSetKeyLabel: found second key with same label!");
130 crtn
= errSecInternalComponent
;
135 /* modify two attributes... */
136 SecKeychainAttribute modAttrs
[2];
137 modAttrs
[0].tag
= kSecKeyLabel
;
138 modAttrs
[0].length
= (UInt32
)keyDigest
.Length
;
139 modAttrs
[0].data
= keyDigest
.Data
;
140 modAttrs
[1].tag
= kSecKeyPrintName
;
141 modAttrs
[1].length
= (UInt32
)newPrintName
->Length
;
142 modAttrs
[1].data
= newPrintName
->Data
;
143 kcAttrList
.count
= 2;
144 kcAttrList
.attr
= modAttrs
;
145 ortn
= SecKeychainItemModifyAttributesAndData(itemRef
, &kcAttrList
,
148 SecImpExpDbg("SecKeychainItemModifyAttributesAndData error");
152 *secKey
= (SecKeyRef
)itemRef
;
156 impExpFreeCssmMemory(cspHand
, keyDigest
.Data
);
165 * Import a raw key. This can be used as a lightweight "guess" evaluator
166 * if a handle to the raw CSP is passed in (with no keychain), or as
167 * the real thing which does full keychain import.
169 OSStatus
impExpImportRawKey(
171 SecExternalFormat externForm
,
172 SecExternalItemType itemType
,
173 CSSM_ALGORITHMS keyAlg
,
174 SecKeychainRef importKeychain
, // optional
175 CSSM_CSP_HANDLE cspHand
, // required
176 SecItemImportExportFlags flags
,
177 const SecKeyImportExportParameters
*keyParams
, // optional
178 const char *printName
, // optional
179 CFMutableArrayRef outArray
) // optional, append here
183 CSSM_KEYHEADER
&hdr
= wrappedKey
.KeyHeader
;
184 CSSM_CSP_HANDLE rawCspHand
= 0;
185 CSSM_KEY_SIZE keySize
;
186 CSSM_KEYBLOB_FORMAT format
;
187 CSSM_KEYCLASS keyClass
;
189 /* First convert external format and types to CSSM style. */
190 crtn
= impExpKeyForm(externForm
, itemType
, keyAlg
, &format
, &keyClass
);
192 /* cook up key to be null-unwrapped */
193 memset(&wrappedKey
, 0, sizeof(CSSM_KEY
));
194 wrappedKey
.KeyData
.Length
= CFDataGetLength(inData
);
195 wrappedKey
.KeyData
.Data
= (uint8
*)CFDataGetBytePtr(inData
);
197 hdr
.HeaderVersion
= CSSM_KEYHEADER_VERSION
;
198 /* CspId don't care */
199 hdr
.BlobType
= CSSM_KEYBLOB_RAW
;
201 hdr
.AlgorithmId
= keyAlg
;
202 hdr
.KeyClass
= keyClass
;
203 /* LogicalKeySizeInBits calculated below */
204 /* attr and usage are for the incoming unwrapped key... */
205 hdr
.KeyAttr
= CSSM_KEYATTR_EXTRACTABLE
;
206 hdr
.KeyUsage
= CSSM_KEYUSE_ANY
;
209 * Get key size in bits from raw CSP. Doing this right now is a good
210 * optimization for the "guessing" case; getting the key size from the
211 * raw CSP involves a full decode on an alg- and format-specific manner.
212 * If we've been given the wrong params, we'll fail right here without
213 * the complication of a full UnwrapKey op.
215 rawCspHand
= cuCspStartup(CSSM_TRUE
);
216 if(rawCspHand
== 0) {
217 return CSSMERR_CSSM_ADDIN_LOAD_FAILED
;
219 crtn
= CSSM_QueryKeySizeInBits(rawCspHand
, CSSM_INVALID_HANDLE
, &wrappedKey
, &keySize
);
220 cuCspDetachUnload(rawCspHand
, CSSM_TRUE
);
222 SecImpExpDbg("CSSM_QueryKeySizeInBits error");
225 hdr
.LogicalKeySizeInBits
= keySize
.LogicalKeySizeInBits
;
227 impExpKeyUnwrapParams unwrapParams
;
228 memset(&unwrapParams
, 0, sizeof(unwrapParams
));
229 unwrapParams
.encrAlg
= CSSM_ALGID_NONE
;
230 unwrapParams
.encrMode
= CSSM_ALGMODE_NONE
;
231 unwrapParams
.unwrappingKey
= NULL
;
232 unwrapParams
.encrPad
= CSSM_PADDING_NONE
;
234 return impExpImportKeyCommon(
245 using namespace KeychainCore
;
248 * Post notification of a "new key added" event.
249 * If you know of another way to do this, other than a dlclient-based lookup of the
250 * existing key in order to get a KeychainCore::Item, by all means have at it.
252 OSStatus
impExpKeyNotify(
253 SecKeychainRef importKeychain
,
254 const CssmData
&keyLabel
, // stored with this, we use it to do a lookup
255 const CSSM_KEY
&cssmKey
) // unwrapped key in CSSM format
258 * Look up key in the DLDB by label, key class, algorithm, and key size.
260 CSSM_DB_RECORDTYPE recordType
;
261 const CSSM_KEYHEADER
&hdr
= cssmKey
.KeyHeader
;
263 switch(hdr
.KeyClass
) {
264 case CSSM_KEYCLASS_PUBLIC_KEY
:
265 recordType
= CSSM_DL_DB_RECORD_PUBLIC_KEY
;
267 case CSSM_KEYCLASS_PRIVATE_KEY
:
268 recordType
= CSSM_DL_DB_RECORD_PRIVATE_KEY
;
270 case CSSM_KEYCLASS_SESSION_KEY
:
271 recordType
= CSSM_DL_DB_RECORD_SYMMETRIC_KEY
;
276 assert(importKeychain
!= NULL
);
277 Keychain keychain
= KeychainImpl::required(importKeychain
);
279 SSDbImpl
* impl
= dynamic_cast<CssmClient::SSDbImpl
*>(&(*keychain
->database()));
280 if (impl
== NULL
) // did we go bad?
282 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
285 CssmClient::SSDb
ssDb(impl
);
287 CssmClient::DbAttributes dbAttributes
;
288 CssmClient::DbUniqueRecord uniqueId
;
289 CssmClient::SSDbCursor
dbCursor(ssDb
, 3); // three attributes
290 dbCursor
->recordType(recordType
);
291 dbCursor
->add(CSSM_DB_EQUAL
, KeySchema::Label
, keyLabel
);
292 dbCursor
->add(CSSM_DB_EQUAL
, KeySchema::KeyType
, hdr
.AlgorithmId
);
293 dbCursor
->add(CSSM_DB_EQUAL
, KeySchema::KeySizeInBits
, hdr
.LogicalKeySizeInBits
);
295 if (!dbCursor
->nextKey(&dbAttributes
, key
, uniqueId
)) {
296 SecImpExpDbg("impExpKeyNotify: key not found");
297 return errSecItemNotFound
;
301 * Get a Keychain-style Item, post notification.
303 Item keyItem
= keychain
->item(recordType
, uniqueId
);
304 keychain
->postEvent(kSecAddEvent
, keyItem
);
306 return errSecSuccess
;
310 * Size of random label string in ASCII chars to facilitate DL lookup.
312 #define SEC_RANDOM_LABEL_LEN 16
314 #define SEC_KEYATTR_RETURN_MASK \
315 (CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_RETURN_NONE)
318 * Common code to unwrap a key, used for raw keys (which do a NULL unwrap) and
321 OSStatus
impExpImportKeyCommon(
322 const CSSM_KEY
*wrappedKey
,
323 SecKeychainRef importKeychain
, // optional
324 CSSM_CSP_HANDLE cspHand
, // required, if importKeychain is
325 // present, must be from there
326 SecItemImportExportFlags flags
,
327 const SecKeyImportExportParameters
*keyParams
, // optional
328 const impExpKeyUnwrapParams
*unwrapParams
,
329 const char *printName
, // optional
330 CFMutableArrayRef outArray
) // optional, append here
332 CSSM_CC_HANDLE ccHand
= 0;
335 CSSM_KEY unwrappedKey
;
336 CSSM_DL_DB_HANDLE dlDbHandle
;
337 CSSM_DL_DB_HANDLE
*dlDbPtr
= NULL
;
339 CSSM_ACCESS_CREDENTIALS nullCreds
;
340 uint8 randLabel
[SEC_RANDOM_LABEL_LEN
+ 1];
341 CSSM_KEYUSE keyUsage
= 0; // default
342 CSSM_KEYATTR_FLAGS keyAttributes
= 0; // default
343 const CSSM_KEYHEADER
&hdr
= wrappedKey
->KeyHeader
;
344 CSSM_DATA descrData
= {0, NULL
};
345 ResourceControlContext rcc
;
346 Security::KeychainCore::Access::Maker maker
;
347 ResourceControlContext
*rccPtr
= NULL
;
348 SecAccessRef accessRef
= keyParams
? keyParams
->accessRef
: NULL
;
349 CssmAutoData
keyLabel(Allocator::standard());
350 SecKeyRef secKeyRef
= NULL
;
351 bool usedSecKeyCreate
= false;
353 assert(unwrapParams
!= NULL
);
354 assert(cspHand
!= 0);
357 ortn
= SecKeychainGetDLDBHandle(importKeychain
, &dlDbHandle
);
361 dlDbPtr
= &dlDbHandle
;
364 memset(&unwrappedKey
, 0, sizeof(CSSM_KEY
));
365 memset(&nullCreds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
367 /* context for unwrap */
368 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
369 unwrapParams
->encrAlg
,
370 unwrapParams
->encrMode
,
372 unwrapParams
->unwrappingKey
,
373 unwrapParams
->iv
.Data
? &unwrapParams
->iv
: NULL
,
374 unwrapParams
->encrPad
,
381 /* Importing to a keychain - add DLDB to context */
382 crtn
= impExpAddContextAttribute(ccHand
,
383 CSSM_ATTRIBUTE_DL_DB_HANDLE
,
384 sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE
),
387 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
392 if((hdr
.KeyClass
!= CSSM_KEYCLASS_SESSION_KEY
) && (dlDbPtr
!= NULL
)) {
393 /* Generate random 16-char label to facilitate DL lookup */
394 char *randAscii
= (char *)randLabel
;
395 uint8 randBinary
[SEC_RANDOM_LABEL_LEN
/ 2];
396 unsigned randBinaryLen
= SEC_RANDOM_LABEL_LEN
/ 2;
397 MacOSError::check(SecRandomCopyBytes(kSecRandomDefault
, randBinaryLen
, randBinary
));
399 for(unsigned i
=0; i
<randBinaryLen
; i
++) {
400 sprintf(randAscii
, "%02X", randBinary
[i
]);
403 labelData
.Data
= randLabel
;
404 labelData
.Length
= SEC_RANDOM_LABEL_LEN
;
405 /* actual keyLabel value set later */
408 labelData
.Data
= (uint8
*)SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE
;
409 labelData
.Length
= strlen(SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE
);
410 keyLabel
.copy(labelData
);
414 * key attr flags and usage. First the defaults.
417 keyUsage
= keyParams
->keyUsage
;
418 keyAttributes
= keyParams
->keyAttributes
;
422 keyUsage
= CSSM_KEYUSE_ANY
;
424 if(keyAttributes
== 0) {
426 keyAttributes
= CSSM_KEYATTR_RETURN_REF
| CSSM_KEYATTR_EXTRACTABLE
;
428 keyAttributes
|= CSSM_KEYATTR_PERMANENT
;
430 if(hdr
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) {
431 keyAttributes
|= (CSSM_KEYATTR_SENSITIVE
| CSSM_KEYATTR_EXTRACTABLE
);
435 /* caller-supplied; ensure we're generating a reference key */
436 keyAttributes
&= ~SEC_KEYATTR_RETURN_MASK
;
437 keyAttributes
|= CSSM_KEYATTR_RETURN_REF
;
440 if( (dlDbPtr
!= NULL
) && // not permanent, no ACL
441 (hdr
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) && // ACLs only for private key
442 ( (keyParams
== NULL
) || // NULL --> default ACL
443 !(keyParams
->flags
& kSecKeyNoAccessControl
) // explicity request no ACL
447 * Prepare to set up either a default ACL or one provided by caller via
448 * keyParams->accessRef.
450 memset(&rcc
, 0, sizeof(rcc
));
451 maker
.initialOwner(rcc
);
456 * Additional optional parameters: block size, rounds,
458 * WARNING: block size and rounds, used for RC5, have not been tested.
459 * OpenSSL, as of Panther ship, did not support RC5 encryption.
461 if(unwrapParams
->effectiveKeySizeInBits
!= 0) {
462 assert(unwrapParams
->unwrappingKey
->KeyHeader
.AlgorithmId
==
464 SecImpExpDbg("impExpImportKeyCommon: setting effectiveKeySizeInBits to %lu",
465 (unsigned long)unwrapParams
->effectiveKeySizeInBits
);
466 crtn
= impExpAddContextAttribute(ccHand
,
467 CSSM_ATTRIBUTE_EFFECTIVE_BITS
,
469 (void *)((size_t) unwrapParams
->effectiveKeySizeInBits
));
471 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
476 if(unwrapParams
->rounds
!= 0) {
477 assert(unwrapParams
->unwrappingKey
->KeyHeader
.AlgorithmId
==
479 SecImpExpDbg("impExpImportKeyCommon: setting rounds to %lu",
480 (unsigned long)unwrapParams
->rounds
);
481 crtn
= impExpAddContextAttribute(ccHand
,
482 CSSM_ATTRIBUTE_ROUNDS
,
484 (void *)((size_t)unwrapParams
->rounds
));
486 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
491 if(unwrapParams
->blockSizeInBits
!= 0) {
492 /* Our RC5 implementation has a fixed block size */
493 if(unwrapParams
->blockSizeInBits
!= 64) {
494 SecImpExpDbg("WARNING impExpImportKeyCommon: setting block size to %lu",
495 (unsigned long)unwrapParams
->blockSizeInBits
);
497 * With the current CSP this will actually be ignored
499 crtn
= impExpAddContextAttribute(ccHand
,
500 CSSM_ATTRIBUTE_BLOCK_SIZE
,
502 (void *)((size_t)unwrapParams
->blockSizeInBits
));
504 SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
511 crtn
= CSSM_UnwrapKey(ccHand
,
513 (const CSSM_WRAP_KEY
*)wrappedKey
,
517 rccPtr
, // CredAndAclEntry
519 &descrData
); // required
520 if(crtn
!= CSSM_OK
) {
521 SecImpExpDbg("CSSM_UnwrapKey failure");
522 if(crtn
== CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA
) {
523 /* report in a keychain-friendly way */
524 crtn
= errSecDuplicateItem
;
529 /* Private and public keys: update Label as public key hash */
530 if((hdr
.KeyClass
!= CSSM_KEYCLASS_SESSION_KEY
) && (dlDbPtr
!= NULL
)) {
531 CSSM_DATA newPrintName
;
533 /* caller specified */
534 newPrintName
.Data
= (uint8
*)printName
;
538 if(hdr
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) {
539 newPrintName
.Data
= (uint8
*)SEC_PRIVKEY_PRINT_NAME_ATTR_VALUE
;
542 newPrintName
.Data
= (uint8
*)SEC_PUBKEY_PRINT_NAME_ATTR_VALUE
;
545 newPrintName
.Length
= strlen((char *)newPrintName
.Data
);
547 crtn
= impExpSetKeyLabel(cspHand
, *dlDbPtr
, &unwrappedKey
,
548 &labelData
, &newPrintName
, keyLabel
);
550 crtn
= impExpSetKeyLabel(cspHand
, *dlDbPtr
, importKeychain
,
551 &unwrappedKey
, &labelData
, &newPrintName
, keyLabel
, &secKeyRef
);
558 /* Private key: adjust ACL as appropriate */
560 SecPointer
<KeychainCore::Access
> theAccess(accessRef
?
561 KeychainCore::Access::required(accessRef
) :
562 new KeychainCore::Access("Imported Private Key"));
564 if(secKeyRef
!= NULL
) {
565 // setAccess using the new secKeyRef, not the old unwrappedKey.
566 // At this point, we might have duplicate keys registered with securityd. Use the newest one.
567 theAccess
->setAccess(*KeyItem::required(secKeyRef
)->key(), maker
);
569 CssmClient::KeyAclBearer
bearer(cspHand
, unwrappedKey
, Allocator::standard());
570 theAccess
->setAccess(bearer
, maker
);
573 catch (const CssmError
&e
) {
574 /* not implemented means we're talking to the raw CSP which does
575 * not implement ACLs */
576 if(e
.error
!= CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED
) {
581 SecImpExpDbg("keyImport: exception on setAccess\n");
582 crtn
= errSecAuthFailed
; /* ??? */
587 * If importKeychain is non-NULL we've already added the key to the keychain.
588 * If importKeychain is NULL, and outArray is non-NULL, we have to use the
589 * half-baked SecKeyCreateWithCSSMKey to give the caller *something*.
592 if(secKeyRef
== NULL
) {
593 assert(importKeychain
== NULL
);
594 ortn
= SecKeyCreateWithCSSMKey(&unwrappedKey
, &secKeyRef
);
596 SecImpExpDbg("SecKeyCreateWithCSSMKey failure");
600 /* don't CSSM_FreeKey() this key */
601 usedSecKeyCreate
= true;
603 CFArrayAppendValue(outArray
, secKeyRef
);
607 impExpKeyNotify(importKeychain
, keyLabel
.get(), unwrappedKey
);
612 CSSM_DeleteContext(ccHand
);
615 CFRelease(secKeyRef
);
617 if((unwrappedKey
.KeyData
.Data
!= NULL
) && !usedSecKeyCreate
) {
618 /* skip this free if we used SecKeyCreateWithCSSMKey() */
619 CSSM_FreeKey(cspHand
, NULL
, &unwrappedKey
, CSSM_FALSE
);
625 * Common code to wrap a key for export.
627 CSSM_RETURN
impExpExportKeyCommon(
628 CSSM_CSP_HANDLE cspHand
, // for all three keys
630 CSSM_KEY_PTR wrappingKey
,
631 CSSM_KEY_PTR wrappedKey
, // RETURNED
632 CSSM_ALGORITHMS wrapAlg
,
633 CSSM_ENCRYPT_MODE wrapMode
,
634 CSSM_PADDING wrapPad
,
635 CSSM_KEYBLOB_FORMAT wrapFormat
, // NONE, PKCS7, PKCS8, OPENSSL
636 CSSM_ATTRIBUTE_TYPE blobAttrType
, // optional raw key format attr
637 CSSM_KEYBLOB_FORMAT blobForm
, // ditto
638 const CSSM_DATA
*descData
, // optional descriptive data
644 const CSSM_KEY
*unwrappedKey
;
645 ortn
= SecKeyGetCSSMKey(secKey
, &unwrappedKey
);
647 SecImpExpDbg("impExpExportKeyCommon SecKeyGetCSSMKey error");
650 else if(!(unwrappedKey
->KeyHeader
.KeyAttr
& CSSM_KEYATTR_EXTRACTABLE
)) {
651 SecImpExpDbg("impExpExportKeyCommon: CSSM key is non-extractable");
652 return errSecDataNotAvailable
;
656 * Creds are needed for wrapping private and session keys.
658 CSSM_ACCESS_CREDENTIALS nullCreds
;
659 memset(&nullCreds
, 0, sizeof(nullCreds
));
660 const CSSM_ACCESS_CREDENTIALS
*creds
= &nullCreds
; // default
662 CSSM_KEYCLASS keyClass
= unwrappedKey
->KeyHeader
.KeyClass
;
663 if(keyClass
== CSSM_KEYCLASS_PRIVATE_KEY
|| keyClass
== CSSM_KEYCLASS_SESSION_KEY
) {
664 ortn
= SecKeyGetCredentials(secKey
,
665 CSSM_ACL_AUTHORIZATION_DECRYPT
,
666 kSecCredentialTypeDefault
,
669 SecImpExpDbg("impExpExportKeyCommon SecKeyGetCredentials error");
674 CSSM_CC_HANDLE ccHand
;
675 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
678 &nullCreds
, // creds for wrapping key, never a private key here
685 SecImpExpDbg("impExpExportKeyCommon CSSM_CSP_CreateSymmetricContext error");
689 /* a couple of optional caller-specified attributes */
690 if(wrapFormat
!= CSSM_KEYBLOB_WRAPPED_FORMAT_NONE
) {
691 crtn
= impExpAddContextAttribute(ccHand
,
692 CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT
,
694 (void *)((size_t)wrapFormat
));
696 SecImpExpDbg("impExpExportKeyCommon AddContextAttribute error (1)");
697 CSSM_DeleteContext(ccHand
);
702 if(blobAttrType
!= CSSM_ATTRIBUTE_NONE
) {
703 crtn
= impExpAddContextAttribute(ccHand
,
706 (void *)((size_t)blobForm
));
708 SecImpExpDbg("impExpExportKeyCommon AddContextAttribute error");
713 CSSM_DATA dData
= {0, 0};
718 crtn
= CSSM_WrapKey(ccHand
,
723 CSSM_DeleteContext(ccHand
);
727 case CSSMERR_CSP_INVALID_KEYATTR_MASK
:
730 * This is what comes back when we try to wrap an unextractable
731 * key, or when we null wrap a sensitive key. Give the caller
734 CSSM_KEYATTR_FLAGS attr
= unwrappedKey
->KeyHeader
.KeyAttr
;
735 if(!(attr
& CSSM_KEYATTR_EXTRACTABLE
)) {
736 SecImpExpDbg("impExpExportKeyCommon !EXTRACTABLE");
737 return errSecDataNotAvailable
;
739 if((attr
& CSSM_KEYATTR_SENSITIVE
) && (wrappingKey
== NULL
)) {
740 SecImpExpDbg("impExpExportKeyCommon !SENSITIVE, NULL wrap");
741 return errSecPassphraseRequired
;
746 SecImpExpDbg("impExpExportKeyCommon CSSM_WrapKey error");