/* uint32 --> CSSM_DATA */
void p12IntToData(
	uint32 num,
	CSSM_DATA &cdata,
	SecNssCoder &coder)
{
	uint32 len = 0;
	
	if(num < 0x100) {
		len = 1;
	}
	else if(num < 0x10000) {
		len = 2;
	}
	else if(num < 0x1000000) {
		len = 3;
	}
	else {
		len = 4;
	}
	coder.allocItem(cdata, len);
	uint8 *cp = &cdata.Data[len - 1];
	for(unsigned i=0; i<len; i++) {
		*cp-- = num & 0xff;
		num >>= 8;
	}
}
/*
 * Calculate the MAC for a PFX. Caller is either going compare
 * the result against an existing PFX's MAC or drop the result into 
 * a newly created PFX.
 */
CSSM_RETURN p12GenMac(
	CSSM_CSP_HANDLE		cspHand,
	const CSSM_DATA		&ptext,	// e.g., NSS_P12_DecodedPFX.derAuthSaafe
	CSSM_ALGORITHMS		alg,	// better be SHA1!
	unsigned			iterCount,
	const CSSM_DATA		&salt,
	/* exactly one of the following two must be valid */
	const CSSM_DATA		*pwd,		// unicode external representation
	const CSSM_KEY		*passKey,
	SecNssCoder			&coder,		// for mallocing macData
	CSSM_DATA			&macData)	// RETURNED 
{
	CSSM_RETURN crtn;
	CSSM_CC_HANDLE ccHand = 0;
	
	/* P12 style key derivation */
	unsigned keySizeInBits;
	CSSM_ALGORITHMS hmacAlg;
	switch(alg) {
		case CSSM_ALGID_SHA1:
			keySizeInBits = 160;
			hmacAlg = CSSM_ALGID_SHA1HMAC;
			break;
		case CSSM_ALGID_MD5:
			/* not even sure if this is legal in p12 world... */
			keySizeInBits = 128;
			hmacAlg = CSSM_ALGID_MD5HMAC;
			break;
		default:
			return CSSMERR_CSP_INVALID_ALGORITHM;
	}
	CSSM_KEY macKey;
	CSSM_DATA iv = {0, NULL};
	crtn = p12KeyGen(cspHand, macKey, false, hmacAlg, alg,
		keySizeInBits, iterCount, salt, pwd, passKey, iv);
	if(crtn) {
		return crtn;
	}	
	/* subsequent errors to errOut: */

	/* prealloc the mac data */
	coder.allocItem(macData, keySizeInBits / 8);
	crtn = CSSM_CSP_CreateMacContext(cspHand, hmacAlg, &macKey, &ccHand);
	if(crtn) {
		cuPrintError("CSSM_CSP_CreateMacContext", crtn);
		goto errOut;
	}
	
	crtn = CSSM_GenerateMac (ccHand, &ptext, 1, &macData);
	if(crtn) {
		cuPrintError("CSSM_GenerateMac", crtn);
	}
errOut:
	if(ccHand) {
		CSSM_DeleteContext(ccHand);
	}
	CSSM_FreeKey(cspHand, NULL, &macKey, CSSM_FALSE);
	return crtn;
}
void p12GenSalt(
	CSSM_DATA &salt,
	SecNssCoder &coder)
{
	DevRandomGenerator rng;
	coder.allocItem(salt, P12_SALT_LEN);
	rng.random(salt.Data, P12_SALT_LEN);
}
/* convert App passphrase to array of chars used in P12 PBE */
void p12ImportPassPhrase(
	CFStringRef		inPhrase,
	SecNssCoder		&coder,
	CSSM_DATA		&outPhrase)
{
	CFDataRef cfData = CFStringCreateExternalRepresentation(NULL,
		inPhrase, kCFStringEncodingUTF8, 0);
	if(cfData == NULL) {
		p12ErrorLog("***p12ImportPassPhrase: can't convert passphrase to UTF8\n");
		MacOSError::throwMe(errSecParam);
	}
	CFIndex keyLen = CFDataGetLength(cfData);
	coder.allocItem(outPhrase, keyLen);
	memmove(outPhrase.Data, CFDataGetBytePtr(cfData), keyLen);
	CFRelease(cfData);
}
/* 
 * Generate random label string to allow associating an imported private
 * key with a cert.
 */
void p12GenLabel(
	CSSM_DATA &label,
	SecNssCoder &coder)
{
	/* first a random uint32 */
	uint8 d[4];
	DevRandomGenerator rng;
	rng.random(d, 4);
	CSSM_DATA cd = {4, d};
	uint32 i;
	p12DataToInt(cd, i);
	
	/* sprintf that into a real string */
	coder.allocItem(label, 9);
	memset(label.Data, 0, 9);
	sprintf((char *)label.Data, "%08X", (unsigned)i);
}
void CL_cssmDistPointsToNss(
	const CE_CRLDistPointsSyntax 	&cdsaObj,
	NSS_CRLDistributionPoints		&nssObj,
	SecNssCoder 					&coder)
{
	memset(&nssObj, 0, sizeof(nssObj));
	unsigned numPoints = cdsaObj.numDistPoints;
	if(numPoints == 0) {
		return;
	}
	nssObj.distPoints = 
		(NSS_DistributionPoint **)clNssNullArray(numPoints, coder);
	for(unsigned dex=0; dex<numPoints; dex++) {
		nssObj.distPoints[dex] = (NSS_DistributionPoint *)
			coder.malloc(sizeof(NSS_DistributionPoint));
		NSS_DistributionPoint *npoint = nssObj.distPoints[dex];
		memset(npoint, 0, sizeof(NSS_DistributionPoint));
		CE_CRLDistributionPoint *cpoint = &cdsaObj.distPoints[dex];
		
		/* all fields are optional */
		if(cpoint->distPointName) {
			/* encode and drop into ASN_ANY slot */
			npoint->distPointName = (CSSM_DATA *)
				coder.malloc(sizeof(CSSM_DATA));
			CL_encodeDistributionPointName(*cpoint->distPointName,
				*npoint->distPointName, coder);
			
		}
		
		if(cpoint->reasonsPresent) {
			/* bit string, presumed max length 8 bits */
			coder.allocItem(npoint->reasons, 1);
			npoint->reasons.Data[0] = cpoint->reasons;
			/* adjust for bit string length */
			npoint->reasons.Length = 8;
		}
		
		if(cpoint->crlIssuer) {
			CL_cssmGeneralNamesToNss(*cpoint->crlIssuer,
				npoint->crlIssuer, coder);
		}
	}
}
/*
 * Attempt to convert a CFStringRef, which represents a SafeBag's
 * FriendlyName, to a UTF8-encoded CSSM_DATA. The CSSM_DATA and its
 * referent are allocated in the specified SecNssCoder's memory.
 * No guarantee that this conversion works. If it doesn't we return 
 * NULL and caller must be prepared to deal with that. 
 */
CSSM_DATA_PTR p12StringToUtf8(
	CFStringRef cfStr,
	SecNssCoder &coder)
{
	if(cfStr == NULL) {
		return NULL;
	}
	CFIndex strLen = CFStringGetLength(cfStr);
	if(strLen == 0) {
		return NULL;
	}
	CSSM_DATA_PTR rtn = coder.mallocn<CSSM_DATA>();
	coder.allocItem(*rtn, strLen + 1);
	if(!CFStringGetCString(cfStr, (char *)rtn->Data,strLen + 1,
			kCFStringEncodingUTF8)) {
		/* not convertible from native Unicode to UTF8 */
		return NULL;
	}
	return rtn;
}
/*
 * Given an array of PEM parameter lines, infer parameters for key derivation and 
 * encryption.
 */
static OSStatus opensslPbeParams(
	CFArrayRef			paramLines,			// elements are CFStrings
	SecNssCoder			&coder,				// IV allocd with this
	/* remaining arguments RETURNED */
	CSSM_ALGORITHMS		&pbeAlg,
	CSSM_ALGORITHMS		&keyAlg,
	CSSM_ALGORITHMS		&encrAlg,
	CSSM_ENCRYPT_MODE	&encrMode,
	CSSM_PADDING		&encrPad,
	uint32				&keySizeInBits,
	unsigned			&blockSizeInBytes,
	CSSM_DATA			&iv)
{
	/* 
	 * This format requires PEM parameter lines. We could have gotten here
	 * without them if caller specified wrong format.
	 */
	 if(paramLines == NULL) {
		SecImpExpDbg("importWrappedKeyOpenssl: no PEM parameter lines");
		return errSecUnknownFormat;
	 }
	 CFStringRef dekInfo = NULL;
	 CFIndex numLines = CFArrayGetCount(paramLines);
	 for(CFIndex dex=0; dex<numLines; dex++) {
		CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(paramLines, dex);
		CFRange range;
		range = CFStringFind(str, CFSTR("DEK-Info: "), 0);
		if(range.length != 0) {
			dekInfo = str;
			break;
		}
	 }
	 if(dekInfo == NULL) {
		SecImpExpDbg("importWrappedKeyOpenssl: no DEK-Info lines");
		return errSecUnknownFormat;
	 }
	 
	 /* drop down to C strings for low level grunging */
	 char cstr[1024];
	 if(!CFStringGetCString(dekInfo, cstr, sizeof(cstr), kCFStringEncodingASCII)) {
		SecImpExpDbg("importWrappedKeyOpenssl: bad DEK-Info line (1)");
		return errSecUnknownFormat;
	 }
	 
	/* 
	 * This line looks like this:
	 * DEK-Info: DES-CBC,A22977A0A6A6F696
	 * 
	 * Now parse, getting the cipher spec and the IV.
	 */
	char *cp = strchr(cstr, ':');
	if(cp == NULL) {
		SecImpExpDbg("importWrappedKeyOpenssl: bad DEK-Info line (2)");
		return errSecUnknownFormat;
	}
	if((cp[1] == ' ') && (cp[2] != '\0')) {
		/* as it normally does... */
		cp += 2;
	}
	
	/* We only support DES and 3DES here */
	if(!strncmp(cp, "DES-EDE3-CBC", 12)) {
		keyAlg = CSSM_ALGID_3DES_3KEY;
		encrAlg = CSSM_ALGID_3DES_3KEY_EDE;
		keySizeInBits = 64 * 3;
		blockSizeInBytes = 8;
	}
	else if(!strncmp(cp, "DES-CBC", 7)) {
		keyAlg = CSSM_ALGID_DES;
		encrAlg = CSSM_ALGID_DES;
		keySizeInBits = 64;
		blockSizeInBytes = 8;
	}
	else {
		SecImpExpDbg("importWrappedKeyOpenssl: unrecognized wrap alg (%s)",
			cp);
		return errSecUnknownFormat;
	}

	/* these are more or less fixed */
	pbeAlg   = CSSM_ALGID_PBE_OPENSSL_MD5;
	encrMode = CSSM_ALGMODE_CBCPadIV8;
	encrPad  = CSSM_PADDING_PKCS7;
	
	/* now get the ASCII hex version of the IV */
	cp = strchr(cp, ',');
	if(cp == NULL) {
		SecImpExpDbg("importWrappedKeyOpenssl: No IV in DEK-Info line");
		return errSecUnknownFormat;
	}
	if(cp[1] != '\0') {
		cp++;
	}
	
	/* remainder should be just the IV */
	if(strlen(cp) != (blockSizeInBytes * 2)) {
		SecImpExpDbg("importWrappedKeyOpenssl: bad IV in DEK-Info line (1)");
		return errSecUnknownFormat;
	}
	
	coder.allocItem(iv, blockSizeInBytes);
	for(unsigned dex=0; dex<blockSizeInBytes; dex++) {
		if(hexToUchar(cp + (dex * 2), &iv.Data[dex])) {
			SecImpExpDbg("importWrappedKeyOpenssl: bad IV in DEK-Info line (2)");
			return errSecUnknownFormat;
		}
	}
	return errSecSuccess;
}
/* 
 * Common code to derive an openssl-wrap style wrap/unwrap key.
 */
static OSStatus deriveKeyOpensslWrap(
	const SecKeyImportExportParameters	*keyParams,		// required 
	CSSM_CSP_HANDLE						cspHand,		// required
	impExpVerifyPhrase					vp,				// import/export
	CSSM_ALGORITHMS						pbeAlg,
	CSSM_ALGORITHMS						keyAlg,
	uint32								keySizeInBits,
	const CSSM_DATA						&salt,	
	CSSM_KEY_PTR						derivedKey)
{
	CFDataRef	cfPhrase = NULL;
	CSSM_KEY	*passKey = NULL;
	OSStatus	ortn;
	
	/* passphrase or passkey? */
	ortn = impExpPassphraseCommon(keyParams, cspHand, SPF_Data, vp,
		(CFTypeRef *)&cfPhrase, &passKey);
	if(ortn) {
		return ortn;
	}
	/* subsequent errors to errOut: */

	CSSM_CRYPTO_DATA		seed;
	CSSM_CC_HANDLE			ccHand = 0;
	CSSM_ACCESS_CREDENTIALS	creds;
	SecNssCoder				coder;
	CSSM_DATA				param = {0, NULL};
	CSSM_DATA				dummyLabel;
	
	memset(&seed, 0, sizeof(seed));
	if(cfPhrase != NULL) {
		size_t len = CFDataGetLength(cfPhrase);
		coder.allocItem(seed.Param, len);
		memmove(seed.Param.Data, CFDataGetBytePtr(cfPhrase), len);
		CFRelease(cfPhrase);
	}

	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
	ortn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
		pbeAlg,
		keyAlg,
		keySizeInBits,
		&creds,
		passKey,				// BaseKey
		1,						// iterCount - yup, this is what openssl does
		&salt,
		&seed,	
		&ccHand);
	if(ortn) {
		SecImpExpDbg("deriveKeyOpensslWrap: CSSM_CSP_CreateDeriveKeyContext error");
		goto errOut;
	}
	
	memset(derivedKey, 0, sizeof(CSSM_KEY));

	dummyLabel.Data = (uint8 *)"temp unwrap key";
	dummyLabel.Length = strlen((char *)dummyLabel.Data);
	
	ortn = CSSM_DeriveKey(ccHand,
		&param,					// i.e., derived IV - don't want one
		CSSM_KEYUSE_ANY,
		/* not extractable even for the short time this key lives */
		CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE,
		&dummyLabel,
		NULL,			// cred and acl
		derivedKey);
	if(ortn) {
		SecImpExpDbg("importWrappedKeyOpenssl: PKCS5 v1.5 CSSM_DeriveKey failure");
	}
	
errOut:
	if(ccHand != 0) {
		CSSM_DeleteContext(ccHand);
	}
	if(passKey != NULL) {
		CSSM_FreeKey(cspHand, NULL, passKey, CSSM_FALSE);
		free(passKey);
	}
	return ortn;
}
/*
 * Wrap a private key, yielding shrouded key bits. 
 */
CSSM_RETURN p12WrapKey(
	CSSM_CSP_HANDLE		cspHand,
	CSSM_KEY_PTR		privKey,
	const CSSM_ACCESS_CREDENTIALS *privKeyCreds,
	CSSM_ALGORITHMS		keyAlg,				// of the unwrapping key
	CSSM_ALGORITHMS		encrAlg,
	CSSM_ALGORITHMS		pbeHashAlg,			// SHA1, MD5 only
	uint32				keySizeInBits,
	uint32				blockSizeInBytes,	// for IV
	CSSM_PADDING		padding,			// CSSM_PADDING_PKCS7, etc.
	CSSM_ENCRYPT_MODE	mode,				// CSSM_ALGMODE_CBCPadIV8, etc.
	uint32				iterCount,
	const CSSM_DATA		&salt,
	const CSSM_DATA		*pwd,		// unicode external representation
	const CSSM_KEY		*passKey,
	SecNssCoder			&coder,		// for mallocing keyBits
	CSSM_DATA			&shroudedKeyBits)	// RETURNED
{
	CSSM_RETURN crtn;
	CSSM_KEY ckey;
	CSSM_CC_HANDLE ccHand = 0;
	CSSM_KEY wrappedKey;
	CSSM_CONTEXT_ATTRIBUTE attr;
	CSSM_DATA descrData = {0, NULL};
	CSSM_ACCESS_CREDENTIALS creds;
	
	/* key must be extractable */
	if (!(privKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
		return errSecDataNotAvailable;
	}

	if(privKeyCreds == NULL) {
		/* i.e., key is from the bare CSP with no ACL support */
		memset(&creds, 0, sizeof(creds));
		privKeyCreds = &creds;
	}
	
	/* P12 style IV derivation, optional */
	CSSM_DATA iv = {0, NULL};
	CSSM_DATA_PTR ivPtr = NULL;
	if(blockSizeInBytes) {
		coder.allocItem(iv, blockSizeInBytes);
		ivPtr = &iv;
	}
	
	/* P12 style key derivation */
	crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg,
		keySizeInBits, iterCount, salt, pwd, passKey, iv);
	if(crtn) {
		return crtn;
	}	
	/* subsequent errors to errOut: */
		
	/* CSSM context */
	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
		encrAlg,
		mode,
		NULL,			// access cred
		&ckey,
		ivPtr,			// InitVector, optional
		padding,	
		NULL,			// Params
		&ccHand);
	if(crtn) {
		p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn);
		goto errOut;
	}
	
	memset(&wrappedKey, 0, sizeof(CSSM_KEY));
	
	/* specify PKCS8 wrap format */
	attr.AttributeType = CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT;
	attr.AttributeLength = sizeof(uint32);
	attr.Attribute.Uint32 = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
	crtn = CSSM_UpdateContextAttributes(
		ccHand,
		1,
		&attr);
	if(crtn) {
		p12LogCssmError("CSSM_UpdateContextAttributes", crtn);
		goto errOut;
	}
	
	crtn = CSSM_WrapKey(ccHand,
		privKeyCreds,
		privKey,
		&descrData,			// DescriptiveData
		&wrappedKey);
	if(crtn) {
		p12LogCssmError("CSSM_WrapKey", crtn);
	}
	else {
		coder.allocCopyItem(wrappedKey.KeyData, shroudedKeyBits);
		
		/* this was mallocd by CSP */
		freeCssmMemory(cspHand, wrappedKey.KeyData.Data);
	}
errOut:
	if(ccHand) {
		CSSM_DeleteContext(ccHand);
	}
	CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE);
	return crtn;
}
/*
 * Unwrap a shrouded key.
 */
CSSM_RETURN p12UnwrapKey(
	CSSM_CSP_HANDLE		cspHand,
	CSSM_DL_DB_HANDLE_PTR	dlDbHand,		// optional
	int					keyIsPermanent,		// nonzero - store in DB
	const CSSM_DATA		&shroudedKeyBits,
	CSSM_ALGORITHMS		keyAlg,				// of the unwrapping key
	CSSM_ALGORITHMS		encrAlg,
	CSSM_ALGORITHMS		pbeHashAlg,			// SHA1, MD5 only
	uint32				keySizeInBits,
	uint32				blockSizeInBytes,	// for IV
	CSSM_PADDING		padding,			// CSSM_PADDING_PKCS7, etc.
	CSSM_ENCRYPT_MODE	mode,				// CSSM_ALGMODE_CBCPadIV8, etc.
	uint32				iterCount,
	const CSSM_DATA		&salt,
	const CSSM_DATA		*pwd,		// unicode external representation
	const CSSM_KEY		*passKey,
	SecNssCoder			&coder,		// for mallocing privKey
	const CSSM_DATA		&labelData,
	SecAccessRef		access,		// optional 
	bool				noAcl,
	CSSM_KEYUSE			keyUsage,
	CSSM_KEYATTR_FLAGS	keyAttrs,

	/*
	 * Result: a private key, reference format, optionaly stored
	 * in dlDbHand
	 */
	CSSM_KEY_PTR		&privKey)
{
	CSSM_RETURN crtn;
	CSSM_KEY ckey;
	CSSM_CC_HANDLE ccHand = 0;
	CSSM_KEY wrappedKey;
	CSSM_KEY unwrappedKey;
	CSSM_KEYHEADER &hdr = wrappedKey.KeyHeader;
	CSSM_DATA descrData = {0, NULL};	// not used for PKCS8 wrap 
	CSSM_KEYATTR_FLAGS reqAttr = keyAttrs;
	
	ResourceControlContext rcc;
	ResourceControlContext *rccPtr = NULL;
	Security::KeychainCore::Access::Maker maker;
	
	/* P12 style IV derivation, optional */
	CSSM_DATA iv = {0, NULL};
	CSSM_DATA_PTR ivPtr = NULL;
	if(blockSizeInBytes) {
		coder.allocItem(iv, blockSizeInBytes);
		ivPtr = &iv;
	}
	
	/* P12 style key derivation */
	crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg,
		keySizeInBits, iterCount, salt, pwd, passKey, iv);
	if(crtn) {
		return crtn;
	}	
	/* subsequent errors to errOut: */
		
	/* CSSM context */
	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
		encrAlg,
		mode,
		NULL,			// access cred
		&ckey,
		ivPtr,			// InitVector, optional
		padding,	
		NULL,			// Params
		&ccHand);
	if(crtn) {
		p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn);
		goto errOut;
	}
	if(dlDbHand) {
		crtn = p12AddContextAttribute(ccHand, 
			CSSM_ATTRIBUTE_DL_DB_HANDLE,
			sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE),
			dlDbHand);
		if(crtn) {
			p12LogCssmError("AddContextAttribute", crtn);
			goto errOut;
		}
	}
	
	/*
	 * Cook up minimal WrappedKey header fields
	 */
	memset(&wrappedKey, 0, sizeof(CSSM_KEY));
	memset(&unwrappedKey, 0, sizeof(CSSM_KEY));
	
	hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
	hdr.BlobType = CSSM_KEYBLOB_WRAPPED;
	hdr.Format = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
	
	/* 
	 * This one we do not know. The CSP will figure out the format 
	 * of the unwrapped key after it decrypts the raw key material. 
	 */
	hdr.AlgorithmId = CSSM_ALGID_NONE;
	hdr.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
	
	/* also inferred by CSP */
	hdr.LogicalKeySizeInBits = 0;
	hdr.KeyAttr = CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE;
	hdr.KeyUsage = CSSM_KEYUSE_ANY;
	hdr.WrapAlgorithmId = encrAlg;
	hdr.WrapMode = mode;
	
	if(dlDbHand && keyIsPermanent) {
		reqAttr |= CSSM_KEYATTR_PERMANENT;
	}

	wrappedKey.KeyData = shroudedKeyBits;
	
	if(!noAcl) {
		// Create a Access::Maker for the initial owner of the private key.
		memset(&rcc, 0, sizeof(rcc));
		maker.initialOwner(rcc);
		rccPtr = &rcc;
	}
	
	crtn = CSSM_UnwrapKey(ccHand,
		NULL,				// PublicKey
		&wrappedKey,
		keyUsage,
		reqAttr,
		&labelData,
		rccPtr,					// CredAndAclEntry
		privKey,
		&descrData);			// required
	if(crtn) {
		p12LogCssmError("CSSM_UnwrapKey", crtn);
		if(crtn == CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA) {
			/* report in a keychain-friendly way */
			crtn = errSecDuplicateItem;
		}
	}
	
	// Finally fix the acl and owner of the private key to the 
	// specified access control settings.
	if((crtn == CSSM_OK) && !noAcl) {
		try {
			CssmClient::KeyAclBearer bearer(
				cspHand, *privKey, Allocator::standard());
			SecPointer<KeychainCore::Access> initialAccess(access ?
				KeychainCore::Access::required(access) :		/* caller-supplied */
				new KeychainCore::Access("privateKey"));		/* default */
			initialAccess->setAccess(bearer, maker);
		}
		catch (const CssmError &e) {
			/* not implemented means we're talking to the CSP which does
			 * not implement ACLs */
			if(e.error != CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED) {
				crtn = e.error;
			}
		}
		catch(...) {
			p12ErrorLog("p12 exception on setAccess\n");
			crtn = errSecAuthFailed;	/* ??? */
		}
	}

errOut:
	if(ccHand) {
		CSSM_DeleteContext(ccHand);
	}
	CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE);
	return crtn;
}
/*
 * Decrypt (typically, an encrypted P7 ContentInfo contents)
 */
CSSM_RETURN p12Encrypt(
	CSSM_CSP_HANDLE		cspHand,
	const CSSM_DATA		&plainText,
	CSSM_ALGORITHMS		keyAlg,				
	CSSM_ALGORITHMS		encrAlg,
	CSSM_ALGORITHMS		pbeHashAlg,			// SHA1, MD5 only
	uint32				keySizeInBits,
	uint32				blockSizeInBytes,	// for IV
	CSSM_PADDING		padding,			// CSSM_PADDING_PKCS7, etc.
	CSSM_ENCRYPT_MODE	mode,				// CSSM_ALGMODE_CBCPadIV8, etc.
	uint32				iterCount,
	const CSSM_DATA		&salt,
	/* exactly one of the following two must be valid */
	const CSSM_DATA		*pwd,		// unicode external representation
	const CSSM_KEY		*passKey,
	SecNssCoder			&coder,		// for mallocing cipherText
	CSSM_DATA			&cipherText)
{
	CSSM_RETURN crtn;
	CSSM_KEY ckey;
	CSSM_CC_HANDLE ccHand = 0;
	CSSM_DATA ourCtext = {0, NULL};
	CSSM_DATA remData = {0, NULL};
	
	/* P12 style IV derivation, optional */
	CSSM_DATA iv = {0, NULL};
	CSSM_DATA_PTR ivPtr = NULL;
	if(blockSizeInBytes) {
		coder.allocItem(iv, blockSizeInBytes);
		ivPtr = &iv;
	}
	
	/* P12 style key derivation */
	crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg,
		keySizeInBits, iterCount, salt, pwd, passKey, iv);
	if(crtn) {
		return crtn;
	}	
	/* subsequent errors to errOut: */
		
	/* CSSM context */
	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
		encrAlg,
		mode,
		NULL,			// access cred
		&ckey,
		ivPtr,			// InitVector, optional
		padding,	
		NULL,			// Params
		&ccHand);
	if(crtn) {
		cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn);
		goto errOut;
	}
	
	/* go - CSP mallocs ctext and rem data */
	CSSM_SIZE bytesEncrypted;
	crtn = CSSM_EncryptData(ccHand,
		&plainText,
		1,
		&ourCtext,
		1,
		&bytesEncrypted,
		&remData);
	if(crtn) {
		cuPrintError("CSSM_DecryptData", crtn);
	}
	else {
		coder.allocCopyItem(ourCtext, cipherText);
		cipherText.Length = bytesEncrypted;
		
		/* plaintext copied into coder space; free the memory allocated
		 * by the CSP */
		freeCssmMemory(cspHand, ourCtext.Data);
	}
	/* an artifact of CSPFUllPLuginSession - this never contains
	 * valid data but sometimes gets mallocds */
	if(remData.Data) {
		freeCssmMemory(cspHand, remData.Data);
	}
errOut:
	if(ccHand) {
		CSSM_DeleteContext(ccHand);
	}
	CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE);
	return crtn;
}