155714Skris/* apps/crl.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
855714Skris *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
1555714Skris *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
2255714Skris *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
3755714Skris * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
4055714Skris *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
5255714Skris *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
5955714Skris#include <stdio.h>
6055714Skris#include <stdlib.h>
6155714Skris#include <string.h>
6255714Skris#include "apps.h"
6355714Skris#include <openssl/bio.h>
6455714Skris#include <openssl/err.h>
6555714Skris#include <openssl/x509.h>
6655714Skris#include <openssl/x509v3.h>
6755714Skris#include <openssl/pem.h>
6855714Skris
6955714Skris#undef PROG
7055714Skris#define PROG	crl_main
7155714Skris
7255714Skris#undef POSTFIX
7355714Skris#define	POSTFIX	".rvk"
7455714Skris
75160814Ssimonstatic const char *crl_usage[]={
7655714Skris"usage: crl args\n",
7755714Skris"\n",
7859191Skris" -inform arg     - input format - default PEM (DER or PEM)\n",
7955714Skris" -outform arg    - output format - default PEM\n",
8055714Skris" -text           - print out a text format version\n",
8155714Skris" -in arg         - input file - default stdin\n",
8255714Skris" -out arg        - output file - default stdout\n",
8355714Skris" -hash           - print hash value\n",
84279264Sdelphij#ifndef OPENSSL_NO_MD5
85279264Sdelphij" -hash_old       - print old-style (MD5) hash value\n",
86279264Sdelphij#endif
87120631Snectar" -fingerprint    - print the crl fingerprint\n",
8855714Skris" -issuer         - print issuer DN\n",
8955714Skris" -lastupdate     - lastUpdate field\n",
9055714Skris" -nextupdate     - nextUpdate field\n",
91194206Ssimon" -crlnumber      - print CRL number\n",
9255714Skris" -noout          - no CRL output\n",
9359191Skris" -CAfile  name   - verify CRL using certificates in file \"name\"\n",
9459191Skris" -CApath  dir    - verify CRL using certificates in \"dir\"\n",
95109998Smarkm" -nameopt arg    - various certificate name options\n",
9655714SkrisNULL
9755714Skris};
9855714Skris
9955714Skrisstatic X509_CRL *load_crl(char *file, int format);
10055714Skrisstatic BIO *bio_out=NULL;
10155714Skris
10259191Skrisint MAIN(int, char **);
10359191Skris
10455714Skrisint MAIN(int argc, char **argv)
10555714Skris	{
106109998Smarkm	unsigned long nmflag = 0;
10755714Skris	X509_CRL *x=NULL;
10859191Skris	char *CAfile = NULL, *CApath = NULL;
10955714Skris	int ret=1,i,num,badops=0;
11055714Skris	BIO *out=NULL;
11155714Skris	int informat,outformat;
11255714Skris	char *infile=NULL,*outfile=NULL;
11355714Skris	int hash=0,issuer=0,lastupdate=0,nextupdate=0,noout=0,text=0;
114279264Sdelphij#ifndef OPENSSL_NO_MD5
115279264Sdelphij       int hash_old=0;
116279264Sdelphij#endif
117194206Ssimon	int fingerprint = 0, crlnumber = 0;
118160814Ssimon	const char **pp;
11959191Skris	X509_STORE *store = NULL;
12059191Skris	X509_STORE_CTX ctx;
12159191Skris	X509_LOOKUP *lookup = NULL;
12259191Skris	X509_OBJECT xobj;
12359191Skris	EVP_PKEY *pkey;
12459191Skris	int do_ver = 0;
125160814Ssimon	const EVP_MD *md_alg,*digest=EVP_sha1();
12655714Skris
12755714Skris	apps_startup();
12855714Skris
12955714Skris	if (bio_err == NULL)
13055714Skris		if ((bio_err=BIO_new(BIO_s_file())) != NULL)
13155714Skris			BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
13255714Skris
133109998Smarkm	if (!load_config(bio_err, NULL))
134109998Smarkm		goto end;
135109998Smarkm
13655714Skris	if (bio_out == NULL)
13755714Skris		if ((bio_out=BIO_new(BIO_s_file())) != NULL)
13868651Skris			{
13955714Skris			BIO_set_fp(bio_out,stdout,BIO_NOCLOSE);
140109998Smarkm#ifdef OPENSSL_SYS_VMS
14168651Skris			{
14268651Skris			BIO *tmpbio = BIO_new(BIO_f_linebuffer());
14368651Skris			bio_out = BIO_push(tmpbio, bio_out);
14468651Skris			}
14568651Skris#endif
14668651Skris			}
14755714Skris
14855714Skris	informat=FORMAT_PEM;
14955714Skris	outformat=FORMAT_PEM;
15055714Skris
15155714Skris	argc--;
15255714Skris	argv++;
15355714Skris	num=0;
15455714Skris	while (argc >= 1)
15555714Skris		{
15655714Skris#ifdef undef
15755714Skris		if	(strcmp(*argv,"-p") == 0)
15855714Skris			{
15955714Skris			if (--argc < 1) goto bad;
16055714Skris			if (!args_from_file(++argv,Nargc,Nargv)) { goto end; }*/
16155714Skris			}
16255714Skris#endif
16355714Skris		if 	(strcmp(*argv,"-inform") == 0)
16455714Skris			{
16555714Skris			if (--argc < 1) goto bad;
16655714Skris			informat=str2fmt(*(++argv));
16755714Skris			}
16855714Skris		else if (strcmp(*argv,"-outform") == 0)
16955714Skris			{
17055714Skris			if (--argc < 1) goto bad;
17155714Skris			outformat=str2fmt(*(++argv));
17255714Skris			}
17355714Skris		else if (strcmp(*argv,"-in") == 0)
17455714Skris			{
17555714Skris			if (--argc < 1) goto bad;
17655714Skris			infile= *(++argv);
17755714Skris			}
17855714Skris		else if (strcmp(*argv,"-out") == 0)
17955714Skris			{
18055714Skris			if (--argc < 1) goto bad;
18155714Skris			outfile= *(++argv);
18255714Skris			}
18359191Skris		else if (strcmp(*argv,"-CApath") == 0)
18459191Skris			{
18559191Skris			if (--argc < 1) goto bad;
18659191Skris			CApath = *(++argv);
18759191Skris			do_ver = 1;
18859191Skris			}
18959191Skris		else if (strcmp(*argv,"-CAfile") == 0)
19059191Skris			{
19159191Skris			if (--argc < 1) goto bad;
19259191Skris			CAfile = *(++argv);
19359191Skris			do_ver = 1;
19459191Skris			}
19559191Skris		else if (strcmp(*argv,"-verify") == 0)
19659191Skris			do_ver = 1;
19755714Skris		else if (strcmp(*argv,"-text") == 0)
19855714Skris			text = 1;
19955714Skris		else if (strcmp(*argv,"-hash") == 0)
20055714Skris			hash= ++num;
201279264Sdelphij#ifndef OPENSSL_NO_MD5
202279264Sdelphij		else if (strcmp(*argv,"-hash_old") == 0)
203279264Sdelphij			hash_old= ++num;
204279264Sdelphij#endif
205109998Smarkm		else if (strcmp(*argv,"-nameopt") == 0)
206109998Smarkm			{
207109998Smarkm			if (--argc < 1) goto bad;
208109998Smarkm			if (!set_name_ex(&nmflag, *(++argv))) goto bad;
209109998Smarkm			}
21055714Skris		else if (strcmp(*argv,"-issuer") == 0)
21155714Skris			issuer= ++num;
21255714Skris		else if (strcmp(*argv,"-lastupdate") == 0)
21355714Skris			lastupdate= ++num;
21455714Skris		else if (strcmp(*argv,"-nextupdate") == 0)
21555714Skris			nextupdate= ++num;
21655714Skris		else if (strcmp(*argv,"-noout") == 0)
21755714Skris			noout= ++num;
21868651Skris		else if (strcmp(*argv,"-fingerprint") == 0)
21968651Skris			fingerprint= ++num;
220194206Ssimon		else if (strcmp(*argv,"-crlnumber") == 0)
221194206Ssimon			crlnumber= ++num;
22268651Skris		else if ((md_alg=EVP_get_digestbyname(*argv + 1)))
22368651Skris			{
22468651Skris			/* ok */
22568651Skris			digest=md_alg;
22668651Skris			}
22755714Skris		else
22855714Skris			{
22955714Skris			BIO_printf(bio_err,"unknown option %s\n",*argv);
23055714Skris			badops=1;
23155714Skris			break;
23255714Skris			}
23355714Skris		argc--;
23455714Skris		argv++;
23555714Skris		}
23655714Skris
23755714Skris	if (badops)
23855714Skris		{
23955714Skrisbad:
24055714Skris		for (pp=crl_usage; (*pp != NULL); pp++)
241109998Smarkm			BIO_printf(bio_err,"%s",*pp);
24255714Skris		goto end;
24355714Skris		}
24455714Skris
24555714Skris	ERR_load_crypto_strings();
24655714Skris	x=load_crl(infile,informat);
24755714Skris	if (x == NULL) { goto end; }
24855714Skris
24959191Skris	if(do_ver) {
25059191Skris		store = X509_STORE_new();
25159191Skris		lookup=X509_STORE_add_lookup(store,X509_LOOKUP_file());
25259191Skris		if (lookup == NULL) goto end;
25359191Skris		if (!X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM))
25459191Skris			X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT);
25559191Skris
25659191Skris		lookup=X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir());
25759191Skris		if (lookup == NULL) goto end;
25859191Skris		if (!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM))
25959191Skris			X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
26059191Skris		ERR_clear_error();
26159191Skris
262109998Smarkm		if(!X509_STORE_CTX_init(&ctx, store, NULL, NULL)) {
263109998Smarkm			BIO_printf(bio_err,
264109998Smarkm				"Error initialising X509 store\n");
265109998Smarkm			goto end;
266109998Smarkm		}
26759191Skris
26859191Skris		i = X509_STORE_get_by_subject(&ctx, X509_LU_X509,
26959191Skris					X509_CRL_get_issuer(x), &xobj);
27059191Skris		if(i <= 0) {
27159191Skris			BIO_printf(bio_err,
27259191Skris				"Error getting CRL issuer certificate\n");
27359191Skris			goto end;
27459191Skris		}
27559191Skris		pkey = X509_get_pubkey(xobj.data.x509);
27659191Skris		X509_OBJECT_free_contents(&xobj);
27759191Skris		if(!pkey) {
27859191Skris			BIO_printf(bio_err,
27959191Skris				"Error getting CRL issuer public key\n");
28059191Skris			goto end;
28159191Skris		}
28259191Skris		i = X509_CRL_verify(x, pkey);
28359191Skris		EVP_PKEY_free(pkey);
28459191Skris		if(i < 0) goto end;
28559191Skris		if(i == 0) BIO_printf(bio_err, "verify failure\n");
28659191Skris		else BIO_printf(bio_err, "verify OK\n");
28759191Skris	}
28859191Skris
28955714Skris	if (num)
29055714Skris		{
29155714Skris		for (i=1; i<=num; i++)
29255714Skris			{
29355714Skris			if (issuer == i)
29455714Skris				{
295109998Smarkm				print_name(bio_out, "issuer=", X509_CRL_get_issuer(x), nmflag);
29655714Skris				}
297194206Ssimon			if (crlnumber == i)
298194206Ssimon				{
299194206Ssimon				ASN1_INTEGER *crlnum;
300194206Ssimon				crlnum = X509_CRL_get_ext_d2i(x, NID_crl_number,
301194206Ssimon							      NULL, NULL);
302194206Ssimon				BIO_printf(bio_out,"crlNumber=");
303194206Ssimon				if (crlnum)
304194206Ssimon					{
305194206Ssimon					i2a_ASN1_INTEGER(bio_out, crlnum);
306194206Ssimon					ASN1_INTEGER_free(crlnum);
307194206Ssimon					}
308194206Ssimon				else
309194206Ssimon					BIO_puts(bio_out, "<NONE>");
310194206Ssimon				BIO_printf(bio_out,"\n");
311194206Ssimon				}
31255714Skris			if (hash == i)
31355714Skris				{
31455714Skris				BIO_printf(bio_out,"%08lx\n",
31559191Skris					X509_NAME_hash(X509_CRL_get_issuer(x)));
31655714Skris				}
317279264Sdelphij#ifndef OPENSSL_NO_MD5
318279264Sdelphij			if (hash_old == i)
319279264Sdelphij				{
320279264Sdelphij				BIO_printf(bio_out,"%08lx\n",
321279264Sdelphij					X509_NAME_hash_old(
322279264Sdelphij						X509_CRL_get_issuer(x)));
323279264Sdelphij				}
324279264Sdelphij#endif
32555714Skris			if (lastupdate == i)
32655714Skris				{
32755714Skris				BIO_printf(bio_out,"lastUpdate=");
32859191Skris				ASN1_TIME_print(bio_out,
32959191Skris						X509_CRL_get_lastUpdate(x));
33055714Skris				BIO_printf(bio_out,"\n");
33155714Skris				}
33255714Skris			if (nextupdate == i)
33355714Skris				{
33455714Skris				BIO_printf(bio_out,"nextUpdate=");
33559191Skris				if (X509_CRL_get_nextUpdate(x))
33659191Skris					ASN1_TIME_print(bio_out,
33759191Skris						X509_CRL_get_nextUpdate(x));
33855714Skris				else
33955714Skris					BIO_printf(bio_out,"NONE");
34055714Skris				BIO_printf(bio_out,"\n");
34155714Skris				}
34268651Skris			if (fingerprint == i)
34368651Skris				{
34468651Skris				int j;
34568651Skris				unsigned int n;
34668651Skris				unsigned char md[EVP_MAX_MD_SIZE];
34768651Skris
34868651Skris				if (!X509_CRL_digest(x,digest,md,&n))
34968651Skris					{
35068651Skris					BIO_printf(bio_err,"out of memory\n");
35168651Skris					goto end;
35268651Skris					}
35368651Skris				BIO_printf(bio_out,"%s Fingerprint=",
35468651Skris						OBJ_nid2sn(EVP_MD_type(digest)));
35568651Skris				for (j=0; j<(int)n; j++)
35668651Skris					{
35768651Skris					BIO_printf(bio_out,"%02X%c",md[j],
35868651Skris						(j+1 == (int)n)
35968651Skris						?'\n':':');
36068651Skris					}
36168651Skris				}
36255714Skris			}
36355714Skris		}
36455714Skris
36555714Skris	out=BIO_new(BIO_s_file());
36655714Skris	if (out == NULL)
36755714Skris		{
36855714Skris		ERR_print_errors(bio_err);
36955714Skris		goto end;
37055714Skris		}
37155714Skris
37255714Skris	if (outfile == NULL)
37368651Skris		{
37455714Skris		BIO_set_fp(out,stdout,BIO_NOCLOSE);
375109998Smarkm#ifdef OPENSSL_SYS_VMS
37668651Skris		{
37768651Skris		BIO *tmpbio = BIO_new(BIO_f_linebuffer());
37868651Skris		out = BIO_push(tmpbio, out);
37968651Skris		}
38068651Skris#endif
38168651Skris		}
38255714Skris	else
38355714Skris		{
38455714Skris		if (BIO_write_filename(out,outfile) <= 0)
38555714Skris			{
38655714Skris			perror(outfile);
38755714Skris			goto end;
38855714Skris			}
38955714Skris		}
39055714Skris
39155714Skris	if (text) X509_CRL_print(out, x);
39255714Skris
393160814Ssimon	if (noout)
394160814Ssimon		{
395160814Ssimon		ret = 0;
396160814Ssimon		goto end;
397160814Ssimon		}
39855714Skris
39955714Skris	if 	(outformat == FORMAT_ASN1)
40055714Skris		i=(int)i2d_X509_CRL_bio(out,x);
40155714Skris	else if (outformat == FORMAT_PEM)
40255714Skris		i=PEM_write_bio_X509_CRL(out,x);
40355714Skris	else
40455714Skris		{
40555714Skris		BIO_printf(bio_err,"bad output format specified for outfile\n");
40655714Skris		goto end;
40755714Skris		}
40855714Skris	if (!i) { BIO_printf(bio_err,"unable to write CRL\n"); goto end; }
40955714Skris	ret=0;
41055714Skrisend:
41168651Skris	BIO_free_all(out);
41268651Skris	BIO_free_all(bio_out);
41359191Skris	bio_out=NULL;
41455714Skris	X509_CRL_free(x);
41559191Skris	if(store) {
41659191Skris		X509_STORE_CTX_cleanup(&ctx);
41759191Skris		X509_STORE_free(store);
41859191Skris	}
419109998Smarkm	apps_shutdown();
420109998Smarkm	OPENSSL_EXIT(ret);
42155714Skris	}
42255714Skris
42355714Skrisstatic X509_CRL *load_crl(char *infile, int format)
42455714Skris	{
42555714Skris	X509_CRL *x=NULL;
42655714Skris	BIO *in=NULL;
42755714Skris
42855714Skris	in=BIO_new(BIO_s_file());
42955714Skris	if (in == NULL)
43055714Skris		{
43155714Skris		ERR_print_errors(bio_err);
43255714Skris		goto end;
43355714Skris		}
43455714Skris
43555714Skris	if (infile == NULL)
43655714Skris		BIO_set_fp(in,stdin,BIO_NOCLOSE);
43755714Skris	else
43855714Skris		{
43955714Skris		if (BIO_read_filename(in,infile) <= 0)
44055714Skris			{
44155714Skris			perror(infile);
44255714Skris			goto end;
44355714Skris			}
44455714Skris		}
44555714Skris	if 	(format == FORMAT_ASN1)
44655714Skris		x=d2i_X509_CRL_bio(in,NULL);
44755714Skris	else if (format == FORMAT_PEM)
44855714Skris		x=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL);
44955714Skris	else	{
45055714Skris		BIO_printf(bio_err,"bad input format specified for input crl\n");
45155714Skris		goto end;
45255714Skris		}
45355714Skris	if (x == NULL)
45455714Skris		{
45555714Skris		BIO_printf(bio_err,"unable to load CRL\n");
45655714Skris		ERR_print_errors(bio_err);
45755714Skris		goto end;
45855714Skris		}
45955714Skris
46055714Skrisend:
46155714Skris	BIO_free(in);
46255714Skris	return(x);
46355714Skris	}
46455714Skris
465