static int
kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
		       RSA * rsa, int padding)
{
    struct kc_rsa *kc = RSA_get_app_data(rsa);

    CSSM_RETURN cret;
    OSStatus ret;
    const CSSM_ACCESS_CREDENTIALS *creds;
    SecKeyRef privKeyRef = kc->pkey;
    CSSM_CSP_HANDLE cspHandle;
    const CSSM_KEY *cssmKey;
    CSSM_CC_HANDLE handle = 0;
    CSSM_DATA out, in, rem;
    int fret = 0;
    CSSM_SIZE outlen = 0;
    char remdata[1024];

    if (padding != RSA_PKCS1_PADDING)
	return -1;

    cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
    if(cret) heim_abort("SecKeyGetCSSMKey failed: %d", (int)cret);

    cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
    if(cret) heim_abort("SecKeyGetCSPHandle failed: %d", (int)cret);

    ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT,
			       kSecCredentialTypeNoUI, &creds);
    if(ret) heim_abort("SecKeyGetCredentials failed: %d", (int)ret);

    ret = CSSM_CSP_CreateAsymmetricContext (cspHandle,
					    CSSM_ALGID_RSA,
					    creds,
					    cssmKey,
					    CSSM_PADDING_PKCS1,
					    &handle);
    if(ret) heim_abort("CSSM_CSP_CreateAsymmetricContext failed: %d", (int)ret);

    in.Data = (uint8 *)from;
    in.Length = flen;

    out.Data = (uint8 *)to;
    out.Length = kc->keysize;

    rem.Data = (uint8 *)remdata;
    rem.Length = sizeof(remdata);

    cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem);
    if(cret) {
	/* cssmErrorString(cret); */
	fret = -1;
    } else
	fret = (int)out.Length;

    if(handle)
	CSSM_DeleteContext(handle);

    return fret;
}
/*
 * Calculate digest of any CSSM_KEY. Unlike older implementations
 * of this logic, you can actually calculate the public key hash
 * on any class of key, any format, raw CSP or CSPDL (though if
 * you're using the CSPDL, the key has to be a reference key
 * in that CSPDL session).
 *
 * Caller must free keyDigest->Data using impExpFreeCssmMemory() since
 * this is allocated by the CSP's app-specified allocator.
 */
CSSM_RETURN impExpKeyDigest(
	CSSM_CSP_HANDLE cspHand,
	CSSM_KEY_PTR	key,
	CSSM_DATA_PTR   keyDigest)		// contents allocd and RETURNED
{
	CSSM_DATA_PTR   localDigest;
	CSSM_CC_HANDLE  ccHand;

	CSSM_RETURN crtn = CSSM_CSP_CreatePassThroughContext(cspHand,
		key,
		&ccHand);
	if(crtn) {
		return crtn;
	}
	crtn = CSSM_CSP_PassThrough(ccHand,
		CSSM_APPLECSP_KEYDIGEST,
		NULL,
		(void **)&localDigest);
	if(crtn) {
		SecImpExpDbg("CSSM_CSP_PassThrough(KEY_DIGEST) failure");
	}
	else {
		/*
		 * Give caller the Data referent and we'll free the
		 * CSSM_DATA struct itswelf.
		 */
		*keyDigest = *localDigest;
		impExpFreeCssmMemory(cspHand, localDigest);
	}
	CSSM_DeleteContext(ccHand);
	return crtn;
}
Example #3
0
/* 
 * Sign/verify wrappers.  
 */
static CSSM_RETURN sigSign(CSSM_CSP_HANDLE cspHandle,
	uint32 algorithm,					// CSSM_ALGID_SHA1WithRSA, etc.
	CSSM_KEY_PTR key,					// private key
	const CSSM_DATA *text,
	CSSM_DATA_PTR sig)
{
	CSSM_CC_HANDLE	sigHand;
	CSSM_RETURN		crtn;
	
	crtn = CSSM_CSP_CreateSignatureContext(cspHandle,
		algorithm,
		NULL,				// passPhrase
		key,
		&sigHand);
	if(crtn) {
		return crtn;
	}
	crtn = CSSM_SignData(sigHand,
		text,
		1,
		CSSM_ALGID_NONE,
		sig);
	CSSM_DeleteContext(sigHand);
	return crtn;
}
Example #4
0
/* 
 * Staged init - cook up a CSSM_CC_HANDLE and call the appropriate
 * init.
 */
CSSM_RETURN cdsaStagedEncDecrInit(
	CSSM_CSP_HANDLE		cspHandle,		// from cdsaCspAttach()
	const CSSM_KEY		*key,			// from cdsaDeriveKey()
	StagedOpType		opType,			// SO_Encrypt, SO_Decrypt
	CSSM_CC_HANDLE		*ccHandle)		// RETURNED
{
	CSSM_RETURN 	crtn;
	CSSM_CC_HANDLE	ccHand;
	
	crtn = genCryptHandle(cspHandle, key, &ivCommon, &ccHand);
	if(crtn) {
		return crtn;
	}
	switch(opType) {
		case SO_Encrypt:
			crtn = CSSM_EncryptDataInit(ccHand);
			break;
		case SO_Decrypt:
			crtn = CSSM_DecryptDataInit(ccHand);
			break;
		default:
			return CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED;
	}
	if(crtn) {
		CSSM_DeleteContext(ccHand);
	}
	else {
		*ccHandle = ccHand;
	}
	return CSSM_OK;
}
/*
 * 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;
}
/*
 * SecCmsDigestContextCancel - cancel digesting operation
 */
void
SecCmsDigestContextCancel(SecCmsDigestContextRef cmsdigcx)
{
    int i;

    for (i = 0; i < cmsdigcx->digcnt; i++)
	if (cmsdigcx->digobjs[i])
	    CSSM_DeleteContext(cmsdigcx->digobjs[i]);
}
Example #7
0
void
SecCmsCipherContextDestroy(SecCmsCipherContext *cc)
{
    PORT_Assert(cc != NULL);
    if (cc == NULL)
	return;
    CSSM_DeleteContext(cc->cc);
    PORT_Free(cc);
}
Example #8
0
void Context::deactivate()
{
    StLock<Mutex> _(mActivateMutex);
	if (mActive)
	{
		mActive = false;
		check(CSSM_DeleteContext(mHandle));
	}
}
Example #9
0
OSStatus cmsNullWrapKey(SecKeyRef refKey,
                               CSSM_KEY_PTR rawKey)
{
    CSSM_DATA descData = {0, 0};
    CSSM_RETURN crtn;
    CSSM_CC_HANDLE ccHand;
    CSSM_ACCESS_CREDENTIALS creds;
    CSSM_CSP_HANDLE refCspHand = CSSM_INVALID_HANDLE;
    const CSSM_KEY *cssmKey = NULL;
    uint32 keyAttr;

    memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
    memset(rawKey, 0, sizeof(CSSM_KEY));

    crtn = SecKeyGetCSSMKey(refKey, &cssmKey);
    if(crtn) {
        CSSM_PERROR("SecKeyGetCSSMKey", crtn);
        goto loser;
    }
    crtn = SecKeyGetCSPHandle(refKey, &refCspHand);
    if(crtn) {
        CSSM_PERROR("SecKeyGetCSPHandle", crtn);
        goto loser;
    }

    crtn = CSSM_CSP_CreateSymmetricContext(refCspHand,
                                           CSSM_ALGID_NONE,
                                           CSSM_ALGMODE_NONE,
                                           &creds,
                                           NULL,			// unwrappingKey
                                           NULL,			// initVector
                                           CSSM_PADDING_NONE,
                                           0,				// Params
                                           &ccHand);
    if(crtn) {
        CSSM_PERROR("CSSM_CSP_CreateSymmetricContext", crtn);
        return crtn;
    }

    keyAttr = rawKey->KeyHeader.KeyAttr;
    keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE |
                 CSSM_KEYATTR_MODIFIABLE);
    keyAttr |= CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
    crtn = CSSM_WrapKey(ccHand,
                        &creds,
                        cssmKey,
                        &descData,
                        rawKey);
    if(crtn != CSSM_OK) {
        CSSM_PERROR("CSSM_WrapKey", crtn);
    }
    CSSM_DeleteContext(ccHand);

loser:
    return crtn;
}
/* verify a cert using specified key and/or signerCert */
static CSSM_RETURN verifyCert(CSSM_CL_HANDLE clHand,
	CSSM_CSP_HANDLE	cspHand,
	CSSM_DATA_PTR	cert,
	CSSM_DATA_PTR	signerCert,		// optional
	CSSM_KEY_PTR	key,			// ditto, to work spec one, other, or both
	CSSM_ALGORITHMS	sigAlg,			// CSSM_ALGID_SHA1WithRSA, etc. 
	CSSM_RETURN		expectResult,
	const char 		*opString)
{
	CSSM_RETURN		crtn;
	CSSM_CC_HANDLE	signContext = CSSM_INVALID_HANDLE;

	if(key) {
		crtn = CSSM_CSP_CreateSignatureContext(cspHand,
				sigAlg,
				NULL,				// AccessCred
				key,
				&signContext);
		if(crtn) {
			printf("Failure during %s\n", opString);
			printError("CSSM_CSP_CreateSignatureContext", crtn);
			return crtn;
		}
	}
	crtn = CSSM_CL_CertVerify(clHand,
		signContext,
		cert,					// CertToBeVerified
		signerCert,				// SignerCert
		NULL,					// VerifyScope 
		0);						// ScopeSize
	if(crtn != expectResult) {
		printf("Failure during %s\n", opString);
		if(crtn == CSSM_OK) {
			printf("Unexpected CSSM_CL_CertVerify success\n");
		}
		else if(expectResult == CSSM_OK) {
			printError("CSSM_CL_CertVerify", crtn);
		}
		else {
			printError("CSSM_CL_CertVerify: expected", expectResult);
			printError("CSSM_CL_CertVerify: got     ", crtn);
		}
		return CSSMERR_CL_VERIFICATION_FAILURE;
	}
	if(signContext != CSSM_INVALID_HANDLE) {
		crtn = CSSM_DeleteContext(signContext);
		if(crtn) {
			printf("Failure during %s\n", opString);
			printError("CSSM_DeleteContext", crtn);
			return crtn;
		}
	}
	return CSSM_OK;
}
Example #11
0
static int
kc_rsa_private_encrypt(int flen,
		       const unsigned char *from,
		       unsigned char *to,
		       RSA *rsa,
		       int padding)
{
    struct kc_rsa *kc = RSA_get_app_data(rsa);

    CSSM_RETURN cret;
    OSStatus ret;
    const CSSM_ACCESS_CREDENTIALS *creds;
    SecKeyRef privKeyRef = (SecKeyRef)kc->item;
    CSSM_CSP_HANDLE cspHandle;
    const CSSM_KEY *cssmKey;
    CSSM_CC_HANDLE sigHandle = 0;
    CSSM_DATA sig, in;
    int fret = 0;

    if (padding != RSA_PKCS1_PADDING)
	return -1;

    cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey);
    if(cret) abort();

    cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle);
    if(cret) abort();

    ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN,
			       kSecCredentialTypeDefault, &creds);
    if(ret) abort();

    ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA,
					  creds, cssmKey, &sigHandle);
    if(ret) abort();

    in.Data = (uint8 *)from;
    in.Length = flen;

    sig.Data = (uint8 *)to;
    sig.Length = kc->keysize;

    cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig);
    if(cret) {
	/* cssmErrorString(cret); */
	fret = -1;
    } else
	fret = sig.Length;

    if(sigHandle)
	CSSM_DeleteContext(sigHandle);

    return fret;
}
/*
 * Common, flexible, error-tolerant symmetric key generator.
 */
static int genSymKey(
	CSSM_CSP_HANDLE 	cspHand,
	CSSM_KEY_PTR		symKey,
	uint32 				alg,
	const char			*keyAlgStr,
	uint32 				keySizeInBits,
	CSSM_KEYATTR_FLAGS	keyAttr,
	CSSM_KEYUSE			keyUsage,
	CSSM_RETURN			expectRtn,
	CSSM_BOOL			quiet,
	CSSM_BOOL 			freeKey,			// true: free the key on exit
	const char			*testStr)
{
	CSSM_RETURN			crtn;
	CSSM_CC_HANDLE 		ccHand;
	CSSM_DATA			dummyLabel = {4, (uint8 *)"foo"};
	int					irtn;
	
	memset(symKey, 0, sizeof(CSSM_KEY));
	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
		alg,
		keySizeInBits,	// keySizeInBits
		NULL,			// Seed
		NULL,			// Salt
		NULL,			// StartDate
		NULL,			// EndDate
		NULL,			// Params
		&ccHand);
	if(crtn) {
		printError("CSSM_CSP_CreateKeyGenContext", crtn);
		return testError(quiet);
	}
	crtn = CSSM_GenerateKey(ccHand,
		keyUsage,
		keyAttr,
		&dummyLabel,
		NULL,			// ACL
		symKey);
	if(crtn != expectRtn) {
		printf("***Testing %s for alg %s:\n", testStr, keyAlgStr);
		printf("   CSSM_GenerateKey: expect %s\n",	cssmErrToStr(expectRtn));
		printf("   CSSM_GenerateKey: got    %s\n",  cssmErrToStr(crtn));
		irtn = testError(quiet);
	}
	else {
		irtn = 0;
	}
	CSSM_DeleteContext(ccHand);
	if(freeKey && (crtn == CSSM_OK)) {
		cspFreeKey(cspHand, symKey);
	}
	return irtn;
}
Example #13
0
/*
 * Derive a symmetric CSSM_KEY from the specified raw key material.
 */
CSSM_RETURN cdsaDeriveKey(
	CSSM_CSP_HANDLE		cspHandle,
	const void 			*rawKey,
	size_t				rawKeyLen,
	CSSM_ALGORITHMS		keyAlg,			// e.g., CSSM_ALGID_AES
	uint32				keySizeInBits,
	CSSM_KEY_PTR		key)
{
	CSSM_RETURN					crtn;
	CSSM_CC_HANDLE 				ccHand;
	CSSM_DATA					dummyLabel = {8, (uint8 *)"tempKey"};
	CSSM_DATA					saltData = {8, (uint8 *)"someSalt"};
	CSSM_PKCS5_PBKDF2_PARAMS 	pbeParams;
	CSSM_DATA					pbeData;
	CSSM_ACCESS_CREDENTIALS		creds;
	
	memset(key, 0, sizeof(CSSM_KEY));
	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
	crtn = CSSM_CSP_CreateDeriveKeyContext(cspHandle,
		CSSM_ALGID_PKCS5_PBKDF2,
		keyAlg,
		keySizeInBits,
		&creds,
		NULL,			// BaseKey
		1000,			// iterationCount, 1000 is the minimum
		&saltData,
		NULL,			// seed
		&ccHand);
	if(crtn) {
		return crtn;
	}
	
	/* this is the caller's raw key bits, typically ASCII (though it
	 * could be anything) */
	pbeParams.Passphrase.Data = (uint8 *)rawKey;
	pbeParams.Passphrase.Length = rawKeyLen;
	/* The only PRF supported by the CSP is HMACSHA1 */
	pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
	pbeData.Data = (uint8 *)&pbeParams;
	pbeData.Length = sizeof(pbeParams);
	crtn = CSSM_DeriveKey(ccHand,
		&pbeData,
		CSSM_KEYUSE_ANY,
		CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
		&dummyLabel,
		NULL,			// cred and acl
		key);
	CSSM_DeleteContext(ccHand);		// ignore error here
	return crtn;
}
static int doVerify(
	CSSM_CSP_HANDLE	cspHand,
	const char *algStr,
	CSSM_KEY_PTR key,			// private
	CSSM_ALGORITHMS sigAlg,
	CSSM_RETURN expRtn,			// expected result
	CSSM_BOOL quiet)
{
	uint8 ptextData[PTEXT_SIZE];
	CSSM_DATA ptext = {PTEXT_SIZE, ptextData};
	uint8 sigData[PTEXT_SIZE];
	CSSM_DATA sig = {PTEXT_SIZE, sigData};
	
	simpleGenData(&ptext, PTEXT_SIZE, PTEXT_SIZE);
	memset(sigData, 0, PTEXT_SIZE);
	
	CSSM_CC_HANDLE cryptHand = 0;
	CSSM_RETURN crtn;
	
	crtn = CSSM_CSP_CreateSignatureContext(cspHand,
		sigAlg,
		NULL,				// passPhrase
		key,
		&cryptHand);
	if(crtn) {
		printError("CSSM_CSP_CreateSignatureContext (2)", crtn);
		return testError(quiet);
	}
	int irtn = 0;
	crtn = CSSM_VerifyData(cryptHand,
		&ptext,
		1,
		CSSM_ALGID_NONE,
		&sig);
	if(crtn != expRtn) {
		if(expRtn == CSSM_OK) {
			printError("CSSM_VerifyData", crtn);
			printf("Unexpected error verifying with %s\n", algStr);
		}
		else {
			printf("***Verify with %s: expected %s, got %s.\n",
				algStr, cssmErrToStr(expRtn),
				cssmErrToStr(crtn));
		}
		irtn = testError(quiet);
	}
	CSSM_DeleteContext(cryptHand);
	return irtn;
}
/* 
 * Perform NULL wrap, generally expecting an error (either 
 * CSSMERR_CSP_INVALID_KEYATTR_MASK, if the raw key bits should be inaccessible,
 * or CSSMERR_CSP_INVALID_KEY_REFERENCE, if the key's header has been munged.)
 */
int nullWrapTest(
	CSSM_CSP_HANDLE	cspHand,
	CSSM_KEY_PTR	key,
	CSSM_BOOL 		quiet,
	CSSM_RETURN		expectRtn,
	const char		*keyAlgStr,
	const char 		*testStr)
{
	CSSM_CC_HANDLE				ccHand;
	CSSM_RETURN					crtn;
	CSSM_ACCESS_CREDENTIALS		creds;
	CSSM_KEY					wrappedKey;		// should not get created
	int							irtn;
	
	memset(&wrappedKey, 0, sizeof(CSSM_KEY));
	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
			CSSM_ALGID_NONE,
			CSSM_ALGMODE_NONE,
			&creds,				// passPhrase,
			NULL,				// wrappingKey,
			NULL,				// IV
			CSSM_PADDING_NONE,	
			0,					// Params
			&ccHand);
	if(crtn) {
		printError("cspWrapKey/CreateContext", crtn);
		return testError(quiet);
	}
	crtn = CSSM_WrapKey(ccHand,
		&creds,
		key,
		NULL,				// DescriptiveData
		&wrappedKey);
	if(crtn != expectRtn) {
		printf("***Testing %s for alg %s:\n", testStr, keyAlgStr);
		printf("   CSSM_WrapKey: expect %s\n",	cssmErrToStr(expectRtn));
		printf("   CSSM_WrapKey: got    %s\n",  cssmErrToStr(crtn));
		irtn = testError(quiet);
	}
	else {
		irtn = 0;
	}
	CSSM_DeleteContext(ccHand);
	return irtn;
}
Example #16
0
/*
 * Perform Diffie-Hellman key exchange. 
 * Given "our" private key (in the form of a CSSM_KEY) and "their" public
 * key (in the form of a raw blob of bytes), cook up a symmetric key.
 */
CSSM_RETURN cdsaDhKeyExchange(
	CSSM_CSP_HANDLE	cspHandle,
	CSSM_KEY_PTR	myPrivateKey,			// from cdsaDhGenerateKeyPair
	const void		*theirPubKey,
	uint32			theirPubKeyLen,
	CSSM_KEY_PTR	derivedKey,				// RETURNED
	uint32			deriveKeySizeInBits,
	CSSM_ALGORITHMS	derivedKeyAlg)			// e.g., CSSM_ALGID_AES
{
	CSSM_RETURN 			crtn;
	CSSM_ACCESS_CREDENTIALS	creds;
	CSSM_CC_HANDLE			ccHandle;
	CSSM_DATA				labelData = {8, (uint8 *)"tempKey"};
	
	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
	memset(derivedKey, 0, sizeof(CSSM_KEY));
	
	crtn = CSSM_CSP_CreateDeriveKeyContext(cspHandle,
		CSSM_ALGID_DH,
		derivedKeyAlg,
		deriveKeySizeInBits,
		&creds,
		myPrivateKey,	// BaseKey
		0,				// IterationCount
		0,				// Salt
		0,				// Seed
		&ccHandle);
	if(crtn) {
		return crtn;
	}
	
	/* public key passed in as CSSM_DATA *Param */
	CSSM_DATA theirPubKeyData = { theirPubKeyLen, (uint8 *)theirPubKey };
	
	crtn = CSSM_DeriveKey(ccHandle,
		&theirPubKeyData,
		CSSM_KEYUSE_ANY, 
		CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
		&labelData,
		NULL,				// cread/acl
		derivedKey);
	CSSM_DeleteContext(ccHandle);
	return crtn;
}
Example #17
0
/*
 * Decrypt.
 * plainText->Data is allocated by the CSP and must be freed (via
 * free()) by caller.
 */
CSSM_RETURN cdsaDecrypt(
	CSSM_CSP_HANDLE		cspHandle,
	const CSSM_KEY		*key,
	const CSSM_DATA		*cipherText,
	CSSM_DATA_PTR		plainText)
{
	CSSM_RETURN 	crtn;
	CSSM_CC_HANDLE	ccHandle;
	CSSM_DATA		remData = {0, NULL};
	uint32			bytesDecrypted;
	
	crtn = genCryptHandle(cspHandle, key, &ivCommon, &ccHandle);
	if(crtn) {
		return crtn;
	}
	plainText->Length = 0;
	plainText->Data = NULL;
	crtn = CSSM_DecryptData(ccHandle,
		cipherText,
		1,
		plainText,
		1,
		&bytesDecrypted,
		&remData);
	CSSM_DeleteContext(ccHandle);
	if(crtn) {
		return crtn;
	}
	
	plainText->Length = bytesDecrypted;
	if(remData.Length != 0) {
		/* append remaining data to plainText */
		uint32 newLen = plainText->Length + remData.Length;
		plainText->Data = (uint8 *)appRealloc(plainText->Data,
			newLen,
			NULL);
		memmove(plainText->Data + plainText->Length, 
			remData.Data, remData.Length);
		plainText->Length = newLen;
		appFree(remData.Data, NULL);
	}
	return CSSM_OK;
}
static CSSM_RETURN sigVerify(CSSM_CSP_HANDLE cspHand,
	uint32 algorithm,					// CSSM_ALGID_FEE_MD5, etc.
	CSSM_KEY_PTR key,					// public key
	const CSSM_DATA *text,
	const CSSM_DATA *sig,
	uint32 digestAlg,					// optional for raw signing
	CSSM_BOOL noPad)					// true --> add PADDING_NONE to context
{
	CSSM_CC_HANDLE	sigHand;
	CSSM_RETURN		crtn;
	
	crtn = CSSM_CSP_CreateSignatureContext(cspHand,
		algorithm,
		NULL,				// passPhrase
		key,
		&sigHand);
	if(crtn) {
		printError("CSSM_CSP_CreateSignatureContext", crtn);
		return crtn;
	}
	if(noPad) {
		crtn = AddContextAttribute(sigHand,
			CSSM_ATTRIBUTE_PADDING,
			sizeof(uint32),
			CAT_Uint32,
			NULL,
			CSSM_PADDING_NONE);
		if(crtn) {
			return crtn;
		}
	}
	crtn = CSSM_VerifyData(sigHand,
		text,
		1,
		digestAlg,
		sig);
	if(crtn) {
		printError("CSSM_VerifyData", crtn);
	}
	CSSM_DeleteContext(sigHand);
	return crtn;
}
static int badDecrypt(
	CSSM_CSP_HANDLE	cspHand,
	CSSM_KEY_PTR	key,
	const char		*keyAlgStr,
	CSSM_ALGORITHMS	opAlg,
	CSSM_RETURN		expectRtn,
	CSSM_BOOL		quiet,
	const char		*goodUseStr,
	const char		*badUseStr)
{
	CSSM_CC_HANDLE 	cryptHand;
	CSSM_DATA		ctext = {4, (uint8 *)"foo"};
	CSSM_DATA		ptext = {0, NULL};
	CSSM_DATA		remData = {0, NULL};
	CSSM_RETURN		crtn;
	CSSM_SIZE		bytesDecrypted;
	int				irtn;
	
	
	cryptHand = genCryptHandle(cspHand, opAlg, CSSM_ALGMODE_NONE, CSSM_PADDING_NONE,
		key, NULL /* key2 */, NULL /* iv */, 0, 0);
	if(cryptHand == 0) {
		return testError(quiet);
	}
	crtn = CSSM_DecryptData(cryptHand, &ctext, 1, &ptext, 1, &bytesDecrypted, &remData);
	if(crtn != expectRtn) {
		printf("***Testing %s key w/%s during %s:\n", keyAlgStr, goodUseStr, badUseStr);
		printf("   CSSM_DecryptData: expect %s\n",	cssmErrToStr(expectRtn));
		printf("   CSSM_DecryptData: got    %s\n",  cssmErrToStr(crtn));
		irtn = testError(quiet);
	}
	else {
		irtn = 0;
	}
	/* assume no ptext or remdata - OK? */
	CSSM_DeleteContext(cryptHand);
	return irtn;
}
/* Convert a reference key to a raw key. */
static CSSM_RETURN refKeyToRaw(
	CSSM_CSP_HANDLE	cspHand,
	const CSSM_KEY	*refKey,
	CSSM_KEY_PTR	rawKey)			// RETURNED
{
	CSSM_CC_HANDLE		ccHand;
	CSSM_RETURN			crtn;
	CSSM_ACCESS_CREDENTIALS	creds;

	memset(rawKey, 0, sizeof(CSSM_KEY));
	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
			CSSM_ALGID_NONE,
			CSSM_ALGMODE_NONE,
			&creds,				// passPhrase
			NULL,				// wrapping key
			NULL,				// init vector
			CSSM_PADDING_NONE,	// Padding
			0,					// Params
			&ccHand);
	if(crtn) {
		sec_error("CSSM_CSP_CreateSymmetricContext: refKeyToRaw context err: %s", sec_errstr(crtn));
		return crtn;
	}

	crtn = CSSM_WrapKey(ccHand,
		&creds,
		refKey,
		NULL,			// DescriptiveData
		rawKey);
	if(crtn != CSSM_OK) {
		sec_error("CSSM_WrapKey: refKeyToRaw wrap err: %s", sec_errstr(crtn));
		return crtn;
	}
	CSSM_DeleteContext(ccHand);
	return CSSM_OK;
}
/* Convert a reference key to a raw key. */
void AppleTPSession::refKeyToRaw(
	CSSM_CSP_HANDLE	cspHand,
	const CSSM_KEY	*refKey,	
	CSSM_KEY_PTR	rawKey)			// RETURNED
{
	CSSM_CC_HANDLE		ccHand;
	CSSM_RETURN			crtn;
	CSSM_ACCESS_CREDENTIALS	creds;
	
	memset(rawKey, 0, sizeof(CSSM_KEY));
	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
			CSSM_ALGID_NONE,
			CSSM_ALGMODE_NONE,
			&creds,				// passPhrase
			NULL,				// wrapping key
			NULL,				// init vector
			CSSM_PADDING_NONE,	// Padding
			0,					// Params
			&ccHand);
	if(crtn) {
		tpCredDebug("AppleTPSession::refKeyToRaw: context err");
		CssmError::throwMe(crtn);
	}
	
	crtn = CSSM_WrapKey(ccHand,
		&creds,
		refKey,
		NULL,			// DescriptiveData
		rawKey);
	if(crtn != CSSM_OK) {
		tpCredDebug("AppleTPSession::refKeyToRaw: wrapKey err");
		CssmError::throwMe(crtn);
	}
	CSSM_DeleteContext(ccHand);
}
CSSM_RETURN cuCspGenKeyPair(CSSM_CSP_HANDLE cspHand,
	CSSM_DL_DB_HANDLE *dlDbHand,	// optional
	uint32 algorithm,
	const char *keyLabel,
	unsigned keyLabelLen,
	uint32 keySize,					// in bits
	CSSM_KEY_PTR pubKey,			// mallocd by caller
	CSSM_KEYUSE pubKeyUsage,		// CSSM_KEYUSE_ENCRYPT, etc.
	CSSM_KEYATTR_FLAGS pubAttrs,	// CSSM_KEYATTR_EXTRACTABLE, etc. 
	CSSM_KEY_PTR privKey,			// mallocd by caller
	CSSM_KEYUSE privKeyUsage,		// CSSM_KEYUSE_DECRYPT, etc.
	CSSM_KEYATTR_FLAGS privAttrs)	// CSSM_KEYATTR_EXTRACTABLE, etc. 
{
	CSSM_RETURN				crtn;
	CSSM_RETURN				ocrtn;
	CSSM_CC_HANDLE 			ccHand;
	CSSM_DATA				keyLabelData;
	
	keyLabelData.Data        = (uint8 *)keyLabel,
	keyLabelData.Length      = keyLabelLen;
	memset(pubKey, 0, sizeof(CSSM_KEY));
	memset(privKey, 0, sizeof(CSSM_KEY));
	
	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
		algorithm,
		keySize,
		NULL,					// Seed
		NULL,					// Salt
		NULL,					// StartDate
		NULL,					// EndDate
		NULL,					// Params
		&ccHand);
	if(crtn) {
		cuPrintError("CSSM_CSP_CreateKeyGenContext", crtn);
		return crtn;
	}

	/* post-context-create algorithm-specific stuff */
	switch(algorithm) {		 
		#if DO_DSA_GEN_PARAMS
		case CSSM_ALGID_DSA:
			/* 
			 * extra step - generate params - this just adds some
			 * info to the context
			 */
			{
				CSSM_DATA dummy = {0, NULL};
				crtn = CSSM_GenerateAlgorithmParams(ccHand, 
					keySize, &dummy);
				if(crtn) {
					cuPrintError("CSSM_GenerateAlgorithmParams", crtn);
					CSSM_DeleteContext(ccHand);
					return crtn;
				}
				cuAppFree(dummy.Data, NULL);
			}
			break;
		#endif	/* DO_DSA_GEN_PARAMS */
		default:
			break;
	}
	
	/* optionally specify DL/DB storage location */
	if(dlDbHand) {
		crtn = cuAddContextAttribute(ccHand, 
			CSSM_ATTRIBUTE_DL_DB_HANDLE,
			sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE),
			dlDbHand);
		if(crtn) {
			CSSM_DeleteContext(ccHand);
			return crtn;
		}
	}
	ocrtn = CSSM_GenerateKeyPair(ccHand,
		pubKeyUsage,
		pubAttrs,
		&keyLabelData,
		pubKey,
		privKeyUsage,
		privAttrs,
		&keyLabelData,			// same labels
		NULL,					// CredAndAclEntry
		privKey);
	if(ocrtn) {
		cuPrintError("CSSM_GenerateKeyPair", ocrtn);
	}
	crtn = CSSM_DeleteContext(ccHand);
	if(crtn) {
		cuPrintError("CSSM_DeleteContext", crtn);
		if(ocrtn == CSSM_OK) {
			/* error on CSSM_GenerateKeyPair takes precedence */
			ocrtn = crtn;
		}
	}
	return ocrtn;
}
int main(int argc, char **argv)
{
	CSSM_CL_HANDLE	clHand;			// CL handle
	CSSM_X509_NAME	*subjName;
	CSSM_X509_NAME	*rootName;
	CSSM_X509_TIME	*notBefore;		// UTC-style "not before" time
	CSSM_X509_TIME	*notAfter;		// UTC-style "not after" time
	CSSM_DATA_PTR	rawCert;		// from CSSM_CL_CertCreateTemplate
	CSSM_DATA		signedRootCert;	// from CSSM_CL_CertSign
	CSSM_DATA		signedSubjCert;	// from CSSM_CL_CertSign
	CSSM_CSP_HANDLE	cspHand;		// CSP handle
	CSSM_KEY		subjPubKey;		// subject's RSA public key blob
	CSSM_KEY		subjPrivKey;	// subject's RSA private key - ref format
	CSSM_KEY		rootPubKey;		// root's RSA public key blob
	CSSM_KEY		rootPrivKey;	// root's RSA private key - ref format
	CSSM_RETURN		crtn;
	CSSM_KEY_PTR	extractRootKey;	// from CSSM_CL_CertGetKeyInfo()
	CSSM_KEY_PTR	extractSubjKey;	// ditto
	CSSM_CC_HANDLE	signContext;	// for signing/verifying the cert
	unsigned		badByte;
	int				arg;
	unsigned		errorCount = 0;
	
	/* user-spec'd variables */
	CSSM_BOOL		writeBlobs = CSSM_FALSE;
	CSSM_ALGORITHMS	keyAlg = KEY_ALG_DEFAULT;
	CSSM_ALGORITHMS sigAlg = SIG_ALG_DEFAULT;
	uint32			keySizeInBits = CSP_KEY_SIZE_DEFAULT;
	
	/* 
	 * Two extensions. Subject has one (KeyUsage); root has KeyUsage and 
	 * BasicConstraints.
	 */
	CSSM_X509_EXTENSION 	exts[2];
	CE_KeyUsage				keyUsage;
	CE_BasicConstraints		bc;
	
	for(arg=1; arg<argc; arg++) {
		switch(argv[arg][0]) {
			case 'w':
				writeBlobs = CSSM_TRUE;
				break;
			case 'a':
				if((argv[arg][1] == '\0') || (argv[arg][2] == '\0')) {
					usage(argv);
				}
				switch(argv[arg][2]) {
					case 's':
						keyAlg = CSSM_ALGID_RSA;
						sigAlg = CSSM_ALGID_SHA1WithRSA;
						break;
					case 'm':
						keyAlg = CSSM_ALGID_RSA;
						sigAlg = CSSM_ALGID_MD5WithRSA;
						break;
					case 'f':
						keyAlg = CSSM_ALGID_FEE;
						sigAlg = CSSM_ALGID_FEE_MD5;
						break;
					case 'F':
						keyAlg = CSSM_ALGID_FEE;
						sigAlg = CSSM_ALGID_FEE_SHA1;
						break;
					case 'e':
						keyAlg = CSSM_ALGID_FEE;
						sigAlg = CSSM_ALGID_SHA1WithECDSA;
						break;
					case 'E':
						keyAlg = CSSM_ALGID_ECDSA;
						sigAlg = CSSM_ALGID_SHA1WithECDSA;
						break;
					case '7':
						keyAlg = CSSM_ALGID_ECDSA;
						sigAlg = CSSM_ALGID_SHA256WithECDSA;
						break;
					case '8':
						keyAlg = CSSM_ALGID_ECDSA;
						sigAlg = CSSM_ALGID_SHA384WithECDSA;
						break;
					case '9':
						keyAlg = CSSM_ALGID_ECDSA;
						sigAlg = CSSM_ALGID_SHA512WithECDSA;
						break;
					case '2':
						keyAlg = CSSM_ALGID_RSA;
						sigAlg = CSSM_ALGID_SHA224WithRSA;
						break;
					case '6':
						keyAlg = CSSM_ALGID_RSA;
						sigAlg = CSSM_ALGID_SHA256WithRSA;
						break;
					case '3':
						keyAlg = CSSM_ALGID_RSA;
						sigAlg = CSSM_ALGID_SHA384WithRSA;
						break;
					case '5':
						keyAlg = CSSM_ALGID_RSA;
						sigAlg = CSSM_ALGID_SHA512WithRSA;
						break;
					default:
						usage(argv);
				}
				break;
		    case 'k':
				keySizeInBits = atoi(&argv[arg][2]);
				break;
			default:
				usage(argv);
		}
	}
	
	/* connect to CL and CSP */
	clHand = clStartup();
	if(clHand == 0) {
		return 0;
	}
	cspHand = cspStartup();
	if(cspHand == 0) {
		return 0;
	}

	/* subsequent errors to abort: to detach */
	
	/* cook up an RSA key pair for the subject */
	crtn = cspGenKeyPair(cspHand,
		keyAlg,
		SUBJ_KEY_LABEL,
		strlen(SUBJ_KEY_LABEL),
		keySizeInBits,
		&subjPubKey,
		CSSM_FALSE,			// pubIsRef - should work both ways, but not yet
		CSSM_KEYUSE_VERIFY,
		CSSM_KEYBLOB_RAW_FORMAT_NONE,
		&subjPrivKey,
		CSSM_FALSE,			// privIsRef
		CSSM_KEYUSE_SIGN,
		CSSM_KEYBLOB_RAW_FORMAT_NONE,
		CSSM_FALSE);
	if(crtn) {
		errorCount++;
		goto abort;
	}
	if(writeBlobs) {
		writeFile(SUBJ_PRIV_KEY_FILE, subjPrivKey.KeyData.Data,
			subjPrivKey.KeyData.Length);
		printf("...wrote %lu bytes to %s\n", subjPrivKey.KeyData.Length,
			SUBJ_PRIV_KEY_FILE);
	}

	/* and the root */
	crtn = cspGenKeyPair(cspHand,
		keyAlg,
		ROOT_KEY_LABEL,
		strlen(ROOT_KEY_LABEL),
		keySizeInBits,
		&rootPubKey,
		CSSM_FALSE,			// pubIsRef - should work both ways, but not yet
		CSSM_KEYUSE_VERIFY,
		CSSM_KEYBLOB_RAW_FORMAT_NONE,
		&rootPrivKey,
		CSSM_FALSE,			// privIsRef
		CSSM_KEYUSE_SIGN,
		CSSM_KEYBLOB_RAW_FORMAT_NONE,
		CSSM_FALSE);
	if(crtn) {
		errorCount++;
		goto abort;
	}
	if(writeBlobs) {
		writeFile(ROOT_PRIV_KEY_FILE, rootPrivKey.KeyData.Data,
			rootPrivKey.KeyData.Length);
		printf("...wrote %lu bytes to %s\n", rootPrivKey.KeyData.Length,
			ROOT_PRIV_KEY_FILE);
	}

	if(compareKeyData(&rootPubKey, &subjPubKey)) {
	 	printf("**WARNING: Identical root and subj keys!\n");
	}

	/*
	 * Cook up various cert fields.
	 * First, the RDNs for subject and issuer. 
	 */
	rootName = CB_BuildX509Name(rootRdn, NUM_ROOT_NAMES);
	subjName = CB_BuildX509Name(subjRdn, NUM_SUBJ_NAMES);
	if((rootName == NULL) || (subjName == NULL)) {
		printf("CB_BuildX509Name failure");
		errorCount++;
		goto abort;
	}
	
	/* not before/after in generalized time format */
	notBefore = CB_BuildX509Time(0);
	notAfter  = CB_BuildX509Time(10000);

	/* A KeyUsage extension for both certs */
	exts[0].extnId = CSSMOID_KeyUsage;
	exts[0].critical = CSSM_FALSE;
	exts[0].format = CSSM_X509_DATAFORMAT_PARSED;
	keyUsage = CE_KU_DigitalSignature | CE_KU_KeyCertSign |
			   CE_KU_KeyEncipherment | CE_KU_DataEncipherment;
	exts[0].value.parsedValue = &keyUsage;
	exts[0].BERvalue.Data = NULL;
	exts[0].BERvalue.Length = 0;

	/* BasicConstraints for root only */
	exts[1].extnId = CSSMOID_BasicConstraints;
	exts[1].critical = CSSM_TRUE;
	exts[1].format = CSSM_X509_DATAFORMAT_PARSED;
	bc.cA = CSSM_TRUE;
	bc.pathLenConstraintPresent = CSSM_TRUE;
	bc.pathLenConstraint = 2;
	exts[1].value.parsedValue = &bc;
	exts[1].BERvalue.Data = NULL;
	exts[1].BERvalue.Length = 0;
	
	/* cook up root cert */
	printf("Creating root cert...\n");
	rawCert = CB_MakeCertTemplate(clHand,
		0x12345678,			// serial number
		rootName,
		rootName,
		notBefore,
		notAfter,
		&rootPubKey,
		sigAlg,
		NULL,				// subjUniqueId
		NULL,				// issuerUniqueId
		exts,				// extensions
		2);					// numExtensions

	if(rawCert == NULL) {
		errorCount++;
		goto abort;
	}
	if(writeBlobs) {
		writeFile(ROOT_TBS_FILE_NAME, rawCert->Data, rawCert->Length);
		printf("...wrote %lu bytes to %s\n", rawCert->Length, ROOT_TBS_FILE_NAME);
	}
	
	/* Self-sign; this is a root cert */
	crtn = CSSM_CSP_CreateSignatureContext(cspHand,
			sigAlg,
			NULL,			// AccessCred
			&rootPrivKey,
			&signContext);
	if(crtn) {
		printError("CSSM_CSP_CreateSignatureContext", crtn);
		errorCount++;
		goto abort;
	}
	signedRootCert.Data = NULL;
	signedRootCert.Length = 0;
	crtn = CSSM_CL_CertSign(clHand,
		signContext,
		rawCert,			// CertToBeSigned
		NULL,				// SignScope
		0,					// ScopeSize,
		&signedRootCert);
	if(crtn) {
		printError("CSSM_CL_CertSign", crtn);
		errorCount++;
		goto abort;
	}
	crtn = CSSM_DeleteContext(signContext);
	if(crtn) {
		printError("CSSM_DeleteContext", crtn);
		errorCount++;
		goto abort;
	}
	appFreeCssmData(rawCert, CSSM_TRUE);
	if(writeBlobs) {
		writeFile(ROOT_CERT_FILE_NAME, signedRootCert.Data, signedRootCert.Length);
		printf("...wrote %lu bytes to %s\n", signedRootCert.Length, 
			ROOT_CERT_FILE_NAME);
	}

	/* now a subject cert signed by the root cert */
	printf("Creating subject cert...\n");
	rawCert = CB_MakeCertTemplate(clHand,
		0x8765,				// serial number
		rootName,
		subjName,
		notBefore,
		notAfter,
		&subjPubKey,
		sigAlg,
		NULL,				// subjUniqueId
		NULL,				// issuerUniqueId
		exts,				// extensions
		1);					// numExtensions
	if(rawCert == NULL) {
		errorCount++;
		goto abort;
	}
	if(writeBlobs) {
		writeFile(SUBJ_TBS_FILE_NAME, rawCert->Data, rawCert->Length);
		printf("...wrote %lu bytes to %s\n", rawCert->Length, SUBJ_TBS_FILE_NAME);
	}

	/* sign by root */
	crtn = CSSM_CSP_CreateSignatureContext(cspHand,
			sigAlg,
			NULL,			// AccessCred
			&rootPrivKey,
			&signContext);
	if(crtn) {
		printError("CSSM_CSP_CreateSignatureContext", crtn);
		errorCount++;
		goto abort;
	}
	signedSubjCert.Data = NULL;
	signedSubjCert.Length = 0;
	crtn = CSSM_CL_CertSign(clHand,
		signContext,
		rawCert,			// CertToBeSigned
		NULL,				// SignScope
		0,					// ScopeSize,
		&signedSubjCert);
	if(crtn) {
		printError("CSSM_CL_CertSign", crtn);
		errorCount++;
		goto abort;
	}
	crtn = CSSM_DeleteContext(signContext);
	if(crtn) {
		printError("CSSM_DeleteContext", crtn);
		errorCount++;
		goto abort;
	}
	appFreeCssmData(rawCert, CSSM_TRUE);
	if(writeBlobs) {
		writeFile(SUBJ_CERT_FILE_NAME, signedSubjCert.Data, signedSubjCert.Length);
		printf("...wrote %lu bytes to %s\n", signedSubjCert.Length, 
			SUBJ_CERT_FILE_NAME);
	}

	/* Free the stuff we allocd to get here */
	CB_FreeX509Name(rootName);
	CB_FreeX509Name(subjName);
	CB_FreeX509Time(notBefore);
	CB_FreeX509Time(notAfter);

	/*
	 * Extract public keys from the two certs, verify.
	 */
	crtn = CSSM_CL_CertGetKeyInfo(clHand, &signedSubjCert, &extractSubjKey);
	if(crtn) {
		printError("CSSM_CL_CertGetKeyInfo", crtn);
	}
	else {
		/* compare key data - header is different.
		 * Known header differences:
		 *  -- CspID - CSSM_CL_CertGetKeyInfo returns a key with NULL for
		 *     this field
		 * --  Format. rootPubKey      : 6 (CSSM_KEYBLOB_RAW_FORMAT_BSAFE)
		 *             extractRootKey  : 1 (CSSM_KEYBLOB_RAW_FORMAT_PKCS1)
		 * --  KeyAttr. rootPubKey     : 0x20 (CSSM_KEYATTR_EXTRACTABLE)
		 *              extractRootKey : 0x0
		 */
		if(!compareKeyData(extractSubjKey, &subjPubKey)) {
			printf("***CSSM_CL_CertGetKeyInfo(signedSubjCert) returned bad key data\n");
		}
		if(extractSubjKey->KeyHeader.LogicalKeySizeInBits !=
				subjPubKey.KeyHeader.LogicalKeySizeInBits) {
			printf("***EffectiveKeySizeInBits mismatch: extract %u subj %u\n",
				(unsigned)extractSubjKey->KeyHeader.LogicalKeySizeInBits,
				(unsigned)subjPubKey.KeyHeader.LogicalKeySizeInBits);
		}
	}
	crtn = CSSM_CL_CertGetKeyInfo(clHand, &signedRootCert, &extractRootKey);
	if(crtn) {
		printError("CSSM_CL_CertGetKeyInfo", crtn);
	}
	else {
		if(!compareKeyData(extractRootKey, &rootPubKey)) {
			printf("***CSSM_CL_CertGetKeyInfo(signedRootCert) returned bad key data\n");
		}
	}

	/*
	 * Verify:
	 */
	printf("Verifying certificates...\n");
	
	/*
	 *  Verify root cert by root pub key, should succeed.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedRootCert,
			NULL,
			&rootPubKey,
			sigAlg,
			CSSM_OK,
			"Verify(root by root key)")) {
		errorCount++;
		/* continue */
	}
	
	/*
	 *  Verify root cert by root cert, should succeed.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedRootCert,
			&signedRootCert,
			NULL,
			CSSM_ALGID_NONE,			// sigAlg not used here
			CSSM_OK,
			"Verify(root by root cert)")) {
		errorCount++;
		/* continue */
	}


	/*
	 *  Verify subject cert by root pub key, should succeed.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedSubjCert,
			NULL,
			&rootPubKey,
			sigAlg,
			CSSM_OK,
			"Verify(subj by root key)")) {
		errorCount++;
		/* continue */
	}

	/*
	 *  Verify subject cert by root cert, should succeed.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedSubjCert,
			&signedRootCert,
			NULL,
			CSSM_ALGID_NONE,			// sigAlg not used here
			CSSM_OK,
			"Verify(subj by root cert)")) {
		errorCount++;
		/* continue */
	}

	/*
	 *  Verify subject cert by root cert AND key, should succeed.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedSubjCert,
			&signedRootCert,
			&rootPubKey,
			sigAlg,
			CSSM_OK,
			"Verify(subj by root cert and key)")) {
		errorCount++;
		/* continue */
	}

	/*
	 *  Verify subject cert by extracted root pub key, should succeed.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedSubjCert,
			NULL,
			extractRootKey,
			sigAlg,
			CSSM_OK,
			"Verify(subj by extracted root key)")) {
		errorCount++;
		/* continue */
	}

	/*
	 *  Verify subject cert by subject pub key, should fail.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedSubjCert,
			NULL,
			&subjPubKey,
			sigAlg,
			CSSMERR_CL_VERIFICATION_FAILURE,
			"Verify(subj by subj key)")) {
		errorCount++;
		/* continue */
	}

	/*
	 *  Verify subject cert by subject cert, should fail.
	 */
	if(verifyCert(clHand,
			cspHand,
			&signedSubjCert,
			&signedSubjCert,
			NULL,
			CSSM_ALGID_NONE,			// sigAlg not used here
			CSSMERR_CL_VERIFICATION_FAILURE,
			"Verify(subj by subj cert)")) {
		errorCount++;
		/* continue */
	}

	/*
	 *  Verify erroneous subject cert by root pub key, should fail.
	 */
	badByte = genRand(1, signedSubjCert.Length - 1);
	signedSubjCert.Data[badByte] ^= 0x55;
	if(verifyCert(clHand,
			cspHand,
			&signedSubjCert,
			NULL,
			&rootPubKey,
			sigAlg,
			CSSMERR_CL_VERIFICATION_FAILURE,
			"Verify(bad subj by root key)")) {
		errorCount++;
		/* continue */
	}


	/* free/delete certs and keys */
	appFreeCssmData(&signedSubjCert, CSSM_FALSE);
	appFreeCssmData(&signedRootCert, CSSM_FALSE);

	cspFreeKey(cspHand, &rootPubKey);
	cspFreeKey(cspHand, &subjPubKey);

	/* These don't work because CSSM_CL_CertGetKeyInfo() gives keys with
	 * a bogus GUID. This may be a problem with the Apple CSP...
	 *
	cspFreeKey(cspHand, extractRootKey);
	cspFreeKey(cspHand, extractSubjKey);
	 *
	 * do it this way instead...*/
	CSSM_FREE(extractRootKey->KeyData.Data);
	CSSM_FREE(extractSubjKey->KeyData.Data);

	/* need to do this regardless...*/
	CSSM_FREE(extractRootKey);
	CSSM_FREE(extractSubjKey);

abort:
	if(cspHand != 0) {
		CSSM_ModuleDetach(cspHand);
	}

	if(errorCount) {
		printf("Signer/Subject test failed with %d errors\n", errorCount);
	}
	else {
		printf("Signer/Subject test succeeded\n");
	}
	return 0;
}
/*
 * SecCmsDigestContextFinishMultiple - finish the digests and put them
 *  into an array of CSSM_DATAs (allocated on poolp)
 */
OSStatus
SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx, SecArenaPoolRef poolp,
			    CSSM_DATA_PTR **digestsp)
{
    CSSM_CC_HANDLE digobj;
    CSSM_DATA_PTR *digests, digest;
    int i;
    void *mark;
    OSStatus rv = SECFailure;

    /* no contents? do not update digests */
    if (digestsp == NULL || !cmsdigcx->saw_contents) {
	for (i = 0; i < cmsdigcx->digcnt; i++)
	    if (cmsdigcx->digobjs[i])
		CSSM_DeleteContext(cmsdigcx->digobjs[i]);
	rv = SECSuccess;
	if (digestsp)
	    *digestsp = NULL;
	goto cleanup;
    }

    mark = PORT_ArenaMark ((PLArenaPool *)poolp);

    /* allocate digest array & CSSM_DATAs on arena */
    digests = (CSSM_DATA_PTR *)PORT_ArenaAlloc((PLArenaPool *)poolp, (cmsdigcx->digcnt+1) * sizeof(CSSM_DATA_PTR));
    digest = (CSSM_DATA_PTR)PORT_ArenaZAlloc((PLArenaPool *)poolp, cmsdigcx->digcnt * sizeof(CSSM_DATA));
    if (digests == NULL || digest == NULL) {
	goto loser;
    }

    for (i = 0; i < cmsdigcx->digcnt; i++, digest++) {
	digobj = cmsdigcx->digobjs[i];
	CSSM_QUERY_SIZE_DATA dataSize;
	rv = CSSM_QuerySize(digobj, CSSM_FALSE, 1, &dataSize);
        if (rv != CSSM_OK)
        {
            goto loser;
        }
        
	int diglength = dataSize.SizeOutputBlock;
	
	if (digobj)
	{
	    digest->Data = (unsigned char*)PORT_ArenaAlloc((PLArenaPool *)poolp, diglength);
	    if (digest->Data == NULL)
		goto loser;
	    digest->Length = diglength;
	    rv = CSSM_DigestDataFinal(digobj, digest);
            if (rv != CSSM_OK)
            {
                goto loser;
            }
            
	    CSSM_DeleteContext(digobj);
	}
	else
	{
	    digest->Data = NULL;
	    digest->Length = 0;
	}
	
	digests[i] = digest;
   }
    digests[i] = NULL;
    *digestsp = digests;

    rv = SECSuccess;

loser:
    if (rv == SECSuccess)
	PORT_ArenaUnmark((PLArenaPool *)poolp, mark);
    else
	PORT_ArenaRelease((PLArenaPool *)poolp, mark);

cleanup:
    if (cmsdigcx->digcnt > 0) {
	PORT_Free(cmsdigcx->digobjs);
    }
    PORT_Free(cmsdigcx);

    return rv;
}
/*
 * Derive symmetric key.
 * Note in the X CSP, we never return an IV. 
 */
CSSM_RETURN cuCspDeriveKey(CSSM_CSP_HANDLE cspHand,
		uint32				keyAlg,			// CSSM_ALGID_RC5, etc.
		const char 			*keyLabel,
		unsigned 			keyLabelLen,
		uint32 				keyUsage,		// CSSM_KEYUSE_ENCRYPT, etc.
		uint32 				keySizeInBits,
		CSSM_DATA_PTR		password,		// in PKCS-5 lingo
		CSSM_DATA_PTR		salt,			// ditto
		uint32				iterationCnt,	// ditto
		CSSM_KEY_PTR		key)
{
	CSSM_RETURN					crtn;
	CSSM_CC_HANDLE 				ccHand;
	uint32						keyAttr;
	CSSM_DATA					dummyLabel;
	CSSM_PKCS5_PBKDF2_PARAMS 	pbeParams;
	CSSM_DATA					pbeData;
	CSSM_ACCESS_CREDENTIALS		creds;
	
	memset(key, 0, sizeof(CSSM_KEY));
	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
	crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
		CSSM_ALGID_PKCS5_PBKDF2,
		keyAlg,
		keySizeInBits,
		&creds,
		NULL,			// BaseKey
		iterationCnt,
		salt,
		NULL,			// seed
		&ccHand);
	if(crtn) {
		cuPrintError("CSSM_CSP_CreateDeriveKeyContext", crtn);
		return crtn;
	}
	keyAttr = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF | 
			  CSSM_KEYATTR_SENSITIVE;
	dummyLabel.Length = keyLabelLen;
	dummyLabel.Data = (uint8 *)keyLabel;
	
	/* passing in password is pretty strange....*/
	pbeParams.Passphrase = *password;
	pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
	pbeData.Data = (uint8 *)&pbeParams;
	pbeData.Length = sizeof(pbeParams);
	crtn = CSSM_DeriveKey(ccHand,
		&pbeData,
		keyUsage,
		keyAttr,
		&dummyLabel,
		NULL,			// cred and acl
		key);
	if(crtn) {
		cuPrintError("CSSM_DeriveKey", crtn);
		return crtn;
	}
	crtn = CSSM_DeleteContext(ccHand);
	if(crtn) {
		cuPrintError("CSSM_DeleteContext", crtn);
	}
	return crtn;
}
/*
 * 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;
}
/*
 * Find private key by label, modify its Label attr to be the
 * hash of the associated public key. 
 * Also optionally re-sets the key's PrintName attribute; used to reset
 * this attr from the random label we create when first unwrap it 
 * to the friendly name we find later after parsing attributes.
 * Detection of a duplicate key when updating the key's attributes
 * results in a lookup of the original key and returning it in
 * foundKey.
 */
CSSM_RETURN p12SetPubKeyHash(
	CSSM_CSP_HANDLE 	cspHand,		// where the key lives
	CSSM_DL_DB_HANDLE 	dlDbHand,		// ditto
	CSSM_DATA			&keyLabel,		// for DB lookup
	CSSM_DATA_PTR		newPrintName,	// optional
	SecNssCoder			&coder,			// for mallocing newLabel
	CSSM_DATA			&newLabel,		// RETURNED with label as hash
	CSSM_KEY_PTR		&foundKey)		// RETURNED
{
	CSSM_QUERY						query;
	CSSM_SELECTION_PREDICATE		predicate;
	CSSM_DB_UNIQUE_RECORD_PTR		record = NULL;
	CSSM_RETURN						crtn;
	CSSM_HANDLE						resultHand = 0;
	CSSM_DATA						keyData = {0, NULL};
	CSSM_CC_HANDLE					ccHand = 0;
	CSSM_KEY_PTR					privKey = NULL;
	CSSM_DATA_PTR					keyDigest = NULL;
	
	assert(cspHand != 0);
	query.RecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
	query.Conjunctive = CSSM_DB_NONE;
	query.NumSelectionPredicates = 1;
	predicate.DbOperator = CSSM_DB_EQUAL;
	
	predicate.Attribute.Info.AttributeNameFormat = 
		CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
	predicate.Attribute.Info.Label.AttributeName = 
		(char*) P12_KEY_ATTR_LABEL_AND_HASH;
	predicate.Attribute.Info.AttributeFormat = 
		CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
	/* hope this cast is OK */
	predicate.Attribute.Value = &keyLabel;
	query.SelectionPredicate = &predicate;
	
	query.QueryLimits.TimeLimit = 0;	// FIXME - meaningful?
	query.QueryLimits.SizeLimit = 1;	// FIXME - meaningful?
	query.QueryFlags = CSSM_QUERY_RETURN_DATA;	

	/* build Record attribute with one or two attrs */
	CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
	CSSM_DB_ATTRIBUTE_DATA attr[2];
	attr[0].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
	attr[0].Info.Label.AttributeName = (char*) P12_KEY_ATTR_LABEL_AND_HASH;
	attr[0].Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
	if(newPrintName) {
		attr[1].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
		attr[1].Info.Label.AttributeName = (char*) P12_KEY_ATTR_PRINT_NAME;
		attr[1].Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
	}
	recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
	recordAttrs.NumberOfAttributes = newPrintName ? 2 : 1;
	recordAttrs.AttributeData = attr;
	
	crtn = CSSM_DL_DataGetFirst(dlDbHand,
		&query,
		&resultHand,
		&recordAttrs,
		&keyData,			// theData
		&record);
	/* abort only on success */
	if(crtn != CSSM_OK) {
		p12LogCssmError("CSSM_DL_DataGetFirst", crtn);
		p12ErrorLog("***p12SetPubKeyHash: can't find private key\n");
		return crtn;
	}
	/* subsequent errors to errOut: */
	if(keyData.Data == NULL) {
		p12ErrorLog("***p12SetPubKeyHash: private key lookup failure\n");
		crtn = CSSMERR_CSSM_INTERNAL_ERROR;
		goto errOut;
	}
	privKey = (CSSM_KEY_PTR)keyData.Data;
	
	/* public key hash via passthrough - works on any key, any CSP/CSPDL.... */
	/*
	 * Warning! This relies on the current default ACL meaning "allow this
	 * current app to access this private key" since we created the key. 
	 */
	crtn = CSSM_CSP_CreatePassThroughContext(cspHand, privKey, &ccHand);
	if(crtn) {
		p12LogCssmError("CSSM_CSP_CreatePassThroughContext", crtn);
		goto errOut;
	}
	crtn = CSSM_CSP_PassThrough(ccHand,
		CSSM_APPLECSP_KEYDIGEST,
		NULL,
		(void **)&keyDigest);
	if(crtn) {
		p12LogCssmError("CSSM_CSP_PassThrough", crtn);
		goto errOut;
	}

	/* 
	 * Replace Label attr data with hash.
	 * NOTE: the module which allocated this attribute data - a DL -
	 * was loaded and attached by out client layer, not by us. Thus 
	 * we can't use the memory allocator functions *we* used when 
	 * attaching to the CSP - we have to use the ones
	 * which the client registered with the DL.
	 */
	freeCssmMemory(dlDbHand.DLHandle, attr[0].Value->Data);
	freeCssmMemory(dlDbHand.DLHandle, attr[0].Value);
	if(newPrintName) {
		freeCssmMemory(dlDbHand.DLHandle, attr[1].Value->Data);
		freeCssmMemory(dlDbHand.DLHandle, attr[1].Value);
	}
	/* modify key attributes */
	attr[0].Value = keyDigest;
	if(newPrintName) {
		attr[1].Value = newPrintName;
	}
	crtn = CSSM_DL_DataModify(dlDbHand,
			CSSM_DL_DB_RECORD_PRIVATE_KEY,
			record,
			&recordAttrs,
            NULL,				// DataToBeModified
			CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
	switch(crtn) {
		case CSSM_OK:
			/* give caller the key's new label */
			coder.allocCopyItem(*keyDigest, newLabel);
			break;
		default:
			p12LogCssmError("CSSM_DL_DataModify", crtn);
			break;
		case CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA:
		{
			/* 
			 * Special case: dup private key. The label we just tried to modify is 
			 * the public key hash so we can be confident that this really is a dup. 
			 * Delete it, look up the original, and return the original to caller. 
			 */ 
			CSSM_RETURN drtn = CSSM_DL_DataDelete(dlDbHand, record);
			if(drtn) {
				p12LogCssmError("CSSM_DL_DataDelete on dup key", drtn);
				crtn = drtn;
				break;
			}

			/* Free items created in last search */
			CSSM_DL_DataAbortQuery(dlDbHand, resultHand);
			resultHand = 0;
			CSSM_DL_FreeUniqueRecord(dlDbHand, record);
			record = NULL;
			
			/* lookup by label as public key hash this time */
			predicate.Attribute.Value = keyDigest;
			drtn = CSSM_DL_DataGetFirst(dlDbHand,
				&query,
				&resultHand,
				NULL,				// no attrs this time
				&keyData,		
				&record);
			if(drtn) {
				p12LogCssmError("CSSM_DL_DataGetFirst on original key", crtn);
				crtn = drtn;
				break;
			}
			foundKey = (CSSM_KEY_PTR)keyData.Data;
			/* give caller the key's actual label */
			coder.allocCopyItem(*keyDigest, newLabel);
			break;
		}
	}
	
errOut:
	/* free resources */
	if(resultHand) {
		CSSM_DL_DataAbortQuery(dlDbHand, resultHand);
	}
	if(record) {
		CSSM_DL_FreeUniqueRecord(dlDbHand, record);
	}
	if(ccHand) {
		CSSM_DeleteContext(ccHand);
	}
	if(privKey) {
		/* key created by the CSPDL */
		CSSM_FreeKey(cspHand, NULL, privKey, CSSM_FALSE);
		freeCssmMemory(dlDbHand.DLHandle, privKey);
	}
	if(keyDigest)  {
		/* mallocd by someone else's CSP */
		freeCssmMemory(cspHand, keyDigest->Data);
		freeCssmMemory(cspHand, keyDigest);
	}
	return crtn;
}
CFDataRef decodePrivateKeyHeader(SecKeychainRef keychain, const FVPrivateKeyHeader &inHeader)
{	
	// kSecKeyLabel is defined in libsecurity_keychain/lib/SecKey.h
	SecKeychainAttribute attrs[] =
	{
		{ 6 /* kSecKeyLabel */, inHeader.publicKeyHashSize, const_cast<uint8 *>(inHeader.publicKeyHash) }
	};
	SecKeychainAttributeList attrList =
	{
		sizeof(attrs) / sizeof(SecKeychainAttribute),
		attrs
	};
	CSSM_CSP_HANDLE cspHandle = 0;
	const CSSM_KEY *cssmKey = NULL;
    const CSSM_ACCESS_CREDENTIALS *accessCred = NULL;
    CSSM_CC_HANDLE cc = 0;
	
	SecKeychainSearchRef _searchRef;
	throwIfError(SecKeychainSearchCreateFromAttributes(keychain, (SecItemClass) CSSM_DL_DB_RECORD_PRIVATE_KEY, &attrList, &_searchRef));
	CFRef<SecKeychainSearchRef> searchRef(_searchRef);
	
	SecKeychainItemRef _item;
    if (SecKeychainSearchCopyNext(searchRef, &_item) != 0) {
		return NULL;  // XXX possibly should throw here?
    }
	
	CFRef<SecKeyRef> keyItem(reinterpret_cast<SecKeyRef>(_item));
	throwIfError(SecKeyGetCSPHandle(keyItem, &cspHandle));
	throwIfError(SecKeyGetCSSMKey(keyItem, &cssmKey));
    throwIfError(SecKeyGetCredentials(keyItem, CSSM_ACL_AUTHORIZATION_DECRYPT, kSecCredentialTypeDefault, &accessCred));
    throwIfError(CSSM_CSP_CreateAsymmetricContext(cspHandle, cssmKey->KeyHeader.AlgorithmId, accessCred, cssmKey, CSSM_PADDING_PKCS1, &cc));
	CFDataRef result;
	
	try
	{		
		CssmMemoryFunctions memFuncs;
		throwIfError(CSSM_GetAPIMemoryFunctions(cspHandle, &memFuncs));
		CssmMemoryFunctionsAllocator allocator(memFuncs);
		
		const CssmData cipherBuf(const_cast<uint8 *>(inHeader.encryptedBlob), inHeader.encryptedBlobSize);
		CssmAutoData clearBuf(allocator);
		CssmAutoData remData(allocator);
		size_t bytesDecrypted;
		CSSM_RETURN crx = CSSM_DecryptData(cc, &cipherBuf, 1, &clearBuf.get(), 1, &bytesDecrypted, &remData.get());
		secinfo("FDERecovery", "decodePrivateKeyHeader: CSSM_DecryptData result: %d", crx);
		throwIfError(crx);
//		throwIfError(CSSM_DecryptData(cc, &cipherBuf, 1, &clearBuf.get(), 1, &bytesDecrypted, &remData.get()));
		clearBuf.length(bytesDecrypted);
//		rawKey.copy(clearBuf.get());
		result = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)clearBuf.get().data(), clearBuf.get().length());
//		result = parseKeyBlob(clearBuf.get());
	}
	catch(...)
	{
		CSSM_DeleteContext(cc);
		throw;
	}
	
	throwIfError(CSSM_DeleteContext(cc));
	
	return result;
}
Example #29
0
/*
 * Generate asymmetric key pair. Currently supported algorithms
 * are RSA, DSA, and FEE.
 */
CSSM_RETURN cdsaGenerateKeyPair(
	CSSM_CSP_HANDLE 	cspHandle,
	CSSM_ALGORITHMS		keyAlg,			// e.g., CSSM_ALGID_RSA
	uint32				keySizeInBits,
	CSSM_KEY_PTR		publicKey,
	CSSM_KEY_PTR		privateKey)
{
	CSSM_RETURN		crtn;
	CSSM_CC_HANDLE 	ccHandle;
	CSSM_DATA		dummyLabel = {8, (uint8 *)"tempKey"};

	memset(publicKey, 0, sizeof(CSSM_KEY));
	memset(privateKey, 0, sizeof(CSSM_KEY));
	
	crtn = CSSM_CSP_CreateKeyGenContext(cspHandle,
		keyAlg,
		keySizeInBits,
		NULL,					// Seed
		NULL,					// Salt
		NULL,					// StartDate
		NULL,					// EndDate
		NULL,					// Params
		&ccHandle);
	if(crtn) {
		return crtn;
	}

	/* post-context-create algorithm-specific stuff */
	switch(keyAlg) {
		 case CSSM_ALGID_DSA:
			/* 
			 * extra step - generate params - this just adds some
			 * info to the context
			 */
			{
				CSSM_DATA dummy = {0, NULL};
				crtn = CSSM_GenerateAlgorithmParams(ccHandle, 
					keySizeInBits, &dummy);
				if(crtn) {
					return crtn;
				}
				free(dummy.Data);
			}
			break;
		default:
			/* RSA, FEE - nothing to do */
			break;
	}
	
	/*
	 * Public keys can encrypt and verify signature. 
	 * Private keys can decrypt and sign.
	 */
	crtn = CSSM_GenerateKeyPair(ccHandle,
		CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY,
		CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
		&dummyLabel,
		publicKey,
		CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN,
		CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
		&dummyLabel,			// same labels
		NULL,					// CredAndAclEntry
		privateKey);
	CSSM_DeleteContext(ccHandle);
	return crtn;
}
Example #30
0
/*
 * Generate a Diffie-Hellman key pair. Algorithm parameters are
 * either specified by caller via inParams, or are generated here
 * and returned to caller in outParams. Exactly one of (inParams,
 * outParams) must be non-NULL.
 */
CSSM_RETURN cdsaDhGenerateKeyPair(
	CSSM_CSP_HANDLE	cspHandle,
	CSSM_KEY_PTR	publicKey,
	CSSM_KEY_PTR	privateKey,
	uint32			keySizeInBits,
	const CSSM_DATA	*inParams,		// optional 
	CSSM_DATA_PTR	outParams)		// optional, we malloc
{
	CSSM_RETURN		crtn;
	CSSM_CC_HANDLE 	ccHandle;
	CSSM_DATA		labelData = {8, (uint8 *)"tempKey"};
	
	/* Caller must specify either inParams or outParams, not both */
	if(inParams && outParams) {
		return CSSMERR_CSSM_INVALID_POINTER;
	}
	if(!inParams && !outParams) {
		return CSSMERR_CSSM_INVALID_POINTER;
	}
	memset(publicKey, 0, sizeof(CSSM_KEY));
	memset(privateKey, 0, sizeof(CSSM_KEY));
	
	crtn = CSSM_CSP_CreateKeyGenContext(cspHandle,
		CSSM_ALGID_DH,
		keySizeInBits,
		NULL,					// Seed
		NULL,					// Salt
		NULL,					// StartDate
		NULL,					// EndDate
		inParams,				// Params, may be NULL
		&ccHandle);
	if(crtn) {
		return crtn;
	}
	
	if(outParams) {
		/* explicitly generate params and return them to caller */
		outParams->Data = NULL;
		outParams->Length = 0;
		crtn = CSSM_GenerateAlgorithmParams(ccHandle, 
			keySizeInBits, outParams);
		if(crtn) {
			CSSM_DeleteContext(ccHandle);
			return crtn;
		}
	}
	
	crtn = CSSM_GenerateKeyPair(ccHandle,
		CSSM_KEYUSE_DERIVE,		// only legal use of a Diffie-Hellman key 
		CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
		&labelData,
		publicKey,
		/* private key specification */
		CSSM_KEYUSE_DERIVE,
		CSSM_KEYATTR_RETURN_REF,
		&labelData,				// same labels
		NULL,					// CredAndAclEntry
		privateKey);
	CSSM_DeleteContext(ccHandle);
	return crtn;
}