xref: /openbsd-src/usr.bin/openssl/apps.c (revision 92d49c0785239a5ccd0757189696b8f500ae73d1)
1*92d49c07Stb /* $OpenBSD: apps.c,v 1.70 2025/01/03 09:14:42 tb Exp $ */
26b8b4364Sjsing /*
36b8b4364Sjsing  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
46b8b4364Sjsing  *
56b8b4364Sjsing  * Permission to use, copy, modify, and distribute this software for any
66b8b4364Sjsing  * purpose with or without fee is hereby granted, provided that the above
76b8b4364Sjsing  * copyright notice and this permission notice appear in all copies.
86b8b4364Sjsing  *
96b8b4364Sjsing  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
106b8b4364Sjsing  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
116b8b4364Sjsing  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
126b8b4364Sjsing  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
136b8b4364Sjsing  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
146b8b4364Sjsing  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
156b8b4364Sjsing  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
166b8b4364Sjsing  */
17dab3f910Sjsing /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
18dab3f910Sjsing  * All rights reserved.
19dab3f910Sjsing  *
20dab3f910Sjsing  * This package is an SSL implementation written
21dab3f910Sjsing  * by Eric Young (eay@cryptsoft.com).
22dab3f910Sjsing  * The implementation was written so as to conform with Netscapes SSL.
23dab3f910Sjsing  *
24dab3f910Sjsing  * This library is free for commercial and non-commercial use as long as
25dab3f910Sjsing  * the following conditions are aheared to.  The following conditions
26dab3f910Sjsing  * apply to all code found in this distribution, be it the RC4, RSA,
27dab3f910Sjsing  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
28dab3f910Sjsing  * included with this distribution is covered by the same copyright terms
29dab3f910Sjsing  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
30dab3f910Sjsing  *
31dab3f910Sjsing  * Copyright remains Eric Young's, and as such any Copyright notices in
32dab3f910Sjsing  * the code are not to be removed.
33dab3f910Sjsing  * If this package is used in a product, Eric Young should be given attribution
34dab3f910Sjsing  * as the author of the parts of the library used.
35dab3f910Sjsing  * This can be in the form of a textual message at program startup or
36dab3f910Sjsing  * in documentation (online or textual) provided with the package.
37dab3f910Sjsing  *
38dab3f910Sjsing  * Redistribution and use in source and binary forms, with or without
39dab3f910Sjsing  * modification, are permitted provided that the following conditions
40dab3f910Sjsing  * are met:
41dab3f910Sjsing  * 1. Redistributions of source code must retain the copyright
42dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer.
43dab3f910Sjsing  * 2. Redistributions in binary form must reproduce the above copyright
44dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer in the
45dab3f910Sjsing  *    documentation and/or other materials provided with the distribution.
46dab3f910Sjsing  * 3. All advertising materials mentioning features or use of this software
47dab3f910Sjsing  *    must display the following acknowledgement:
48dab3f910Sjsing  *    "This product includes cryptographic software written by
49dab3f910Sjsing  *     Eric Young (eay@cryptsoft.com)"
50dab3f910Sjsing  *    The word 'cryptographic' can be left out if the rouines from the library
51dab3f910Sjsing  *    being used are not cryptographic related :-).
52dab3f910Sjsing  * 4. If you include any Windows specific code (or a derivative thereof) from
53dab3f910Sjsing  *    the apps directory (application code) you must include an acknowledgement:
54dab3f910Sjsing  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
55dab3f910Sjsing  *
56dab3f910Sjsing  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
57dab3f910Sjsing  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58dab3f910Sjsing  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59dab3f910Sjsing  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
60dab3f910Sjsing  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61dab3f910Sjsing  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62dab3f910Sjsing  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63dab3f910Sjsing  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64dab3f910Sjsing  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65dab3f910Sjsing  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66dab3f910Sjsing  * SUCH DAMAGE.
67dab3f910Sjsing  *
68dab3f910Sjsing  * The licence and distribution terms for any publically available version or
69dab3f910Sjsing  * derivative of this code cannot be changed.  i.e. this code cannot simply be
70dab3f910Sjsing  * copied and put under another distribution licence
71dab3f910Sjsing  * [including the GNU Public Licence.]
72dab3f910Sjsing  */
73dab3f910Sjsing /* ====================================================================
74dab3f910Sjsing  * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
75dab3f910Sjsing  *
76dab3f910Sjsing  * Redistribution and use in source and binary forms, with or without
77dab3f910Sjsing  * modification, are permitted provided that the following conditions
78dab3f910Sjsing  * are met:
79dab3f910Sjsing  *
80dab3f910Sjsing  * 1. Redistributions of source code must retain the above copyright
81dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer.
82dab3f910Sjsing  *
83dab3f910Sjsing  * 2. Redistributions in binary form must reproduce the above copyright
84dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer in
85dab3f910Sjsing  *    the documentation and/or other materials provided with the
86dab3f910Sjsing  *    distribution.
87dab3f910Sjsing  *
88dab3f910Sjsing  * 3. All advertising materials mentioning features or use of this
89dab3f910Sjsing  *    software must display the following acknowledgment:
90dab3f910Sjsing  *    "This product includes software developed by the OpenSSL Project
91dab3f910Sjsing  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
92dab3f910Sjsing  *
93dab3f910Sjsing  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
94dab3f910Sjsing  *    endorse or promote products derived from this software without
95dab3f910Sjsing  *    prior written permission. For written permission, please contact
96dab3f910Sjsing  *    openssl-core@openssl.org.
97dab3f910Sjsing  *
98dab3f910Sjsing  * 5. Products derived from this software may not be called "OpenSSL"
99dab3f910Sjsing  *    nor may "OpenSSL" appear in their names without prior written
100dab3f910Sjsing  *    permission of the OpenSSL Project.
101dab3f910Sjsing  *
102dab3f910Sjsing  * 6. Redistributions of any form whatsoever must retain the following
103dab3f910Sjsing  *    acknowledgment:
104dab3f910Sjsing  *    "This product includes software developed by the OpenSSL Project
105dab3f910Sjsing  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
106dab3f910Sjsing  *
107dab3f910Sjsing  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
108dab3f910Sjsing  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
109dab3f910Sjsing  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
110dab3f910Sjsing  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
111dab3f910Sjsing  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
112dab3f910Sjsing  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
113dab3f910Sjsing  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
114dab3f910Sjsing  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
115dab3f910Sjsing  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
116dab3f910Sjsing  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
117dab3f910Sjsing  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
118dab3f910Sjsing  * OF THE POSSIBILITY OF SUCH DAMAGE.
119dab3f910Sjsing  * ====================================================================
120dab3f910Sjsing  *
121dab3f910Sjsing  * This product includes cryptographic software written by Eric Young
122dab3f910Sjsing  * (eay@cryptsoft.com).  This product includes software written by Tim
123dab3f910Sjsing  * Hudson (tjh@cryptsoft.com).
124dab3f910Sjsing  *
125dab3f910Sjsing  */
126dab3f910Sjsing 
127dab3f910Sjsing #include <sys/types.h>
128dab3f910Sjsing #include <sys/stat.h>
129dab3f910Sjsing 
130dab3f910Sjsing #include <ctype.h>
131dab3f910Sjsing #include <errno.h>
132dab3f910Sjsing #include <stdio.h>
133dab3f910Sjsing #include <stdlib.h>
134dab3f910Sjsing #include <limits.h>
135dab3f910Sjsing #include <string.h>
136dab3f910Sjsing #include <unistd.h>
137dab3f910Sjsing 
138dab3f910Sjsing #include "apps.h"
139dab3f910Sjsing 
140dab3f910Sjsing #include <openssl/bn.h>
141dab3f910Sjsing #include <openssl/err.h>
142dab3f910Sjsing #include <openssl/pem.h>
143dab3f910Sjsing #include <openssl/pkcs12.h>
14493dafd19Sjsing #include <openssl/rsa.h>
145dab3f910Sjsing #include <openssl/safestack.h>
14693dafd19Sjsing #include <openssl/ssl.h>
147dab3f910Sjsing #include <openssl/x509.h>
148dab3f910Sjsing #include <openssl/x509v3.h>
149dab3f910Sjsing 
150dab3f910Sjsing typedef struct {
151dab3f910Sjsing 	const char *name;
152dab3f910Sjsing 	unsigned long flag;
153dab3f910Sjsing 	unsigned long mask;
154dab3f910Sjsing } NAME_EX_TBL;
155dab3f910Sjsing 
1565827cb97Sbcook UI_METHOD *ui_method = NULL;
157dab3f910Sjsing 
158dab3f910Sjsing static int set_table_opts(unsigned long *flags, const char *arg,
159dab3f910Sjsing     const NAME_EX_TBL *in_tbl);
160dab3f910Sjsing static int set_multi_opts(unsigned long *flags, const char *arg,
161dab3f910Sjsing     const NAME_EX_TBL *in_tbl);
162dab3f910Sjsing 
163dab3f910Sjsing int
164dab3f910Sjsing str2fmt(char *s)
165dab3f910Sjsing {
166dab3f910Sjsing 	if (s == NULL)
167dab3f910Sjsing 		return FORMAT_UNDEF;
168dab3f910Sjsing 	if ((*s == 'D') || (*s == 'd'))
169dab3f910Sjsing 		return (FORMAT_ASN1);
170dab3f910Sjsing 	else if ((*s == 'T') || (*s == 't'))
171dab3f910Sjsing 		return (FORMAT_TEXT);
172dab3f910Sjsing 	else if ((*s == 'S') || (*s == 's'))
173dab3f910Sjsing 		return (FORMAT_SMIME);
174dab3f910Sjsing 	else if ((*s == 'M') || (*s == 'm'))
175dab3f910Sjsing 		return (FORMAT_MSBLOB);
176dab3f910Sjsing 	else if ((*s == '1') ||
177dab3f910Sjsing 	    (strcmp(s, "PKCS12") == 0) || (strcmp(s, "pkcs12") == 0) ||
178dab3f910Sjsing 	    (strcmp(s, "P12") == 0) || (strcmp(s, "p12") == 0))
179dab3f910Sjsing 		return (FORMAT_PKCS12);
180dab3f910Sjsing 	else if ((*s == 'P') || (*s == 'p')) {
181dab3f910Sjsing 		if (s[1] == 'V' || s[1] == 'v')
182dab3f910Sjsing 			return FORMAT_PVK;
183dab3f910Sjsing 		else
184dab3f910Sjsing 			return (FORMAT_PEM);
185dab3f910Sjsing 	} else
186dab3f910Sjsing 		return (FORMAT_UNDEF);
187dab3f910Sjsing }
188dab3f910Sjsing 
189dab3f910Sjsing void
190dab3f910Sjsing program_name(char *in, char *out, int size)
191dab3f910Sjsing {
192dab3f910Sjsing 	char *p;
193dab3f910Sjsing 
194dab3f910Sjsing 	p = strrchr(in, '/');
195dab3f910Sjsing 	if (p != NULL)
196dab3f910Sjsing 		p++;
197dab3f910Sjsing 	else
198dab3f910Sjsing 		p = in;
199dab3f910Sjsing 	strlcpy(out, p, size);
200dab3f910Sjsing }
201dab3f910Sjsing 
202dab3f910Sjsing int
203dab3f910Sjsing dump_cert_text(BIO *out, X509 *x)
204dab3f910Sjsing {
205dab3f910Sjsing 	char *p;
206dab3f910Sjsing 
207dab3f910Sjsing 	p = X509_NAME_oneline(X509_get_subject_name(x), NULL, 0);
208dab3f910Sjsing 	BIO_puts(out, "subject=");
209dab3f910Sjsing 	BIO_puts(out, p);
210dab3f910Sjsing 	free(p);
211dab3f910Sjsing 
212dab3f910Sjsing 	p = X509_NAME_oneline(X509_get_issuer_name(x), NULL, 0);
213dab3f910Sjsing 	BIO_puts(out, "\nissuer=");
214dab3f910Sjsing 	BIO_puts(out, p);
215dab3f910Sjsing 	BIO_puts(out, "\n");
216dab3f910Sjsing 	free(p);
217dab3f910Sjsing 
218dab3f910Sjsing 	return 0;
219dab3f910Sjsing }
220dab3f910Sjsing 
2215827cb97Sbcook int
222dab3f910Sjsing ui_open(UI *ui)
223dab3f910Sjsing {
224dab3f910Sjsing 	return UI_method_get_opener(UI_OpenSSL()) (ui);
225dab3f910Sjsing }
226dab3f910Sjsing 
2275827cb97Sbcook int
228dab3f910Sjsing ui_read(UI *ui, UI_STRING *uis)
229dab3f910Sjsing {
2305827cb97Sbcook 	const char *password;
2315827cb97Sbcook 	int string_type;
2325827cb97Sbcook 
233dab3f910Sjsing 	if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD &&
234dab3f910Sjsing 	    UI_get0_user_data(ui)) {
2355827cb97Sbcook 		string_type = UI_get_string_type(uis);
2365827cb97Sbcook 		if (string_type == UIT_PROMPT || string_type == UIT_VERIFY) {
2375827cb97Sbcook 			password =
238dab3f910Sjsing 			    ((PW_CB_DATA *)UI_get0_user_data(ui))->password;
239dab3f910Sjsing 			if (password && password[0] != '\0') {
240dab3f910Sjsing 				UI_set_result(ui, uis, password);
241dab3f910Sjsing 				return 1;
242dab3f910Sjsing 			}
243dab3f910Sjsing 		}
244dab3f910Sjsing 	}
245dab3f910Sjsing 	return UI_method_get_reader(UI_OpenSSL()) (ui, uis);
246dab3f910Sjsing }
247dab3f910Sjsing 
2485827cb97Sbcook int
249dab3f910Sjsing ui_write(UI *ui, UI_STRING *uis)
250dab3f910Sjsing {
2515827cb97Sbcook 	const char *password;
2525827cb97Sbcook 	int string_type;
2535827cb97Sbcook 
254dab3f910Sjsing 	if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD &&
255dab3f910Sjsing 	    UI_get0_user_data(ui)) {
2565827cb97Sbcook 		string_type = UI_get_string_type(uis);
2575827cb97Sbcook 		if (string_type == UIT_PROMPT || string_type == UIT_VERIFY) {
2585827cb97Sbcook 			password =
259dab3f910Sjsing 			    ((PW_CB_DATA *)UI_get0_user_data(ui))->password;
260dab3f910Sjsing 			if (password && password[0] != '\0')
261dab3f910Sjsing 				return 1;
262dab3f910Sjsing 		}
263dab3f910Sjsing 	}
264dab3f910Sjsing 	return UI_method_get_writer(UI_OpenSSL()) (ui, uis);
265dab3f910Sjsing }
266dab3f910Sjsing 
2675827cb97Sbcook int
268dab3f910Sjsing ui_close(UI *ui)
269dab3f910Sjsing {
270dab3f910Sjsing 	return UI_method_get_closer(UI_OpenSSL()) (ui);
271dab3f910Sjsing }
272dab3f910Sjsing 
273dab3f910Sjsing int
274dab3f910Sjsing password_callback(char *buf, int bufsiz, int verify, void *arg)
275dab3f910Sjsing {
276dab3f910Sjsing 	PW_CB_DATA *cb_tmp = arg;
277dab3f910Sjsing 	UI *ui = NULL;
278dab3f910Sjsing 	int res = 0;
279dab3f910Sjsing 	const char *prompt_info = NULL;
280dab3f910Sjsing 	const char *password = NULL;
281dab3f910Sjsing 	PW_CB_DATA *cb_data = (PW_CB_DATA *) cb_tmp;
282dab3f910Sjsing 
283dab3f910Sjsing 	if (cb_data) {
284dab3f910Sjsing 		if (cb_data->password)
285dab3f910Sjsing 			password = cb_data->password;
286dab3f910Sjsing 		if (cb_data->prompt_info)
287dab3f910Sjsing 			prompt_info = cb_data->prompt_info;
288dab3f910Sjsing 	}
289dab3f910Sjsing 	if (password) {
290dab3f910Sjsing 		res = strlen(password);
291dab3f910Sjsing 		if (res > bufsiz)
292dab3f910Sjsing 			res = bufsiz;
293dab3f910Sjsing 		memcpy(buf, password, res);
294dab3f910Sjsing 		return res;
295dab3f910Sjsing 	}
296dab3f910Sjsing 	ui = UI_new_method(ui_method);
297dab3f910Sjsing 	if (ui) {
298dab3f910Sjsing 		int ok = 0;
299dab3f910Sjsing 		char *buff = NULL;
300dab3f910Sjsing 		int ui_flags = 0;
301dab3f910Sjsing 		char *prompt = NULL;
302dab3f910Sjsing 
303dab3f910Sjsing 		prompt = UI_construct_prompt(ui, "pass phrase", prompt_info);
304dab3f910Sjsing 
305dab3f910Sjsing 		ui_flags |= UI_INPUT_FLAG_DEFAULT_PWD;
306dab3f910Sjsing 		UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0);
307dab3f910Sjsing 
308dab3f910Sjsing 		if (ok >= 0)
309dab3f910Sjsing 			ok = UI_add_input_string(ui, prompt, ui_flags, buf,
310dab3f910Sjsing 			    PW_MIN_LENGTH, bufsiz - 1);
311dab3f910Sjsing 		if (ok >= 0 && verify) {
312dab3f910Sjsing 			buff = malloc(bufsiz);
313dab3f910Sjsing 			ok = UI_add_verify_string(ui, prompt, ui_flags, buff,
314dab3f910Sjsing 			    PW_MIN_LENGTH, bufsiz - 1, buf);
315dab3f910Sjsing 		}
316dab3f910Sjsing 		if (ok >= 0)
317dab3f910Sjsing 			do {
318dab3f910Sjsing 				ok = UI_process(ui);
319dab3f910Sjsing 			} while (ok < 0 &&
320dab3f910Sjsing 			    UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0));
321dab3f910Sjsing 
322cf4db30dSderaadt 		freezero(buff, (unsigned int) bufsiz);
323dab3f910Sjsing 		if (ok >= 0)
324dab3f910Sjsing 			res = strlen(buf);
325dab3f910Sjsing 		if (ok == -1) {
326dab3f910Sjsing 			BIO_printf(bio_err, "User interface error\n");
327dab3f910Sjsing 			ERR_print_errors(bio_err);
3289fd20351Sjsing 			explicit_bzero(buf, (unsigned int) bufsiz);
329dab3f910Sjsing 			res = 0;
330dab3f910Sjsing 		}
331dab3f910Sjsing 		if (ok == -2) {
332dab3f910Sjsing 			BIO_printf(bio_err, "aborted!\n");
3339fd20351Sjsing 			explicit_bzero(buf, (unsigned int) bufsiz);
334dab3f910Sjsing 			res = 0;
335dab3f910Sjsing 		}
336dab3f910Sjsing 		UI_free(ui);
337dab3f910Sjsing 		free(prompt);
338dab3f910Sjsing 	}
339dab3f910Sjsing 	return res;
340dab3f910Sjsing }
341dab3f910Sjsing 
342dab3f910Sjsing static char *app_get_pass(BIO *err, char *arg, int keepbio);
343dab3f910Sjsing 
344dab3f910Sjsing int
345dab3f910Sjsing app_passwd(BIO *err, char *arg1, char *arg2, char **pass1, char **pass2)
346dab3f910Sjsing {
347dab3f910Sjsing 	int same;
348dab3f910Sjsing 
349dab3f910Sjsing 	if (!arg2 || !arg1 || strcmp(arg1, arg2))
350dab3f910Sjsing 		same = 0;
351dab3f910Sjsing 	else
352dab3f910Sjsing 		same = 1;
353dab3f910Sjsing 	if (arg1) {
354dab3f910Sjsing 		*pass1 = app_get_pass(err, arg1, same);
355dab3f910Sjsing 		if (!*pass1)
356dab3f910Sjsing 			return 0;
357dab3f910Sjsing 	} else if (pass1)
358dab3f910Sjsing 		*pass1 = NULL;
359dab3f910Sjsing 	if (arg2) {
360dab3f910Sjsing 		*pass2 = app_get_pass(err, arg2, same ? 2 : 0);
361dab3f910Sjsing 		if (!*pass2)
362dab3f910Sjsing 			return 0;
363dab3f910Sjsing 	} else if (pass2)
364dab3f910Sjsing 		*pass2 = NULL;
365dab3f910Sjsing 	return 1;
366dab3f910Sjsing }
367dab3f910Sjsing 
368dab3f910Sjsing static char *
369dab3f910Sjsing app_get_pass(BIO *err, char *arg, int keepbio)
370dab3f910Sjsing {
371dab3f910Sjsing 	char *tmp, tpass[APP_PASS_LEN];
372dab3f910Sjsing 	static BIO *pwdbio = NULL;
373dab3f910Sjsing 	const char *errstr = NULL;
374dab3f910Sjsing 	int i;
375dab3f910Sjsing 
376dab3f910Sjsing 	if (!strncmp(arg, "pass:", 5))
377dab3f910Sjsing 		return strdup(arg + 5);
378dab3f910Sjsing 	if (!strncmp(arg, "env:", 4)) {
379dab3f910Sjsing 		tmp = getenv(arg + 4);
380dab3f910Sjsing 		if (!tmp) {
381dab3f910Sjsing 			BIO_printf(err, "Can't read environment variable %s\n",
382dab3f910Sjsing 			    arg + 4);
383dab3f910Sjsing 			return NULL;
384dab3f910Sjsing 		}
385dab3f910Sjsing 		return strdup(tmp);
386dab3f910Sjsing 	}
387dab3f910Sjsing 	if (!keepbio || !pwdbio) {
388dab3f910Sjsing 		if (!strncmp(arg, "file:", 5)) {
389dab3f910Sjsing 			pwdbio = BIO_new_file(arg + 5, "r");
390dab3f910Sjsing 			if (!pwdbio) {
391dab3f910Sjsing 				BIO_printf(err, "Can't open file %s\n",
392dab3f910Sjsing 				    arg + 5);
393dab3f910Sjsing 				return NULL;
394dab3f910Sjsing 			}
395dab3f910Sjsing 		} else if (!strncmp(arg, "fd:", 3)) {
396dab3f910Sjsing 			BIO *btmp;
397dab3f910Sjsing 			i = strtonum(arg + 3, 0, INT_MAX, &errstr);
398dab3f910Sjsing 			if (errstr) {
399dab3f910Sjsing 				BIO_printf(err,
400dab3f910Sjsing 				    "Invalid file descriptor %s: %s\n",
401dab3f910Sjsing 				    arg, errstr);
402dab3f910Sjsing 				return NULL;
403dab3f910Sjsing 			}
404dab3f910Sjsing 			pwdbio = BIO_new_fd(i, BIO_NOCLOSE);
405dab3f910Sjsing 			if (!pwdbio) {
406dab3f910Sjsing 				BIO_printf(err,
407dab3f910Sjsing 				    "Can't access file descriptor %s\n",
408dab3f910Sjsing 				    arg + 3);
409dab3f910Sjsing 				return NULL;
410dab3f910Sjsing 			}
411dab3f910Sjsing 			/*
412dab3f910Sjsing 			 * Can't do BIO_gets on an fd BIO so add a buffering
413dab3f910Sjsing 			 * BIO
414dab3f910Sjsing 			 */
415dab3f910Sjsing 			btmp = BIO_new(BIO_f_buffer());
416dab3f910Sjsing 			pwdbio = BIO_push(btmp, pwdbio);
417dab3f910Sjsing 		} else if (!strcmp(arg, "stdin")) {
418dab3f910Sjsing 			pwdbio = BIO_new_fp(stdin, BIO_NOCLOSE);
419dab3f910Sjsing 			if (!pwdbio) {
420dab3f910Sjsing 				BIO_printf(err, "Can't open BIO for stdin\n");
421dab3f910Sjsing 				return NULL;
422dab3f910Sjsing 			}
423dab3f910Sjsing 		} else {
424dab3f910Sjsing 			BIO_printf(err, "Invalid password argument \"%s\"\n",
425dab3f910Sjsing 			    arg);
426dab3f910Sjsing 			return NULL;
427dab3f910Sjsing 		}
428dab3f910Sjsing 	}
429dab3f910Sjsing 	i = BIO_gets(pwdbio, tpass, APP_PASS_LEN);
430dab3f910Sjsing 	if (keepbio != 1) {
431dab3f910Sjsing 		BIO_free_all(pwdbio);
432dab3f910Sjsing 		pwdbio = NULL;
433dab3f910Sjsing 	}
434dab3f910Sjsing 	if (i <= 0) {
435dab3f910Sjsing 		BIO_printf(err, "Error reading password from BIO\n");
436dab3f910Sjsing 		return NULL;
437dab3f910Sjsing 	}
438dab3f910Sjsing 	tmp = strchr(tpass, '\n');
439dab3f910Sjsing 	if (tmp)
440dab3f910Sjsing 		*tmp = 0;
441dab3f910Sjsing 	return strdup(tpass);
442dab3f910Sjsing }
443dab3f910Sjsing 
444dab3f910Sjsing int
445dab3f910Sjsing add_oid_section(BIO *err, CONF *conf)
446dab3f910Sjsing {
447dab3f910Sjsing 	char *p;
448dab3f910Sjsing 	STACK_OF(CONF_VALUE) *sktmp;
449dab3f910Sjsing 	CONF_VALUE *cnf;
450dab3f910Sjsing 	int i;
451dab3f910Sjsing 
452dab3f910Sjsing 	if (!(p = NCONF_get_string(conf, NULL, "oid_section"))) {
453dab3f910Sjsing 		ERR_clear_error();
454dab3f910Sjsing 		return 1;
455dab3f910Sjsing 	}
456dab3f910Sjsing 	if (!(sktmp = NCONF_get_section(conf, p))) {
457dab3f910Sjsing 		BIO_printf(err, "problem loading oid section %s\n", p);
458dab3f910Sjsing 		return 0;
459dab3f910Sjsing 	}
460dab3f910Sjsing 	for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
461dab3f910Sjsing 		cnf = sk_CONF_VALUE_value(sktmp, i);
462dab3f910Sjsing 		if (OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) {
463dab3f910Sjsing 			BIO_printf(err, "problem creating object %s=%s\n",
464dab3f910Sjsing 			    cnf->name, cnf->value);
465dab3f910Sjsing 			return 0;
466dab3f910Sjsing 		}
467dab3f910Sjsing 	}
468dab3f910Sjsing 	return 1;
469dab3f910Sjsing }
470dab3f910Sjsing 
471dab3f910Sjsing static int
472dab3f910Sjsing load_pkcs12(BIO *err, BIO *in, const char *desc, pem_password_cb *pem_cb,
473dab3f910Sjsing     void *cb_data, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca)
474dab3f910Sjsing {
475dab3f910Sjsing 	const char *pass;
476dab3f910Sjsing 	char tpass[PEM_BUFSIZE];
477dab3f910Sjsing 	int len, ret = 0;
478dab3f910Sjsing 	PKCS12 *p12;
479dab3f910Sjsing 
480dab3f910Sjsing 	p12 = d2i_PKCS12_bio(in, NULL);
481dab3f910Sjsing 	if (p12 == NULL) {
482dab3f910Sjsing 		BIO_printf(err, "Error loading PKCS12 file for %s\n", desc);
483dab3f910Sjsing 		goto die;
484dab3f910Sjsing 	}
485dab3f910Sjsing 	/* See if an empty password will do */
486dab3f910Sjsing 	if (PKCS12_verify_mac(p12, "", 0) || PKCS12_verify_mac(p12, NULL, 0))
487dab3f910Sjsing 		pass = "";
488dab3f910Sjsing 	else {
489dab3f910Sjsing 		if (!pem_cb)
490dab3f910Sjsing 			pem_cb = password_callback;
491dab3f910Sjsing 		len = pem_cb(tpass, PEM_BUFSIZE, 0, cb_data);
492dab3f910Sjsing 		if (len < 0) {
493dab3f910Sjsing 			BIO_printf(err, "Passpharse callback error for %s\n",
494dab3f910Sjsing 			    desc);
495dab3f910Sjsing 			goto die;
496dab3f910Sjsing 		}
497dab3f910Sjsing 		if (len < PEM_BUFSIZE)
498dab3f910Sjsing 			tpass[len] = 0;
499dab3f910Sjsing 		if (!PKCS12_verify_mac(p12, tpass, len)) {
500dab3f910Sjsing 			BIO_printf(err,
501dab3f910Sjsing 			    "Mac verify error (wrong password?) in PKCS12 file for %s\n", desc);
502dab3f910Sjsing 			goto die;
503dab3f910Sjsing 		}
504dab3f910Sjsing 		pass = tpass;
505dab3f910Sjsing 	}
506dab3f910Sjsing 	ret = PKCS12_parse(p12, pass, pkey, cert, ca);
507dab3f910Sjsing 
508dab3f910Sjsing  die:
509dab3f910Sjsing 	PKCS12_free(p12);
510dab3f910Sjsing 	return ret;
511dab3f910Sjsing }
512dab3f910Sjsing 
513dab3f910Sjsing X509 *
5145284dfeaSbcook load_cert(BIO *err, const char *file, int format, const char *pass,
515dab3f910Sjsing     const char *cert_descrip)
516dab3f910Sjsing {
517dab3f910Sjsing 	X509 *x = NULL;
518dab3f910Sjsing 	BIO *cert;
519dab3f910Sjsing 
520dab3f910Sjsing 	if ((cert = BIO_new(BIO_s_file())) == NULL) {
521dab3f910Sjsing 		ERR_print_errors(err);
522dab3f910Sjsing 		goto end;
523dab3f910Sjsing 	}
524dab3f910Sjsing 	if (file == NULL) {
525dab3f910Sjsing 		setvbuf(stdin, NULL, _IONBF, 0);
526dab3f910Sjsing 		BIO_set_fp(cert, stdin, BIO_NOCLOSE);
527dab3f910Sjsing 	} else {
528dab3f910Sjsing 		if (BIO_read_filename(cert, file) <= 0) {
529dab3f910Sjsing 			BIO_printf(err, "Error opening %s %s\n",
530dab3f910Sjsing 			    cert_descrip, file);
531dab3f910Sjsing 			ERR_print_errors(err);
532dab3f910Sjsing 			goto end;
533dab3f910Sjsing 		}
534dab3f910Sjsing 	}
535dab3f910Sjsing 
536dab3f910Sjsing 	if (format == FORMAT_ASN1)
537dab3f910Sjsing 		x = d2i_X509_bio(cert, NULL);
538b1044e52Stb 	else if (format == FORMAT_PEM)
539dab3f910Sjsing 		x = PEM_read_bio_X509_AUX(cert, NULL, password_callback, NULL);
540dab3f910Sjsing 	else if (format == FORMAT_PKCS12) {
541dab3f910Sjsing 		if (!load_pkcs12(err, cert, cert_descrip, NULL, NULL,
542dab3f910Sjsing 		    NULL, &x, NULL))
543dab3f910Sjsing 			goto end;
544dab3f910Sjsing 	} else {
545dab3f910Sjsing 		BIO_printf(err, "bad input format specified for %s\n",
546dab3f910Sjsing 		    cert_descrip);
547dab3f910Sjsing 		goto end;
548dab3f910Sjsing 	}
549dab3f910Sjsing 
550dab3f910Sjsing  end:
551dab3f910Sjsing 	if (x == NULL) {
552dab3f910Sjsing 		BIO_printf(err, "unable to load certificate\n");
553dab3f910Sjsing 		ERR_print_errors(err);
554dab3f910Sjsing 	}
555dab3f910Sjsing 	BIO_free(cert);
556dab3f910Sjsing 	return (x);
557dab3f910Sjsing }
558dab3f910Sjsing 
559dab3f910Sjsing EVP_PKEY *
560dab3f910Sjsing load_key(BIO *err, const char *file, int format, int maybe_stdin,
5615284dfeaSbcook     const char *pass, const char *key_descrip)
562dab3f910Sjsing {
563dab3f910Sjsing 	BIO *key = NULL;
564dab3f910Sjsing 	EVP_PKEY *pkey = NULL;
565dab3f910Sjsing 	PW_CB_DATA cb_data;
566dab3f910Sjsing 
567dab3f910Sjsing 	cb_data.password = pass;
568dab3f910Sjsing 	cb_data.prompt_info = file;
569dab3f910Sjsing 
5705284dfeaSbcook 	if (file == NULL && (!maybe_stdin)) {
571dab3f910Sjsing 		BIO_printf(err, "no keyfile specified\n");
572dab3f910Sjsing 		goto end;
573dab3f910Sjsing 	}
574dab3f910Sjsing 	key = BIO_new(BIO_s_file());
575dab3f910Sjsing 	if (key == NULL) {
576dab3f910Sjsing 		ERR_print_errors(err);
577dab3f910Sjsing 		goto end;
578dab3f910Sjsing 	}
579dab3f910Sjsing 	if (file == NULL && maybe_stdin) {
580dab3f910Sjsing 		setvbuf(stdin, NULL, _IONBF, 0);
581dab3f910Sjsing 		BIO_set_fp(key, stdin, BIO_NOCLOSE);
582dab3f910Sjsing 	} else if (BIO_read_filename(key, file) <= 0) {
583dab3f910Sjsing 		BIO_printf(err, "Error opening %s %s\n",
584dab3f910Sjsing 		    key_descrip, file);
585dab3f910Sjsing 		ERR_print_errors(err);
586dab3f910Sjsing 		goto end;
587dab3f910Sjsing 	}
588dab3f910Sjsing 	if (format == FORMAT_ASN1) {
589dab3f910Sjsing 		pkey = d2i_PrivateKey_bio(key, NULL);
590dab3f910Sjsing 	} else if (format == FORMAT_PEM) {
591dab3f910Sjsing 		pkey = PEM_read_bio_PrivateKey(key, NULL, password_callback, &cb_data);
592dab3f910Sjsing 	}
593dab3f910Sjsing 	else if (format == FORMAT_PKCS12) {
594dab3f910Sjsing 		if (!load_pkcs12(err, key, key_descrip, password_callback, &cb_data,
595dab3f910Sjsing 		    &pkey, NULL, NULL))
596dab3f910Sjsing 			goto end;
597dab3f910Sjsing 	}
598dab3f910Sjsing #if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) && !defined (OPENSSL_NO_RC4)
599dab3f910Sjsing 	else if (format == FORMAT_MSBLOB)
600dab3f910Sjsing 		pkey = b2i_PrivateKey_bio(key);
601dab3f910Sjsing 	else if (format == FORMAT_PVK)
602dab3f910Sjsing 		pkey = b2i_PVK_bio(key, password_callback,
603dab3f910Sjsing 		    &cb_data);
604dab3f910Sjsing #endif
605dab3f910Sjsing 	else {
606dab3f910Sjsing 		BIO_printf(err, "bad input format specified for key file\n");
607dab3f910Sjsing 		goto end;
608dab3f910Sjsing 	}
609dab3f910Sjsing  end:
610dab3f910Sjsing 	BIO_free(key);
611dab3f910Sjsing 	if (pkey == NULL) {
612dab3f910Sjsing 		BIO_printf(err, "unable to load %s\n", key_descrip);
613dab3f910Sjsing 		ERR_print_errors(err);
614dab3f910Sjsing 	}
615dab3f910Sjsing 	return (pkey);
616dab3f910Sjsing }
617dab3f910Sjsing 
618dab3f910Sjsing EVP_PKEY *
619dab3f910Sjsing load_pubkey(BIO *err, const char *file, int format, int maybe_stdin,
6205284dfeaSbcook     const char *pass, const char *key_descrip)
621dab3f910Sjsing {
622dab3f910Sjsing 	BIO *key = NULL;
623dab3f910Sjsing 	EVP_PKEY *pkey = NULL;
624dab3f910Sjsing 	PW_CB_DATA cb_data;
625dab3f910Sjsing 
626dab3f910Sjsing 	cb_data.password = pass;
627dab3f910Sjsing 	cb_data.prompt_info = file;
628dab3f910Sjsing 
6295284dfeaSbcook 	if (file == NULL && !maybe_stdin) {
630dab3f910Sjsing 		BIO_printf(err, "no keyfile specified\n");
631dab3f910Sjsing 		goto end;
632dab3f910Sjsing 	}
633dab3f910Sjsing 	key = BIO_new(BIO_s_file());
634dab3f910Sjsing 	if (key == NULL) {
635dab3f910Sjsing 		ERR_print_errors(err);
636dab3f910Sjsing 		goto end;
637dab3f910Sjsing 	}
638dab3f910Sjsing 	if (file == NULL && maybe_stdin) {
639dab3f910Sjsing 		setvbuf(stdin, NULL, _IONBF, 0);
640dab3f910Sjsing 		BIO_set_fp(key, stdin, BIO_NOCLOSE);
641dab3f910Sjsing 	} else if (BIO_read_filename(key, file) <= 0) {
642dab3f910Sjsing 		BIO_printf(err, "Error opening %s %s\n", key_descrip, file);
643dab3f910Sjsing 		ERR_print_errors(err);
644dab3f910Sjsing 		goto end;
645dab3f910Sjsing 	}
646dab3f910Sjsing 	if (format == FORMAT_ASN1) {
647dab3f910Sjsing 		pkey = d2i_PUBKEY_bio(key, NULL);
648dab3f910Sjsing 	}
649dab3f910Sjsing 	else if (format == FORMAT_ASN1RSA) {
650dab3f910Sjsing 		RSA *rsa;
651dab3f910Sjsing 		rsa = d2i_RSAPublicKey_bio(key, NULL);
652dab3f910Sjsing 		if (rsa) {
653dab3f910Sjsing 			pkey = EVP_PKEY_new();
654dab3f910Sjsing 			if (pkey)
655dab3f910Sjsing 				EVP_PKEY_set1_RSA(pkey, rsa);
656dab3f910Sjsing 			RSA_free(rsa);
657dab3f910Sjsing 		} else
658dab3f910Sjsing 			pkey = NULL;
659dab3f910Sjsing 	} else if (format == FORMAT_PEMRSA) {
660dab3f910Sjsing 		RSA *rsa;
661dab3f910Sjsing 		rsa = PEM_read_bio_RSAPublicKey(key, NULL, password_callback, &cb_data);
662dab3f910Sjsing 		if (rsa) {
663dab3f910Sjsing 			pkey = EVP_PKEY_new();
664dab3f910Sjsing 			if (pkey)
665dab3f910Sjsing 				EVP_PKEY_set1_RSA(pkey, rsa);
666dab3f910Sjsing 			RSA_free(rsa);
667dab3f910Sjsing 		} else
668dab3f910Sjsing 			pkey = NULL;
669dab3f910Sjsing 	}
670dab3f910Sjsing 	else if (format == FORMAT_PEM) {
671dab3f910Sjsing 		pkey = PEM_read_bio_PUBKEY(key, NULL, password_callback, &cb_data);
672dab3f910Sjsing 	}
673dab3f910Sjsing #if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA)
674dab3f910Sjsing 	else if (format == FORMAT_MSBLOB)
675dab3f910Sjsing 		pkey = b2i_PublicKey_bio(key);
676dab3f910Sjsing #endif
677dab3f910Sjsing 	else {
678dab3f910Sjsing 		BIO_printf(err, "bad input format specified for key file\n");
679dab3f910Sjsing 		goto end;
680dab3f910Sjsing 	}
681dab3f910Sjsing 
682dab3f910Sjsing  end:
683dab3f910Sjsing 	BIO_free(key);
684dab3f910Sjsing 	if (pkey == NULL)
685dab3f910Sjsing 		BIO_printf(err, "unable to load %s\n", key_descrip);
686dab3f910Sjsing 	return (pkey);
687dab3f910Sjsing }
688dab3f910Sjsing 
689dab3f910Sjsing static int
690dab3f910Sjsing load_certs_crls(BIO *err, const char *file, int format, const char *pass,
6915284dfeaSbcook     const char *desc, STACK_OF(X509) **pcerts,
692dab3f910Sjsing     STACK_OF(X509_CRL) **pcrls)
693dab3f910Sjsing {
694dab3f910Sjsing 	int i;
695dab3f910Sjsing 	BIO *bio;
696dab3f910Sjsing 	STACK_OF(X509_INFO) *xis = NULL;
697dab3f910Sjsing 	X509_INFO *xi;
698dab3f910Sjsing 	PW_CB_DATA cb_data;
699dab3f910Sjsing 	int rv = 0;
700dab3f910Sjsing 
701dab3f910Sjsing 	cb_data.password = pass;
702dab3f910Sjsing 	cb_data.prompt_info = file;
703dab3f910Sjsing 
704dab3f910Sjsing 	if (format != FORMAT_PEM) {
705dab3f910Sjsing 		BIO_printf(err, "bad input format specified for %s\n", desc);
706dab3f910Sjsing 		return 0;
707dab3f910Sjsing 	}
708dab3f910Sjsing 	if (file == NULL)
709dab3f910Sjsing 		bio = BIO_new_fp(stdin, BIO_NOCLOSE);
710dab3f910Sjsing 	else
711dab3f910Sjsing 		bio = BIO_new_file(file, "r");
712dab3f910Sjsing 
713dab3f910Sjsing 	if (bio == NULL) {
714dab3f910Sjsing 		BIO_printf(err, "Error opening %s %s\n",
715dab3f910Sjsing 		    desc, file ? file : "stdin");
716dab3f910Sjsing 		ERR_print_errors(err);
717dab3f910Sjsing 		return 0;
718dab3f910Sjsing 	}
719dab3f910Sjsing 	xis = PEM_X509_INFO_read_bio(bio, NULL, password_callback, &cb_data);
720dab3f910Sjsing 
721dab3f910Sjsing 	BIO_free(bio);
722dab3f910Sjsing 
723dab3f910Sjsing 	if (pcerts) {
724dab3f910Sjsing 		*pcerts = sk_X509_new_null();
725dab3f910Sjsing 		if (!*pcerts)
726dab3f910Sjsing 			goto end;
727dab3f910Sjsing 	}
728dab3f910Sjsing 	if (pcrls) {
729dab3f910Sjsing 		*pcrls = sk_X509_CRL_new_null();
730dab3f910Sjsing 		if (!*pcrls)
731dab3f910Sjsing 			goto end;
732dab3f910Sjsing 	}
733dab3f910Sjsing 	for (i = 0; i < sk_X509_INFO_num(xis); i++) {
734dab3f910Sjsing 		xi = sk_X509_INFO_value(xis, i);
735dab3f910Sjsing 		if (xi->x509 && pcerts) {
736dab3f910Sjsing 			if (!sk_X509_push(*pcerts, xi->x509))
737dab3f910Sjsing 				goto end;
738dab3f910Sjsing 			xi->x509 = NULL;
739dab3f910Sjsing 		}
740dab3f910Sjsing 		if (xi->crl && pcrls) {
741dab3f910Sjsing 			if (!sk_X509_CRL_push(*pcrls, xi->crl))
742dab3f910Sjsing 				goto end;
743dab3f910Sjsing 			xi->crl = NULL;
744dab3f910Sjsing 		}
745dab3f910Sjsing 	}
746dab3f910Sjsing 
747dab3f910Sjsing 	if (pcerts && sk_X509_num(*pcerts) > 0)
748dab3f910Sjsing 		rv = 1;
749dab3f910Sjsing 
750dab3f910Sjsing 	if (pcrls && sk_X509_CRL_num(*pcrls) > 0)
751dab3f910Sjsing 		rv = 1;
752dab3f910Sjsing 
753dab3f910Sjsing  end:
754dab3f910Sjsing 	sk_X509_INFO_pop_free(xis, X509_INFO_free);
755dab3f910Sjsing 
756dab3f910Sjsing 	if (rv == 0) {
757dab3f910Sjsing 		if (pcerts) {
758dab3f910Sjsing 			sk_X509_pop_free(*pcerts, X509_free);
759dab3f910Sjsing 			*pcerts = NULL;
760dab3f910Sjsing 		}
761dab3f910Sjsing 		if (pcrls) {
762dab3f910Sjsing 			sk_X509_CRL_pop_free(*pcrls, X509_CRL_free);
763dab3f910Sjsing 			*pcrls = NULL;
764dab3f910Sjsing 		}
765dab3f910Sjsing 		BIO_printf(err, "unable to load %s\n",
766dab3f910Sjsing 		    pcerts ? "certificates" : "CRLs");
767dab3f910Sjsing 		ERR_print_errors(err);
768dab3f910Sjsing 	}
769dab3f910Sjsing 	return rv;
770dab3f910Sjsing }
771dab3f910Sjsing 
772dab3f910Sjsing STACK_OF(X509) *
773dab3f910Sjsing load_certs(BIO *err, const char *file, int format, const char *pass,
7745284dfeaSbcook     const char *desc)
775dab3f910Sjsing {
776dab3f910Sjsing 	STACK_OF(X509) *certs;
777dab3f910Sjsing 
7785284dfeaSbcook 	if (!load_certs_crls(err, file, format, pass, desc, &certs, NULL))
779dab3f910Sjsing 		return NULL;
780dab3f910Sjsing 	return certs;
781dab3f910Sjsing }
782dab3f910Sjsing 
783dab3f910Sjsing STACK_OF(X509_CRL) *
7845284dfeaSbcook load_crls(BIO *err, const char *file, int format, const char *pass,
785dab3f910Sjsing     const char *desc)
786dab3f910Sjsing {
787dab3f910Sjsing 	STACK_OF(X509_CRL) *crls;
788dab3f910Sjsing 
7895284dfeaSbcook 	if (!load_certs_crls(err, file, format, pass, desc, NULL, &crls))
790dab3f910Sjsing 		return NULL;
791dab3f910Sjsing 	return crls;
792dab3f910Sjsing }
793dab3f910Sjsing 
794dab3f910Sjsing #define X509V3_EXT_UNKNOWN_MASK		(0xfL << 16)
795dab3f910Sjsing /* Return error for unknown extensions */
796dab3f910Sjsing #define X509V3_EXT_DEFAULT		0
797dab3f910Sjsing /* Print error for unknown extensions */
798dab3f910Sjsing #define X509V3_EXT_ERROR_UNKNOWN	(1L << 16)
799dab3f910Sjsing /* ASN1 parse unknown extensions */
800dab3f910Sjsing #define X509V3_EXT_PARSE_UNKNOWN	(2L << 16)
801dab3f910Sjsing /* BIO_dump unknown extensions */
802dab3f910Sjsing #define X509V3_EXT_DUMP_UNKNOWN		(3L << 16)
803dab3f910Sjsing 
804dab3f910Sjsing #define X509_FLAG_CA (X509_FLAG_NO_ISSUER | X509_FLAG_NO_PUBKEY | \
805dab3f910Sjsing 			 X509_FLAG_NO_HEADER | X509_FLAG_NO_VERSION)
806dab3f910Sjsing 
807dab3f910Sjsing int
808dab3f910Sjsing set_cert_ex(unsigned long *flags, const char *arg)
809dab3f910Sjsing {
810dab3f910Sjsing 	static const NAME_EX_TBL cert_tbl[] = {
811dab3f910Sjsing 		{"compatible", X509_FLAG_COMPAT, 0xffffffffl},
812dab3f910Sjsing 		{"ca_default", X509_FLAG_CA, 0xffffffffl},
813dab3f910Sjsing 		{"no_header", X509_FLAG_NO_HEADER, 0},
814dab3f910Sjsing 		{"no_version", X509_FLAG_NO_VERSION, 0},
815dab3f910Sjsing 		{"no_serial", X509_FLAG_NO_SERIAL, 0},
816dab3f910Sjsing 		{"no_signame", X509_FLAG_NO_SIGNAME, 0},
817dab3f910Sjsing 		{"no_validity", X509_FLAG_NO_VALIDITY, 0},
818dab3f910Sjsing 		{"no_subject", X509_FLAG_NO_SUBJECT, 0},
819dab3f910Sjsing 		{"no_issuer", X509_FLAG_NO_ISSUER, 0},
820dab3f910Sjsing 		{"no_pubkey", X509_FLAG_NO_PUBKEY, 0},
821dab3f910Sjsing 		{"no_extensions", X509_FLAG_NO_EXTENSIONS, 0},
822dab3f910Sjsing 		{"no_sigdump", X509_FLAG_NO_SIGDUMP, 0},
823dab3f910Sjsing 		{"no_aux", X509_FLAG_NO_AUX, 0},
824dab3f910Sjsing 		{"no_attributes", X509_FLAG_NO_ATTRIBUTES, 0},
825dab3f910Sjsing 		{"ext_default", X509V3_EXT_DEFAULT, X509V3_EXT_UNKNOWN_MASK},
826dab3f910Sjsing 		{"ext_error", X509V3_EXT_ERROR_UNKNOWN, X509V3_EXT_UNKNOWN_MASK},
827dab3f910Sjsing 		{"ext_parse", X509V3_EXT_PARSE_UNKNOWN, X509V3_EXT_UNKNOWN_MASK},
828dab3f910Sjsing 		{"ext_dump", X509V3_EXT_DUMP_UNKNOWN, X509V3_EXT_UNKNOWN_MASK},
829dab3f910Sjsing 		{NULL, 0, 0}
830dab3f910Sjsing 	};
831dab3f910Sjsing 	return set_multi_opts(flags, arg, cert_tbl);
832dab3f910Sjsing }
833dab3f910Sjsing 
834dab3f910Sjsing int
835dab3f910Sjsing set_name_ex(unsigned long *flags, const char *arg)
836dab3f910Sjsing {
837dab3f910Sjsing 	static const NAME_EX_TBL ex_tbl[] = {
838dab3f910Sjsing 		{"esc_2253", ASN1_STRFLGS_ESC_2253, 0},
839dab3f910Sjsing 		{"esc_ctrl", ASN1_STRFLGS_ESC_CTRL, 0},
840dab3f910Sjsing 		{"esc_msb", ASN1_STRFLGS_ESC_MSB, 0},
841dab3f910Sjsing 		{"use_quote", ASN1_STRFLGS_ESC_QUOTE, 0},
842dab3f910Sjsing 		{"utf8", ASN1_STRFLGS_UTF8_CONVERT, 0},
843dab3f910Sjsing 		{"ignore_type", ASN1_STRFLGS_IGNORE_TYPE, 0},
844dab3f910Sjsing 		{"show_type", ASN1_STRFLGS_SHOW_TYPE, 0},
845dab3f910Sjsing 		{"dump_all", ASN1_STRFLGS_DUMP_ALL, 0},
846dab3f910Sjsing 		{"dump_nostr", ASN1_STRFLGS_DUMP_UNKNOWN, 0},
847dab3f910Sjsing 		{"dump_der", ASN1_STRFLGS_DUMP_DER, 0},
848dab3f910Sjsing 		{"compat", XN_FLAG_COMPAT, 0xffffffffL},
849dab3f910Sjsing 		{"sep_comma_plus", XN_FLAG_SEP_COMMA_PLUS, XN_FLAG_SEP_MASK},
850dab3f910Sjsing 		{"sep_comma_plus_space", XN_FLAG_SEP_CPLUS_SPC, XN_FLAG_SEP_MASK},
851dab3f910Sjsing 		{"sep_semi_plus_space", XN_FLAG_SEP_SPLUS_SPC, XN_FLAG_SEP_MASK},
852dab3f910Sjsing 		{"sep_multiline", XN_FLAG_SEP_MULTILINE, XN_FLAG_SEP_MASK},
853dab3f910Sjsing 		{"dn_rev", XN_FLAG_DN_REV, 0},
854dab3f910Sjsing 		{"nofname", XN_FLAG_FN_NONE, XN_FLAG_FN_MASK},
855dab3f910Sjsing 		{"sname", XN_FLAG_FN_SN, XN_FLAG_FN_MASK},
856dab3f910Sjsing 		{"lname", XN_FLAG_FN_LN, XN_FLAG_FN_MASK},
857dab3f910Sjsing 		{"align", XN_FLAG_FN_ALIGN, 0},
858dab3f910Sjsing 		{"oid", XN_FLAG_FN_OID, XN_FLAG_FN_MASK},
859dab3f910Sjsing 		{"space_eq", XN_FLAG_SPC_EQ, 0},
860dab3f910Sjsing 		{"dump_unknown", XN_FLAG_DUMP_UNKNOWN_FIELDS, 0},
861dab3f910Sjsing 		{"RFC2253", XN_FLAG_RFC2253, 0xffffffffL},
862dab3f910Sjsing 		{"oneline", XN_FLAG_ONELINE, 0xffffffffL},
863dab3f910Sjsing 		{"multiline", XN_FLAG_MULTILINE, 0xffffffffL},
864dab3f910Sjsing 		{"ca_default", XN_FLAG_MULTILINE, 0xffffffffL},
865dab3f910Sjsing 		{NULL, 0, 0}
866dab3f910Sjsing 	};
86707cb660dStb 	if (!set_multi_opts(flags, arg, ex_tbl))
86807cb660dStb 		return 0;
86907cb660dStb 	if (*flags != XN_FLAG_COMPAT && (*flags & XN_FLAG_SEP_MASK) == 0)
87007cb660dStb 		*flags |= XN_FLAG_SEP_CPLUS_SPC;
87107cb660dStb 	return 1;
872dab3f910Sjsing }
873dab3f910Sjsing 
874dab3f910Sjsing int
875dab3f910Sjsing set_ext_copy(int *copy_type, const char *arg)
876dab3f910Sjsing {
877dab3f910Sjsing 	if (!strcasecmp(arg, "none"))
878dab3f910Sjsing 		*copy_type = EXT_COPY_NONE;
879dab3f910Sjsing 	else if (!strcasecmp(arg, "copy"))
880dab3f910Sjsing 		*copy_type = EXT_COPY_ADD;
881dab3f910Sjsing 	else if (!strcasecmp(arg, "copyall"))
882dab3f910Sjsing 		*copy_type = EXT_COPY_ALL;
883dab3f910Sjsing 	else
884dab3f910Sjsing 		return 0;
885dab3f910Sjsing 	return 1;
886dab3f910Sjsing }
887dab3f910Sjsing 
888dab3f910Sjsing int
889dab3f910Sjsing copy_extensions(X509 *x, X509_REQ *req, int copy_type)
890dab3f910Sjsing {
891dab3f910Sjsing 	STACK_OF(X509_EXTENSION) *exts = NULL;
892dab3f910Sjsing 	X509_EXTENSION *ext, *tmpext;
893dab3f910Sjsing 	ASN1_OBJECT *obj;
894dab3f910Sjsing 	int i, idx, ret = 0;
895dab3f910Sjsing 
896dab3f910Sjsing 	if (!x || !req || (copy_type == EXT_COPY_NONE))
897dab3f910Sjsing 		return 1;
898dab3f910Sjsing 	exts = X509_REQ_get_extensions(req);
899dab3f910Sjsing 
900dab3f910Sjsing 	for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
901dab3f910Sjsing 		ext = sk_X509_EXTENSION_value(exts, i);
902dab3f910Sjsing 		obj = X509_EXTENSION_get_object(ext);
903dab3f910Sjsing 		idx = X509_get_ext_by_OBJ(x, obj, -1);
904dab3f910Sjsing 		/* Does extension exist? */
905dab3f910Sjsing 		if (idx != -1) {
906dab3f910Sjsing 			/* If normal copy don't override existing extension */
907dab3f910Sjsing 			if (copy_type == EXT_COPY_ADD)
908dab3f910Sjsing 				continue;
909dab3f910Sjsing 			/* Delete all extensions of same type */
910dab3f910Sjsing 			do {
911dab3f910Sjsing 				tmpext = X509_get_ext(x, idx);
912dab3f910Sjsing 				X509_delete_ext(x, idx);
913dab3f910Sjsing 				X509_EXTENSION_free(tmpext);
914dab3f910Sjsing 				idx = X509_get_ext_by_OBJ(x, obj, -1);
915dab3f910Sjsing 			} while (idx != -1);
916dab3f910Sjsing 		}
917dab3f910Sjsing 		if (!X509_add_ext(x, ext, -1))
918dab3f910Sjsing 			goto end;
919dab3f910Sjsing 	}
920dab3f910Sjsing 
921dab3f910Sjsing 	ret = 1;
922dab3f910Sjsing 
923dab3f910Sjsing  end:
924dab3f910Sjsing 	sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
925dab3f910Sjsing 
926dab3f910Sjsing 	return ret;
927dab3f910Sjsing }
928dab3f910Sjsing 
929dab3f910Sjsing static int
930dab3f910Sjsing set_multi_opts(unsigned long *flags, const char *arg,
931dab3f910Sjsing     const NAME_EX_TBL *in_tbl)
932dab3f910Sjsing {
933dab3f910Sjsing 	STACK_OF(CONF_VALUE) *vals;
934dab3f910Sjsing 	CONF_VALUE *val;
935dab3f910Sjsing 	int i, ret = 1;
936dab3f910Sjsing 
937dab3f910Sjsing 	if (!arg)
938dab3f910Sjsing 		return 0;
939dab3f910Sjsing 	vals = X509V3_parse_list(arg);
940dab3f910Sjsing 	for (i = 0; i < sk_CONF_VALUE_num(vals); i++) {
941dab3f910Sjsing 		val = sk_CONF_VALUE_value(vals, i);
942dab3f910Sjsing 		if (!set_table_opts(flags, val->name, in_tbl))
943dab3f910Sjsing 			ret = 0;
944dab3f910Sjsing 	}
945dab3f910Sjsing 	sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
946dab3f910Sjsing 	return ret;
947dab3f910Sjsing }
948dab3f910Sjsing 
949dab3f910Sjsing static int
950dab3f910Sjsing set_table_opts(unsigned long *flags, const char *arg,
951dab3f910Sjsing     const NAME_EX_TBL *in_tbl)
952dab3f910Sjsing {
953dab3f910Sjsing 	char c;
954dab3f910Sjsing 	const NAME_EX_TBL *ptbl;
955dab3f910Sjsing 
956dab3f910Sjsing 	c = arg[0];
957dab3f910Sjsing 	if (c == '-') {
958dab3f910Sjsing 		c = 0;
959dab3f910Sjsing 		arg++;
960dab3f910Sjsing 	} else if (c == '+') {
961dab3f910Sjsing 		c = 1;
962dab3f910Sjsing 		arg++;
963dab3f910Sjsing 	} else
964dab3f910Sjsing 		c = 1;
965dab3f910Sjsing 
966dab3f910Sjsing 	for (ptbl = in_tbl; ptbl->name; ptbl++) {
967dab3f910Sjsing 		if (!strcasecmp(arg, ptbl->name)) {
968dab3f910Sjsing 			*flags &= ~ptbl->mask;
969dab3f910Sjsing 			if (c)
970dab3f910Sjsing 				*flags |= ptbl->flag;
971dab3f910Sjsing 			else
972dab3f910Sjsing 				*flags &= ~ptbl->flag;
973dab3f910Sjsing 			return 1;
974dab3f910Sjsing 		}
975dab3f910Sjsing 	}
976dab3f910Sjsing 	return 0;
977dab3f910Sjsing }
978dab3f910Sjsing 
979dab3f910Sjsing void
980dab3f910Sjsing print_name(BIO *out, const char *title, X509_NAME *nm, unsigned long lflags)
981dab3f910Sjsing {
982dab3f910Sjsing 	char *buf;
983dab3f910Sjsing 	char mline = 0;
984dab3f910Sjsing 	int indent = 0;
985dab3f910Sjsing 
986dab3f910Sjsing 	if (title)
987dab3f910Sjsing 		BIO_puts(out, title);
988dab3f910Sjsing 	if ((lflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) {
989dab3f910Sjsing 		mline = 1;
990dab3f910Sjsing 		indent = 4;
991dab3f910Sjsing 	}
992dab3f910Sjsing 	if (lflags == XN_FLAG_COMPAT) {
993dab3f910Sjsing 		buf = X509_NAME_oneline(nm, 0, 0);
994dab3f910Sjsing 		BIO_puts(out, buf);
995dab3f910Sjsing 		BIO_puts(out, "\n");
996dab3f910Sjsing 		free(buf);
997dab3f910Sjsing 	} else {
998dab3f910Sjsing 		if (mline)
999dab3f910Sjsing 			BIO_puts(out, "\n");
1000dab3f910Sjsing 		X509_NAME_print_ex(out, nm, indent, lflags);
1001dab3f910Sjsing 		BIO_puts(out, "\n");
1002dab3f910Sjsing 	}
1003dab3f910Sjsing }
1004dab3f910Sjsing 
1005dab3f910Sjsing X509_STORE *
1006dab3f910Sjsing setup_verify(BIO *bp, char *CAfile, char *CApath)
1007dab3f910Sjsing {
1008dab3f910Sjsing 	X509_STORE *store;
1009dab3f910Sjsing 	X509_LOOKUP *lookup;
1010dab3f910Sjsing 
1011dab3f910Sjsing 	if (!(store = X509_STORE_new()))
1012dab3f910Sjsing 		goto end;
1013dab3f910Sjsing 	lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
1014dab3f910Sjsing 	if (lookup == NULL)
1015dab3f910Sjsing 		goto end;
1016dab3f910Sjsing 	if (CAfile) {
1017dab3f910Sjsing 		if (!X509_LOOKUP_load_file(lookup, CAfile, X509_FILETYPE_PEM)) {
1018dab3f910Sjsing 			BIO_printf(bp, "Error loading file %s\n", CAfile);
1019dab3f910Sjsing 			goto end;
1020dab3f910Sjsing 		}
1021dab3f910Sjsing 	} else
1022dab3f910Sjsing 		X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT);
1023dab3f910Sjsing 
1024dab3f910Sjsing 	lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
1025dab3f910Sjsing 	if (lookup == NULL)
1026dab3f910Sjsing 		goto end;
1027dab3f910Sjsing 	if (CApath) {
1028dab3f910Sjsing 		if (!X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM)) {
1029dab3f910Sjsing 			BIO_printf(bp, "Error loading directory %s\n", CApath);
1030dab3f910Sjsing 			goto end;
1031dab3f910Sjsing 		}
1032dab3f910Sjsing 	} else
1033dab3f910Sjsing 		X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
1034dab3f910Sjsing 
1035dab3f910Sjsing 	ERR_clear_error();
1036dab3f910Sjsing 	return store;
1037dab3f910Sjsing 
1038dab3f910Sjsing  end:
1039dab3f910Sjsing 	X509_STORE_free(store);
1040dab3f910Sjsing 	return NULL;
1041dab3f910Sjsing }
1042dab3f910Sjsing 
1043dab3f910Sjsing int
1044dab3f910Sjsing load_config(BIO *err, CONF *cnf)
1045dab3f910Sjsing {
1046dab3f910Sjsing 	static int load_config_called = 0;
1047dab3f910Sjsing 
1048dab3f910Sjsing 	if (load_config_called)
1049dab3f910Sjsing 		return 1;
1050dab3f910Sjsing 	load_config_called = 1;
1051dab3f910Sjsing 	if (cnf == NULL)
1052dab3f910Sjsing 		cnf = config;
1053dab3f910Sjsing 	if (cnf == NULL)
1054dab3f910Sjsing 		return 1;
1055dab3f910Sjsing 
10561ba4ec79Stb 	OPENSSL_config(NULL);
1057dab3f910Sjsing 
1058dab3f910Sjsing 	if (CONF_modules_load(cnf, NULL, 0) <= 0) {
1059dab3f910Sjsing 		BIO_printf(err, "Error configuring OpenSSL\n");
1060dab3f910Sjsing 		ERR_print_errors(err);
1061dab3f910Sjsing 		return 0;
1062dab3f910Sjsing 	}
1063dab3f910Sjsing 	return 1;
1064dab3f910Sjsing }
1065dab3f910Sjsing 
1066dab3f910Sjsing char *
1067440d1414Stb make_config_name(void)
1068dab3f910Sjsing {
1069dab3f910Sjsing 	const char *t = X509_get_default_cert_area();
1070dab3f910Sjsing 	char *p;
1071dab3f910Sjsing 
1072dab3f910Sjsing 	if (asprintf(&p, "%s/openssl.cnf", t) == -1)
1073dab3f910Sjsing 		return NULL;
1074dab3f910Sjsing 	return p;
1075dab3f910Sjsing }
1076dab3f910Sjsing 
1077dab3f910Sjsing static unsigned long
1078dab3f910Sjsing index_serial_hash(const OPENSSL_CSTRING *a)
1079dab3f910Sjsing {
1080dab3f910Sjsing 	const char *n;
1081dab3f910Sjsing 
1082dab3f910Sjsing 	n = a[DB_serial];
1083dab3f910Sjsing 	while (*n == '0')
1084dab3f910Sjsing 		n++;
1085dab3f910Sjsing 	return (lh_strhash(n));
1086dab3f910Sjsing }
1087dab3f910Sjsing 
1088dab3f910Sjsing static int
1089dab3f910Sjsing index_serial_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b)
1090dab3f910Sjsing {
1091dab3f910Sjsing 	const char *aa, *bb;
1092dab3f910Sjsing 
1093dab3f910Sjsing 	for (aa = a[DB_serial]; *aa == '0'; aa++)
1094dab3f910Sjsing 		;
1095dab3f910Sjsing 	for (bb = b[DB_serial]; *bb == '0'; bb++)
1096dab3f910Sjsing 		;
1097dab3f910Sjsing 	return (strcmp(aa, bb));
1098dab3f910Sjsing }
1099dab3f910Sjsing 
1100dab3f910Sjsing static int
1101dab3f910Sjsing index_name_qual(char **a)
1102dab3f910Sjsing {
1103dab3f910Sjsing 	return (a[0][0] == 'V');
1104dab3f910Sjsing }
1105dab3f910Sjsing 
1106dab3f910Sjsing static unsigned long
1107dab3f910Sjsing index_name_hash(const OPENSSL_CSTRING *a)
1108dab3f910Sjsing {
1109dab3f910Sjsing 	return (lh_strhash(a[DB_name]));
1110dab3f910Sjsing }
1111dab3f910Sjsing 
1112dab3f910Sjsing int
1113dab3f910Sjsing index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b)
1114dab3f910Sjsing {
1115dab3f910Sjsing 	return (strcmp(a[DB_name], b[DB_name]));
1116dab3f910Sjsing }
1117dab3f910Sjsing 
1118dab3f910Sjsing static IMPLEMENT_LHASH_HASH_FN(index_serial, OPENSSL_CSTRING)
1119dab3f910Sjsing static IMPLEMENT_LHASH_COMP_FN(index_serial, OPENSSL_CSTRING)
1120dab3f910Sjsing static IMPLEMENT_LHASH_HASH_FN(index_name, OPENSSL_CSTRING)
1121dab3f910Sjsing static IMPLEMENT_LHASH_COMP_FN(index_name, OPENSSL_CSTRING)
1122dab3f910Sjsing 
1123dab3f910Sjsing BIGNUM *
1124dab3f910Sjsing load_serial(char *serialfile, int create, ASN1_INTEGER **retai)
1125dab3f910Sjsing {
1126dab3f910Sjsing 	BIO *in = NULL;
1127dab3f910Sjsing 	BIGNUM *ret = NULL;
1128dab3f910Sjsing 	char buf[1024];
1129dab3f910Sjsing 	ASN1_INTEGER *ai = NULL;
1130dab3f910Sjsing 
1131dab3f910Sjsing 	ai = ASN1_INTEGER_new();
1132dab3f910Sjsing 	if (ai == NULL)
1133dab3f910Sjsing 		goto err;
1134dab3f910Sjsing 
1135dab3f910Sjsing 	if ((in = BIO_new(BIO_s_file())) == NULL) {
1136dab3f910Sjsing 		ERR_print_errors(bio_err);
1137dab3f910Sjsing 		goto err;
1138dab3f910Sjsing 	}
1139dab3f910Sjsing 	if (BIO_read_filename(in, serialfile) <= 0) {
1140dab3f910Sjsing 		if (!create) {
1141dab3f910Sjsing 			perror(serialfile);
1142dab3f910Sjsing 			goto err;
1143dab3f910Sjsing 		} else {
1144dab3f910Sjsing 			ret = BN_new();
1145dab3f910Sjsing 			if (ret == NULL || !rand_serial(ret, ai))
1146dab3f910Sjsing 				BIO_printf(bio_err, "Out of memory\n");
1147dab3f910Sjsing 		}
1148dab3f910Sjsing 	} else {
11498907b694Sderaadt 		if (!a2i_ASN1_INTEGER(in, ai, buf, sizeof buf)) {
1150dab3f910Sjsing 			BIO_printf(bio_err, "unable to load number from %s\n",
1151dab3f910Sjsing 			    serialfile);
1152dab3f910Sjsing 			goto err;
1153dab3f910Sjsing 		}
1154dab3f910Sjsing 		ret = ASN1_INTEGER_to_BN(ai, NULL);
1155dab3f910Sjsing 		if (ret == NULL) {
1156dab3f910Sjsing 			BIO_printf(bio_err,
1157dab3f910Sjsing 			    "error converting number from bin to BIGNUM\n");
1158dab3f910Sjsing 			goto err;
1159dab3f910Sjsing 		}
1160dab3f910Sjsing 	}
1161dab3f910Sjsing 
1162dab3f910Sjsing 	if (ret && retai) {
1163dab3f910Sjsing 		*retai = ai;
1164dab3f910Sjsing 		ai = NULL;
1165dab3f910Sjsing 	}
1166dab3f910Sjsing 
1167dab3f910Sjsing  err:
1168dab3f910Sjsing 	BIO_free(in);
1169dab3f910Sjsing 	ASN1_INTEGER_free(ai);
1170dab3f910Sjsing 	return (ret);
1171dab3f910Sjsing }
1172dab3f910Sjsing 
1173dab3f910Sjsing int
1174dab3f910Sjsing save_serial(char *serialfile, char *suffix, BIGNUM *serial,
1175dab3f910Sjsing     ASN1_INTEGER **retai)
1176dab3f910Sjsing {
11778907b694Sderaadt 	char serialpath[PATH_MAX];
1178dab3f910Sjsing 	BIO *out = NULL;
1179dab3f910Sjsing 	int ret = 0, n;
1180dab3f910Sjsing 	ASN1_INTEGER *ai = NULL;
1181dab3f910Sjsing 
1182dab3f910Sjsing 	if (suffix == NULL)
11838907b694Sderaadt 		n = strlcpy(serialpath, serialfile, sizeof serialpath);
1184dab3f910Sjsing 	else
11858907b694Sderaadt 		n = snprintf(serialpath, sizeof serialpath, "%s.%s",
1186dab3f910Sjsing 		    serialfile, suffix);
1187515e489cSderaadt 	if (n < 0 || n >= sizeof(serialpath)) {
1188dab3f910Sjsing 		BIO_printf(bio_err, "serial too long\n");
1189dab3f910Sjsing 		goto err;
1190dab3f910Sjsing 	}
1191dab3f910Sjsing 	out = BIO_new(BIO_s_file());
1192dab3f910Sjsing 	if (out == NULL) {
1193dab3f910Sjsing 		ERR_print_errors(bio_err);
1194dab3f910Sjsing 		goto err;
1195dab3f910Sjsing 	}
11968907b694Sderaadt 	if (BIO_write_filename(out, serialpath) <= 0) {
1197dab3f910Sjsing 		perror(serialfile);
1198dab3f910Sjsing 		goto err;
1199dab3f910Sjsing 	}
1200dab3f910Sjsing 	if ((ai = BN_to_ASN1_INTEGER(serial, NULL)) == NULL) {
1201dab3f910Sjsing 		BIO_printf(bio_err,
1202dab3f910Sjsing 		    "error converting serial to ASN.1 format\n");
1203dab3f910Sjsing 		goto err;
1204dab3f910Sjsing 	}
1205dab3f910Sjsing 	i2a_ASN1_INTEGER(out, ai);
1206dab3f910Sjsing 	BIO_puts(out, "\n");
1207dab3f910Sjsing 	ret = 1;
1208dab3f910Sjsing 	if (retai) {
1209dab3f910Sjsing 		*retai = ai;
1210dab3f910Sjsing 		ai = NULL;
1211dab3f910Sjsing 	}
1212dab3f910Sjsing 
1213dab3f910Sjsing  err:
1214dab3f910Sjsing 	BIO_free_all(out);
1215dab3f910Sjsing 	ASN1_INTEGER_free(ai);
1216dab3f910Sjsing 	return (ret);
1217dab3f910Sjsing }
1218dab3f910Sjsing 
1219dab3f910Sjsing int
1220dab3f910Sjsing rotate_serial(char *serialfile, char *new_suffix, char *old_suffix)
1221dab3f910Sjsing {
12228907b694Sderaadt 	char opath[PATH_MAX], npath[PATH_MAX];
1223dab3f910Sjsing 
12248907b694Sderaadt 	if (snprintf(npath, sizeof npath, "%s.%s", serialfile,
12258907b694Sderaadt 	    new_suffix) >= sizeof npath) {
1226dab3f910Sjsing 		BIO_printf(bio_err, "file name too long\n");
1227dab3f910Sjsing 		goto err;
1228dab3f910Sjsing 	}
1229dab3f910Sjsing 
12308907b694Sderaadt 	if (snprintf(opath, sizeof opath, "%s.%s", serialfile,
12318907b694Sderaadt 	    old_suffix) >= sizeof opath) {
12328907b694Sderaadt 		BIO_printf(bio_err, "file name too long\n");
12338907b694Sderaadt 		goto err;
12348907b694Sderaadt 	}
1235dab3f910Sjsing 
12363aaa63ebSderaadt 	if (rename(serialfile, opath) == -1 &&
1237dab3f910Sjsing 	    errno != ENOENT && errno != ENOTDIR) {
1238dab3f910Sjsing 		BIO_printf(bio_err, "unable to rename %s to %s\n",
12398907b694Sderaadt 		    serialfile, opath);
1240dab3f910Sjsing 		perror("reason");
1241dab3f910Sjsing 		goto err;
1242dab3f910Sjsing 	}
1243dab3f910Sjsing 
1244dab3f910Sjsing 
12453aaa63ebSderaadt 	if (rename(npath, serialfile) == -1) {
1246dab3f910Sjsing 		BIO_printf(bio_err, "unable to rename %s to %s\n",
12478907b694Sderaadt 		    npath, serialfile);
1248dab3f910Sjsing 		perror("reason");
12493aaa63ebSderaadt 		if (rename(opath, serialfile) == -1) {
1250270038edSdoug 			BIO_printf(bio_err, "unable to rename %s to %s\n",
12518907b694Sderaadt 			    opath, serialfile);
1252270038edSdoug 			perror("reason");
1253270038edSdoug 		}
1254dab3f910Sjsing 		goto err;
1255dab3f910Sjsing 	}
1256dab3f910Sjsing 	return 1;
1257dab3f910Sjsing 
1258dab3f910Sjsing  err:
1259dab3f910Sjsing 	return 0;
1260dab3f910Sjsing }
1261dab3f910Sjsing 
1262dab3f910Sjsing int
1263dab3f910Sjsing rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
1264dab3f910Sjsing {
1265dab3f910Sjsing 	BIGNUM *btmp;
1266dab3f910Sjsing 	int ret = 0;
1267dab3f910Sjsing 
1268dab3f910Sjsing 	if (b)
1269dab3f910Sjsing 		btmp = b;
1270dab3f910Sjsing 	else
1271dab3f910Sjsing 		btmp = BN_new();
1272dab3f910Sjsing 
1273dab3f910Sjsing 	if (!btmp)
1274dab3f910Sjsing 		return 0;
1275dab3f910Sjsing 
1276dab3f910Sjsing 	if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0))
1277dab3f910Sjsing 		goto error;
1278dab3f910Sjsing 	if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
1279dab3f910Sjsing 		goto error;
1280dab3f910Sjsing 
1281dab3f910Sjsing 	ret = 1;
1282dab3f910Sjsing 
1283dab3f910Sjsing  error:
1284c4ec5d7dSjsing 	if (b != btmp)
1285dab3f910Sjsing 		BN_free(btmp);
1286dab3f910Sjsing 
1287dab3f910Sjsing 	return ret;
1288dab3f910Sjsing }
1289dab3f910Sjsing 
1290dab3f910Sjsing CA_DB *
1291dab3f910Sjsing load_index(char *dbfile, DB_ATTR *db_attr)
1292dab3f910Sjsing {
1293dab3f910Sjsing 	CA_DB *retdb = NULL;
1294dab3f910Sjsing 	TXT_DB *tmpdb = NULL;
1295dab3f910Sjsing 	BIO *in = BIO_new(BIO_s_file());
1296dab3f910Sjsing 	CONF *dbattr_conf = NULL;
12978907b694Sderaadt 	char attrpath[PATH_MAX];
1298dab3f910Sjsing 	long errorline = -1;
1299dab3f910Sjsing 
1300dab3f910Sjsing 	if (in == NULL) {
1301dab3f910Sjsing 		ERR_print_errors(bio_err);
1302dab3f910Sjsing 		goto err;
1303dab3f910Sjsing 	}
1304dab3f910Sjsing 	if (BIO_read_filename(in, dbfile) <= 0) {
1305dab3f910Sjsing 		perror(dbfile);
1306dab3f910Sjsing 		BIO_printf(bio_err, "unable to open '%s'\n", dbfile);
1307dab3f910Sjsing 		goto err;
1308dab3f910Sjsing 	}
1309dab3f910Sjsing 	if ((tmpdb = TXT_DB_read(in, DB_NUMBER)) == NULL)
1310dab3f910Sjsing 		goto err;
1311dab3f910Sjsing 
13128907b694Sderaadt 	if (snprintf(attrpath, sizeof attrpath, "%s.attr", dbfile)
13138907b694Sderaadt 	    >= sizeof attrpath) {
13148907b694Sderaadt 		BIO_printf(bio_err, "attr filename too long\n");
13158907b694Sderaadt 		goto err;
13168907b694Sderaadt 	}
13178907b694Sderaadt 
1318dab3f910Sjsing 	dbattr_conf = NCONF_new(NULL);
13198907b694Sderaadt 	if (NCONF_load(dbattr_conf, attrpath, &errorline) <= 0) {
1320dab3f910Sjsing 		if (errorline > 0) {
1321dab3f910Sjsing 			BIO_printf(bio_err,
1322dab3f910Sjsing 			    "error on line %ld of db attribute file '%s'\n",
13238907b694Sderaadt 			    errorline, attrpath);
1324dab3f910Sjsing 			goto err;
1325dab3f910Sjsing 		} else {
1326dab3f910Sjsing 			NCONF_free(dbattr_conf);
1327dab3f910Sjsing 			dbattr_conf = NULL;
1328dab3f910Sjsing 		}
1329dab3f910Sjsing 	}
1330dab3f910Sjsing 	if ((retdb = malloc(sizeof(CA_DB))) == NULL) {
1331dab3f910Sjsing 		fprintf(stderr, "Out of memory\n");
1332dab3f910Sjsing 		goto err;
1333dab3f910Sjsing 	}
1334dab3f910Sjsing 	retdb->db = tmpdb;
1335dab3f910Sjsing 	tmpdb = NULL;
1336dab3f910Sjsing 	if (db_attr)
1337dab3f910Sjsing 		retdb->attributes = *db_attr;
1338dab3f910Sjsing 	else {
1339dab3f910Sjsing 		retdb->attributes.unique_subject = 1;
1340dab3f910Sjsing 	}
1341dab3f910Sjsing 
1342dab3f910Sjsing 	if (dbattr_conf) {
1343dab3f910Sjsing 		char *p = NCONF_get_string(dbattr_conf, NULL, "unique_subject");
1344dab3f910Sjsing 		if (p) {
1345dab3f910Sjsing 			retdb->attributes.unique_subject = parse_yesno(p, 1);
1346dab3f910Sjsing 		}
1347dab3f910Sjsing 	}
1348dab3f910Sjsing 
1349dab3f910Sjsing  err:
1350dab3f910Sjsing 	NCONF_free(dbattr_conf);
1351dab3f910Sjsing 	TXT_DB_free(tmpdb);
1352dab3f910Sjsing 	BIO_free_all(in);
1353dab3f910Sjsing 	return retdb;
1354dab3f910Sjsing }
1355dab3f910Sjsing 
1356dab3f910Sjsing int
1357dab3f910Sjsing index_index(CA_DB *db)
1358dab3f910Sjsing {
1359dab3f910Sjsing 	if (!TXT_DB_create_index(db->db, DB_serial, NULL,
1360dab3f910Sjsing 	    LHASH_HASH_FN(index_serial), LHASH_COMP_FN(index_serial))) {
1361dab3f910Sjsing 		BIO_printf(bio_err,
1362dab3f910Sjsing 		    "error creating serial number index:(%ld,%ld,%ld)\n",
1363dab3f910Sjsing 		    db->db->error, db->db->arg1, db->db->arg2);
1364dab3f910Sjsing 		return 0;
1365dab3f910Sjsing 	}
1366dab3f910Sjsing 	if (db->attributes.unique_subject &&
1367dab3f910Sjsing 	    !TXT_DB_create_index(db->db, DB_name, index_name_qual,
1368dab3f910Sjsing 	    LHASH_HASH_FN(index_name), LHASH_COMP_FN(index_name))) {
1369dab3f910Sjsing 		BIO_printf(bio_err, "error creating name index:(%ld,%ld,%ld)\n",
1370dab3f910Sjsing 		    db->db->error, db->db->arg1, db->db->arg2);
1371dab3f910Sjsing 		return 0;
1372dab3f910Sjsing 	}
1373dab3f910Sjsing 	return 1;
1374dab3f910Sjsing }
1375dab3f910Sjsing 
1376dab3f910Sjsing int
13778907b694Sderaadt save_index(const char *file, const char *suffix, CA_DB *db)
1378dab3f910Sjsing {
13798907b694Sderaadt 	char attrpath[PATH_MAX], dbfile[PATH_MAX];
1380dab3f910Sjsing 	BIO *out = BIO_new(BIO_s_file());
1381dab3f910Sjsing 	int j;
1382dab3f910Sjsing 
1383dab3f910Sjsing 	if (out == NULL) {
1384dab3f910Sjsing 		ERR_print_errors(bio_err);
1385dab3f910Sjsing 		goto err;
1386dab3f910Sjsing 	}
13878907b694Sderaadt 	if (snprintf(attrpath, sizeof attrpath, "%s.attr.%s",
13888907b694Sderaadt 	    file, suffix) >= sizeof attrpath) {
1389dab3f910Sjsing 		BIO_printf(bio_err, "file name too long\n");
1390dab3f910Sjsing 		goto err;
1391dab3f910Sjsing 	}
13928907b694Sderaadt 	if (snprintf(dbfile, sizeof dbfile, "%s.%s",
13938907b694Sderaadt 	    file, suffix) >= sizeof dbfile) {
13948907b694Sderaadt 		BIO_printf(bio_err, "file name too long\n");
13958907b694Sderaadt 		goto err;
13968907b694Sderaadt 	}
1397dab3f910Sjsing 
13988907b694Sderaadt 	if (BIO_write_filename(out, dbfile) <= 0) {
1399dab3f910Sjsing 		perror(dbfile);
1400dab3f910Sjsing 		BIO_printf(bio_err, "unable to open '%s'\n", dbfile);
1401dab3f910Sjsing 		goto err;
1402dab3f910Sjsing 	}
1403dab3f910Sjsing 	j = TXT_DB_write(out, db->db);
1404dab3f910Sjsing 	if (j <= 0)
1405dab3f910Sjsing 		goto err;
1406dab3f910Sjsing 
1407dab3f910Sjsing 	BIO_free(out);
1408dab3f910Sjsing 
1409dab3f910Sjsing 	out = BIO_new(BIO_s_file());
1410dab3f910Sjsing 
14118907b694Sderaadt 	if (BIO_write_filename(out, attrpath) <= 0) {
14128907b694Sderaadt 		perror(attrpath);
14138907b694Sderaadt 		BIO_printf(bio_err, "unable to open '%s'\n", attrpath);
1414dab3f910Sjsing 		goto err;
1415dab3f910Sjsing 	}
1416dab3f910Sjsing 	BIO_printf(out, "unique_subject = %s\n",
1417dab3f910Sjsing 	    db->attributes.unique_subject ? "yes" : "no");
1418dab3f910Sjsing 	BIO_free(out);
1419dab3f910Sjsing 
1420dab3f910Sjsing 	return 1;
1421dab3f910Sjsing 
1422dab3f910Sjsing  err:
1423dab3f910Sjsing 	return 0;
1424dab3f910Sjsing }
1425dab3f910Sjsing 
1426dab3f910Sjsing int
1427dab3f910Sjsing rotate_index(const char *dbfile, const char *new_suffix, const char *old_suffix)
1428dab3f910Sjsing {
14298907b694Sderaadt 	char attrpath[PATH_MAX], nattrpath[PATH_MAX], oattrpath[PATH_MAX];
14308907b694Sderaadt 	char dbpath[PATH_MAX], odbpath[PATH_MAX];
1431dab3f910Sjsing 
14328907b694Sderaadt 	if (snprintf(attrpath, sizeof attrpath, "%s.attr",
14338907b694Sderaadt 	    dbfile) >= sizeof attrpath) {
1434dab3f910Sjsing 		BIO_printf(bio_err, "file name too long\n");
1435dab3f910Sjsing 		goto err;
1436dab3f910Sjsing 	}
14378907b694Sderaadt 	if (snprintf(nattrpath, sizeof nattrpath, "%s.attr.%s",
14388907b694Sderaadt 	    dbfile, new_suffix) >= sizeof nattrpath) {
14398907b694Sderaadt 		BIO_printf(bio_err, "file name too long\n");
14408907b694Sderaadt 		goto err;
14418907b694Sderaadt 	}
14428907b694Sderaadt 	if (snprintf(oattrpath, sizeof oattrpath, "%s.attr.%s",
14438907b694Sderaadt 	    dbfile, old_suffix) >= sizeof oattrpath) {
14448907b694Sderaadt 		BIO_printf(bio_err, "file name too long\n");
14458907b694Sderaadt 		goto err;
14468907b694Sderaadt 	}
14478907b694Sderaadt 	if (snprintf(dbpath, sizeof dbpath, "%s.%s",
14488907b694Sderaadt 	    dbfile, new_suffix) >= sizeof dbpath) {
14498907b694Sderaadt 		BIO_printf(bio_err, "file name too long\n");
14508907b694Sderaadt 		goto err;
14518907b694Sderaadt 	}
14528907b694Sderaadt 	if (snprintf(odbpath, sizeof odbpath, "%s.%s",
14538907b694Sderaadt 	    dbfile, old_suffix) >= sizeof odbpath) {
14548907b694Sderaadt 		BIO_printf(bio_err, "file name too long\n");
14558907b694Sderaadt 		goto err;
14568907b694Sderaadt 	}
1457dab3f910Sjsing 
14583aaa63ebSderaadt 	if (rename(dbfile, odbpath) == -1 && errno != ENOENT && errno != ENOTDIR) {
1459dab3f910Sjsing 		BIO_printf(bio_err, "unable to rename %s to %s\n",
14608907b694Sderaadt 		    dbfile, odbpath);
1461dab3f910Sjsing 		perror("reason");
1462dab3f910Sjsing 		goto err;
1463dab3f910Sjsing 	}
1464dab3f910Sjsing 
14653aaa63ebSderaadt 	if (rename(dbpath, dbfile) == -1) {
1466dab3f910Sjsing 		BIO_printf(bio_err, "unable to rename %s to %s\n",
14678907b694Sderaadt 		    dbpath, dbfile);
1468dab3f910Sjsing 		perror("reason");
14693aaa63ebSderaadt 		if (rename(odbpath, dbfile) == -1) {
1470270038edSdoug 			BIO_printf(bio_err, "unable to rename %s to %s\n",
14718907b694Sderaadt 			    odbpath, dbfile);
1472270038edSdoug 			perror("reason");
1473270038edSdoug 		}
1474dab3f910Sjsing 		goto err;
1475dab3f910Sjsing 	}
1476dab3f910Sjsing 
14773aaa63ebSderaadt 	if (rename(attrpath, oattrpath) == -1 && errno != ENOENT && errno != ENOTDIR) {
1478dab3f910Sjsing 		BIO_printf(bio_err, "unable to rename %s to %s\n",
14798907b694Sderaadt 		    attrpath, oattrpath);
1480dab3f910Sjsing 		perror("reason");
14813aaa63ebSderaadt 		if (rename(dbfile, dbpath) == -1) {
1482270038edSdoug 			BIO_printf(bio_err, "unable to rename %s to %s\n",
14838907b694Sderaadt 			    dbfile, dbpath);
1484270038edSdoug 			perror("reason");
1485270038edSdoug 		}
14863aaa63ebSderaadt 		if (rename(odbpath, dbfile) == -1) {
1487270038edSdoug 			BIO_printf(bio_err, "unable to rename %s to %s\n",
14888907b694Sderaadt 			    odbpath, dbfile);
1489270038edSdoug 			perror("reason");
1490270038edSdoug 		}
1491dab3f910Sjsing 		goto err;
1492dab3f910Sjsing 	}
1493dab3f910Sjsing 
14943aaa63ebSderaadt 	if (rename(nattrpath, attrpath) == -1) {
1495dab3f910Sjsing 		BIO_printf(bio_err, "unable to rename %s to %s\n",
14968907b694Sderaadt 		    nattrpath, attrpath);
1497dab3f910Sjsing 		perror("reason");
14983aaa63ebSderaadt 		if (rename(oattrpath, attrpath) == -1) {
1499270038edSdoug 			BIO_printf(bio_err, "unable to rename %s to %s\n",
15008907b694Sderaadt 			    oattrpath, attrpath);
1501270038edSdoug 			perror("reason");
1502270038edSdoug 		}
15033aaa63ebSderaadt 		if (rename(dbfile, dbpath) == -1) {
1504270038edSdoug 			BIO_printf(bio_err, "unable to rename %s to %s\n",
15058907b694Sderaadt 			    dbfile, dbpath);
1506270038edSdoug 			perror("reason");
1507270038edSdoug 		}
15083aaa63ebSderaadt 		if (rename(odbpath, dbfile) == -1) {
1509270038edSdoug 			BIO_printf(bio_err, "unable to rename %s to %s\n",
15108907b694Sderaadt 			    odbpath, dbfile);
1511270038edSdoug 			perror("reason");
1512270038edSdoug 		}
1513dab3f910Sjsing 		goto err;
1514dab3f910Sjsing 	}
1515dab3f910Sjsing 	return 1;
1516dab3f910Sjsing 
1517dab3f910Sjsing  err:
1518dab3f910Sjsing 	return 0;
1519dab3f910Sjsing }
1520dab3f910Sjsing 
1521dab3f910Sjsing void
1522dab3f910Sjsing free_index(CA_DB *db)
1523dab3f910Sjsing {
1524dab3f910Sjsing 	if (db) {
1525dab3f910Sjsing 		TXT_DB_free(db->db);
1526dab3f910Sjsing 		free(db);
1527dab3f910Sjsing 	}
1528dab3f910Sjsing }
1529dab3f910Sjsing 
1530dab3f910Sjsing int
1531dab3f910Sjsing parse_yesno(const char *str, int def)
1532dab3f910Sjsing {
1533dab3f910Sjsing 	int ret = def;
1534dab3f910Sjsing 
1535dab3f910Sjsing 	if (str) {
1536dab3f910Sjsing 		switch (*str) {
1537dab3f910Sjsing 		case 'f':	/* false */
1538dab3f910Sjsing 		case 'F':	/* FALSE */
1539dab3f910Sjsing 		case 'n':	/* no */
1540dab3f910Sjsing 		case 'N':	/* NO */
1541dab3f910Sjsing 		case '0':	/* 0 */
1542dab3f910Sjsing 			ret = 0;
1543dab3f910Sjsing 			break;
1544dab3f910Sjsing 		case 't':	/* true */
1545dab3f910Sjsing 		case 'T':	/* TRUE */
1546dab3f910Sjsing 		case 'y':	/* yes */
1547dab3f910Sjsing 		case 'Y':	/* YES */
1548dab3f910Sjsing 		case '1':	/* 1 */
1549dab3f910Sjsing 			ret = 1;
1550dab3f910Sjsing 			break;
1551dab3f910Sjsing 		default:
1552dab3f910Sjsing 			ret = def;
1553dab3f910Sjsing 			break;
1554dab3f910Sjsing 		}
1555dab3f910Sjsing 	}
1556dab3f910Sjsing 	return ret;
1557dab3f910Sjsing }
1558dab3f910Sjsing 
1559dab3f910Sjsing /*
1560dab3f910Sjsing  * subject is expected to be in the format /type0=value0/type1=value1/type2=...
1561dab3f910Sjsing  * where characters may be escaped by \
1562dab3f910Sjsing  */
1563dab3f910Sjsing X509_NAME *
1564dab3f910Sjsing parse_name(char *subject, long chtype, int multirdn)
1565dab3f910Sjsing {
1566dab3f910Sjsing 	X509_NAME *name = NULL;
1567dab3f910Sjsing 	size_t buflen, max_ne;
1568dab3f910Sjsing 	char **ne_types, **ne_values;
1569dab3f910Sjsing 	char *buf, *bp, *sp;
1570dab3f910Sjsing 	int i, nid, ne_num = 0;
1571dab3f910Sjsing 	int *mval;
1572dab3f910Sjsing 
1573dab3f910Sjsing 	/*
1574dab3f910Sjsing 	 * Buffer to copy the types and values into. Due to escaping the
1575dab3f910Sjsing 	 * copy can only become shorter.
1576dab3f910Sjsing 	 */
1577dab3f910Sjsing 	buflen = strlen(subject) + 1;
1578dab3f910Sjsing 	buf = malloc(buflen);
1579dab3f910Sjsing 
1580dab3f910Sjsing 	/* Maximum number of name elements. */
1581dab3f910Sjsing 	max_ne = buflen / 2 + 1;
1582dab3f910Sjsing 	ne_types = reallocarray(NULL, max_ne, sizeof(char *));
1583dab3f910Sjsing 	ne_values = reallocarray(NULL, max_ne, sizeof(char *));
1584dab3f910Sjsing 	mval = reallocarray(NULL, max_ne, sizeof(int));
1585dab3f910Sjsing 
1586dab3f910Sjsing 	if (buf == NULL || ne_types == NULL || ne_values == NULL ||
1587dab3f910Sjsing 	    mval == NULL) {
1588dab3f910Sjsing 		BIO_printf(bio_err, "malloc error\n");
1589dab3f910Sjsing 		goto error;
1590dab3f910Sjsing 	}
1591dab3f910Sjsing 
1592dab3f910Sjsing 	bp = buf;
1593dab3f910Sjsing 	sp = subject;
1594dab3f910Sjsing 
1595dab3f910Sjsing 	if (*subject != '/') {
1596dab3f910Sjsing 		BIO_printf(bio_err, "Subject does not start with '/'.\n");
1597dab3f910Sjsing 		goto error;
1598dab3f910Sjsing 	}
1599dab3f910Sjsing 
1600dab3f910Sjsing 	/* Skip leading '/'. */
1601dab3f910Sjsing 	sp++;
1602dab3f910Sjsing 
1603dab3f910Sjsing 	/* No multivalued RDN by default. */
1604dab3f910Sjsing 	mval[ne_num] = 0;
1605dab3f910Sjsing 
1606dab3f910Sjsing 	while (*sp) {
1607dab3f910Sjsing 		/* Collect type. */
1608dab3f910Sjsing 		ne_types[ne_num] = bp;
1609dab3f910Sjsing 		while (*sp) {
1610dab3f910Sjsing 			/* is there anything to escape in the type...? */
1611dab3f910Sjsing 			if (*sp == '\\') {
1612dab3f910Sjsing 				if (*++sp)
1613dab3f910Sjsing 					*bp++ = *sp++;
1614dab3f910Sjsing 				else {
1615dab3f910Sjsing 					BIO_printf(bio_err, "escape character "
1616dab3f910Sjsing 					    "at end of string\n");
1617dab3f910Sjsing 					goto error;
1618dab3f910Sjsing 				}
1619dab3f910Sjsing 			} else if (*sp == '=') {
1620dab3f910Sjsing 				sp++;
1621dab3f910Sjsing 				*bp++ = '\0';
1622dab3f910Sjsing 				break;
1623dab3f910Sjsing 			} else
1624dab3f910Sjsing 				*bp++ = *sp++;
1625dab3f910Sjsing 		}
1626dab3f910Sjsing 		if (!*sp) {
1627dab3f910Sjsing 			BIO_printf(bio_err, "end of string encountered while "
1628dab3f910Sjsing 			    "processing type of subject name element #%d\n",
1629dab3f910Sjsing 			    ne_num);
1630dab3f910Sjsing 			goto error;
1631dab3f910Sjsing 		}
1632dab3f910Sjsing 		ne_values[ne_num] = bp;
1633dab3f910Sjsing 		while (*sp) {
1634dab3f910Sjsing 			if (*sp == '\\') {
1635dab3f910Sjsing 				if (*++sp)
1636dab3f910Sjsing 					*bp++ = *sp++;
1637dab3f910Sjsing 				else {
1638dab3f910Sjsing 					BIO_printf(bio_err, "escape character "
1639dab3f910Sjsing 					    "at end of string\n");
1640dab3f910Sjsing 					goto error;
1641dab3f910Sjsing 				}
1642dab3f910Sjsing 			} else if (*sp == '/') {
1643dab3f910Sjsing 				sp++;
1644dab3f910Sjsing 				/* no multivalued RDN by default */
1645dab3f910Sjsing 				mval[ne_num + 1] = 0;
1646dab3f910Sjsing 				break;
1647dab3f910Sjsing 			} else if (*sp == '+' && multirdn) {
164880772f88Smiod 				/* a not escaped + signals a multivalued RDN */
1649dab3f910Sjsing 				sp++;
1650dab3f910Sjsing 				mval[ne_num + 1] = -1;
1651dab3f910Sjsing 				break;
1652dab3f910Sjsing 			} else
1653dab3f910Sjsing 				*bp++ = *sp++;
1654dab3f910Sjsing 		}
1655dab3f910Sjsing 		*bp++ = '\0';
1656dab3f910Sjsing 		ne_num++;
1657dab3f910Sjsing 	}
1658dab3f910Sjsing 
1659dab3f910Sjsing 	if ((name = X509_NAME_new()) == NULL)
1660dab3f910Sjsing 		goto error;
1661dab3f910Sjsing 
1662dab3f910Sjsing 	for (i = 0; i < ne_num; i++) {
1663dab3f910Sjsing 		if ((nid = OBJ_txt2nid(ne_types[i])) == NID_undef) {
1664dab3f910Sjsing 			BIO_printf(bio_err,
1665dab3f910Sjsing 			    "Subject Attribute %s has no known NID, skipped\n",
1666dab3f910Sjsing 			    ne_types[i]);
1667dab3f910Sjsing 			continue;
1668dab3f910Sjsing 		}
1669dab3f910Sjsing 		if (!*ne_values[i]) {
1670dab3f910Sjsing 			BIO_printf(bio_err, "No value provided for Subject "
1671dab3f910Sjsing 			    "Attribute %s, skipped\n", ne_types[i]);
1672dab3f910Sjsing 			continue;
1673dab3f910Sjsing 		}
1674dab3f910Sjsing 		if (!X509_NAME_add_entry_by_NID(name, nid, chtype,
1675dab3f910Sjsing 		    (unsigned char *) ne_values[i], -1, -1, mval[i]))
1676dab3f910Sjsing 			goto error;
1677dab3f910Sjsing 	}
1678dab3f910Sjsing 	goto done;
1679dab3f910Sjsing 
1680dab3f910Sjsing  error:
1681dab3f910Sjsing 	X509_NAME_free(name);
1682dab3f910Sjsing 	name = NULL;
1683dab3f910Sjsing 
1684dab3f910Sjsing  done:
1685dab3f910Sjsing 	free(ne_values);
1686dab3f910Sjsing 	free(ne_types);
1687dab3f910Sjsing 	free(mval);
1688dab3f910Sjsing 	free(buf);
1689dab3f910Sjsing 
1690dab3f910Sjsing 	return name;
1691dab3f910Sjsing }
1692dab3f910Sjsing 
1693dab3f910Sjsing int
1694dab3f910Sjsing args_verify(char ***pargs, int *pargc, int *badarg, BIO *err,
1695dab3f910Sjsing     X509_VERIFY_PARAM **pm)
1696dab3f910Sjsing {
1697dab3f910Sjsing 	ASN1_OBJECT *otmp = NULL;
1698dab3f910Sjsing 	unsigned long flags = 0;
1699dab3f910Sjsing 	int i;
1700dab3f910Sjsing 	int purpose = 0, depth = -1;
1701dab3f910Sjsing 	char **oldargs = *pargs;
1702dab3f910Sjsing 	char *arg = **pargs, *argn = (*pargs)[1];
1703dab3f910Sjsing 	time_t at_time = 0;
1704dab3f910Sjsing 	const char *errstr = NULL;
1705dab3f910Sjsing 
1706dab3f910Sjsing 	if (!strcmp(arg, "-policy")) {
1707dab3f910Sjsing 		if (!argn)
1708dab3f910Sjsing 			*badarg = 1;
1709dab3f910Sjsing 		else {
1710dab3f910Sjsing 			otmp = OBJ_txt2obj(argn, 0);
1711dab3f910Sjsing 			if (!otmp) {
1712dab3f910Sjsing 				BIO_printf(err, "Invalid Policy \"%s\"\n",
1713dab3f910Sjsing 				    argn);
1714dab3f910Sjsing 				*badarg = 1;
1715dab3f910Sjsing 			}
1716dab3f910Sjsing 		}
1717dab3f910Sjsing 		(*pargs)++;
1718dab3f910Sjsing 	} else if (strcmp(arg, "-purpose") == 0) {
17195bbf7eacStb 		const X509_PURPOSE *xptmp;
1720dab3f910Sjsing 		if (!argn)
1721dab3f910Sjsing 			*badarg = 1;
1722dab3f910Sjsing 		else {
1723dab3f910Sjsing 			i = X509_PURPOSE_get_by_sname(argn);
1724dab3f910Sjsing 			if (i < 0) {
1725dab3f910Sjsing 				BIO_printf(err, "unrecognized purpose\n");
1726dab3f910Sjsing 				*badarg = 1;
1727dab3f910Sjsing 			} else {
1728dab3f910Sjsing 				xptmp = X509_PURPOSE_get0(i);
1729dab3f910Sjsing 				purpose = X509_PURPOSE_get_id(xptmp);
1730dab3f910Sjsing 			}
1731dab3f910Sjsing 		}
1732dab3f910Sjsing 		(*pargs)++;
1733dab3f910Sjsing 	} else if (strcmp(arg, "-verify_depth") == 0) {
1734dab3f910Sjsing 		if (!argn)
1735dab3f910Sjsing 			*badarg = 1;
1736dab3f910Sjsing 		else {
1737dab3f910Sjsing 			depth = strtonum(argn, 1, INT_MAX, &errstr);
1738dab3f910Sjsing 			if (errstr) {
1739dab3f910Sjsing 				BIO_printf(err, "invalid depth %s: %s\n",
1740dab3f910Sjsing 				    argn, errstr);
1741dab3f910Sjsing 				*badarg = 1;
1742dab3f910Sjsing 			}
1743dab3f910Sjsing 		}
1744dab3f910Sjsing 		(*pargs)++;
1745dab3f910Sjsing 	} else if (strcmp(arg, "-attime") == 0) {
1746dab3f910Sjsing 		if (!argn)
1747dab3f910Sjsing 			*badarg = 1;
1748dab3f910Sjsing 		else {
1749dab3f910Sjsing 			long long timestamp;
1750dab3f910Sjsing 			/*
1751dab3f910Sjsing 			 * interpret the -attime argument as seconds since
1752dab3f910Sjsing 			 * Epoch
1753dab3f910Sjsing 			 */
1754dab3f910Sjsing 			if (sscanf(argn, "%lli", &timestamp) != 1) {
1755dab3f910Sjsing 				BIO_printf(bio_err,
1756dab3f910Sjsing 				    "Error parsing timestamp %s\n",
1757dab3f910Sjsing 				    argn);
1758dab3f910Sjsing 				*badarg = 1;
1759dab3f910Sjsing 			}
1760dab3f910Sjsing 			/* XXX 2038 truncation */
1761dab3f910Sjsing 			at_time = (time_t) timestamp;
1762dab3f910Sjsing 		}
1763dab3f910Sjsing 		(*pargs)++;
1764dab3f910Sjsing 	} else if (!strcmp(arg, "-ignore_critical"))
1765dab3f910Sjsing 		flags |= X509_V_FLAG_IGNORE_CRITICAL;
1766dab3f910Sjsing 	else if (!strcmp(arg, "-issuer_checks"))
1767dab3f910Sjsing 		flags |= X509_V_FLAG_CB_ISSUER_CHECK;
1768dab3f910Sjsing 	else if (!strcmp(arg, "-crl_check"))
1769dab3f910Sjsing 		flags |= X509_V_FLAG_CRL_CHECK;
1770dab3f910Sjsing 	else if (!strcmp(arg, "-crl_check_all"))
1771dab3f910Sjsing 		flags |= X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL;
1772dab3f910Sjsing 	else if (!strcmp(arg, "-policy_check"))
1773dab3f910Sjsing 		flags |= X509_V_FLAG_POLICY_CHECK;
1774dab3f910Sjsing 	else if (!strcmp(arg, "-explicit_policy"))
1775dab3f910Sjsing 		flags |= X509_V_FLAG_EXPLICIT_POLICY;
17766f2a58b6Stb 	else if (!strcmp(arg, "-legacy_verify"))
17776f2a58b6Stb 		flags |= X509_V_FLAG_LEGACY_VERIFY;
1778dab3f910Sjsing 	else if (!strcmp(arg, "-inhibit_any"))
1779dab3f910Sjsing 		flags |= X509_V_FLAG_INHIBIT_ANY;
1780dab3f910Sjsing 	else if (!strcmp(arg, "-inhibit_map"))
1781dab3f910Sjsing 		flags |= X509_V_FLAG_INHIBIT_MAP;
1782dab3f910Sjsing 	else if (!strcmp(arg, "-x509_strict"))
1783dab3f910Sjsing 		flags |= X509_V_FLAG_X509_STRICT;
1784dab3f910Sjsing 	else if (!strcmp(arg, "-extended_crl"))
1785dab3f910Sjsing 		flags |= X509_V_FLAG_EXTENDED_CRL_SUPPORT;
1786dab3f910Sjsing 	else if (!strcmp(arg, "-use_deltas"))
1787dab3f910Sjsing 		flags |= X509_V_FLAG_USE_DELTAS;
1788dab3f910Sjsing 	else if (!strcmp(arg, "-policy_print"))
1789dab3f910Sjsing 		flags |= X509_V_FLAG_NOTIFY_POLICY;
1790dab3f910Sjsing 	else if (!strcmp(arg, "-check_ss_sig"))
1791dab3f910Sjsing 		flags |= X509_V_FLAG_CHECK_SS_SIGNATURE;
1792dab3f910Sjsing 	else
1793dab3f910Sjsing 		return 0;
1794dab3f910Sjsing 
1795dab3f910Sjsing 	if (*badarg) {
1796dab3f910Sjsing 		X509_VERIFY_PARAM_free(*pm);
1797dab3f910Sjsing 		*pm = NULL;
1798dab3f910Sjsing 		goto end;
1799dab3f910Sjsing 	}
1800dab3f910Sjsing 	if (!*pm && !(*pm = X509_VERIFY_PARAM_new())) {
1801dab3f910Sjsing 		*badarg = 1;
1802dab3f910Sjsing 		goto end;
1803dab3f910Sjsing 	}
18045edcce77Sbeck 	if (otmp) {
1805dab3f910Sjsing 		X509_VERIFY_PARAM_add0_policy(*pm, otmp);
18065edcce77Sbeck 		otmp = NULL;
18075edcce77Sbeck 	}
1808dab3f910Sjsing 	if (flags)
1809dab3f910Sjsing 		X509_VERIFY_PARAM_set_flags(*pm, flags);
1810dab3f910Sjsing 
1811dab3f910Sjsing 	if (purpose)
1812dab3f910Sjsing 		X509_VERIFY_PARAM_set_purpose(*pm, purpose);
1813dab3f910Sjsing 
1814dab3f910Sjsing 	if (depth >= 0)
1815dab3f910Sjsing 		X509_VERIFY_PARAM_set_depth(*pm, depth);
1816dab3f910Sjsing 
1817dab3f910Sjsing 	if (at_time)
1818dab3f910Sjsing 		X509_VERIFY_PARAM_set_time(*pm, at_time);
1819dab3f910Sjsing 
1820dab3f910Sjsing  end:
1821dab3f910Sjsing 	(*pargs)++;
1822dab3f910Sjsing 
1823dab3f910Sjsing 	if (pargc)
1824dab3f910Sjsing 		*pargc -= *pargs - oldargs;
1825dab3f910Sjsing 
18265edcce77Sbeck 	ASN1_OBJECT_free(otmp);
1827dab3f910Sjsing 	return 1;
1828dab3f910Sjsing }
1829dab3f910Sjsing 
1830dab3f910Sjsing /* Read whole contents of a BIO into an allocated memory buffer and
1831dab3f910Sjsing  * return it.
1832dab3f910Sjsing  */
1833dab3f910Sjsing 
1834dab3f910Sjsing int
1835dab3f910Sjsing bio_to_mem(unsigned char **out, int maxlen, BIO *in)
1836dab3f910Sjsing {
1837dab3f910Sjsing 	BIO *mem;
1838dab3f910Sjsing 	int len, ret;
1839dab3f910Sjsing 	unsigned char tbuf[1024];
1840dab3f910Sjsing 
1841dab3f910Sjsing 	mem = BIO_new(BIO_s_mem());
1842dab3f910Sjsing 	if (!mem)
1843dab3f910Sjsing 		return -1;
1844dab3f910Sjsing 	for (;;) {
1845dab3f910Sjsing 		if ((maxlen != -1) && maxlen < 1024)
1846dab3f910Sjsing 			len = maxlen;
1847dab3f910Sjsing 		else
1848dab3f910Sjsing 			len = 1024;
1849dab3f910Sjsing 		len = BIO_read(in, tbuf, len);
1850dab3f910Sjsing 		if (len <= 0)
1851dab3f910Sjsing 			break;
1852dab3f910Sjsing 		if (BIO_write(mem, tbuf, len) != len) {
1853dab3f910Sjsing 			BIO_free(mem);
1854dab3f910Sjsing 			return -1;
1855dab3f910Sjsing 		}
1856dab3f910Sjsing 		maxlen -= len;
1857dab3f910Sjsing 
1858dab3f910Sjsing 		if (maxlen == 0)
1859dab3f910Sjsing 			break;
1860dab3f910Sjsing 	}
1861dab3f910Sjsing 	ret = BIO_get_mem_data(mem, (char **) out);
1862dab3f910Sjsing 	BIO_set_flags(mem, BIO_FLAGS_MEM_RDONLY);
1863dab3f910Sjsing 	BIO_free(mem);
1864dab3f910Sjsing 	return ret;
1865dab3f910Sjsing }
1866dab3f910Sjsing 
1867dab3f910Sjsing int
1868dab3f910Sjsing pkey_ctrl_string(EVP_PKEY_CTX *ctx, char *value)
1869dab3f910Sjsing {
1870dab3f910Sjsing 	int rv;
1871dab3f910Sjsing 	char *stmp, *vtmp = NULL;
1872dab3f910Sjsing 
18738e315e4cSjsing 	if (value == NULL)
18748e315e4cSjsing 		return -1;
18758e315e4cSjsing 	stmp = strdup(value);
1876dab3f910Sjsing 	if (!stmp)
1877dab3f910Sjsing 		return -1;
1878dab3f910Sjsing 	vtmp = strchr(stmp, ':');
1879dab3f910Sjsing 	if (vtmp) {
1880dab3f910Sjsing 		*vtmp = 0;
1881dab3f910Sjsing 		vtmp++;
1882dab3f910Sjsing 	}
1883dab3f910Sjsing 	rv = EVP_PKEY_CTX_ctrl_str(ctx, stmp, vtmp);
1884dab3f910Sjsing 	free(stmp);
1885dab3f910Sjsing 
1886dab3f910Sjsing 	return rv;
1887dab3f910Sjsing }
1888dab3f910Sjsing 
188941eb9d41Sjsing /*
189041eb9d41Sjsing  * next_protos_parse parses a comma separated list of strings into a string
1891dab3f910Sjsing  * in a format suitable for passing to SSL_CTX_set_next_protos_advertised.
1892dab3f910Sjsing  *   outlen: (output) set to the length of the resulting buffer on success.
1893dab3f910Sjsing  *   err: (maybe NULL) on failure, an error message line is written to this BIO.
1894*92d49c07Stb  *   in: a NUL terminated string like "abc,def,ghi"
1895dab3f910Sjsing  *
1896dab3f910Sjsing  *   returns: a malloced buffer or NULL on failure.
1897dab3f910Sjsing  */
1898dab3f910Sjsing unsigned char *
1899dab3f910Sjsing next_protos_parse(unsigned short *outlen, const char *in)
1900dab3f910Sjsing {
1901dab3f910Sjsing 	size_t len;
1902dab3f910Sjsing 	unsigned char *out;
1903dab3f910Sjsing 	size_t i, start = 0;
1904dab3f910Sjsing 
1905dab3f910Sjsing 	len = strlen(in);
1906dab3f910Sjsing 	if (len >= 65535)
1907dab3f910Sjsing 		return NULL;
1908dab3f910Sjsing 
1909dab3f910Sjsing 	out = malloc(strlen(in) + 1);
1910dab3f910Sjsing 	if (!out)
1911dab3f910Sjsing 		return NULL;
1912dab3f910Sjsing 
1913dab3f910Sjsing 	for (i = 0; i <= len; ++i) {
1914dab3f910Sjsing 		if (i == len || in[i] == ',') {
1915dab3f910Sjsing 			if (i - start > 255) {
1916dab3f910Sjsing 				free(out);
1917dab3f910Sjsing 				return NULL;
1918dab3f910Sjsing 			}
1919dab3f910Sjsing 			out[start] = i - start;
1920dab3f910Sjsing 			start = i + 1;
1921dab3f910Sjsing 		} else
1922dab3f910Sjsing 			out[i + 1] = in[i];
1923dab3f910Sjsing 	}
1924dab3f910Sjsing 
1925dab3f910Sjsing 	*outlen = len + 1;
1926dab3f910Sjsing 	return out;
1927dab3f910Sjsing }
1928dab3f910Sjsing 
1929dab3f910Sjsing int
1930dab3f910Sjsing app_isdir(const char *name)
1931dab3f910Sjsing {
1932dab3f910Sjsing 	struct stat st;
1933dab3f910Sjsing 
1934dab3f910Sjsing 	if (stat(name, &st) == 0)
1935dab3f910Sjsing 		return S_ISDIR(st.st_mode);
1936dab3f910Sjsing 	return -1;
1937dab3f910Sjsing }
19386b8b4364Sjsing 
1939938f9cfcSjsing #define OPTION_WIDTH 18
1940938f9cfcSjsing 
19416b8b4364Sjsing void
1942ea149709Sguenther options_usage(const struct option *opts)
19436b8b4364Sjsing {
1944938f9cfcSjsing 	const char *p, *q;
1945938f9cfcSjsing 	char optstr[32];
19466b8b4364Sjsing 	int i;
19476b8b4364Sjsing 
19486b8b4364Sjsing 	for (i = 0; opts[i].name != NULL; i++) {
19496b8b4364Sjsing 		if (opts[i].desc == NULL)
19506b8b4364Sjsing 			continue;
1951938f9cfcSjsing 
1952938f9cfcSjsing 		snprintf(optstr, sizeof(optstr), "-%s %s", opts[i].name,
1953938f9cfcSjsing 		    (opts[i].argname != NULL) ? opts[i].argname : "");
1954938f9cfcSjsing 		fprintf(stderr, " %-*s", OPTION_WIDTH, optstr);
1955938f9cfcSjsing 		if (strlen(optstr) > OPTION_WIDTH)
1956938f9cfcSjsing 			fprintf(stderr, "\n %-*s", OPTION_WIDTH, "");
1957938f9cfcSjsing 
1958938f9cfcSjsing 		p = opts[i].desc;
1959938f9cfcSjsing 		while ((q = strchr(p, '\n')) != NULL) {
1960938f9cfcSjsing 			fprintf(stderr, " %.*s", (int)(q - p), p);
1961938f9cfcSjsing 			fprintf(stderr, "\n %-*s", OPTION_WIDTH, "");
1962938f9cfcSjsing 			p = q + 1;
1963938f9cfcSjsing 		}
1964938f9cfcSjsing 		fprintf(stderr, " %s\n", p);
19656b8b4364Sjsing 	}
19666b8b4364Sjsing }
19676b8b4364Sjsing 
19686b8b4364Sjsing int
1969ea149709Sguenther options_parse(int argc, char **argv, const struct option *opts, char **unnamed,
1970beba0da1Sjsing     int *argsused)
19716b8b4364Sjsing {
1972644a601eSjsing 	const char *errstr;
1973ea149709Sguenther 	const struct option *opt;
1974644a601eSjsing 	long long val;
19756b8b4364Sjsing 	char *arg, *p;
1976b1649c7eSjsing 	int fmt, used;
1977f9a600f9Sjsing 	int ord = 0;
19786b8b4364Sjsing 	int i, j;
19796b8b4364Sjsing 
198045435f71Sjsing 	if (unnamed != NULL)
198145435f71Sjsing 		*unnamed = NULL;
198245435f71Sjsing 
19836b8b4364Sjsing 	for (i = 1; i < argc; i++) {
19846b8b4364Sjsing 		p = arg = argv[i];
19856b8b4364Sjsing 
198645435f71Sjsing 		/* Single unnamed argument (without leading hyphen). */
19876b8b4364Sjsing 		if (*p++ != '-') {
1988beba0da1Sjsing 			if (argsused != NULL)
1989beba0da1Sjsing 				goto done;
19906b8b4364Sjsing 			if (unnamed == NULL)
19916b8b4364Sjsing 				goto unknown;
199245435f71Sjsing 			if (*unnamed != NULL)
199345435f71Sjsing 				goto toomany;
19946b8b4364Sjsing 			*unnamed = arg;
19956b8b4364Sjsing 			continue;
19966b8b4364Sjsing 		}
199745435f71Sjsing 
1998024f1184Sjsing 		/* End of named options (single hyphen). */
1999024f1184Sjsing 		if (*p == '\0') {
2000024f1184Sjsing 			if (++i >= argc)
2001024f1184Sjsing 				goto done;
2002024f1184Sjsing 			if (argsused != NULL)
2003024f1184Sjsing 				goto done;
2004024f1184Sjsing 			if (unnamed != NULL && i == argc - 1) {
2005024f1184Sjsing 				if (*unnamed != NULL)
2006024f1184Sjsing 					goto toomany;
2007024f1184Sjsing 				*unnamed = argv[i];
2008024f1184Sjsing 				continue;
2009024f1184Sjsing 			}
20106b8b4364Sjsing 			goto unknown;
2011024f1184Sjsing 		}
20126b8b4364Sjsing 
2013b1649c7eSjsing 		/* See if there is a matching option... */
20146b8b4364Sjsing 		for (j = 0; opts[j].name != NULL; j++) {
201573bf9b78Sjsing 			if (strcmp(p, opts[j].name) == 0)
2016620e0cb1Sjsing 				break;
2017620e0cb1Sjsing 		}
201873bf9b78Sjsing 		opt = &opts[j];
2019179b5346Sjsing 		if (opt->name == NULL && opt->type == 0)
2020620e0cb1Sjsing 			goto unknown;
20216b8b4364Sjsing 
2022644a601eSjsing 		if (opt->type == OPTION_ARG ||
20230ee7f8aeSjsing 		    opt->type == OPTION_ARG_FORMAT ||
2024ec4a4065Sjsing 		    opt->type == OPTION_ARG_FUNC ||
2025751065ffSjsing 		    opt->type == OPTION_ARG_INT ||
2026712e3e77Sguenther 		    opt->type == OPTION_ARG_LONG ||
2027712e3e77Sguenther 		    opt->type == OPTION_ARG_TIME) {
20286b8b4364Sjsing 			if (++i >= argc) {
2029620e0cb1Sjsing 				fprintf(stderr, "missing %s argument for -%s\n",
20306b8b4364Sjsing 				    opt->argname, opt->name);
20316b8b4364Sjsing 				return (1);
20326b8b4364Sjsing 			}
2033644a601eSjsing 		}
2034644a601eSjsing 
2035644a601eSjsing 		switch (opt->type) {
2036644a601eSjsing 		case OPTION_ARG:
20376b8b4364Sjsing 			*opt->opt.arg = argv[i];
20386b8b4364Sjsing 			break;
20396b8b4364Sjsing 
2040b1649c7eSjsing 		case OPTION_ARGV_FUNC:
2041b1649c7eSjsing 			if (opt->opt.argvfunc(argc - i, &argv[i], &used) != 0)
2042b1649c7eSjsing 				return (1);
2043b1649c7eSjsing 			i += used - 1;
2044b1649c7eSjsing 			break;
2045b1649c7eSjsing 
20460ee7f8aeSjsing 		case OPTION_ARG_FORMAT:
2047e498f05eSjsing 			fmt = str2fmt(argv[i]);
2048e498f05eSjsing 			if (fmt == FORMAT_UNDEF) {
2049620e0cb1Sjsing 				fprintf(stderr, "unknown %s '%s' for -%s\n",
2050e498f05eSjsing 				    opt->argname, argv[i], opt->name);
2051e498f05eSjsing 				return (1);
2052e498f05eSjsing 			}
2053e498f05eSjsing 			*opt->opt.value = fmt;
20540ee7f8aeSjsing 			break;
20550ee7f8aeSjsing 
2056ec4a4065Sjsing 		case OPTION_ARG_FUNC:
2057d16f2e55Sjsing 			if (opt->opt.argfunc(argv[i]) != 0)
2058ec4a4065Sjsing 				return (1);
2059ec4a4065Sjsing 			break;
2060ec4a4065Sjsing 
2061644a601eSjsing 		case OPTION_ARG_INT:
2062644a601eSjsing 			val = strtonum(argv[i], 0, INT_MAX, &errstr);
2063644a601eSjsing 			if (errstr != NULL) {
2064620e0cb1Sjsing 				fprintf(stderr, "%s %s argument for -%s\n",
2065644a601eSjsing 				    errstr, opt->argname, opt->name);
2066644a601eSjsing 				return (1);
2067644a601eSjsing 			}
2068644a601eSjsing 			*opt->opt.value = (int)val;
2069644a601eSjsing 			break;
2070644a601eSjsing 
2071751065ffSjsing 		case OPTION_ARG_LONG:
2072751065ffSjsing 			val = strtonum(argv[i], 0, LONG_MAX, &errstr);
2073751065ffSjsing 			if (errstr != NULL) {
2074751065ffSjsing 				fprintf(stderr, "%s %s argument for -%s\n",
2075751065ffSjsing 				    errstr, opt->argname, opt->name);
2076751065ffSjsing 				return (1);
2077751065ffSjsing 			}
2078751065ffSjsing 			*opt->opt.lvalue = (long)val;
2079751065ffSjsing 			break;
2080751065ffSjsing 
2081ea1128d8Sderaadt 		case OPTION_ARG_TIME:
2082ea1128d8Sderaadt 			val = strtonum(argv[i], 0, LLONG_MAX, &errstr);
2083ea1128d8Sderaadt 			if (errstr != NULL) {
2084ea1128d8Sderaadt 				fprintf(stderr, "%s %s argument for -%s\n",
2085ea1128d8Sderaadt 				    errstr, opt->argname, opt->name);
2086ea1128d8Sderaadt 				return (1);
2087ea1128d8Sderaadt 			}
2088ea1128d8Sderaadt 			*opt->opt.tvalue = val;
2089ea1128d8Sderaadt 			break;
2090ea1128d8Sderaadt 
20910aaa00e6Sdoug 		case OPTION_DISCARD:
20920aaa00e6Sdoug 			break;
20930aaa00e6Sdoug 
20940c2cbfefSjsing 		case OPTION_FUNC:
2095d16f2e55Sjsing 			if (opt->opt.func() != 0)
20960c2cbfefSjsing 				return (1);
20970c2cbfefSjsing 			break;
20980c2cbfefSjsing 
20996b8b4364Sjsing 		case OPTION_FLAG:
21006b8b4364Sjsing 			*opt->opt.flag = 1;
21016b8b4364Sjsing 			break;
21026b8b4364Sjsing 
2103f9a600f9Sjsing 		case OPTION_FLAG_ORD:
2104f9a600f9Sjsing 			*opt->opt.flag = ++ord;
2105f9a600f9Sjsing 			break;
2106f9a600f9Sjsing 
21076b8b4364Sjsing 		case OPTION_VALUE:
21086b8b4364Sjsing 			*opt->opt.value = opt->value;
21096b8b4364Sjsing 			break;
21106b8b4364Sjsing 
21111cb342c7Sjsing 		case OPTION_VALUE_AND:
21121cb342c7Sjsing 			*opt->opt.value &= opt->value;
21131cb342c7Sjsing 			break;
21141cb342c7Sjsing 
21151cb342c7Sjsing 		case OPTION_VALUE_OR:
21161cb342c7Sjsing 			*opt->opt.value |= opt->value;
21171cb342c7Sjsing 			break;
21181cb342c7Sjsing 
21196fde9eb9Sinoguchi 		case OPTION_UL_VALUE_OR:
21206fde9eb9Sinoguchi 			*opt->opt.ulvalue |= opt->ulvalue;
21216fde9eb9Sinoguchi 			break;
21226fde9eb9Sinoguchi 
2123ac908323Sinoguchi 		case OPTION_ORDER:
2124ac908323Sinoguchi 			*opt->opt.order = ++(*opt->order);
2125ac908323Sinoguchi 			break;
2126ac908323Sinoguchi 
21276b8b4364Sjsing 		default:
2128620e0cb1Sjsing 			fprintf(stderr, "option %s - unknown type %i\n",
21296b8b4364Sjsing 			    opt->name, opt->type);
21306b8b4364Sjsing 			return (1);
21316b8b4364Sjsing 		}
21326b8b4364Sjsing 	}
21336b8b4364Sjsing 
2134beba0da1Sjsing  done:
2135beba0da1Sjsing 	if (argsused != NULL)
2136beba0da1Sjsing 		*argsused = i;
2137beba0da1Sjsing 
21386b8b4364Sjsing 	return (0);
21396b8b4364Sjsing 
214045435f71Sjsing  toomany:
214145435f71Sjsing 	fprintf(stderr, "too many arguments\n");
214245435f71Sjsing 	return (1);
214345435f71Sjsing 
21446b8b4364Sjsing  unknown:
21456b8b4364Sjsing 	fprintf(stderr, "unknown option '%s'\n", arg);
21466b8b4364Sjsing 	return (1);
21476b8b4364Sjsing }
21484071f800Sinoguchi 
21494071f800Sinoguchi void
21504071f800Sinoguchi show_cipher(const OBJ_NAME *name, void *arg)
21514071f800Sinoguchi {
21526685372aSinoguchi 	int *n = arg;
21534071f800Sinoguchi 
21544071f800Sinoguchi 	if (!islower((unsigned char)*name->name))
21554071f800Sinoguchi 		return;
21564071f800Sinoguchi 
21576685372aSinoguchi 	fprintf(stderr, " -%-24s%s", name->name, (++*n % 3 != 0 ? "" : "\n"));
21584071f800Sinoguchi }
2159