1/* cgVerifyThr.cpp - simple version CertGroupVerify test */
2
3#include "testParams.h"
4#include <Security/cssm.h>
5#include <utilLib/common.h>
6#include <utilLib/cspwrap.h>
7#include <clAppUtils/clutils.h>
8#include <clAppUtils/tpUtils.h>
9#include <clAppUtils/timeStr.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <time.h>
13#include <string.h>
14#include <Security/oidsalg.h>
15
16/* for memory leak debug only, with only one thread running */
17#define DO_PAUSE			0
18
19/*** start of code directly copied from ../cgVerify/cgVerify.cpp ***/
20#define NUM_CERTS_MIN		4
21#define KEYGEN_ALG_DEF		CSSM_ALGID_RSA
22#define SIG_ALG_DEF			CSSM_ALGID_SHA1WithRSA
23#define LOOPS_DEF			10
24#define CG_KEY_SIZE_DEFAULT	CSP_RSA_KEY_SIZE_DEFAULT
25#define SECONDS_TO_LIVE		(60 * 60 * 24)		/* certs are valid for this long */
26
27#define CERT_IN_DB		0
28
29/*
30 * How we define the "expected result".
31 */
32typedef enum {
33	ER_InvalidAnchor,		// root in certGroup, not found in AnchorCerts
34	ER_RootInCertGroup,		// root in certGroup, copy in AnchorCerts
35	ER_AnchorVerify,		// end of chain verified by an anchor
36	ER_NoRoot				// no root, no anchor verify
37} ExpectResult;
38
39static int testError()
40{
41	char resp;
42
43	printf("Attach via debugger for more info.\n");
44	printf("a to abort, c to continue: ");
45	resp = getchar();
46	return (resp == 'a');
47}
48
49static int doTest(
50	CSSM_TP_HANDLE	tpHand,
51	CSSM_CL_HANDLE	clHand,
52	CSSM_CSP_HANDLE	cspHand,
53	CSSM_DL_DB_HANDLE dlDb,
54	CSSM_DATA_PTR	certs,
55	unsigned		numCerts,
56	CSSM_BOOL		useDb,
57	ExpectResult	expectResult,
58	CSSM_BOOL		verbose)
59{
60	unsigned			cgEnd;				// last cert in certGroupFrag
61	unsigned			anchorStart;		// first cert in anchorGroup
62	unsigned			anchorEnd;			// last cert in anchorGroup
63	CSSM_CERTGROUP		certGroupFrag;		// INPUT to CertGroupVerify
64	CSSM_CERTGROUP		anchorCerts;		// ditto
65	unsigned			die;				// random number
66	CSSM_DL_DB_LIST		dbList;
67	CSSM_DL_DB_LIST_PTR	dbListPtr;
68	CSSM_DL_DB_HANDLE_PTR	dlDbPtr;
69	CSSM_RETURN			expErr;				// expected rtn from GroupVfy()
70	int					rtn = 0;
71	const char			*expResStr;
72	uint32				expEvidenceSize;	// expected evidenceSize
73	unsigned			evidenceSize;		// actual evidence size
74	CSSM_TP_VERIFY_CONTEXT_RESULT	vfyResult;
75	CSSM_CERTGROUP_PTR 	outGrp = NULL;
76	CSSM_RETURN			crtn;
77
78	memset(&vfyResult, 0, sizeof(CSSM_TP_VERIFY_CONTEXT_RESULT));
79
80	if(useDb) {
81		dlDbPtr = &dlDb;
82		dbList.NumHandles = 1;
83		dbList.DLDBHandle = &dlDb;
84		dbListPtr = &dbList;
85	}
86	else {
87		/* not yet */
88		dlDbPtr = NULL;
89		dbListPtr = NULL;
90	}
91
92 	/* the four test cases */
93 	switch(expectResult) {
94		case ER_InvalidAnchor:
95			/* root in certGroup, not found in AnchorCerts */
96			cgEnd = numCerts - 1;		// certGroupFrag is the whole pile
97			anchorStart = 0;			// anchors = all except root
98			anchorEnd = numCerts - 2;
99			expErr = CSSMERR_TP_INVALID_ANCHOR_CERT;
100			expEvidenceSize = numCerts;
101			expResStr = "InvalidAnchor (root in certGroup but not in anchors)";
102			break;
103
104		case ER_RootInCertGroup:
105			/* root in certGroup, copy in AnchorCerts */
106			cgEnd = numCerts - 1;		// certGroupFrag = the whole pile
107			anchorStart = 0;			// anchors = the whole pile
108			anchorEnd = numCerts - 1;
109			expErr = CSSM_OK;
110			expEvidenceSize = numCerts;
111			expResStr = "Good (root in certGroup AND in anchors)";
112			break;
113
114		case ER_AnchorVerify:
115			/* non-root end of chain verified by an anchor */
116			/* break chain at random place other than start and end-2 */
117			die = genRand(1, numCerts-3);
118			cgEnd = die;				// certGroupFrag up to break point
119			anchorStart = 0;			// anchors = all
120			anchorEnd = numCerts - 1;
121			expErr = CSSM_OK;
122			/* size = # certs in certGroupFrag, plus one anchor */
123			expEvidenceSize = die + 2;
124			expResStr = "Good (root ONLY in anchors)";
125			break;
126
127		case ER_NoRoot:
128			/* no root, no anchor verify */
129			/* break chain at random place other than start and end-1 */
130			die = genRand(1, numCerts-2);
131			cgEnd = die;				// certGroupFrag up to break point
132			/* and skip one cert */
133			anchorStart = die + 2;		// anchors = n+1...numCerts-2
134										// may be empty if n == numCerts-2
135			anchorEnd = numCerts - 1;
136			expErr = CSSMERR_TP_NOT_TRUSTED;
137			expEvidenceSize = die + 1;
138			expResStr = "Not Trusted (no root, no anchor verify)";
139			break;
140 	}
141
142 	if(verbose) {
143 		printf("   ...expectResult = %s\n", expResStr);
144 	}
145
146 	/* cook up two cert groups */
147 	if(verbose) {
148 		printf("   ...building certGroupFrag from certs[0..%d]\n",
149 			cgEnd);
150 	}
151  	if(tpMakeRandCertGroup(clHand,
152	 		dbListPtr,
153	 		certs,				// certGroupFrag always starts at 0
154	 		cgEnd+1,			// # of certs
155	 		&certGroupFrag,
156	 		CSSM_TRUE,			// firstCertIsSubject
157	 		verbose,
158	 		CSSM_FALSE,			// allInDbs
159	 		CSSM_FALSE)) {		// skipFirstDb
160	 	printf("\nError in tpMakeRandCertGroup\n");
161	 	return 1;
162	}
163
164	if(anchorStart > anchorEnd) {
165		/* legal for ER_NoRoot */
166		if((expectResult != ER_NoRoot) || (anchorStart != numCerts)) {
167			printf("Try again, pal.\n");
168			exit(1);
169		}
170	}
171 	if(verbose) {
172 		printf("   ...building anchorCerts from certs[%d..%d]\n",
173 			anchorStart, anchorEnd);
174 	}
175 	if(anchorEnd > (numCerts - 1)) {
176 		printf("anchorEnd overflow\n");
177 		exit(1);
178 	}
179 	/* anchors do not go in DB */
180  	if(tpMakeRandCertGroup(clHand,
181	 		NULL,
182	 		certs + anchorStart,
183	 		anchorEnd - anchorStart + 1,			// # of certs
184	 		&anchorCerts,
185	 		CSSM_FALSE,			// firstCertIsSubject
186	 		verbose,
187	 		CSSM_FALSE,			// allInDbs
188	 		CSSM_FALSE)) {		// skipFirstDb
189	 	printf("\nError in tpMakeRandCertGroup\n");
190	 	return 1;
191	}
192
193	crtn = tpCertGroupVerify(
194		tpHand,
195		clHand,
196		cspHand,
197		dbListPtr,
198		&CSSMOID_APPLE_X509_BASIC, 	// Policy
199		NULL,						// fieldOpts
200		NULL,						// actionData
201		NULL,						// policyOpts
202		&certGroupFrag,
203		anchorCerts.GroupList.CertList,	// passed as CSSM_DATA_PTR, not CERTGROUP....
204		anchorCerts.NumCerts,
205		CSSM_TP_STOP_ON_POLICY,
206		NULL,					// cssmTimeStr
207		&vfyResult);
208
209	/* first verify format of result */
210	if( (vfyResult.NumberOfEvidences != 3) ||
211	    (vfyResult.Evidence == NULL) ||
212		(vfyResult.Evidence[0].EvidenceForm != CSSM_EVIDENCE_FORM_APPLE_HEADER) ||
213		(vfyResult.Evidence[1].EvidenceForm != CSSM_EVIDENCE_FORM_APPLE_CERTGROUP) ||
214		(vfyResult.Evidence[2].EvidenceForm != CSSM_EVIDENCE_FORM_APPLE_CERT_INFO) ||
215		(vfyResult.Evidence[0].Evidence == NULL) ||
216		(vfyResult.Evidence[1].Evidence == NULL) ||
217		(vfyResult.Evidence[2].Evidence == NULL)) {
218		printf("***Malformed VerifyContextResult\n");
219		return 1;
220	}
221	if((vfyResult.Evidence != NULL) && (vfyResult.Evidence[1].Evidence != NULL)) {
222		outGrp = (CSSM_CERTGROUP_PTR)vfyResult.Evidence[1].Evidence;
223		evidenceSize = outGrp->NumCerts;
224	}
225	else {
226		/* in case no evidence returned */
227		evidenceSize = 0;
228	}
229
230	/* %%% since non-root anchors are permitted as of <rdar://5685316>,
231	 * the test assumptions have become invalid: these tests generate
232	 * an anchors list which always includes the full chain, so by
233	 * definition, the evidence chain will never be longer than 2,
234	 * since the leaf's issuer is always an anchor.
235	 * %%% need to revisit and rewrite these tests. -kcm
236	 */
237	if ((evidenceSize > 1) && (evidenceSize < expEvidenceSize) &&
238		(crtn == CSSM_OK || crtn == CSSMERR_TP_CERTIFICATE_CANT_OPERATE)) {
239		/* ignore, for now */
240		expErr = crtn;
241		expEvidenceSize = evidenceSize;
242	}
243
244	if((crtn != expErr) ||
245	   (evidenceSize != expEvidenceSize)) {
246		printf("\n***cgVerify: Error on tpCertGroupVerify expectResult %s\n",
247			expResStr);
248		printf("   err  %s   expErr  %s\n",
249			cssmErrToStr(crtn), cssmErrToStr(expErr));
250		printf("   evidenceSize  %d   expEvidenceSize  %u\n",
251			evidenceSize, (unsigned)expEvidenceSize);
252		printf("   numCerts %d  cgEnd %d  anchorStart %d  anchorEnd %d\n",
253			numCerts, cgEnd, anchorStart, anchorEnd);
254		rtn = testError();
255	}
256	else {
257		rtn = 0;
258	}
259
260	/* free resources */
261	tpFreeCertGroup(&certGroupFrag,
262		CSSM_FALSE,			// caller malloc'd the actual certs
263		CSSM_FALSE);		// struct is on stack
264	tpFreeCertGroup(&anchorCerts,
265		CSSM_FALSE,			// caller malloc'd the actual certs
266		CSSM_FALSE);		// struct is on stack
267	freeVfyResult(&vfyResult);
268	if(useDb) {
269		clDeleteAllCerts(dlDb);
270	}
271	return rtn;
272}
273
274/*** end of code directly copied from ../cgVerify/cgVerify.cpp ***/
275
276/*
277 * For debug only - ensure that the given array of public keys are all unique
278 * Only saw this when using FEE RNG (i.e., no SecurityServer running).
279 */
280int comparePubKeys(
281	unsigned numKeys,
282	const CSSM_KEY *pubKeys)
283{
284	unsigned i,j;
285
286	for(i=0; i<numKeys-1; i++) {
287		for(j=i+1; j<numKeys; j++) {
288			if(appCompareCssmData(&pubKeys[i].KeyData, &pubKeys[j].KeyData)) {
289				printf("***HEY! DUPLICATE PUBLIC KEYS in cgVerify!\n");
290				return testError();
291			}
292		}
293	}
294	return 0;
295}
296
297
298/*
299 * key pairs - created in cgConstructInit, stored in testParams->perThread
300 */
301typedef struct {
302	CSSM_KEY_PTR pubKeys;
303	CSSM_KEY_PTR privKeys;
304	unsigned numKeys;
305	char *notBeforeStr;		// to use thread-safe tpGenCerts()
306	char *notAfterStr;		// to use thread-safe tpGenCerts()
307}	TT_KeyPairs;
308
309
310int cgVerifyInit(TestParams *testParams)
311{
312	unsigned			numKeys = NUM_CERTS_MIN + testParams->threadNum;
313	TT_KeyPairs			*keyPairs;
314
315	if(testParams->verbose) {
316		printf("cgVerify thread %d: generating keys...\n",
317			testParams->threadNum);
318	}
319	keyPairs = (TT_KeyPairs *)CSSM_MALLOC(sizeof(TT_KeyPairs));
320	keyPairs->numKeys = numKeys;
321	keyPairs->pubKeys  = (CSSM_KEY_PTR)CSSM_CALLOC(numKeys, sizeof(CSSM_KEY));
322	keyPairs->privKeys = (CSSM_KEY_PTR)CSSM_CALLOC(numKeys, sizeof(CSSM_KEY));
323	CSSM_DL_DB_HANDLE	dlDbHand = {0, 0};
324	if(tpGenKeys(testParams->cspHand,
325			dlDbHand,
326			numKeys,
327			KEYGEN_ALG_DEF,
328			CG_KEY_SIZE_DEFAULT,
329			"cgVerify",			// keyLabelBase
330			keyPairs->pubKeys,
331			keyPairs->privKeys)) {
332		goto abort;
333	}
334	if(comparePubKeys(numKeys, keyPairs->pubKeys)) {
335		return 1;
336	}
337	keyPairs->notBeforeStr = genTimeAtNowPlus(0);
338	keyPairs->notAfterStr = genTimeAtNowPlus(SECONDS_TO_LIVE);
339
340	testParams->perThread = keyPairs;
341	return 0;
342
343abort:
344	printf("Error generating keys; aborting\n");
345	CSSM_FREE(keyPairs->pubKeys);
346	CSSM_FREE(keyPairs->privKeys);
347	CSSM_FREE(keyPairs);
348	return 1;
349}
350
351int cgVerify(TestParams *testParams)
352{
353	unsigned 			loopNum;
354	int					status = -1;		// exit status
355	unsigned			dex;
356
357	TT_KeyPairs			*keyPairs = (TT_KeyPairs *)testParams->perThread;
358
359	/* all three of these are arrays with numCert elements */
360	CSSM_KEY_PTR		pubKeys = keyPairs->pubKeys;
361	CSSM_KEY_PTR		privKeys = keyPairs->privKeys;
362	CSSM_DATA_PTR		certs = NULL;
363
364	unsigned			numCerts = keyPairs->numKeys;
365	uint32				sigAlg = SIG_ALG_DEF;
366	ExpectResult		expectResult;
367	#if	CERT_IN_DB
368	CSSM_BOOL			useDb = CSSM_TRUE;
369	#else
370	CSSM_BOOL			useDb = CSSM_FALSE;
371	#endif
372	CSSM_DL_DB_HANDLE	dlDbHand = {0, 0};
373
374	/* malloc empty certs */
375	certs = (CSSM_DATA_PTR)CSSM_CALLOC(numCerts, sizeof(CSSM_DATA));
376	if(certs == NULL) {
377		printf("not enough memory for %u certs.\n", numCerts);
378		goto abort;
379	}
380	memset(certs, 0, numCerts * sizeof(CSSM_DATA));
381
382	for(loopNum=0; loopNum<testParams->numLoops; loopNum++) {
383		/* generate certs */
384		if(testParams->verbose) {
385			printf("generating certs...\n");
386		}
387		else if(!testParams->quiet) {
388			printChar(testParams->progressChar);
389		}
390		if(tpGenCerts(testParams->cspHand,
391				testParams->clHand,
392				numCerts,
393				sigAlg,
394				"cgConstruct",	// nameBase
395				pubKeys,
396				privKeys,
397				certs,
398				keyPairs->notBeforeStr,
399				keyPairs->notAfterStr)) {
400			goto abort;
401		}
402
403		/* cycle thru test scenarios */
404		switch(loopNum % 4) {
405			case 0:
406				expectResult = ER_InvalidAnchor;
407				break;
408			case 1:
409				expectResult = ER_RootInCertGroup;
410				break;
411			case 2:
412				expectResult = ER_AnchorVerify;
413				break;
414			case 3:
415				expectResult = ER_NoRoot;
416				break;
417		}
418		status = doTest(testParams->tpHand,
419				testParams->clHand,
420				testParams->cspHand,
421				dlDbHand,
422				certs,
423				numCerts,
424				useDb,
425				expectResult,
426				testParams->verbose);
427		if(status) {
428			break;
429		}
430		/* free certs */
431		for(dex=0; dex<numCerts; dex++) {
432			CSSM_FREE(certs[dex].Data);
433		}
434		memset(certs, 0, numCerts * sizeof(CSSM_DATA));
435		#if DO_PAUSE
436		fpurge(stdin);
437		printf("Hit CR to proceed: ");
438		getchar();
439		#endif
440	}
441abort:
442	/* free resources */
443	for(dex=0; dex<numCerts; dex++) {
444		if(certs[dex].Data) {
445			CSSM_FREE(certs[dex].Data);
446		}
447	}
448	CSSM_FREE(keyPairs->pubKeys);
449	CSSM_FREE(keyPairs->privKeys);
450	CSSM_FREE(keyPairs);
451	return status;
452}
453
454