xref: /openbsd/usr.bin/openssl/crl2p7.c (revision a6445c1d)
1 /* $OpenBSD: crl2p7.c,v 1.2 2014/08/28 14:23:52 jsing Exp $ */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young (eay@cryptsoft.com).
7  * The implementation was written so as to conform with Netscapes SSL.
8  *
9  * This library is free for commercial and non-commercial use as long as
10  * the following conditions are aheared to.  The following conditions
11  * apply to all code found in this distribution, be it the RC4, RSA,
12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13  * included with this distribution is covered by the same copyright terms
14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15  *
16  * Copyright remains Eric Young's, and as such any Copyright notices in
17  * the code are not to be removed.
18  * If this package is used in a product, Eric Young should be given attribution
19  * as the author of the parts of the library used.
20  * This can be in the form of a textual message at program startup or
21  * in documentation (online or textual) provided with the package.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *    "This product includes cryptographic software written by
34  *     Eric Young (eay@cryptsoft.com)"
35  *    The word 'cryptographic' can be left out if the rouines from the library
36  *    being used are not cryptographic related :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  *
41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  *
53  * The licence and distribution terms for any publically available version or
54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55  * copied and put under another distribution licence
56  * [including the GNU Public Licence.]
57  */
58 
59 /* This was written by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu>
60  * and donated 'to the cause' along with lots and lots of other fixes to
61  * the library. */
62 
63 #include <sys/types.h>
64 
65 #include <stdio.h>
66 #include <string.h>
67 
68 #include "apps.h"
69 
70 #include <openssl/err.h>
71 #include <openssl/evp.h>
72 #include <openssl/objects.h>
73 #include <openssl/pem.h>
74 #include <openssl/pkcs7.h>
75 #include <openssl/x509.h>
76 
77 static int add_certs_from_file(STACK_OF(X509) * stack, char *certfile);
78 
79 /* -inform arg	- input format - default PEM (DER or PEM)
80  * -outform arg - output format - default PEM
81  * -in arg	- input file - default stdin
82  * -out arg	- output file - default stdout
83  */
84 
85 int crl2pkcs7_main(int, char **);
86 
87 int
88 crl2pkcs7_main(int argc, char **argv)
89 {
90 	int i, badops = 0;
91 	BIO *in = NULL, *out = NULL;
92 	int informat, outformat;
93 	char *infile, *outfile, *prog, *certfile;
94 	PKCS7 *p7 = NULL;
95 	PKCS7_SIGNED *p7s = NULL;
96 	X509_CRL *crl = NULL;
97 	STACK_OF(OPENSSL_STRING) * certflst = NULL;
98 	STACK_OF(X509_CRL) * crl_stack = NULL;
99 	STACK_OF(X509) * cert_stack = NULL;
100 	int ret = 1, nocrl = 0;
101 
102 	infile = NULL;
103 	outfile = NULL;
104 	informat = FORMAT_PEM;
105 	outformat = FORMAT_PEM;
106 
107 	prog = argv[0];
108 	argc--;
109 	argv++;
110 	while (argc >= 1) {
111 		if (strcmp(*argv, "-inform") == 0) {
112 			if (--argc < 1)
113 				goto bad;
114 			informat = str2fmt(*(++argv));
115 		} else if (strcmp(*argv, "-outform") == 0) {
116 			if (--argc < 1)
117 				goto bad;
118 			outformat = str2fmt(*(++argv));
119 		} else if (strcmp(*argv, "-in") == 0) {
120 			if (--argc < 1)
121 				goto bad;
122 			infile = *(++argv);
123 		} else if (strcmp(*argv, "-nocrl") == 0) {
124 			nocrl = 1;
125 		} else if (strcmp(*argv, "-out") == 0) {
126 			if (--argc < 1)
127 				goto bad;
128 			outfile = *(++argv);
129 		} else if (strcmp(*argv, "-certfile") == 0) {
130 			if (--argc < 1)
131 				goto bad;
132 			if (!certflst)
133 				certflst = sk_OPENSSL_STRING_new_null();
134 			sk_OPENSSL_STRING_push(certflst, *(++argv));
135 		} else {
136 			BIO_printf(bio_err, "unknown option %s\n", *argv);
137 			badops = 1;
138 			break;
139 		}
140 		argc--;
141 		argv++;
142 	}
143 
144 	if (badops) {
145 bad:
146 		BIO_printf(bio_err, "%s [options] <infile >outfile\n", prog);
147 		BIO_printf(bio_err, "where options are\n");
148 		BIO_printf(bio_err, " -inform arg    input format - DER or PEM\n");
149 		BIO_printf(bio_err, " -outform arg   output format - DER or PEM\n");
150 		BIO_printf(bio_err, " -in arg        input file\n");
151 		BIO_printf(bio_err, " -out arg       output file\n");
152 		BIO_printf(bio_err, " -certfile arg  certificates file of chain to a trusted CA\n");
153 		BIO_printf(bio_err, "                (can be used more than once)\n");
154 		BIO_printf(bio_err, " -nocrl         no crl to load, just certs from '-certfile'\n");
155 		ret = 1;
156 		goto end;
157 	}
158 
159 	in = BIO_new(BIO_s_file());
160 	out = BIO_new(BIO_s_file());
161 	if ((in == NULL) || (out == NULL)) {
162 		ERR_print_errors(bio_err);
163 		goto end;
164 	}
165 	if (!nocrl) {
166 		if (infile == NULL)
167 			BIO_set_fp(in, stdin, BIO_NOCLOSE);
168 		else {
169 			if (BIO_read_filename(in, infile) <= 0) {
170 				perror(infile);
171 				goto end;
172 			}
173 		}
174 
175 		if (informat == FORMAT_ASN1)
176 			crl = d2i_X509_CRL_bio(in, NULL);
177 		else if (informat == FORMAT_PEM)
178 			crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
179 		else {
180 			BIO_printf(bio_err,
181 			    "bad input format specified for input crl\n");
182 			goto end;
183 		}
184 		if (crl == NULL) {
185 			BIO_printf(bio_err, "unable to load CRL\n");
186 			ERR_print_errors(bio_err);
187 			goto end;
188 		}
189 	}
190 	if ((p7 = PKCS7_new()) == NULL)
191 		goto end;
192 	if ((p7s = PKCS7_SIGNED_new()) == NULL)
193 		goto end;
194 	p7->type = OBJ_nid2obj(NID_pkcs7_signed);
195 	p7->d.sign = p7s;
196 	p7s->contents->type = OBJ_nid2obj(NID_pkcs7_data);
197 
198 	if (!ASN1_INTEGER_set(p7s->version, 1))
199 		goto end;
200 	if ((crl_stack = sk_X509_CRL_new_null()) == NULL)
201 		goto end;
202 	p7s->crl = crl_stack;
203 	if (crl != NULL) {
204 		sk_X509_CRL_push(crl_stack, crl);
205 		crl = NULL;	/* now part of p7 for freeing */
206 	}
207 	if ((cert_stack = sk_X509_new_null()) == NULL)
208 		goto end;
209 	p7s->cert = cert_stack;
210 
211 	if (certflst)
212 		for (i = 0; i < sk_OPENSSL_STRING_num(certflst); i++) {
213 			certfile = sk_OPENSSL_STRING_value(certflst, i);
214 			if (add_certs_from_file(cert_stack, certfile) < 0) {
215 				BIO_printf(bio_err,
216 				    "error loading certificates\n");
217 				ERR_print_errors(bio_err);
218 				goto end;
219 			}
220 		}
221 
222 	sk_OPENSSL_STRING_free(certflst);
223 
224 	if (outfile == NULL) {
225 		BIO_set_fp(out, stdout, BIO_NOCLOSE);
226 	} else {
227 		if (BIO_write_filename(out, outfile) <= 0) {
228 			perror(outfile);
229 			goto end;
230 		}
231 	}
232 
233 	if (outformat == FORMAT_ASN1)
234 		i = i2d_PKCS7_bio(out, p7);
235 	else if (outformat == FORMAT_PEM)
236 		i = PEM_write_bio_PKCS7(out, p7);
237 	else {
238 		BIO_printf(bio_err,
239 		    "bad output format specified for outfile\n");
240 		goto end;
241 	}
242 	if (!i) {
243 		BIO_printf(bio_err, "unable to write pkcs7 object\n");
244 		ERR_print_errors(bio_err);
245 		goto end;
246 	}
247 	ret = 0;
248 
249 end:
250 	if (in != NULL)
251 		BIO_free(in);
252 	if (out != NULL)
253 		BIO_free_all(out);
254 	if (p7 != NULL)
255 		PKCS7_free(p7);
256 	if (crl != NULL)
257 		X509_CRL_free(crl);
258 
259 
260 	return (ret);
261 }
262 
263 /*
264  *----------------------------------------------------------------------
265  * int add_certs_from_file
266  *
267  *	Read a list of certificates to be checked from a file.
268  *
269  * Results:
270  *	number of certs added if successful, -1 if not.
271  *----------------------------------------------------------------------
272  */
273 static int
274 add_certs_from_file(STACK_OF(X509) * stack, char *certfile)
275 {
276 	BIO *in = NULL;
277 	int count = 0;
278 	int ret = -1;
279 	STACK_OF(X509_INFO) * sk = NULL;
280 	X509_INFO *xi;
281 
282 	in = BIO_new(BIO_s_file());
283 	if ((in == NULL) || (BIO_read_filename(in, certfile) <= 0)) {
284 		BIO_printf(bio_err, "error opening the file, %s\n", certfile);
285 		goto end;
286 	}
287 	/* This loads from a file, a stack of x509/crl/pkey sets */
288 	sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL);
289 	if (sk == NULL) {
290 		BIO_printf(bio_err, "error reading the file, %s\n", certfile);
291 		goto end;
292 	}
293 	/* scan over it and pull out the CRL's */
294 	while (sk_X509_INFO_num(sk)) {
295 		xi = sk_X509_INFO_shift(sk);
296 		if (xi->x509 != NULL) {
297 			sk_X509_push(stack, xi->x509);
298 			xi->x509 = NULL;
299 			count++;
300 		}
301 		X509_INFO_free(xi);
302 	}
303 
304 	ret = count;
305 
306 end:
307 	/* never need to free x */
308 	if (in != NULL)
309 		BIO_free(in);
310 	if (sk != NULL)
311 		sk_X509_INFO_free(sk);
312 	return (ret);
313 }
314