xref: /openbsd-src/usr.bin/openssl/crl2p7.c (revision 85d11f29bf7e49377d19cdef965d634bba71524f)
1*85d11f29Stb /* $OpenBSD: crl2p7.c,v 1.12 2024/12/26 14:07:58 tb Exp $ */
2dab3f910Sjsing /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3dab3f910Sjsing  * All rights reserved.
4dab3f910Sjsing  *
5dab3f910Sjsing  * This package is an SSL implementation written
6dab3f910Sjsing  * by Eric Young (eay@cryptsoft.com).
7dab3f910Sjsing  * The implementation was written so as to conform with Netscapes SSL.
8dab3f910Sjsing  *
9dab3f910Sjsing  * This library is free for commercial and non-commercial use as long as
10dab3f910Sjsing  * the following conditions are aheared to.  The following conditions
11dab3f910Sjsing  * apply to all code found in this distribution, be it the RC4, RSA,
12dab3f910Sjsing  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13dab3f910Sjsing  * included with this distribution is covered by the same copyright terms
14dab3f910Sjsing  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15dab3f910Sjsing  *
16dab3f910Sjsing  * Copyright remains Eric Young's, and as such any Copyright notices in
17dab3f910Sjsing  * the code are not to be removed.
18dab3f910Sjsing  * If this package is used in a product, Eric Young should be given attribution
19dab3f910Sjsing  * as the author of the parts of the library used.
20dab3f910Sjsing  * This can be in the form of a textual message at program startup or
21dab3f910Sjsing  * in documentation (online or textual) provided with the package.
22dab3f910Sjsing  *
23dab3f910Sjsing  * Redistribution and use in source and binary forms, with or without
24dab3f910Sjsing  * modification, are permitted provided that the following conditions
25dab3f910Sjsing  * are met:
26dab3f910Sjsing  * 1. Redistributions of source code must retain the copyright
27dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer.
28dab3f910Sjsing  * 2. Redistributions in binary form must reproduce the above copyright
29dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer in the
30dab3f910Sjsing  *    documentation and/or other materials provided with the distribution.
31dab3f910Sjsing  * 3. All advertising materials mentioning features or use of this software
32dab3f910Sjsing  *    must display the following acknowledgement:
33dab3f910Sjsing  *    "This product includes cryptographic software written by
34dab3f910Sjsing  *     Eric Young (eay@cryptsoft.com)"
35dab3f910Sjsing  *    The word 'cryptographic' can be left out if the rouines from the library
36dab3f910Sjsing  *    being used are not cryptographic related :-).
37dab3f910Sjsing  * 4. If you include any Windows specific code (or a derivative thereof) from
38dab3f910Sjsing  *    the apps directory (application code) you must include an acknowledgement:
39dab3f910Sjsing  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40dab3f910Sjsing  *
41dab3f910Sjsing  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42dab3f910Sjsing  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43dab3f910Sjsing  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44dab3f910Sjsing  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45dab3f910Sjsing  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46dab3f910Sjsing  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47dab3f910Sjsing  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48dab3f910Sjsing  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49dab3f910Sjsing  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50dab3f910Sjsing  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51dab3f910Sjsing  * SUCH DAMAGE.
52dab3f910Sjsing  *
53dab3f910Sjsing  * The licence and distribution terms for any publically available version or
54dab3f910Sjsing  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55dab3f910Sjsing  * copied and put under another distribution licence
56dab3f910Sjsing  * [including the GNU Public Licence.]
57dab3f910Sjsing  */
58dab3f910Sjsing 
59dab3f910Sjsing /* This was written by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu>
60dab3f910Sjsing  * and donated 'to the cause' along with lots and lots of other fixes to
61dab3f910Sjsing  * the library. */
62dab3f910Sjsing 
63dab3f910Sjsing #include <sys/types.h>
64dab3f910Sjsing 
65dab3f910Sjsing #include <stdio.h>
66dab3f910Sjsing #include <string.h>
67dab3f910Sjsing 
68dab3f910Sjsing #include "apps.h"
69dab3f910Sjsing 
70dab3f910Sjsing #include <openssl/err.h>
71dab3f910Sjsing #include <openssl/evp.h>
72dab3f910Sjsing #include <openssl/objects.h>
73dab3f910Sjsing #include <openssl/pem.h>
74dab3f910Sjsing #include <openssl/pkcs7.h>
75dab3f910Sjsing #include <openssl/x509.h>
76dab3f910Sjsing 
77dab3f910Sjsing static int add_certs_from_file(STACK_OF(X509) * stack, char *certfile);
78dab3f910Sjsing 
79320be8b6Sdoug static struct {
80320be8b6Sdoug 	STACK_OF(OPENSSL_STRING) *certflst;
81320be8b6Sdoug 	char *infile;
82320be8b6Sdoug 	int informat;
83320be8b6Sdoug 	int nocrl;
84320be8b6Sdoug 	char *outfile;
85320be8b6Sdoug 	int outformat;
86e7718adaStb } cfg;
87320be8b6Sdoug 
88320be8b6Sdoug static int
89320be8b6Sdoug crl2p7_opt_certfile(char *arg)
90320be8b6Sdoug {
91e7718adaStb 	if (cfg.certflst == NULL)
92e7718adaStb 		cfg.certflst = sk_OPENSSL_STRING_new_null();
93e7718adaStb 	if (cfg.certflst == NULL) {
94320be8b6Sdoug 		fprintf(stderr, "out of memory\n");
95320be8b6Sdoug 		return (1);
96320be8b6Sdoug 	}
97e7718adaStb 	if (!sk_OPENSSL_STRING_push(cfg.certflst, arg)) {
98320be8b6Sdoug 		fprintf(stderr, "out of memory\n");
99320be8b6Sdoug 		return (1);
100320be8b6Sdoug 	}
101320be8b6Sdoug 
102320be8b6Sdoug 	return (0);
103320be8b6Sdoug }
104320be8b6Sdoug 
105ea149709Sguenther static const struct option crl2p7_options[] = {
106320be8b6Sdoug 	{
107320be8b6Sdoug 		.name = "certfile",
108320be8b6Sdoug 		.argname = "file",
109320be8b6Sdoug 		.desc = "Chain of PEM certificates to a trusted CA",
110320be8b6Sdoug 		.type = OPTION_ARG_FUNC,
111320be8b6Sdoug 		.opt.argfunc = crl2p7_opt_certfile,
112320be8b6Sdoug 	},
113320be8b6Sdoug 	{
114320be8b6Sdoug 		.name = "in",
115320be8b6Sdoug 		.argname = "file",
116320be8b6Sdoug 		.desc = "Input file (default stdin)",
117320be8b6Sdoug 		.type = OPTION_ARG,
118e7718adaStb 		.opt.arg = &cfg.infile,
119320be8b6Sdoug 	},
120320be8b6Sdoug 	{
121320be8b6Sdoug 		.name = "inform",
122320be8b6Sdoug 		.argname = "format",
123320be8b6Sdoug 		.desc = "Input format (DER or PEM (default))",
124320be8b6Sdoug 		.type = OPTION_ARG_FORMAT,
125e7718adaStb 		.opt.value = &cfg.informat,
126320be8b6Sdoug 	},
127320be8b6Sdoug 	{
128320be8b6Sdoug 		.name = "nocrl",
129320be8b6Sdoug 		.desc = "Do not read CRL from input or include CRL in output",
130320be8b6Sdoug 		.type = OPTION_FLAG,
131e7718adaStb 		.opt.flag = &cfg.nocrl,
132320be8b6Sdoug 	},
133320be8b6Sdoug 	{
134320be8b6Sdoug 		.name = "out",
135320be8b6Sdoug 		.argname = "file",
136320be8b6Sdoug 		.desc = "Output file (default stdout)",
137320be8b6Sdoug 		.type = OPTION_ARG,
138e7718adaStb 		.opt.arg = &cfg.outfile,
139320be8b6Sdoug 	},
140320be8b6Sdoug 	{
141320be8b6Sdoug 		.name = "outform",
142320be8b6Sdoug 		.argname = "format",
143320be8b6Sdoug 		.desc = "Output format (DER or PEM (default))",
144320be8b6Sdoug 		.type = OPTION_ARG_FORMAT,
145e7718adaStb 		.opt.value = &cfg.outformat,
146320be8b6Sdoug 	},
147320be8b6Sdoug 	{ NULL },
148320be8b6Sdoug };
149320be8b6Sdoug 
150320be8b6Sdoug static void
151320be8b6Sdoug crl2p7_usage(void)
152320be8b6Sdoug {
153320be8b6Sdoug 	fprintf(stderr,
154320be8b6Sdoug 	    "usage: crl2p7 [-certfile file] [-in file] [-inform DER | PEM]\n"
155320be8b6Sdoug 	    "    [-nocrl] [-out file] [-outform DER | PEM]\n\n");
156320be8b6Sdoug 	options_usage(crl2p7_options);
157320be8b6Sdoug }
158dab3f910Sjsing 
159dab3f910Sjsing int
160dab3f910Sjsing crl2pkcs7_main(int argc, char **argv)
161dab3f910Sjsing {
162320be8b6Sdoug 	int i;
163dab3f910Sjsing 	BIO *in = NULL, *out = NULL;
164320be8b6Sdoug 	char *certfile;
165dab3f910Sjsing 	PKCS7 *p7 = NULL;
166dab3f910Sjsing 	PKCS7_SIGNED *p7s = NULL;
167dab3f910Sjsing 	X509_CRL *crl = NULL;
168dab3f910Sjsing 	STACK_OF(X509_CRL) *crl_stack = NULL;
169dab3f910Sjsing 	STACK_OF(X509) *cert_stack = NULL;
170320be8b6Sdoug 	int ret = 1;
171dab3f910Sjsing 
17251811eadSderaadt 	if (pledge("stdio cpath wpath rpath", NULL) == -1) {
1739bc487adSdoug 		perror("pledge");
174e370f0eeSdoug 		exit(1);
175e370f0eeSdoug 	}
1769bc487adSdoug 
177e7718adaStb 	memset(&cfg, 0, sizeof(cfg));
178dab3f910Sjsing 
179e7718adaStb 	cfg.informat = FORMAT_PEM;
180e7718adaStb 	cfg.outformat = FORMAT_PEM;
181dab3f910Sjsing 
182320be8b6Sdoug 	if (options_parse(argc, argv, crl2p7_options, NULL, NULL) != 0) {
183320be8b6Sdoug 		crl2p7_usage();
184dab3f910Sjsing 		goto end;
185dab3f910Sjsing 	}
186dab3f910Sjsing 
187dab3f910Sjsing 	in = BIO_new(BIO_s_file());
188dab3f910Sjsing 	out = BIO_new(BIO_s_file());
189320be8b6Sdoug 	if (in == NULL || out == NULL) {
190dab3f910Sjsing 		ERR_print_errors(bio_err);
191dab3f910Sjsing 		goto end;
192dab3f910Sjsing 	}
193e7718adaStb 	if (!cfg.nocrl) {
194e7718adaStb 		if (cfg.infile == NULL)
195dab3f910Sjsing 			BIO_set_fp(in, stdin, BIO_NOCLOSE);
196dab3f910Sjsing 		else {
197e7718adaStb 			if (BIO_read_filename(in, cfg.infile) <= 0) {
198e7718adaStb 				perror(cfg.infile);
199dab3f910Sjsing 				goto end;
200dab3f910Sjsing 			}
201dab3f910Sjsing 		}
202dab3f910Sjsing 
203e7718adaStb 		if (cfg.informat == FORMAT_ASN1)
204dab3f910Sjsing 			crl = d2i_X509_CRL_bio(in, NULL);
205e7718adaStb 		else if (cfg.informat == FORMAT_PEM)
206dab3f910Sjsing 			crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
207dab3f910Sjsing 		else {
208dab3f910Sjsing 			BIO_printf(bio_err,
209dab3f910Sjsing 			    "bad input format specified for input crl\n");
210dab3f910Sjsing 			goto end;
211dab3f910Sjsing 		}
212dab3f910Sjsing 		if (crl == NULL) {
213dab3f910Sjsing 			BIO_printf(bio_err, "unable to load CRL\n");
214dab3f910Sjsing 			ERR_print_errors(bio_err);
215dab3f910Sjsing 			goto end;
216dab3f910Sjsing 		}
217dab3f910Sjsing 	}
218dab3f910Sjsing 	if ((p7 = PKCS7_new()) == NULL)
219dab3f910Sjsing 		goto end;
220dab3f910Sjsing 	if ((p7s = PKCS7_SIGNED_new()) == NULL)
221dab3f910Sjsing 		goto end;
222dab3f910Sjsing 	p7->type = OBJ_nid2obj(NID_pkcs7_signed);
223dab3f910Sjsing 	p7->d.sign = p7s;
224dab3f910Sjsing 	p7s->contents->type = OBJ_nid2obj(NID_pkcs7_data);
225dab3f910Sjsing 
226dab3f910Sjsing 	if (!ASN1_INTEGER_set(p7s->version, 1))
227dab3f910Sjsing 		goto end;
228dab3f910Sjsing 	if ((crl_stack = sk_X509_CRL_new_null()) == NULL)
229dab3f910Sjsing 		goto end;
230dab3f910Sjsing 	p7s->crl = crl_stack;
231dab3f910Sjsing 	if (crl != NULL) {
232*85d11f29Stb 		if (!sk_X509_CRL_push(crl_stack, crl))
233*85d11f29Stb 			goto end;
234*85d11f29Stb 		crl = NULL;
235dab3f910Sjsing 	}
236dab3f910Sjsing 	if ((cert_stack = sk_X509_new_null()) == NULL)
237dab3f910Sjsing 		goto end;
238dab3f910Sjsing 	p7s->cert = cert_stack;
239dab3f910Sjsing 
240e7718adaStb 	if (cfg.certflst) {
241e7718adaStb 		for (i = 0; i < sk_OPENSSL_STRING_num(cfg.certflst); i++) {
242e7718adaStb 			certfile = sk_OPENSSL_STRING_value(cfg.certflst, i);
243dab3f910Sjsing 			if (add_certs_from_file(cert_stack, certfile) < 0) {
244dab3f910Sjsing 				BIO_printf(bio_err,
245dab3f910Sjsing 				    "error loading certificates\n");
246dab3f910Sjsing 				ERR_print_errors(bio_err);
247dab3f910Sjsing 				goto end;
248dab3f910Sjsing 			}
249dab3f910Sjsing 		}
250320be8b6Sdoug 	}
251dab3f910Sjsing 
252e7718adaStb 	if (cfg.outfile == NULL) {
253dab3f910Sjsing 		BIO_set_fp(out, stdout, BIO_NOCLOSE);
254dab3f910Sjsing 	} else {
255e7718adaStb 		if (BIO_write_filename(out, cfg.outfile) <= 0) {
256e7718adaStb 			perror(cfg.outfile);
257dab3f910Sjsing 			goto end;
258dab3f910Sjsing 		}
259dab3f910Sjsing 	}
260dab3f910Sjsing 
261e7718adaStb 	if (cfg.outformat == FORMAT_ASN1)
262dab3f910Sjsing 		i = i2d_PKCS7_bio(out, p7);
263e7718adaStb 	else if (cfg.outformat == FORMAT_PEM)
264dab3f910Sjsing 		i = PEM_write_bio_PKCS7(out, p7);
265dab3f910Sjsing 	else {
266dab3f910Sjsing 		BIO_printf(bio_err,
267dab3f910Sjsing 		    "bad output format specified for outfile\n");
268dab3f910Sjsing 		goto end;
269dab3f910Sjsing 	}
270dab3f910Sjsing 	if (!i) {
271dab3f910Sjsing 		BIO_printf(bio_err, "unable to write pkcs7 object\n");
272dab3f910Sjsing 		ERR_print_errors(bio_err);
273dab3f910Sjsing 		goto end;
274dab3f910Sjsing 	}
275*85d11f29Stb 
276dab3f910Sjsing 	ret = 0;
277dab3f910Sjsing 
278dab3f910Sjsing  end:
279dab3f910Sjsing 	BIO_free(in);
280dab3f910Sjsing 	BIO_free_all(out);
281dab3f910Sjsing 	PKCS7_free(p7);
282dab3f910Sjsing 	X509_CRL_free(crl);
283*85d11f29Stb 	sk_OPENSSL_STRING_free(cfg.certflst);
284dab3f910Sjsing 
285*85d11f29Stb 	return ret;
286dab3f910Sjsing }
287dab3f910Sjsing 
288dab3f910Sjsing static int
289dab3f910Sjsing add_certs_from_file(STACK_OF(X509) *stack, char *certfile)
290dab3f910Sjsing {
291dab3f910Sjsing 	BIO *in = NULL;
292dab3f910Sjsing 	int count = 0;
293dab3f910Sjsing 	int ret = -1;
294dab3f910Sjsing 	STACK_OF(X509_INFO) *sk = NULL;
295*85d11f29Stb 	X509_INFO *xi = NULL;
296dab3f910Sjsing 
297dab3f910Sjsing 	in = BIO_new(BIO_s_file());
298320be8b6Sdoug 	if (in == NULL || BIO_read_filename(in, certfile) <= 0) {
299dab3f910Sjsing 		BIO_printf(bio_err, "error opening the file, %s\n", certfile);
300dab3f910Sjsing 		goto end;
301dab3f910Sjsing 	}
302dab3f910Sjsing 	/* This loads from a file, a stack of x509/crl/pkey sets */
303dab3f910Sjsing 	sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL);
304dab3f910Sjsing 	if (sk == NULL) {
305dab3f910Sjsing 		BIO_printf(bio_err, "error reading the file, %s\n", certfile);
306dab3f910Sjsing 		goto end;
307dab3f910Sjsing 	}
308dab3f910Sjsing 	/* scan over it and pull out the CRL's */
309*85d11f29Stb 	while (sk_X509_INFO_num(sk) > 0) {
310dab3f910Sjsing 		xi = sk_X509_INFO_shift(sk);
311dab3f910Sjsing 		if (xi->x509 != NULL) {
312*85d11f29Stb 			if (!sk_X509_push(stack, xi->x509))
313*85d11f29Stb 				goto end;
314dab3f910Sjsing 			xi->x509 = NULL;
315dab3f910Sjsing 			count++;
316dab3f910Sjsing 		}
317dab3f910Sjsing 		X509_INFO_free(xi);
318*85d11f29Stb 		xi = NULL;
319dab3f910Sjsing 	}
320dab3f910Sjsing 
321dab3f910Sjsing 	ret = count;
322dab3f910Sjsing 
323dab3f910Sjsing  end:
324dab3f910Sjsing 	BIO_free(in);
325*85d11f29Stb 	X509_INFO_free(xi);
326dab3f910Sjsing 	sk_X509_INFO_free(sk);
327*85d11f29Stb 
328*85d11f29Stb 	return ret;
329dab3f910Sjsing }
330