crl.c revision 194206
1145522Sdarrenr/* apps/crl.c */
2145522Sdarrenr/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
353642Sguido * All rights reserved.
4255332Scy *
553642Sguido * This package is an SSL implementation written
680482Sdarrenr * by Eric Young (eay@cryptsoft.com).
7255332Scy * The implementation was written so as to conform with Netscapes SSL.
8255332Scy *
9255332Scy * This library is free for commercial and non-commercial use as long as
10255332Scy * the following conditions are aheared to.  The following conditions
11255332Scy * apply to all code found in this distribution, be it the RC4, RSA,
1253642Sguido * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13145522Sdarrenr * included with this distribution is covered by the same copyright terms
14145522Sdarrenr * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15145522Sdarrenr *
16145522Sdarrenr * Copyright remains Eric Young's, and as such any Copyright notices in
17145522Sdarrenr * the code are not to be removed.
1892685Sdarrenr * If this package is used in a product, Eric Young should be given attribution
1953642Sguido * as the author of the parts of the library used.
2053642Sguido * This can be in the form of a textual message at program startup or
2153642Sguido * in documentation (online or textual) provided with the package.
2253642Sguido *
23369277Scy * Redistribution and use in source and binary forms, with or without
24145522Sdarrenr * modification, are permitted provided that the following conditions
2563523Sdarrenr * are met:
2663523Sdarrenr * 1. Redistributions of source code must retain the copyright
2753642Sguido *    notice, this list of conditions and the following disclaimer.
2853642Sguido * 2. Redistributions in binary form must reproduce the above copyright
2953642Sguido *    notice, this list of conditions and the following disclaimer in the
3053642Sguido *    documentation and/or other materials provided with the distribution.
31344833Scy * 3. All advertising materials mentioning features or use of this software
32170268Sdarrenr *    must display the following acknowledgement:
33170268Sdarrenr *    "This product includes cryptographic software written by
34153876Sguido *     Eric Young (eay@cryptsoft.com)"
35145522Sdarrenr *    The word 'cryptographic' can be left out if the rouines from the library
3653642Sguido *    being used are not cryptographic related :-).
37145522Sdarrenr * 4. If you include any Windows specific code (or a derivative thereof) from
3853642Sguido *    the apps directory (application code) you must include an acknowledgement:
3953642Sguido *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
4053642Sguido *
4153642Sguido * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42145522Sdarrenr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43145522Sdarrenr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44145522Sdarrenr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45145522Sdarrenr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46145522Sdarrenr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4753642Sguido * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48344833Scy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49145522Sdarrenr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50145522Sdarrenr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51369246Scy * SUCH DAMAGE.
52145522Sdarrenr *
5353642Sguido * The licence and distribution terms for any publically available version or
5453642Sguido * derivative of this code cannot be changed.  i.e. this code cannot simply be
5553642Sguido * copied and put under another distribution licence
5653642Sguido * [including the GNU Public Licence.]
57145522Sdarrenr */
5853642Sguido
5953642Sguido#include <stdio.h>
6053642Sguido#include <stdlib.h>
6153642Sguido#include <string.h>
6253642Sguido#include "apps.h"
6353642Sguido#include <openssl/bio.h>
6453642Sguido#include <openssl/err.h>
6553642Sguido#include <openssl/x509.h>
66145522Sdarrenr#include <openssl/x509v3.h>
67145522Sdarrenr#include <openssl/pem.h>
6853642Sguido
6960850Sdarrenr#undef PROG
7060850Sdarrenr#define PROG	crl_main
71344833Scy
7260850Sdarrenr#undef POSTFIX
7360850Sdarrenr#define	POSTFIX	".rvk"
7460850Sdarrenr
7553642Sguidostatic const char *crl_usage[]={
7653642Sguido"usage: crl args\n",
7753642Sguido"\n",
7853642Sguido" -inform arg     - input format - default PEM (DER or PEM)\n",
7992685Sdarrenr" -outform arg    - output format - default PEM\n",
8053642Sguido" -text           - print out a text format version\n",
81145522Sdarrenr" -in arg         - input file - default stdin\n",
82145522Sdarrenr" -out arg        - output file - default stdout\n",
83145522Sdarrenr" -hash           - print hash value\n",
84255332Scy" -fingerprint    - print the crl fingerprint\n",
85255332Scy" -issuer         - print issuer DN\n",
86145522Sdarrenr" -lastupdate     - lastUpdate field\n",
87145522Sdarrenr" -nextupdate     - nextUpdate field\n",
88145522Sdarrenr" -crlnumber      - print CRL number\n",
89145522Sdarrenr" -noout          - no CRL output\n",
90145522Sdarrenr" -CAfile  name   - verify CRL using certificates in file \"name\"\n",
91145522Sdarrenr" -CApath  dir    - verify CRL using certificates in \"dir\"\n",
92145522Sdarrenr" -nameopt arg    - various certificate name options\n",
93145522SdarrenrNULL
94369277Scy};
95145522Sdarrenr
9653642Sguidostatic X509_CRL *load_crl(char *file, int format);
9753642Sguidostatic BIO *bio_out=NULL;
98255332Scy
99255332Scyint MAIN(int, char **);
100255332Scy
101255332Scyint MAIN(int argc, char **argv)
102255332Scy	{
103145522Sdarrenr	unsigned long nmflag = 0;
10453642Sguido	X509_CRL *x=NULL;
10580482Sdarrenr	char *CAfile = NULL, *CApath = NULL;
10680482Sdarrenr	int ret=1,i,num,badops=0;
10780482Sdarrenr	BIO *out=NULL;
108172776Sdarrenr	int informat,outformat;
10980482Sdarrenr	char *infile=NULL,*outfile=NULL;
11080482Sdarrenr	int hash=0,issuer=0,lastupdate=0,nextupdate=0,noout=0,text=0;
11153642Sguido	int fingerprint = 0, crlnumber = 0;
11253642Sguido	const char **pp;
11353642Sguido	X509_STORE *store = NULL;
11453642Sguido	X509_STORE_CTX ctx;
115255332Scy	X509_LOOKUP *lookup = NULL;
11653642Sguido	X509_OBJECT xobj;
11753642Sguido	EVP_PKEY *pkey;
118363769Scy	int do_ver = 0;
119363769Scy	const EVP_MD *md_alg,*digest=EVP_sha1();
120255332Scy
121255332Scy	apps_startup();
12253642Sguido
123369245Sgit2svn	if (bio_err == NULL)
124369245Sgit2svn		if ((bio_err=BIO_new(BIO_s_file())) != NULL)
125369245Sgit2svn			BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
126369245Sgit2svn
127255332Scy	if (!load_config(bio_err, NULL))
128369245Sgit2svn		goto end;
12953642Sguido
130369245Sgit2svn	if (bio_out == NULL)
131369245Sgit2svn		if ((bio_out=BIO_new(BIO_s_file())) != NULL)
132369245Sgit2svn			{
133369245Sgit2svn			BIO_set_fp(bio_out,stdout,BIO_NOCLOSE);
134369245Sgit2svn#ifdef OPENSSL_SYS_VMS
135369245Sgit2svn			{
136369245Sgit2svn			BIO *tmpbio = BIO_new(BIO_f_linebuffer());
137369245Sgit2svn			bio_out = BIO_push(tmpbio, bio_out);
138369245Sgit2svn			}
139369245Sgit2svn#endif
140369245Sgit2svn			}
141369245Sgit2svn
142369245Sgit2svn	informat=FORMAT_PEM;
143369245Sgit2svn	outformat=FORMAT_PEM;
144369245Sgit2svn
145369245Sgit2svn	argc--;
146369245Sgit2svn	argv++;
147369245Sgit2svn	num=0;
148369245Sgit2svn	while (argc >= 1)
149369245Sgit2svn		{
150369245Sgit2svn#ifdef undef
151369245Sgit2svn		if	(strcmp(*argv,"-p") == 0)
152369245Sgit2svn			{
153369245Sgit2svn			if (--argc < 1) goto bad;
154369245Sgit2svn			if (!args_from_file(++argv,Nargc,Nargv)) { goto end; }*/
155369245Sgit2svn			}
156369245Sgit2svn#endif
157369245Sgit2svn		if 	(strcmp(*argv,"-inform") == 0)
158369245Sgit2svn			{
159369245Sgit2svn			if (--argc < 1) goto bad;
160369245Sgit2svn			informat=str2fmt(*(++argv));
161369245Sgit2svn			}
162369245Sgit2svn		else if (strcmp(*argv,"-outform") == 0)
163369245Sgit2svn			{
164369245Sgit2svn			if (--argc < 1) goto bad;
165369245Sgit2svn			outformat=str2fmt(*(++argv));
166369245Sgit2svn			}
167369245Sgit2svn		else if (strcmp(*argv,"-in") == 0)
168369245Sgit2svn			{
169369245Sgit2svn			if (--argc < 1) goto bad;
170369245Sgit2svn			infile= *(++argv);
171369245Sgit2svn			}
172369245Sgit2svn		else if (strcmp(*argv,"-out") == 0)
173369245Sgit2svn			{
174369245Sgit2svn			if (--argc < 1) goto bad;
175369245Sgit2svn			outfile= *(++argv);
176369245Sgit2svn			}
177369245Sgit2svn		else if (strcmp(*argv,"-CApath") == 0)
178369245Sgit2svn			{
179369245Sgit2svn			if (--argc < 1) goto bad;
180255332Scy			CApath = *(++argv);
181369245Sgit2svn			do_ver = 1;
182344833Scy			}
183255332Scy		else if (strcmp(*argv,"-CAfile") == 0)
184145522Sdarrenr			{
18553642Sguido			if (--argc < 1) goto bad;
18653642Sguido			CAfile = *(++argv);
18753642Sguido			do_ver = 1;
18853642Sguido			}
189145522Sdarrenr		else if (strcmp(*argv,"-verify") == 0)
190145522Sdarrenr			do_ver = 1;
191145522Sdarrenr		else if (strcmp(*argv,"-text") == 0)
19253642Sguido			text = 1;
193351468Scy		else if (strcmp(*argv,"-hash") == 0)
19453642Sguido			hash= ++num;
19553642Sguido		else if (strcmp(*argv,"-nameopt") == 0)
19653642Sguido			{
19753642Sguido			if (--argc < 1) goto bad;
19853642Sguido			if (!set_name_ex(&nmflag, *(++argv))) goto bad;
19953642Sguido			}
20053642Sguido		else if (strcmp(*argv,"-issuer") == 0)
20153642Sguido			issuer= ++num;
20253642Sguido		else if (strcmp(*argv,"-lastupdate") == 0)
20353642Sguido			lastupdate= ++num;
20453642Sguido		else if (strcmp(*argv,"-nextupdate") == 0)
20553642Sguido			nextupdate= ++num;
20653642Sguido		else if (strcmp(*argv,"-noout") == 0)
20753642Sguido			noout= ++num;
20853642Sguido		else if (strcmp(*argv,"-fingerprint") == 0)
20953642Sguido			fingerprint= ++num;
21053642Sguido		else if (strcmp(*argv,"-crlnumber") == 0)
21153642Sguido			crlnumber= ++num;
21253642Sguido		else if ((md_alg=EVP_get_digestbyname(*argv + 1)))
21353642Sguido			{
21453642Sguido			/* ok */
21553642Sguido			digest=md_alg;
216145522Sdarrenr			}
217275199Scy		else
218145522Sdarrenr			{
219145522Sdarrenr			BIO_printf(bio_err,"unknown option %s\n",*argv);
220145522Sdarrenr			badops=1;
221145522Sdarrenr			break;
222145522Sdarrenr			}
223145522Sdarrenr		argc--;
224145522Sdarrenr		argv++;
225145522Sdarrenr		}
226153876Sguido
227145522Sdarrenr	if (badops)
228145522Sdarrenr		{
229145522Sdarrenrbad:
230145522Sdarrenr		for (pp=crl_usage; (*pp != NULL); pp++)
23153642Sguido			BIO_printf(bio_err,"%s",*pp);
23253642Sguido		goto end;
23353642Sguido		}
234351468Scy
23553642Sguido	ERR_load_crypto_strings();
23653642Sguido	x=load_crl(infile,informat);
23753642Sguido	if (x == NULL) { goto end; }
23853642Sguido
23953642Sguido	if(do_ver) {
24053642Sguido		store = X509_STORE_new();
24153642Sguido		lookup=X509_STORE_add_lookup(store,X509_LOOKUP_file());
24253642Sguido		if (lookup == NULL) goto end;
24353642Sguido		if (!X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM))
24453642Sguido			X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT);
245255332Scy
24653642Sguido		lookup=X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir());
247255332Scy		if (lookup == NULL) goto end;
248255332Scy		if (!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM))
249255332Scy			X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
250255332Scy		ERR_clear_error();
251255332Scy
252255332Scy		if(!X509_STORE_CTX_init(&ctx, store, NULL, NULL)) {
253255332Scy			BIO_printf(bio_err,
254255332Scy				"Error initialising X509 store\n");
255255332Scy			goto end;
256255332Scy		}
257255332Scy
258255332Scy		i = X509_STORE_get_by_subject(&ctx, X509_LU_X509,
259255332Scy					X509_CRL_get_issuer(x), &xobj);
260255332Scy		if(i <= 0) {
261255332Scy			BIO_printf(bio_err,
262255332Scy				"Error getting CRL issuer certificate\n");
263255332Scy			goto end;
264255332Scy		}
265255332Scy		pkey = X509_get_pubkey(xobj.data.x509);
266255332Scy		X509_OBJECT_free_contents(&xobj);
267255332Scy		if(!pkey) {
268255332Scy			BIO_printf(bio_err,
269255332Scy				"Error getting CRL issuer public key\n");
270255332Scy			goto end;
271255332Scy		}
272255332Scy		i = X509_CRL_verify(x, pkey);
273255332Scy		EVP_PKEY_free(pkey);
27453642Sguido		if(i < 0) goto end;
275145522Sdarrenr		if(i == 0) BIO_printf(bio_err, "verify failure\n");
27653642Sguido		else BIO_printf(bio_err, "verify OK\n");
277255332Scy	}
278255332Scy
279255332Scy	if (num)
280255332Scy		{
281255332Scy		for (i=1; i<=num; i++)
282255332Scy			{
283255332Scy			if (issuer == i)
284255332Scy				{
285255332Scy				print_name(bio_out, "issuer=", X509_CRL_get_issuer(x), nmflag);
286255332Scy				}
287255332Scy			if (crlnumber == i)
288255332Scy				{
289255332Scy				ASN1_INTEGER *crlnum;
290255332Scy				crlnum = X509_CRL_get_ext_d2i(x, NID_crl_number,
291255332Scy							      NULL, NULL);
292255332Scy				BIO_printf(bio_out,"crlNumber=");
293255332Scy				if (crlnum)
294255332Scy					{
295255332Scy					i2a_ASN1_INTEGER(bio_out, crlnum);
296255332Scy					ASN1_INTEGER_free(crlnum);
297255332Scy					}
298255332Scy				else
299255332Scy					BIO_puts(bio_out, "<NONE>");
300255332Scy				BIO_printf(bio_out,"\n");
301255332Scy				}
302255332Scy			if (hash == i)
303255332Scy				{
304255332Scy				BIO_printf(bio_out,"%08lx\n",
305255332Scy					X509_NAME_hash(X509_CRL_get_issuer(x)));
306255332Scy				}
307255332Scy			if (lastupdate == i)
308255332Scy				{
309255332Scy				BIO_printf(bio_out,"lastUpdate=");
310255332Scy				ASN1_TIME_print(bio_out,
311255332Scy						X509_CRL_get_lastUpdate(x));
312255332Scy				BIO_printf(bio_out,"\n");
313255332Scy				}
314255332Scy			if (nextupdate == i)
315255332Scy				{
316255332Scy				BIO_printf(bio_out,"nextUpdate=");
317255332Scy				if (X509_CRL_get_nextUpdate(x))
318255332Scy					ASN1_TIME_print(bio_out,
319255332Scy						X509_CRL_get_nextUpdate(x));
320255332Scy				else
321255332Scy					BIO_printf(bio_out,"NONE");
322255332Scy				BIO_printf(bio_out,"\n");
323255332Scy				}
324255332Scy			if (fingerprint == i)
325255332Scy				{
326255332Scy				int j;
327255332Scy				unsigned int n;
328255332Scy				unsigned char md[EVP_MAX_MD_SIZE];
329255332Scy
330255332Scy				if (!X509_CRL_digest(x,digest,md,&n))
331255332Scy					{
332255332Scy					BIO_printf(bio_err,"out of memory\n");
333255332Scy					goto end;
334255332Scy					}
335255332Scy				BIO_printf(bio_out,"%s Fingerprint=",
336255332Scy						OBJ_nid2sn(EVP_MD_type(digest)));
337255332Scy				for (j=0; j<(int)n; j++)
338255332Scy					{
339255332Scy					BIO_printf(bio_out,"%02X%c",md[j],
340255332Scy						(j+1 == (int)n)
341255332Scy						?'\n':':');
342255332Scy					}
343255332Scy				}
344255332Scy			}
345255332Scy		}
346255332Scy
347255332Scy	out=BIO_new(BIO_s_file());
348255332Scy	if (out == NULL)
349255332Scy		{
350255332Scy		ERR_print_errors(bio_err);
351255332Scy		goto end;
352255332Scy		}
353255332Scy
354255332Scy	if (outfile == NULL)
355255332Scy		{
356255332Scy		BIO_set_fp(out,stdout,BIO_NOCLOSE);
357255332Scy#ifdef OPENSSL_SYS_VMS
358255332Scy		{
359255332Scy		BIO *tmpbio = BIO_new(BIO_f_linebuffer());
360255332Scy		out = BIO_push(tmpbio, out);
361255332Scy		}
362255332Scy#endif
363255332Scy		}
364255332Scy	else
365255332Scy		{
366255332Scy		if (BIO_write_filename(out,outfile) <= 0)
367255332Scy			{
368255332Scy			perror(outfile);
369255332Scy			goto end;
370255332Scy			}
371255332Scy		}
372255332Scy
373255332Scy	if (text) X509_CRL_print(out, x);
374255332Scy
375255332Scy	if (noout)
376255332Scy		{
377145522Sdarrenr		ret = 0;
378255332Scy		goto end;
379255332Scy		}
380255332Scy
381255332Scy	if 	(outformat == FORMAT_ASN1)
382145522Sdarrenr		i=(int)i2d_X509_CRL_bio(out,x);
383145522Sdarrenr	else if (outformat == FORMAT_PEM)
384145522Sdarrenr		i=PEM_write_bio_X509_CRL(out,x);
385145522Sdarrenr	else
386330475Seadler		{
387145522Sdarrenr		BIO_printf(bio_err,"bad output format specified for outfile\n");
388145522Sdarrenr		goto end;
389145522Sdarrenr		}
390145522Sdarrenr	if (!i) { BIO_printf(bio_err,"unable to write CRL\n"); goto end; }
391255332Scy	ret=0;
392145522Sdarrenrend:
393145522Sdarrenr	BIO_free_all(out);
394145522Sdarrenr	BIO_free_all(bio_out);
395369245Sgit2svn	bio_out=NULL;
396369245Sgit2svn	X509_CRL_free(x);
397369245Sgit2svn	if(store) {
398369245Sgit2svn		X509_STORE_CTX_cleanup(&ctx);
399369245Sgit2svn		X509_STORE_free(store);
400369245Sgit2svn	}
401369245Sgit2svn	apps_shutdown();
402369245Sgit2svn	OPENSSL_EXIT(ret);
403369245Sgit2svn	}
404369245Sgit2svn
405369245Sgit2svnstatic X509_CRL *load_crl(char *infile, int format)
406369245Sgit2svn	{
407369245Sgit2svn	X509_CRL *x=NULL;
408369245Sgit2svn	BIO *in=NULL;
409145522Sdarrenr
410145522Sdarrenr	in=BIO_new(BIO_s_file());
411145522Sdarrenr	if (in == NULL)
412255332Scy		{
413145522Sdarrenr		ERR_print_errors(bio_err);
414255332Scy		goto end;
415255332Scy		}
416145522Sdarrenr
417145522Sdarrenr	if (infile == NULL)
418145522Sdarrenr		BIO_set_fp(in,stdin,BIO_NOCLOSE);
419145522Sdarrenr	else
420255332Scy		{
421145522Sdarrenr		if (BIO_read_filename(in,infile) <= 0)
422255332Scy			{
423255332Scy			perror(infile);
424255332Scy			goto end;
425255332Scy			}
42653642Sguido		}
42753642Sguido	if 	(format == FORMAT_ASN1)
428153876Sguido		x=d2i_X509_CRL_bio(in,NULL);
429153876Sguido	else if (format == FORMAT_PEM)
430145522Sdarrenr		x=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL);
43160850Sdarrenr	else	{
432145522Sdarrenr		BIO_printf(bio_err,"bad input format specified for input crl\n");
433145522Sdarrenr		goto end;
434255332Scy		}
435255332Scy	if (x == NULL)
436145522Sdarrenr		{
437145522Sdarrenr		BIO_printf(bio_err,"unable to load CRL\n");
438145522Sdarrenr		ERR_print_errors(bio_err);
439145522Sdarrenr		goto end;
440153876Sguido		}
441153876Sguido
442153876Sguidoend:
443145522Sdarrenr	BIO_free(in);
444255332Scy	return(x);
445255332Scy	}
446255332Scy
447145522Sdarrenr