1/*
2 * keyHashAsym.c - CSSM_APPLECSP_KEYDIGEST passthrough test for all
3 *				   known asymmetric algorithms and key formats
4 */
5
6#include <stdlib.h>
7#include <stdio.h>
8#include <time.h>
9#include <string.h>
10#include <Security/cssm.h>
11#include "cspwrap.h"
12#include "common.h"
13#include "cspdlTesting.h"
14#include <security_cdsa_utils/cuFileIo.h>
15
16#define USAGE_NAME			"noUsage"
17#define USAGE_NAME_LEN		(strlen(USAGE_NAME))
18#define LOOPS_DEF			10
19
20#define DSA_PARAM_FILE		"dsaParams_512.der"
21#define DH_PARAM_FILE		"dhParams_512.der"
22
23static void usage(char **argv)
24{
25	printf("usage: %s [options]\n", argv[0]);
26	printf("Options:\n");
27	printf("  l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
28	printf("  D (CSP/DL; default = bare CSP)\n");
29	printf("  p(ause on each loop)\n");
30	printf("  q(uiet)\n");
31	printf("  v(erbose))\n");
32	exit(1);
33}
34
35static CSSM_DATA	dsa512Params;
36static CSSM_DATA	dh512Params;
37
38/*
39 * Describe parameters for one test iteration.
40 */
41typedef struct {
42	CSSM_ALGORITHMS		keyAlg;
43	CSSM_KEYBLOB_FORMAT	pubKeyForm;
44	CSSM_KEYBLOB_FORMAT	privKeyForm;
45	uint32				keySizeInBits;
46	CSSM_DATA			*algParams;		// optional
47} KeyHashTest;
48
49KeyHashTest KeyHashTestParams[] =
50{
51	/* RSA */
52	{ 	CSSM_ALGID_RSA,
53		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
54		512, NULL
55	},
56	{ 	CSSM_ALGID_RSA,
57		CSSM_KEYBLOB_RAW_FORMAT_PKCS1, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
58		512, NULL
59	},
60	{ 	CSSM_ALGID_RSA,
61		CSSM_KEYBLOB_RAW_FORMAT_X509, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
62		512, NULL
63	},
64	{ 	CSSM_ALGID_RSA,
65		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_PKCS1,
66		512, NULL
67	},
68	{ 	CSSM_ALGID_RSA,
69		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
70		512, NULL
71	},
72
73	/* ECDSA */
74	{	CSSM_ALGID_ECDSA,
75		CSSM_KEYBLOB_RAW_FORMAT_NONE, CSSM_KEYBLOB_RAW_FORMAT_NONE,
76		192, NULL
77	},
78	{	CSSM_ALGID_ECDSA,
79		CSSM_KEYBLOB_RAW_FORMAT_X509, CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
80		256, NULL
81	},
82	{	CSSM_ALGID_ECDSA,
83		CSSM_KEYBLOB_RAW_FORMAT_NONE, CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
84		384, NULL
85	},
86	{	CSSM_ALGID_ECDSA,
87		CSSM_KEYBLOB_RAW_FORMAT_X509, CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
88		521, NULL
89	},
90
91	/* DSA */
92	{ 	CSSM_ALGID_DSA,
93		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
94		512, &dsa512Params
95	},
96	{ 	CSSM_ALGID_DSA,
97		CSSM_KEYBLOB_RAW_FORMAT_FIPS186, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
98		512, &dsa512Params
99	},
100	{ 	CSSM_ALGID_DSA,
101		CSSM_KEYBLOB_RAW_FORMAT_X509, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
102		512, &dsa512Params
103	},
104	{ 	CSSM_ALGID_DSA,
105		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_FIPS186,
106		512, &dsa512Params
107	},
108	{ 	CSSM_ALGID_DSA,
109		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_OPENSSL,
110		512, &dsa512Params
111	},
112	{ 	CSSM_ALGID_DSA,
113		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
114		512, &dsa512Params
115	},
116	{ 	CSSM_ALGID_DSA,
117		CSSM_KEYBLOB_RAW_FORMAT_X509, 	CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
118		512, &dsa512Params
119	},
120
121	/* Diffie-Hellman */
122	{ 	CSSM_ALGID_DH,
123		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
124		512, &dh512Params
125	},
126	{ 	CSSM_ALGID_DH,
127		CSSM_KEYBLOB_RAW_FORMAT_PKCS3, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
128		512, &dh512Params
129	},
130	{ 	CSSM_ALGID_DH,
131		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_PKCS3,
132		512, &dh512Params
133	},
134	{ 	CSSM_ALGID_DH,
135		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
136		512, &dh512Params
137	},
138	{ 	CSSM_ALGID_DH,
139		CSSM_KEYBLOB_RAW_FORMAT_X509, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
140		512, &dh512Params
141	},
142	{ 	CSSM_ALGID_DH,
143		CSSM_KEYBLOB_RAW_FORMAT_X509, 	CSSM_KEYBLOB_RAW_FORMAT_PKCS8,
144		512, &dh512Params
145	},
146
147	/* FEE */
148	{	CSSM_ALGID_FEE,
149		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
150		127, NULL
151	},
152	{	CSSM_ALGID_FEE,
153		CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING, 	CSSM_KEYBLOB_RAW_FORMAT_NONE,
154		128, NULL
155	},
156	{	CSSM_ALGID_FEE,
157		CSSM_KEYBLOB_RAW_FORMAT_NONE, 	CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING,
158		161, NULL
159	},
160	{	CSSM_ALGID_FEE,
161		CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING,
162		CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING,
163		192, NULL
164	},
165
166};
167#define NUM_TEST_PARAMS\
168	(sizeof(KeyHashTestParams) / sizeof(KeyHashTestParams[0]))
169
170static void dumpBuf(uint8 *buf,
171	unsigned len)
172{
173	unsigned i;
174
175	printf("   ");
176	for(i=0; i<len; i++) {
177		printf("%02X ", buf[i]);
178		if((i % 24) == 23) {
179			printf("\n      ");
180		}
181	}
182	printf("\n");
183}
184
185const char *formStr(CSSM_KEYBLOB_FORMAT form)
186{
187	switch(form) {
188		case CSSM_KEYBLOB_RAW_FORMAT_NONE: return "NONE";
189		case CSSM_KEYBLOB_RAW_FORMAT_PKCS1: return "PKCS1";
190		case CSSM_KEYBLOB_RAW_FORMAT_PKCS3: return "PKCS3";
191		case CSSM_KEYBLOB_RAW_FORMAT_FIPS186: return "FIPS186";
192		case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: return "PKCS8";
193		case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: return "OCTET_STRING";
194		case CSSM_KEYBLOB_RAW_FORMAT_OTHER: return "OTHER";
195		case CSSM_KEYBLOB_RAW_FORMAT_X509: return "X509";
196		case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH: return "OPENSSH";
197		case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL: return "OPENSSL";
198		default:
199			printf("**BRRZAP! formStr needs work\n");
200			exit(1);
201	}
202}
203
204const char *algStr(CSSM_ALGORITHMS alg)
205{
206	switch(alg) {
207		case CSSM_ALGID_RSA: return "RSA";
208		case CSSM_ALGID_DSA: return "DSA";
209		case CSSM_ALGID_DH: return "DH";
210		case CSSM_ALGID_FEE: return "FEE";
211		case CSSM_ALGID_ECDSA: return "ECDSA";
212		default:
213			printf("**BRRZAP! algStr needs work\n");
214			exit(1);
215	}
216}
217
218static void showTestParams(KeyHashTest *testParam)
219{
220	printf("alg %s  pubForm %s  privForm %s\n",
221			algStr(testParam->keyAlg),
222		formStr(testParam->pubKeyForm),
223		formStr(testParam->privKeyForm));
224
225}
226
227/*
228 * Generate key pair of specified alg and raw format.
229 * Alg params are optional, though they are expected to be here
230 * for DH and DSA.
231 */
232static CSSM_RETURN genKeyPair(
233	CSSM_CSP_HANDLE cspHand,
234	CSSM_ALGORITHMS keyAlg,
235	uint32 keySize,					// in bits
236	CSSM_KEY_PTR pubKey,
237	CSSM_KEYBLOB_FORMAT pubFormat,
238	CSSM_KEY_PTR privKey,
239	CSSM_KEYBLOB_FORMAT privFormat,
240	const CSSM_DATA	*inParams)		// optional
241{
242	CSSM_RETURN				crtn;
243	CSSM_CC_HANDLE 			ccHand;
244	CSSM_DATA				keyLabelData;
245	CSSM_RETURN 			ocrtn = CSSM_OK;
246
247	keyLabelData.Data        = (uint8 *)USAGE_NAME,
248	keyLabelData.Length      = USAGE_NAME_LEN;
249	memset(pubKey, 0, sizeof(CSSM_KEY));
250	memset(privKey, 0, sizeof(CSSM_KEY));
251
252	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
253		keyAlg,
254		keySize,
255		NULL,					// Seed
256		NULL,					// Salt
257		NULL,					// StartDate
258		NULL,					// EndDate
259		inParams,				// Params, may be NULL
260		&ccHand);
261	if(crtn) {
262		printError("CSSM_CSP_CreateKeyGenContext", crtn);
263		return crtn;
264	}
265
266	/* optional format specifiers */
267	if(pubFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE) {
268		crtn = AddContextAttribute(ccHand,
269			CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT,
270			sizeof(uint32),
271			CAT_Uint32,
272			NULL,
273			pubFormat);
274		if(crtn) {
275				printError("AddContextAttribute("
276					"CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT)", crtn);
277			return crtn;
278		}
279	}
280	if(privFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE) {
281		crtn = AddContextAttribute(ccHand,
282			CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT,
283			sizeof(uint32),
284			CAT_Uint32,
285			NULL,
286			privFormat);
287		if(crtn) {
288			printError("AddContextAttribute("
289				"CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT)", crtn);
290			return crtn;
291		}
292	}
293	CSSM_KEYATTR_FLAGS attrFlags = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
294	crtn = CSSM_GenerateKeyPair(ccHand,
295		CSSM_KEYUSE_DERIVE,
296		attrFlags,
297		&keyLabelData,
298		pubKey,
299		CSSM_KEYUSE_DERIVE,
300		attrFlags,
301		&keyLabelData,			// same labels
302		NULL,					// CredAndAclEntry
303		privKey);
304	if(crtn) {
305		printError("CSSM_GenerateKeyPair", crtn);
306		ocrtn = crtn;
307	}
308	if(ccHand != 0) {
309		crtn = CSSM_DeleteContext(ccHand);
310		if(crtn) {
311			printError("CSSM_DeleteContext", crtn);
312			ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
313		}
314	}
315	return ocrtn;
316}
317
318/*
319 * Given two keys (presumably, in this test, one a raw key and
320 * one an equivalent ref key), calculate the key digest of both of them
321 * and ensure they're the same.
322 */
323static int compareKeyHashes(
324	const CSSM_DATA *key1Hash,
325	const char *key1Descr,
326	const CSSM_DATA *key2Hash,
327	const char *key2Descr,
328	CSSM_BOOL verbose)
329{
330	if(appCompareCssmData(key1Hash, key2Hash)) {
331		return 0;
332	}
333	printf("***Key Digest miscompare (%s,%s)***\n", key1Descr, key2Descr);
334	if(!verbose) {
335		printf("...%s hash:\n", key1Descr);
336		dumpBuf(key1Hash->Data, key1Hash->Length);
337		printf("...%s hash:\n", key2Descr);
338		dumpBuf(key2Hash->Data, key2Hash->Length);
339	}
340	return 1;
341}
342
343/*
344 * Given a KeyHashTest:
345 *	-- cook up key pair, raw, specified formats
346 *  -- NULL unwrap each raw to ref;
347 *  -- obtain four key digests;
348 *  -- ensure all digests match;
349 */
350static int doTest(
351	CSSM_CSP_HANDLE		rawCspHand,		// generate keys here
352	CSSM_CSP_HANDLE		refCspHand,		// null unwrap here
353	KeyHashTest			*testParam,
354	CSSM_BOOL			verbose,
355	CSSM_BOOL			quiet)
356{
357	CSSM_RETURN crtn;
358	CSSM_KEY pubKey;
359	CSSM_KEY privKey;
360	CSSM_KEY pubKeyRef;
361	CSSM_KEY privKeyRef;
362	CSSM_DATA_PTR rawPubHash;
363	CSSM_DATA_PTR rawPrivHash;
364	CSSM_DATA_PTR refPubHash;
365	CSSM_DATA_PTR refPrivHash;
366	int rtn = 0;
367
368	/* generate key pair, specified raw form */
369	crtn = genKeyPair(rawCspHand,
370		testParam->keyAlg,
371		testParam->keySizeInBits,
372		&pubKey,
373		testParam->pubKeyForm,
374		&privKey,
375		testParam->privKeyForm,
376		testParam->algParams);
377	if(crtn) {
378		return testError(quiet);
379	}
380
381	/* null unwrap both raw keys to ref form */
382	crtn = cspRawKeyToRef(refCspHand, &pubKey, &pubKeyRef);
383	if(crtn) {
384		return testError(quiet);
385	}
386	crtn = cspRawKeyToRef(refCspHand, &privKey, &privKeyRef);
387	if(crtn) {
388		return testError(quiet);
389	}
390
391	/* calculate four key digests */
392	crtn = cspKeyHash(rawCspHand, &pubKey, &rawPubHash);
393	if(crtn) {
394		return testError(quiet);
395	}
396	crtn = cspKeyHash(rawCspHand, &privKey, &rawPrivHash);
397	if(crtn) {
398		return testError(quiet);
399	}
400	crtn = cspKeyHash(refCspHand, &pubKeyRef, &refPubHash);
401	if(crtn) {
402		return testError(quiet);
403	}
404	crtn = cspKeyHash(refCspHand, &privKeyRef, &refPrivHash);
405	if(crtn) {
406		return testError(quiet);
407	}
408
409	if(verbose) {
410		printf("...raw pub key hash:\n");
411		dumpBuf(rawPubHash->Data, rawPubHash->Length);
412		printf("...ref pub key hash:\n");
413		dumpBuf(refPubHash->Data, refPubHash->Length);
414		printf("...raw priv key hash:\n");
415		dumpBuf(rawPrivHash->Data, rawPrivHash->Length);
416		printf("...ref priv key hash:\n");
417		dumpBuf(refPrivHash->Data, refPrivHash->Length);
418	}
419
420	/* compare */
421	rtn += compareKeyHashes(rawPubHash, "Raw public",
422		refPubHash, "Ref public", verbose);
423	rtn += compareKeyHashes(rawPrivHash, "Raw private",
424		refPrivHash, "Ref private", verbose);
425	rtn += compareKeyHashes(refPubHash, "Ref public",
426		refPrivHash, "Ref private", verbose);
427	if(rtn) {
428		rtn = testError(quiet);
429	}
430	cspFreeKey(rawCspHand, &pubKey);
431	cspFreeKey(rawCspHand, &privKey);
432	cspFreeKey(refCspHand, &pubKeyRef);
433	cspFreeKey(refCspHand, &privKeyRef);
434	appFreeCssmData(rawPubHash, CSSM_TRUE);
435	appFreeCssmData(rawPrivHash, CSSM_TRUE);
436	appFreeCssmData(refPubHash, CSSM_TRUE);
437	appFreeCssmData(refPrivHash, CSSM_TRUE);
438	return rtn;
439}
440
441int main(int argc, char **argv)
442{
443	int					arg;
444	char				*argp;
445	unsigned			loop;
446	CSSM_CSP_HANDLE 	rawCspHand;		// always Raw CSP
447	CSSM_CSP_HANDLE		refCspHand;		// CSPDL if !bareCsp
448	int					rtn = 0;
449	int					i;
450	unsigned			len;
451
452	/*
453	 * User-spec'd params
454	 */
455	unsigned			loops = LOOPS_DEF;
456	CSSM_BOOL			verbose = CSSM_FALSE;
457	CSSM_BOOL			quiet = CSSM_FALSE;
458	CSSM_BOOL			bareCsp = CSSM_TRUE;
459	CSSM_BOOL			doPause = CSSM_FALSE;
460
461	for(arg=1; arg<argc; arg++) {
462		argp = argv[arg];
463		switch(argp[0]) {
464		    case 'l':
465				loops = atoi(&argp[2]);
466				break;
467			case 'D':
468				bareCsp = CSSM_FALSE;
469				break;
470		    case 'p':
471		    	doPause = CSSM_TRUE;
472				break;
473		    case 'v':
474		    	verbose = CSSM_TRUE;
475				break;
476		    case 'q':
477		    	quiet = CSSM_TRUE;
478				break;
479		    case 'h':
480		    default:
481				usage(argv);
482		}
483	}
484
485	/* prefetch the alg params */
486	rtn = readFile(DSA_PARAM_FILE, &dsa512Params.Data, &len);
487	if(rtn) {
488		printf("***%s file missing. Aborting.\n", DSA_PARAM_FILE);
489		exit(1);
490	}
491	dsa512Params.Length = len;
492	rtn = readFile(DH_PARAM_FILE, &dh512Params.Data, &len);
493	if(rtn) {
494		printf("***%s file missing. Aborting.\n", DH_PARAM_FILE);
495		exit(1);
496	}
497	dh512Params.Length = len;
498
499	printf("Starting keyHashAsym; args: ");
500	for(i=1; i<argc; i++) {
501		printf("%s ", argv[i]);
502	}
503	printf("\n");
504	refCspHand = cspDlDbStartup(bareCsp, NULL);
505	if(refCspHand == 0) {
506		exit(1);
507	}
508	if(bareCsp) {
509		/* raw and ref on same CSP */
510		rawCspHand = refCspHand;
511	}
512	else {
513		/* generate on CSPDL, NULL unwrap to bare CSP */
514		rawCspHand = cspDlDbStartup(CSSM_TRUE, NULL);
515		if(rawCspHand == 0) {
516			exit(1);
517		}
518	}
519	for(loop=1; ; loop++) {
520		if(!quiet) {
521			printf("...loop %d\n", loop);
522		}
523		for(unsigned testNum=0; testNum<NUM_TEST_PARAMS; testNum++) {
524			KeyHashTest *testParams = &KeyHashTestParams[testNum];
525			if(!quiet) {
526				printf("..."); showTestParams(testParams);
527			}
528			rtn = doTest(rawCspHand, refCspHand, testParams, verbose, quiet);
529			if(rtn) {
530				goto done;
531			}
532			if(doPause) {
533				fpurge(stdin);
534				printf("Hit CR to proceed: ");
535				getchar();
536			}
537		}
538		if(loops && (loop == loops)) {
539			break;
540		}
541	}
542done:
543	if((rtn == 0) && !quiet) {
544		printf("...%s complete\n", argv[0]);
545	}
546	return rtn;
547}
548