1/*
2 * cgVerifyParsed.cpp - basic test of TP's CertGroupVerify using parsed anchors
3 *
4 * ------- THIS TEST IS OBSOLETE; WE DON'T SUPPORT PARSED ANCHORS ----------
5 *
6 * cook up array of n key pairs;
7 * cook up cert chain to go with them;
8 * main test loop {
9 *    numCerts = total # of incoming certs;
10 *	  test one of four or five "expected result" cases {
11 *		case root in certGroup but not found in AnchorCerts:
12 *			certGroup = tpMakeRandCertGroup(certs[0..numCerts-1];
13 *			anchorCerts = tpMakeRandCertGroup[certs[0...numCerts-2];
14 *			expErr = CSSMERR_TP_INVALID_ANCHOR_CERT;
15 *			expEvidenceSize = numCerts;
16 *		case root in certGroup, found a copy in AnchorCerts:
17 *			certGroup = tpMakeRandCertGroup(certs[0..numCerts-1];
18 *			anchorCerts = tpMakeRandCertGroup[certs[0...numCerts-1];
19 *			expErr = CSSM_OK;
20 *			expEvidenceSize = numCerts;
21 *		case verified by an AnchorCert:
22 *			n = rand(1, numCerts-2);
23 *			certGroup = tpMakeRandCertGroup(certs[0..n]);
24 *			anchorCerts = tpMakeRandCertGroup[certs[0...numCerts-2];
25 *			expErr = CSSM_OK;
26 *			expEvidenceSize = n+2;
27 *		case no root found:
28 *			n = rand(1, numCerts-3);
29 *			certGroup = tpMakeRandCertGroup(certs[0..n]);
30 *			anchorCerts = tpMakeRandCertGroup[certs[n+2...numCerts-2];
31 *					anchorCerts may be empty....
32 *			expErr = CSSMERR_TP_NOT_TRUSTED;
33 *			expEvidenceSize = n+1;
34 *		case incomplete public key (DSA only):
35 *			root public keys is incomplete;
36 *			certGroup = tpMakeRandCertGroup(certs[0..numCerts-1];
37 *			anchorCerts = tpMakeRandCertGroup[certs[0...numCerts-1];
38 *			expErr = CSSM_OK;
39 *			expEvidenceSize = numCerts;
40 *    }
41 *    result = certGroupVerify();
42 *    verify expected result and getError();
43 *    delete certs from DB;
44 * }
45 */
46
47#include <Security/cssm.h>
48#include <utilLib/common.h>
49#include <utilLib/cspwrap.h>
50#include <clAppUtils/clutils.h>
51#include <clAppUtils/tpUtils.h>
52#include <clAppUtils/timeStr.h>
53#include <utilLib/nssAppUtils.h>
54#include <utilLib/fileIo.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <time.h>
58#include <string.h>
59#include <sys/types.h>
60#include <unistd.h>
61#include <Security/oidsalg.h>
62#include "tpVerifyParsed.h"
63
64#define NUM_CERTS_DEF		10
65#define KEYGEN_ALG_DEF		CSSM_ALGID_RSA
66#define SIG_ALG_DEF			CSSM_ALGID_SHA1WithRSA
67#define LOOPS_DEF			10
68#define SECONDS_TO_LIVE		(60 * 60 * 24)		/* certs are valid for this long */
69//#define SECONDS_TO_LIVE		5
70
71#define CERT_IN_DB			1
72#define DB_NAME				"cgVerify.db"
73#define DSA_PARAM_FILE		"dsaParam512.der"
74
75/*
76 * How we define the "expected result".
77 */
78typedef enum {
79	ER_InvalidAnchor,		// root in certGroup, not found in AnchorCerts
80	ER_RootInCertGroup,		// root in certGroup, copy in AnchorCerts
81	ER_AnchorVerify,		// end of chain verified by an anchor
82	ER_NoRoot,				// no root, no anchor verify
83	ER_IncompleteKey		// un-completable public key (all keys are partial), DSA
84							//   ONLY
85} ExpectResult;
86
87static void usage(char **argv)
88{
89	printf("Usage: %s [options]\n", argv[0]);
90	printf("   Options:\n");
91	printf("   n=numCerts; default = %d\n", NUM_CERTS_DEF);
92	printf("   l=loops; default=%d; 0=forever\n", LOOPS_DEF);
93	printf("   a=alg (f=FEE/MD5, F=FEE/SHA1, e=FEE/ECDSA, s=RSA/SHA1, m=RSA/MD5,\n");
94	printf("          d=DSA; 6=RSA/SHA256, 3=RSA/SHA384, 5=RSA/SHA512; default = RSA/SHA1\n");
95	printf("   k=keySizeInBits\n");
96	printf("   d(isable DB)\n");
97	printf("   P(ause on each loop)\n");
98	printf("   N (no partial pub keys)\n");
99	printf("   v(erbose)\n");
100	printf("   q(uiet)\n");
101	printf("   h(elp)\n");
102	exit(1);
103}
104
105static int doTest(
106	CSSM_TP_HANDLE	tpHand,
107	CSSM_CL_HANDLE	clHand,
108	CSSM_CSP_HANDLE	cspHand,
109	CSSM_DL_DB_HANDLE dlDb,
110	CSSM_DATA_PTR	certs,
111	unsigned		numCerts,
112	CSSM_KEY_PTR	pubKeys,		// for partial key detect
113	CSSM_BOOL		useDb,
114	ExpectResult	expectResult,
115	CSSM_BOOL		verbose,
116	CSSM_BOOL		quiet)
117{
118	unsigned			cgEnd;				// last cert in certGroupFrag
119	unsigned			anchorStart;		// first cert in anchorGroup
120	unsigned			anchorEnd;			// last cert in anchorGroup
121	CSSM_CERTGROUP		certGroupFrag;		// INPUT to CertGroupVerify
122	CSSM_CERTGROUP		anchorCerts;		// ditto
123	unsigned			die;				// random number
124	CSSM_DL_DB_LIST		dbList;
125	CSSM_DL_DB_LIST_PTR	dbListPtr;
126	CSSM_RETURN			expErr;				// expected rtn from GroupVfy()
127	int					rtn = 0;
128	char				*expResStr;
129	uint32				expEvidenceSize;	// expected evidenceSize
130	unsigned			evidenceSize;		// actual evidence size
131	CSSM_TP_VERIFY_CONTEXT_RESULT	vfyResult;
132	CSSM_CERTGROUP_PTR 	outGrp = NULL;
133	CSSM_RETURN			crtn;
134	CSSM_DL_DB_HANDLE_PTR	dlDbPtr;
135	unsigned numAnchors;
136
137	memset(&vfyResult, 0, sizeof(CSSM_TP_VERIFY_CONTEXT_RESULT));
138
139	if(useDb) {
140		dlDbPtr = &dlDb;
141		dbList.NumHandles = 1;
142		dbList.DLDBHandle = &dlDb;
143		dbListPtr = &dbList;
144	}
145	else {
146		/* not yet */
147		dlDbPtr = NULL;
148		dbListPtr = NULL;
149	}
150
151 	/* the four test cases */
152 	switch(expectResult) {
153		case ER_InvalidAnchor:
154			/* root in certGroup, not found in AnchorCerts */
155			cgEnd = numCerts - 1;		// certGroupFrag is the whole pile
156			anchorStart = 0;			// anchors = all except root
157			anchorEnd = numCerts - 2;
158			expErr = CSSMERR_TP_INVALID_ANCHOR_CERT;
159			expEvidenceSize = numCerts;
160			expResStr = "InvalidAnchor (root in certGroup but not in anchors)";
161			break;
162
163		case ER_RootInCertGroup:
164			/* root in certGroup, copy in AnchorCerts */
165			cgEnd = numCerts - 1;		// certGroupFrag = the whole pile
166			anchorStart = 0;			// anchors = the whole pile
167			anchorEnd = numCerts - 1;
168			expErr = CSSM_OK;
169			expEvidenceSize = numCerts;
170			expResStr = "Good (root in certGroup AND in anchors)";
171			break;
172
173		case ER_AnchorVerify:
174			/* non-root end of chain verified by an anchor */
175			/* break chain at random place other than end */
176			/* die is the last cert in certGroupFrag */
177			die = genRand(0, numCerts-2);
178			cgEnd = die;				// certGroupFrag up to break point
179			anchorStart = 0;			// anchors = all
180			anchorEnd = numCerts - 1;
181			if(pubKeys[die+1].KeyHeader.KeyAttr & CSSM_KEYATTR_PARTIAL) {
182				/* this will fail due to an unusable anchor */
183				expErr = CSSMERR_TP_CERTIFICATE_CANT_OPERATE;
184				expResStr = "Root ONLY in anchors but has partial pub key";
185			}
186			else {
187				expErr = CSSM_OK;
188				expResStr = "Good (root ONLY in anchors)";
189			}
190			/* size = # certs in certGroupFrag, plus one anchor */
191			expEvidenceSize = die + 2;
192			break;
193
194		case ER_NoRoot:
195			/* no root, no anchor verify */
196			/* break chain at random place other than end */
197			/* die is the last cert in certGroupFrag */
198			/* skip a cert, then anchors start at die + 2 */
199			die = genRand(0, numCerts-2);
200			cgEnd = die;				// certGroupFrag up to break point
201			anchorStart = die + 2;		// anchors = n+1...numCerts-2
202										// may be empty if n == numCerts-2
203			anchorEnd = numCerts - 2;
204			if((die != 0) &&			// partial leaf not reported as partial!
205			   (pubKeys[die].KeyHeader.KeyAttr & CSSM_KEYATTR_PARTIAL)) {
206				/* this will fail due to an unusable cert (this one) */
207				expErr = CSSMERR_TP_CERTIFICATE_CANT_OPERATE;
208				expResStr = "Not Trusted (no root, no anchor verify), partial";
209			}
210			else {
211				expErr = CSSMERR_TP_NOT_TRUSTED;
212				expResStr = "Not Trusted (no root, no anchor verify)";
213			}
214			expEvidenceSize = die + 1;
215			break;
216
217		case ER_IncompleteKey:
218			/*
219			 * Anchor has incomplete pub key
220			 * Root in certGroup, copy in AnchorCerts
221			 * Avoid putting anchor in certGroupFrag because the TP will think
222			 * it's NOT a root and it'll show up twice in the evidence - once
223			 * from certGroupFrag (at which point the search for a root
224			 * keeps going), and once from Anchors.
225			 */
226			cgEnd = numCerts - 2;		// certGroupFrag = the whole pile less the anchor
227			anchorStart = 0;			// anchors = the whole pile
228			anchorEnd = numCerts - 1;
229			expErr = CSSMERR_TP_CERTIFICATE_CANT_OPERATE;
230			expEvidenceSize = numCerts;
231			expResStr = "Partial public key in anchor";
232			break;
233 	}
234
235 	if(verbose) {
236 		printf("   ...expectResult = %s\n", expResStr);
237 	}
238
239 	/* cook up two cert groups */
240 	if(verbose) {
241 		printf("   ...building certGroupFrag from certs[0..%d]\n",
242 			cgEnd);
243 	}
244  	if(tpMakeRandCertGroup(clHand,
245	 		dbListPtr,
246	 		certs,				// certGroupFrag always starts at 0
247	 		cgEnd+1,			// # of certs
248	 		&certGroupFrag,
249	 		CSSM_TRUE,			// firstCertIsSubject
250	 		verbose,
251	 		CSSM_FALSE,			// allInDbs
252	 		CSSM_FALSE)) {		// skipFirstDb
253	 	printf("Error in tpMakeRandCertGroup\n");
254	 	return 1;
255	}
256
257 	if(verbose) {
258 		printf("   ...building anchorCerts from certs[%d..%d]\n",
259 			anchorStart, anchorEnd);
260 	}
261 	if(anchorEnd > (numCerts - 1)) {
262 		printf("anchorEnd overflow\n");
263 		exit(1);
264 	}
265	if(anchorStart >= anchorEnd) {
266		/* legal in some corner cases, ==> empty enchors */
267		numAnchors = 0;
268	}
269	else {
270		numAnchors = anchorEnd - anchorStart + 1;
271	}
272 	/* anchors do not go in DB */
273  	if(tpMakeRandCertGroup(clHand,
274	 		NULL,
275	 		certs + anchorStart,
276	 		numAnchors,			// # of certs
277	 		&anchorCerts,
278	 		CSSM_FALSE,			// firstCertIsSubject
279	 		verbose,
280	 		CSSM_FALSE,			// allInDbs
281	 		CSSM_FALSE)) {		// skipFirstDb
282	 	printf("Error in tpMakeRandCertGroup\n");
283	 	return 1;
284	}
285
286	crtn = tpCertGroupVerifyParsed(
287		tpHand,
288		clHand,
289		cspHand,
290		dbListPtr,
291		&CSSMOID_APPLE_X509_BASIC,	// policy
292		NULL,						// fieldOpts
293		NULL,						// actionData
294		NULL,						// policyOpts
295		&certGroupFrag,
296		anchorCerts.GroupList.CertList,	// passed as CSSM_DATA_PTR, not CERTGROUP....
297		anchorCerts.NumCerts,
298		CSSM_TP_STOP_ON_POLICY,
299		NULL,					// cssmTimeStr
300		&vfyResult);
301
302	/* first verify format of result */
303	if( (vfyResult.NumberOfEvidences != 3) ||
304	    (vfyResult.Evidence == NULL) ||
305		(vfyResult.Evidence[0].EvidenceForm != CSSM_EVIDENCE_FORM_APPLE_HEADER) ||
306		(vfyResult.Evidence[1].EvidenceForm != CSSM_EVIDENCE_FORM_APPLE_CERTGROUP) ||
307		(vfyResult.Evidence[2].EvidenceForm != CSSM_EVIDENCE_FORM_APPLE_CERT_INFO) ||
308		(vfyResult.Evidence[0].Evidence == NULL) ||
309		(vfyResult.Evidence[1].Evidence == NULL) ||
310		(vfyResult.Evidence[2].Evidence == NULL)) {
311		printf("***Malformed VerifyContextResult\n");
312		rtn = testError(quiet);
313		if(rtn) {
314			return rtn;
315		}
316	}
317	if((vfyResult.Evidence != NULL) && (vfyResult.Evidence[1].Evidence != NULL)) {
318		outGrp = (CSSM_CERTGROUP_PTR)vfyResult.Evidence[1].Evidence;
319		evidenceSize = outGrp->NumCerts;
320	}
321	else {
322		/* in case no evidence returned */
323		evidenceSize = 0;
324	}
325	if((crtn != expErr) ||
326	   (evidenceSize != expEvidenceSize)) {
327		printf("***Error on expectResult %s\n", expResStr);
328		printf("   err  %s   expErr  %s\n",
329			cssmErrToStr(crtn), cssmErrToStr(expErr));
330		printf("   evidenceSize  %d   expEvidenceSize  %lu\n",
331			evidenceSize, expEvidenceSize);
332		rtn = testError(quiet);
333	}
334	else {
335		rtn = 0;
336	}
337
338	/* free resources */
339	tpFreeCertGroup(&certGroupFrag,
340		CSSM_FALSE,			// caller malloc'd the actual certs
341		CSSM_FALSE);		// struct is on stack
342	tpFreeCertGroup(&anchorCerts,
343		CSSM_FALSE,			// caller malloc'd the actual certs
344		CSSM_FALSE);		// struct is on stack
345	freeVfyResult(&vfyResult);
346	if(useDb) {
347		clDeleteAllCerts(dlDb);
348	}
349	return rtn;
350}
351
352int main(int argc, char **argv)
353{
354	int					arg;
355	char				*argp;
356	unsigned			loop;
357	CSSM_TP_HANDLE		tpHand = 0;
358	CSSM_CL_HANDLE		clHand = 0;
359	CSSM_CSP_HANDLE		cspHand = 0;
360	CSSM_DL_DB_HANDLE	dlDbHand = {0, 0};
361	ExpectResult		expectResult;
362	char				*notAfterStr;
363	char 				*notBeforeStr;
364	unsigned 			i;
365	CSSM_DATA 			paramData;
366	CSSM_DATA_PTR 		paramDataP = NULL;
367	unsigned 			numTests = 4;
368
369	/* all three of these are arrays with numCert elements */
370	CSSM_KEY_PTR		pubKeys = NULL;
371	CSSM_KEY_PTR		privKeys = NULL;
372	CSSM_DATA_PTR		certs = NULL;
373
374	/* Keys do NOT go in the cert DB */
375	CSSM_DL_DB_HANDLE 	keyDb = {0, 0};
376	CSSM_KEY			savedRoot;		// for ER_IncompleteKey
377
378	/*
379	 * User-spec'd params
380	 */
381	unsigned	loops = LOOPS_DEF;
382	CSSM_BOOL	verbose = CSSM_FALSE;
383	CSSM_BOOL	quiet = CSSM_FALSE;
384	unsigned	numCerts = NUM_CERTS_DEF;
385	uint32		keyGenAlg = KEYGEN_ALG_DEF;
386	uint32		sigAlg = SIG_ALG_DEF;
387	#if	CERT_IN_DB
388	CSSM_BOOL	useDb = CSSM_TRUE;
389	#else
390	CSSM_BOOL	useDb = CSSM_FALSE;
391	#endif
392	CSSM_BOOL	doPause = CSSM_FALSE;
393	uint32		keySizeInBits = CSP_KEY_SIZE_DEFAULT;
394	CSSM_BOOL	noPartialKeys = CSSM_FALSE;
395	char		dbName[100];		/* DB_NAME_pid */
396
397	for(arg=1; arg<argc; arg++) {
398		argp = argv[arg];
399		switch(argp[0]) {
400		    case 'l':
401				loops = atoi(&argp[2]);
402				break;
403		    case 'k':
404				keySizeInBits = atoi(&argp[2]);
405				break;
406		    case 'n':
407				numCerts = atoi(&argp[2]);
408				break;
409		    case 'v':
410		    	verbose = CSSM_TRUE;
411				break;
412		    case 'q':
413		    	quiet = CSSM_TRUE;
414				break;
415			case 'a':
416				switch(argp[2]) {
417					case 'f':
418						keyGenAlg = CSSM_ALGID_FEE;
419						sigAlg = CSSM_ALGID_FEE_MD5;
420						break;
421					case 'F':
422						keyGenAlg = CSSM_ALGID_FEE;
423						sigAlg = CSSM_ALGID_FEE_SHA1;
424						break;
425					case 'e':
426						keyGenAlg = CSSM_ALGID_FEE;
427						sigAlg = CSSM_ALGID_SHA1WithECDSA;
428						break;
429					case 's':
430						keyGenAlg = CSSM_ALGID_RSA;
431						sigAlg = CSSM_ALGID_SHA1WithRSA;
432						break;
433					case 'm':
434						keyGenAlg = CSSM_ALGID_RSA;
435						sigAlg = CSSM_ALGID_MD5WithRSA;
436						break;
437					case 'd':
438						keyGenAlg = CSSM_ALGID_DSA;
439						sigAlg = CSSM_ALGID_SHA1WithDSA;
440						break;
441					case '6':
442						keyGenAlg = CSSM_ALGID_RSA;
443						sigAlg = CSSM_ALGID_SHA256WithRSA;
444						break;
445					case '3':
446						keyGenAlg = CSSM_ALGID_RSA;
447						sigAlg = CSSM_ALGID_SHA512WithRSA;
448						break;
449					case '5':
450						keyGenAlg = CSSM_ALGID_RSA;
451						sigAlg = CSSM_ALGID_SHA512WithRSA;
452						break;
453					default:
454						usage(argv);
455				}
456				break;
457			case 'N':
458				noPartialKeys = CSSM_TRUE;
459				break;
460			case 'd':
461				useDb = CSSM_FALSE;
462				break;
463			case 'P':
464				doPause = CSSM_TRUE;
465				break;
466		    case 'h':
467		    default:
468				usage(argv);
469		}
470	}
471
472	sprintf(dbName, "%s_%d", DB_NAME, (int)getpid());
473
474	if(numCerts < 2) {
475		printf("Can't run with cert chain smaller than 2\n");
476		exit(1);
477	}
478
479	/* attach to all the modules we need */
480	cspHand = cspStartup();
481	if(cspHand == 0) {
482		exit(1);
483	}
484	#if CERT_IN_DB
485	if(useDb) {
486		dlDbHand.DLHandle = dlStartup();
487		if(dlDbHand.DLHandle == 0) {
488			exit(1);
489		}
490		CSSM_RETURN crtn = tpKcOpen(dlDbHand.DLHandle, dbName, dbName,
491			CSSM_TRUE, &dlDbHand.DBHandle);
492		if(crtn) {
493			printf("Error opening keychain %s; aborting.\n", dbName);
494			exit(1);
495		}
496	}
497	#endif
498	clHand = clStartup();
499	if(clHand == 0) {
500		goto abort;
501	}
502	tpHand = tpStartup();
503	if(tpHand == 0) {
504		goto abort;
505	}
506
507	/* malloc empty keys and certs */
508	pubKeys  = (CSSM_KEY_PTR)CSSM_CALLOC(numCerts, sizeof(CSSM_KEY));
509	privKeys = (CSSM_KEY_PTR)CSSM_CALLOC(numCerts, sizeof(CSSM_KEY));
510	certs    = (CSSM_DATA_PTR)CSSM_CALLOC(numCerts, sizeof(CSSM_DATA));
511	if((pubKeys == NULL) || (privKeys == NULL) || (certs == NULL)) {
512		printf("not enough memory for %u keys pairs and certs.\n",
513			numCerts);
514		goto abort;
515	}
516
517	printf("Starting cgVerify; args: ");
518	for(i=1; i<(unsigned)argc; i++) {
519		printf("%s ", argv[i]);
520	}
521	printf("\n");
522
523	/* generate key pairs */
524	if(!quiet) {
525		printf("generating keys...\n");
526	}
527	if(keyGenAlg == CSSM_ALGID_DSA) {
528		unsigned len;
529		if(!readFile(DSA_PARAM_FILE, (unsigned char **)&paramData.Data,	&len)) {
530			if(!quiet) {
531				printf("...using DSA params from %s\n", DSA_PARAM_FILE);
532			}
533			paramData.Length = len;
534			paramDataP = &paramData;
535		}
536		else {
537			printf("***warning: no param file. KeyGen is going to be slow!\n");
538			printf("***You might consider running this from the clxutils/cgVerify "
539				"directory.\n");
540		}
541	}
542	if(tpGenKeys(cspHand,
543			keyDb,
544			numCerts,
545			keyGenAlg,
546			keySizeInBits,
547			"cgVerify",		// keyLabelBase
548			pubKeys,
549			privKeys,
550			paramDataP)) {
551		goto abort;
552	}
553	notBeforeStr = genTimeAtNowPlus(0);
554	notAfterStr = genTimeAtNowPlus(SECONDS_TO_LIVE);
555
556	/*
557	 * If DSA, insert some random partial public keys which are not
558	 * fatal (i.e., root can not be partial). We include the leaf in this
559	 * loop - the TP is *supposed* to ignore that situation, ane we make
560	 * sure it does.
561	 */
562	if((keyGenAlg == CSSM_ALGID_DSA) && !noPartialKeys) {
563		for(unsigned dex=0; dex<(numCerts-1); dex++) {
564			int die = genRand(0,1);
565			if(die) {
566				/* this one gets partialized */
567				CSSM_KEY newKey;
568				if(verbose) {
569					printf("...making partial DSA pub key at index %u\n", dex);
570				}
571				CSSM_RETURN crtn = extractDsaPartial(cspHand, &pubKeys[dex], &newKey);
572				if(crtn) {
573					printf("***Error converting to partial key. Aborting.\n");
574					exit(1);
575				}
576				CSSM_FREE(pubKeys[dex].KeyData.Data);
577				pubKeys[dex] = newKey;
578			}
579		}
580	}
581	if(!quiet) {
582		printf("starting %s test\n", argv[0]);
583
584	}
585	if(keyGenAlg == CSSM_ALGID_DSA) {
586		numTests = 5;
587	}
588	for(loop=1; ; loop++) {
589		if(!quiet) {
590			printf("...loop %d\n", loop);
591		}
592
593		/* cycle thru test scenarios */
594		switch(loop % numTests) {
595			case 0:
596				expectResult = ER_InvalidAnchor;
597				break;
598			case 1:
599				expectResult = ER_RootInCertGroup;
600				break;
601			case 2:
602				expectResult = ER_AnchorVerify;
603				break;
604			case 3:
605				expectResult = ER_NoRoot;
606				break;
607			case 4:
608				/* DSA only */
609				expectResult = ER_IncompleteKey;
610				savedRoot = pubKeys[numCerts-1];
611				/* make anchor unusable */
612				if(extractDsaPartial(cspHand, &savedRoot, &pubKeys[numCerts-1])) {
613					printf("...error partializing anchor key; aborting\n");
614					exit(1);
615				}
616				break;
617		}
618		if(tpGenCerts(cspHand,
619				clHand,
620				numCerts,
621				sigAlg,
622				"cgConstruct",	// nameBase
623				pubKeys,
624				privKeys,
625				certs,
626				notBeforeStr,
627				notAfterStr)) {
628			break;
629		}
630
631		if(doTest(tpHand,
632				clHand,
633				cspHand,
634				dlDbHand,
635				certs,
636				numCerts,
637				pubKeys,
638				useDb,
639				expectResult,
640				verbose,
641				quiet)) {
642			break;
643		}
644		for(i=0; i<numCerts; i++) {
645			appFreeCssmData(&certs[i], CSSM_FALSE);
646		}
647		if(expectResult == ER_IncompleteKey) {
648			CSSM_FREE(pubKeys[numCerts-1].KeyData.Data);
649			pubKeys[numCerts-1] = savedRoot;
650		}
651
652		memset(certs, 0, numCerts * sizeof(CSSM_DATA));
653		if(loops && (loop == loops)) {
654			break;
655		}
656		if(doPause) {
657			printf("Hit CR to continue: ");
658			fpurge(stdin);
659			getchar();
660		}
661	}
662abort:
663	if(privKeys != NULL) {
664		for(i=0; i<numCerts; i++) {
665			if(privKeys[i].KeyData.Data != NULL) {
666				cspFreeKey(cspHand, &privKeys[i]);
667			}
668		}
669		CSSM_FREE(privKeys);
670	}
671	if(pubKeys != NULL) {
672		for(i=0; i<numCerts; i++) {
673			if(pubKeys[i].KeyData.Data != NULL) {
674				cspFreeKey(cspHand, &pubKeys[i]);
675			}
676		}
677		CSSM_FREE(pubKeys);
678	}
679	if(certs != NULL) {
680		for(i=0; i<numCerts; i++) {
681			appFreeCssmData(&certs[i], CSSM_FALSE);
682		}
683		CSSM_FREE(certs);
684	}
685	if(cspHand != 0) {
686		CSSM_ModuleDetach(cspHand);
687	}
688	if(clHand != 0) {
689		CSSM_ModuleDetach(clHand);
690	}
691	if(tpHand != 0) {
692		CSSM_ModuleDetach(tpHand);
693	}
694
695	if(!quiet) {
696		printf("%s test complete\n", argv[0]);
697	}
698	return 0;
699}
700