badattr.c   [plain text]


/*
 * badattr.c - verify proper rejection of bad key attribute bits
 */
 
#ifdef pcode

partial description...

for each asymmetric alg {
	gen pub key with KEYUSE_ENCRYPT
		make sure you cannot use it for vfy or decrypt
		make sure you cannot use it for encrypting with other alg
	gen priv key with KEYUSE_DECRYPT
		make sure you cannot use it for sign or decrypt
		make sure you cannot use it for decrypting with other alg
	gen priv key with KEYUSE_SIGN
		make sure you cannot use it for encrypt or decrypt
	gen pub with KEYUSE_VERIFY 
		make sure you cannot use it for encrypt or decrypt

}

#endif

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <Security/cssm.h>
#include <Security/cssmapple.h>
#include "cspwrap.h"
#include "common.h"
#include "cspdlTesting.h"
/*
 * Enumerate algs our own way to allow iteration.
 */
typedef unsigned privAlg;
enum {
	ALG_ASC = 1,
	ALG_DES,
	ALG_RC2,
	ALG_RC4,
	ALG_RC5,
	ALG_3DES,
	ALG_AES,
	ALG_RSA,
	ALG_FEE,
	ALG_ECDSA,
	ALG_DSA
};

#define SYM_FIRST		ALG_ASC
#define SYM_LAST		ALG_AES
#define ASYM_FIRST		ALG_RSA
#define ASYM_LAST		ALG_ECDSA		/* DSA if we're patient */

/*
 * ops expressed at bitfields
 */
#define OP_SIGN		0x0001
#define OP_VERIFY	0x0002
#define OP_ENCRYPT	0x0004
#define OP_DECRYPT	0x0008
#define OP_GENMAC	0x0010
#define OP_VFYMAC	0x0020

static void usage(char **argv)
{
	printf("usage: %s [options]\n", argv[0]);
	printf("   Options:\n");
	printf("   s(ymmetric only)\n");
	printf("   a(symmetric only)\n");
	printf("   q(uiet)\n");
	printf("   h(elp)\n");
	exit(1);
}

/*
 * 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;
}

/*
 * Common, flexible, error-tolerant key pair generator.
 */
static int genKeyPair(
	CSSM_CSP_HANDLE 	cspHand,
	uint32 				algorithm,
	const char			*keyAlgStr,
	uint32 				keySizeInBits,
	CSSM_KEY_PTR 		pubKey,			
	CSSM_KEYATTR_FLAGS 	pubKeyAttr,
	CSSM_KEYUSE 		pubKeyUsage,	
	CSSM_KEY_PTR 		privKey,		
	CSSM_KEYATTR_FLAGS 	privKeyAttr,
	CSSM_KEYUSE 		privKeyUsage,	
	CSSM_RETURN			expectRtn,
	CSSM_BOOL 			quiet,
	CSSM_BOOL 			freeKeys,			// true: free the keys on exit
	const char			*testStr)
{
	CSSM_RETURN			crtn;
	CSSM_CC_HANDLE 		ccHand;
	CSSM_DATA			keyLabelData = {4, (uint8 *)"foo"};
	int					irtn;
	
	memset(pubKey, 0, sizeof(CSSM_KEY));
	memset(privKey, 0, sizeof(CSSM_KEY));

	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
		algorithm,
		keySizeInBits,
		NULL,					// Seed
		NULL,					// Salt
		NULL,					// StartDate
		NULL,					// EndDate
		NULL,					// Params
		&ccHand);
	if(crtn) {
		printError("CSSM_CSP_CreateKeyGenContext", crtn);
		return testError(quiet);
	}

	/* post-context-create algorithm-specific stuff */
	switch(algorithm) {
		case CSSM_ALGID_RSA:
			break;
		 
		 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, 
					keySizeInBits, &dummy);
				if(crtn) {
					printError("CSSM_GenerateAlgorithmParams", crtn);
					return testError(quiet);
				}
				appFreeCssmData(&dummy, CSSM_FALSE);
			}
			break;
		default:
			break;
	}
	
	crtn = CSSM_GenerateKeyPair(ccHand,
		pubKeyUsage,
		pubKeyAttr,
		&keyLabelData,
		pubKey,
		privKeyUsage,
		privKeyAttr,
		&keyLabelData,			// same labels
		NULL,					// CredAndAclEntry
		privKey);
	if(crtn != expectRtn) {
		printf("***Testing %s for alg %s:\n", testStr, keyAlgStr);
		printf("   CSSM_GenerateKeyPair: expect %s\n",	cssmErrToStr(expectRtn));
		printf("   CSSM_GenerateKeyPair: got    %s\n",  cssmErrToStr(crtn));
		irtn = testError(quiet);
	}
	else {
		irtn = 0;
	}
	CSSM_DeleteContext(ccHand);
	if(freeKeys && (crtn == CSSM_OK)) {
		cspFreeKey(cspHand, pubKey);
		cspFreeKey(cspHand, privKey);
	}
	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;
}

/* 
 * Attempt to wrap incoming key with a DES key that we generate. Expect
 * CSSMERR_CSP_INVALID_KEYATTR_MASK since the unwrapped key is marked 
 * !EXTRACTABLE.
 */
#define WRAPPING_KEY_ALG	CSSM_ALGID_DES
#define WRAPPING_KEY_SIZE	CSP_DES_KEY_SIZE_DEFAULT

static int badWrapTest(
	CSSM_CSP_HANDLE		cspHand,
	CSSM_KEY_PTR		unwrappedKey,
	CSSM_KEYBLOB_FORMAT	wrapForm,
	CSSM_BOOL 			quiet,
	const char			*keyAlgStr,
	const char			*testStr)
{
	CSSM_CC_HANDLE				ccHand;
	CSSM_RETURN					crtn;
	CSSM_ACCESS_CREDENTIALS		creds;
	CSSM_KEY					wrappedKey;		// should not get created
	CSSM_KEY					wrappingKey;
	int							irtn;
		
	/* first generate a DES wrapping key */
	if(genSymKey(cspHand, &wrappingKey, CSSM_ALGID_DES, "DES", 
			CSP_DES_KEY_SIZE_DEFAULT, 
			CSSM_KEYATTR_RETURN_REF,
			CSSM_KEYUSE_ANY, CSSM_OK, quiet, 
			CSSM_FALSE, "not a test case")) {
		return 1;
	}

	memset(&wrappedKey, 0, sizeof(CSSM_KEY));
	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
	
	/* symmetric wrapping context */
	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
			CSSM_ALGID_DES,
			CSSM_ALGMODE_CBCPadIV8,
			&creds,				// passPhrase,
			&wrappingKey,	
			NULL,				// IV
			CSSM_PADDING_PKCS5,	
			0,					// Params
			&ccHand);
	if(crtn) {
		printError("cspWrapKey/CreateContext", crtn);
		return testError(quiet);
	}
	
	/* do it, demand error */
	crtn = CSSM_WrapKey(ccHand,
		&creds,
		unwrappedKey,
		NULL,				// DescriptiveData
		&wrappedKey);
	if(crtn != CSSMERR_CSP_INVALID_KEYATTR_MASK) {
		printf("***Testing %s for alg %s:\n", testStr, keyAlgStr);
		printf("   CSSM_WrapKey: expect CSSMERR_CSP_INVALID_KEYATTR_MASK, got %s\n",
			cssmErrToStr(crtn));
		irtn = testError(quiet);
	}
	else {
		irtn = 0;
	}
	CSSM_DeleteContext(ccHand);
	cspFreeKey(cspHand, &wrappingKey);
	return irtn;
}


/*
 * Note for these op stubs, the data, mode, padding, etc. are unimportant as 
 * the ops are expected to fail during key extraction. 
 */ 
static int badEncrypt(
	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		ptext = {4, (uint8 *)"foo"};
	CSSM_DATA		ctext = {0, NULL};
	CSSM_DATA		remData = {0, NULL};
	CSSM_RETURN		crtn;
	CSSM_SIZE		bytesEncrypted;
	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_EncryptData(cryptHand, &ptext, 1, &ctext, 1, &bytesEncrypted, &remData);
	if(crtn != expectRtn) {
		printf("***Testing %s key w/%s during %s:\n", keyAlgStr, goodUseStr, badUseStr);
		printf("   CSSM_EncryptData: expect %s\n",	cssmErrToStr(expectRtn));
		printf("   CSSM_EncryptData: got    %s\n",  cssmErrToStr(crtn));
		irtn = testError(quiet);
	}
	else {
		irtn = 0;
	}
	/* assume no ctext or remdata - OK? */
	CSSM_DeleteContext(cryptHand);
	return irtn;
}

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;
}

/*
 * Given a reference key (any class, any alg), attempt to perform null wrap after
 * munging various fields in the header. Every attempt should result in
 * CSSMERR_CSP_INVALID_KEY_REFERENCE.
 */
static int badHdrTest(
	CSSM_CSP_HANDLE		cspHand,
	CSSM_KEY_PTR		key, 
	CSSM_BOOL			quiet,
	const char			*keyAlgStr)
{
	CSSM_KEYHEADER	*hdr = &key->KeyHeader;
	CSSM_KEYHEADER	savedHdr = *hdr;

	hdr->HeaderVersion++;
	if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
			keyAlgStr, "Munged hdr(HeaderVersion)")) {
		return 1;
	}
	*hdr = savedHdr;

	hdr->CspId.Data1++;
	if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
			keyAlgStr, "Munged hdr(CspId.Data1)")) {
		return 1;
	}
	*hdr = savedHdr;

	/* can't test BlobType for Format, they're known to differ */
	
	hdr->AlgorithmId++;
	if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
			keyAlgStr, "Munged hdr(AlgorithmId)")) {
		return 1;
	}
	*hdr = savedHdr;

	/* have to come up with valid KeyClass here */
	switch(hdr->KeyClass) {
		case CSSM_KEYCLASS_PUBLIC_KEY:
			hdr->KeyClass = CSSM_KEYCLASS_PRIVATE_KEY; break;
		case CSSM_KEYCLASS_PRIVATE_KEY:
			hdr->KeyClass = CSSM_KEYCLASS_SESSION_KEY; break;
		case CSSM_KEYCLASS_SESSION_KEY:
			hdr->KeyClass = CSSM_KEYCLASS_PUBLIC_KEY; break;
		default:
			printf("***BRZZAP! badHdrTest needs work\n");
			exit(1);
	}
	if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
			keyAlgStr, "Munged hdr(KeyClass)")) {
		return 1;
	}
	*hdr = savedHdr;

	hdr->LogicalKeySizeInBits++;
	if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
			keyAlgStr, "Munged hdr(LogicalKeySizeInBits)")) {
		return 1;
	}
	*hdr = savedHdr;

	hdr->KeyAttr++;
	if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
			keyAlgStr, "Munged hdr(KeyAttr)")) {
		return 1;
	}
	*hdr = savedHdr;

	hdr->StartDate.Day[0]++;
	if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
			keyAlgStr, "Munged hdr(StartDate.Day)")) {
		return 1;
	}
	*hdr = savedHdr;

	hdr->EndDate.Year[1]++;
	if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
			keyAlgStr, "Munged hdr(EndDate.Year)")) {
		return 1;
	}
	*hdr = savedHdr;

	hdr->WrapAlgorithmId++;
	if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
			keyAlgStr, "Munged hdr(WrapAlgorithmId)")) {
		return 1;
	}
	*hdr = savedHdr;

	hdr->WrapMode++;
	if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
			keyAlgStr, "Munged hdr(WrapMode)")) {
		return 1;
	}
	*hdr = savedHdr;

	return 0;
}

/*
 * Given some op alg, return a different op alg which is of the same class
 * but should not work with an opAlg-related key.
 */
CSSM_ALGORITHMS badOpAlg(
	CSSM_ALGORITHMS	opAlg)
{
	switch(opAlg) {
		/* symmetric block ciphers */
		case CSSM_ALGID_DES: return CSSM_ALGID_3DES_3KEY_EDE;
		case CSSM_ALGID_3DES_3KEY_EDE: return CSSM_ALGID_RC2;
		case CSSM_ALGID_RC2: return CSSM_ALGID_RC5;
		case CSSM_ALGID_RC5: return CSSM_ALGID_AES;
		case CSSM_ALGID_AES: return CSSM_ALGID_DES;

		/* symmetric stream ciphers */
		case CSSM_ALGID_ASC: return CSSM_ALGID_RC4;	
		case CSSM_ALGID_RC4: return CSSM_ALGID_ASC;	
		
		/* asymmetric ciphers */
		case CSSM_ALGID_RSA: return CSSM_ALGID_FEEDEXP;
		case CSSM_ALGID_FEEDEXP: return CSSM_ALGID_RSA;
		
		/* digital signature */
		case CSSM_ALGID_SHA1WithRSA: return CSSM_ALGID_SHA1WithDSA;
		case CSSM_ALGID_SHA1WithDSA: return CSSM_ALGID_SHA1WithECDSA;
		case CSSM_ALGID_SHA1WithECDSA: return CSSM_ALGID_SHA1WithRSA;
		
		default: printf("***BRRZAP! badOpAlg needs work.\n"); exit(1);
	}
	/* NOT REACHED */
	return 0;
}

/*
 * -- Generate symmetric key with specified alg and usage;
 * -- Verify that it can't be used for any of the ops specified 
 *    in badOpFlags using goodEncrAlg/goodSignAlg;
 * -- Verify that it can't be used for goodOp/badAlg;
 *
 * Used by symUsageTest().
 *
 */
#define SYM_USAGE_ENABLE	1
 
static int badSymUsage(
	CSSM_CSP_HANDLE	cspHand,
	CSSM_ALGORITHMS	keyAlg,			// alg of the key
	const char		*keyAlgStr, 
	uint32 			keySizeInBits,
	CSSM_KEYUSE		keyUse,			// gen key with this usage
	CSSM_ALGORITHMS	goodEncrAlg,	// key is good for this encryption alg
	CSSM_ALGORITHMS	goodSignAlg,	// key is good for this sign alg (may not be used)
	unsigned		badOpFlags,		// array of (OP_DECRYPT,...)
	unsigned		goodOp,			// one good op...
	CSSM_ALGORITHMS	badAlg,			// ..which fails for this alg
	CSSM_BOOL		quiet,
	const char		*useStr)
{
	CSSM_KEY		symKey;
	int				irtn;
	
	if(genSymKey(cspHand, &symKey, keyAlg, keyAlgStr, keySizeInBits,
			CSSM_KEYATTR_RETURN_REF, keyUse, CSSM_OK, quiet, CSSM_FALSE, useStr)) {
		return 1;
	}
	#if		SYM_USAGE_ENABLE
	if(!quiet) {
		printf("         ...testing key usage\n");
	}
	if(badOpFlags & OP_ENCRYPT) {
		irtn = badEncrypt(cspHand, &symKey, keyAlgStr, goodEncrAlg,
			CSSMERR_CSP_KEY_USAGE_INCORRECT, quiet, useStr, "ENCRYPT");
		if(irtn) {
			goto abort;
		}
	}
	if(badOpFlags & OP_DECRYPT) {
		irtn = badDecrypt(cspHand, &symKey, keyAlgStr, goodEncrAlg,
			CSSMERR_CSP_KEY_USAGE_INCORRECT, quiet, useStr, "DECRYPT");
		if(irtn) {
			goto abort;
		}
	}
	#endif	/* SYM_USAGE_ENABLE */
	
	/* now do a good op with an incorrect algorithm */
	if(!quiet) {
		printf("         ...testing key/algorithm match\n");
	}
	if(goodOp & OP_ENCRYPT) {
		irtn = badEncrypt(cspHand, &symKey, keyAlgStr, badAlg,
			CSSMERR_CSP_ALGID_MISMATCH, quiet, useStr, "ENCRYPT w/bad alg");
		if(irtn) {
			goto abort;
		}
	}
	if(goodOp & OP_DECRYPT) {
		irtn = badDecrypt(cspHand, &symKey, keyAlgStr, badAlg,
			CSSMERR_CSP_ALGID_MISMATCH, quiet, useStr, "DECRYPT w/bad alg");
		if(irtn) {
			goto abort;
		}
	}
abort:
	cspFreeKey(cspHand, &symKey);
	return irtn;
}

/* 
 * Verify symmetric key usage behavior:
 *
 *	gen key with KEYUSE_ENCRYPT
 *		make sure you can't use it for decrypt
 *		make sure you can't use it for encrypting with other alg
 *	gen key with KEYUSE_DECRYPT
 *		make sure you can't use it for encrypt
 *		make sure you can't use it for decrypting with other alg
 *	gen key with KEYUSE_SIGN (mac)
 *		make sure you can't use it for encrypt or decrypt
 *	gen key with KEYUSE_VERIFY (mac verify)
 *		make sure you can't use it for encrypt or decrypt
 */
int symUsageTest(
	CSSM_CSP_HANDLE	cspHand,
	CSSM_ALGORITHMS	keyAlg,
	const char		*keyAlgStr,
	CSSM_ALGORITHMS	encrAlg,
	CSSM_ALGORITHMS	signAlg,
	uint32			keySizeInBits,
	CSSM_BOOL 		quiet)
{
	if(!quiet) {
		printf("      ...testing encrypt-enabled key\n");
	}
	if(badSymUsage(cspHand, keyAlg, keyAlgStr, keySizeInBits, CSSM_KEYUSE_ENCRYPT,
			encrAlg, signAlg, OP_DECRYPT, OP_ENCRYPT, badOpAlg(encrAlg), 
			quiet, "ENCRYPT")) {
		return 1;
	}
	if(!quiet) {
		printf("      ...testing decrypt-enabled key\n");
	}
	if(badSymUsage(cspHand, keyAlg, keyAlgStr, keySizeInBits, CSSM_KEYUSE_DECRYPT,
			encrAlg, signAlg, OP_ENCRYPT, OP_DECRYPT, badOpAlg(encrAlg), 
			quiet, "DECRYPT")) {
		return 1;
	}
	return 0;
}

/* 
 * Verify symmetric key attribute behavior:
 *
 *	check that you can not gen a key with {
 *		CSSM_KEYATTR_ALWAYS_SENSITIVE
 *		CSSM_KEYATTR_NEVER_EXTRACTABLE
 *		CSSM_KEYATTR_PERMANENT
 *		CSSM_KEYATTR_PRIVATE
 *		CSSM_KEYATTR_RETURN_DATA | !CSSM_KEYATTR_EXTRACTABLE
 *		CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_SENSITIVE
 *		CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_RETURN_REF
 *	}
 */
int symAttrTest(
	CSSM_CSP_HANDLE	cspHand,
	CSSM_ALGORITHMS	alg,
	const char		*keyAlgStr,
	uint32			keySizeInBits,
	CSSM_BOOL		bareCsp,
	CSSM_BOOL 		quiet)
{
	CSSM_KEY key;
	
	if(!quiet) {
		printf("      ...testing key attr\n");
	}
	if(bareCsp || CSPDL_ALWAYS_SENSITIVE_CHECK) {
		if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
				CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_ALWAYS_SENSITIVE,
				CSSM_KEYUSE_ANY, CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet,
				CSSM_TRUE, "ALWAYS_SENSITIVE")) {
			return 1;
		}	
	}
	if(bareCsp || CSPDL_NEVER_EXTRACTABLE_CHECK) {
		if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
				CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_NEVER_EXTRACTABLE,
				CSSM_KEYUSE_ANY, CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet,
				CSSM_TRUE, "NEVER_EXTRACTABLE")) {
			return 1;
		}
	}
	/*
	 * bare CSP : CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK
	 * CSPDL    : CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE
	 */
	if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
			CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT,
			CSSM_KEYUSE_ANY,
			bareCsp ?  CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK : 
				CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE,
			quiet,
			CSSM_TRUE, "PERMANENT")) {
		return 1;
	}
	if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
			CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PRIVATE,
			CSSM_KEYUSE_ANY, CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK, quiet,
			CSSM_TRUE, "PRIVATE")) {
		return 1;
	}
	if(bareCsp) {
		/* CSPDL doesn't support RETURN_DATA */
		if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
				CSSM_KEYATTR_RETURN_DATA /* and !extractable */,
				CSSM_KEYUSE_ANY, 
				CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet,
				CSSM_TRUE, "RETURN_DATA | !EXTRACTABLE")) {
			return 1;
		}
		if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
				CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_SENSITIVE,
				CSSM_KEYUSE_ANY, CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet,
				CSSM_TRUE, "RETURN_DATA | SENSITIVE")) {
			return 1;
		}
		if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
				CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_RETURN_REF,
				CSSM_KEYUSE_ANY, CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet,
				CSSM_TRUE, "RETURN_DATA | RETURN_REF")) {
			return 1;
		}
	}
	return 0;
}

/*
 * Verify proper symmetric key null wrap operation.
 *
 *	gen ref key, CSSM_KEYATTR_SENSITIVE, vfy you can't do null wrap;
 *	gen ref key, !CSSM_KEYATTR_EXTRACTABLE, vfy you can't do null wrap;
 */
int symNullWrapTest(
	CSSM_CSP_HANDLE	cspHand,
	CSSM_ALGORITHMS	alg,
	const char		*keyAlgStr,
	uint32			keySizeInBits,
	CSSM_BOOL 		quiet)
{
	CSSM_KEY key;

	if(!quiet) {
		printf("      ...testing access to inaccessible key bits via NULL wrap\n");
	}
	
	/* gen ref key, CSSM_KEYATTR_SENSITIVE, vfy you can't do null wrap */
	if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
			CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE,
			CSSM_KEYUSE_ANY, CSSM_OK, quiet, 
			CSSM_FALSE, "SENSITIVE | RETURN_REF")) {
		return 1;
	}
	if(nullWrapTest(cspHand, &key, quiet, CSSMERR_CSP_INVALID_KEYATTR_MASK,
			keyAlgStr, "KEYATTR_SENSITIVE")) {
		return 1;
	}
	cspFreeKey(cspHand, &key);
	
	/* gen ref key, !CSSM_KEYATTR_EXTRACTABLE, vfy you can't do null wrap */
	if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
			CSSM_KEYATTR_RETURN_REF /* !CSSM_KEYATTR_EXTRACTABLE */,
			CSSM_KEYUSE_ANY, CSSM_OK, quiet, 
			CSSM_FALSE, "!EXTRACTABLE | RETURN_REF")) {
		return 1;
	}
	if(nullWrapTest(cspHand, &key, quiet, CSSMERR_CSP_INVALID_KEYATTR_MASK,
			keyAlgStr, "!EXTRACTABLE")) {
		return 1;
	}
	cspFreeKey(cspHand, &key);

	return 0;
}

/*
 * Verify proper symmetric key wrap !EXTRACTABLE handling.
 *
 * Gen unwrapped ref key, !CSSM_KEYATTR_EXTRACTABLE;
 * Gen wrapping key - a simple DES key;
 * vfy you can't wrap unwrappedKey with wrappingKey;
 */
int symBadWrapTest(
	CSSM_CSP_HANDLE	cspHand,
	CSSM_ALGORITHMS	alg,
	const char		*keyAlgStr,
	uint32			keySizeInBits,
	CSSM_BOOL 		quiet)
{
	CSSM_KEY unwrappedKey;
	
	if(!quiet) {
		printf("      ...testing access to !EXTRACTABLE key bits via PKCS7 wrap\n");
	}
	
	/* gen ref key, CSSM_KEYATTR_SENSITIVE, !EXTRACTABLE */
	if(genSymKey(cspHand, &unwrappedKey, alg, keyAlgStr, keySizeInBits, 
			CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE,
			CSSM_KEYUSE_ANY, CSSM_OK, quiet, 
			CSSM_FALSE, "SENSITIVE | RETURN_REF")) {
		return 1;
	}
	if(badWrapTest(cspHand, 
		&unwrappedKey, 
		CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7,
		quiet, keyAlgStr, 
		"!EXTRACTABLE wrap")) {
		return 1;
	}
	cspFreeKey(cspHand, &unwrappedKey);
	return 0;
}

/*
 * Verify proper asymmetric key wrap !EXTRACTABLE handling.
 *
 * Gen unwrapped ref key, !CSSM_KEYATTR_EXTRACTABLE;
 * Gen wrapping key - a simple DES key;
 * vfy you can't wrap unwrappedKey with wrappingKey;
 */
int asymBadWrapTest(
	CSSM_CSP_HANDLE	cspHand,
	CSSM_ALGORITHMS	alg,
	const char		*keyAlgStr,
	uint32			keySizeInBits,
	CSSM_BOOL 		quiet)
{
	CSSM_KEY pubKey;
	CSSM_KEY privKey;
	
	if(!quiet) {
		printf("      ...testing access to !EXTRACTABLE key bits via CUSTOM wrap\n");
	}
	
	/* gen ref key, CSSM_KEYATTR_SENSITIVE, !EXTRACTABLE */
	if(genKeyPair(cspHand, alg, keyAlgStr, keySizeInBits, 
			&pubKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE, 
				CSSM_KEYUSE_ANY, 
			&privKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE, 
				CSSM_KEYUSE_ANY, 
			CSSM_OK, quiet, CSSM_FALSE, "RETURN_REF | SENSITIVE")) {
		return 1;
	}	
	if(badWrapTest(cspHand, 
		&privKey, 
		CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM,
		quiet, keyAlgStr, 
		"!EXTRACTABLE wrap")) {
		return 1;
	}
	cspFreeKey(cspHand, &privKey);
	cspFreeKey(cspHand, &pubKey);
	return 0;
}

/*
 * Generate a ref key, munge various fields in the header, verify that attempts
 * to use the munged key result in CSSMERR_CSP_INVALID_KEY_REFERENCE.
 */
int symHeaderTest(
	CSSM_CSP_HANDLE	cspHand,
	CSSM_ALGORITHMS	keyAlg,
	const char		*keyAlgStr,
	CSSM_ALGORITHMS	encrAlg,
	CSSM_ALGORITHMS	signAlg,
	uint32			keySizeInBits,
	CSSM_BOOL 		quiet)
{
	CSSM_KEY key;

	if(!quiet) {
		printf("      ...testing munged ref key header\n");
	}
	if(genSymKey(cspHand, &key, keyAlg, keyAlgStr, keySizeInBits, 
			CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE,
			CSSM_KEYUSE_ANY, CSSM_OK, quiet, 
			CSSM_FALSE, "RETURN_REF")) {
		return 1;
	}
	if(badHdrTest(cspHand, &key, quiet, keyAlgStr)) {
		return 1;
	}
	cspFreeKey(cspHand, &key);
	return 0;
}

/*
 * Generate key pair, specified pub key attr and expected result, standard
 * "good" priv key attr. Used by asymAttrTest().
 */
static int pubKeyAttrTest(
	CSSM_CSP_HANDLE		cspHand,
	CSSM_ALGORITHMS		alg,
	const char			*keyAlgStr,
	uint32				keySizeInBits,
	CSSM_KEYATTR_FLAGS 	pubKeyAttr,
	CSSM_RETURN			expectRtn,
	CSSM_BOOL 			quiet,
	const char			*testStr)
{
	CSSM_KEY pubKey;
	CSSM_KEY privKey;
	
	return genKeyPair(cspHand, alg, keyAlgStr, keySizeInBits, 
			&pubKey, pubKeyAttr, CSSM_KEYUSE_ANY, 
			&privKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE, CSSM_KEYUSE_ANY, 
			expectRtn, quiet, CSSM_TRUE, testStr);
}

/*
 * Generate key pair, specified priv key attr and expected result, standard
 * "good" pub key attr. Used by asymAttrTest().
 */
static int privKeyAttrTest(
	CSSM_CSP_HANDLE		cspHand,
	CSSM_ALGORITHMS		alg,
	const char			*keyAlgStr,
	uint32				keySizeInBits,
	CSSM_KEYATTR_FLAGS 	privKeyAttr,
	CSSM_RETURN			expectRtn,
	CSSM_BOOL 			quiet,
	const char			*testStr)
{
	CSSM_KEY pubKey;
	CSSM_KEY privKey;
	
	return genKeyPair(cspHand, alg, keyAlgStr, keySizeInBits, 
			&pubKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE, 
				CSSM_KEYUSE_ANY, 
			&privKey, privKeyAttr, CSSM_KEYUSE_ANY,
			expectRtn, quiet, CSSM_TRUE, testStr);
}

/*
 * Verify asymmetric key attribute behavior.
 *
 *	check that you can't gen pub key with {
 *		CSSM_KEYATTR_ALWAYS_SENSITIVE
 *		CSSM_KEYATTR_NEVER_EXTRACTABLE
 *		CSSM_KEYATTR_PERMANENT
 *		CSSM_KEYATTR_PRIVATE
 *		CSSM_KEYATTR_RETURN_DATA | !CSSM_KEYATTR_EXTRACTABLE
 *		CSSM_KEYATTR_RETURN_REF  | !CSSM_KEYATTR_EXTRACTABLE
 *		CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_SENSITIVE
 *		CSSM_KEYATTR_RETURN_REF  | CSSM_KEYATTR_SENSITIVE
 *	}
 *	check that you can't gen priv key with {
 *		CSSM_KEYATTR_ALWAYS_SENSITIVE
 *		CSSM_KEYATTR_NEVER_EXTRACTABLE
 *		CSSM_KEYATTR_PERMANENT
 *		CSSM_KEYATTR_PRIVATE
 *		CSSM_KEYATTR_RETURN_DATA | !CSSM_KEYATTR_EXTRACTABLE
 *		CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_SENSITIVE
 *	}
 */
static int asymAttrTest(
	CSSM_CSP_HANDLE	cspHand,
	CSSM_ALGORITHMS	alg,
	const char		*keyAlgStr,
	uint32			keySizeInBits,
	CSSM_BOOL		bareCsp,
	CSSM_BOOL 		quiet)
{
	#if CSPDL_ALL_KEYS_ARE_PERMANENT
	printf("      ...SKIPING asymAttrTest due to Radar 3732910\n");
	return 0;
	#endif
	if(!quiet) {
		printf("      ...testing key attr\n");
	}
	if(bareCsp || CSPDL_ALWAYS_SENSITIVE_CHECK) {
		if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits,
				CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_ALWAYS_SENSITIVE,
				CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, "ALWAYS_SENSITIVE pub")) {
			return 1;
		}	
	}
	if(bareCsp || CSPDL_NEVER_EXTRACTABLE_CHECK) {
		if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits, 
				CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_NEVER_EXTRACTABLE,
				CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, "NEVER_EXTRACTABLE pub")) {
			return 1;
		}	
	}
	if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits, 
			CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT | 
				CSSM_KEYATTR_EXTRACTABLE,
			bareCsp ?
				/* bare CSP - permanent is checked first, this is the error */
				CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK :
				/* CSPDL - SS strips off permanent, then does key gen (so we'd
					* better specify EXTRACTABLE!), *then* checks for DLDB. */
				CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE,
		quiet, "PERMANENT pub")) {
		return 1;
	}	
	if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits, 
			CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PRIVATE |
				CSSM_KEYATTR_EXTRACTABLE,
			CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK, quiet, "PRIVATE pub")) {
		return 1;
	}	
	if(bareCsp) {
		/* CSPDL doesn't support RETURN_DATA */
		if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits, 
				CSSM_KEYATTR_RETURN_DATA /* | !CSSM_KEYATTR_EXTRACTABLE */,
				CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, 
					"RETURN_DATA | !EXTRACTABLE pub")) {
			return 1;
		}
	}	
	/* pub key should always be extractable */ 
	if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits, 
			CSSM_KEYATTR_RETURN_REF /* | !CSSM_KEYATTR_EXTRACTABLE */,
			CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, 
				"RETURN_REF | !EXTRACTABLE pub")) {
		return 1;
	}	
	/* pub keys can't be sensitive */
	if(bareCsp) {
		/* CSPDL doesn't support RETURN_DATA */
		if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits, 
				CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_SENSITIVE,
				CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, "RETURN_DATA | SENSITIVE pub")) {
			return 1;
		}
	}	
	if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits, 
			CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE,
			CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, "RETURN_REF | !SENSITIVE pub")) {
		return 1;
	}	
	
	/* priv key attr tests */
	if(bareCsp || CSPDL_ALWAYS_SENSITIVE_CHECK) {
		if(privKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits,
				CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_ALWAYS_SENSITIVE,
				CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, "ALWAYS_SENSITIVE priv")) {
			return 1;
		}	
	}
	if(bareCsp || CSPDL_NEVER_EXTRACTABLE_CHECK) {
		if(privKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits,
				CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_NEVER_EXTRACTABLE,
				CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, "NEVER_EXTRACTABLE priv")) {
			return 1;
		}	
	}
	if(privKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits,
			CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT,
			bareCsp ?  CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK : 
				CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE,
			quiet, "PERMANENT priv")) {
		return 1;
	}	
	if(privKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits,
			CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PRIVATE,
			CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK, quiet, "PRIVATE priv")) {
		return 1;
	}	
	if(bareCsp) {
		/* CSPDL doesn't support RETURN_DATA */
		if(privKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits,
				CSSM_KEYATTR_RETURN_DATA /* | CSSM_KEYATTR_EXTRACTABLE */,
				CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, 
				"RETURN_DATA | !EXTRACTABLE priv")) {
			return 1;
		}
		if(privKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits,
				CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_SENSITIVE,
				CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, "RETURN_DATA | SENSITIVE priv")) {
			return 1;
		}	
	}
	return 0;
}

/* 
 * Verify asymmetric key null wrap behavior:
 *	gen ref key, CSSM_KEYATTR_SENSITIVE, vfy you can't do null wrap;
 *	gen ref key, !CSSM_KEYATTR_EXTRACTABLE, vfy you can't do null wrap;
 */
static int asymNullWrapTest(
	CSSM_CSP_HANDLE	cspHand,
	CSSM_ALGORITHMS	alg,
	const char		*keyAlgStr,
	uint32			keySizeInBits,
	CSSM_BOOL 		quiet)
{
	CSSM_KEY pubKey;
	CSSM_KEY privKey;
	
	if(!quiet) {
		printf("      ...testing access to inaccessible key bits via NULL wrap\n");
	}
	/* gen priv ref key, CSSM_KEYATTR_SENSITIVE, vfy you can't do null wrap */
	if(genKeyPair(cspHand, alg, keyAlgStr, keySizeInBits, 
			&pubKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE, 
				CSSM_KEYUSE_ANY, 
			&privKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE, 
				CSSM_KEYUSE_ANY, 
			CSSM_OK, quiet, CSSM_FALSE, "RETURN_REF | SENSITIVE")) {
		return 1;
	}	
	if(nullWrapTest(cspHand, &privKey, quiet, CSSMERR_CSP_INVALID_KEYATTR_MASK,
			keyAlgStr, "SENSITIVE")) {
		return 1;
	}
	cspFreeKey(cspHand, &privKey);
	cspFreeKey(cspHand, &pubKey);
	
	/* gen priv ref key, !CSSM_KEYATTR_EXTRACTABLE, vfy you can't do null wrap */
	if(genKeyPair(cspHand, alg, keyAlgStr, keySizeInBits, 
			&pubKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE, 
				CSSM_KEYUSE_ANY, 
			&privKey, CSSM_KEYATTR_RETURN_REF /* | !EXTRACTABLE */, CSSM_KEYUSE_ANY, 
			CSSM_OK, quiet, CSSM_FALSE, "RETURN_REF | !EXTRACTABLE")) {
		return 1;
	}	
	if(nullWrapTest(cspHand, &privKey, quiet, CSSMERR_CSP_INVALID_KEYATTR_MASK,
			keyAlgStr, "!EXTRACTABLE")) {
		return 1;
	}
	cspFreeKey(cspHand, &privKey);
	cspFreeKey(cspHand, &pubKey);
	return 0;
}

/*
 * Generate public and private ref keys, munge various fields in the header, 
 * verify that attempts to use the munged key result in 
 * CSSMERR_CSP_INVALID_KEY_REFERENCE.
 */
int asymHeaderTest(
	CSSM_CSP_HANDLE	cspHand,
	CSSM_ALGORITHMS	keyAlg,
	const char		*keyAlgStr,
	CSSM_ALGORITHMS	encrAlg,
	CSSM_ALGORITHMS	signAlg,
	uint32			keySizeInBits,
	CSSM_BOOL 		quiet)
{
	CSSM_KEY privKey;
	CSSM_KEY pubKey;

	if(!quiet) {
		printf("      ...testing munged ref key header\n");
	}
	if(genKeyPair(cspHand, keyAlg, keyAlgStr, keySizeInBits, 
			&pubKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE, 
				CSSM_KEYUSE_ANY, 
			&privKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE, 
				CSSM_KEYUSE_ANY, 
			CSSM_OK, quiet, CSSM_FALSE, "RETURN_REF")) {
		return 1;
	}	
	if(badHdrTest(cspHand, &privKey, quiet, keyAlgStr)) {
		return 1;
	}
	if(badHdrTest(cspHand, &pubKey, quiet, keyAlgStr)) {
		return 1;
	}
	cspFreeKey(cspHand, &privKey);
	cspFreeKey(cspHand, &pubKey);
	return 0;
}

/* map one of our private privAlgs (ALG_DES, etc.) to associated CSSM info. */
void privAlgToCssm(
	privAlg 		palg,
	CSSM_ALGORITHMS	*keyAlg,
	CSSM_ALGORITHMS *signAlg,		// CSSM_ALGID_NONE means incapable (e.g., DES)
	CSSM_ALGORITHMS	*encrAlg,		// CSSM_ALGID_NONE means incapable (e.g., DSA)
	uint32			*keySizeInBits,
	const char		**keyAlgStr)
{
	*signAlg = *encrAlg = CSSM_ALGID_NONE;	// default
	switch(palg) {
		case ALG_ASC:
			*encrAlg = *keyAlg = CSSM_ALGID_ASC;
			*keySizeInBits = CSP_ASC_KEY_SIZE_DEFAULT;
			*keyAlgStr = "ASC";
			break;
		case ALG_DES:
			*encrAlg = *keyAlg = CSSM_ALGID_DES;
			*keySizeInBits = CSP_DES_KEY_SIZE_DEFAULT;
			*keyAlgStr = "DES";
			break;
		case ALG_3DES:
			*encrAlg = CSSM_ALGID_3DES_3KEY_EDE;
			*keyAlg = CSSM_ALGID_3DES_3KEY;
			*keySizeInBits = CSP_DES3_KEY_SIZE_DEFAULT;
			*keyAlgStr = "3DES";
			break;
		case ALG_RC2:
			*encrAlg = *keyAlg = CSSM_ALGID_RC2;
			*keySizeInBits = CSP_RC2_KEY_SIZE_DEFAULT;
			*keyAlgStr = "RC2";
			break;
		case ALG_RC4:
			*encrAlg = *keyAlg = CSSM_ALGID_RC4;
			*keySizeInBits = CSP_RC4_KEY_SIZE_DEFAULT;
			*keyAlgStr = "RC4";
			break;
		case ALG_RC5:
			*encrAlg = *keyAlg = CSSM_ALGID_RC5;
			*keySizeInBits = CSP_RC5_KEY_SIZE_DEFAULT;
			*keyAlgStr = "RC5";
			break;
		case ALG_AES:
			*encrAlg = *keyAlg = CSSM_ALGID_AES;
			*keySizeInBits = CSP_AES_KEY_SIZE_DEFAULT;
			*keyAlgStr = "AES";
			break;
		case ALG_RSA:
			*keyAlg = CSSM_ALGID_RSA;
			*encrAlg = CSSM_ALGID_RSA;
			*signAlg = CSSM_ALGID_SHA1WithRSA;
			*keySizeInBits = CSP_RSA_KEY_SIZE_DEFAULT;
			*keyAlgStr = "RSA";
			break;
		case ALG_DSA:
			*keyAlg = CSSM_ALGID_DSA;
			*signAlg = CSSM_ALGID_SHA1WithDSA;
			*keySizeInBits = CSP_DSA_KEY_SIZE_DEFAULT;
			*keyAlgStr = "DSA";
			break;
		case ALG_FEE:
			*keyAlg = CSSM_ALGID_FEE;
			*signAlg = CSSM_ALGID_SHA1WithECDSA;
			*encrAlg = CSSM_ALGID_FEEDEXP;
			*keySizeInBits = CSP_FEE_KEY_SIZE_DEFAULT;
			*keyAlgStr = "FEE";
			break;
		case ALG_ECDSA:
			*keyAlg = CSSM_ALGID_ECDSA;
			*signAlg = CSSM_ALGID_SHA1WithECDSA;
			*keySizeInBits = CSP_ECDSA_KEY_SIZE_DEFAULT;
			*keyAlgStr = "ECDSA";
			break;
		default:
			printf("***BRRZAP! privAlgToCssm needs work\n");
			exit(1);
	}
	return;
}

int main(int argc, char **argv)
{
	int					arg;
	char				*argp;
	CSSM_CSP_HANDLE 	cspHand;
	CSSM_ALGORITHMS		keyAlg;			// CSSM_ALGID_xxx of the key
	CSSM_ALGORITHMS		signAlg;		// CSSM_ALGID_xxx of the associated signing op
	CSSM_ALGORITHMS		encrAlg;		// CSSM_ALGID_xxx of the associated encrypt op
	privAlg				palg;
	uint32				keySizeInBits;
	int					rtn;
	int					i;
	const char			*keyAlgStr;
	
	/*
	 * User-spec'd params
	 */
	CSSM_BOOL	quiet = CSSM_FALSE;
	CSSM_BOOL	doSym = CSSM_TRUE;
	CSSM_BOOL	doAsym = CSSM_TRUE;
	CSSM_BOOL	bareCsp = CSSM_TRUE;
	
	for(arg=1; arg<argc; arg++) {
		argp = argv[arg];
		switch(argp[0]) {
		    case 'q':
		    	quiet = CSSM_TRUE;
				break;
		    case 's':
		    	doAsym = CSSM_FALSE;
				break;
		    case 'a':
		    	doSym = CSSM_FALSE;
				break;
		    case 'D':
		    	bareCsp = CSSM_FALSE;
				break;
		    case 'h':
		    default:
				usage(argv);
		}
	}
	cspHand = cspDlDbStartup(bareCsp, NULL);
	if(cspHand == 0) {
		exit(1);
	}
	printf("Starting badattr; args: ");
	for(i=1; i<argc; i++) {
		printf("%s ", argv[i]);
	}
	printf("\n");
	
	if(doSym) {
		for(palg=SYM_FIRST; palg<=SYM_LAST; palg++) {
			privAlgToCssm(palg, &keyAlg, &signAlg, &encrAlg, &keySizeInBits, &keyAlgStr);
			if(!quiet) {
				printf("   ...alg %s\n", keyAlgStr);
			}
			rtn = symAttrTest(cspHand, keyAlg, keyAlgStr, keySizeInBits, bareCsp, 
					quiet);
			if(rtn) {
				goto abort;
			}
			rtn = symNullWrapTest(cspHand, keyAlg, keyAlgStr, keySizeInBits, quiet);
			if(rtn) {
				goto abort;
			}
			rtn = symBadWrapTest(cspHand, keyAlg, keyAlgStr, keySizeInBits, quiet);
			if(rtn) {
				goto abort;
			}
			rtn = symUsageTest(cspHand, keyAlg, keyAlgStr, encrAlg, signAlg, 
					keySizeInBits, quiet);
			if(rtn) {
				goto abort;
			}
			if(bareCsp || CSPDL_MUNGE_HEADER_CHECK) {
				rtn = symHeaderTest(cspHand, keyAlg, keyAlgStr, encrAlg, signAlg, 
						keySizeInBits, quiet);
				if(rtn) {
					goto abort;
				}
			}
			else if(!quiet) {
				printf("      ...SKIPPING munged ref key header test\n");
			}
		}
	}
	
	if(doAsym) {
		for(palg=ASYM_FIRST; palg<=ASYM_LAST; palg++) {
			privAlgToCssm(palg, &keyAlg, &signAlg, &encrAlg, &keySizeInBits, 
				&keyAlgStr);
			if(!quiet) {
				printf("   ...alg %s\n", keyAlgStr);
			}
			rtn = asymAttrTest(cspHand, keyAlg, keyAlgStr, keySizeInBits, 
				bareCsp, quiet);
			if(rtn) {
				goto abort;
			}
			rtn = asymNullWrapTest(cspHand, keyAlg, keyAlgStr, keySizeInBits, quiet);
			if(rtn) {
				goto abort;
			}
			rtn = asymBadWrapTest(cspHand, keyAlg, keyAlgStr, keySizeInBits, quiet);
			if(rtn) {
				goto abort;
			}
			if(bareCsp || CSPDL_MUNGE_HEADER_CHECK) {
				rtn = asymHeaderTest(cspHand, keyAlg, keyAlgStr, encrAlg, signAlg, 
						keySizeInBits, quiet);
				if(rtn) {
					goto abort;
				}
			}
			else if(!quiet) {
				printf("      ...SKIPPING munged ref key header test\n");
			}
		}
	}
abort:
	cspShutdown(cspHand, bareCsp);
	if((rtn == 0) && !quiet) {
		printf("%s complete\n", argv[0]);
	}
	return rtn;
}