1/*
2 * script.cpp - run certcrl from script file
3 */
4
5#include <security_cdsa_utils/cuFileIo.h>
6#include <utilLib/common.h>
7#include <stdlib.h>
8#include <stdio.h>
9#include <string.h>
10#include <ctype.h>
11#include <Security/cssm.h>
12#include <clAppUtils/BlobList.h>
13#include <clAppUtils/certVerify.h>
14#include "script.h"
15
16/* Line type returned from parseLine */
17typedef enum {
18	LT_Empty,			// comments, whitespace
19	LT_TestName,
20	LT_DirName,
21	LT_Cert,
22	LT_Root,
23	LT_CRL,
24	LT_CertDb,
25	LT_CrlDb,
26	LT_ExpectError,		// expected function return
27	LT_CertError,		// per-cert error string
28	LT_CertStatus,		// per-cert StatusBits
29	LT_SslHost,
30	LT_SslClient,
31	LT_SenderEmail,
32	LT_Policy,
33	LT_KeyUsage,
34	LT_RevokePolicy,
35	LT_RespURI,
36	LT_RespCert,
37	LT_EndOfSection,
38	LT_EndOfFile,
39	LT_BadLine,
40	LT_Globals,
41	LT_Echo,
42	LT_GenerateOcspNonce,
43	LT_RequireOcspNonce,
44	LT_AllowExpiredRoot,
45	LT_VerifyTime,
46	LT_ImplicitAnchors,
47
48	/* variables which can be in globals or per-test */
49	LT_AllowUnverified,
50	LT_CrlNetFetchEnable,
51	LT_CertNetFetchEnable,
52	LT_UseSystemAnchors,
53	LT_UseTrustSettings,
54	LT_LeafCertIsCA,
55	LT_CacheDisable,
56	LT_OcspNetFetchDisable,
57	LT_RequireOcspIfPresent,
58	LT_RequireCrlIfPresent,
59	LT_RequireCrlForAll,
60	LT_RequireOcspForAll
61} LineType;
62
63/* table to map key names to LineType */
64typedef struct {
65	const char 	*keyName;
66	LineType	lineType;
67} KeyLineType;
68
69KeyLineType keyLineTypes[] =
70{
71	{ "test", 				LT_TestName 			},
72	{ "dir",				LT_DirName 				},
73	{ "cert",				LT_Cert 				},
74	{ "root",				LT_Root 				},
75	{ "crl",				LT_CRL 					},
76	{ "certDb",				LT_CertDb				},
77	{ "crlDb",				LT_CrlDb				},	// no longer used
78	{ "error",				LT_ExpectError 			},
79	{ "certerror",			LT_CertError			},
80	{ "certstatus",			LT_CertStatus			},
81	{ "sslHost",			LT_SslHost				},
82	{ "sslClient",			LT_SslClient			},
83	{ "senderEmail",		LT_SenderEmail			},
84	{ "policy",				LT_Policy				},
85	{ "keyUsage",			LT_KeyUsage				},
86	{ "revokePolicy",		LT_RevokePolicy			},
87	{ "responderURI",		LT_RespURI				},
88	{ "responderCert",		LT_RespCert				},
89	{ "cacheDisable",       LT_CacheDisable			},
90	{ "echo",				LT_Echo					},
91	{ "globals",			LT_Globals				},
92	{ "end",				LT_EndOfSection			},
93	{ "allowUnverified",	LT_AllowUnverified 		},
94	{ "requireCrlIfPresent",LT_RequireCrlIfPresent  },
95	{ "crlNetFetchEnable",	LT_CrlNetFetchEnable	},
96	{ "certNetFetchEnable",	LT_CertNetFetchEnable 	},
97	{ "ocspNetFetchDisable",LT_OcspNetFetchDisable 	},
98	{ "requireCrlForAll",	LT_RequireCrlForAll		},
99	{ "requireOcspForAll",	LT_RequireOcspForAll	},
100	{ "useSystemAnchors",	LT_UseSystemAnchors	 	},
101	{ "useTrustSettings",	LT_UseTrustSettings		},
102	{ "leafCertIsCA",		LT_LeafCertIsCA			},
103	{ "requireOcspIfPresent",LT_RequireOcspIfPresent },
104	{ "generateOcspNonce",	LT_GenerateOcspNonce	},
105	{ "requireOcspNonce",	LT_RequireOcspNonce		},
106	{ "allowExpiredRoot",	LT_AllowExpiredRoot		},
107	{ "verifyTime",			LT_VerifyTime			},
108	{ "implicitAnchors",	LT_ImplicitAnchors		},
109};
110
111#define NUM_KEYS (sizeof(keyLineTypes) / sizeof(KeyLineType))
112
113/* map policy string to CertVerifyPolicy */
114typedef struct {
115	const char *str;
116	CertVerifyPolicy policy;
117} PolicyString;
118
119static const PolicyString policyStrings[] =
120{
121	{ "basic",			CVP_Basic				},
122	{ "ssl",			CVP_SSL					},
123	{ "smime",			CVP_SMIME				},
124	{ "swuSign",		CVP_SWUpdateSign		},
125	{ "codeSign",		CVP_AppleCodeSigning	},
126	{ "pkgSign",		CVP_PackageSigning		},
127	{ "resourceSign",	CVP_ResourceSigning		},
128	{ "iChat",			CVP_iChat				},
129	{ "pkinitServer",	CVP_PKINIT_Server		},
130	{ "pkinitClient",	CVP_PKINIT_Client		},
131	{ "IPSec",			CVP_IPSec				},
132	{ NULL,				(CertVerifyPolicy)0		}
133};
134
135/* skip whitespace (but not line terminators) */
136static void skipWhite(
137	const unsigned char *&cp,
138	unsigned &bytesLeft)
139{
140	while(bytesLeft != 0) {
141		switch(*cp) {
142			case ' ':
143			case '\t':
144				cp++;
145				bytesLeft--;
146				break;
147			default:
148				return;
149		}
150	}
151}
152
153/* skip to next char after EOL */
154static void skipLine(
155	const unsigned char *&cp,
156	unsigned &bytesLeft)
157{
158	bool foundEol = false;
159	while(bytesLeft != 0) {
160		switch(*cp) {
161			case '\n':
162			case '\r':
163				foundEol = true;
164				cp++;
165				bytesLeft--;
166				break;
167			default:
168				if(foundEol) {
169					return;
170				}
171				cp++;
172				bytesLeft--;
173				break;
174		}
175	}
176}
177
178/* skip to end of current token (i.e., find next whitespace or '=') */
179static void skipToken(
180	const unsigned char *&cp,
181	unsigned &bytesLeft,
182	bool isQuoted)
183{
184	while(bytesLeft != 0) {
185		char c = *cp;
186		if(isQuoted) {
187			if(c == '"') {
188				/* end of quoted string, return still pointing to it */
189				return;
190			}
191		}
192		else {
193			if(isspace(c)) {
194				return;
195			}
196			if(c == '=') {
197				/* hopefully, end of key */
198				return;
199			}
200		}
201		cp++;
202		bytesLeft--;
203	}
204}
205
206/*
207 * Parse one line, return value (following "=" and whitespace) as
208 * mallocd C string. On return, scriptData points to next char after line
209 * terminator(s).
210 *
211 * The basic form of a line is
212 * [whitespace] key [whitespace] = [whitespace] value [whitespace] \n|\r...
213 *
214 * ...except for comments and blank lines. Comments contain '#' as the
215 * first non-whitespace char.
216 */
217#define CHECK_EOF(bytesLeft)	\
218	if(bytesLeft == 0) {		\
219		return LT_BadLine;	\
220	}
221
222#define MAX_KEY_LEN		80
223
224static LineType parseLine(
225	const unsigned char	*&cp,			// IN/OUT
226	unsigned			&bytesLeft,		// IN/OUT bytes left in script
227	char				*&value,		// mallocd and RETURNED
228	CSSM_BOOL			verbose)
229{
230	if(bytesLeft == 0) {
231		if(verbose) {
232			printf("...EOF reached\n");
233		}
234		return LT_EndOfFile;
235	}
236	skipWhite(cp, bytesLeft);
237	if(bytesLeft == 0) {
238		return LT_Empty;
239	}
240	switch(*cp) {
241		case '#':
242		case '\n':
243		case '\r':
244		skipLine(cp, bytesLeft);
245		return LT_Empty;
246	}
247
248	/*
249	 * cp points to start of key
250	 * get key value as NULL terminated C string
251	 */
252	const unsigned char *tokenStart = cp;
253	skipToken(cp, bytesLeft, false);
254	CHECK_EOF(bytesLeft);
255	unsigned tokenLen = cp - tokenStart;
256	char key[MAX_KEY_LEN];
257	memmove(key, tokenStart, tokenLen);
258	key[tokenLen] = '\0';
259
260	/* parse key */
261	LineType rtnType = LT_BadLine;
262	for(unsigned i=0; i<NUM_KEYS; i++) {
263		KeyLineType *klt = &keyLineTypes[i];
264		if(!strcmp(klt->keyName, key)) {
265			rtnType = klt->lineType;
266			break;
267		}
268	}
269
270	/* these keys have no value */
271	bool noValue = false;
272	switch(rtnType) {
273		case LT_EndOfSection:
274			if(verbose) {
275				printf("...end of section\n");
276			}
277			noValue = true;
278			break;
279		case LT_Globals:
280			noValue = true;
281			break;
282		case LT_BadLine:
283			printf("***unknown key '%s'\n", key);
284			noValue = true;
285			break;
286		default:
287			break;
288	}
289	if(noValue) {
290		/* done with line */
291		skipLine(cp, bytesLeft);
292		return rtnType;
293	}
294
295	/* get to start of value */
296	skipWhite(cp, bytesLeft);
297	CHECK_EOF(bytesLeft);
298	if(rtnType == LT_Echo) {
299		/* echo: value is everything from this char to end of line */
300		tokenStart = cp;
301		for( ; bytesLeft != 0; cp++, bytesLeft--) {
302			if((*cp == '\n') || (*cp == '\r')) {
303				break;
304			}
305		}
306		if(cp != tokenStart) {
307			tokenLen = cp - tokenStart;
308			value = (char *)malloc(tokenLen + 1);
309			memmove(value, tokenStart, tokenLen);
310			value[tokenLen] = '\0';
311		}
312		else {
313			value = NULL;
314		}
315		skipLine(cp, bytesLeft);
316		return LT_Echo;
317	}
318
319	/* all other line types: value is first token after '=' */
320	if(*cp != '=') {
321		printf("===missing = after key\n");
322		return LT_BadLine;
323	}
324	cp++;
325	bytesLeft--;
326	skipWhite(cp, bytesLeft);
327	CHECK_EOF(bytesLeft);
328
329	/* cp points to start of value */
330	bool isQuoted = false;
331	if(*cp == '"') {
332		cp++;
333		bytesLeft--;
334		CHECK_EOF(bytesLeft)
335		isQuoted = true;
336	}
337	tokenStart = cp;
338	skipToken(cp, bytesLeft, isQuoted);
339	/* cp points to next char after end of value */
340	/* get value as mallocd C string */
341	tokenLen = cp - tokenStart;
342	if(tokenLen == 0) {
343		value = NULL;
344	}
345	else {
346		value = (char *)malloc(tokenLen + 1);
347		memmove(value, tokenStart, tokenLen);
348		value[tokenLen] = '\0';
349	}
350	skipLine(cp, bytesLeft);
351	if(verbose) {
352		printf("'%s' = '%s'\n", key, value);
353	}
354	return rtnType;
355}
356
357/* describe fate of one run of runOneTest() */
358typedef enum {
359	OTR_Success,
360	OTR_Fail,
361	OTR_EndOfScript
362} OneTestResult;
363
364/* parse boolean variable, in globals or per-test */
365OneTestResult parseVar(
366	LineType lineType,
367	const char *value,
368	ScriptVars &scriptVars)
369{
370	/* parse value  */
371	CSSM_BOOL cval;
372	if(!strcmp(value, "true")) {
373		cval = CSSM_TRUE;
374	}
375	else if(!strcmp(value, "false")) {
376		cval = CSSM_FALSE;
377	}
378	else {
379		printf("***boolean variables must be true or false, not '%s'\n", value);
380		return OTR_Fail;
381	}
382
383	switch(lineType) {
384		case LT_AllowUnverified:
385			scriptVars.allowUnverified = cval;
386			break;
387		case LT_CrlNetFetchEnable:
388			scriptVars.crlNetFetchEnable = cval;
389			break;
390		case LT_CertNetFetchEnable:
391			scriptVars.certNetFetchEnable = cval;
392			break;
393		case LT_UseSystemAnchors:
394			scriptVars.useSystemAnchors = cval;
395			break;
396		case LT_UseTrustSettings:
397			scriptVars.useTrustSettings = cval;
398			break;
399		case LT_LeafCertIsCA:
400			scriptVars.leafCertIsCA = cval;
401			break;
402		case LT_CacheDisable:
403			scriptVars.cacheDisable = cval;
404			break;
405		case LT_OcspNetFetchDisable:
406			scriptVars.ocspNetFetchDisable = cval;
407			break;
408		case LT_RequireOcspIfPresent:
409			scriptVars.requireOcspIfPresent = cval;
410			break;
411		case LT_RequireCrlIfPresent:
412			scriptVars.requireCrlIfPresent = cval;
413			break;
414		case LT_RequireCrlForAll:
415			scriptVars.requireCrlForAll = cval;
416			break;
417		case LT_RequireOcspForAll:
418			scriptVars.requireOcspForAll = cval;
419			break;
420		default:
421			return OTR_Fail;
422	}
423	return OTR_Success;
424}
425
426#if 0
427/* sure wish X had strnstr */
428static char *strnstr(
429	const char *big,
430	const char *little,
431	size_t len)
432{
433	const char *cp;
434	unsigned littleLen = strlen(little);
435	const char *end = big + len - littleLen;
436	char first = little[0];
437
438	for(cp=big; cp<end; cp++) {
439		/* find first char of little in what's left of big */
440		if(*cp != first) {
441			continue;
442		}
443		if(memcmp(cp, little, littleLen) == 0) {
444			return (char *)cp;
445		}
446	} while(cp < end);
447	return NULL;
448}
449#endif
450
451OneTestResult fetchGlobals(
452	const unsigned char *&scriptData,	// IN/OUT
453	unsigned 			&bytesLeft,		// IN/OUT
454	ScriptVars			&scriptVars,	// may be modified
455	CSSM_BOOL			verbose)
456{
457	char *value;		// mallocd by parseLine
458	LineType lineType;
459	OneTestResult result;
460
461	if(verbose) {
462		printf("...processing global section\n");
463	}
464	/* parse globals section until end encountered */
465	do {
466		value = NULL;
467		lineType = parseLine(scriptData, bytesLeft, value, verbose);
468		switch(lineType) {
469			case LT_Empty:
470			case LT_Globals:
471				break;					// nop
472			case LT_EndOfSection:
473				return OTR_Success;
474			case LT_EndOfFile:
475				printf("***Premature end of file in globals section.\n");
476				return OTR_EndOfScript;
477			case LT_BadLine:
478				return OTR_Fail;
479			default:
480				/* hopefully a variable */
481				result = parseVar(lineType, value, scriptVars);
482				if(result != OTR_Success) {
483					return OTR_Fail;
484				}
485				break;
486		}
487		if(value != NULL) {
488			free(value);
489		}
490	} while(1);
491	/* NOT REACHED */
492	return OTR_Success;
493}
494
495/* parse script fragment for one test, run it */
496OneTestResult runOneTest(
497	const unsigned char *&scriptData,			// IN/OUT
498	unsigned 			&bytesLeft,				// IN/OUT bytes left in script
499	CSSM_TP_HANDLE		tpHand,
500	CSSM_CL_HANDLE 		clHand,
501	CSSM_CSP_HANDLE 	cspHand,
502	CSSM_DL_HANDLE 		dlHand,
503	ScriptVars 			&scriptVars,
504	CSSM_BOOL			quiet,
505	CSSM_BOOL			verbose)
506{
507	CertVerifyArgs vfyArgs;
508	memset(&vfyArgs, 0, sizeof(vfyArgs));
509
510	/* to be gathered from script */
511	char 			*testName = NULL;
512	char 			*dirName = NULL;
513	BlobList 		certs;
514	BlobList 		roots;
515	BlobList 		crls;
516
517	LineType 		lineType;
518	char 			*value;			// mallocd by parseLine
519	int 			blobErr;
520	ScriptVars 		localVars = scriptVars;
521	OneTestResult 	result;
522	char			pathName[300];
523	CSSM_RETURN		crtn;
524	CSSM_DL_DB_HANDLE_PTR currDlDb = NULL;
525	CSSM_DL_DB_LIST	dlDbList = {0, NULL};
526
527	vfyArgs.version = CERT_VFY_ARGS_VERS;
528	vfyArgs.certs = &certs;
529	vfyArgs.roots = &roots;
530	vfyArgs.crls = &crls;
531	vfyArgs.quiet = quiet;
532	vfyArgs.tpHand = tpHand;
533	vfyArgs.clHand = clHand;
534	vfyArgs.cspHand = cspHand;
535	vfyArgs.quiet = quiet;
536	vfyArgs.revokePolicy = CRP_None;
537	vfyArgs.vfyPolicy = CVP_Basic;
538	vfyArgs.dlDbList = &dlDbList;
539
540	/* parse script up to end of test */
541	do {
542		value = NULL;
543		blobErr = 0;
544		lineType = parseLine(scriptData, bytesLeft, value, verbose);
545		switch(lineType) {
546			case LT_Empty:
547				break;					// nop
548			case LT_TestName:
549				if(testName != NULL) {
550					printf("***Duplicate test name ignored\n");
551					free(value);
552				}
553				else {
554					testName = value;	// free after test
555				}
556				value = NULL;
557				break;
558			case LT_DirName:
559				if(dirName != NULL) {
560					printf("***Duplicate directory name ignored\n");
561					free(value);
562				}
563				else {
564					dirName = value;	// free after test
565				}
566				value = NULL;
567				break;
568			case LT_Cert:
569				blobErr = certs.addFile(value, dirName);
570				break;
571			case LT_Root:
572				blobErr = roots.addFile(value, dirName);
573				break;
574			case LT_CRL:
575				blobErr = crls.addFile(value, dirName);
576				break;
577			case LT_CertDb:
578			case LT_CrlDb:
579				/* these can be called multiple times */
580				if(dirName) {
581					sprintf(pathName, "%s/%s", dirName, value);
582				}
583				else {
584					strcpy(pathName, value);
585				}
586				dlDbList.NumHandles++;
587				dlDbList.DLDBHandle = (CSSM_DL_DB_HANDLE_PTR)realloc(
588					dlDbList.DLDBHandle,
589					dlDbList.NumHandles * sizeof(CSSM_DL_DB_HANDLE));
590				currDlDb = &dlDbList.DLDBHandle[dlDbList.NumHandles-1];
591				currDlDb->DLHandle = dlHand;
592				crtn = CSSM_DL_DbOpen(dlHand,
593					pathName,
594					NULL,			// DbLocation
595					CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
596					NULL, 			// CSSM_ACCESS_CREDENTIALS *AccessCred
597					NULL,			// void *OpenParameters
598					&currDlDb->DBHandle);
599				if(crtn) {
600					printError("CSSM_DL_DbOpen", crtn);
601					printf("***Error opening DB %s. Aborting.\n", value);
602					return OTR_Fail;
603				}
604				break;
605			case LT_ExpectError:
606				if(vfyArgs.expectedErrStr != NULL) {
607					printf("***Duplicate expected error ignored\n");
608					free(value);
609				}
610				else {
611					vfyArgs.expectedErrStr = value;	// free after test
612				}
613				value = NULL;
614				break;
615			case LT_CertError:
616				vfyArgs.numCertErrors++;
617				vfyArgs.certErrors = (const char **)realloc(vfyArgs.certErrors,
618					vfyArgs.numCertErrors * sizeof(char *));
619				vfyArgs.certErrors[vfyArgs.numCertErrors - 1] = value;
620				value = NULL;						// free after test
621				break;
622			case LT_CertStatus:
623				vfyArgs.numCertStatus++;
624				vfyArgs.certStatus = (const char **)realloc(vfyArgs.certStatus,
625					vfyArgs.numCertStatus * sizeof(char *));
626				vfyArgs.certStatus[vfyArgs.numCertStatus - 1] = value;
627				value = NULL;						// // free after test
628				break;
629			case LT_SslHost:
630				vfyArgs.sslHost = value;
631				value = NULL;			// free after test
632				vfyArgs.vfyPolicy = CVP_SSL;
633				break;
634			case LT_SenderEmail:
635				vfyArgs.senderEmail = value;
636				value = NULL;			// free after test
637				if(vfyArgs.vfyPolicy == CVP_Basic) {
638					/* don't overwrite if it's already been set to e.g. iChat */
639					vfyArgs.vfyPolicy = CVP_SMIME;
640				}
641				break;
642			case LT_Policy:
643				if(parsePolicyString(value, &vfyArgs.vfyPolicy)) {
644					printf("Bogus policyValue (%s)\n", value);
645					printPolicyStrings();
646					return OTR_Fail;
647				}
648				break;
649			case LT_KeyUsage:
650				vfyArgs.intendedKeyUse = hexToBin(value);
651				break;
652			case LT_RevokePolicy:
653				if(!strcmp(value, "none")) {
654					vfyArgs.revokePolicy = CRP_None;
655				}
656				else if(!strcmp(value, "crl")) {
657					vfyArgs.revokePolicy = CRP_CRL;
658				}
659				else if(!strcmp(value, "ocsp")) {
660					vfyArgs.revokePolicy = CRP_OCSP;
661				}
662				else if(!strcmp(value, "both")) {
663					vfyArgs.revokePolicy = CRP_CRL_OCSP;
664				}
665				else {
666					printf("***Illegal revokePolicy (%s)\n.", value);
667					return OTR_Fail;
668				}
669				break;
670			case LT_RespURI:
671				vfyArgs.responderURI = value;
672				value = NULL;			// free after test
673				break;
674			case LT_VerifyTime:
675				vfyArgs.vfyTime = value;
676				value = NULL;			// free after test
677				break;
678			case LT_RespCert:
679				if(readFile(value, (unsigned char **)&vfyArgs.responderCert,
680						&vfyArgs.responderCertLen)) {
681					printf("***Error reading responderCert from %s\n", value);
682					return OTR_Fail;
683				}
684				break;
685			case LT_EndOfSection:
686				break;
687			case LT_EndOfFile:
688				/* only legal if we haven't gotten a test name */
689				if(testName == NULL) {
690					return OTR_EndOfScript;
691				}
692				printf("***Premature end of file.\n");
693				return OTR_Fail;
694			case LT_BadLine:
695				return OTR_Fail;
696			case LT_Globals:
697				result = fetchGlobals(scriptData, bytesLeft, scriptVars, verbose);
698				if(result != OTR_Success) {
699					printf("***Bad globals section\n");
700					return OTR_Fail;
701				}
702				/* and start over with these variables */
703				localVars = scriptVars;
704				break;
705			case LT_SslClient:
706				if(!strcmp(value, "true")) {
707					vfyArgs.sslClient = CSSM_TRUE;
708				}
709				else {
710					vfyArgs.sslClient = CSSM_FALSE;
711				}
712				vfyArgs.vfyPolicy = CVP_SSL;
713				break;
714			case LT_Echo:
715				if(!quiet) {
716					printf("%s\n", value);
717				}
718				break;
719			case LT_GenerateOcspNonce:
720				vfyArgs.generateOcspNonce = CSSM_TRUE;
721				break;
722			case LT_RequireOcspNonce:
723				vfyArgs.requireOcspRespNonce = CSSM_TRUE;
724				break;
725			case LT_AllowExpiredRoot:
726				if(!strcmp(value, "true")) {
727					vfyArgs.allowExpiredRoot = CSSM_TRUE;
728				}
729				else {
730					vfyArgs.allowExpiredRoot = CSSM_FALSE;
731				}
732				break;
733			case LT_ImplicitAnchors:
734				if(!strcmp(value, "true")) {
735					vfyArgs.implicitAnchors = CSSM_TRUE;
736				}
737				else {
738					vfyArgs.implicitAnchors = CSSM_FALSE;
739				}
740				break;
741			default:
742				/* hopefully a variable */
743				result = parseVar(lineType, value, localVars);
744				if(result != OTR_Success) {
745					printf("**Bogus line in script %u bytes from EOF\n",
746						bytesLeft);
747					return OTR_Fail;
748				}
749				break;
750
751		}
752		if(blobErr) {
753			return OTR_Fail;
754		}
755		if(value != NULL) {
756			free(value);
757		}
758	} while(lineType != LT_EndOfSection);
759
760	/* some args: copy from ScriptVars -> CertVerifyArgs */
761	vfyArgs.allowUnverified = localVars.allowUnverified;
762	vfyArgs.requireOcspIfPresent = localVars.requireOcspIfPresent;
763	vfyArgs.requireCrlIfPresent = localVars.requireCrlIfPresent;
764	vfyArgs.crlNetFetchEnable = localVars.crlNetFetchEnable;
765	vfyArgs.certNetFetchEnable = localVars.certNetFetchEnable;
766	vfyArgs.useSystemAnchors = localVars.useSystemAnchors;
767	vfyArgs.useTrustSettings = localVars.useTrustSettings;
768	vfyArgs.leafCertIsCA = localVars.leafCertIsCA;
769	vfyArgs.disableCache = localVars.cacheDisable;
770	vfyArgs.disableOcspNet = localVars.ocspNetFetchDisable;
771	vfyArgs.requireCrlForAll = localVars.requireCrlForAll;
772	vfyArgs.requireOcspForAll = localVars.requireOcspForAll;
773	vfyArgs.verbose = verbose;
774
775	/* here we go */
776	if(!quiet && (testName != NULL)) {
777		printf("%s\n", testName);
778	}
779	int rtn = certVerify(&vfyArgs);
780
781	OneTestResult ourRtn = OTR_Success;
782	if(rtn) {
783		printf("***Failure on %s\n", testName);
784		if(testError(quiet)) {
785			ourRtn = OTR_Fail;
786		}
787	}
788	/* free the stuff that didn't get freed and the end of the
789	 * main per-line loop */
790	if(dirName != NULL) {
791		free(dirName);
792	}
793	if(vfyArgs.expectedErrStr != NULL) {
794		free((void *)vfyArgs.expectedErrStr);
795	}
796	if(vfyArgs.certErrors != NULL) {
797		for(unsigned i=0; i<vfyArgs.numCertErrors; i++) {
798			free((void *)vfyArgs.certErrors[i]);		// mallocd by parseLine
799		}
800		free((void *)vfyArgs.certErrors);				// reallocd by us
801	}
802	if(vfyArgs.certStatus != NULL) {
803		for(unsigned i=0; i<vfyArgs.numCertStatus; i++) {
804			free((void *)vfyArgs.certStatus[i]);		// mallocd by parseLine
805		}
806		free((void *)vfyArgs.certStatus);				// reallocd by us
807	}
808	if(testName != NULL) {
809		free(testName);
810	}
811	if(vfyArgs.sslHost) {
812		free((void *)vfyArgs.sslHost);
813	}
814	if(vfyArgs.senderEmail) {
815		free((void *)vfyArgs.senderEmail);
816	}
817	if(vfyArgs.responderURI) {
818		free((void *)vfyArgs.responderURI);
819	}
820	if(vfyArgs.responderCert) {
821		free((void *)vfyArgs.responderCert);
822	}
823	if(vfyArgs.vfyTime) {
824		free((void *)vfyArgs.vfyTime);
825	}
826	if(dlDbList.DLDBHandle) {
827		for(unsigned dex=0; dex<dlDbList.NumHandles; dex++) {
828			CSSM_DL_DbClose(dlDbList.DLDBHandle[dex]);
829		}
830		free(dlDbList.DLDBHandle);
831	}
832	return ourRtn;
833}
834
835int runScript(
836	const char 		*fileName,
837	CSSM_TP_HANDLE	tpHand,
838	CSSM_CL_HANDLE 	clHand,
839	CSSM_CSP_HANDLE cspHand,
840	CSSM_DL_HANDLE 	dlHand,
841	ScriptVars		*scriptVars,
842	CSSM_BOOL		quiet,
843	CSSM_BOOL		verbose,
844	CSSM_BOOL		doPause)
845{
846	const unsigned char *scriptData;
847	unsigned char *cp;
848	unsigned scriptDataLen;
849	int rtn;
850	ScriptVars localVars = *scriptVars;
851
852	rtn = readFile(fileName, &cp, &scriptDataLen);
853	if(rtn) {
854		printf("***Error reading script file; aborting.\n");
855		printf("***Are you sure you're running this from the proper directory?\n");
856		return rtn;
857	}
858	scriptData = (const unsigned char *)cp;
859	OneTestResult result;
860
861	do {
862		result = runOneTest(scriptData, scriptDataLen,
863			tpHand, clHand, cspHand, dlHand,
864			localVars, quiet, verbose);
865		if(result == OTR_Fail) {
866			rtn = 1;
867			break;
868		}
869		if(doPause) {
870			fpurge(stdin);
871			printf("CR to continue: ");
872			getchar();
873		}
874	} while(result == OTR_Success);
875	free(cp);
876	return rtn;
877}
878
879/* parse policy string; returns nonzero if not found */
880int parsePolicyString(
881	const char *str,
882	CertVerifyPolicy *policy)
883{
884	const PolicyString *ps;
885	for(ps=policyStrings; ps->str; ps++) {
886		if(!strcmp(ps->str, str)) {
887			*policy = ps->policy;
888			return 0;
889		}
890	}
891	return 1;
892}
893
894void printPolicyStrings()
895{
896	printf("Valid policy strings are:\n   ");
897	const PolicyString *ps;
898	unsigned i=0;
899	for(ps=policyStrings; ps->str; ps++, i++) {
900		printf("%s", ps->str);
901		if(ps[1].str == NULL) {
902			break;
903		}
904		if((i % 6)  == 5) {
905			printf(",\n   ");
906		}
907		else {
908			printf(", ");
909		}
910	}
911	printf("\n");
912}
913
914void printScriptVars()
915{
916	printf("The list of script variables is as follows:\n");
917	for(unsigned dex=0; dex<NUM_KEYS; dex++) {
918		printf("   %s\n", keyLineTypes[dex].keyName);
919	}
920	printPolicyStrings();
921	printf("Valid revokePolicy strings are:\n   none, crl, ocsp, both\n");
922}
923
924