1/*
2 * cgConstruct.c - basic test of TP's CertGroupConstruct
3 *
4 * cook up array of n key pairs;
5 * cook up cert chain to go with them;
6 * main test loop {
7 * 	pick a random spot to break the cert chain - half the time use the
8 *		whole chain, half the time break it;
9 * 	cook up CertGroup frag big enough for the unbroken part of the chain;
10 * 	put cert[0] in certGroup[0];
11 * 	for each cert from cert[1] to break point {
12 *		roll the  dice and put the cert in either a random place
13 *			in certGroup or in DB;
14 * 	}
15 *  resultGroup = certGroupConstruct();
16 *  vfy result Grp is identical to unbroken part of chain;
17 *  delete certs from DB;
18 * }
19 */
20
21#include <Security/cssm.h>
22#include <utilLib/common.h>
23#include <utilLib/cspwrap.h>
24#include <clAppUtils/clutils.h>
25#include <clAppUtils/tpUtils.h>
26#include <clAppUtils/timeStr.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <time.h>
30#include <string.h>
31
32#define NUM_CERTS_DEF		10
33#define NUM_DBS_DEF			3
34#define KEYGEN_ALG_DEF		CSSM_ALGID_RSA
35#define SIG_ALG_DEF			CSSM_ALGID_SHA1WithRSA
36#define LOOPS_DEF			10
37#define DB_NAME_BASE		"cgConstruct"	/* default */
38#define SECONDS_TO_LIVE		(60 * 60 * 24)	/* certs are valid for this long */
39
40/* Read-only access not supported */
41#define PUBLIC_READ_ENABLE	0
42
43static void usage(char **argv)
44{
45	printf("Usage: %s [options]\n", argv[0]);
46	printf("   Options:\n");
47	printf("   n=numCerts; default = %d\n", NUM_CERTS_DEF);
48	printf("   l=loops; default=%d; 0=forever\n", LOOPS_DEF);
49	printf("   a=alg (f=FEE/MD5, f=FEE/SHA1, e=FEE/ECDSA, r=RSA, E=ANSI ECDSA; default = RSA\n");
50	printf("   K=keySizeInBits\n");
51	#if	TP_DB_ENABLE
52	printf("   d=numDBs, default = %d\n", NUM_DBS_DEF);
53	printf("   A(ll certs to DBs)\n");
54	printf("   k (skip first DB when storing)\n");
55	#if PUBLIC_READ_ENABLE
56	printf("   p(ublic access open on read)\n");
57	#endif
58	#endif
59	printf("   f=fileNameBase (default = %s)\n", DB_NAME_BASE);
60	printf("   P(ause on each loop)\n");
61	printf("   v(erbose)\n");
62	printf("   q(uiet)\n");
63	printf("   h(elp)\n");
64	exit(1);
65}
66
67#if TP_DB_ENABLE
68static int doOpenDbs(
69	CSSM_DL_HANDLE			dlHand,
70	const char 				*dbNameBase,
71	CSSM_DL_DB_HANDLE_PTR 	dlDbPtr,
72	unsigned 				numDbs,
73	CSSM_BOOL 				publicReadOnly,		// ignored if !PUBLIC_READ_ENABLE
74	CSSM_BOOL				quiet)
75{
76	unsigned i;
77	char dbName[20];
78	CSSM_BOOL doCreate = (publicReadOnly ? CSSM_FALSE : CSSM_TRUE);
79
80	for(i=0; i<numDbs; i++) {
81		dlDbPtr[i].DLHandle = dlHand;
82		sprintf(dbName, "%s%d", dbNameBase, i);
83		CSSM_RETURN crtn = tpKcOpen(dlHand, dbName,
84			dbName,			// file name as pwd
85			doCreate,
86			&dlDbPtr[i].DBHandle);
87		if(crtn) {
88			printf("Can't create %d DBs\n", numDbs);
89			return testError(quiet);
90		}
91	}
92	return 0;
93}
94#endif
95
96static int doTest(
97	CSSM_TP_HANDLE		tpHand,
98	CSSM_CL_HANDLE		clHand,
99	CSSM_CSP_HANDLE		cspHand,
100	CSSM_DL_HANDLE		dlHand,
101	CSSM_DL_DB_LIST_PTR	dbList,
102	CSSM_DATA_PTR		certs,
103	unsigned			numCerts,
104	CSSM_BOOL			verbose,
105	CSSM_BOOL			allInDbs,
106	CSSM_BOOL			skipFirstDb,
107	CSSM_BOOL			publicRead,		// close/open with public access
108	const char			*fileBaseName,
109	CSSM_BOOL			quiet)
110{
111	unsigned				certsToUse;		// # of certs we actually use
112	CSSM_CERTGROUP			certGroupFrag;	// INPUT to CertGroupConstruct
113	CSSM_CERTGROUP_PTR		resultGroup;	// OUTPUT from "
114	unsigned				certDex;
115	int						rtn = 0;
116	CSSM_RETURN				crtn;
117
118	#if	TP_DB_ENABLE
119	if(publicRead && (dbList != NULL)) {
120		/* DBs are closed on entry, open r/w */
121		if(doOpenDbs(dlHand,
122				fileBaseName,
123				dbList->DLDBHandle,
124				dbList->NumHandles,
125				CSSM_FALSE,
126				quiet)) {		// publicReadOnly: this is create/write
127			return 1;
128		}
129	}
130	/* else DBs are already open and stay that way */
131	#endif
132
133	/*
134	 * Pick a random spot to break the cert chain - half the time use the
135	 * whole chain, half the time break it.
136	 */
137	certsToUse = genRand(1, numCerts * 2);
138	if(certsToUse > numCerts) {
139		/* use the whole chain */
140		certsToUse = numCerts;
141	}
142 	if(verbose) {
143 		printf("   ...numCerts %d  certsToUse %d\n", numCerts, certsToUse);
144 	}
145
146 	if(tpMakeRandCertGroup(clHand,
147			#if		TP_DB_ENABLE
148	 		dbList,
149			#else
150			NULL,
151			#endif
152	 		certs,
153	 		certsToUse,
154	 		&certGroupFrag,
155	 		CSSM_TRUE,			// firstCertIsSubject
156	 		verbose,
157	 		allInDbs,
158	 		skipFirstDb)) {
159	 	printf("Error in tpMakeRandCertGroup\n");
160	 	return testError(quiet);
161	}
162
163	if(certGroupFrag.NumCerts > certsToUse) {
164		printf("Error NOMAD sterlize\n");
165		exit(1);
166	}
167
168	#if	TP_DB_ENABLE
169	if(publicRead) {
170		/* close existing DBs and open again read-only */
171
172		unsigned i;
173		CSSM_RETURN crtn;
174
175		if(verbose) {
176			printf("   ...closing DBs\n");
177		}
178		for(i=0; i<dbList->NumHandles; i++) {
179			crtn = CSSM_DL_DbClose(dbList->DLDBHandle[i]);
180			if(crtn) {
181				printError("CSSM_DL_DbClose", crtn);
182				if(testError(quiet)) {
183					return 1;
184				}
185			}
186		}
187		if(verbose) {
188			printf("   ...opening DBs read-only\n");
189		}
190		if(doOpenDbs(dlHand,
191				fileBaseName,
192				dbList->DLDBHandle,
193				dbList->NumHandles,
194				CSSM_TRUE, 		// publicReadOnly: this is read only
195				quiet)) {
196			return 1;
197		}
198	}
199	#endif
200
201	/*
202	 * Okay, some of the certs we were given are in the DB, some are in
203	 * random places in certGroupFrag, some are nowhere (if certsToUse is
204	 * less than numCerts). Have the TP construct us an ordered verified
205	 * group.
206	 */
207	crtn = CSSM_TP_CertGroupConstruct(
208		tpHand,
209		clHand,
210		cspHand,
211		dbList,
212		NULL,			// ConstructParams
213		&certGroupFrag,
214		&resultGroup);
215	if(crtn) {
216		printError("CSSM_TP_CertGroupConstruct", crtn);
217		return testError(quiet);
218	}
219
220 	/* vfy resultGroup is identical to unbroken part of chain */
221 	if(verbose) {
222 		printf("   ...CSSM_TP_CertGroupConstruct returned %u certs\n",
223 			(unsigned)resultGroup->NumCerts);
224 	}
225	if(resultGroup->NumCerts != certsToUse) {
226		printf("***resultGroup->NumCerts was %u, expected %u\n",
227			(unsigned)resultGroup->NumCerts, (unsigned)certsToUse);
228		rtn = testError(quiet);
229		goto abort;
230	}
231	for(certDex=0; certDex<certsToUse; certDex++) {
232		if(!appCompareCssmData(&certs[certDex],
233					&resultGroup->GroupList.CertList[certDex])) {
234			printf("***certs[%d] miscompare\n", certDex);
235			rtn = testError(quiet);
236			goto abort;
237		}
238	}
239abort:
240	/* free resurces */
241	tpFreeCertGroup(&certGroupFrag,
242		CSSM_FALSE,			// caller malloc'd the actual certs
243		CSSM_FALSE);		// struct is on stack
244	tpFreeCertGroup(resultGroup,
245		CSSM_TRUE,			// mallocd by TP
246		CSSM_TRUE);			// ditto
247	#if	TP_DB_ENABLE
248	if(dbList != NULL) {
249		unsigned i;
250		CSSM_RETURN crtn;
251
252		if(verbose) {
253			printf("   ...deleting all certs from DBs\n");
254		}
255		for(i=0; i<dbList->NumHandles; i++) {
256			clDeleteAllCerts(dbList->DLDBHandle[i]);
257		}
258		if(publicRead) {
259			if(verbose) {
260				printf("   ...closing DBs\n");
261			}
262			for(i=0; i<dbList->NumHandles; i++) {
263				crtn = CSSM_DL_DbClose(dbList->DLDBHandle[i]);
264				if(crtn) {
265					printError("CSSM_DL_DbClose", crtn);
266					if(testError(quiet)) {
267						return 1;
268					}
269				}
270			}
271		}
272	}
273	#endif
274	return rtn;
275}
276
277int main(int argc, char **argv)
278{
279	int					arg;
280	char				*argp;
281	unsigned			loop;
282	CSSM_TP_HANDLE		tpHand = 0;
283	CSSM_CL_HANDLE		clHand = 0;
284	CSSM_CSP_HANDLE		cspHand = 0;
285	CSSM_DL_DB_LIST		dbList = {0, NULL};	/* for storing certs */
286	CSSM_DL_DB_LIST_PTR	dbListPtr;			/* pts to dbList or NULL */
287	unsigned			i;
288	char				*notAfterStr;
289	char 				*notBeforeStr;
290	CSSM_DL_HANDLE 		dlHand;
291
292	/* all three of these are arrays with numCert elements */
293	CSSM_KEY_PTR		pubKeys = NULL;
294	CSSM_KEY_PTR		privKeys = NULL;
295	CSSM_DATA_PTR		certs = NULL;
296
297	/* Keys do NOT go in the cert DB */
298	CSSM_DL_DB_HANDLE 	keyDb = {0, 0};
299
300	/*
301	 * User-spec'd params
302	 */
303	unsigned	loops = LOOPS_DEF;
304	CSSM_BOOL	verbose = CSSM_FALSE;
305	CSSM_BOOL	quiet = CSSM_FALSE;
306	unsigned	numCerts = NUM_CERTS_DEF;
307	uint32		keyGenAlg = KEYGEN_ALG_DEF;
308	uint32		sigAlg = SIG_ALG_DEF;
309	unsigned	numDBs = NUM_DBS_DEF;
310	CSSM_BOOL	allInDbs = CSSM_FALSE;
311	CSSM_BOOL	skipFirstDb = CSSM_FALSE;
312	CSSM_BOOL	publicRead = CSSM_FALSE;
313	CSSM_BOOL	doPause = CSSM_FALSE;
314	uint32		keySizeInBits = CSP_KEY_SIZE_DEFAULT;
315	const char	*fileBaseName = DB_NAME_BASE;
316
317	for(arg=1; arg<argc; arg++) {
318		argp = argv[arg];
319		switch(argp[0]) {
320		    case 'l':
321				loops = atoi(&argp[2]);
322				break;
323		    case 'n':
324				numCerts = atoi(&argp[2]);
325				break;
326		    case 'K':
327				keySizeInBits = atoi(&argp[2]);
328				break;
329		    case 'v':
330		    	verbose = CSSM_TRUE;
331				break;
332		    case 'q':
333		    	quiet = CSSM_TRUE;
334				break;
335			case 'a':
336				switch(argp[2]) {
337					case 'f':
338						keyGenAlg = CSSM_ALGID_FEE;
339						sigAlg = CSSM_ALGID_FEE_MD5;
340						break;
341					case 'F':
342						keyGenAlg = CSSM_ALGID_FEE;
343						sigAlg = CSSM_ALGID_FEE_SHA1;
344						break;
345					case 'e':
346						keyGenAlg = CSSM_ALGID_FEE;
347						sigAlg = CSSM_ALGID_SHA1WithECDSA;
348						break;
349					case 'E':
350						keyGenAlg = CSSM_ALGID_ECDSA;
351						sigAlg = CSSM_ALGID_SHA1WithECDSA;
352						break;
353					case 'r':
354						break;
355					default:
356						usage(argv);
357				}
358				break;
359			case 'd':
360				numDBs = atoi(&argp[2]);
361				break;
362			case 'A':
363				allInDbs = CSSM_TRUE;
364				break;
365			case 'k':
366				skipFirstDb = CSSM_TRUE;
367				break;
368			#if PUBLIC_READ_ENABLE
369			case 'p':
370				publicRead = CSSM_TRUE;
371				break;
372			#endif
373			case 'f':
374				fileBaseName = &argp[2];
375				break;
376			case 'P':
377				doPause = CSSM_TRUE;
378				break;
379		    case 'h':
380		    default:
381				usage(argv);
382		}
383	}
384
385	/* attach to all the modules we need */
386	cspHand = cspStartup();
387	if(cspHand == 0) {
388		exit(1);
389	}
390	if(cspHand == 0) {
391		exit(1);
392	}
393	clHand = clStartup();
394	if(clHand == 0) {
395		goto abort;
396	}
397	tpHand = tpStartup();
398	if(tpHand == 0) {
399		goto abort;
400	}
401
402	/* malloc empty keys and certs */
403	pubKeys  = (CSSM_KEY_PTR)CSSM_CALLOC(numCerts, sizeof(CSSM_KEY));
404	privKeys = (CSSM_KEY_PTR)CSSM_CALLOC(numCerts, sizeof(CSSM_KEY));
405	certs    = (CSSM_DATA_PTR)CSSM_CALLOC(numCerts, sizeof(CSSM_DATA));
406	if((pubKeys == NULL) || (privKeys == NULL) || (certs == NULL)) {
407		printf("not enough memory for %u keys pairs and certs.\n",
408			numCerts);
409		goto abort;
410	}
411
412	printf("Starting cgConstruct; args: ");
413	for(i=1; i<(unsigned)argc; i++) {
414		printf("%s ", argv[i]);
415	}
416	printf("\n");
417
418	/* generate key pairs */
419	if(!quiet) {
420		printf("generating keys...\n");
421	}
422	if(tpGenKeys(cspHand,
423			keyDb,
424			numCerts,
425			keyGenAlg,
426			keySizeInBits,
427			"cgConstruct",		// keyLabelBase
428			pubKeys,
429			privKeys)) {
430		goto abort;
431	}
432	notBeforeStr = genTimeAtNowPlus(0);
433	notAfterStr = genTimeAtNowPlus(SECONDS_TO_LIVE);
434
435	#if	TP_DB_ENABLE
436	/* create numDbs new DBs */
437	if(numDBs != 0) {
438		dlHand = dlStartup();
439		if(dlHand == 0) {
440			exit(1);
441		}
442		dbList.NumHandles = numDBs;
443		dbList.DLDBHandle =
444			(CSSM_DL_DB_HANDLE_PTR)CSSM_CALLOC(numDBs, sizeof(CSSM_DL_DB_HANDLE));
445		if(!publicRead) {
446			/*
447			 * In this case, this is the only time we open these DBs - they
448			 * stay open for the duration of the test
449			 */
450			if(verbose) {
451				printf("   ...opening DBs read/write\n");
452			}
453			if(doOpenDbs(dlHand,
454					fileBaseName,
455					dbList.DLDBHandle,
456					numDBs,
457					CSSM_FALSE,		// publicReadOnly: this is create/write
458					quiet)) {
459				goto abort;
460			}
461		}
462		dbListPtr = &dbList;
463	}
464	else {
465		/* it's required anyway... */
466		dbList.NumHandles = 0;
467		dbList.DLDBHandle = NULL;
468		dbListPtr = &dbList;
469	}
470	#else
471	/* it's required anyway... */
472	dbList.NumHandles = 0;
473	dbList.DLDBHandle = NULL;
474	dbListPtr = &dbList;
475	#endif
476
477	for(loop=1; ; loop++) {
478		if(!quiet) {
479			printf("...loop %d\n", loop);
480		}
481		if(tpGenCerts(cspHand,
482				clHand,
483				numCerts,
484				sigAlg,
485				"cgConstruct",	// nameBase
486				pubKeys,
487				privKeys,
488				certs,
489				notBeforeStr,
490				notAfterStr)) {
491			break;
492		}
493		if(doTest(tpHand,
494				clHand,
495				cspHand,
496				dlHand,
497				dbListPtr,
498				certs,
499				numCerts,
500				verbose,
501				allInDbs,
502				skipFirstDb,
503				publicRead,
504				fileBaseName,
505				quiet)) {
506			break;
507		}
508		for(i=0; i<numCerts; i++) {
509			appFreeCssmData(&certs[i], CSSM_FALSE);
510		}
511		memset(certs, 0, numCerts * sizeof(CSSM_DATA));
512
513		if(loops && (loop == loops)) {
514			break;
515		}
516		if(doPause) {
517			printf("Hit CR to continue: ");
518			fpurge(stdin);
519			getchar();
520		}
521	}
522
523abort:
524	/* free keys and certs */
525	if(privKeys != NULL) {
526		for(i=0; i<numCerts; i++) {
527			if(privKeys[i].KeyData.Data != NULL) {
528				cspFreeKey(cspHand, &privKeys[i]);
529			}
530		}
531		CSSM_FREE(privKeys);
532	}
533	if(pubKeys != NULL) {
534		for(i=0; i<numCerts; i++) {
535			if(pubKeys[i].KeyData.Data != NULL) {
536				cspFreeKey(cspHand, &pubKeys[i]);
537			}
538		}
539		CSSM_FREE(pubKeys);
540	}
541	if(certs != NULL) {
542		for(i=0; i<numCerts; i++) {
543			appFreeCssmData(&certs[i], CSSM_FALSE);
544		}
545		CSSM_FREE(certs);
546	}
547	if(dbList.DLDBHandle != NULL) {
548		/* don't have to close, detach should do that */
549		CSSM_FREE(dbList.DLDBHandle);
550	}
551	if(cspHand != 0) {
552		CSSM_ModuleDetach(cspHand);
553	}
554	if(clHand != 0) {
555		CSSM_ModuleDetach(clHand);
556	}
557	if(tpHand != 0) {
558		CSSM_ModuleDetach(tpHand);
559	}
560
561	if(!quiet) {
562		printf("%s test complete\n", argv[0]);
563	}
564	return 0;
565}
566