1/*
2 * certcrl - generic cert/CRL verifier
3 */
4#include <security_cdsa_utils/cuFileIo.h>
5#include <utilLib/common.h>
6#include <clAppUtils/clutils.h>
7#include <stdlib.h>
8#include <stdio.h>
9#include <string.h>
10#include <Security/cssm.h>
11#include <clAppUtils/BlobList.h>
12#include <clAppUtils/certVerify.h>
13#include "script.h"
14
15static void usage(char **argv)
16{
17	printf("Usage: %s [options]\n", argv[0]);
18	printf("Options:\n");
19	printf("   -c certFileName [...]\n");
20	printf("   -C rootCertFileName [...]\n");
21	printf("   -r crlFileName [...]\n");
22	printf("   -d certDbName\n");
23	printf("   -D crlDlDbName\n");
24	printf("   -s (use system anchor certs)\n");
25	printf("   -g (use Trust Settings)\n");
26	printf("   -i (implicit anchors)\n");
27	printf("   -l=loopCount (default = 1)\n");
28	printf("   -f (leaf cert is a CA)\n");
29	printf("   -w(rite CRLs to dlDbName)\n");
30	printf("Policy options:\n");
31	printf("   -y ssl|smime|swuSign|codeSign|pkgSign|resourceSign|iChat|pkinitServer|\n"
32		   "      pkinitClient|IPSec\n");
33	printf("   -h sslHostName (implies SSL policy; default is basic)\n");
34	printf("   -t SSL client side (implies SSL policy, default is server side)\n");
35	printf("   -E senderEmail (implies SMIME policy unless iChat is specified)\n");
36	printf("Revocation options:\n");
37	printf("   -R revocationPolicy (crl|ocsp|both|none); default = none\n");
38	printf("   -a (allow certs unverified by CRL or OCSP)\n");
39	printf("   -A (require CRL verification if present in cert\n");
40	printf("   -4 (require CRL verification for all certs)\n");
41	printf("   -Q (require OCSP if present in cert)\n");
42	printf("   -5 (require OCSP verification for all certs)\n");
43	printf("   -u responderURI\n");
44	printf("   -U responderCert\n");
45	printf("   -H (OCSP cache disable)\n");
46	printf("   -W (network OCSP disable)\n");
47	printf("   -o generate OCSP nonce\n");
48	printf("   -O require nonce in OCSP response\n");
49	printf("Misc. options:\n");
50	printf("   -n (no network fetch of CRLs)\n");
51	printf("   -N (no network fetch of certs)\n");
52	printf("   -k keyUsage (In HEX starting with 0x)\n");
53	printf("   -T verifyTime (in CSSM_TIMESTRING format, like 20041217154316)\n");
54	printf("   -e=expectedError (default is CSSM_OK)\n");
55	printf("   -S scriptFile\n");
56	printf("   -p (print script variable names)\n");
57	printf("   -P (pause after each script test)\n");
58	printf("   -v (verbose)\n");
59	printf("   -q (quiet)\n");
60	printf("   -L (silent)\n");
61	exit(1);
62}
63
64
65
66/* add files named by successive items in argv to blobList, up until the
67 * next '-' arg */
68static void gatherFiles(
69	BlobList &blobList,
70	char **argv,
71	int argc,
72	int &currArg)
73{
74	if((currArg == argc) || (argv[currArg][0] == '-')) {
75		/* need at least one file name */
76		usage(argv);
77	}
78	while(currArg<argc) {
79		char *argp = argv[currArg];
80		if(argp[0] == '-') {
81			/* done with this file list */
82			currArg--;
83			return;
84		}
85		int rtn = blobList.addFile(argv[currArg]);
86		if(rtn) {
87			exit(1);
88		}
89		currArg++;
90	}
91	/* out of args */
92	return;
93}
94
95int main(int argc, char **argv)
96{
97	BlobList				certs;
98	BlobList				roots;
99	BlobList				crls;
100	int 					rtn;
101	CSSM_DL_HANDLE 			dlHand;
102	int						loop;
103	int 					arg;
104	char 					*argp;
105	CSSM_DL_DB_HANDLE_PTR	crlDbHandPtr = NULL;
106	CSSM_DL_DB_LIST			dlDbList;
107	CSSM_DL_DB_HANDLE		dlDbHandles[2];
108	CSSM_RETURN				crtn;
109	CSSM_RETURN				silent = CSSM_FALSE;
110	CSSM_BOOL				scriptPause = CSSM_FALSE;
111
112	CertVerifyArgs			vfyArgs;
113	memset(&vfyArgs, 0, sizeof(vfyArgs));
114
115	vfyArgs.version = CERT_VFY_ARGS_VERS;
116	vfyArgs.certs = &certs;
117	vfyArgs.roots = &roots;
118	vfyArgs.crls = &crls;
119
120	/* for historical reasons the defaults for these are true */
121	vfyArgs.crlNetFetchEnable = CSSM_TRUE;
122	vfyArgs.certNetFetchEnable = CSSM_TRUE;
123
124	/* user-specd variables */
125	int 					loops = 1;
126	const char				*crlDbName = NULL;
127	const char				*certDbName = NULL;
128	char					*scriptFile = NULL;
129
130	if(argc < 2) {
131		usage(argv);
132	}
133	for(arg=1; arg<argc; arg++) {
134		argp = argv[arg];
135		if(argp[0] != '-') {
136			usage(argv);
137		}
138		switch(argp[1]) {
139			case 'l':
140				loops = atoi(&argp[3]);
141				break;
142			case 'r':
143				arg++;
144				gatherFiles(crls, argv, argc, arg);
145				break;
146			case 'c':
147				arg++;
148				gatherFiles(certs, argv, argc, arg);
149				break;
150			case 'C':
151				arg++;
152				gatherFiles(roots, argv, argc, arg);
153				break;
154			case 'v':
155				vfyArgs.verbose = CSSM_TRUE;
156				break;
157			case 'q':
158				vfyArgs.quiet = CSSM_TRUE;
159				break;
160			case 's':
161				vfyArgs.useSystemAnchors = CSSM_TRUE;
162				break;
163			case 'g':
164				vfyArgs.useTrustSettings = CSSM_TRUE;
165				break;
166			case 'i':
167				vfyArgs.implicitAnchors = CSSM_TRUE;
168				break;
169			case 'a':
170				vfyArgs.allowUnverified = CSSM_TRUE;
171				break;
172			case 'e':
173				vfyArgs.expectedErrStr = &argp[3];
174				break;
175			case 'n':
176				vfyArgs.crlNetFetchEnable = CSSM_FALSE;
177				break;
178			case 'N':
179				vfyArgs.certNetFetchEnable = CSSM_FALSE;
180				break;
181			case 'f':
182				vfyArgs.leafCertIsCA = CSSM_TRUE;
183				break;
184			case 'd':
185				arg++;
186				if(arg == argc) {
187					usage(argv);
188				}
189				certDbName = argv[arg];
190				break;
191			case 'D':
192				arg++;
193				if(arg == argc) {
194					usage(argv);
195				}
196				crlDbName = argv[arg];
197				break;
198			case 'S':
199				arg++;
200				if(arg == argc) {
201					usage(argv);
202				}
203				scriptFile = argv[arg];
204				break;
205			case 'h':
206				arg++;
207				if(arg == argc) {
208					usage(argv);
209				}
210				vfyArgs.sslHost= argv[arg];
211				vfyArgs.vfyPolicy = CVP_SSL;
212				break;
213			case 'E':
214				arg++;
215				if(arg == argc) {
216					usage(argv);
217				}
218				if(vfyArgs.vfyPolicy == CVP_Basic) {
219					/* user hasn't specified; now default to SMIME - still
220					 * can override (e.g., for iChat) */
221					vfyArgs.vfyPolicy = CVP_SMIME;
222				}
223				vfyArgs.senderEmail = argv[arg];
224				break;
225			case 'k':
226				arg++;
227				if(arg == argc) {
228					usage(argv);
229				}
230				vfyArgs.intendedKeyUse = hexToBin(argv[arg]);
231				break;
232			case 't':
233				vfyArgs.sslClient = CSSM_TRUE;
234				vfyArgs.vfyPolicy = CVP_SSL;
235				break;
236			case 'y':
237				arg++;
238				if(arg == argc) {
239					usage(argv);
240				}
241				argp = argv[arg];
242				if(parsePolicyString(argp, &vfyArgs.vfyPolicy)) {
243					printf("Bogus policyValue (%s)\n", argp);
244					printPolicyStrings();
245					exit(1);
246				}
247				break;
248			case 'R':
249				arg++;
250				if(arg == argc) {
251					usage(argv);
252				}
253				argp = argv[arg];
254				if(!strcmp(argp, "none")) {
255					vfyArgs.revokePolicy = CRP_None;
256				}
257				else if(!strcmp(argp, "crl")) {
258					vfyArgs.revokePolicy = CRP_CRL;
259				}
260				else if(!strcmp(argp, "ocsp")) {
261					vfyArgs.revokePolicy = CRP_OCSP;
262				}
263				else if(!strcmp(argp, "both")) {
264					vfyArgs.revokePolicy = CRP_CRL_OCSP;
265				}
266				else {
267					usage(argv);
268				}
269				break;
270			case 'u':
271				arg++;
272				if(arg == argc) {
273					usage(argv);
274				}
275				vfyArgs.responderURI = argv[arg];
276				/* no implied policy yet - could be CRP_OCSP or CRP_CRL_OCSP */
277				break;
278			case 'U':
279				if(readFile(argv[arg], (unsigned char **)vfyArgs.responderCert,
280					&vfyArgs.responderCertLen)) {
281					printf("***Error reading responderCert from %s. Aborting.\n",
282						argv[arg]);
283					exit(1);
284				}
285				/* no implied policy yet - could be CRP_OCSP or CRP_CRL_OCSP */
286				break;
287			case 'H':
288				vfyArgs.disableCache = CSSM_TRUE;
289				break;
290			case 'W':
291				vfyArgs.disableOcspNet = CSSM_TRUE;
292				break;
293			case 'Q':
294				vfyArgs.requireOcspIfPresent = CSSM_TRUE;
295				break;
296			case '5':
297				vfyArgs.requireOcspForAll = CSSM_TRUE;
298				break;
299			case 'o':
300				vfyArgs.generateOcspNonce = CSSM_TRUE;
301				break;
302			case 'O':
303				vfyArgs.requireOcspRespNonce = CSSM_TRUE;
304				break;
305			case 'A':
306				vfyArgs.requireCrlIfPresent = CSSM_TRUE;
307				break;
308			case '4':
309				vfyArgs.requireCrlForAll = CSSM_TRUE;
310				break;
311			case 'T':
312				arg++;
313				if(arg == argc) {
314					usage(argv);
315				}
316				vfyArgs.vfyTime = argv[arg];
317				break;
318			case 'p':
319				printScriptVars();
320				exit(0);
321			case 'P':
322				scriptPause = CSSM_TRUE;
323				break;
324			case 'L':
325				silent = CSSM_TRUE;				// inhibits start banner
326				vfyArgs.quiet = CSSM_TRUE;		// inhibits stdout from certVerify
327				break;
328			default:
329				usage(argv);
330		}
331	}
332
333	if((vfyArgs.responderCert != NULL) || (vfyArgs.responderURI != NULL)) {
334		switch(vfyArgs.revokePolicy) {
335			case CRP_None:
336				vfyArgs.revokePolicy = CRP_OCSP;
337				break;
338			case CRP_OCSP:
339			case CRP_CRL_OCSP:
340				break;
341			case CRP_CRL:
342				printf("*** OCSP options (responderURI, responderCert) only valid "
343					"with OCSP policy\n");
344				usage(argv);
345		}
346	}
347
348	vfyArgs.clHand = clStartup();
349	if(vfyArgs.clHand == CSSM_INVALID_HANDLE) {
350		return 1;
351	}
352	vfyArgs.tpHand = tpStartup();
353	if(vfyArgs.tpHand == CSSM_INVALID_HANDLE) {
354		return 1;
355	}
356	vfyArgs.cspHand = cspStartup();
357	if(vfyArgs.cspHand == CSSM_INVALID_HANDLE) {
358		return 1;
359	}
360	dlHand = dlStartup();
361	if(dlHand == CSSM_INVALID_HANDLE) {
362		return 1;
363	}
364
365	if(!silent) {
366		testStartBanner("certcrl", argc, argv);
367	}
368
369	if(scriptFile) {
370		ScriptVars vars;
371		vars.allowUnverified		= vfyArgs.allowUnverified;
372		vars.requireCrlIfPresent	= vfyArgs.requireCrlIfPresent;
373		vars.requireOcspIfPresent	= vfyArgs.requireOcspIfPresent;
374		vars.crlNetFetchEnable		= vfyArgs.crlNetFetchEnable;
375		vars.certNetFetchEnable		= vfyArgs.certNetFetchEnable;
376		vars.useSystemAnchors		= vfyArgs.useSystemAnchors;
377		vars.useTrustSettings		= vfyArgs.useTrustSettings;
378		vars.leafCertIsCA			= vfyArgs.leafCertIsCA;
379		vars.cacheDisable			= vfyArgs.disableCache;
380		vars.ocspNetFetchDisable	= vfyArgs.disableOcspNet;
381		vars.requireCrlForAll		= vfyArgs.requireCrlForAll;
382		vars.requireOcspForAll		= vfyArgs.requireOcspForAll;
383		return runScript(scriptFile, vfyArgs.tpHand, vfyArgs.clHand,
384			vfyArgs.cspHand, dlHand,
385			&vars, vfyArgs.quiet, vfyArgs.verbose, scriptPause);
386	}
387
388	/* open DlDbs if enabled */
389	dlDbList.NumHandles = 0;
390	dlDbList.DLDBHandle = &dlDbHandles[0];
391	dlDbList.DLDBHandle[0].DLHandle = dlHand;
392	dlDbList.DLDBHandle[1].DLHandle = dlHand;
393	if(certDbName != NULL) {
394		crtn = CSSM_DL_DbOpen(dlHand,
395			certDbName,
396			NULL,			// DbLocation
397			CSSM_DB_ACCESS_READ,
398			NULL, 			// CSSM_ACCESS_CREDENTIALS *AccessCred
399			NULL,			// void *OpenParameters
400			&dlDbList.DLDBHandle[0].DBHandle);
401		if(crtn) {
402			printError("CSSM_DL_DbOpen", crtn);
403			printf("***Error opening DB %s. Aborting.\n", certDbName);
404			return 1;
405		}
406		dlDbList.NumHandles++;
407		vfyArgs.dlDbList = &dlDbList;
408	}
409	if(crlDbName != NULL) {
410		vfyArgs.crlDlDb = &dlDbList.DLDBHandle[dlDbList.NumHandles];
411		crtn = CSSM_DL_DbOpen(dlHand,
412			crlDbName,
413			NULL,			// DbLocation
414			CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
415			NULL, 			// CSSM_ACCESS_CREDENTIALS *AccessCred
416			NULL,			// void *OpenParameters
417			&crlDbHandPtr->DBHandle);
418		if(crtn) {
419			printError("CSSM_DL_DbOpen", crtn);
420			printf("***Error opening DB %s. Aborting.\n", crlDbName);
421			return 1;
422		}
423		dlDbList.NumHandles++;
424		vfyArgs.dlDbList = &dlDbList;
425	}
426	for(loop=0; loop<loops; loop++) {
427		rtn = certVerify(&vfyArgs);
428		if(rtn) {
429			break;
430		}
431
432		if(loops != 1) {
433			fpurge(stdin);
434			printf("CR to continue, q to quit: ");
435			char c = getchar();
436			if(c == 'q') {
437				break;
438			}
439		}
440	}
441	return rtn;
442}
443
444