1/*
2 * crlTool.cpp
3 */
4
5#include <stdlib.h>
6#include <strings.h>
7#include <stdio.h>
8#include <unistd.h>
9#include <security_cdsa_utils/cuFileIo.h>
10#include <utilLib/common.h>
11#include <clAppUtils/clutils.h>
12#include <clAppUtils/CertParser.h>
13#include <Security/Security.h>
14#include "crlNetwork.h"
15#include <security_cdsa_utils/cuPrintCert.h>
16#define LOOPS_DEF			100
17
18static void usage(char **argv)
19{
20	printf("usage: %s [options]\n", argv[0]);
21	printf("Options:\n");
22	printf("  -c certFile    -- obtain CRL via net from this cert\n");
23	printf("  -C crlFile     -- CRL from this file\n");
24	printf("  -p             -- parse the CRL\n");
25	printf("  -o outFile     -- write the fetched CRL to this file\n");
26	printf("  -v             -- verbose CRL dump\n");
27	/* etc. */
28	exit(1);
29}
30
31static int fetchCrlViaGeneralNames(
32	const CE_GeneralNames	*names,
33	unsigned char			**crl,		// mallocd and RETURNED
34	size_t					*crlLen)	// RETURNED
35{
36	CSSM_DATA crlData = {0, NULL};
37	CSSM_RETURN crtn;
38
39	for(unsigned nameDex=0; nameDex<names->numNames; nameDex++) {
40		CE_GeneralName *name = &names->generalName[nameDex];
41		switch(name->nameType) {
42			case GNT_URI:
43				if(name->name.Length < 5) {
44					continue;
45				}
46				if(strncmp((char *)name->name.Data, "ldap:", 5) &&
47				   strncmp((char *)name->name.Data, "http:", 5) &&
48				   strncmp((char *)name->name.Data, "https:", 6)) {
49					/* eventually handle other schemes here */
50					continue;
51				}
52
53				/* OK, we can do this */
54				crtn = crlNetFetch(&name->name, LT_Crl, &crlData);
55				if(crtn) {
56					printf("...net fetch error\n");
57					return 1;
58				}
59				*crl = crlData.Data;
60				*crlLen = crlData.Length;
61				return 0;
62
63			default:
64				printf("fetchCrlViaGeneralNames: unknown"
65					"nameType (%u)", (unsigned)name->nameType);
66				break;
67		}
68	}
69	printf("...GNT_URI name not found in GeneralNames\n");
70	return 1;
71}
72
73static int fetchCrl(
74	CertParser &cert,
75	unsigned char **crl,		// mallocd and RETURNED
76	size_t *crlLen)				// RETURNED
77{
78	CE_CRLDistPointsSyntax *dps = (CE_CRLDistPointsSyntax *)
79		cert.extensionForOid(CSSMOID_CrlDistributionPoints);
80
81	*crl = NULL;
82	*crlLen = 0;
83	if(dps == NULL) {
84		/* not an error, just indicate NULL return */
85		printf("***No CrlDistributionPoints in this cert.\n");
86		return 0;
87	}
88	for(unsigned dex=0; dex<dps->numDistPoints; dex++) {
89
90		CE_CRLDistributionPoint *dp = &dps->distPoints[dex];
91		if(dp->distPointName == NULL) {
92			continue;
93		}
94		switch(dp->distPointName->nameType) {
95			case CE_CDNT_NameRelativeToCrlIssuer:
96				printf("...CE_CDNT_NameRelativeToCrlIssuer not implemented\n");
97				break;
98
99			case CE_CDNT_FullName:
100			{
101				CE_GeneralNames *names = dp->distPointName->dpn.fullName;
102				int rtn = fetchCrlViaGeneralNames(names, crl, crlLen);
103				if(rtn == 0) {
104					return 0;
105				}
106				/* else try again if there's another name */
107				break;
108			}	/* CE_CDNT_FullName */
109
110			default:
111				/* not yet */
112				printf("unknown distPointName->nameType (%u)\n",
113						(unsigned)dp->distPointName->nameType);
114				break;
115		}	/* switch distPointName->nameType */
116	}	/* for each distPoints */
117	printf("...CrlDistributionPoints found, but nothing we can use.\n");
118	return 0;
119}
120
121int main(int argc, char **argv)
122{
123	char *certFile = NULL;
124	char *crlFile = NULL;
125	unsigned char *certData;
126	unsigned certDataLen;
127	bool doParse = false;
128	char *outFile = NULL;
129	CSSM_BOOL verbose = CSSM_FALSE;
130	unsigned char *crl = NULL;
131	size_t crlLen = 0;
132	int rtn = -1;
133
134	if(argc < 2) {
135		usage(argv);
136	}
137
138	extern char *optarg;
139	int arg;
140	while ((arg = getopt(argc, argv, "c:C:po:vh")) != -1) {
141		switch (arg) {
142			case 'c':
143				certFile = optarg;
144				break;
145			case 'C':
146				crlFile = optarg;
147				break;
148			case 'p':
149				doParse = true;
150				break;
151			case 'o':
152				outFile = optarg;
153				break;
154			case 'v':
155				verbose = CSSM_TRUE;
156				break;
157			case 'h':
158				usage(argv);
159		}
160	}
161	if(optind != argc) {
162		usage(argv);
163	}
164	if((certFile != NULL) && (crlFile != NULL)) {
165		printf("***crlFile and certFile are mutually exclusive.\n");
166		usage(argv);
167	}
168	if((certFile == NULL) && (crlFile == NULL)) {
169		printf("***Must specify either certFile or crlFile\n");
170		usage(argv);
171	}
172
173	CSSM_RETURN crtn;
174	CSSM_CL_HANDLE clHand = clStartup();
175	CertParser parser(clHand);
176
177	if(crlFile) {
178		unsigned len;
179		if(readFile(crlFile, &crl, &len)) {
180			printf("***Error reading %s. Aborting.\n", crlFile);
181			exit(1);
182		}
183		crlLen = len;
184	}
185	if(certFile) {
186		if(readFile(certFile, &certData, &certDataLen)) {
187			printf("***Error reading %s. Aborting.\n", certFile);
188			exit(1);
189		}
190		CSSM_DATA cdata = {certDataLen, certData};
191		crtn = parser.initWithData(cdata);
192		if(crtn) {
193			printf("Error parsing cert %s. Aborting.\n", certFile);
194			exit(1);
195		}
196		rtn = fetchCrl(parser, &crl, &crlLen);
197		if(rtn) {
198			printf("***aborting.\n");
199			exit(1);
200		}
201	}
202
203	if(doParse) {
204		if(crl == NULL) {
205			printf("...parse specified but no CRL found.\n");
206		}
207		else {
208			if(certFile != NULL) {
209				printf("============== CRL for cert %s ==============\n", certFile);
210			}
211			printCrl(crl, crlLen, verbose);
212			if(certFile != NULL) {
213				printf("============== end of CRL ==============\n");
214			}
215		}
216	}
217	if(outFile) {
218		if(crl == NULL) {
219			printf("...outFile specified but no CRL found.\n");
220		}
221		else {
222			if(writeFile(outFile, crl, crlLen)) {
223				printf("***Error writing CRL to %s.\n", outFile);
224				rtn = 1;
225			}
226			else {
227				printf("...wrote %u bytes to %s\n", (unsigned)crlLen, outFile);
228			}
229		}
230	}
231	return rtn;
232}
233