keyHashAsym.c   [plain text]


/*
 * keyHashAsym.c - CSSM_APPLECSP_KEYDIGEST passthrough test for all
 *				   known asymmetric algorithms and key formats
 */
 
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <Security/cssm.h>
#include "cspwrap.h"
#include "common.h"
#include "cspdlTesting.h"
#include <security_cdsa_utils/cuFileIo.h>

#define USAGE_NAME			"noUsage"
#define USAGE_NAME_LEN		(strlen(USAGE_NAME))
#define LOOPS_DEF			10

#define DSA_PARAM_FILE		"dsaParams_512.der"
#define DH_PARAM_FILE		"dhParams_512.der"

static void usage(char **argv)
{
	printf("usage: %s [options]\n", argv[0]);
	printf("Options:\n");
	printf("  l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
	printf("  D (CSP/DL; default = bare CSP)\n");
	printf("  p(ause on each loop)\n");
	printf("  q(uiet)\n");
	printf("  v(erbose))\n");
	exit(1);
}

static CSSM_DATA	dsa512Params;
static CSSM_DATA	dh512Params;

/*
 * Describe parameters for one test iteration.
 */
typedef struct {
	CSSM_ALGORITHMS		keyAlg;
	CSSM_KEYBLOB_FORMAT	pubKeyForm;
	CSSM_KEYBLOB_FORMAT	privKeyForm;
	uint32				keySizeInBits;
	CSSM_DATA			*algParams;		// optional
} KeyHashTest;

KeyHashTest KeyHashTestParams[] = 
{
	/* RSA */
	{ 	CSSM_ALGID_RSA, 
		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
		512, NULL
	},
	{ 	CSSM_ALGID_RSA, 
		CSSM_KEYBLOB_RAW_FORMAT_PKCS1, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
		512, NULL
	},
	{ 	CSSM_ALGID_RSA, 
		CSSM_KEYBLOB_RAW_FORMAT_X509, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
		512, NULL
	},
	{ 	CSSM_ALGID_RSA, 
		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_PKCS1,
		512, NULL
	},
	{ 	CSSM_ALGID_RSA, 
		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
		512, NULL
	},
	
	/* ECDSA */
	{	CSSM_ALGID_ECDSA,
		CSSM_KEYBLOB_RAW_FORMAT_NONE, CSSM_KEYBLOB_RAW_FORMAT_NONE,
		192, NULL 
	},
	{	CSSM_ALGID_ECDSA,
		CSSM_KEYBLOB_RAW_FORMAT_X509, CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
		256, NULL 
	},
	{	CSSM_ALGID_ECDSA,
		CSSM_KEYBLOB_RAW_FORMAT_NONE, CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
		384, NULL 
	},
	{	CSSM_ALGID_ECDSA,
		CSSM_KEYBLOB_RAW_FORMAT_X509, CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
		521, NULL 
	},

	/* DSA */
	{ 	CSSM_ALGID_DSA, 
		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
		512, &dsa512Params
	},
	{ 	CSSM_ALGID_DSA, 
		CSSM_KEYBLOB_RAW_FORMAT_FIPS186, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
		512, &dsa512Params
	},
	{ 	CSSM_ALGID_DSA, 
		CSSM_KEYBLOB_RAW_FORMAT_X509, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
		512, &dsa512Params
	},
	{ 	CSSM_ALGID_DSA, 
		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_FIPS186,
		512, &dsa512Params
	},
	{ 	CSSM_ALGID_DSA, 
		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_OPENSSL,
		512, &dsa512Params
	},
	{ 	CSSM_ALGID_DSA, 
		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
		512, &dsa512Params
	},
	{ 	CSSM_ALGID_DSA, 
		CSSM_KEYBLOB_RAW_FORMAT_X509, 	CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
		512, &dsa512Params
	},
	
	/* Diffie-Hellman */
	{ 	CSSM_ALGID_DH, 
		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
		512, &dh512Params
	},
	{ 	CSSM_ALGID_DH, 
		CSSM_KEYBLOB_RAW_FORMAT_PKCS3, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
		512, &dh512Params
	},
	{ 	CSSM_ALGID_DH, 
		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_PKCS3,
		512, &dh512Params
	},
	{ 	CSSM_ALGID_DH, 
		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
		512, &dh512Params
	},
	{ 	CSSM_ALGID_DH, 
		CSSM_KEYBLOB_RAW_FORMAT_X509, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
		512, &dh512Params
	},
	{ 	CSSM_ALGID_DH, 
		CSSM_KEYBLOB_RAW_FORMAT_X509, 	CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
		512, &dh512Params
	},
	
	/* FEE */
	{	CSSM_ALGID_FEE,
		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
		127, NULL 
	},
	{	CSSM_ALGID_FEE,
		CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
		128, NULL 
	},
	{	CSSM_ALGID_FEE,
		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING,
		161, NULL 
	},
	{	CSSM_ALGID_FEE,
		CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING, 	
		CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING,
		192, NULL 
	},
	
};
#define NUM_TEST_PARAMS\
	(sizeof(KeyHashTestParams) / sizeof(KeyHashTestParams[0]))

static void dumpBuf(uint8 *buf,
	unsigned len)
{
	unsigned i;
	
	printf("   ");
	for(i=0; i<len; i++) {
		printf("%02X ", buf[i]);
		if((i % 24) == 23) {
			printf("\n      ");
		}
	}
	printf("\n");
}

const char *formStr(CSSM_KEYBLOB_FORMAT form)
{
	switch(form) {
		case CSSM_KEYBLOB_RAW_FORMAT_NONE: return "NONE";
		case CSSM_KEYBLOB_RAW_FORMAT_PKCS1: return "PKCS1";
		case CSSM_KEYBLOB_RAW_FORMAT_PKCS3: return "PKCS3";
		case CSSM_KEYBLOB_RAW_FORMAT_FIPS186: return "FIPS186";
		case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: return "PKCS8";
		case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: return "OCTET_STRING";
		case CSSM_KEYBLOB_RAW_FORMAT_OTHER: return "OTHER";
		case CSSM_KEYBLOB_RAW_FORMAT_X509: return "X509";
		case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH: return "OPENSSH";
		case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL: return "OPENSSL";
		default: 
			printf("**BRRZAP! formStr needs work\n");
			exit(1);
	}
}

const char *algStr(CSSM_ALGORITHMS alg)
{
	switch(alg) {
		case CSSM_ALGID_RSA: return "RSA";
		case CSSM_ALGID_DSA: return "DSA";
		case CSSM_ALGID_DH: return "DH";
		case CSSM_ALGID_FEE: return "FEE";
		case CSSM_ALGID_ECDSA: return "ECDSA";
		default: 
			printf("**BRRZAP! algStr needs work\n");
			exit(1);
	}
}

static void showTestParams(KeyHashTest *testParam)
{
	printf("alg %s  pubForm %s  privForm %s\n",
			algStr(testParam->keyAlg),
		formStr(testParam->pubKeyForm),
		formStr(testParam->privKeyForm));

}

/*
 * Generate key pair of specified alg and raw format. 
 * Alg params are optional, though they are expected to be here
 * for DH and DSA.
 */
static CSSM_RETURN genKeyPair(
	CSSM_CSP_HANDLE cspHand,
	CSSM_ALGORITHMS keyAlg,
	uint32 keySize,					// in bits
	CSSM_KEY_PTR pubKey,			
	CSSM_KEYBLOB_FORMAT pubFormat,
	CSSM_KEY_PTR privKey,			
	CSSM_KEYBLOB_FORMAT privFormat,
	const CSSM_DATA	*inParams)		// optional 
{
	CSSM_RETURN				crtn;
	CSSM_CC_HANDLE 			ccHand;
	CSSM_DATA				keyLabelData;
	CSSM_RETURN 			ocrtn = CSSM_OK;
	
	keyLabelData.Data        = (uint8 *)USAGE_NAME,
	keyLabelData.Length      = USAGE_NAME_LEN;
	memset(pubKey, 0, sizeof(CSSM_KEY));
	memset(privKey, 0, sizeof(CSSM_KEY));
	
	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
		keyAlg,
		keySize,
		NULL,					// Seed
		NULL,					// Salt
		NULL,					// StartDate
		NULL,					// EndDate
		inParams,				// Params, may be NULL
		&ccHand);
	if(crtn) {
		printError("CSSM_CSP_CreateKeyGenContext", crtn);
		return crtn;
	}
	
	/* optional format specifiers */
	if(pubFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE) {
		crtn = AddContextAttribute(ccHand,
			CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT,
			sizeof(uint32),	
			CAT_Uint32,
			NULL,
			pubFormat);
		if(crtn) {
				printError("AddContextAttribute("
					"CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT)", crtn);
			return crtn;
		}
	}
	if(privFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE) {
		crtn = AddContextAttribute(ccHand,
			CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT,
			sizeof(uint32),
			CAT_Uint32,
			NULL,
			privFormat);
		if(crtn) {
			printError("AddContextAttribute("
				"CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT)", crtn);
			return crtn;
		}
	}
	CSSM_KEYATTR_FLAGS attrFlags = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
	crtn = CSSM_GenerateKeyPair(ccHand,
		CSSM_KEYUSE_DERIVE,
		attrFlags,
		&keyLabelData,
		pubKey,
		CSSM_KEYUSE_DERIVE,
		attrFlags,
		&keyLabelData,			// same labels
		NULL,					// CredAndAclEntry
		privKey);
	if(crtn) {
		printError("CSSM_GenerateKeyPair", crtn);
		ocrtn = crtn;
	}
	if(ccHand != 0) {
		crtn = CSSM_DeleteContext(ccHand);
		if(crtn) {
			printError("CSSM_DeleteContext", crtn);
			ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
		}
	}
	return ocrtn;
}

/*
 * Given two keys (presumably, in this test, one a raw key and 
 * one an equivalent ref key), calculate the key digest of both of them
 * and ensure they're the same. 
 */
static int compareKeyHashes(
	const CSSM_DATA *key1Hash,
	const char *key1Descr,
	const CSSM_DATA *key2Hash,
	const char *key2Descr,
	CSSM_BOOL verbose)
{
	if(appCompareCssmData(key1Hash, key2Hash)) {
		return 0;
	}
	printf("***Key Digest miscompare (%s,%s)***\n", key1Descr, key2Descr);
	if(!verbose) {
		printf("...%s hash:\n", key1Descr);
		dumpBuf(key1Hash->Data, key1Hash->Length);
		printf("...%s hash:\n", key2Descr);
		dumpBuf(key2Hash->Data, key2Hash->Length);
	}
	return 1;
}

/*
 * Given a KeyHashTest:
 *	-- cook up key pair, raw, specified formats
 *  -- NULL unwrap each raw to ref;
 *  -- obtain four key digests;
 *  -- ensure all digests match;
 */
static int doTest(
	CSSM_CSP_HANDLE		rawCspHand,		// generate keys here
	CSSM_CSP_HANDLE		refCspHand,		// null unwrap here
	KeyHashTest			*testParam,
	CSSM_BOOL			verbose,
	CSSM_BOOL			quiet)
{
	CSSM_RETURN crtn;
	CSSM_KEY pubKey;
	CSSM_KEY privKey;
	CSSM_KEY pubKeyRef;			
	CSSM_KEY privKeyRef;
	CSSM_DATA_PTR rawPubHash;
	CSSM_DATA_PTR rawPrivHash;
	CSSM_DATA_PTR refPubHash;
	CSSM_DATA_PTR refPrivHash;
	int rtn = 0;
	
	/* generate key pair, specified raw form */
	crtn = genKeyPair(rawCspHand,
		testParam->keyAlg,
		testParam->keySizeInBits,
		&pubKey,
		testParam->pubKeyForm,
		&privKey,
		testParam->privKeyForm,
		testParam->algParams);
	if(crtn) {
		return testError(quiet);
	}
	
	/* null unwrap both raw keys to ref form */
	crtn = cspRawKeyToRef(refCspHand, &pubKey, &pubKeyRef);
	if(crtn) {
		return testError(quiet);
	}
	crtn = cspRawKeyToRef(refCspHand, &privKey, &privKeyRef);
	if(crtn) {
		return testError(quiet);
	}
	
	/* calculate four key digests */
	crtn = cspKeyHash(rawCspHand, &pubKey, &rawPubHash);
	if(crtn) {
		return testError(quiet);
	}
	crtn = cspKeyHash(rawCspHand, &privKey, &rawPrivHash);
	if(crtn) {
		return testError(quiet);
	}
	crtn = cspKeyHash(refCspHand, &pubKeyRef, &refPubHash);
	if(crtn) {
		return testError(quiet);
	}
	crtn = cspKeyHash(refCspHand, &privKeyRef, &refPrivHash);
	if(crtn) {
		return testError(quiet);
	}

	if(verbose) {
		printf("...raw pub key hash:\n");
		dumpBuf(rawPubHash->Data, rawPubHash->Length);
		printf("...ref pub key hash:\n");
		dumpBuf(refPubHash->Data, refPubHash->Length);
		printf("...raw priv key hash:\n");
		dumpBuf(rawPrivHash->Data, rawPrivHash->Length);
		printf("...ref priv key hash:\n");
		dumpBuf(refPrivHash->Data, refPrivHash->Length);
	}

	/* compare */
	rtn += compareKeyHashes(rawPubHash, "Raw public",
		refPubHash, "Ref public", verbose);
	rtn += compareKeyHashes(rawPrivHash, "Raw private",
		refPrivHash, "Ref private", verbose);
	rtn += compareKeyHashes(refPubHash, "Ref public",
		refPrivHash, "Ref private", verbose);
	if(rtn) {
		rtn = testError(quiet);
	}
	cspFreeKey(rawCspHand, &pubKey);
	cspFreeKey(rawCspHand, &privKey);
	cspFreeKey(refCspHand, &pubKeyRef);
	cspFreeKey(refCspHand, &privKeyRef);
	appFreeCssmData(rawPubHash, CSSM_TRUE);
	appFreeCssmData(rawPrivHash, CSSM_TRUE);
	appFreeCssmData(refPubHash, CSSM_TRUE);
	appFreeCssmData(refPrivHash, CSSM_TRUE);
	return rtn;
}

int main(int argc, char **argv)
{
	int					arg;
	char				*argp;
	unsigned			loop;
	CSSM_CSP_HANDLE 	rawCspHand;		// always Raw CSP
	CSSM_CSP_HANDLE		refCspHand;		// CSPDL if !bareCsp
	int					rtn = 0;
	int					i;
	unsigned			len;
	
	/*
	 * User-spec'd params
	 */
	unsigned			loops = LOOPS_DEF;
	CSSM_BOOL			verbose = CSSM_FALSE;
	CSSM_BOOL			quiet = CSSM_FALSE;
	CSSM_BOOL			bareCsp = CSSM_TRUE;
	CSSM_BOOL			doPause = CSSM_FALSE;
	
	for(arg=1; arg<argc; arg++) {
		argp = argv[arg];
		switch(argp[0]) {
		    case 'l':
				loops = atoi(&argp[2]);
				break;
			case 'D':
				bareCsp = CSSM_FALSE;
				break;
		    case 'p':
		    	doPause = CSSM_TRUE;
				break;
		    case 'v':
		    	verbose = CSSM_TRUE;
				break;
		    case 'q':
		    	quiet = CSSM_TRUE;
				break;
		    case 'h':
		    default:
				usage(argv);
		}
	}

	/* prefetch the alg params */
	rtn = readFile(DSA_PARAM_FILE, &dsa512Params.Data, &len);
	if(rtn) {
		printf("***%s file missing. Aborting.\n", DSA_PARAM_FILE);
		exit(1);
	}
	dsa512Params.Length = len;
	rtn = readFile(DH_PARAM_FILE, &dh512Params.Data, &len);
	if(rtn) {
		printf("***%s file missing. Aborting.\n", DH_PARAM_FILE);
		exit(1);
	}
	dh512Params.Length = len;
	
	printf("Starting keyHashAsym; args: ");
	for(i=1; i<argc; i++) {
		printf("%s ", argv[i]);
	}
	printf("\n");
	refCspHand = cspDlDbStartup(bareCsp, NULL);
	if(refCspHand == 0) {
		exit(1);
	}
	if(bareCsp) {
		/* raw and ref on same CSP */
		rawCspHand = refCspHand;
	}
	else {
		/* generate on CSPDL, NULL unwrap to bare CSP */
		rawCspHand = cspDlDbStartup(CSSM_TRUE, NULL);
		if(rawCspHand == 0) {
			exit(1);
		}
	}
	for(loop=1; ; loop++) {
		if(!quiet) {
			printf("...loop %d\n", loop);
		}
		for(unsigned testNum=0; testNum<NUM_TEST_PARAMS; testNum++) {
			KeyHashTest *testParams = &KeyHashTestParams[testNum];
			if(!quiet) {
				printf("..."); showTestParams(testParams);
			}
			rtn = doTest(rawCspHand, refCspHand, testParams, verbose, quiet);
			if(rtn) {
				goto done;
			}
			if(doPause) {
				fpurge(stdin);
				printf("Hit CR to proceed: ");
				getchar();
			}
		}
		if(loops && (loop == loops)) {
			break;
		}
	}
done:
	if((rtn == 0) && !quiet) {
		printf("...%s complete\n", argv[0]);
	}
	return rtn;
}