/ OSX / libsecurity_keychain / lib / SecImportExportCrypto.cpp
SecImportExportCrypto.cpp
  1  /*
  2   * Copyright (c) 2000-2004,2011-2014 Apple 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 <Security/SecImportExport.h>
 29  #include "SecImportExportCrypto.h"
 30  #include "SecImportExportUtils.h"
 31  #include "Keychains.h"
 32  #include "Access.h"
 33  #include "Item.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>
 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;
 94  	switch (cssmKey->KeyHeader.KeyClass) {
 95  		case CSSM_KEYCLASS_PRIVATE_KEY:
 96  			itemClass = kSecPrivateKeyItemClass;
 97  			break;
 98  		case CSSM_KEYCLASS_PUBLIC_KEY:
 99  			itemClass = kSecPublicKeyItemClass;
100  			break;
101  		case CSSM_KEYCLASS_SESSION_KEY:
102  			itemClass = kSecSymmetricKeyItemClass;
103  			break;
104  		default:
105  			itemClass = (SecItemClass) 0;
106  	}
107  	SecKeychainAttribute kcAttr = {kSecKeyLabel, (UInt32)existKeyLabel->Length, existKeyLabel->Data};
108  	SecKeychainAttributeList kcAttrList = {1, &kcAttr};
109  	SecKeychainSearchRef srchRef = NULL;
110  	OSStatus ortn;
111  	SecKeychainItemRef itemRef = NULL;
112  
113  	ortn = SecKeychainSearchCreateFromAttributes(kcRef, itemClass,
114  		&kcAttrList, &srchRef);
115  	if(ortn) {
116  		SecImpExpDbg("SecKeychainSearchCreateFromAttributes error");
117  		crtn = ortn;
118  		goto errOut;
119  	}
120  	ortn = SecKeychainSearchCopyNext(srchRef, &itemRef);
121  	if(ortn) {
122  		SecImpExpDbg("SecKeychainSearchCopyNext error");
123  		crtn = ortn;
124  		goto errOut;
125  	}
126  	#ifndef	NDEBUG
127  	ortn = SecKeychainSearchCopyNext(srchRef, &itemRef);
128  	if(ortn == errSecSuccess) {
129  		SecImpExpDbg("impExpSetKeyLabel: found second key with same label!");
130  		crtn = errSecInternalComponent;
131  		goto errOut;
132  	}
133  	#endif	/* NDEBUG */
134  
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,
146  		0, NULL);
147  	if(ortn) {
148  		SecImpExpDbg("SecKeychainItemModifyAttributesAndData error");
149  		crtn = ortn;
150  		goto errOut;
151  	}
152  	*secKey = (SecKeyRef)itemRef;
153  errOut:
154  	if(keyDigest.Data)  {
155  		/* mallocd by CSP */
156  		impExpFreeCssmMemory(cspHand, keyDigest.Data);
157  	}
158  	if(srchRef) {
159  		CFRelease(srchRef);
160  	}
161  	return crtn;
162  }
163  
164  /*
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.
168   */
169  OSStatus impExpImportRawKey(
170  	CFDataRef						inData,
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
180  {
181  	CSSM_RETURN			crtn;
182  	CSSM_KEY			wrappedKey;
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;
188  
189  	/* First convert external format and types to CSSM style. */
190  	crtn = impExpKeyForm(externForm, itemType, keyAlg, &format, &keyClass);
191  
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);
196  
197  	hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
198  	/* CspId don't care */
199  	hdr.BlobType = CSSM_KEYBLOB_RAW;
200  	hdr.Format = format;
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;
207  
208  	/*
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.
214  	 */
215  	rawCspHand = cuCspStartup(CSSM_TRUE);
216  	if(rawCspHand == 0) {
217  		return CSSMERR_CSSM_ADDIN_LOAD_FAILED;
218  	}
219  	crtn = CSSM_QueryKeySizeInBits(rawCspHand, CSSM_INVALID_HANDLE, &wrappedKey, &keySize);
220  	cuCspDetachUnload(rawCspHand, CSSM_TRUE);
221  	if(crtn) {
222  		SecImpExpDbg("CSSM_QueryKeySizeInBits error");
223  		return crtn;
224  	}
225  	hdr.LogicalKeySizeInBits = keySize.LogicalKeySizeInBits;
226  
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;
233  
234  	return impExpImportKeyCommon(
235  		&wrappedKey,
236  		importKeychain,
237  		cspHand,
238  		flags,
239  		keyParams,
240  		&unwrapParams,
241  		printName,
242  		outArray);
243  }
244  
245  using namespace KeychainCore;
246  
247  /*
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.
251   */
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
256  {
257  	/*
258  	 * Look up key in the DLDB by label, key class, algorithm, and key size.
259  	 */
260  	CSSM_DB_RECORDTYPE recordType;
261  	const CSSM_KEYHEADER &hdr = cssmKey.KeyHeader;
262  
263  	switch(hdr.KeyClass) {
264  		case CSSM_KEYCLASS_PUBLIC_KEY:
265  			recordType = CSSM_DL_DB_RECORD_PUBLIC_KEY;
266  			break;
267  		case CSSM_KEYCLASS_PRIVATE_KEY:
268  			recordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
269  			break;
270  		case CSSM_KEYCLASS_SESSION_KEY:
271  			recordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
272  			break;
273  		default:
274  			return errSecParam;
275  	}
276  	assert(importKeychain != NULL);
277  	Keychain keychain = KeychainImpl::required(importKeychain);
278  
279  	SSDbImpl* impl = dynamic_cast<CssmClient::SSDbImpl *>(&(*keychain->database()));
280  	if (impl == NULL) // did we go bad?
281  	{
282  		CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
283  	}
284  
285  	CssmClient::SSDb ssDb(impl);
286  
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);
294  	CssmClient::Key key;
295  	if (!dbCursor->nextKey(&dbAttributes, key, uniqueId)) {
296  		SecImpExpDbg("impExpKeyNotify: key not found");
297  		return errSecItemNotFound;
298  	}
299  
300  	/*
301  	 * Get a Keychain-style Item, post notification.
302  	 */
303  	Item keyItem = keychain->item(recordType, uniqueId);
304  	keychain->postEvent(kSecAddEvent, keyItem);
305  
306  	return errSecSuccess;
307  }
308  
309  /*
310   * Size of random label string in ASCII chars to facilitate DL lookup.
311   */
312  #define SEC_RANDOM_LABEL_LEN		16
313  
314  #define SEC_KEYATTR_RETURN_MASK		\
315  	(CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_RETURN_NONE)
316  
317  /*
318   * Common code to unwrap a key, used for raw keys (which do a NULL unwrap) and
319   * wrapped keys.
320   */
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
331  {
332  	CSSM_CC_HANDLE		ccHand = 0;
333  	CSSM_RETURN			crtn;
334  	CSSM_DATA			labelData;
335  	CSSM_KEY			unwrappedKey;
336  	CSSM_DL_DB_HANDLE   dlDbHandle;
337  	CSSM_DL_DB_HANDLE   *dlDbPtr = NULL;
338  	OSStatus			ortn;
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;
352  
353  	assert(unwrapParams != NULL);
354  	assert(cspHand != 0);
355  
356  	if(importKeychain) {
357  		ortn = SecKeychainGetDLDBHandle(importKeychain, &dlDbHandle);
358  		if(ortn) {
359  			return ortn;
360  		}
361  		dlDbPtr = &dlDbHandle;
362  	}
363  
364  	memset(&unwrappedKey, 0, sizeof(CSSM_KEY));
365  	memset(&nullCreds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
366  
367  	/* context for unwrap */
368  	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
369  			unwrapParams->encrAlg,
370  			unwrapParams->encrMode,
371  			&nullCreds,
372  			unwrapParams->unwrappingKey,
373  			unwrapParams->iv.Data ? &unwrapParams->iv : NULL,
374  			unwrapParams->encrPad,
375  			0,				// Params
376  			&ccHand);
377  	if(crtn) {
378  		goto errOut;
379  	}
380  	if(dlDbPtr) {
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),
385  			dlDbPtr);
386  		if(crtn) {
387  			SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
388  			goto errOut;
389  		}
390  	}
391  
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));
398          
399  		for(unsigned i=0; i<randBinaryLen; i++) {
400  			sprintf(randAscii, "%02X", randBinary[i]);
401  			randAscii += 2;
402  		}
403  		labelData.Data = randLabel;
404  		labelData.Length = SEC_RANDOM_LABEL_LEN;
405  		/* actual keyLabel value set later */
406  	}
407  	else {
408  		labelData.Data = (uint8 *)SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE;
409  		labelData.Length = strlen(SEC_SESSIONKEY_PRINT_NAME_ATTR_VALUE);
410  		keyLabel.copy(labelData);
411  	}
412  
413  	/*
414  	 * key attr flags and usage. First the defaults.
415  	 */
416  	if(keyParams) {
417  		keyUsage = keyParams->keyUsage;
418  		keyAttributes = keyParams->keyAttributes;
419  	}
420  	if(keyUsage == 0) {
421  		/* default */
422  		keyUsage = CSSM_KEYUSE_ANY;
423  	}
424  	if(keyAttributes == 0) {
425  		/* default */
426  		keyAttributes = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
427  		if(dlDbPtr) {
428  			keyAttributes |= CSSM_KEYATTR_PERMANENT;
429  		}
430  		if(hdr.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY) {
431  			keyAttributes |= (CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE);
432  		}
433  	}
434  	else {
435  		/* caller-supplied; ensure we're generating a reference key */
436  		keyAttributes &= ~SEC_KEYATTR_RETURN_MASK;
437  		keyAttributes |= CSSM_KEYATTR_RETURN_REF;
438  	}
439  
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
444  		)
445  	  ) {
446  		/*
447  		 * Prepare to set up either a default ACL or one provided by caller via
448  		 * keyParams->accessRef.
449  		 */
450  		memset(&rcc, 0, sizeof(rcc));
451  		maker.initialOwner(rcc);
452  		rccPtr = &rcc;
453  	}
454  
455  	/*
456  	 * Additional optional parameters: block size, rounds,
457  	 * effectiveKeySize.
458  	 * WARNING: block size and rounds, used for RC5, have not been tested.
459  	 * OpenSSL, as of Panther ship, did not support RC5 encryption.
460  	 */
461  	if(unwrapParams->effectiveKeySizeInBits != 0) {
462  		assert(unwrapParams->unwrappingKey->KeyHeader.AlgorithmId ==
463  			CSSM_ALGID_RC2);
464  		SecImpExpDbg("impExpImportKeyCommon: setting effectiveKeySizeInBits to %lu",
465  			(unsigned long)unwrapParams->effectiveKeySizeInBits);
466  		crtn = impExpAddContextAttribute(ccHand,
467  			CSSM_ATTRIBUTE_EFFECTIVE_BITS,
468  			sizeof(uint32),
469  			(void *)((size_t) unwrapParams->effectiveKeySizeInBits));
470  		if(crtn) {
471  			SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
472  			goto errOut;
473  		}
474  	}
475  
476  	if(unwrapParams->rounds != 0) {
477  		assert(unwrapParams->unwrappingKey->KeyHeader.AlgorithmId ==
478  			CSSM_ALGID_RC5);
479  		SecImpExpDbg("impExpImportKeyCommon: setting rounds to %lu",
480  			(unsigned long)unwrapParams->rounds);
481  		crtn = impExpAddContextAttribute(ccHand,
482  			CSSM_ATTRIBUTE_ROUNDS,
483  			sizeof(uint32),
484  			(void *)((size_t)unwrapParams->rounds));
485  		if(crtn) {
486  			SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
487  			goto errOut;
488  		}
489  	}
490  
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);
496  			/*
497  			 * With the current CSP this will actually be ignored
498  			 */
499  			crtn = impExpAddContextAttribute(ccHand,
500  				CSSM_ATTRIBUTE_BLOCK_SIZE,
501  				sizeof(uint32),
502  				(void *)((size_t)unwrapParams->blockSizeInBits));
503  			if(crtn) {
504  				SecImpExpDbg("impExpImportKeyCommon: CSSM_UpdateContextAttributes error");
505  				goto errOut;
506  			}
507  		}
508  	}
509  
510  	/* Here we go */
511  	crtn = CSSM_UnwrapKey(ccHand,
512  		NULL,				// public key
513  		(const CSSM_WRAP_KEY *)wrappedKey,
514  		keyUsage,
515  		keyAttributes,
516  		&labelData,
517  		rccPtr,				// CredAndAclEntry
518  		&unwrappedKey,
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;
525  		}
526  		goto errOut;
527  	}
528  
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;
532  		if(printName) {
533  			/* caller specified */
534  			newPrintName.Data = (uint8 *)printName;
535  		}
536  		else {
537  			/* use defaults */
538  			if(hdr.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY) {
539  				newPrintName.Data = (uint8 *)SEC_PRIVKEY_PRINT_NAME_ATTR_VALUE;
540  			}
541  			else {
542  				newPrintName.Data = (uint8 *)SEC_PUBKEY_PRINT_NAME_ATTR_VALUE;
543  			}
544  		}
545  		newPrintName.Length = strlen((char *)newPrintName.Data);
546  		#if old_way
547  		crtn = impExpSetKeyLabel(cspHand, *dlDbPtr, &unwrappedKey,
548  			&labelData, &newPrintName, keyLabel);
549  		#else
550  		crtn = impExpSetKeyLabel(cspHand, *dlDbPtr, importKeychain,
551  			&unwrappedKey, &labelData, &newPrintName, keyLabel, &secKeyRef);
552  		#endif
553  		if(crtn) {
554  			goto errOut;
555  		}
556  	}
557  
558  	/* Private key: adjust ACL as appropriate */
559  	if(rccPtr != NULL) {
560  		SecPointer<KeychainCore::Access> theAccess(accessRef ?
561  			KeychainCore::Access::required(accessRef) :
562  			new KeychainCore::Access("Imported Private Key"));
563  		try {
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);
568              } else {
569                  CssmClient::KeyAclBearer bearer(cspHand, unwrappedKey, Allocator::standard());
570                  theAccess->setAccess(bearer, maker);
571              }
572  		}
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) {
577  				crtn = e.error;
578  			}
579  		}
580  		catch(...) {
581  			SecImpExpDbg("keyImport: exception on setAccess\n");
582  			crtn = errSecAuthFailed;	/* ??? */
583  		}
584  	}
585  
586  	/*
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*.
590  	 */
591  	if(outArray) {
592  		if(secKeyRef == NULL) {
593  			assert(importKeychain == NULL);
594  			ortn = SecKeyCreateWithCSSMKey(&unwrappedKey, &secKeyRef);
595  			if(ortn) {
596  				SecImpExpDbg("SecKeyCreateWithCSSMKey failure");
597  				crtn = ortn;
598  				goto errOut;
599  			}
600  			/* don't CSSM_FreeKey() this key */
601  			usedSecKeyCreate = true;
602  		}
603  		CFArrayAppendValue(outArray, secKeyRef);
604  	}
605  
606  	if(importKeychain) {
607  		impExpKeyNotify(importKeychain, keyLabel.get(), unwrappedKey);
608  	}
609  
610  errOut:
611  	if(ccHand != 0) {
612  		CSSM_DeleteContext(ccHand);
613  	}
614  	if(secKeyRef) {
615  		CFRelease(secKeyRef);
616  	}
617  	if((unwrappedKey.KeyData.Data != NULL) && !usedSecKeyCreate) {
618  		/* skip this free if we used SecKeyCreateWithCSSMKey() */
619  		CSSM_FreeKey(cspHand, NULL, &unwrappedKey, CSSM_FALSE);
620  	}
621  	return crtn;
622  }
623  
624  /*
625   * Common code to wrap a key for export.
626   */
627  CSSM_RETURN impExpExportKeyCommon(
628  	CSSM_CSP_HANDLE		cspHand,		// for all three keys
629  	SecKeyRef			secKey,
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
639  	const CSSM_DATA		*iv)
640  {
641  	OSStatus ortn;
642  	CSSM_RETURN crtn;
643  
644  	const CSSM_KEY *unwrappedKey;
645  	ortn = SecKeyGetCSSMKey(secKey, &unwrappedKey);
646  	if(ortn) {
647  		SecImpExpDbg("impExpExportKeyCommon SecKeyGetCSSMKey error");
648  		return ortn;
649  	}
650  	else if(!(unwrappedKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
651  		SecImpExpDbg("impExpExportKeyCommon: CSSM key is non-extractable");
652  		return errSecDataNotAvailable;
653  	}
654  
655  	/*
656  	 * Creds are needed for wrapping private and session keys.
657  	 */
658  	CSSM_ACCESS_CREDENTIALS	nullCreds;
659  	memset(&nullCreds, 0, sizeof(nullCreds));
660  	const CSSM_ACCESS_CREDENTIALS *creds = &nullCreds;		// default
661  
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,
667  			&creds);
668  		if(ortn) {
669  			SecImpExpDbg("impExpExportKeyCommon SecKeyGetCredentials error");
670  			return ortn;
671  		}
672  	}
673  
674  	CSSM_CC_HANDLE ccHand;
675  	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
676  		wrapAlg,
677  		wrapMode,
678  		&nullCreds,			// creds for wrapping key, never a private key here
679  		wrappingKey,
680  		iv,
681  		wrapPad,
682  		0,					// Params
683  		&ccHand);
684  	if(ortn) {
685  		SecImpExpDbg("impExpExportKeyCommon CSSM_CSP_CreateSymmetricContext error");
686  		return crtn;
687  	}
688  
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,
693  			sizeof(uint32),
694  			(void *)((size_t)wrapFormat));
695  		if(crtn) {
696  			SecImpExpDbg("impExpExportKeyCommon AddContextAttribute error (1)");
697  			CSSM_DeleteContext(ccHand);
698  			return crtn;
699  		}
700  	}
701  
702  	if(blobAttrType != CSSM_ATTRIBUTE_NONE) {
703  		crtn = impExpAddContextAttribute(ccHand,
704  			blobAttrType,
705  			sizeof(uint32),
706  			(void *)((size_t)blobForm));
707  		if(crtn) {
708  			SecImpExpDbg("impExpExportKeyCommon AddContextAttribute error");
709  			return crtn;
710  		}
711  	}
712  
713  	CSSM_DATA dData = {0, 0};
714  	if(descData) {
715  		dData = *descData;
716  	}
717  
718  	crtn = CSSM_WrapKey(ccHand,
719  		creds,
720  		unwrappedKey,
721  		&dData,
722  		wrappedKey);
723  	CSSM_DeleteContext(ccHand);
724  	switch(crtn) {
725  		case CSSM_OK:
726  			break;
727  		case CSSMERR_CSP_INVALID_KEYATTR_MASK:
728  		{
729  			/*
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
732  			 * some useful info.
733  			 */
734  			CSSM_KEYATTR_FLAGS attr = unwrappedKey->KeyHeader.KeyAttr;
735  			if(!(attr & CSSM_KEYATTR_EXTRACTABLE)) {
736  				SecImpExpDbg("impExpExportKeyCommon !EXTRACTABLE");
737  				return errSecDataNotAvailable;
738  			}
739  			if((attr & CSSM_KEYATTR_SENSITIVE) && (wrappingKey == NULL)) {
740  				SecImpExpDbg("impExpExportKeyCommon !SENSITIVE, NULL wrap");
741  				return errSecPassphraseRequired;
742  			}
743  
744  		}
745  		default:
746  			SecImpExpDbg("impExpExportKeyCommon CSSM_WrapKey error");
747  	}
748  	return crtn;
749  }