void p12GenSalt(
	CSSM_DATA &salt,
	SecNssCoder &coder)
{
	DevRandomGenerator rng;
	coder.allocItem(salt, P12_SALT_LEN);
	rng.random(salt.Data, P12_SALT_LEN);
}
/* 
 * 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);
}
OSStatus impExpWrappedKeyOpenSslExport(
	SecKeyRef							secKey,
	SecItemImportExportFlags			flags,		
	const SecKeyImportExportParameters	*keyParams,		// optional 
	CFMutableDataRef					outData,		// output appended here
	const char							**pemHeader,	// RETURNED
	CFArrayRef							*pemParamLines) // RETURNED
{
	DevRandomGenerator		rng;
	SecNssCoder				coder;
	CSSM_CSP_HANDLE			cspHand = 0;
	OSStatus				ortn;
	bool					releaseCspHand = false;
	CFMutableArrayRef		paramLines;
	CFStringRef				cfStr;
	char					dekStr[100];
	char					ivStr[3];
	
	if(keyParams == NULL) {
		return errSecParam;
	}
	
	/* we need a CSPDL handle - try to get it from the key */	
	ortn = SecKeyGetCSPHandle(secKey, &cspHand);
	if(ortn) {
		cspHand = cuCspStartup(CSSM_FALSE);
		if(cspHand == 0) {
			return CSSMERR_CSSM_ADDIN_LOAD_FAILED;
		}
		releaseCspHand = true;
	}
	/* subsequent errors to errOut: */
	
	/* 8 bytes of random IV/salt */
	uint8 saltIv[8];
	CSSM_DATA saltIvData = { 8, saltIv} ;
	rng.random(saltIv, 8);
	
	/* derive wrapping key */
	CSSM_KEY	wrappingKey;
	wrappingKey.KeyData.Data = NULL;
	wrappingKey.KeyData.Length = 0;
	ortn = deriveKeyOpensslWrap(keyParams, cspHand, VP_Export, 
		OPENSSL_WRAP_PBE_ALG, OPENSSL_WRAP_KEY_ALG,
		OPENSSL_WRAP_KEY_SIZE,
		saltIvData,		// IV == salt for this wrapping alg
		&wrappingKey);
	if(ortn) {
		goto errOut;
	}
	
	/* wrap the outgoing key */
	CSSM_KEY wrappedKey;
	memset(&wrappedKey, 0, sizeof(CSSM_KEY));
	
	ortn = impExpExportKeyCommon(cspHand, secKey, &wrappingKey, &wrappedKey,
		OPENSSL_WRAP_ENCR_ALG, OPENSSL_WRAP_ENCR_MODE, OPENSSL_WRAP_ENCR_PAD,
		CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSL, 
		CSSM_ATTRIBUTE_NONE, CSSM_KEYBLOB_RAW_FORMAT_NONE,
		NULL, &saltIvData);
	if(ortn) {
		goto errOut;
	}
	
	/*
	 * That wrapped key's KeyData is our output 
	 */
	CFDataAppendBytes(outData, wrappedKey.KeyData.Data, wrappedKey.KeyData.Length);
	
	/* PEM header depends on key algorithm */
	switch(wrappedKey.KeyHeader.AlgorithmId) {
		case CSSM_ALGID_RSA:
			*pemHeader = PEM_STRING_RSA;
			break;  
		case CSSM_ALGID_DH:
			*pemHeader = PEM_STRING_DH_PRIVATE;
			break; 
		case CSSM_ALGID_DSA:
			*pemHeader = PEM_STRING_DSA;
			break;  
		case CSSM_ALGID_ECDSA:
			*pemHeader = PEM_STRING_ECDSA_PRIVATE;
			break;  
		default:
			SecImpExpDbg("impExpWrappedKeyOpenSslExport unknown private key alg "
				"%lu", (unsigned long)wrappedKey.KeyHeader.AlgorithmId);
			/* punt though I think something is seriously hosed */
			*pemHeader = "Private Key";
	}
	CSSM_FreeKey(cspHand, NULL, &wrappedKey, CSSM_FALSE);
	
	/* 
	 * Last thing: set up outgoing PEM parameter lines
	 */
	assert(pemParamLines != NULL);
	paramLines = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
	cfStr = CFStringCreateWithCString(NULL, 
		"Proc-Type: 4,ENCRYPTED", kCFStringEncodingASCII);
	CFArrayAppendValue(paramLines, cfStr);
	CFRelease(cfStr);		// owned by array now */
	strcpy(dekStr, "DEK-Info: DES-EDE3-CBC,");
	/* next goes the IV */
	for(unsigned dex=0; dex<8; dex++) {
		sprintf(ivStr, "%02X", saltIv[dex]);
		strcat(dekStr, ivStr);
	}
	cfStr = CFStringCreateWithCString(NULL, dekStr, kCFStringEncodingASCII);
	CFArrayAppendValue(paramLines, cfStr);
	CFRelease(cfStr);		// owned by array now */
	/* and an empty line */
	cfStr = CFStringCreateWithCString(NULL, "", kCFStringEncodingASCII);
	CFArrayAppendValue(paramLines, cfStr);
	CFRelease(cfStr);		// owned by array now */
	*pemParamLines = paramLines;
	
errOut:
	if(wrappingKey.KeyData.Data != NULL) {
		CSSM_FreeKey(cspHand, NULL, &wrappingKey, CSSM_FALSE);
	}
	return ortn;

}