1/*
2 * Copyright (c) 2003-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/*
25 * pkc12Crypto.cpp - PKCS12-specific cyptrographic routines
26 */
27
28#include "pkcs12Crypto.h"
29#include "pkcs12Utils.h"
30#include "pkcs12Debug.h"
31#include <security_cdsa_utils/cuCdsaUtils.h>
32#include <security_cdsa_utilities/cssmacl.h>
33#include <security_keychain/Access.h>
34
35/*
36 * Given appropriate P12-style parameters, cook up a CSSM_KEY.
37 * Caller MUST CSSM_FreeKey() when it's done with the key.
38 */
39#define KEY_LABEL	"p12 key"
40
41CSSM_RETURN p12KeyGen(
42	CSSM_CSP_HANDLE		cspHand,
43	CSSM_KEY			&key,
44	bool				isForEncr,	// true: en/decrypt   false: MAC
45	CSSM_ALGORITHMS		keyAlg,
46	CSSM_ALGORITHMS		pbeHashAlg,	// actually must be SHA1 for now
47	uint32				keySizeInBits,
48	uint32				iterCount,
49	const CSSM_DATA		&salt,
50	/* exactly one of the following two must be valid */
51	const CSSM_DATA		*pwd,		// unicode external representation
52	const CSSM_KEY		*passKey,
53	CSSM_DATA			&iv)		// referent is optional
54{
55	CSSM_RETURN					crtn;
56	CSSM_CC_HANDLE 				ccHand;
57	CSSM_DATA					dummyLabel;
58	CSSM_ACCESS_CREDENTIALS		creds;
59
60	memset(&key, 0, sizeof(CSSM_KEY));
61	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
62
63	/* infer key derivation algorithm */
64	CSSM_ALGORITHMS deriveAlg = CSSM_ALGID_NONE;
65	if(pbeHashAlg != CSSM_ALGID_SHA1) {
66		return CSSMERR_CSP_INVALID_ALGORITHM;
67	}
68	if(isForEncr) {
69		/*
70		 * FIXME - if this key is going to be used to wrap/unwrap a
71		 * shrouded key bag, its usage will change accordingly...
72		 */
73		deriveAlg = CSSM_ALGID_PKCS12_PBE_ENCR;
74	}
75	else {
76		deriveAlg = CSSM_ALGID_PKCS12_PBE_MAC;
77	}
78	CSSM_CRYPTO_DATA seed;
79	if(pwd) {
80		seed.Param = *pwd;
81	}
82	else {
83		seed.Param.Data = NULL;
84		seed.Param.Length = 0;
85	}
86	seed.Callback = NULL;
87	seed.CallerCtx = NULL;
88
89	crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
90		deriveAlg,
91		keyAlg,
92		keySizeInBits,
93		&creds,
94		passKey,		// BaseKey
95		iterCount,
96		&salt,
97		&seed,			// seed
98		&ccHand);
99	if(crtn) {
100		p12LogCssmError("CSSM_CSP_CreateDeriveKeyContext", crtn);
101		return crtn;
102	}
103
104	dummyLabel.Length = strlen(KEY_LABEL);
105	dummyLabel.Data = (uint8 *)KEY_LABEL;
106
107	/* KEYUSE_ANY - this is just an ephemeral session key */
108	crtn = CSSM_DeriveKey(ccHand,
109		&iv,
110		CSSM_KEYUSE_ANY,
111		CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE,
112		&dummyLabel,
113		NULL,			// cred and acl
114		&key);
115	CSSM_DeleteContext(ccHand);
116	if(crtn) {
117		p12LogCssmError("CSSM_DeriveKey", crtn);
118	}
119	return crtn;
120}
121
122/*
123 * Decrypt (typically, an encrypted P7 ContentInfo contents)
124 */
125CSSM_RETURN p12Decrypt(
126	CSSM_CSP_HANDLE		cspHand,
127	const CSSM_DATA		&cipherText,
128	CSSM_ALGORITHMS		keyAlg,
129	CSSM_ALGORITHMS		encrAlg,
130	CSSM_ALGORITHMS		pbeHashAlg,			// SHA1, MD5 only
131	uint32				keySizeInBits,
132	uint32				blockSizeInBytes,	// for IV
133	CSSM_PADDING		padding,			// CSSM_PADDING_PKCS7, etc.
134	CSSM_ENCRYPT_MODE	mode,				// CSSM_ALGMODE_CBCPadIV8, etc.
135	uint32				iterCount,
136	const CSSM_DATA		&salt,
137	/* exactly one of the following two must be valid */
138	const CSSM_DATA		*pwd,		// unicode external representation
139	const CSSM_KEY		*passKey,
140	SecNssCoder			&coder,		// for mallocing plainText
141	CSSM_DATA			&plainText)
142{
143	CSSM_RETURN crtn;
144	CSSM_KEY ckey;
145	CSSM_CC_HANDLE ccHand = 0;
146	CSSM_DATA ourPtext = {0, NULL};
147	CSSM_DATA remData = {0, NULL};
148
149	/* P12 style IV derivation, optional */
150	CSSM_DATA iv = {0, NULL};
151	CSSM_DATA_PTR ivPtr = NULL;
152	if(blockSizeInBytes) {
153		coder.allocItem(iv, blockSizeInBytes);
154		ivPtr = &iv;
155	}
156
157	/* P12 style key derivation */
158	crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg,
159		keySizeInBits, iterCount, salt, pwd, passKey, iv);
160	if(crtn) {
161		return crtn;
162	}
163	/* subsequent errors to errOut: */
164
165	/* CSSM context */
166	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
167		encrAlg,
168		mode,
169		NULL,			// access cred
170		&ckey,
171		ivPtr,			// InitVector, optional
172		padding,
173		NULL,			// Params
174		&ccHand);
175	if(crtn) {
176		cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn);
177		goto errOut;
178	}
179
180	/* go - CSP mallocs ptext and rem data */
181	CSSM_SIZE bytesDecrypted;
182	crtn = CSSM_DecryptData(ccHand,
183		&cipherText,
184		1,
185		&ourPtext,
186		1,
187		&bytesDecrypted,
188		&remData);
189	if(crtn) {
190		cuPrintError("CSSM_DecryptData", crtn);
191	}
192	else {
193		coder.allocCopyItem(ourPtext, plainText);
194		plainText.Length = bytesDecrypted;
195
196		/* plaintext copied into coder space; free the memory allocated
197		 * by the CSP */
198		freeCssmMemory(cspHand, ourPtext.Data);
199	}
200	/* an artifact of CSPFullPLuginSession - this never contains
201	 * valid data but sometimes gets mallocds */
202	if(remData.Data) {
203		freeCssmMemory(cspHand, remData.Data);
204	}
205errOut:
206	if(ccHand) {
207		CSSM_DeleteContext(ccHand);
208	}
209	CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE);
210	return crtn;
211}
212
213/*
214 * Decrypt (typically, an encrypted P7 ContentInfo contents)
215 */
216CSSM_RETURN p12Encrypt(
217	CSSM_CSP_HANDLE		cspHand,
218	const CSSM_DATA		&plainText,
219	CSSM_ALGORITHMS		keyAlg,
220	CSSM_ALGORITHMS		encrAlg,
221	CSSM_ALGORITHMS		pbeHashAlg,			// SHA1, MD5 only
222	uint32				keySizeInBits,
223	uint32				blockSizeInBytes,	// for IV
224	CSSM_PADDING		padding,			// CSSM_PADDING_PKCS7, etc.
225	CSSM_ENCRYPT_MODE	mode,				// CSSM_ALGMODE_CBCPadIV8, etc.
226	uint32				iterCount,
227	const CSSM_DATA		&salt,
228	/* exactly one of the following two must be valid */
229	const CSSM_DATA		*pwd,		// unicode external representation
230	const CSSM_KEY		*passKey,
231	SecNssCoder			&coder,		// for mallocing cipherText
232	CSSM_DATA			&cipherText)
233{
234	CSSM_RETURN crtn;
235	CSSM_KEY ckey;
236	CSSM_CC_HANDLE ccHand = 0;
237	CSSM_DATA ourCtext = {0, NULL};
238	CSSM_DATA remData = {0, NULL};
239
240	/* P12 style IV derivation, optional */
241	CSSM_DATA iv = {0, NULL};
242	CSSM_DATA_PTR ivPtr = NULL;
243	if(blockSizeInBytes) {
244		coder.allocItem(iv, blockSizeInBytes);
245		ivPtr = &iv;
246	}
247
248	/* P12 style key derivation */
249	crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg,
250		keySizeInBits, iterCount, salt, pwd, passKey, iv);
251	if(crtn) {
252		return crtn;
253	}
254	/* subsequent errors to errOut: */
255
256	/* CSSM context */
257	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
258		encrAlg,
259		mode,
260		NULL,			// access cred
261		&ckey,
262		ivPtr,			// InitVector, optional
263		padding,
264		NULL,			// Params
265		&ccHand);
266	if(crtn) {
267		cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn);
268		goto errOut;
269	}
270
271	/* go - CSP mallocs ctext and rem data */
272	CSSM_SIZE bytesEncrypted;
273	crtn = CSSM_EncryptData(ccHand,
274		&plainText,
275		1,
276		&ourCtext,
277		1,
278		&bytesEncrypted,
279		&remData);
280	if(crtn) {
281		cuPrintError("CSSM_DecryptData", crtn);
282	}
283	else {
284		coder.allocCopyItem(ourCtext, cipherText);
285		cipherText.Length = bytesEncrypted;
286
287		/* plaintext copied into coder space; free the memory allocated
288		 * by the CSP */
289		freeCssmMemory(cspHand, ourCtext.Data);
290	}
291	/* an artifact of CSPFUllPLuginSession - this never contains
292	 * valid data but sometimes gets mallocds */
293	if(remData.Data) {
294		freeCssmMemory(cspHand, remData.Data);
295	}
296errOut:
297	if(ccHand) {
298		CSSM_DeleteContext(ccHand);
299	}
300	CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE);
301	return crtn;
302}
303
304/*
305 * Calculate the MAC for a PFX. Caller is either going compare
306 * the result against an existing PFX's MAC or drop the result into
307 * a newly created PFX.
308 */
309CSSM_RETURN p12GenMac(
310	CSSM_CSP_HANDLE		cspHand,
311	const CSSM_DATA		&ptext,	// e.g., NSS_P12_DecodedPFX.derAuthSaafe
312	CSSM_ALGORITHMS		alg,	// better be SHA1!
313	unsigned			iterCount,
314	const CSSM_DATA		&salt,
315	/* exactly one of the following two must be valid */
316	const CSSM_DATA		*pwd,		// unicode external representation
317	const CSSM_KEY		*passKey,
318	SecNssCoder			&coder,		// for mallocing macData
319	CSSM_DATA			&macData)	// RETURNED
320{
321	CSSM_RETURN crtn;
322	CSSM_CC_HANDLE ccHand = 0;
323
324	/* P12 style key derivation */
325	unsigned keySizeInBits;
326	CSSM_ALGORITHMS hmacAlg;
327	switch(alg) {
328		case CSSM_ALGID_SHA1:
329			keySizeInBits = 160;
330			hmacAlg = CSSM_ALGID_SHA1HMAC;
331			break;
332		case CSSM_ALGID_MD5:
333			/* not even sure if this is legal in p12 world... */
334			keySizeInBits = 128;
335			hmacAlg = CSSM_ALGID_MD5HMAC;
336			break;
337		default:
338			return CSSMERR_CSP_INVALID_ALGORITHM;
339	}
340	CSSM_KEY macKey;
341	CSSM_DATA iv = {0, NULL};
342	crtn = p12KeyGen(cspHand, macKey, false, hmacAlg, alg,
343		keySizeInBits, iterCount, salt, pwd, passKey, iv);
344	if(crtn) {
345		return crtn;
346	}
347	/* subsequent errors to errOut: */
348
349	/* prealloc the mac data */
350	coder.allocItem(macData, keySizeInBits / 8);
351	crtn = CSSM_CSP_CreateMacContext(cspHand, hmacAlg, &macKey, &ccHand);
352	if(crtn) {
353		cuPrintError("CSSM_CSP_CreateMacContext", crtn);
354		goto errOut;
355	}
356
357	crtn = CSSM_GenerateMac (ccHand, &ptext, 1, &macData);
358	if(crtn) {
359		cuPrintError("CSSM_GenerateMac", crtn);
360	}
361errOut:
362	if(ccHand) {
363		CSSM_DeleteContext(ccHand);
364	}
365	CSSM_FreeKey(cspHand, NULL, &macKey, CSSM_FALSE);
366	return crtn;
367}
368
369/*
370 * Unwrap a shrouded key.
371 */
372CSSM_RETURN p12UnwrapKey(
373	CSSM_CSP_HANDLE		cspHand,
374	CSSM_DL_DB_HANDLE_PTR	dlDbHand,		// optional
375	int					keyIsPermanent,		// nonzero - store in DB
376	const CSSM_DATA		&shroudedKeyBits,
377	CSSM_ALGORITHMS		keyAlg,				// of the unwrapping key
378	CSSM_ALGORITHMS		encrAlg,
379	CSSM_ALGORITHMS		pbeHashAlg,			// SHA1, MD5 only
380	uint32				keySizeInBits,
381	uint32				blockSizeInBytes,	// for IV
382	CSSM_PADDING		padding,			// CSSM_PADDING_PKCS7, etc.
383	CSSM_ENCRYPT_MODE	mode,				// CSSM_ALGMODE_CBCPadIV8, etc.
384	uint32				iterCount,
385	const CSSM_DATA		&salt,
386	const CSSM_DATA		*pwd,		// unicode external representation
387	const CSSM_KEY		*passKey,
388	SecNssCoder			&coder,		// for mallocing privKey
389	const CSSM_DATA		&labelData,
390	SecAccessRef		access,		// optional
391	bool				noAcl,
392	CSSM_KEYUSE			keyUsage,
393	CSSM_KEYATTR_FLAGS	keyAttrs,
394
395	/*
396	 * Result: a private key, reference format, optionaly stored
397	 * in dlDbHand
398	 */
399	CSSM_KEY_PTR		&privKey)
400{
401	CSSM_RETURN crtn;
402	CSSM_KEY ckey;
403	CSSM_CC_HANDLE ccHand = 0;
404	CSSM_KEY wrappedKey;
405	CSSM_KEY unwrappedKey;
406	CSSM_KEYHEADER &hdr = wrappedKey.KeyHeader;
407	CSSM_DATA descrData = {0, NULL};	// not used for PKCS8 wrap
408	CSSM_KEYATTR_FLAGS reqAttr = keyAttrs;
409
410	ResourceControlContext rcc;
411	ResourceControlContext *rccPtr = NULL;
412	Security::KeychainCore::Access::Maker maker;
413
414	/* P12 style IV derivation, optional */
415	CSSM_DATA iv = {0, NULL};
416	CSSM_DATA_PTR ivPtr = NULL;
417	if(blockSizeInBytes) {
418		coder.allocItem(iv, blockSizeInBytes);
419		ivPtr = &iv;
420	}
421
422	/* P12 style key derivation */
423	crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg,
424		keySizeInBits, iterCount, salt, pwd, passKey, iv);
425	if(crtn) {
426		return crtn;
427	}
428	/* subsequent errors to errOut: */
429
430	/* CSSM context */
431	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
432		encrAlg,
433		mode,
434		NULL,			// access cred
435		&ckey,
436		ivPtr,			// InitVector, optional
437		padding,
438		NULL,			// Params
439		&ccHand);
440	if(crtn) {
441		p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn);
442		goto errOut;
443	}
444	if(dlDbHand) {
445		crtn = p12AddContextAttribute(ccHand,
446			CSSM_ATTRIBUTE_DL_DB_HANDLE,
447			sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE),
448			dlDbHand);
449		if(crtn) {
450			p12LogCssmError("AddContextAttribute", crtn);
451			goto errOut;
452		}
453	}
454
455	/*
456	 * Cook up minimal WrappedKey header fields
457	 */
458	memset(&wrappedKey, 0, sizeof(CSSM_KEY));
459	memset(&unwrappedKey, 0, sizeof(CSSM_KEY));
460
461	hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
462	hdr.BlobType = CSSM_KEYBLOB_WRAPPED;
463	hdr.Format = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
464
465	/*
466	 * This one we do not know. The CSP will figure out the format
467	 * of the unwrapped key after it decrypts the raw key material.
468	 */
469	hdr.AlgorithmId = CSSM_ALGID_NONE;
470	hdr.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
471
472	/* also inferred by CSP */
473	hdr.LogicalKeySizeInBits = 0;
474	hdr.KeyAttr = CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE;
475	hdr.KeyUsage = CSSM_KEYUSE_ANY;
476	hdr.WrapAlgorithmId = encrAlg;
477	hdr.WrapMode = mode;
478
479	if(dlDbHand && keyIsPermanent) {
480		reqAttr |= CSSM_KEYATTR_PERMANENT;
481	}
482
483	wrappedKey.KeyData = shroudedKeyBits;
484
485	if(!noAcl) {
486		// Create a Access::Maker for the initial owner of the private key.
487		memset(&rcc, 0, sizeof(rcc));
488		maker.initialOwner(rcc);
489		rccPtr = &rcc;
490	}
491
492	crtn = CSSM_UnwrapKey(ccHand,
493		NULL,				// PublicKey
494		&wrappedKey,
495		keyUsage,
496		reqAttr,
497		&labelData,
498		rccPtr,					// CredAndAclEntry
499		privKey,
500		&descrData);			// required
501	if(crtn) {
502		p12LogCssmError("CSSM_UnwrapKey", crtn);
503		if(crtn == CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA) {
504			/* report in a keychain-friendly way */
505			crtn = errSecDuplicateItem;
506		}
507	}
508
509	// Finally fix the acl and owner of the private key to the
510	// specified access control settings.
511	if((crtn == CSSM_OK) && !noAcl) {
512		try {
513			CssmClient::KeyAclBearer bearer(
514				cspHand, *privKey, Allocator::standard());
515			SecPointer<KeychainCore::Access> initialAccess(access ?
516				KeychainCore::Access::required(access) :		/* caller-supplied */
517				new KeychainCore::Access("privateKey"));		/* default */
518			initialAccess->setAccess(bearer, maker);
519		}
520		catch (const CssmError &e) {
521			/* not implemented means we're talking to the CSP which does
522			 * not implement ACLs */
523			if(e.error != CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED) {
524				crtn = e.error;
525			}
526		}
527		catch(...) {
528			p12ErrorLog("p12 exception on setAccess\n");
529			crtn = errSecAuthFailed;	/* ??? */
530		}
531	}
532
533errOut:
534	if(ccHand) {
535		CSSM_DeleteContext(ccHand);
536	}
537	CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE);
538	return crtn;
539}
540
541/*
542 * Wrap a private key, yielding shrouded key bits.
543 */
544CSSM_RETURN p12WrapKey(
545	CSSM_CSP_HANDLE		cspHand,
546	CSSM_KEY_PTR		privKey,
547	const CSSM_ACCESS_CREDENTIALS *privKeyCreds,
548	CSSM_ALGORITHMS		keyAlg,				// of the unwrapping key
549	CSSM_ALGORITHMS		encrAlg,
550	CSSM_ALGORITHMS		pbeHashAlg,			// SHA1, MD5 only
551	uint32				keySizeInBits,
552	uint32				blockSizeInBytes,	// for IV
553	CSSM_PADDING		padding,			// CSSM_PADDING_PKCS7, etc.
554	CSSM_ENCRYPT_MODE	mode,				// CSSM_ALGMODE_CBCPadIV8, etc.
555	uint32				iterCount,
556	const CSSM_DATA		&salt,
557	const CSSM_DATA		*pwd,		// unicode external representation
558	const CSSM_KEY		*passKey,
559	SecNssCoder			&coder,		// for mallocing keyBits
560	CSSM_DATA			&shroudedKeyBits)	// RETURNED
561{
562	CSSM_RETURN crtn;
563	CSSM_KEY ckey;
564	CSSM_CC_HANDLE ccHand = 0;
565	CSSM_KEY wrappedKey;
566	CSSM_CONTEXT_ATTRIBUTE attr;
567	CSSM_DATA descrData = {0, NULL};
568	CSSM_ACCESS_CREDENTIALS creds;
569
570	/* key must be extractable */
571	if (!(privKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
572		return errSecDataNotAvailable;
573	}
574
575	if(privKeyCreds == NULL) {
576		/* i.e., key is from the bare CSP with no ACL support */
577		memset(&creds, 0, sizeof(creds));
578		privKeyCreds = &creds;
579	}
580
581	/* P12 style IV derivation, optional */
582	CSSM_DATA iv = {0, NULL};
583	CSSM_DATA_PTR ivPtr = NULL;
584	if(blockSizeInBytes) {
585		coder.allocItem(iv, blockSizeInBytes);
586		ivPtr = &iv;
587	}
588
589	/* P12 style key derivation */
590	crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg,
591		keySizeInBits, iterCount, salt, pwd, passKey, iv);
592	if(crtn) {
593		return crtn;
594	}
595	/* subsequent errors to errOut: */
596
597	/* CSSM context */
598	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
599		encrAlg,
600		mode,
601		NULL,			// access cred
602		&ckey,
603		ivPtr,			// InitVector, optional
604		padding,
605		NULL,			// Params
606		&ccHand);
607	if(crtn) {
608		p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn);
609		goto errOut;
610	}
611
612	memset(&wrappedKey, 0, sizeof(CSSM_KEY));
613
614	/* specify PKCS8 wrap format */
615	attr.AttributeType = CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT;
616	attr.AttributeLength = sizeof(uint32);
617	attr.Attribute.Uint32 = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
618	crtn = CSSM_UpdateContextAttributes(
619		ccHand,
620		1,
621		&attr);
622	if(crtn) {
623		p12LogCssmError("CSSM_UpdateContextAttributes", crtn);
624		goto errOut;
625	}
626
627	crtn = CSSM_WrapKey(ccHand,
628		privKeyCreds,
629		privKey,
630		&descrData,			// DescriptiveData
631		&wrappedKey);
632	if(crtn) {
633		p12LogCssmError("CSSM_WrapKey", crtn);
634	}
635	else {
636		coder.allocCopyItem(wrappedKey.KeyData, shroudedKeyBits);
637
638		/* this was mallocd by CSP */
639		freeCssmMemory(cspHand, wrappedKey.KeyData.Data);
640	}
641errOut:
642	if(ccHand) {
643		CSSM_DeleteContext(ccHand);
644	}
645	CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE);
646	return crtn;
647}
648