xref: /freebsd/crypto/openssl/apps/lib/apps.c (revision ad991e4c142ebabad7aef488ad97b189ecabb270)
1b077aed3SPierre Pronchery /*
2b077aed3SPierre Pronchery  * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
3b077aed3SPierre Pronchery  *
4b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5b077aed3SPierre Pronchery  * this file except in compliance with the License.  You can obtain a copy
6b077aed3SPierre Pronchery  * in the file LICENSE in the source distribution or at
7b077aed3SPierre Pronchery  * https://www.openssl.org/source/license.html
8b077aed3SPierre Pronchery  */
9b077aed3SPierre Pronchery 
10b077aed3SPierre Pronchery #if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS)
11b077aed3SPierre Pronchery /*
12b077aed3SPierre Pronchery  * On VMS, you need to define this to get the declaration of fileno().  The
13b077aed3SPierre Pronchery  * value 2 is to make sure no function defined in POSIX-2 is left undefined.
14b077aed3SPierre Pronchery  */
15b077aed3SPierre Pronchery # define _POSIX_C_SOURCE 2
16b077aed3SPierre Pronchery #endif
17b077aed3SPierre Pronchery 
18b077aed3SPierre Pronchery #ifndef OPENSSL_NO_ENGINE
19b077aed3SPierre Pronchery /* We need to use some deprecated APIs */
20b077aed3SPierre Pronchery # define OPENSSL_SUPPRESS_DEPRECATED
21b077aed3SPierre Pronchery # include <openssl/engine.h>
22b077aed3SPierre Pronchery #endif
23b077aed3SPierre Pronchery 
24b077aed3SPierre Pronchery #include <stdio.h>
25b077aed3SPierre Pronchery #include <stdlib.h>
26b077aed3SPierre Pronchery #include <string.h>
27b077aed3SPierre Pronchery #include <sys/types.h>
28b077aed3SPierre Pronchery #ifndef OPENSSL_NO_POSIX_IO
29b077aed3SPierre Pronchery # include <sys/stat.h>
30b077aed3SPierre Pronchery # include <fcntl.h>
31b077aed3SPierre Pronchery #endif
32b077aed3SPierre Pronchery #include <ctype.h>
33b077aed3SPierre Pronchery #include <errno.h>
34b077aed3SPierre Pronchery #include <openssl/err.h>
35b077aed3SPierre Pronchery #include <openssl/x509.h>
36b077aed3SPierre Pronchery #include <openssl/x509v3.h>
37b077aed3SPierre Pronchery #include <openssl/http.h>
38b077aed3SPierre Pronchery #include <openssl/pem.h>
39b077aed3SPierre Pronchery #include <openssl/store.h>
40b077aed3SPierre Pronchery #include <openssl/pkcs12.h>
41b077aed3SPierre Pronchery #include <openssl/ui.h>
42b077aed3SPierre Pronchery #include <openssl/safestack.h>
43b077aed3SPierre Pronchery #include <openssl/rsa.h>
44b077aed3SPierre Pronchery #include <openssl/rand.h>
45b077aed3SPierre Pronchery #include <openssl/bn.h>
46b077aed3SPierre Pronchery #include <openssl/ssl.h>
47b077aed3SPierre Pronchery #include <openssl/store.h>
48b077aed3SPierre Pronchery #include <openssl/core_names.h>
49b077aed3SPierre Pronchery #include "s_apps.h"
50b077aed3SPierre Pronchery #include "apps.h"
51b077aed3SPierre Pronchery 
52b077aed3SPierre Pronchery #ifdef _WIN32
53b077aed3SPierre Pronchery static int WIN32_rename(const char *from, const char *to);
54b077aed3SPierre Pronchery # define rename(from,to) WIN32_rename((from),(to))
55b077aed3SPierre Pronchery #endif
56b077aed3SPierre Pronchery 
57b077aed3SPierre Pronchery #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS)
58b077aed3SPierre Pronchery # include <conio.h>
59b077aed3SPierre Pronchery #endif
60b077aed3SPierre Pronchery 
61b077aed3SPierre Pronchery #if defined(OPENSSL_SYS_MSDOS) && !defined(_WIN32) || defined(__BORLANDC__)
62b077aed3SPierre Pronchery # define _kbhit kbhit
63b077aed3SPierre Pronchery #endif
64b077aed3SPierre Pronchery 
65b077aed3SPierre Pronchery static BIO *bio_open_default_(const char *filename, char mode, int format,
66b077aed3SPierre Pronchery                               int quiet);
67b077aed3SPierre Pronchery 
68b077aed3SPierre Pronchery #define PASS_SOURCE_SIZE_MAX 4
69b077aed3SPierre Pronchery 
70b077aed3SPierre Pronchery DEFINE_STACK_OF(CONF)
71b077aed3SPierre Pronchery 
72b077aed3SPierre Pronchery typedef struct {
73b077aed3SPierre Pronchery     const char *name;
74b077aed3SPierre Pronchery     unsigned long flag;
75b077aed3SPierre Pronchery     unsigned long mask;
76b077aed3SPierre Pronchery } NAME_EX_TBL;
77b077aed3SPierre Pronchery 
78b077aed3SPierre Pronchery static int set_table_opts(unsigned long *flags, const char *arg,
79b077aed3SPierre Pronchery                           const NAME_EX_TBL * in_tbl);
80b077aed3SPierre Pronchery static int set_multi_opts(unsigned long *flags, const char *arg,
81b077aed3SPierre Pronchery                           const NAME_EX_TBL * in_tbl);
82b077aed3SPierre Pronchery static
83b077aed3SPierre Pronchery int load_key_certs_crls_suppress(const char *uri, int format, int maybe_stdin,
84b077aed3SPierre Pronchery                                  const char *pass, const char *desc,
85b077aed3SPierre Pronchery                                  EVP_PKEY **ppkey, EVP_PKEY **ppubkey,
86b077aed3SPierre Pronchery                                  EVP_PKEY **pparams,
87b077aed3SPierre Pronchery                                  X509 **pcert, STACK_OF(X509) **pcerts,
88b077aed3SPierre Pronchery                                  X509_CRL **pcrl, STACK_OF(X509_CRL) **pcrls,
89b077aed3SPierre Pronchery                                  int suppress_decode_errors);
90b077aed3SPierre Pronchery 
91b077aed3SPierre Pronchery int app_init(long mesgwin);
92b077aed3SPierre Pronchery 
chopup_args(ARGS * arg,char * buf)93b077aed3SPierre Pronchery int chopup_args(ARGS *arg, char *buf)
94b077aed3SPierre Pronchery {
95b077aed3SPierre Pronchery     int quoted;
96b077aed3SPierre Pronchery     char c = '\0', *p = NULL;
97b077aed3SPierre Pronchery 
98b077aed3SPierre Pronchery     arg->argc = 0;
99b077aed3SPierre Pronchery     if (arg->size == 0) {
100b077aed3SPierre Pronchery         arg->size = 20;
101b077aed3SPierre Pronchery         arg->argv = app_malloc(sizeof(*arg->argv) * arg->size, "argv space");
102b077aed3SPierre Pronchery     }
103b077aed3SPierre Pronchery 
104b077aed3SPierre Pronchery     for (p = buf;;) {
105b077aed3SPierre Pronchery         /* Skip whitespace. */
106b077aed3SPierre Pronchery         while (*p && isspace(_UC(*p)))
107b077aed3SPierre Pronchery             p++;
108b077aed3SPierre Pronchery         if (*p == '\0')
109b077aed3SPierre Pronchery             break;
110b077aed3SPierre Pronchery 
111b077aed3SPierre Pronchery         /* The start of something good :-) */
112b077aed3SPierre Pronchery         if (arg->argc >= arg->size) {
113b077aed3SPierre Pronchery             char **tmp;
114b077aed3SPierre Pronchery             arg->size += 20;
115b077aed3SPierre Pronchery             tmp = OPENSSL_realloc(arg->argv, sizeof(*arg->argv) * arg->size);
116b077aed3SPierre Pronchery             if (tmp == NULL)
117b077aed3SPierre Pronchery                 return 0;
118b077aed3SPierre Pronchery             arg->argv = tmp;
119b077aed3SPierre Pronchery         }
120b077aed3SPierre Pronchery         quoted = *p == '\'' || *p == '"';
121b077aed3SPierre Pronchery         if (quoted)
122b077aed3SPierre Pronchery             c = *p++;
123b077aed3SPierre Pronchery         arg->argv[arg->argc++] = p;
124b077aed3SPierre Pronchery 
125b077aed3SPierre Pronchery         /* now look for the end of this */
126b077aed3SPierre Pronchery         if (quoted) {
127b077aed3SPierre Pronchery             while (*p && *p != c)
128b077aed3SPierre Pronchery                 p++;
129b077aed3SPierre Pronchery             *p++ = '\0';
130b077aed3SPierre Pronchery         } else {
131b077aed3SPierre Pronchery             while (*p && !isspace(_UC(*p)))
132b077aed3SPierre Pronchery                 p++;
133b077aed3SPierre Pronchery             if (*p)
134b077aed3SPierre Pronchery                 *p++ = '\0';
135b077aed3SPierre Pronchery         }
136b077aed3SPierre Pronchery     }
137b077aed3SPierre Pronchery     arg->argv[arg->argc] = NULL;
138b077aed3SPierre Pronchery     return 1;
139b077aed3SPierre Pronchery }
140b077aed3SPierre Pronchery 
141b077aed3SPierre Pronchery #ifndef APP_INIT
app_init(long mesgwin)142b077aed3SPierre Pronchery int app_init(long mesgwin)
143b077aed3SPierre Pronchery {
144b077aed3SPierre Pronchery     return 1;
145b077aed3SPierre Pronchery }
146b077aed3SPierre Pronchery #endif
147b077aed3SPierre Pronchery 
ctx_set_verify_locations(SSL_CTX * ctx,const char * CAfile,int noCAfile,const char * CApath,int noCApath,const char * CAstore,int noCAstore)148b077aed3SPierre Pronchery int ctx_set_verify_locations(SSL_CTX *ctx,
149b077aed3SPierre Pronchery                              const char *CAfile, int noCAfile,
150b077aed3SPierre Pronchery                              const char *CApath, int noCApath,
151b077aed3SPierre Pronchery                              const char *CAstore, int noCAstore)
152b077aed3SPierre Pronchery {
153b077aed3SPierre Pronchery     if (CAfile == NULL && CApath == NULL && CAstore == NULL) {
154b077aed3SPierre Pronchery         if (!noCAfile && SSL_CTX_set_default_verify_file(ctx) <= 0)
155b077aed3SPierre Pronchery             return 0;
156b077aed3SPierre Pronchery         if (!noCApath && SSL_CTX_set_default_verify_dir(ctx) <= 0)
157b077aed3SPierre Pronchery             return 0;
158b077aed3SPierre Pronchery         if (!noCAstore && SSL_CTX_set_default_verify_store(ctx) <= 0)
159b077aed3SPierre Pronchery             return 0;
160b077aed3SPierre Pronchery 
161b077aed3SPierre Pronchery         return 1;
162b077aed3SPierre Pronchery     }
163b077aed3SPierre Pronchery 
164b077aed3SPierre Pronchery     if (CAfile != NULL && !SSL_CTX_load_verify_file(ctx, CAfile))
165b077aed3SPierre Pronchery         return 0;
166b077aed3SPierre Pronchery     if (CApath != NULL && !SSL_CTX_load_verify_dir(ctx, CApath))
167b077aed3SPierre Pronchery         return 0;
168b077aed3SPierre Pronchery     if (CAstore != NULL && !SSL_CTX_load_verify_store(ctx, CAstore))
169b077aed3SPierre Pronchery         return 0;
170b077aed3SPierre Pronchery     return 1;
171b077aed3SPierre Pronchery }
172b077aed3SPierre Pronchery 
173b077aed3SPierre Pronchery #ifndef OPENSSL_NO_CT
174b077aed3SPierre Pronchery 
ctx_set_ctlog_list_file(SSL_CTX * ctx,const char * path)175b077aed3SPierre Pronchery int ctx_set_ctlog_list_file(SSL_CTX *ctx, const char *path)
176b077aed3SPierre Pronchery {
177b077aed3SPierre Pronchery     if (path == NULL)
178b077aed3SPierre Pronchery         return SSL_CTX_set_default_ctlog_list_file(ctx);
179b077aed3SPierre Pronchery 
180b077aed3SPierre Pronchery     return SSL_CTX_set_ctlog_list_file(ctx, path);
181b077aed3SPierre Pronchery }
182b077aed3SPierre Pronchery 
183b077aed3SPierre Pronchery #endif
184b077aed3SPierre Pronchery 
185b077aed3SPierre Pronchery static unsigned long nmflag = 0;
186b077aed3SPierre Pronchery static char nmflag_set = 0;
187b077aed3SPierre Pronchery 
set_nameopt(const char * arg)188b077aed3SPierre Pronchery int set_nameopt(const char *arg)
189b077aed3SPierre Pronchery {
190b077aed3SPierre Pronchery     int ret = set_name_ex(&nmflag, arg);
191b077aed3SPierre Pronchery 
192b077aed3SPierre Pronchery     if (ret)
193b077aed3SPierre Pronchery         nmflag_set = 1;
194b077aed3SPierre Pronchery 
195b077aed3SPierre Pronchery     return ret;
196b077aed3SPierre Pronchery }
197b077aed3SPierre Pronchery 
get_nameopt(void)198b077aed3SPierre Pronchery unsigned long get_nameopt(void)
199b077aed3SPierre Pronchery {
200b077aed3SPierre Pronchery     return (nmflag_set) ? nmflag : XN_FLAG_ONELINE;
201b077aed3SPierre Pronchery }
202b077aed3SPierre Pronchery 
dump_cert_text(BIO * out,X509 * x)203b077aed3SPierre Pronchery void dump_cert_text(BIO *out, X509 *x)
204b077aed3SPierre Pronchery {
205b077aed3SPierre Pronchery     print_name(out, "subject=", X509_get_subject_name(x));
206b077aed3SPierre Pronchery     print_name(out, "issuer=", X509_get_issuer_name(x));
207b077aed3SPierre Pronchery }
208b077aed3SPierre Pronchery 
wrap_password_callback(char * buf,int bufsiz,int verify,void * userdata)209b077aed3SPierre Pronchery int wrap_password_callback(char *buf, int bufsiz, int verify, void *userdata)
210b077aed3SPierre Pronchery {
211b077aed3SPierre Pronchery     return password_callback(buf, bufsiz, verify, (PW_CB_DATA *)userdata);
212b077aed3SPierre Pronchery }
213b077aed3SPierre Pronchery 
214b077aed3SPierre Pronchery 
215b077aed3SPierre Pronchery static char *app_get_pass(const char *arg, int keepbio);
216b077aed3SPierre Pronchery 
get_passwd(const char * pass,const char * desc)217b077aed3SPierre Pronchery char *get_passwd(const char *pass, const char *desc)
218b077aed3SPierre Pronchery {
219b077aed3SPierre Pronchery     char *result = NULL;
220b077aed3SPierre Pronchery 
221b077aed3SPierre Pronchery     if (desc == NULL)
222b077aed3SPierre Pronchery         desc = "<unknown>";
223b077aed3SPierre Pronchery     if (!app_passwd(pass, NULL, &result, NULL))
224b077aed3SPierre Pronchery         BIO_printf(bio_err, "Error getting password for %s\n", desc);
225b077aed3SPierre Pronchery     if (pass != NULL && result == NULL) {
226b077aed3SPierre Pronchery         BIO_printf(bio_err,
227b077aed3SPierre Pronchery                    "Trying plain input string (better precede with 'pass:')\n");
228b077aed3SPierre Pronchery         result = OPENSSL_strdup(pass);
229b077aed3SPierre Pronchery         if (result == NULL)
230b077aed3SPierre Pronchery             BIO_printf(bio_err, "Out of memory getting password for %s\n", desc);
231b077aed3SPierre Pronchery     }
232b077aed3SPierre Pronchery     return result;
233b077aed3SPierre Pronchery }
234b077aed3SPierre Pronchery 
app_passwd(const char * arg1,const char * arg2,char ** pass1,char ** pass2)235b077aed3SPierre Pronchery int app_passwd(const char *arg1, const char *arg2, char **pass1, char **pass2)
236b077aed3SPierre Pronchery {
237b077aed3SPierre Pronchery     int same = arg1 != NULL && arg2 != NULL && strcmp(arg1, arg2) == 0;
238b077aed3SPierre Pronchery 
239b077aed3SPierre Pronchery     if (arg1 != NULL) {
240b077aed3SPierre Pronchery         *pass1 = app_get_pass(arg1, same);
241b077aed3SPierre Pronchery         if (*pass1 == NULL)
242b077aed3SPierre Pronchery             return 0;
243b077aed3SPierre Pronchery     } else if (pass1 != NULL) {
244b077aed3SPierre Pronchery         *pass1 = NULL;
245b077aed3SPierre Pronchery     }
246b077aed3SPierre Pronchery     if (arg2 != NULL) {
247b077aed3SPierre Pronchery         *pass2 = app_get_pass(arg2, same ? 2 : 0);
248b077aed3SPierre Pronchery         if (*pass2 == NULL)
249b077aed3SPierre Pronchery             return 0;
250b077aed3SPierre Pronchery     } else if (pass2 != NULL) {
251b077aed3SPierre Pronchery         *pass2 = NULL;
252b077aed3SPierre Pronchery     }
253b077aed3SPierre Pronchery     return 1;
254b077aed3SPierre Pronchery }
255b077aed3SPierre Pronchery 
app_get_pass(const char * arg,int keepbio)256b077aed3SPierre Pronchery static char *app_get_pass(const char *arg, int keepbio)
257b077aed3SPierre Pronchery {
258b077aed3SPierre Pronchery     static BIO *pwdbio = NULL;
259b077aed3SPierre Pronchery     char *tmp, tpass[APP_PASS_LEN];
260b077aed3SPierre Pronchery     int i;
261b077aed3SPierre Pronchery 
262b077aed3SPierre Pronchery     /* PASS_SOURCE_SIZE_MAX = max number of chars before ':' in below strings */
263b077aed3SPierre Pronchery     if (strncmp(arg, "pass:", 5) == 0)
264b077aed3SPierre Pronchery         return OPENSSL_strdup(arg + 5);
265b077aed3SPierre Pronchery     if (strncmp(arg, "env:", 4) == 0) {
266b077aed3SPierre Pronchery         tmp = getenv(arg + 4);
267b077aed3SPierre Pronchery         if (tmp == NULL) {
268b077aed3SPierre Pronchery             BIO_printf(bio_err, "No environment variable %s\n", arg + 4);
269b077aed3SPierre Pronchery             return NULL;
270b077aed3SPierre Pronchery         }
271b077aed3SPierre Pronchery         return OPENSSL_strdup(tmp);
272b077aed3SPierre Pronchery     }
273b077aed3SPierre Pronchery     if (!keepbio || pwdbio == NULL) {
274b077aed3SPierre Pronchery         if (strncmp(arg, "file:", 5) == 0) {
275b077aed3SPierre Pronchery             pwdbio = BIO_new_file(arg + 5, "r");
276b077aed3SPierre Pronchery             if (pwdbio == NULL) {
277b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Can't open file %s\n", arg + 5);
278b077aed3SPierre Pronchery                 return NULL;
279b077aed3SPierre Pronchery             }
280b077aed3SPierre Pronchery #if !defined(_WIN32)
281b077aed3SPierre Pronchery             /*
282b077aed3SPierre Pronchery              * Under _WIN32, which covers even Win64 and CE, file
283b077aed3SPierre Pronchery              * descriptors referenced by BIO_s_fd are not inherited
284b077aed3SPierre Pronchery              * by child process and therefore below is not an option.
285b077aed3SPierre Pronchery              * It could have been an option if bss_fd.c was operating
286b077aed3SPierre Pronchery              * on real Windows descriptors, such as those obtained
287b077aed3SPierre Pronchery              * with CreateFile.
288b077aed3SPierre Pronchery              */
289b077aed3SPierre Pronchery         } else if (strncmp(arg, "fd:", 3) == 0) {
290b077aed3SPierre Pronchery             BIO *btmp;
291b077aed3SPierre Pronchery             i = atoi(arg + 3);
292b077aed3SPierre Pronchery             if (i >= 0)
293b077aed3SPierre Pronchery                 pwdbio = BIO_new_fd(i, BIO_NOCLOSE);
294b077aed3SPierre Pronchery             if ((i < 0) || pwdbio == NULL) {
295b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Can't access file descriptor %s\n", arg + 3);
296b077aed3SPierre Pronchery                 return NULL;
297b077aed3SPierre Pronchery             }
298b077aed3SPierre Pronchery             /*
299b077aed3SPierre Pronchery              * Can't do BIO_gets on an fd BIO so add a buffering BIO
300b077aed3SPierre Pronchery              */
301b077aed3SPierre Pronchery             btmp = BIO_new(BIO_f_buffer());
302b077aed3SPierre Pronchery             if (btmp == NULL) {
303b077aed3SPierre Pronchery                 BIO_free_all(pwdbio);
304b077aed3SPierre Pronchery                 pwdbio = NULL;
305b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Out of memory\n");
306b077aed3SPierre Pronchery                 return NULL;
307b077aed3SPierre Pronchery             }
308b077aed3SPierre Pronchery             pwdbio = BIO_push(btmp, pwdbio);
309b077aed3SPierre Pronchery #endif
310b077aed3SPierre Pronchery         } else if (strcmp(arg, "stdin") == 0) {
311b077aed3SPierre Pronchery             unbuffer(stdin);
312b077aed3SPierre Pronchery             pwdbio = dup_bio_in(FORMAT_TEXT);
313b077aed3SPierre Pronchery             if (pwdbio == NULL) {
314b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Can't open BIO for stdin\n");
315b077aed3SPierre Pronchery                 return NULL;
316b077aed3SPierre Pronchery             }
317b077aed3SPierre Pronchery         } else {
318b077aed3SPierre Pronchery             /* argument syntax error; do not reveal too much about arg */
319b077aed3SPierre Pronchery             tmp = strchr(arg, ':');
320b077aed3SPierre Pronchery             if (tmp == NULL || tmp - arg > PASS_SOURCE_SIZE_MAX)
321b077aed3SPierre Pronchery                 BIO_printf(bio_err,
322b077aed3SPierre Pronchery                            "Invalid password argument, missing ':' within the first %d chars\n",
323b077aed3SPierre Pronchery                            PASS_SOURCE_SIZE_MAX + 1);
324b077aed3SPierre Pronchery             else
325b077aed3SPierre Pronchery                 BIO_printf(bio_err,
326b077aed3SPierre Pronchery                            "Invalid password argument, starting with \"%.*s\"\n",
327b077aed3SPierre Pronchery                            (int)(tmp - arg + 1), arg);
328b077aed3SPierre Pronchery             return NULL;
329b077aed3SPierre Pronchery         }
330b077aed3SPierre Pronchery     }
331b077aed3SPierre Pronchery     i = BIO_gets(pwdbio, tpass, APP_PASS_LEN);
332b077aed3SPierre Pronchery     if (keepbio != 1) {
333b077aed3SPierre Pronchery         BIO_free_all(pwdbio);
334b077aed3SPierre Pronchery         pwdbio = NULL;
335b077aed3SPierre Pronchery     }
336b077aed3SPierre Pronchery     if (i <= 0) {
337b077aed3SPierre Pronchery         BIO_printf(bio_err, "Error reading password from BIO\n");
338b077aed3SPierre Pronchery         return NULL;
339b077aed3SPierre Pronchery     }
340b077aed3SPierre Pronchery     tmp = strchr(tpass, '\n');
341b077aed3SPierre Pronchery     if (tmp != NULL)
342b077aed3SPierre Pronchery         *tmp = 0;
343b077aed3SPierre Pronchery     return OPENSSL_strdup(tpass);
344b077aed3SPierre Pronchery }
345b077aed3SPierre Pronchery 
app_load_config_bio(BIO * in,const char * filename)346b077aed3SPierre Pronchery CONF *app_load_config_bio(BIO *in, const char *filename)
347b077aed3SPierre Pronchery {
348b077aed3SPierre Pronchery     long errorline = -1;
349b077aed3SPierre Pronchery     CONF *conf;
350b077aed3SPierre Pronchery     int i;
351b077aed3SPierre Pronchery 
352b077aed3SPierre Pronchery     conf = NCONF_new_ex(app_get0_libctx(), NULL);
353b077aed3SPierre Pronchery     i = NCONF_load_bio(conf, in, &errorline);
354b077aed3SPierre Pronchery     if (i > 0)
355b077aed3SPierre Pronchery         return conf;
356b077aed3SPierre Pronchery 
357b077aed3SPierre Pronchery     if (errorline <= 0) {
358b077aed3SPierre Pronchery         BIO_printf(bio_err, "%s: Can't load ", opt_getprog());
359b077aed3SPierre Pronchery     } else {
360b077aed3SPierre Pronchery         BIO_printf(bio_err, "%s: Error on line %ld of ", opt_getprog(),
361b077aed3SPierre Pronchery                    errorline);
362b077aed3SPierre Pronchery     }
363b077aed3SPierre Pronchery     if (filename != NULL)
364b077aed3SPierre Pronchery         BIO_printf(bio_err, "config file \"%s\"\n", filename);
365b077aed3SPierre Pronchery     else
366b077aed3SPierre Pronchery         BIO_printf(bio_err, "config input");
367b077aed3SPierre Pronchery 
368b077aed3SPierre Pronchery     NCONF_free(conf);
369b077aed3SPierre Pronchery     return NULL;
370b077aed3SPierre Pronchery }
371b077aed3SPierre Pronchery 
app_load_config_verbose(const char * filename,int verbose)372b077aed3SPierre Pronchery CONF *app_load_config_verbose(const char *filename, int verbose)
373b077aed3SPierre Pronchery {
374b077aed3SPierre Pronchery     if (verbose) {
375b077aed3SPierre Pronchery         if (*filename == '\0')
376b077aed3SPierre Pronchery             BIO_printf(bio_err, "No configuration used\n");
377b077aed3SPierre Pronchery         else
378b077aed3SPierre Pronchery             BIO_printf(bio_err, "Using configuration from %s\n", filename);
379b077aed3SPierre Pronchery     }
380b077aed3SPierre Pronchery     return app_load_config_internal(filename, 0);
381b077aed3SPierre Pronchery }
382b077aed3SPierre Pronchery 
app_load_config_internal(const char * filename,int quiet)383b077aed3SPierre Pronchery CONF *app_load_config_internal(const char *filename, int quiet)
384b077aed3SPierre Pronchery {
385b077aed3SPierre Pronchery     BIO *in;
386b077aed3SPierre Pronchery     CONF *conf;
387b077aed3SPierre Pronchery 
388b077aed3SPierre Pronchery     if (filename == NULL || *filename != '\0') {
389b077aed3SPierre Pronchery         if ((in = bio_open_default_(filename, 'r', FORMAT_TEXT, quiet)) == NULL)
390b077aed3SPierre Pronchery             return NULL;
391b077aed3SPierre Pronchery         conf = app_load_config_bio(in, filename);
392b077aed3SPierre Pronchery         BIO_free(in);
393b077aed3SPierre Pronchery     } else {
394b077aed3SPierre Pronchery         /* Return empty config if filename is empty string. */
395b077aed3SPierre Pronchery         conf = NCONF_new_ex(app_get0_libctx(), NULL);
396b077aed3SPierre Pronchery     }
397b077aed3SPierre Pronchery     return conf;
398b077aed3SPierre Pronchery }
399b077aed3SPierre Pronchery 
app_load_modules(const CONF * config)400b077aed3SPierre Pronchery int app_load_modules(const CONF *config)
401b077aed3SPierre Pronchery {
402b077aed3SPierre Pronchery     CONF *to_free = NULL;
403b077aed3SPierre Pronchery 
404b077aed3SPierre Pronchery     if (config == NULL)
405b077aed3SPierre Pronchery         config = to_free = app_load_config_quiet(default_config_file);
406b077aed3SPierre Pronchery     if (config == NULL)
407b077aed3SPierre Pronchery         return 1;
408b077aed3SPierre Pronchery 
409b077aed3SPierre Pronchery     if (CONF_modules_load(config, NULL, 0) <= 0) {
410b077aed3SPierre Pronchery         BIO_printf(bio_err, "Error configuring OpenSSL modules\n");
411b077aed3SPierre Pronchery         ERR_print_errors(bio_err);
412b077aed3SPierre Pronchery         NCONF_free(to_free);
413b077aed3SPierre Pronchery         return 0;
414b077aed3SPierre Pronchery     }
415b077aed3SPierre Pronchery     NCONF_free(to_free);
416b077aed3SPierre Pronchery     return 1;
417b077aed3SPierre Pronchery }
418b077aed3SPierre Pronchery 
add_oid_section(CONF * conf)419b077aed3SPierre Pronchery int add_oid_section(CONF *conf)
420b077aed3SPierre Pronchery {
421b077aed3SPierre Pronchery     char *p;
422b077aed3SPierre Pronchery     STACK_OF(CONF_VALUE) *sktmp;
423b077aed3SPierre Pronchery     CONF_VALUE *cnf;
424b077aed3SPierre Pronchery     int i;
425b077aed3SPierre Pronchery 
426b077aed3SPierre Pronchery     if ((p = NCONF_get_string(conf, NULL, "oid_section")) == NULL) {
427b077aed3SPierre Pronchery         ERR_clear_error();
428b077aed3SPierre Pronchery         return 1;
429b077aed3SPierre Pronchery     }
430b077aed3SPierre Pronchery     if ((sktmp = NCONF_get_section(conf, p)) == NULL) {
431b077aed3SPierre Pronchery         BIO_printf(bio_err, "problem loading oid section %s\n", p);
432b077aed3SPierre Pronchery         return 0;
433b077aed3SPierre Pronchery     }
434b077aed3SPierre Pronchery     for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
435b077aed3SPierre Pronchery         cnf = sk_CONF_VALUE_value(sktmp, i);
436b077aed3SPierre Pronchery         if (OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) {
437b077aed3SPierre Pronchery             BIO_printf(bio_err, "problem creating object %s=%s\n",
438b077aed3SPierre Pronchery                        cnf->name, cnf->value);
439b077aed3SPierre Pronchery             return 0;
440b077aed3SPierre Pronchery         }
441b077aed3SPierre Pronchery     }
442b077aed3SPierre Pronchery     return 1;
443b077aed3SPierre Pronchery }
444b077aed3SPierre Pronchery 
app_load_config_modules(const char * configfile)445b077aed3SPierre Pronchery CONF *app_load_config_modules(const char *configfile)
446b077aed3SPierre Pronchery {
447b077aed3SPierre Pronchery     CONF *conf = NULL;
448b077aed3SPierre Pronchery 
449b077aed3SPierre Pronchery     if (configfile != NULL) {
450b077aed3SPierre Pronchery         if ((conf = app_load_config_verbose(configfile, 1)) == NULL)
451b077aed3SPierre Pronchery             return NULL;
452b077aed3SPierre Pronchery         if (configfile != default_config_file && !app_load_modules(conf)) {
453b077aed3SPierre Pronchery             NCONF_free(conf);
454b077aed3SPierre Pronchery             conf = NULL;
455b077aed3SPierre Pronchery         }
456b077aed3SPierre Pronchery     }
457b077aed3SPierre Pronchery     return conf;
458b077aed3SPierre Pronchery }
459b077aed3SPierre Pronchery 
460b077aed3SPierre Pronchery #define IS_HTTP(uri) ((uri) != NULL \
461b077aed3SPierre Pronchery         && strncmp(uri, OSSL_HTTP_PREFIX, strlen(OSSL_HTTP_PREFIX)) == 0)
462b077aed3SPierre Pronchery #define IS_HTTPS(uri) ((uri) != NULL \
463b077aed3SPierre Pronchery         && strncmp(uri, OSSL_HTTPS_PREFIX, strlen(OSSL_HTTPS_PREFIX)) == 0)
464b077aed3SPierre Pronchery 
load_cert_pass(const char * uri,int format,int maybe_stdin,const char * pass,const char * desc)465b077aed3SPierre Pronchery X509 *load_cert_pass(const char *uri, int format, int maybe_stdin,
466b077aed3SPierre Pronchery                      const char *pass, const char *desc)
467b077aed3SPierre Pronchery {
468b077aed3SPierre Pronchery     X509 *cert = NULL;
469b077aed3SPierre Pronchery 
470b077aed3SPierre Pronchery     if (desc == NULL)
471b077aed3SPierre Pronchery         desc = "certificate";
472b077aed3SPierre Pronchery     if (IS_HTTPS(uri))
473b077aed3SPierre Pronchery         BIO_printf(bio_err, "Loading %s over HTTPS is unsupported\n", desc);
474b077aed3SPierre Pronchery     else if (IS_HTTP(uri))
475b077aed3SPierre Pronchery         cert = X509_load_http(uri, NULL, NULL, 0 /* timeout */);
476b077aed3SPierre Pronchery     else
477b077aed3SPierre Pronchery         (void)load_key_certs_crls(uri, format, maybe_stdin, pass, desc,
478b077aed3SPierre Pronchery                                   NULL, NULL, NULL, &cert, NULL, NULL, NULL);
479b077aed3SPierre Pronchery     if (cert == NULL) {
480b077aed3SPierre Pronchery         BIO_printf(bio_err, "Unable to load %s\n", desc);
481b077aed3SPierre Pronchery         ERR_print_errors(bio_err);
482b077aed3SPierre Pronchery     }
483b077aed3SPierre Pronchery     return cert;
484b077aed3SPierre Pronchery }
485b077aed3SPierre Pronchery 
load_crl(const char * uri,int format,int maybe_stdin,const char * desc)486b077aed3SPierre Pronchery X509_CRL *load_crl(const char *uri, int format, int maybe_stdin,
487b077aed3SPierre Pronchery                    const char *desc)
488b077aed3SPierre Pronchery {
489b077aed3SPierre Pronchery     X509_CRL *crl = NULL;
490b077aed3SPierre Pronchery 
491b077aed3SPierre Pronchery     if (desc == NULL)
492b077aed3SPierre Pronchery         desc = "CRL";
493b077aed3SPierre Pronchery     if (IS_HTTPS(uri))
494b077aed3SPierre Pronchery         BIO_printf(bio_err, "Loading %s over HTTPS is unsupported\n", desc);
495b077aed3SPierre Pronchery     else if (IS_HTTP(uri))
496b077aed3SPierre Pronchery         crl = X509_CRL_load_http(uri, NULL, NULL, 0 /* timeout */);
497b077aed3SPierre Pronchery     else
498b077aed3SPierre Pronchery         (void)load_key_certs_crls(uri, format, maybe_stdin, NULL, desc,
499b077aed3SPierre Pronchery                                   NULL, NULL,  NULL, NULL, NULL, &crl, NULL);
500b077aed3SPierre Pronchery     if (crl == NULL) {
501b077aed3SPierre Pronchery         BIO_printf(bio_err, "Unable to load %s\n", desc);
502b077aed3SPierre Pronchery         ERR_print_errors(bio_err);
503b077aed3SPierre Pronchery     }
504b077aed3SPierre Pronchery     return crl;
505b077aed3SPierre Pronchery }
506b077aed3SPierre Pronchery 
load_csr(const char * file,int format,const char * desc)507b077aed3SPierre Pronchery X509_REQ *load_csr(const char *file, int format, const char *desc)
508b077aed3SPierre Pronchery {
509b077aed3SPierre Pronchery     X509_REQ *req = NULL;
510b077aed3SPierre Pronchery     BIO *in;
511b077aed3SPierre Pronchery 
512b077aed3SPierre Pronchery     if (format == FORMAT_UNDEF)
513b077aed3SPierre Pronchery         format = FORMAT_PEM;
514b077aed3SPierre Pronchery     if (desc == NULL)
515b077aed3SPierre Pronchery         desc = "CSR";
516b077aed3SPierre Pronchery     in = bio_open_default(file, 'r', format);
517b077aed3SPierre Pronchery     if (in == NULL)
518b077aed3SPierre Pronchery         goto end;
519b077aed3SPierre Pronchery 
520b077aed3SPierre Pronchery     if (format == FORMAT_ASN1)
521b077aed3SPierre Pronchery         req = d2i_X509_REQ_bio(in, NULL);
522b077aed3SPierre Pronchery     else if (format == FORMAT_PEM)
523b077aed3SPierre Pronchery         req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL);
524b077aed3SPierre Pronchery     else
525b077aed3SPierre Pronchery         print_format_error(format, OPT_FMT_PEMDER);
526b077aed3SPierre Pronchery 
527b077aed3SPierre Pronchery  end:
528b077aed3SPierre Pronchery     if (req == NULL) {
529b077aed3SPierre Pronchery         BIO_printf(bio_err, "Unable to load %s\n", desc);
530b077aed3SPierre Pronchery         ERR_print_errors(bio_err);
531b077aed3SPierre Pronchery     }
532b077aed3SPierre Pronchery     BIO_free(in);
533b077aed3SPierre Pronchery     return req;
534b077aed3SPierre Pronchery }
535b077aed3SPierre Pronchery 
cleanse(char * str)536b077aed3SPierre Pronchery void cleanse(char *str)
537b077aed3SPierre Pronchery {
538b077aed3SPierre Pronchery     if (str != NULL)
539b077aed3SPierre Pronchery         OPENSSL_cleanse(str, strlen(str));
540b077aed3SPierre Pronchery }
541b077aed3SPierre Pronchery 
clear_free(char * str)542b077aed3SPierre Pronchery void clear_free(char *str)
543b077aed3SPierre Pronchery {
544b077aed3SPierre Pronchery     if (str != NULL)
545b077aed3SPierre Pronchery         OPENSSL_clear_free(str, strlen(str));
546b077aed3SPierre Pronchery }
547b077aed3SPierre Pronchery 
load_key(const char * uri,int format,int may_stdin,const char * pass,ENGINE * e,const char * desc)548b077aed3SPierre Pronchery EVP_PKEY *load_key(const char *uri, int format, int may_stdin,
549b077aed3SPierre Pronchery                    const char *pass, ENGINE *e, const char *desc)
550b077aed3SPierre Pronchery {
551b077aed3SPierre Pronchery     EVP_PKEY *pkey = NULL;
552b077aed3SPierre Pronchery     char *allocated_uri = NULL;
553b077aed3SPierre Pronchery 
554b077aed3SPierre Pronchery     if (desc == NULL)
555b077aed3SPierre Pronchery         desc = "private key";
556b077aed3SPierre Pronchery 
557b077aed3SPierre Pronchery     if (format == FORMAT_ENGINE) {
558b077aed3SPierre Pronchery         uri = allocated_uri = make_engine_uri(e, uri, desc);
559b077aed3SPierre Pronchery     }
560b077aed3SPierre Pronchery     (void)load_key_certs_crls(uri, format, may_stdin, pass, desc,
561b077aed3SPierre Pronchery                               &pkey, NULL, NULL, NULL, NULL, NULL, NULL);
562b077aed3SPierre Pronchery 
563b077aed3SPierre Pronchery     OPENSSL_free(allocated_uri);
564b077aed3SPierre Pronchery     return pkey;
565b077aed3SPierre Pronchery }
566b077aed3SPierre Pronchery 
load_pubkey(const char * uri,int format,int maybe_stdin,const char * pass,ENGINE * e,const char * desc)567b077aed3SPierre Pronchery EVP_PKEY *load_pubkey(const char *uri, int format, int maybe_stdin,
568b077aed3SPierre Pronchery                       const char *pass, ENGINE *e, const char *desc)
569b077aed3SPierre Pronchery {
570b077aed3SPierre Pronchery     EVP_PKEY *pkey = NULL;
571b077aed3SPierre Pronchery     char *allocated_uri = NULL;
572b077aed3SPierre Pronchery 
573b077aed3SPierre Pronchery     if (desc == NULL)
574b077aed3SPierre Pronchery         desc = "public key";
575b077aed3SPierre Pronchery 
576b077aed3SPierre Pronchery     if (format == FORMAT_ENGINE) {
577b077aed3SPierre Pronchery         uri = allocated_uri = make_engine_uri(e, uri, desc);
578b077aed3SPierre Pronchery     }
579b077aed3SPierre Pronchery     (void)load_key_certs_crls(uri, format, maybe_stdin, pass, desc,
580b077aed3SPierre Pronchery                               NULL, &pkey, NULL, NULL, NULL, NULL, NULL);
581b077aed3SPierre Pronchery 
582b077aed3SPierre Pronchery     OPENSSL_free(allocated_uri);
583b077aed3SPierre Pronchery     return pkey;
584b077aed3SPierre Pronchery }
585b077aed3SPierre Pronchery 
load_keyparams_suppress(const char * uri,int format,int maybe_stdin,const char * keytype,const char * desc,int suppress_decode_errors)586b077aed3SPierre Pronchery EVP_PKEY *load_keyparams_suppress(const char *uri, int format, int maybe_stdin,
587b077aed3SPierre Pronchery                                  const char *keytype, const char *desc,
588b077aed3SPierre Pronchery                                  int suppress_decode_errors)
589b077aed3SPierre Pronchery {
590b077aed3SPierre Pronchery     EVP_PKEY *params = NULL;
591b077aed3SPierre Pronchery 
592b077aed3SPierre Pronchery     if (desc == NULL)
593b077aed3SPierre Pronchery         desc = "key parameters";
594b077aed3SPierre Pronchery 
595b077aed3SPierre Pronchery     (void)load_key_certs_crls_suppress(uri, format, maybe_stdin, NULL, desc,
596b077aed3SPierre Pronchery                                        NULL, NULL, &params, NULL, NULL, NULL,
597b077aed3SPierre Pronchery                                        NULL, suppress_decode_errors);
598b077aed3SPierre Pronchery     if (params != NULL && keytype != NULL && !EVP_PKEY_is_a(params, keytype)) {
599b077aed3SPierre Pronchery         if (!suppress_decode_errors) {
600b077aed3SPierre Pronchery             BIO_printf(bio_err,
601b077aed3SPierre Pronchery                        "Unable to load %s from %s (unexpected parameters type)\n",
602b077aed3SPierre Pronchery                        desc, uri);
603b077aed3SPierre Pronchery             ERR_print_errors(bio_err);
604b077aed3SPierre Pronchery         }
605b077aed3SPierre Pronchery         EVP_PKEY_free(params);
606b077aed3SPierre Pronchery         params = NULL;
607b077aed3SPierre Pronchery     }
608b077aed3SPierre Pronchery     return params;
609b077aed3SPierre Pronchery }
610b077aed3SPierre Pronchery 
load_keyparams(const char * uri,int format,int maybe_stdin,const char * keytype,const char * desc)611b077aed3SPierre Pronchery EVP_PKEY *load_keyparams(const char *uri, int format, int maybe_stdin,
612b077aed3SPierre Pronchery                          const char *keytype, const char *desc)
613b077aed3SPierre Pronchery {
614b077aed3SPierre Pronchery     return load_keyparams_suppress(uri, format, maybe_stdin, keytype, desc, 0);
615b077aed3SPierre Pronchery }
616b077aed3SPierre Pronchery 
app_bail_out(char * fmt,...)617b077aed3SPierre Pronchery void app_bail_out(char *fmt, ...)
618b077aed3SPierre Pronchery {
619b077aed3SPierre Pronchery     va_list args;
620b077aed3SPierre Pronchery 
621b077aed3SPierre Pronchery     va_start(args, fmt);
622b077aed3SPierre Pronchery     BIO_vprintf(bio_err, fmt, args);
623b077aed3SPierre Pronchery     va_end(args);
624b077aed3SPierre Pronchery     ERR_print_errors(bio_err);
625b077aed3SPierre Pronchery     exit(EXIT_FAILURE);
626b077aed3SPierre Pronchery }
627b077aed3SPierre Pronchery 
app_malloc(size_t sz,const char * what)628b077aed3SPierre Pronchery void *app_malloc(size_t sz, const char *what)
629b077aed3SPierre Pronchery {
630b077aed3SPierre Pronchery     void *vp = OPENSSL_malloc(sz);
631b077aed3SPierre Pronchery 
632b077aed3SPierre Pronchery     if (vp == NULL)
633b077aed3SPierre Pronchery         app_bail_out("%s: Could not allocate %zu bytes for %s\n",
634b077aed3SPierre Pronchery                      opt_getprog(), sz, what);
635b077aed3SPierre Pronchery     return vp;
636b077aed3SPierre Pronchery }
637b077aed3SPierre Pronchery 
next_item(char * opt)638b077aed3SPierre Pronchery char *next_item(char *opt) /* in list separated by comma and/or space */
639b077aed3SPierre Pronchery {
640b077aed3SPierre Pronchery     /* advance to separator (comma or whitespace), if any */
641aa795734SPierre Pronchery     while (*opt != ',' && !isspace(_UC(*opt)) && *opt != '\0')
642b077aed3SPierre Pronchery         opt++;
643b077aed3SPierre Pronchery     if (*opt != '\0') {
644b077aed3SPierre Pronchery         /* terminate current item */
645b077aed3SPierre Pronchery         *opt++ = '\0';
646b077aed3SPierre Pronchery         /* skip over any whitespace after separator */
647aa795734SPierre Pronchery         while (isspace(_UC(*opt)))
648b077aed3SPierre Pronchery             opt++;
649b077aed3SPierre Pronchery     }
650b077aed3SPierre Pronchery     return *opt == '\0' ? NULL : opt; /* NULL indicates end of input */
651b077aed3SPierre Pronchery }
652b077aed3SPierre Pronchery 
warn_cert_msg(const char * uri,X509 * cert,const char * msg)653b077aed3SPierre Pronchery static void warn_cert_msg(const char *uri, X509 *cert, const char *msg)
654b077aed3SPierre Pronchery {
655b077aed3SPierre Pronchery     char *subj = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
656b077aed3SPierre Pronchery 
657b077aed3SPierre Pronchery     BIO_printf(bio_err, "Warning: certificate from '%s' with subject '%s' %s\n",
658b077aed3SPierre Pronchery                uri, subj, msg);
659b077aed3SPierre Pronchery     OPENSSL_free(subj);
660b077aed3SPierre Pronchery }
661b077aed3SPierre Pronchery 
warn_cert(const char * uri,X509 * cert,int warn_EE,X509_VERIFY_PARAM * vpm)662b077aed3SPierre Pronchery static void warn_cert(const char *uri, X509 *cert, int warn_EE,
663b077aed3SPierre Pronchery                       X509_VERIFY_PARAM *vpm)
664b077aed3SPierre Pronchery {
665b077aed3SPierre Pronchery     uint32_t ex_flags = X509_get_extension_flags(cert);
666b077aed3SPierre Pronchery     int res = X509_cmp_timeframe(vpm, X509_get0_notBefore(cert),
667b077aed3SPierre Pronchery                                  X509_get0_notAfter(cert));
668b077aed3SPierre Pronchery 
669b077aed3SPierre Pronchery     if (res != 0)
670b077aed3SPierre Pronchery         warn_cert_msg(uri, cert, res > 0 ? "has expired" : "not yet valid");
671b077aed3SPierre Pronchery     if (warn_EE && (ex_flags & EXFLAG_V1) == 0 && (ex_flags & EXFLAG_CA) == 0)
672b077aed3SPierre Pronchery         warn_cert_msg(uri, cert, "is not a CA cert");
673b077aed3SPierre Pronchery }
674b077aed3SPierre Pronchery 
warn_certs(const char * uri,STACK_OF (X509)* certs,int warn_EE,X509_VERIFY_PARAM * vpm)675b077aed3SPierre Pronchery static void warn_certs(const char *uri, STACK_OF(X509) *certs, int warn_EE,
676b077aed3SPierre Pronchery                        X509_VERIFY_PARAM *vpm)
677b077aed3SPierre Pronchery {
678b077aed3SPierre Pronchery     int i;
679b077aed3SPierre Pronchery 
680b077aed3SPierre Pronchery     for (i = 0; i < sk_X509_num(certs); i++)
681b077aed3SPierre Pronchery         warn_cert(uri, sk_X509_value(certs, i), warn_EE, vpm);
682b077aed3SPierre Pronchery }
683b077aed3SPierre Pronchery 
load_cert_certs(const char * uri,X509 ** pcert,STACK_OF (X509)** pcerts,int exclude_http,const char * pass,const char * desc,X509_VERIFY_PARAM * vpm)684b077aed3SPierre Pronchery int load_cert_certs(const char *uri,
685b077aed3SPierre Pronchery                     X509 **pcert, STACK_OF(X509) **pcerts,
686b077aed3SPierre Pronchery                     int exclude_http, const char *pass, const char *desc,
687b077aed3SPierre Pronchery                     X509_VERIFY_PARAM *vpm)
688b077aed3SPierre Pronchery {
689b077aed3SPierre Pronchery     int ret = 0;
690b077aed3SPierre Pronchery     char *pass_string;
691b077aed3SPierre Pronchery 
692b077aed3SPierre Pronchery     if (exclude_http && (OPENSSL_strncasecmp(uri, "http://", 7) == 0
693b077aed3SPierre Pronchery                          || OPENSSL_strncasecmp(uri, "https://", 8) == 0)) {
694b077aed3SPierre Pronchery         BIO_printf(bio_err, "error: HTTP retrieval not allowed for %s\n", desc);
695b077aed3SPierre Pronchery         return ret;
696b077aed3SPierre Pronchery     }
697b077aed3SPierre Pronchery     pass_string = get_passwd(pass, desc);
698b077aed3SPierre Pronchery     ret = load_key_certs_crls(uri, FORMAT_UNDEF, 0, pass_string, desc,
699b077aed3SPierre Pronchery                               NULL, NULL, NULL,
700b077aed3SPierre Pronchery                               pcert, pcerts, NULL, NULL);
701b077aed3SPierre Pronchery     clear_free(pass_string);
702b077aed3SPierre Pronchery 
703b077aed3SPierre Pronchery     if (ret) {
704b077aed3SPierre Pronchery         if (pcert != NULL)
705b077aed3SPierre Pronchery             warn_cert(uri, *pcert, 0, vpm);
706b077aed3SPierre Pronchery         if (pcerts != NULL)
707b077aed3SPierre Pronchery             warn_certs(uri, *pcerts, 1, vpm);
708b077aed3SPierre Pronchery     } else {
709b077aed3SPierre Pronchery         if (pcerts != NULL) {
710b077aed3SPierre Pronchery             sk_X509_pop_free(*pcerts, X509_free);
711b077aed3SPierre Pronchery             *pcerts = NULL;
712b077aed3SPierre Pronchery         }
713b077aed3SPierre Pronchery     }
714b077aed3SPierre Pronchery     return ret;
715b077aed3SPierre Pronchery }
716b077aed3SPierre Pronchery 
STACK_OF(X509)717b077aed3SPierre Pronchery STACK_OF(X509) *load_certs_multifile(char *files, const char *pass,
718b077aed3SPierre Pronchery                                      const char *desc, X509_VERIFY_PARAM *vpm)
719b077aed3SPierre Pronchery {
720b077aed3SPierre Pronchery     STACK_OF(X509) *certs = NULL;
721b077aed3SPierre Pronchery     STACK_OF(X509) *result = sk_X509_new_null();
722b077aed3SPierre Pronchery 
723b077aed3SPierre Pronchery     if (files == NULL)
724b077aed3SPierre Pronchery         goto err;
725b077aed3SPierre Pronchery     if (result == NULL)
726b077aed3SPierre Pronchery         goto oom;
727b077aed3SPierre Pronchery 
728b077aed3SPierre Pronchery     while (files != NULL) {
729b077aed3SPierre Pronchery         char *next = next_item(files);
730b077aed3SPierre Pronchery 
731b077aed3SPierre Pronchery         if (!load_cert_certs(files, NULL, &certs, 0, pass, desc, vpm))
732b077aed3SPierre Pronchery             goto err;
733b077aed3SPierre Pronchery         if (!X509_add_certs(result, certs,
734b077aed3SPierre Pronchery                             X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP))
735b077aed3SPierre Pronchery             goto oom;
736b077aed3SPierre Pronchery         sk_X509_pop_free(certs, X509_free);
737b077aed3SPierre Pronchery         certs = NULL;
738b077aed3SPierre Pronchery         files = next;
739b077aed3SPierre Pronchery     }
740b077aed3SPierre Pronchery     return result;
741b077aed3SPierre Pronchery 
742b077aed3SPierre Pronchery  oom:
743b077aed3SPierre Pronchery     BIO_printf(bio_err, "out of memory\n");
744b077aed3SPierre Pronchery  err:
745b077aed3SPierre Pronchery     sk_X509_pop_free(certs, X509_free);
746b077aed3SPierre Pronchery     sk_X509_pop_free(result, X509_free);
747b077aed3SPierre Pronchery     return NULL;
748b077aed3SPierre Pronchery }
749b077aed3SPierre Pronchery 
sk_X509_to_store(X509_STORE * store,const STACK_OF (X509)* certs)750b077aed3SPierre Pronchery static X509_STORE *sk_X509_to_store(X509_STORE *store /* may be NULL */,
751b077aed3SPierre Pronchery                                     const STACK_OF(X509) *certs /* may NULL */)
752b077aed3SPierre Pronchery {
753b077aed3SPierre Pronchery     int i;
754b077aed3SPierre Pronchery 
755b077aed3SPierre Pronchery     if (store == NULL)
756b077aed3SPierre Pronchery         store = X509_STORE_new();
757b077aed3SPierre Pronchery     if (store == NULL)
758b077aed3SPierre Pronchery         return NULL;
759b077aed3SPierre Pronchery     for (i = 0; i < sk_X509_num(certs); i++) {
760b077aed3SPierre Pronchery         if (!X509_STORE_add_cert(store, sk_X509_value(certs, i))) {
761b077aed3SPierre Pronchery             X509_STORE_free(store);
762b077aed3SPierre Pronchery             return NULL;
763b077aed3SPierre Pronchery         }
764b077aed3SPierre Pronchery     }
765b077aed3SPierre Pronchery     return store;
766b077aed3SPierre Pronchery }
767b077aed3SPierre Pronchery 
768b077aed3SPierre Pronchery /*
769b077aed3SPierre Pronchery  * Create cert store structure with certificates read from given file(s).
770b077aed3SPierre Pronchery  * Returns pointer to created X509_STORE on success, NULL on error.
771b077aed3SPierre Pronchery  */
load_certstore(char * input,const char * pass,const char * desc,X509_VERIFY_PARAM * vpm)772b077aed3SPierre Pronchery X509_STORE *load_certstore(char *input, const char *pass, const char *desc,
773b077aed3SPierre Pronchery                            X509_VERIFY_PARAM *vpm)
774b077aed3SPierre Pronchery {
775b077aed3SPierre Pronchery     X509_STORE *store = NULL;
776b077aed3SPierre Pronchery     STACK_OF(X509) *certs = NULL;
777b077aed3SPierre Pronchery 
778b077aed3SPierre Pronchery     while (input != NULL) {
779b077aed3SPierre Pronchery         char *next = next_item(input);
780b077aed3SPierre Pronchery         int ok;
781b077aed3SPierre Pronchery 
782b077aed3SPierre Pronchery         if (!load_cert_certs(input, NULL, &certs, 1, pass, desc, vpm)) {
783b077aed3SPierre Pronchery             X509_STORE_free(store);
784b077aed3SPierre Pronchery             return NULL;
785b077aed3SPierre Pronchery         }
786b077aed3SPierre Pronchery         ok = (store = sk_X509_to_store(store, certs)) != NULL;
787b077aed3SPierre Pronchery         sk_X509_pop_free(certs, X509_free);
788b077aed3SPierre Pronchery         certs = NULL;
789b077aed3SPierre Pronchery         if (!ok)
790b077aed3SPierre Pronchery             return NULL;
791b077aed3SPierre Pronchery         input = next;
792b077aed3SPierre Pronchery     }
793b077aed3SPierre Pronchery     return store;
794b077aed3SPierre Pronchery }
795b077aed3SPierre Pronchery 
796b077aed3SPierre Pronchery /*
797b077aed3SPierre Pronchery  * Initialize or extend, if *certs != NULL, a certificate stack.
798b077aed3SPierre Pronchery  * The caller is responsible for freeing *certs if its value is left not NULL.
799b077aed3SPierre Pronchery  */
load_certs(const char * uri,int maybe_stdin,STACK_OF (X509)** certs,const char * pass,const char * desc)800b077aed3SPierre Pronchery int load_certs(const char *uri, int maybe_stdin, STACK_OF(X509) **certs,
801b077aed3SPierre Pronchery                const char *pass, const char *desc)
802b077aed3SPierre Pronchery {
803b077aed3SPierre Pronchery     int was_NULL = *certs == NULL;
804b077aed3SPierre Pronchery     int ret = load_key_certs_crls(uri, FORMAT_UNDEF, maybe_stdin,
805b077aed3SPierre Pronchery                                   pass, desc, NULL, NULL,
806b077aed3SPierre Pronchery                                   NULL, NULL, certs, NULL, NULL);
807b077aed3SPierre Pronchery 
808b077aed3SPierre Pronchery     if (!ret && was_NULL) {
809b077aed3SPierre Pronchery         sk_X509_pop_free(*certs, X509_free);
810b077aed3SPierre Pronchery         *certs = NULL;
811b077aed3SPierre Pronchery     }
812b077aed3SPierre Pronchery     return ret;
813b077aed3SPierre Pronchery }
814b077aed3SPierre Pronchery 
815b077aed3SPierre Pronchery /*
816b077aed3SPierre Pronchery  * Initialize or extend, if *crls != NULL, a certificate stack.
817b077aed3SPierre Pronchery  * The caller is responsible for freeing *crls if its value is left not NULL.
818b077aed3SPierre Pronchery  */
load_crls(const char * uri,STACK_OF (X509_CRL)** crls,const char * pass,const char * desc)819b077aed3SPierre Pronchery int load_crls(const char *uri, STACK_OF(X509_CRL) **crls,
820b077aed3SPierre Pronchery               const char *pass, const char *desc)
821b077aed3SPierre Pronchery {
822b077aed3SPierre Pronchery     int was_NULL = *crls == NULL;
823b077aed3SPierre Pronchery     int ret = load_key_certs_crls(uri, FORMAT_UNDEF, 0, pass, desc,
824b077aed3SPierre Pronchery                                   NULL, NULL, NULL,
825b077aed3SPierre Pronchery                                   NULL, NULL, NULL, crls);
826b077aed3SPierre Pronchery 
827b077aed3SPierre Pronchery     if (!ret && was_NULL) {
828b077aed3SPierre Pronchery         sk_X509_CRL_pop_free(*crls, X509_CRL_free);
829b077aed3SPierre Pronchery         *crls = NULL;
830b077aed3SPierre Pronchery     }
831b077aed3SPierre Pronchery     return ret;
832b077aed3SPierre Pronchery }
833b077aed3SPierre Pronchery 
format2string(int format)834b077aed3SPierre Pronchery static const char *format2string(int format)
835b077aed3SPierre Pronchery {
836b077aed3SPierre Pronchery     switch(format) {
837b077aed3SPierre Pronchery     case FORMAT_PEM:
838b077aed3SPierre Pronchery         return "PEM";
839b077aed3SPierre Pronchery     case FORMAT_ASN1:
840b077aed3SPierre Pronchery         return "DER";
841b077aed3SPierre Pronchery     }
842b077aed3SPierre Pronchery     return NULL;
843b077aed3SPierre Pronchery }
844b077aed3SPierre Pronchery 
845b077aed3SPierre Pronchery /* Set type expectation, but clear it if objects of different types expected. */
846b077aed3SPierre Pronchery #define SET_EXPECT(expect, val) ((expect) = (expect) < 0 ? (val) : ((expect) == (val) ? (val) : 0))
847b077aed3SPierre Pronchery /*
848b077aed3SPierre Pronchery  * Load those types of credentials for which the result pointer is not NULL.
849b077aed3SPierre Pronchery  * Reads from stdio if uri is NULL and maybe_stdin is nonzero.
850b077aed3SPierre Pronchery  * For non-NULL ppkey, pcert, and pcrl the first suitable value found is loaded.
851b077aed3SPierre Pronchery  * If pcerts is non-NULL and *pcerts == NULL then a new cert list is allocated.
852b077aed3SPierre Pronchery  * If pcerts is non-NULL then all available certificates are appended to *pcerts
853b077aed3SPierre Pronchery  * except any certificate assigned to *pcert.
854b077aed3SPierre Pronchery  * If pcrls is non-NULL and *pcrls == NULL then a new list of CRLs is allocated.
855b077aed3SPierre Pronchery  * If pcrls is non-NULL then all available CRLs are appended to *pcerts
856b077aed3SPierre Pronchery  * except any CRL assigned to *pcrl.
857b077aed3SPierre Pronchery  * In any case (also on error) the caller is responsible for freeing all members
858b077aed3SPierre Pronchery  * of *pcerts and *pcrls (as far as they are not NULL).
859b077aed3SPierre Pronchery  */
860b077aed3SPierre Pronchery static
load_key_certs_crls_suppress(const char * uri,int format,int maybe_stdin,const char * pass,const char * desc,EVP_PKEY ** ppkey,EVP_PKEY ** ppubkey,EVP_PKEY ** pparams,X509 ** pcert,STACK_OF (X509)** pcerts,X509_CRL ** pcrl,STACK_OF (X509_CRL)** pcrls,int suppress_decode_errors)861b077aed3SPierre Pronchery int load_key_certs_crls_suppress(const char *uri, int format, int maybe_stdin,
862b077aed3SPierre Pronchery                                  const char *pass, const char *desc,
863b077aed3SPierre Pronchery                                  EVP_PKEY **ppkey, EVP_PKEY **ppubkey,
864b077aed3SPierre Pronchery                                  EVP_PKEY **pparams,
865b077aed3SPierre Pronchery                                  X509 **pcert, STACK_OF(X509) **pcerts,
866b077aed3SPierre Pronchery                                  X509_CRL **pcrl, STACK_OF(X509_CRL) **pcrls,
867b077aed3SPierre Pronchery                                  int suppress_decode_errors)
868b077aed3SPierre Pronchery {
869b077aed3SPierre Pronchery     PW_CB_DATA uidata;
870b077aed3SPierre Pronchery     OSSL_STORE_CTX *ctx = NULL;
871b077aed3SPierre Pronchery     OSSL_LIB_CTX *libctx = app_get0_libctx();
872b077aed3SPierre Pronchery     const char *propq = app_get0_propq();
873b077aed3SPierre Pronchery     int ncerts = 0;
874b077aed3SPierre Pronchery     int ncrls = 0;
875b077aed3SPierre Pronchery     const char *failed =
876b077aed3SPierre Pronchery         ppkey != NULL ? "key" : ppubkey != NULL ? "public key" :
877b077aed3SPierre Pronchery         pparams != NULL ? "params" : pcert != NULL ? "cert" :
878b077aed3SPierre Pronchery         pcrl != NULL ? "CRL" : pcerts != NULL ? "certs" :
879b077aed3SPierre Pronchery         pcrls != NULL ? "CRLs" : NULL;
880b077aed3SPierre Pronchery     int cnt_expectations = 0;
881b077aed3SPierre Pronchery     int expect = -1;
882b077aed3SPierre Pronchery     const char *input_type;
883b077aed3SPierre Pronchery     OSSL_PARAM itp[2];
884b077aed3SPierre Pronchery     const OSSL_PARAM *params = NULL;
885b077aed3SPierre Pronchery 
886b077aed3SPierre Pronchery     if (ppkey != NULL) {
887b077aed3SPierre Pronchery         *ppkey = NULL;
888b077aed3SPierre Pronchery         cnt_expectations++;
889b077aed3SPierre Pronchery         SET_EXPECT(expect, OSSL_STORE_INFO_PKEY);
890b077aed3SPierre Pronchery     }
891b077aed3SPierre Pronchery     if (ppubkey != NULL) {
892b077aed3SPierre Pronchery         *ppubkey = NULL;
893b077aed3SPierre Pronchery         cnt_expectations++;
894b077aed3SPierre Pronchery         SET_EXPECT(expect, OSSL_STORE_INFO_PUBKEY);
895b077aed3SPierre Pronchery     }
896b077aed3SPierre Pronchery     if (pparams != NULL) {
897b077aed3SPierre Pronchery         *pparams = NULL;
898b077aed3SPierre Pronchery         cnt_expectations++;
899b077aed3SPierre Pronchery         SET_EXPECT(expect, OSSL_STORE_INFO_PARAMS);
900b077aed3SPierre Pronchery     }
901b077aed3SPierre Pronchery     if (pcert != NULL) {
902b077aed3SPierre Pronchery         *pcert = NULL;
903b077aed3SPierre Pronchery         cnt_expectations++;
904b077aed3SPierre Pronchery         SET_EXPECT(expect, OSSL_STORE_INFO_CERT);
905b077aed3SPierre Pronchery     }
906b077aed3SPierre Pronchery     if (pcerts != NULL) {
907b077aed3SPierre Pronchery         if (*pcerts == NULL && (*pcerts = sk_X509_new_null()) == NULL) {
908b077aed3SPierre Pronchery             BIO_printf(bio_err, "Out of memory loading");
909b077aed3SPierre Pronchery             goto end;
910b077aed3SPierre Pronchery         }
911b077aed3SPierre Pronchery         cnt_expectations++;
912b077aed3SPierre Pronchery         SET_EXPECT(expect, OSSL_STORE_INFO_CERT);
913b077aed3SPierre Pronchery     }
914b077aed3SPierre Pronchery     if (pcrl != NULL) {
915b077aed3SPierre Pronchery         *pcrl = NULL;
916b077aed3SPierre Pronchery         cnt_expectations++;
917b077aed3SPierre Pronchery         SET_EXPECT(expect, OSSL_STORE_INFO_CRL);
918b077aed3SPierre Pronchery     }
919b077aed3SPierre Pronchery     if (pcrls != NULL) {
920b077aed3SPierre Pronchery         if (*pcrls == NULL && (*pcrls = sk_X509_CRL_new_null()) == NULL) {
921b077aed3SPierre Pronchery             BIO_printf(bio_err, "Out of memory loading");
922b077aed3SPierre Pronchery             goto end;
923b077aed3SPierre Pronchery         }
924b077aed3SPierre Pronchery         cnt_expectations++;
925b077aed3SPierre Pronchery         SET_EXPECT(expect, OSSL_STORE_INFO_CRL);
926b077aed3SPierre Pronchery     }
927b077aed3SPierre Pronchery     if (cnt_expectations == 0) {
928b077aed3SPierre Pronchery         BIO_printf(bio_err, "Internal error: nothing to load from %s\n",
929b077aed3SPierre Pronchery                    uri != NULL ? uri : "<stdin>");
930b077aed3SPierre Pronchery         return 0;
931b077aed3SPierre Pronchery     }
932b077aed3SPierre Pronchery 
933b077aed3SPierre Pronchery     uidata.password = pass;
934b077aed3SPierre Pronchery     uidata.prompt_info = uri;
935b077aed3SPierre Pronchery 
936b077aed3SPierre Pronchery     if ((input_type = format2string(format)) != NULL) {
937b077aed3SPierre Pronchery        itp[0] = OSSL_PARAM_construct_utf8_string(OSSL_STORE_PARAM_INPUT_TYPE,
938b077aed3SPierre Pronchery                                                  (char *)input_type, 0);
939b077aed3SPierre Pronchery        itp[1] = OSSL_PARAM_construct_end();
940b077aed3SPierre Pronchery        params = itp;
941b077aed3SPierre Pronchery     }
942b077aed3SPierre Pronchery 
943b077aed3SPierre Pronchery     if (uri == NULL) {
944b077aed3SPierre Pronchery         BIO *bio;
945b077aed3SPierre Pronchery 
946b077aed3SPierre Pronchery         if (!maybe_stdin) {
9476f1af0d7SPierre Pronchery             BIO_printf(bio_err, "No filename or uri specified for loading\n");
948b077aed3SPierre Pronchery             goto end;
949b077aed3SPierre Pronchery         }
950b077aed3SPierre Pronchery         uri = "<stdin>";
951b077aed3SPierre Pronchery         unbuffer(stdin);
952b077aed3SPierre Pronchery         bio = BIO_new_fp(stdin, 0);
953b077aed3SPierre Pronchery         if (bio != NULL) {
954b077aed3SPierre Pronchery             ctx = OSSL_STORE_attach(bio, "file", libctx, propq,
955b077aed3SPierre Pronchery                                     get_ui_method(), &uidata, params,
956b077aed3SPierre Pronchery                                     NULL, NULL);
957b077aed3SPierre Pronchery             BIO_free(bio);
958b077aed3SPierre Pronchery         }
959b077aed3SPierre Pronchery     } else {
960b077aed3SPierre Pronchery         ctx = OSSL_STORE_open_ex(uri, libctx, propq, get_ui_method(), &uidata,
961b077aed3SPierre Pronchery                                  params, NULL, NULL);
962b077aed3SPierre Pronchery     }
963*ad991e4cSEd Maste     if (ctx == NULL) {
964*ad991e4cSEd Maste         BIO_printf(bio_err, "Could not open file or uri for loading");
965b077aed3SPierre Pronchery         goto end;
966*ad991e4cSEd Maste     }
967*ad991e4cSEd Maste     if (expect > 0 && !OSSL_STORE_expect(ctx, expect)) {
968*ad991e4cSEd Maste         BIO_printf(bio_err, "Internal error trying to load");
969b077aed3SPierre Pronchery         goto end;
970*ad991e4cSEd Maste     }
971b077aed3SPierre Pronchery 
972b077aed3SPierre Pronchery     failed = NULL;
973b077aed3SPierre Pronchery     while (cnt_expectations > 0 && !OSSL_STORE_eof(ctx)) {
974b077aed3SPierre Pronchery         OSSL_STORE_INFO *info = OSSL_STORE_load(ctx);
975b077aed3SPierre Pronchery         int type, ok = 1;
976b077aed3SPierre Pronchery 
977b077aed3SPierre Pronchery         /*
978b077aed3SPierre Pronchery          * This can happen (for example) if we attempt to load a file with
979b077aed3SPierre Pronchery          * multiple different types of things in it - but the thing we just
980b077aed3SPierre Pronchery          * tried to load wasn't one of the ones we wanted, e.g. if we're trying
981b077aed3SPierre Pronchery          * to load a certificate but the file has both the private key and the
982b077aed3SPierre Pronchery          * certificate in it. We just retry until eof.
983b077aed3SPierre Pronchery          */
984b077aed3SPierre Pronchery         if (info == NULL) {
985b077aed3SPierre Pronchery             continue;
986b077aed3SPierre Pronchery         }
987b077aed3SPierre Pronchery 
988b077aed3SPierre Pronchery         type = OSSL_STORE_INFO_get_type(info);
989b077aed3SPierre Pronchery         switch (type) {
990b077aed3SPierre Pronchery         case OSSL_STORE_INFO_PKEY:
991b077aed3SPierre Pronchery             if (ppkey != NULL && *ppkey == NULL) {
992b077aed3SPierre Pronchery                 ok = (*ppkey = OSSL_STORE_INFO_get1_PKEY(info)) != NULL;
993b077aed3SPierre Pronchery                 cnt_expectations -= ok;
994b077aed3SPierre Pronchery             }
995b077aed3SPierre Pronchery             /*
996b077aed3SPierre Pronchery              * An EVP_PKEY with private parts also holds the public parts,
997b077aed3SPierre Pronchery              * so if the caller asked for a public key, and we got a private
998b077aed3SPierre Pronchery              * key, we can still pass it back.
999b077aed3SPierre Pronchery              */
1000b077aed3SPierre Pronchery             if (ok && ppubkey != NULL && *ppubkey == NULL) {
1001b077aed3SPierre Pronchery                 ok = ((*ppubkey = OSSL_STORE_INFO_get1_PKEY(info)) != NULL);
1002b077aed3SPierre Pronchery                 cnt_expectations -= ok;
1003b077aed3SPierre Pronchery             }
1004b077aed3SPierre Pronchery             break;
1005b077aed3SPierre Pronchery         case OSSL_STORE_INFO_PUBKEY:
1006b077aed3SPierre Pronchery             if (ppubkey != NULL && *ppubkey == NULL) {
1007b077aed3SPierre Pronchery                 ok = ((*ppubkey = OSSL_STORE_INFO_get1_PUBKEY(info)) != NULL);
1008b077aed3SPierre Pronchery                 cnt_expectations -= ok;
1009b077aed3SPierre Pronchery             }
1010b077aed3SPierre Pronchery             break;
1011b077aed3SPierre Pronchery         case OSSL_STORE_INFO_PARAMS:
1012b077aed3SPierre Pronchery             if (pparams != NULL && *pparams == NULL) {
1013b077aed3SPierre Pronchery                 ok = ((*pparams = OSSL_STORE_INFO_get1_PARAMS(info)) != NULL);
1014b077aed3SPierre Pronchery                 cnt_expectations -= ok;
1015b077aed3SPierre Pronchery             }
1016b077aed3SPierre Pronchery             break;
1017b077aed3SPierre Pronchery         case OSSL_STORE_INFO_CERT:
1018b077aed3SPierre Pronchery             if (pcert != NULL && *pcert == NULL) {
1019b077aed3SPierre Pronchery                 ok = (*pcert = OSSL_STORE_INFO_get1_CERT(info)) != NULL;
1020b077aed3SPierre Pronchery                 cnt_expectations -= ok;
1021b077aed3SPierre Pronchery             }
1022b077aed3SPierre Pronchery             else if (pcerts != NULL)
1023b077aed3SPierre Pronchery                 ok = X509_add_cert(*pcerts,
1024b077aed3SPierre Pronchery                                    OSSL_STORE_INFO_get1_CERT(info),
1025b077aed3SPierre Pronchery                                    X509_ADD_FLAG_DEFAULT);
1026b077aed3SPierre Pronchery             ncerts += ok;
1027b077aed3SPierre Pronchery             break;
1028b077aed3SPierre Pronchery         case OSSL_STORE_INFO_CRL:
1029b077aed3SPierre Pronchery             if (pcrl != NULL && *pcrl == NULL) {
1030b077aed3SPierre Pronchery                 ok = (*pcrl = OSSL_STORE_INFO_get1_CRL(info)) != NULL;
1031b077aed3SPierre Pronchery                 cnt_expectations -= ok;
1032b077aed3SPierre Pronchery             }
1033b077aed3SPierre Pronchery             else if (pcrls != NULL)
1034b077aed3SPierre Pronchery                 ok = sk_X509_CRL_push(*pcrls, OSSL_STORE_INFO_get1_CRL(info));
1035b077aed3SPierre Pronchery             ncrls += ok;
1036b077aed3SPierre Pronchery             break;
1037b077aed3SPierre Pronchery         default:
1038b077aed3SPierre Pronchery             /* skip any other type */
1039b077aed3SPierre Pronchery             break;
1040b077aed3SPierre Pronchery         }
1041b077aed3SPierre Pronchery         OSSL_STORE_INFO_free(info);
1042b077aed3SPierre Pronchery         if (!ok) {
1043b077aed3SPierre Pronchery             failed = info == NULL ? NULL : OSSL_STORE_INFO_type_string(type);
1044b077aed3SPierre Pronchery             BIO_printf(bio_err, "Error reading");
1045b077aed3SPierre Pronchery             break;
1046b077aed3SPierre Pronchery         }
1047b077aed3SPierre Pronchery     }
1048b077aed3SPierre Pronchery 
1049b077aed3SPierre Pronchery  end:
1050b077aed3SPierre Pronchery     OSSL_STORE_close(ctx);
1051b077aed3SPierre Pronchery     if (failed == NULL) {
1052b077aed3SPierre Pronchery         int any = 0;
1053b077aed3SPierre Pronchery 
1054b077aed3SPierre Pronchery         if ((ppkey != NULL && *ppkey == NULL)
1055b077aed3SPierre Pronchery             || (ppubkey != NULL && *ppubkey == NULL)) {
1056b077aed3SPierre Pronchery             failed = "key";
1057b077aed3SPierre Pronchery         } else if (pparams != NULL && *pparams == NULL) {
1058b077aed3SPierre Pronchery             failed = "params";
1059b077aed3SPierre Pronchery         } else if ((pcert != NULL || pcerts != NULL) && ncerts == 0) {
1060b077aed3SPierre Pronchery             if (pcert == NULL)
1061b077aed3SPierre Pronchery                 any = 1;
1062b077aed3SPierre Pronchery             failed = "cert";
1063b077aed3SPierre Pronchery         } else if ((pcrl != NULL || pcrls != NULL) && ncrls == 0) {
1064b077aed3SPierre Pronchery             if (pcrl == NULL)
1065b077aed3SPierre Pronchery                 any = 1;
1066b077aed3SPierre Pronchery             failed = "CRL";
1067b077aed3SPierre Pronchery         }
1068b077aed3SPierre Pronchery         if (!suppress_decode_errors) {
1069b077aed3SPierre Pronchery             if (failed != NULL)
1070b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Could not read");
1071b077aed3SPierre Pronchery             if (any)
1072b077aed3SPierre Pronchery                 BIO_printf(bio_err, " any");
1073b077aed3SPierre Pronchery         }
1074b077aed3SPierre Pronchery     }
1075b077aed3SPierre Pronchery     if (!suppress_decode_errors && failed != NULL) {
1076b077aed3SPierre Pronchery         if (desc != NULL && strstr(desc, failed) != NULL) {
1077b077aed3SPierre Pronchery             BIO_printf(bio_err, " %s", desc);
1078b077aed3SPierre Pronchery         } else {
1079b077aed3SPierre Pronchery             BIO_printf(bio_err, " %s", failed);
1080b077aed3SPierre Pronchery             if (desc != NULL)
1081b077aed3SPierre Pronchery                 BIO_printf(bio_err, " of %s", desc);
1082b077aed3SPierre Pronchery         }
1083b077aed3SPierre Pronchery         if (uri != NULL)
1084b077aed3SPierre Pronchery             BIO_printf(bio_err, " from %s", uri);
1085b077aed3SPierre Pronchery         BIO_printf(bio_err, "\n");
1086b077aed3SPierre Pronchery         ERR_print_errors(bio_err);
1087b077aed3SPierre Pronchery     }
1088b077aed3SPierre Pronchery     if (suppress_decode_errors || failed == NULL)
1089b077aed3SPierre Pronchery         /* clear any spurious errors */
1090b077aed3SPierre Pronchery         ERR_clear_error();
1091b077aed3SPierre Pronchery     return failed == NULL;
1092b077aed3SPierre Pronchery }
1093b077aed3SPierre Pronchery 
load_key_certs_crls(const char * uri,int format,int maybe_stdin,const char * pass,const char * desc,EVP_PKEY ** ppkey,EVP_PKEY ** ppubkey,EVP_PKEY ** pparams,X509 ** pcert,STACK_OF (X509)** pcerts,X509_CRL ** pcrl,STACK_OF (X509_CRL)** pcrls)1094b077aed3SPierre Pronchery int load_key_certs_crls(const char *uri, int format, int maybe_stdin,
1095b077aed3SPierre Pronchery                         const char *pass, const char *desc,
1096b077aed3SPierre Pronchery                         EVP_PKEY **ppkey, EVP_PKEY **ppubkey,
1097b077aed3SPierre Pronchery                         EVP_PKEY **pparams,
1098b077aed3SPierre Pronchery                         X509 **pcert, STACK_OF(X509) **pcerts,
1099b077aed3SPierre Pronchery                         X509_CRL **pcrl, STACK_OF(X509_CRL) **pcrls)
1100b077aed3SPierre Pronchery {
1101b077aed3SPierre Pronchery     return load_key_certs_crls_suppress(uri, format, maybe_stdin, pass, desc,
1102b077aed3SPierre Pronchery                                         ppkey, ppubkey, pparams, pcert, pcerts,
1103b077aed3SPierre Pronchery                                         pcrl, pcrls, 0);
1104b077aed3SPierre Pronchery }
1105b077aed3SPierre Pronchery 
1106b077aed3SPierre Pronchery #define X509V3_EXT_UNKNOWN_MASK         (0xfL << 16)
1107b077aed3SPierre Pronchery /* Return error for unknown extensions */
1108b077aed3SPierre Pronchery #define X509V3_EXT_DEFAULT              0
1109b077aed3SPierre Pronchery /* Print error for unknown extensions */
1110b077aed3SPierre Pronchery #define X509V3_EXT_ERROR_UNKNOWN        (1L << 16)
1111b077aed3SPierre Pronchery /* ASN1 parse unknown extensions */
1112b077aed3SPierre Pronchery #define X509V3_EXT_PARSE_UNKNOWN        (2L << 16)
1113b077aed3SPierre Pronchery /* BIO_dump unknown extensions */
1114b077aed3SPierre Pronchery #define X509V3_EXT_DUMP_UNKNOWN         (3L << 16)
1115b077aed3SPierre Pronchery 
1116b077aed3SPierre Pronchery #define X509_FLAG_CA (X509_FLAG_NO_ISSUER | X509_FLAG_NO_PUBKEY | \
1117b077aed3SPierre Pronchery                          X509_FLAG_NO_HEADER | X509_FLAG_NO_VERSION)
1118b077aed3SPierre Pronchery 
set_cert_ex(unsigned long * flags,const char * arg)1119b077aed3SPierre Pronchery int set_cert_ex(unsigned long *flags, const char *arg)
1120b077aed3SPierre Pronchery {
1121b077aed3SPierre Pronchery     static const NAME_EX_TBL cert_tbl[] = {
1122b077aed3SPierre Pronchery         {"compatible", X509_FLAG_COMPAT, 0xffffffffl},
1123b077aed3SPierre Pronchery         {"ca_default", X509_FLAG_CA, 0xffffffffl},
1124b077aed3SPierre Pronchery         {"no_header", X509_FLAG_NO_HEADER, 0},
1125b077aed3SPierre Pronchery         {"no_version", X509_FLAG_NO_VERSION, 0},
1126b077aed3SPierre Pronchery         {"no_serial", X509_FLAG_NO_SERIAL, 0},
1127b077aed3SPierre Pronchery         {"no_signame", X509_FLAG_NO_SIGNAME, 0},
1128b077aed3SPierre Pronchery         {"no_validity", X509_FLAG_NO_VALIDITY, 0},
1129b077aed3SPierre Pronchery         {"no_subject", X509_FLAG_NO_SUBJECT, 0},
1130b077aed3SPierre Pronchery         {"no_issuer", X509_FLAG_NO_ISSUER, 0},
1131b077aed3SPierre Pronchery         {"no_pubkey", X509_FLAG_NO_PUBKEY, 0},
1132b077aed3SPierre Pronchery         {"no_extensions", X509_FLAG_NO_EXTENSIONS, 0},
1133b077aed3SPierre Pronchery         {"no_sigdump", X509_FLAG_NO_SIGDUMP, 0},
1134b077aed3SPierre Pronchery         {"no_aux", X509_FLAG_NO_AUX, 0},
1135b077aed3SPierre Pronchery         {"no_attributes", X509_FLAG_NO_ATTRIBUTES, 0},
1136b077aed3SPierre Pronchery         {"ext_default", X509V3_EXT_DEFAULT, X509V3_EXT_UNKNOWN_MASK},
1137b077aed3SPierre Pronchery         {"ext_error", X509V3_EXT_ERROR_UNKNOWN, X509V3_EXT_UNKNOWN_MASK},
1138b077aed3SPierre Pronchery         {"ext_parse", X509V3_EXT_PARSE_UNKNOWN, X509V3_EXT_UNKNOWN_MASK},
1139b077aed3SPierre Pronchery         {"ext_dump", X509V3_EXT_DUMP_UNKNOWN, X509V3_EXT_UNKNOWN_MASK},
1140b077aed3SPierre Pronchery         {NULL, 0, 0}
1141b077aed3SPierre Pronchery     };
1142b077aed3SPierre Pronchery     return set_multi_opts(flags, arg, cert_tbl);
1143b077aed3SPierre Pronchery }
1144b077aed3SPierre Pronchery 
set_name_ex(unsigned long * flags,const char * arg)1145b077aed3SPierre Pronchery int set_name_ex(unsigned long *flags, const char *arg)
1146b077aed3SPierre Pronchery {
1147b077aed3SPierre Pronchery     static const NAME_EX_TBL ex_tbl[] = {
1148b077aed3SPierre Pronchery         {"esc_2253", ASN1_STRFLGS_ESC_2253, 0},
1149b077aed3SPierre Pronchery         {"esc_2254", ASN1_STRFLGS_ESC_2254, 0},
1150b077aed3SPierre Pronchery         {"esc_ctrl", ASN1_STRFLGS_ESC_CTRL, 0},
1151b077aed3SPierre Pronchery         {"esc_msb", ASN1_STRFLGS_ESC_MSB, 0},
1152b077aed3SPierre Pronchery         {"use_quote", ASN1_STRFLGS_ESC_QUOTE, 0},
1153b077aed3SPierre Pronchery         {"utf8", ASN1_STRFLGS_UTF8_CONVERT, 0},
1154b077aed3SPierre Pronchery         {"ignore_type", ASN1_STRFLGS_IGNORE_TYPE, 0},
1155b077aed3SPierre Pronchery         {"show_type", ASN1_STRFLGS_SHOW_TYPE, 0},
1156b077aed3SPierre Pronchery         {"dump_all", ASN1_STRFLGS_DUMP_ALL, 0},
1157b077aed3SPierre Pronchery         {"dump_nostr", ASN1_STRFLGS_DUMP_UNKNOWN, 0},
1158b077aed3SPierre Pronchery         {"dump_der", ASN1_STRFLGS_DUMP_DER, 0},
1159b077aed3SPierre Pronchery         {"compat", XN_FLAG_COMPAT, 0xffffffffL},
1160b077aed3SPierre Pronchery         {"sep_comma_plus", XN_FLAG_SEP_COMMA_PLUS, XN_FLAG_SEP_MASK},
1161b077aed3SPierre Pronchery         {"sep_comma_plus_space", XN_FLAG_SEP_CPLUS_SPC, XN_FLAG_SEP_MASK},
1162b077aed3SPierre Pronchery         {"sep_semi_plus_space", XN_FLAG_SEP_SPLUS_SPC, XN_FLAG_SEP_MASK},
1163b077aed3SPierre Pronchery         {"sep_multiline", XN_FLAG_SEP_MULTILINE, XN_FLAG_SEP_MASK},
1164b077aed3SPierre Pronchery         {"dn_rev", XN_FLAG_DN_REV, 0},
1165b077aed3SPierre Pronchery         {"nofname", XN_FLAG_FN_NONE, XN_FLAG_FN_MASK},
1166b077aed3SPierre Pronchery         {"sname", XN_FLAG_FN_SN, XN_FLAG_FN_MASK},
1167b077aed3SPierre Pronchery         {"lname", XN_FLAG_FN_LN, XN_FLAG_FN_MASK},
1168b077aed3SPierre Pronchery         {"align", XN_FLAG_FN_ALIGN, 0},
1169b077aed3SPierre Pronchery         {"oid", XN_FLAG_FN_OID, XN_FLAG_FN_MASK},
1170b077aed3SPierre Pronchery         {"space_eq", XN_FLAG_SPC_EQ, 0},
1171b077aed3SPierre Pronchery         {"dump_unknown", XN_FLAG_DUMP_UNKNOWN_FIELDS, 0},
1172b077aed3SPierre Pronchery         {"RFC2253", XN_FLAG_RFC2253, 0xffffffffL},
1173b077aed3SPierre Pronchery         {"oneline", XN_FLAG_ONELINE, 0xffffffffL},
1174b077aed3SPierre Pronchery         {"multiline", XN_FLAG_MULTILINE, 0xffffffffL},
1175b077aed3SPierre Pronchery         {"ca_default", XN_FLAG_MULTILINE, 0xffffffffL},
1176b077aed3SPierre Pronchery         {NULL, 0, 0}
1177b077aed3SPierre Pronchery     };
1178b077aed3SPierre Pronchery     if (set_multi_opts(flags, arg, ex_tbl) == 0)
1179b077aed3SPierre Pronchery         return 0;
1180b077aed3SPierre Pronchery     if (*flags != XN_FLAG_COMPAT
1181b077aed3SPierre Pronchery         && (*flags & XN_FLAG_SEP_MASK) == 0)
1182b077aed3SPierre Pronchery         *flags |= XN_FLAG_SEP_CPLUS_SPC;
1183b077aed3SPierre Pronchery     return 1;
1184b077aed3SPierre Pronchery }
1185b077aed3SPierre Pronchery 
set_dateopt(unsigned long * dateopt,const char * arg)1186b077aed3SPierre Pronchery int set_dateopt(unsigned long *dateopt, const char *arg)
1187b077aed3SPierre Pronchery {
1188b077aed3SPierre Pronchery     if (OPENSSL_strcasecmp(arg, "rfc_822") == 0)
1189b077aed3SPierre Pronchery         *dateopt = ASN1_DTFLGS_RFC822;
1190b077aed3SPierre Pronchery     else if (OPENSSL_strcasecmp(arg, "iso_8601") == 0)
1191b077aed3SPierre Pronchery         *dateopt = ASN1_DTFLGS_ISO8601;
1192b077aed3SPierre Pronchery     else
1193b077aed3SPierre Pronchery         return 0;
1194b077aed3SPierre Pronchery     return 1;
1195b077aed3SPierre Pronchery }
1196b077aed3SPierre Pronchery 
set_ext_copy(int * copy_type,const char * arg)1197b077aed3SPierre Pronchery int set_ext_copy(int *copy_type, const char *arg)
1198b077aed3SPierre Pronchery {
1199b077aed3SPierre Pronchery     if (OPENSSL_strcasecmp(arg, "none") == 0)
1200b077aed3SPierre Pronchery         *copy_type = EXT_COPY_NONE;
1201b077aed3SPierre Pronchery     else if (OPENSSL_strcasecmp(arg, "copy") == 0)
1202b077aed3SPierre Pronchery         *copy_type = EXT_COPY_ADD;
1203b077aed3SPierre Pronchery     else if (OPENSSL_strcasecmp(arg, "copyall") == 0)
1204b077aed3SPierre Pronchery         *copy_type = EXT_COPY_ALL;
1205b077aed3SPierre Pronchery     else
1206b077aed3SPierre Pronchery         return 0;
1207b077aed3SPierre Pronchery     return 1;
1208b077aed3SPierre Pronchery }
1209b077aed3SPierre Pronchery 
copy_extensions(X509 * x,X509_REQ * req,int copy_type)1210b077aed3SPierre Pronchery int copy_extensions(X509 *x, X509_REQ *req, int copy_type)
1211b077aed3SPierre Pronchery {
1212b077aed3SPierre Pronchery     STACK_OF(X509_EXTENSION) *exts;
1213b077aed3SPierre Pronchery     int i, ret = 0;
1214b077aed3SPierre Pronchery 
1215b077aed3SPierre Pronchery     if (x == NULL || req == NULL)
1216b077aed3SPierre Pronchery         return 0;
1217b077aed3SPierre Pronchery     if (copy_type == EXT_COPY_NONE)
1218b077aed3SPierre Pronchery         return 1;
1219b077aed3SPierre Pronchery     exts = X509_REQ_get_extensions(req);
1220b077aed3SPierre Pronchery 
1221b077aed3SPierre Pronchery     for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
1222b077aed3SPierre Pronchery         X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
1223b077aed3SPierre Pronchery         ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext);
1224b077aed3SPierre Pronchery         int idx = X509_get_ext_by_OBJ(x, obj, -1);
1225b077aed3SPierre Pronchery 
1226b077aed3SPierre Pronchery         /* Does extension exist in target? */
1227b077aed3SPierre Pronchery         if (idx != -1) {
1228b077aed3SPierre Pronchery             /* If normal copy don't override existing extension */
1229b077aed3SPierre Pronchery             if (copy_type == EXT_COPY_ADD)
1230b077aed3SPierre Pronchery                 continue;
1231b077aed3SPierre Pronchery             /* Delete all extensions of same type */
1232b077aed3SPierre Pronchery             do {
1233b077aed3SPierre Pronchery                 X509_EXTENSION_free(X509_delete_ext(x, idx));
1234b077aed3SPierre Pronchery                 idx = X509_get_ext_by_OBJ(x, obj, -1);
1235b077aed3SPierre Pronchery             } while (idx != -1);
1236b077aed3SPierre Pronchery         }
1237b077aed3SPierre Pronchery         if (!X509_add_ext(x, ext, -1))
1238b077aed3SPierre Pronchery             goto end;
1239b077aed3SPierre Pronchery     }
1240b077aed3SPierre Pronchery     ret = 1;
1241b077aed3SPierre Pronchery 
1242b077aed3SPierre Pronchery  end:
1243b077aed3SPierre Pronchery     sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
1244b077aed3SPierre Pronchery     return ret;
1245b077aed3SPierre Pronchery }
1246b077aed3SPierre Pronchery 
set_multi_opts(unsigned long * flags,const char * arg,const NAME_EX_TBL * in_tbl)1247b077aed3SPierre Pronchery static int set_multi_opts(unsigned long *flags, const char *arg,
1248b077aed3SPierre Pronchery                           const NAME_EX_TBL * in_tbl)
1249b077aed3SPierre Pronchery {
1250b077aed3SPierre Pronchery     STACK_OF(CONF_VALUE) *vals;
1251b077aed3SPierre Pronchery     CONF_VALUE *val;
1252b077aed3SPierre Pronchery     int i, ret = 1;
1253b077aed3SPierre Pronchery     if (!arg)
1254b077aed3SPierre Pronchery         return 0;
1255b077aed3SPierre Pronchery     vals = X509V3_parse_list(arg);
1256b077aed3SPierre Pronchery     for (i = 0; i < sk_CONF_VALUE_num(vals); i++) {
1257b077aed3SPierre Pronchery         val = sk_CONF_VALUE_value(vals, i);
1258b077aed3SPierre Pronchery         if (!set_table_opts(flags, val->name, in_tbl))
1259b077aed3SPierre Pronchery             ret = 0;
1260b077aed3SPierre Pronchery     }
1261b077aed3SPierre Pronchery     sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
1262b077aed3SPierre Pronchery     return ret;
1263b077aed3SPierre Pronchery }
1264b077aed3SPierre Pronchery 
set_table_opts(unsigned long * flags,const char * arg,const NAME_EX_TBL * in_tbl)1265b077aed3SPierre Pronchery static int set_table_opts(unsigned long *flags, const char *arg,
1266b077aed3SPierre Pronchery                           const NAME_EX_TBL * in_tbl)
1267b077aed3SPierre Pronchery {
1268b077aed3SPierre Pronchery     char c;
1269b077aed3SPierre Pronchery     const NAME_EX_TBL *ptbl;
1270b077aed3SPierre Pronchery     c = arg[0];
1271b077aed3SPierre Pronchery 
1272b077aed3SPierre Pronchery     if (c == '-') {
1273b077aed3SPierre Pronchery         c = 0;
1274b077aed3SPierre Pronchery         arg++;
1275b077aed3SPierre Pronchery     } else if (c == '+') {
1276b077aed3SPierre Pronchery         c = 1;
1277b077aed3SPierre Pronchery         arg++;
1278b077aed3SPierre Pronchery     } else {
1279b077aed3SPierre Pronchery         c = 1;
1280b077aed3SPierre Pronchery     }
1281b077aed3SPierre Pronchery 
1282b077aed3SPierre Pronchery     for (ptbl = in_tbl; ptbl->name; ptbl++) {
1283b077aed3SPierre Pronchery         if (OPENSSL_strcasecmp(arg, ptbl->name) == 0) {
1284b077aed3SPierre Pronchery             *flags &= ~ptbl->mask;
1285b077aed3SPierre Pronchery             if (c)
1286b077aed3SPierre Pronchery                 *flags |= ptbl->flag;
1287b077aed3SPierre Pronchery             else
1288b077aed3SPierre Pronchery                 *flags &= ~ptbl->flag;
1289b077aed3SPierre Pronchery             return 1;
1290b077aed3SPierre Pronchery         }
1291b077aed3SPierre Pronchery     }
1292b077aed3SPierre Pronchery     return 0;
1293b077aed3SPierre Pronchery }
1294b077aed3SPierre Pronchery 
print_name(BIO * out,const char * title,const X509_NAME * nm)1295b077aed3SPierre Pronchery void print_name(BIO *out, const char *title, const X509_NAME *nm)
1296b077aed3SPierre Pronchery {
1297b077aed3SPierre Pronchery     char *buf;
1298b077aed3SPierre Pronchery     char mline = 0;
1299b077aed3SPierre Pronchery     int indent = 0;
1300b077aed3SPierre Pronchery     unsigned long lflags = get_nameopt();
1301b077aed3SPierre Pronchery 
1302b077aed3SPierre Pronchery     if (out == NULL)
1303b077aed3SPierre Pronchery         return;
1304b077aed3SPierre Pronchery     if (title != NULL)
1305b077aed3SPierre Pronchery         BIO_puts(out, title);
1306b077aed3SPierre Pronchery     if ((lflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) {
1307b077aed3SPierre Pronchery         mline = 1;
1308b077aed3SPierre Pronchery         indent = 4;
1309b077aed3SPierre Pronchery     }
1310b077aed3SPierre Pronchery     if (lflags == XN_FLAG_COMPAT) {
1311b077aed3SPierre Pronchery         buf = X509_NAME_oneline(nm, 0, 0);
1312b077aed3SPierre Pronchery         BIO_puts(out, buf);
1313b077aed3SPierre Pronchery         BIO_puts(out, "\n");
1314b077aed3SPierre Pronchery         OPENSSL_free(buf);
1315b077aed3SPierre Pronchery     } else {
1316b077aed3SPierre Pronchery         if (mline)
1317b077aed3SPierre Pronchery             BIO_puts(out, "\n");
1318b077aed3SPierre Pronchery         X509_NAME_print_ex(out, nm, indent, lflags);
1319b077aed3SPierre Pronchery         BIO_puts(out, "\n");
1320b077aed3SPierre Pronchery     }
1321b077aed3SPierre Pronchery }
1322b077aed3SPierre Pronchery 
print_bignum_var(BIO * out,const BIGNUM * in,const char * var,int len,unsigned char * buffer)1323b077aed3SPierre Pronchery void print_bignum_var(BIO *out, const BIGNUM *in, const char *var,
1324b077aed3SPierre Pronchery                       int len, unsigned char *buffer)
1325b077aed3SPierre Pronchery {
1326b077aed3SPierre Pronchery     BIO_printf(out, "    static unsigned char %s_%d[] = {", var, len);
1327b077aed3SPierre Pronchery     if (BN_is_zero(in)) {
1328b077aed3SPierre Pronchery         BIO_printf(out, "\n        0x00");
1329b077aed3SPierre Pronchery     } else {
1330b077aed3SPierre Pronchery         int i, l;
1331b077aed3SPierre Pronchery 
1332b077aed3SPierre Pronchery         l = BN_bn2bin(in, buffer);
1333b077aed3SPierre Pronchery         for (i = 0; i < l; i++) {
1334b077aed3SPierre Pronchery             BIO_printf(out, (i % 10) == 0 ? "\n        " : " ");
1335b077aed3SPierre Pronchery             if (i < l - 1)
1336b077aed3SPierre Pronchery                 BIO_printf(out, "0x%02X,", buffer[i]);
1337b077aed3SPierre Pronchery             else
1338b077aed3SPierre Pronchery                 BIO_printf(out, "0x%02X", buffer[i]);
1339b077aed3SPierre Pronchery         }
1340b077aed3SPierre Pronchery     }
1341b077aed3SPierre Pronchery     BIO_printf(out, "\n    };\n");
1342b077aed3SPierre Pronchery }
1343b077aed3SPierre Pronchery 
print_array(BIO * out,const char * title,int len,const unsigned char * d)1344b077aed3SPierre Pronchery void print_array(BIO *out, const char* title, int len, const unsigned char* d)
1345b077aed3SPierre Pronchery {
1346b077aed3SPierre Pronchery     int i;
1347b077aed3SPierre Pronchery 
1348b077aed3SPierre Pronchery     BIO_printf(out, "unsigned char %s[%d] = {", title, len);
1349b077aed3SPierre Pronchery     for (i = 0; i < len; i++) {
1350b077aed3SPierre Pronchery         if ((i % 10) == 0)
1351b077aed3SPierre Pronchery             BIO_printf(out, "\n    ");
1352b077aed3SPierre Pronchery         if (i < len - 1)
1353b077aed3SPierre Pronchery             BIO_printf(out, "0x%02X, ", d[i]);
1354b077aed3SPierre Pronchery         else
1355b077aed3SPierre Pronchery             BIO_printf(out, "0x%02X", d[i]);
1356b077aed3SPierre Pronchery     }
1357b077aed3SPierre Pronchery     BIO_printf(out, "\n};\n");
1358b077aed3SPierre Pronchery }
1359b077aed3SPierre Pronchery 
setup_verify(const char * CAfile,int noCAfile,const char * CApath,int noCApath,const char * CAstore,int noCAstore)1360b077aed3SPierre Pronchery X509_STORE *setup_verify(const char *CAfile, int noCAfile,
1361b077aed3SPierre Pronchery                          const char *CApath, int noCApath,
1362b077aed3SPierre Pronchery                          const char *CAstore, int noCAstore)
1363b077aed3SPierre Pronchery {
1364b077aed3SPierre Pronchery     X509_STORE *store = X509_STORE_new();
1365b077aed3SPierre Pronchery     X509_LOOKUP *lookup;
1366b077aed3SPierre Pronchery     OSSL_LIB_CTX *libctx = app_get0_libctx();
1367b077aed3SPierre Pronchery     const char *propq = app_get0_propq();
1368b077aed3SPierre Pronchery 
1369b077aed3SPierre Pronchery     if (store == NULL)
1370b077aed3SPierre Pronchery         goto end;
1371b077aed3SPierre Pronchery 
1372b077aed3SPierre Pronchery     if (CAfile != NULL || !noCAfile) {
1373b077aed3SPierre Pronchery         lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
1374b077aed3SPierre Pronchery         if (lookup == NULL)
1375b077aed3SPierre Pronchery             goto end;
1376b077aed3SPierre Pronchery         if (CAfile != NULL) {
1377b077aed3SPierre Pronchery             if (X509_LOOKUP_load_file_ex(lookup, CAfile, X509_FILETYPE_PEM,
1378b077aed3SPierre Pronchery                                           libctx, propq) <= 0) {
1379b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Error loading file %s\n", CAfile);
1380b077aed3SPierre Pronchery                 goto end;
1381b077aed3SPierre Pronchery             }
1382b077aed3SPierre Pronchery         } else {
1383b077aed3SPierre Pronchery             X509_LOOKUP_load_file_ex(lookup, NULL, X509_FILETYPE_DEFAULT,
1384b077aed3SPierre Pronchery                                      libctx, propq);
1385b077aed3SPierre Pronchery         }
1386b077aed3SPierre Pronchery     }
1387b077aed3SPierre Pronchery 
1388b077aed3SPierre Pronchery     if (CApath != NULL || !noCApath) {
1389b077aed3SPierre Pronchery         lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
1390b077aed3SPierre Pronchery         if (lookup == NULL)
1391b077aed3SPierre Pronchery             goto end;
1392b077aed3SPierre Pronchery         if (CApath != NULL) {
1393b077aed3SPierre Pronchery             if (X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM) <= 0) {
1394b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Error loading directory %s\n", CApath);
1395b077aed3SPierre Pronchery                 goto end;
1396b077aed3SPierre Pronchery             }
1397b077aed3SPierre Pronchery         } else {
1398b077aed3SPierre Pronchery             X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
1399b077aed3SPierre Pronchery         }
1400b077aed3SPierre Pronchery     }
1401b077aed3SPierre Pronchery 
1402b077aed3SPierre Pronchery     if (CAstore != NULL || !noCAstore) {
1403b077aed3SPierre Pronchery         lookup = X509_STORE_add_lookup(store, X509_LOOKUP_store());
1404b077aed3SPierre Pronchery         if (lookup == NULL)
1405b077aed3SPierre Pronchery             goto end;
1406b077aed3SPierre Pronchery         if (!X509_LOOKUP_add_store_ex(lookup, CAstore, libctx, propq)) {
1407b077aed3SPierre Pronchery             if (CAstore != NULL)
1408b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Error loading store URI %s\n", CAstore);
1409b077aed3SPierre Pronchery             goto end;
1410b077aed3SPierre Pronchery         }
1411b077aed3SPierre Pronchery     }
1412b077aed3SPierre Pronchery 
1413b077aed3SPierre Pronchery     ERR_clear_error();
1414b077aed3SPierre Pronchery     return store;
1415b077aed3SPierre Pronchery  end:
1416b077aed3SPierre Pronchery     ERR_print_errors(bio_err);
1417b077aed3SPierre Pronchery     X509_STORE_free(store);
1418b077aed3SPierre Pronchery     return NULL;
1419b077aed3SPierre Pronchery }
1420b077aed3SPierre Pronchery 
index_serial_hash(const OPENSSL_CSTRING * a)1421b077aed3SPierre Pronchery static unsigned long index_serial_hash(const OPENSSL_CSTRING *a)
1422b077aed3SPierre Pronchery {
1423b077aed3SPierre Pronchery     const char *n;
1424b077aed3SPierre Pronchery 
1425b077aed3SPierre Pronchery     n = a[DB_serial];
1426b077aed3SPierre Pronchery     while (*n == '0')
1427b077aed3SPierre Pronchery         n++;
1428b077aed3SPierre Pronchery     return OPENSSL_LH_strhash(n);
1429b077aed3SPierre Pronchery }
1430b077aed3SPierre Pronchery 
index_serial_cmp(const OPENSSL_CSTRING * a,const OPENSSL_CSTRING * b)1431b077aed3SPierre Pronchery static int index_serial_cmp(const OPENSSL_CSTRING *a,
1432b077aed3SPierre Pronchery                             const OPENSSL_CSTRING *b)
1433b077aed3SPierre Pronchery {
1434b077aed3SPierre Pronchery     const char *aa, *bb;
1435b077aed3SPierre Pronchery 
1436b077aed3SPierre Pronchery     for (aa = a[DB_serial]; *aa == '0'; aa++) ;
1437b077aed3SPierre Pronchery     for (bb = b[DB_serial]; *bb == '0'; bb++) ;
1438b077aed3SPierre Pronchery     return strcmp(aa, bb);
1439b077aed3SPierre Pronchery }
1440b077aed3SPierre Pronchery 
index_name_qual(char ** a)1441b077aed3SPierre Pronchery static int index_name_qual(char **a)
1442b077aed3SPierre Pronchery {
1443b077aed3SPierre Pronchery     return (a[0][0] == 'V');
1444b077aed3SPierre Pronchery }
1445b077aed3SPierre Pronchery 
index_name_hash(const OPENSSL_CSTRING * a)1446b077aed3SPierre Pronchery static unsigned long index_name_hash(const OPENSSL_CSTRING *a)
1447b077aed3SPierre Pronchery {
1448b077aed3SPierre Pronchery     return OPENSSL_LH_strhash(a[DB_name]);
1449b077aed3SPierre Pronchery }
1450b077aed3SPierre Pronchery 
index_name_cmp(const OPENSSL_CSTRING * a,const OPENSSL_CSTRING * b)1451b077aed3SPierre Pronchery int index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b)
1452b077aed3SPierre Pronchery {
1453b077aed3SPierre Pronchery     return strcmp(a[DB_name], b[DB_name]);
1454b077aed3SPierre Pronchery }
1455b077aed3SPierre Pronchery 
IMPLEMENT_LHASH_HASH_FN(index_serial,OPENSSL_CSTRING)1456b077aed3SPierre Pronchery static IMPLEMENT_LHASH_HASH_FN(index_serial, OPENSSL_CSTRING)
1457b077aed3SPierre Pronchery static IMPLEMENT_LHASH_COMP_FN(index_serial, OPENSSL_CSTRING)
1458b077aed3SPierre Pronchery static IMPLEMENT_LHASH_HASH_FN(index_name, OPENSSL_CSTRING)
1459b077aed3SPierre Pronchery static IMPLEMENT_LHASH_COMP_FN(index_name, OPENSSL_CSTRING)
1460b077aed3SPierre Pronchery #undef BSIZE
1461b077aed3SPierre Pronchery #define BSIZE 256
1462b077aed3SPierre Pronchery BIGNUM *load_serial(const char *serialfile, int *exists, int create,
1463b077aed3SPierre Pronchery                     ASN1_INTEGER **retai)
1464b077aed3SPierre Pronchery {
1465b077aed3SPierre Pronchery     BIO *in = NULL;
1466b077aed3SPierre Pronchery     BIGNUM *ret = NULL;
1467b077aed3SPierre Pronchery     char buf[1024];
1468b077aed3SPierre Pronchery     ASN1_INTEGER *ai = NULL;
1469b077aed3SPierre Pronchery 
1470b077aed3SPierre Pronchery     ai = ASN1_INTEGER_new();
1471b077aed3SPierre Pronchery     if (ai == NULL)
1472b077aed3SPierre Pronchery         goto err;
1473b077aed3SPierre Pronchery 
1474b077aed3SPierre Pronchery     in = BIO_new_file(serialfile, "r");
1475b077aed3SPierre Pronchery     if (exists != NULL)
1476b077aed3SPierre Pronchery         *exists = in != NULL;
1477b077aed3SPierre Pronchery     if (in == NULL) {
1478b077aed3SPierre Pronchery         if (!create) {
1479b077aed3SPierre Pronchery             perror(serialfile);
1480b077aed3SPierre Pronchery             goto err;
1481b077aed3SPierre Pronchery         }
1482b077aed3SPierre Pronchery         ERR_clear_error();
1483b077aed3SPierre Pronchery         ret = BN_new();
1484b077aed3SPierre Pronchery         if (ret == NULL) {
1485b077aed3SPierre Pronchery             BIO_printf(bio_err, "Out of memory\n");
1486b077aed3SPierre Pronchery         } else if (!rand_serial(ret, ai)) {
1487b077aed3SPierre Pronchery             BIO_printf(bio_err, "Error creating random number to store in %s\n",
1488b077aed3SPierre Pronchery                        serialfile);
1489b077aed3SPierre Pronchery             BN_free(ret);
1490b077aed3SPierre Pronchery             ret = NULL;
1491b077aed3SPierre Pronchery         }
1492b077aed3SPierre Pronchery     } else {
1493b077aed3SPierre Pronchery         if (!a2i_ASN1_INTEGER(in, ai, buf, 1024)) {
1494b077aed3SPierre Pronchery             BIO_printf(bio_err, "Unable to load number from %s\n",
1495b077aed3SPierre Pronchery                        serialfile);
1496b077aed3SPierre Pronchery             goto err;
1497b077aed3SPierre Pronchery         }
1498b077aed3SPierre Pronchery         ret = ASN1_INTEGER_to_BN(ai, NULL);
1499b077aed3SPierre Pronchery         if (ret == NULL) {
1500b077aed3SPierre Pronchery             BIO_printf(bio_err, "Error converting number from bin to BIGNUM\n");
1501b077aed3SPierre Pronchery             goto err;
1502b077aed3SPierre Pronchery         }
1503b077aed3SPierre Pronchery     }
1504b077aed3SPierre Pronchery 
1505b077aed3SPierre Pronchery     if (ret != NULL && retai != NULL) {
1506b077aed3SPierre Pronchery         *retai = ai;
1507b077aed3SPierre Pronchery         ai = NULL;
1508b077aed3SPierre Pronchery     }
1509b077aed3SPierre Pronchery  err:
1510b077aed3SPierre Pronchery     if (ret == NULL)
1511b077aed3SPierre Pronchery         ERR_print_errors(bio_err);
1512b077aed3SPierre Pronchery     BIO_free(in);
1513b077aed3SPierre Pronchery     ASN1_INTEGER_free(ai);
1514b077aed3SPierre Pronchery     return ret;
1515b077aed3SPierre Pronchery }
1516b077aed3SPierre Pronchery 
save_serial(const char * serialfile,const char * suffix,const BIGNUM * serial,ASN1_INTEGER ** retai)1517b077aed3SPierre Pronchery int save_serial(const char *serialfile, const char *suffix, const BIGNUM *serial,
1518b077aed3SPierre Pronchery                 ASN1_INTEGER **retai)
1519b077aed3SPierre Pronchery {
1520b077aed3SPierre Pronchery     char buf[1][BSIZE];
1521b077aed3SPierre Pronchery     BIO *out = NULL;
1522b077aed3SPierre Pronchery     int ret = 0;
1523b077aed3SPierre Pronchery     ASN1_INTEGER *ai = NULL;
1524b077aed3SPierre Pronchery     int j;
1525b077aed3SPierre Pronchery 
1526b077aed3SPierre Pronchery     if (suffix == NULL)
1527b077aed3SPierre Pronchery         j = strlen(serialfile);
1528b077aed3SPierre Pronchery     else
1529b077aed3SPierre Pronchery         j = strlen(serialfile) + strlen(suffix) + 1;
1530b077aed3SPierre Pronchery     if (j >= BSIZE) {
1531b077aed3SPierre Pronchery         BIO_printf(bio_err, "File name too long\n");
1532b077aed3SPierre Pronchery         goto err;
1533b077aed3SPierre Pronchery     }
1534b077aed3SPierre Pronchery 
1535b077aed3SPierre Pronchery     if (suffix == NULL)
1536b077aed3SPierre Pronchery         OPENSSL_strlcpy(buf[0], serialfile, BSIZE);
1537b077aed3SPierre Pronchery     else {
1538b077aed3SPierre Pronchery #ifndef OPENSSL_SYS_VMS
1539b077aed3SPierre Pronchery         j = BIO_snprintf(buf[0], sizeof(buf[0]), "%s.%s", serialfile, suffix);
1540b077aed3SPierre Pronchery #else
1541b077aed3SPierre Pronchery         j = BIO_snprintf(buf[0], sizeof(buf[0]), "%s-%s", serialfile, suffix);
1542b077aed3SPierre Pronchery #endif
1543b077aed3SPierre Pronchery     }
1544b077aed3SPierre Pronchery     out = BIO_new_file(buf[0], "w");
1545b077aed3SPierre Pronchery     if (out == NULL) {
1546b077aed3SPierre Pronchery         goto err;
1547b077aed3SPierre Pronchery     }
1548b077aed3SPierre Pronchery 
1549b077aed3SPierre Pronchery     if ((ai = BN_to_ASN1_INTEGER(serial, NULL)) == NULL) {
1550b077aed3SPierre Pronchery         BIO_printf(bio_err, "error converting serial to ASN.1 format\n");
1551b077aed3SPierre Pronchery         goto err;
1552b077aed3SPierre Pronchery     }
1553b077aed3SPierre Pronchery     i2a_ASN1_INTEGER(out, ai);
1554b077aed3SPierre Pronchery     BIO_puts(out, "\n");
1555b077aed3SPierre Pronchery     ret = 1;
1556b077aed3SPierre Pronchery     if (retai) {
1557b077aed3SPierre Pronchery         *retai = ai;
1558b077aed3SPierre Pronchery         ai = NULL;
1559b077aed3SPierre Pronchery     }
1560b077aed3SPierre Pronchery  err:
1561b077aed3SPierre Pronchery     if (!ret)
1562b077aed3SPierre Pronchery         ERR_print_errors(bio_err);
1563b077aed3SPierre Pronchery     BIO_free_all(out);
1564b077aed3SPierre Pronchery     ASN1_INTEGER_free(ai);
1565b077aed3SPierre Pronchery     return ret;
1566b077aed3SPierre Pronchery }
1567b077aed3SPierre Pronchery 
rotate_serial(const char * serialfile,const char * new_suffix,const char * old_suffix)1568b077aed3SPierre Pronchery int rotate_serial(const char *serialfile, const char *new_suffix,
1569b077aed3SPierre Pronchery                   const char *old_suffix)
1570b077aed3SPierre Pronchery {
1571b077aed3SPierre Pronchery     char buf[2][BSIZE];
1572b077aed3SPierre Pronchery     int i, j;
1573b077aed3SPierre Pronchery 
1574b077aed3SPierre Pronchery     i = strlen(serialfile) + strlen(old_suffix);
1575b077aed3SPierre Pronchery     j = strlen(serialfile) + strlen(new_suffix);
1576b077aed3SPierre Pronchery     if (i > j)
1577b077aed3SPierre Pronchery         j = i;
1578b077aed3SPierre Pronchery     if (j + 1 >= BSIZE) {
1579b077aed3SPierre Pronchery         BIO_printf(bio_err, "File name too long\n");
1580b077aed3SPierre Pronchery         goto err;
1581b077aed3SPierre Pronchery     }
1582b077aed3SPierre Pronchery #ifndef OPENSSL_SYS_VMS
1583b077aed3SPierre Pronchery     j = BIO_snprintf(buf[0], sizeof(buf[0]), "%s.%s", serialfile, new_suffix);
1584b077aed3SPierre Pronchery     j = BIO_snprintf(buf[1], sizeof(buf[1]), "%s.%s", serialfile, old_suffix);
1585b077aed3SPierre Pronchery #else
1586b077aed3SPierre Pronchery     j = BIO_snprintf(buf[0], sizeof(buf[0]), "%s-%s", serialfile, new_suffix);
1587b077aed3SPierre Pronchery     j = BIO_snprintf(buf[1], sizeof(buf[1]), "%s-%s", serialfile, old_suffix);
1588b077aed3SPierre Pronchery #endif
1589b077aed3SPierre Pronchery     if (rename(serialfile, buf[1]) < 0 && errno != ENOENT
1590b077aed3SPierre Pronchery #ifdef ENOTDIR
1591b077aed3SPierre Pronchery         && errno != ENOTDIR
1592b077aed3SPierre Pronchery #endif
1593b077aed3SPierre Pronchery         ) {
1594b077aed3SPierre Pronchery         BIO_printf(bio_err,
1595b077aed3SPierre Pronchery                    "Unable to rename %s to %s\n", serialfile, buf[1]);
1596b077aed3SPierre Pronchery         perror("reason");
1597b077aed3SPierre Pronchery         goto err;
1598b077aed3SPierre Pronchery     }
1599b077aed3SPierre Pronchery     if (rename(buf[0], serialfile) < 0) {
1600b077aed3SPierre Pronchery         BIO_printf(bio_err,
1601b077aed3SPierre Pronchery                    "Unable to rename %s to %s\n", buf[0], serialfile);
1602b077aed3SPierre Pronchery         perror("reason");
1603b077aed3SPierre Pronchery         rename(buf[1], serialfile);
1604b077aed3SPierre Pronchery         goto err;
1605b077aed3SPierre Pronchery     }
1606b077aed3SPierre Pronchery     return 1;
1607b077aed3SPierre Pronchery  err:
1608b077aed3SPierre Pronchery     ERR_print_errors(bio_err);
1609b077aed3SPierre Pronchery     return 0;
1610b077aed3SPierre Pronchery }
1611b077aed3SPierre Pronchery 
rand_serial(BIGNUM * b,ASN1_INTEGER * ai)1612b077aed3SPierre Pronchery int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
1613b077aed3SPierre Pronchery {
1614b077aed3SPierre Pronchery     BIGNUM *btmp;
1615b077aed3SPierre Pronchery     int ret = 0;
1616b077aed3SPierre Pronchery 
1617b077aed3SPierre Pronchery     btmp = b == NULL ? BN_new() : b;
1618b077aed3SPierre Pronchery     if (btmp == NULL)
1619b077aed3SPierre Pronchery         return 0;
1620b077aed3SPierre Pronchery 
1621b077aed3SPierre Pronchery     if (!BN_rand(btmp, SERIAL_RAND_BITS, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY))
1622b077aed3SPierre Pronchery         goto error;
1623b077aed3SPierre Pronchery     if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
1624b077aed3SPierre Pronchery         goto error;
1625b077aed3SPierre Pronchery 
1626b077aed3SPierre Pronchery     ret = 1;
1627b077aed3SPierre Pronchery 
1628b077aed3SPierre Pronchery  error:
1629b077aed3SPierre Pronchery 
1630b077aed3SPierre Pronchery     if (btmp != b)
1631b077aed3SPierre Pronchery         BN_free(btmp);
1632b077aed3SPierre Pronchery 
1633b077aed3SPierre Pronchery     return ret;
1634b077aed3SPierre Pronchery }
1635b077aed3SPierre Pronchery 
load_index(const char * dbfile,DB_ATTR * db_attr)1636b077aed3SPierre Pronchery CA_DB *load_index(const char *dbfile, DB_ATTR *db_attr)
1637b077aed3SPierre Pronchery {
1638b077aed3SPierre Pronchery     CA_DB *retdb = NULL;
1639b077aed3SPierre Pronchery     TXT_DB *tmpdb = NULL;
1640b077aed3SPierre Pronchery     BIO *in;
1641b077aed3SPierre Pronchery     CONF *dbattr_conf = NULL;
1642b077aed3SPierre Pronchery     char buf[BSIZE];
1643b077aed3SPierre Pronchery #ifndef OPENSSL_NO_POSIX_IO
1644b077aed3SPierre Pronchery     FILE *dbfp;
1645b077aed3SPierre Pronchery     struct stat dbst;
1646b077aed3SPierre Pronchery #endif
1647b077aed3SPierre Pronchery 
1648b077aed3SPierre Pronchery     in = BIO_new_file(dbfile, "r");
1649b077aed3SPierre Pronchery     if (in == NULL)
1650b077aed3SPierre Pronchery         goto err;
1651b077aed3SPierre Pronchery 
1652b077aed3SPierre Pronchery #ifndef OPENSSL_NO_POSIX_IO
1653b077aed3SPierre Pronchery     BIO_get_fp(in, &dbfp);
1654b077aed3SPierre Pronchery     if (fstat(fileno(dbfp), &dbst) == -1) {
1655b077aed3SPierre Pronchery         ERR_raise_data(ERR_LIB_SYS, errno,
1656b077aed3SPierre Pronchery                        "calling fstat(%s)", dbfile);
1657b077aed3SPierre Pronchery         goto err;
1658b077aed3SPierre Pronchery     }
1659b077aed3SPierre Pronchery #endif
1660b077aed3SPierre Pronchery 
1661b077aed3SPierre Pronchery     if ((tmpdb = TXT_DB_read(in, DB_NUMBER)) == NULL)
1662b077aed3SPierre Pronchery         goto err;
1663b077aed3SPierre Pronchery 
1664b077aed3SPierre Pronchery #ifndef OPENSSL_SYS_VMS
1665b077aed3SPierre Pronchery     BIO_snprintf(buf, sizeof(buf), "%s.attr", dbfile);
1666b077aed3SPierre Pronchery #else
1667b077aed3SPierre Pronchery     BIO_snprintf(buf, sizeof(buf), "%s-attr", dbfile);
1668b077aed3SPierre Pronchery #endif
1669b077aed3SPierre Pronchery     dbattr_conf = app_load_config_quiet(buf);
1670b077aed3SPierre Pronchery 
1671b077aed3SPierre Pronchery     retdb = app_malloc(sizeof(*retdb), "new DB");
1672b077aed3SPierre Pronchery     retdb->db = tmpdb;
1673b077aed3SPierre Pronchery     tmpdb = NULL;
1674b077aed3SPierre Pronchery     if (db_attr)
1675b077aed3SPierre Pronchery         retdb->attributes = *db_attr;
1676b077aed3SPierre Pronchery     else {
1677b077aed3SPierre Pronchery         retdb->attributes.unique_subject = 1;
1678b077aed3SPierre Pronchery     }
1679b077aed3SPierre Pronchery 
1680b077aed3SPierre Pronchery     if (dbattr_conf) {
1681b077aed3SPierre Pronchery         char *p = NCONF_get_string(dbattr_conf, NULL, "unique_subject");
1682b077aed3SPierre Pronchery         if (p) {
1683b077aed3SPierre Pronchery             retdb->attributes.unique_subject = parse_yesno(p, 1);
1684aa795734SPierre Pronchery         } else {
1685aa795734SPierre Pronchery             ERR_clear_error();
1686b077aed3SPierre Pronchery         }
1687aa795734SPierre Pronchery 
1688b077aed3SPierre Pronchery     }
1689b077aed3SPierre Pronchery 
1690b077aed3SPierre Pronchery     retdb->dbfname = OPENSSL_strdup(dbfile);
1691b077aed3SPierre Pronchery #ifndef OPENSSL_NO_POSIX_IO
1692b077aed3SPierre Pronchery     retdb->dbst = dbst;
1693b077aed3SPierre Pronchery #endif
1694b077aed3SPierre Pronchery 
1695b077aed3SPierre Pronchery  err:
1696b077aed3SPierre Pronchery     ERR_print_errors(bio_err);
1697b077aed3SPierre Pronchery     NCONF_free(dbattr_conf);
1698b077aed3SPierre Pronchery     TXT_DB_free(tmpdb);
1699b077aed3SPierre Pronchery     BIO_free_all(in);
1700b077aed3SPierre Pronchery     return retdb;
1701b077aed3SPierre Pronchery }
1702b077aed3SPierre Pronchery 
1703b077aed3SPierre Pronchery /*
1704b077aed3SPierre Pronchery  * Returns > 0 on success, <= 0 on error
1705b077aed3SPierre Pronchery  */
index_index(CA_DB * db)1706b077aed3SPierre Pronchery int index_index(CA_DB *db)
1707b077aed3SPierre Pronchery {
1708b077aed3SPierre Pronchery     if (!TXT_DB_create_index(db->db, DB_serial, NULL,
1709b077aed3SPierre Pronchery                              LHASH_HASH_FN(index_serial),
1710b077aed3SPierre Pronchery                              LHASH_COMP_FN(index_serial))) {
1711b077aed3SPierre Pronchery         BIO_printf(bio_err,
1712b077aed3SPierre Pronchery                    "Error creating serial number index:(%ld,%ld,%ld)\n",
1713b077aed3SPierre Pronchery                    db->db->error, db->db->arg1, db->db->arg2);
1714b077aed3SPierre Pronchery         goto err;
1715b077aed3SPierre Pronchery     }
1716b077aed3SPierre Pronchery 
1717b077aed3SPierre Pronchery     if (db->attributes.unique_subject
1718b077aed3SPierre Pronchery         && !TXT_DB_create_index(db->db, DB_name, index_name_qual,
1719b077aed3SPierre Pronchery                                 LHASH_HASH_FN(index_name),
1720b077aed3SPierre Pronchery                                 LHASH_COMP_FN(index_name))) {
1721b077aed3SPierre Pronchery         BIO_printf(bio_err, "Error creating name index:(%ld,%ld,%ld)\n",
1722b077aed3SPierre Pronchery                    db->db->error, db->db->arg1, db->db->arg2);
1723b077aed3SPierre Pronchery         goto err;
1724b077aed3SPierre Pronchery     }
1725b077aed3SPierre Pronchery     return 1;
1726b077aed3SPierre Pronchery  err:
1727b077aed3SPierre Pronchery     ERR_print_errors(bio_err);
1728b077aed3SPierre Pronchery     return 0;
1729b077aed3SPierre Pronchery }
1730b077aed3SPierre Pronchery 
save_index(const char * dbfile,const char * suffix,CA_DB * db)1731b077aed3SPierre Pronchery int save_index(const char *dbfile, const char *suffix, CA_DB *db)
1732b077aed3SPierre Pronchery {
1733b077aed3SPierre Pronchery     char buf[3][BSIZE];
1734b077aed3SPierre Pronchery     BIO *out;
1735b077aed3SPierre Pronchery     int j;
1736b077aed3SPierre Pronchery 
1737b077aed3SPierre Pronchery     j = strlen(dbfile) + strlen(suffix);
1738b077aed3SPierre Pronchery     if (j + 6 >= BSIZE) {
1739b077aed3SPierre Pronchery         BIO_printf(bio_err, "File name too long\n");
1740b077aed3SPierre Pronchery         goto err;
1741b077aed3SPierre Pronchery     }
1742b077aed3SPierre Pronchery #ifndef OPENSSL_SYS_VMS
1743b077aed3SPierre Pronchery     j = BIO_snprintf(buf[2], sizeof(buf[2]), "%s.attr", dbfile);
1744b077aed3SPierre Pronchery     j = BIO_snprintf(buf[1], sizeof(buf[1]), "%s.attr.%s", dbfile, suffix);
1745b077aed3SPierre Pronchery     j = BIO_snprintf(buf[0], sizeof(buf[0]), "%s.%s", dbfile, suffix);
1746b077aed3SPierre Pronchery #else
1747b077aed3SPierre Pronchery     j = BIO_snprintf(buf[2], sizeof(buf[2]), "%s-attr", dbfile);
1748b077aed3SPierre Pronchery     j = BIO_snprintf(buf[1], sizeof(buf[1]), "%s-attr-%s", dbfile, suffix);
1749b077aed3SPierre Pronchery     j = BIO_snprintf(buf[0], sizeof(buf[0]), "%s-%s", dbfile, suffix);
1750b077aed3SPierre Pronchery #endif
1751b077aed3SPierre Pronchery     out = BIO_new_file(buf[0], "w");
1752b077aed3SPierre Pronchery     if (out == NULL) {
1753b077aed3SPierre Pronchery         perror(dbfile);
1754b077aed3SPierre Pronchery         BIO_printf(bio_err, "Unable to open '%s'\n", dbfile);
1755b077aed3SPierre Pronchery         goto err;
1756b077aed3SPierre Pronchery     }
1757b077aed3SPierre Pronchery     j = TXT_DB_write(out, db->db);
1758b077aed3SPierre Pronchery     BIO_free(out);
1759b077aed3SPierre Pronchery     if (j <= 0)
1760b077aed3SPierre Pronchery         goto err;
1761b077aed3SPierre Pronchery 
1762b077aed3SPierre Pronchery     out = BIO_new_file(buf[1], "w");
1763b077aed3SPierre Pronchery     if (out == NULL) {
1764b077aed3SPierre Pronchery         perror(buf[2]);
1765b077aed3SPierre Pronchery         BIO_printf(bio_err, "Unable to open '%s'\n", buf[2]);
1766b077aed3SPierre Pronchery         goto err;
1767b077aed3SPierre Pronchery     }
1768b077aed3SPierre Pronchery     BIO_printf(out, "unique_subject = %s\n",
1769b077aed3SPierre Pronchery                db->attributes.unique_subject ? "yes" : "no");
1770b077aed3SPierre Pronchery     BIO_free(out);
1771b077aed3SPierre Pronchery 
1772b077aed3SPierre Pronchery     return 1;
1773b077aed3SPierre Pronchery  err:
1774b077aed3SPierre Pronchery     ERR_print_errors(bio_err);
1775b077aed3SPierre Pronchery     return 0;
1776b077aed3SPierre Pronchery }
1777b077aed3SPierre Pronchery 
rotate_index(const char * dbfile,const char * new_suffix,const char * old_suffix)1778b077aed3SPierre Pronchery int rotate_index(const char *dbfile, const char *new_suffix,
1779b077aed3SPierre Pronchery                  const char *old_suffix)
1780b077aed3SPierre Pronchery {
1781b077aed3SPierre Pronchery     char buf[5][BSIZE];
1782b077aed3SPierre Pronchery     int i, j;
1783b077aed3SPierre Pronchery 
1784b077aed3SPierre Pronchery     i = strlen(dbfile) + strlen(old_suffix);
1785b077aed3SPierre Pronchery     j = strlen(dbfile) + strlen(new_suffix);
1786b077aed3SPierre Pronchery     if (i > j)
1787b077aed3SPierre Pronchery         j = i;
1788b077aed3SPierre Pronchery     if (j + 6 >= BSIZE) {
1789b077aed3SPierre Pronchery         BIO_printf(bio_err, "File name too long\n");
1790b077aed3SPierre Pronchery         goto err;
1791b077aed3SPierre Pronchery     }
1792b077aed3SPierre Pronchery #ifndef OPENSSL_SYS_VMS
1793b077aed3SPierre Pronchery     j = BIO_snprintf(buf[4], sizeof(buf[4]), "%s.attr", dbfile);
1794b077aed3SPierre Pronchery     j = BIO_snprintf(buf[3], sizeof(buf[3]), "%s.attr.%s", dbfile, old_suffix);
1795b077aed3SPierre Pronchery     j = BIO_snprintf(buf[2], sizeof(buf[2]), "%s.attr.%s", dbfile, new_suffix);
1796b077aed3SPierre Pronchery     j = BIO_snprintf(buf[1], sizeof(buf[1]), "%s.%s", dbfile, old_suffix);
1797b077aed3SPierre Pronchery     j = BIO_snprintf(buf[0], sizeof(buf[0]), "%s.%s", dbfile, new_suffix);
1798b077aed3SPierre Pronchery #else
1799b077aed3SPierre Pronchery     j = BIO_snprintf(buf[4], sizeof(buf[4]), "%s-attr", dbfile);
1800b077aed3SPierre Pronchery     j = BIO_snprintf(buf[3], sizeof(buf[3]), "%s-attr-%s", dbfile, old_suffix);
1801b077aed3SPierre Pronchery     j = BIO_snprintf(buf[2], sizeof(buf[2]), "%s-attr-%s", dbfile, new_suffix);
1802b077aed3SPierre Pronchery     j = BIO_snprintf(buf[1], sizeof(buf[1]), "%s-%s", dbfile, old_suffix);
1803b077aed3SPierre Pronchery     j = BIO_snprintf(buf[0], sizeof(buf[0]), "%s-%s", dbfile, new_suffix);
1804b077aed3SPierre Pronchery #endif
1805b077aed3SPierre Pronchery     if (rename(dbfile, buf[1]) < 0 && errno != ENOENT
1806b077aed3SPierre Pronchery #ifdef ENOTDIR
1807b077aed3SPierre Pronchery         && errno != ENOTDIR
1808b077aed3SPierre Pronchery #endif
1809b077aed3SPierre Pronchery         ) {
1810b077aed3SPierre Pronchery         BIO_printf(bio_err, "Unable to rename %s to %s\n", dbfile, buf[1]);
1811b077aed3SPierre Pronchery         perror("reason");
1812b077aed3SPierre Pronchery         goto err;
1813b077aed3SPierre Pronchery     }
1814b077aed3SPierre Pronchery     if (rename(buf[0], dbfile) < 0) {
1815b077aed3SPierre Pronchery         BIO_printf(bio_err, "Unable to rename %s to %s\n", buf[0], dbfile);
1816b077aed3SPierre Pronchery         perror("reason");
1817b077aed3SPierre Pronchery         rename(buf[1], dbfile);
1818b077aed3SPierre Pronchery         goto err;
1819b077aed3SPierre Pronchery     }
1820b077aed3SPierre Pronchery     if (rename(buf[4], buf[3]) < 0 && errno != ENOENT
1821b077aed3SPierre Pronchery #ifdef ENOTDIR
1822b077aed3SPierre Pronchery         && errno != ENOTDIR
1823b077aed3SPierre Pronchery #endif
1824b077aed3SPierre Pronchery         ) {
1825b077aed3SPierre Pronchery         BIO_printf(bio_err, "Unable to rename %s to %s\n", buf[4], buf[3]);
1826b077aed3SPierre Pronchery         perror("reason");
1827b077aed3SPierre Pronchery         rename(dbfile, buf[0]);
1828b077aed3SPierre Pronchery         rename(buf[1], dbfile);
1829b077aed3SPierre Pronchery         goto err;
1830b077aed3SPierre Pronchery     }
1831b077aed3SPierre Pronchery     if (rename(buf[2], buf[4]) < 0) {
1832b077aed3SPierre Pronchery         BIO_printf(bio_err, "Unable to rename %s to %s\n", buf[2], buf[4]);
1833b077aed3SPierre Pronchery         perror("reason");
1834b077aed3SPierre Pronchery         rename(buf[3], buf[4]);
1835b077aed3SPierre Pronchery         rename(dbfile, buf[0]);
1836b077aed3SPierre Pronchery         rename(buf[1], dbfile);
1837b077aed3SPierre Pronchery         goto err;
1838b077aed3SPierre Pronchery     }
1839b077aed3SPierre Pronchery     return 1;
1840b077aed3SPierre Pronchery  err:
1841b077aed3SPierre Pronchery     ERR_print_errors(bio_err);
1842b077aed3SPierre Pronchery     return 0;
1843b077aed3SPierre Pronchery }
1844b077aed3SPierre Pronchery 
free_index(CA_DB * db)1845b077aed3SPierre Pronchery void free_index(CA_DB *db)
1846b077aed3SPierre Pronchery {
1847b077aed3SPierre Pronchery     if (db) {
1848b077aed3SPierre Pronchery         TXT_DB_free(db->db);
1849b077aed3SPierre Pronchery         OPENSSL_free(db->dbfname);
1850b077aed3SPierre Pronchery         OPENSSL_free(db);
1851b077aed3SPierre Pronchery     }
1852b077aed3SPierre Pronchery }
1853b077aed3SPierre Pronchery 
parse_yesno(const char * str,int def)1854b077aed3SPierre Pronchery int parse_yesno(const char *str, int def)
1855b077aed3SPierre Pronchery {
1856b077aed3SPierre Pronchery     if (str) {
1857b077aed3SPierre Pronchery         switch (*str) {
1858b077aed3SPierre Pronchery         case 'f':              /* false */
1859b077aed3SPierre Pronchery         case 'F':              /* FALSE */
1860b077aed3SPierre Pronchery         case 'n':              /* no */
1861b077aed3SPierre Pronchery         case 'N':              /* NO */
1862b077aed3SPierre Pronchery         case '0':              /* 0 */
1863b077aed3SPierre Pronchery             return 0;
1864b077aed3SPierre Pronchery         case 't':              /* true */
1865b077aed3SPierre Pronchery         case 'T':              /* TRUE */
1866b077aed3SPierre Pronchery         case 'y':              /* yes */
1867b077aed3SPierre Pronchery         case 'Y':              /* YES */
1868b077aed3SPierre Pronchery         case '1':              /* 1 */
1869b077aed3SPierre Pronchery             return 1;
1870b077aed3SPierre Pronchery         }
1871b077aed3SPierre Pronchery     }
1872b077aed3SPierre Pronchery     return def;
1873b077aed3SPierre Pronchery }
1874b077aed3SPierre Pronchery 
1875b077aed3SPierre Pronchery /*
1876b077aed3SPierre Pronchery  * name is expected to be in the format /type0=value0/type1=value1/type2=...
1877b077aed3SPierre Pronchery  * where + can be used instead of / to form multi-valued RDNs if canmulti
1878b077aed3SPierre Pronchery  * and characters may be escaped by \
1879b077aed3SPierre Pronchery  */
parse_name(const char * cp,int chtype,int canmulti,const char * desc)1880b077aed3SPierre Pronchery X509_NAME *parse_name(const char *cp, int chtype, int canmulti,
1881b077aed3SPierre Pronchery                       const char *desc)
1882b077aed3SPierre Pronchery {
1883b077aed3SPierre Pronchery     int nextismulti = 0;
1884b077aed3SPierre Pronchery     char *work;
1885b077aed3SPierre Pronchery     X509_NAME *n;
1886b077aed3SPierre Pronchery 
1887b077aed3SPierre Pronchery     if (*cp++ != '/') {
1888b077aed3SPierre Pronchery         BIO_printf(bio_err,
1889b077aed3SPierre Pronchery                    "%s: %s name is expected to be in the format "
1890b077aed3SPierre Pronchery                    "/type0=value0/type1=value1/type2=... where characters may "
1891b077aed3SPierre Pronchery                    "be escaped by \\. This name is not in that format: '%s'\n",
1892b077aed3SPierre Pronchery                    opt_getprog(), desc, --cp);
1893b077aed3SPierre Pronchery         return NULL;
1894b077aed3SPierre Pronchery     }
1895b077aed3SPierre Pronchery 
1896b077aed3SPierre Pronchery     n = X509_NAME_new();
1897b077aed3SPierre Pronchery     if (n == NULL) {
1898b077aed3SPierre Pronchery         BIO_printf(bio_err, "%s: Out of memory\n", opt_getprog());
1899b077aed3SPierre Pronchery         return NULL;
1900b077aed3SPierre Pronchery     }
1901b077aed3SPierre Pronchery     work = OPENSSL_strdup(cp);
1902b077aed3SPierre Pronchery     if (work == NULL) {
1903b077aed3SPierre Pronchery         BIO_printf(bio_err, "%s: Error copying %s name input\n",
1904b077aed3SPierre Pronchery                    opt_getprog(), desc);
1905b077aed3SPierre Pronchery         goto err;
1906b077aed3SPierre Pronchery     }
1907b077aed3SPierre Pronchery 
1908b077aed3SPierre Pronchery     while (*cp != '\0') {
1909b077aed3SPierre Pronchery         char *bp = work;
1910b077aed3SPierre Pronchery         char *typestr = bp;
1911b077aed3SPierre Pronchery         unsigned char *valstr;
1912b077aed3SPierre Pronchery         int nid;
1913b077aed3SPierre Pronchery         int ismulti = nextismulti;
1914b077aed3SPierre Pronchery         nextismulti = 0;
1915b077aed3SPierre Pronchery 
1916b077aed3SPierre Pronchery         /* Collect the type */
1917b077aed3SPierre Pronchery         while (*cp != '\0' && *cp != '=')
1918b077aed3SPierre Pronchery             *bp++ = *cp++;
1919b077aed3SPierre Pronchery         *bp++ = '\0';
1920b077aed3SPierre Pronchery         if (*cp == '\0') {
1921b077aed3SPierre Pronchery             BIO_printf(bio_err,
1922b077aed3SPierre Pronchery                        "%s: Missing '=' after RDN type string '%s' in %s name string\n",
1923b077aed3SPierre Pronchery                        opt_getprog(), typestr, desc);
1924b077aed3SPierre Pronchery             goto err;
1925b077aed3SPierre Pronchery         }
1926b077aed3SPierre Pronchery         ++cp;
1927b077aed3SPierre Pronchery 
1928b077aed3SPierre Pronchery         /* Collect the value. */
1929b077aed3SPierre Pronchery         valstr = (unsigned char *)bp;
1930b077aed3SPierre Pronchery         for (; *cp != '\0' && *cp != '/'; *bp++ = *cp++) {
1931b077aed3SPierre Pronchery             /* unescaped '+' symbol string signals further member of multiRDN */
1932b077aed3SPierre Pronchery             if (canmulti && *cp == '+') {
1933b077aed3SPierre Pronchery                 nextismulti = 1;
1934b077aed3SPierre Pronchery                 break;
1935b077aed3SPierre Pronchery             }
1936b077aed3SPierre Pronchery             if (*cp == '\\' && *++cp == '\0') {
1937b077aed3SPierre Pronchery                 BIO_printf(bio_err,
1938b077aed3SPierre Pronchery                            "%s: Escape character at end of %s name string\n",
1939b077aed3SPierre Pronchery                            opt_getprog(), desc);
1940b077aed3SPierre Pronchery                 goto err;
1941b077aed3SPierre Pronchery             }
1942b077aed3SPierre Pronchery         }
1943b077aed3SPierre Pronchery         *bp++ = '\0';
1944b077aed3SPierre Pronchery 
1945b077aed3SPierre Pronchery         /* If not at EOS (must be + or /), move forward. */
1946b077aed3SPierre Pronchery         if (*cp != '\0')
1947b077aed3SPierre Pronchery             ++cp;
1948b077aed3SPierre Pronchery 
1949b077aed3SPierre Pronchery         /* Parse */
1950b077aed3SPierre Pronchery         nid = OBJ_txt2nid(typestr);
1951b077aed3SPierre Pronchery         if (nid == NID_undef) {
1952b077aed3SPierre Pronchery             BIO_printf(bio_err,
19536f1af0d7SPierre Pronchery                        "%s warning: Skipping unknown %s name attribute \"%s\"\n",
1954b077aed3SPierre Pronchery                        opt_getprog(), desc, typestr);
1955b077aed3SPierre Pronchery             if (ismulti)
1956b077aed3SPierre Pronchery                 BIO_printf(bio_err,
19576f1af0d7SPierre Pronchery                            "%s hint: a '+' in a value string needs be escaped using '\\' else a new member of a multi-valued RDN is expected\n",
19586f1af0d7SPierre Pronchery                            opt_getprog());
1959b077aed3SPierre Pronchery             continue;
1960b077aed3SPierre Pronchery         }
1961b077aed3SPierre Pronchery         if (*valstr == '\0') {
1962b077aed3SPierre Pronchery             BIO_printf(bio_err,
19636f1af0d7SPierre Pronchery                        "%s warning: No value provided for %s name attribute \"%s\", skipped\n",
1964b077aed3SPierre Pronchery                        opt_getprog(), desc, typestr);
1965b077aed3SPierre Pronchery             continue;
1966b077aed3SPierre Pronchery         }
1967b077aed3SPierre Pronchery         if (!X509_NAME_add_entry_by_NID(n, nid, chtype,
1968b077aed3SPierre Pronchery                                         valstr, strlen((char *)valstr),
1969b077aed3SPierre Pronchery                                         -1, ismulti ? -1 : 0)) {
1970b077aed3SPierre Pronchery             ERR_print_errors(bio_err);
1971b077aed3SPierre Pronchery             BIO_printf(bio_err,
1972b077aed3SPierre Pronchery                        "%s: Error adding %s name attribute \"/%s=%s\"\n",
1973b077aed3SPierre Pronchery                        opt_getprog(), desc, typestr ,valstr);
1974b077aed3SPierre Pronchery             goto err;
1975b077aed3SPierre Pronchery         }
1976b077aed3SPierre Pronchery     }
1977b077aed3SPierre Pronchery 
1978b077aed3SPierre Pronchery     OPENSSL_free(work);
1979b077aed3SPierre Pronchery     return n;
1980b077aed3SPierre Pronchery 
1981b077aed3SPierre Pronchery  err:
1982b077aed3SPierre Pronchery     X509_NAME_free(n);
1983b077aed3SPierre Pronchery     OPENSSL_free(work);
1984b077aed3SPierre Pronchery     return NULL;
1985b077aed3SPierre Pronchery }
1986b077aed3SPierre Pronchery 
1987b077aed3SPierre Pronchery /*
1988b077aed3SPierre Pronchery  * Read whole contents of a BIO into an allocated memory buffer and return
1989b077aed3SPierre Pronchery  * it.
1990b077aed3SPierre Pronchery  */
1991b077aed3SPierre Pronchery 
bio_to_mem(unsigned char ** out,int maxlen,BIO * in)1992b077aed3SPierre Pronchery int bio_to_mem(unsigned char **out, int maxlen, BIO *in)
1993b077aed3SPierre Pronchery {
1994b077aed3SPierre Pronchery     BIO *mem;
1995b077aed3SPierre Pronchery     int len, ret;
1996b077aed3SPierre Pronchery     unsigned char tbuf[1024];
1997b077aed3SPierre Pronchery 
1998b077aed3SPierre Pronchery     mem = BIO_new(BIO_s_mem());
1999b077aed3SPierre Pronchery     if (mem == NULL)
2000b077aed3SPierre Pronchery         return -1;
2001b077aed3SPierre Pronchery     for (;;) {
2002b077aed3SPierre Pronchery         if ((maxlen != -1) && maxlen < 1024)
2003b077aed3SPierre Pronchery             len = maxlen;
2004b077aed3SPierre Pronchery         else
2005b077aed3SPierre Pronchery             len = 1024;
2006b077aed3SPierre Pronchery         len = BIO_read(in, tbuf, len);
2007b077aed3SPierre Pronchery         if (len < 0) {
2008b077aed3SPierre Pronchery             BIO_free(mem);
2009b077aed3SPierre Pronchery             return -1;
2010b077aed3SPierre Pronchery         }
2011b077aed3SPierre Pronchery         if (len == 0)
2012b077aed3SPierre Pronchery             break;
2013b077aed3SPierre Pronchery         if (BIO_write(mem, tbuf, len) != len) {
2014b077aed3SPierre Pronchery             BIO_free(mem);
2015b077aed3SPierre Pronchery             return -1;
2016b077aed3SPierre Pronchery         }
2017aa795734SPierre Pronchery         if (maxlen != -1)
2018b077aed3SPierre Pronchery             maxlen -= len;
2019b077aed3SPierre Pronchery 
2020b077aed3SPierre Pronchery         if (maxlen == 0)
2021b077aed3SPierre Pronchery             break;
2022b077aed3SPierre Pronchery     }
2023b077aed3SPierre Pronchery     ret = BIO_get_mem_data(mem, (char **)out);
2024b077aed3SPierre Pronchery     BIO_set_flags(mem, BIO_FLAGS_MEM_RDONLY);
2025b077aed3SPierre Pronchery     BIO_free(mem);
2026b077aed3SPierre Pronchery     return ret;
2027b077aed3SPierre Pronchery }
2028b077aed3SPierre Pronchery 
pkey_ctrl_string(EVP_PKEY_CTX * ctx,const char * value)2029b077aed3SPierre Pronchery int pkey_ctrl_string(EVP_PKEY_CTX *ctx, const char *value)
2030b077aed3SPierre Pronchery {
2031b077aed3SPierre Pronchery     int rv = 0;
2032b077aed3SPierre Pronchery     char *stmp, *vtmp = NULL;
2033b077aed3SPierre Pronchery 
2034b077aed3SPierre Pronchery     stmp = OPENSSL_strdup(value);
2035b077aed3SPierre Pronchery     if (stmp == NULL)
2036b077aed3SPierre Pronchery         return -1;
2037b077aed3SPierre Pronchery     vtmp = strchr(stmp, ':');
2038b077aed3SPierre Pronchery     if (vtmp == NULL)
2039b077aed3SPierre Pronchery         goto err;
2040b077aed3SPierre Pronchery 
2041b077aed3SPierre Pronchery     *vtmp = 0;
2042b077aed3SPierre Pronchery     vtmp++;
2043b077aed3SPierre Pronchery     rv = EVP_PKEY_CTX_ctrl_str(ctx, stmp, vtmp);
2044b077aed3SPierre Pronchery 
2045b077aed3SPierre Pronchery  err:
2046b077aed3SPierre Pronchery     OPENSSL_free(stmp);
2047b077aed3SPierre Pronchery     return rv;
2048b077aed3SPierre Pronchery }
2049b077aed3SPierre Pronchery 
nodes_print(const char * name,STACK_OF (X509_POLICY_NODE)* nodes)2050b077aed3SPierre Pronchery static void nodes_print(const char *name, STACK_OF(X509_POLICY_NODE) *nodes)
2051b077aed3SPierre Pronchery {
2052b077aed3SPierre Pronchery     X509_POLICY_NODE *node;
2053b077aed3SPierre Pronchery     int i;
2054b077aed3SPierre Pronchery 
2055b077aed3SPierre Pronchery     BIO_printf(bio_err, "%s Policies:", name);
2056b077aed3SPierre Pronchery     if (nodes) {
2057b077aed3SPierre Pronchery         BIO_puts(bio_err, "\n");
2058b077aed3SPierre Pronchery         for (i = 0; i < sk_X509_POLICY_NODE_num(nodes); i++) {
2059b077aed3SPierre Pronchery             node = sk_X509_POLICY_NODE_value(nodes, i);
2060b077aed3SPierre Pronchery             X509_POLICY_NODE_print(bio_err, node, 2);
2061b077aed3SPierre Pronchery         }
2062b077aed3SPierre Pronchery     } else {
2063b077aed3SPierre Pronchery         BIO_puts(bio_err, " <empty>\n");
2064b077aed3SPierre Pronchery     }
2065b077aed3SPierre Pronchery }
2066b077aed3SPierre Pronchery 
policies_print(X509_STORE_CTX * ctx)2067b077aed3SPierre Pronchery void policies_print(X509_STORE_CTX *ctx)
2068b077aed3SPierre Pronchery {
2069b077aed3SPierre Pronchery     X509_POLICY_TREE *tree;
2070b077aed3SPierre Pronchery     int explicit_policy;
2071b077aed3SPierre Pronchery     tree = X509_STORE_CTX_get0_policy_tree(ctx);
2072b077aed3SPierre Pronchery     explicit_policy = X509_STORE_CTX_get_explicit_policy(ctx);
2073b077aed3SPierre Pronchery 
2074b077aed3SPierre Pronchery     BIO_printf(bio_err, "Require explicit Policy: %s\n",
2075b077aed3SPierre Pronchery                explicit_policy ? "True" : "False");
2076b077aed3SPierre Pronchery 
2077b077aed3SPierre Pronchery     nodes_print("Authority", X509_policy_tree_get0_policies(tree));
2078b077aed3SPierre Pronchery     nodes_print("User", X509_policy_tree_get0_user_policies(tree));
2079b077aed3SPierre Pronchery }
2080b077aed3SPierre Pronchery 
2081b077aed3SPierre Pronchery /*-
2082b077aed3SPierre Pronchery  * next_protos_parse parses a comma separated list of strings into a string
2083b077aed3SPierre Pronchery  * in a format suitable for passing to SSL_CTX_set_next_protos_advertised.
2084b077aed3SPierre Pronchery  *   outlen: (output) set to the length of the resulting buffer on success.
2085b077aed3SPierre Pronchery  *   err: (maybe NULL) on failure, an error message line is written to this BIO.
2086b077aed3SPierre Pronchery  *   in: a NUL terminated string like "abc,def,ghi"
2087b077aed3SPierre Pronchery  *
2088b077aed3SPierre Pronchery  *   returns: a malloc'd buffer or NULL on failure.
2089b077aed3SPierre Pronchery  */
next_protos_parse(size_t * outlen,const char * in)2090b077aed3SPierre Pronchery unsigned char *next_protos_parse(size_t *outlen, const char *in)
2091b077aed3SPierre Pronchery {
2092b077aed3SPierre Pronchery     size_t len;
2093b077aed3SPierre Pronchery     unsigned char *out;
2094b077aed3SPierre Pronchery     size_t i, start = 0;
2095b077aed3SPierre Pronchery     size_t skipped = 0;
2096b077aed3SPierre Pronchery 
2097b077aed3SPierre Pronchery     len = strlen(in);
2098b077aed3SPierre Pronchery     if (len == 0 || len >= 65535)
2099b077aed3SPierre Pronchery         return NULL;
2100b077aed3SPierre Pronchery 
2101b077aed3SPierre Pronchery     out = app_malloc(len + 1, "NPN buffer");
2102b077aed3SPierre Pronchery     for (i = 0; i <= len; ++i) {
2103b077aed3SPierre Pronchery         if (i == len || in[i] == ',') {
2104b077aed3SPierre Pronchery             /*
2105b077aed3SPierre Pronchery              * Zero-length ALPN elements are invalid on the wire, we could be
2106b077aed3SPierre Pronchery              * strict and reject the entire string, but just ignoring extra
2107b077aed3SPierre Pronchery              * commas seems harmless and more friendly.
2108b077aed3SPierre Pronchery              *
2109b077aed3SPierre Pronchery              * Every comma we skip in this way puts the input buffer another
2110b077aed3SPierre Pronchery              * byte ahead of the output buffer, so all stores into the output
2111b077aed3SPierre Pronchery              * buffer need to be decremented by the number commas skipped.
2112b077aed3SPierre Pronchery              */
2113b077aed3SPierre Pronchery             if (i == start) {
2114b077aed3SPierre Pronchery                 ++start;
2115b077aed3SPierre Pronchery                 ++skipped;
2116b077aed3SPierre Pronchery                 continue;
2117b077aed3SPierre Pronchery             }
2118b077aed3SPierre Pronchery             if (i - start > 255) {
2119b077aed3SPierre Pronchery                 OPENSSL_free(out);
2120b077aed3SPierre Pronchery                 return NULL;
2121b077aed3SPierre Pronchery             }
2122b077aed3SPierre Pronchery             out[start-skipped] = (unsigned char)(i - start);
2123b077aed3SPierre Pronchery             start = i + 1;
2124b077aed3SPierre Pronchery         } else {
2125b077aed3SPierre Pronchery             out[i + 1 - skipped] = in[i];
2126b077aed3SPierre Pronchery         }
2127b077aed3SPierre Pronchery     }
2128b077aed3SPierre Pronchery 
2129b077aed3SPierre Pronchery     if (len <= skipped) {
2130b077aed3SPierre Pronchery         OPENSSL_free(out);
2131b077aed3SPierre Pronchery         return NULL;
2132b077aed3SPierre Pronchery     }
2133b077aed3SPierre Pronchery 
2134b077aed3SPierre Pronchery     *outlen = len + 1 - skipped;
2135b077aed3SPierre Pronchery     return out;
2136b077aed3SPierre Pronchery }
2137b077aed3SPierre Pronchery 
print_cert_checks(BIO * bio,X509 * x,const char * checkhost,const char * checkemail,const char * checkip)2138b077aed3SPierre Pronchery void print_cert_checks(BIO *bio, X509 *x,
2139b077aed3SPierre Pronchery                        const char *checkhost,
2140b077aed3SPierre Pronchery                        const char *checkemail, const char *checkip)
2141b077aed3SPierre Pronchery {
2142b077aed3SPierre Pronchery     if (x == NULL)
2143b077aed3SPierre Pronchery         return;
2144b077aed3SPierre Pronchery     if (checkhost) {
2145b077aed3SPierre Pronchery         BIO_printf(bio, "Hostname %s does%s match certificate\n",
2146b077aed3SPierre Pronchery                    checkhost,
2147b077aed3SPierre Pronchery                    X509_check_host(x, checkhost, 0, 0, NULL) == 1
2148b077aed3SPierre Pronchery                        ? "" : " NOT");
2149b077aed3SPierre Pronchery     }
2150b077aed3SPierre Pronchery 
2151b077aed3SPierre Pronchery     if (checkemail) {
2152b077aed3SPierre Pronchery         BIO_printf(bio, "Email %s does%s match certificate\n",
2153b077aed3SPierre Pronchery                    checkemail, X509_check_email(x, checkemail, 0, 0)
2154b077aed3SPierre Pronchery                    ? "" : " NOT");
2155b077aed3SPierre Pronchery     }
2156b077aed3SPierre Pronchery 
2157b077aed3SPierre Pronchery     if (checkip) {
2158b077aed3SPierre Pronchery         BIO_printf(bio, "IP %s does%s match certificate\n",
2159b077aed3SPierre Pronchery                    checkip, X509_check_ip_asc(x, checkip, 0) ? "" : " NOT");
2160b077aed3SPierre Pronchery     }
2161b077aed3SPierre Pronchery }
2162b077aed3SPierre Pronchery 
do_pkey_ctx_init(EVP_PKEY_CTX * pkctx,STACK_OF (OPENSSL_STRING)* opts)2163b077aed3SPierre Pronchery static int do_pkey_ctx_init(EVP_PKEY_CTX *pkctx, STACK_OF(OPENSSL_STRING) *opts)
2164b077aed3SPierre Pronchery {
2165b077aed3SPierre Pronchery     int i;
2166b077aed3SPierre Pronchery 
2167b077aed3SPierre Pronchery     if (opts == NULL)
2168b077aed3SPierre Pronchery         return 1;
2169b077aed3SPierre Pronchery 
2170b077aed3SPierre Pronchery     for (i = 0; i < sk_OPENSSL_STRING_num(opts); i++) {
2171b077aed3SPierre Pronchery         char *opt = sk_OPENSSL_STRING_value(opts, i);
2172b077aed3SPierre Pronchery         if (pkey_ctrl_string(pkctx, opt) <= 0) {
2173b077aed3SPierre Pronchery             BIO_printf(bio_err, "parameter error \"%s\"\n", opt);
2174b077aed3SPierre Pronchery             ERR_print_errors(bio_err);
2175b077aed3SPierre Pronchery             return 0;
2176b077aed3SPierre Pronchery         }
2177b077aed3SPierre Pronchery     }
2178b077aed3SPierre Pronchery 
2179b077aed3SPierre Pronchery     return 1;
2180b077aed3SPierre Pronchery }
2181b077aed3SPierre Pronchery 
do_x509_init(X509 * x,STACK_OF (OPENSSL_STRING)* opts)2182b077aed3SPierre Pronchery static int do_x509_init(X509 *x, STACK_OF(OPENSSL_STRING) *opts)
2183b077aed3SPierre Pronchery {
2184b077aed3SPierre Pronchery     int i;
2185b077aed3SPierre Pronchery 
2186b077aed3SPierre Pronchery     if (opts == NULL)
2187b077aed3SPierre Pronchery         return 1;
2188b077aed3SPierre Pronchery 
2189b077aed3SPierre Pronchery     for (i = 0; i < sk_OPENSSL_STRING_num(opts); i++) {
2190b077aed3SPierre Pronchery         char *opt = sk_OPENSSL_STRING_value(opts, i);
2191b077aed3SPierre Pronchery         if (x509_ctrl_string(x, opt) <= 0) {
2192b077aed3SPierre Pronchery             BIO_printf(bio_err, "parameter error \"%s\"\n", opt);
2193b077aed3SPierre Pronchery             ERR_print_errors(bio_err);
2194b077aed3SPierre Pronchery             return 0;
2195b077aed3SPierre Pronchery         }
2196b077aed3SPierre Pronchery     }
2197b077aed3SPierre Pronchery 
2198b077aed3SPierre Pronchery     return 1;
2199b077aed3SPierre Pronchery }
2200b077aed3SPierre Pronchery 
do_x509_req_init(X509_REQ * x,STACK_OF (OPENSSL_STRING)* opts)2201b077aed3SPierre Pronchery static int do_x509_req_init(X509_REQ *x, STACK_OF(OPENSSL_STRING) *opts)
2202b077aed3SPierre Pronchery {
2203b077aed3SPierre Pronchery     int i;
2204b077aed3SPierre Pronchery 
2205b077aed3SPierre Pronchery     if (opts == NULL)
2206b077aed3SPierre Pronchery         return 1;
2207b077aed3SPierre Pronchery 
2208b077aed3SPierre Pronchery     for (i = 0; i < sk_OPENSSL_STRING_num(opts); i++) {
2209b077aed3SPierre Pronchery         char *opt = sk_OPENSSL_STRING_value(opts, i);
2210b077aed3SPierre Pronchery         if (x509_req_ctrl_string(x, opt) <= 0) {
2211b077aed3SPierre Pronchery             BIO_printf(bio_err, "parameter error \"%s\"\n", opt);
2212b077aed3SPierre Pronchery             ERR_print_errors(bio_err);
2213b077aed3SPierre Pronchery             return 0;
2214b077aed3SPierre Pronchery         }
2215b077aed3SPierre Pronchery     }
2216b077aed3SPierre Pronchery 
2217b077aed3SPierre Pronchery     return 1;
2218b077aed3SPierre Pronchery }
2219b077aed3SPierre Pronchery 
do_sign_init(EVP_MD_CTX * ctx,EVP_PKEY * pkey,const char * md,STACK_OF (OPENSSL_STRING)* sigopts)2220b077aed3SPierre Pronchery static int do_sign_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey,
2221b077aed3SPierre Pronchery                         const char *md, STACK_OF(OPENSSL_STRING) *sigopts)
2222b077aed3SPierre Pronchery {
2223b077aed3SPierre Pronchery     EVP_PKEY_CTX *pkctx = NULL;
2224b077aed3SPierre Pronchery     char def_md[80];
2225b077aed3SPierre Pronchery 
2226b077aed3SPierre Pronchery     if (ctx == NULL)
2227b077aed3SPierre Pronchery         return 0;
2228b077aed3SPierre Pronchery     /*
2229b077aed3SPierre Pronchery      * EVP_PKEY_get_default_digest_name() returns 2 if the digest is mandatory
2230b077aed3SPierre Pronchery      * for this algorithm.
2231b077aed3SPierre Pronchery      */
2232b077aed3SPierre Pronchery     if (EVP_PKEY_get_default_digest_name(pkey, def_md, sizeof(def_md)) == 2
2233b077aed3SPierre Pronchery             && strcmp(def_md, "UNDEF") == 0) {
2234b077aed3SPierre Pronchery         /* The signing algorithm requires there to be no digest */
2235b077aed3SPierre Pronchery         md = NULL;
2236b077aed3SPierre Pronchery     }
2237b077aed3SPierre Pronchery 
2238b077aed3SPierre Pronchery     return EVP_DigestSignInit_ex(ctx, &pkctx, md, app_get0_libctx(),
2239b077aed3SPierre Pronchery                                  app_get0_propq(), pkey, NULL)
2240b077aed3SPierre Pronchery         && do_pkey_ctx_init(pkctx, sigopts);
2241b077aed3SPierre Pronchery }
2242b077aed3SPierre Pronchery 
adapt_keyid_ext(X509 * cert,X509V3_CTX * ext_ctx,const char * name,const char * value,int add_default)2243b077aed3SPierre Pronchery static int adapt_keyid_ext(X509 *cert, X509V3_CTX *ext_ctx,
2244b077aed3SPierre Pronchery                            const char *name, const char *value, int add_default)
2245b077aed3SPierre Pronchery {
2246b077aed3SPierre Pronchery     const STACK_OF(X509_EXTENSION) *exts = X509_get0_extensions(cert);
2247b077aed3SPierre Pronchery     X509_EXTENSION *new_ext = X509V3_EXT_nconf(NULL, ext_ctx, name, value);
2248b077aed3SPierre Pronchery     int idx, rv = 0;
2249b077aed3SPierre Pronchery 
2250b077aed3SPierre Pronchery     if (new_ext == NULL)
2251b077aed3SPierre Pronchery         return rv;
2252b077aed3SPierre Pronchery 
2253b077aed3SPierre Pronchery     idx = X509v3_get_ext_by_OBJ(exts, X509_EXTENSION_get_object(new_ext), -1);
2254b077aed3SPierre Pronchery     if (idx >= 0) {
2255b077aed3SPierre Pronchery         X509_EXTENSION *found_ext = X509v3_get_ext(exts, idx);
2256b077aed3SPierre Pronchery         ASN1_OCTET_STRING *data = X509_EXTENSION_get_data(found_ext);
2257b077aed3SPierre Pronchery         int disabled = ASN1_STRING_length(data) <= 2; /* config said "none" */
2258b077aed3SPierre Pronchery 
2259b077aed3SPierre Pronchery         if (disabled) {
2260b077aed3SPierre Pronchery             X509_delete_ext(cert, idx);
2261b077aed3SPierre Pronchery             X509_EXTENSION_free(found_ext);
2262b077aed3SPierre Pronchery         } /* else keep existing key identifier, which might be outdated */
2263b077aed3SPierre Pronchery         rv = 1;
2264b077aed3SPierre Pronchery     } else  {
2265b077aed3SPierre Pronchery         rv = !add_default || X509_add_ext(cert, new_ext, -1);
2266b077aed3SPierre Pronchery     }
2267b077aed3SPierre Pronchery     X509_EXTENSION_free(new_ext);
2268b077aed3SPierre Pronchery     return rv;
2269b077aed3SPierre Pronchery }
2270b077aed3SPierre Pronchery 
2271b077aed3SPierre Pronchery /* Ensure RFC 5280 compliance, adapt keyIDs as needed, and sign the cert info */
do_X509_sign(X509 * cert,EVP_PKEY * pkey,const char * md,STACK_OF (OPENSSL_STRING)* sigopts,X509V3_CTX * ext_ctx)2272b077aed3SPierre Pronchery int do_X509_sign(X509 *cert, EVP_PKEY *pkey, const char *md,
2273b077aed3SPierre Pronchery                  STACK_OF(OPENSSL_STRING) *sigopts, X509V3_CTX *ext_ctx)
2274b077aed3SPierre Pronchery {
2275b077aed3SPierre Pronchery     const STACK_OF(X509_EXTENSION) *exts = X509_get0_extensions(cert);
2276b077aed3SPierre Pronchery     EVP_MD_CTX *mctx = EVP_MD_CTX_new();
2277b077aed3SPierre Pronchery     int self_sign;
2278b077aed3SPierre Pronchery     int rv = 0;
2279b077aed3SPierre Pronchery 
2280b077aed3SPierre Pronchery     if (sk_X509_EXTENSION_num(exts /* may be NULL */) > 0) {
2281b077aed3SPierre Pronchery         /* Prevent X509_V_ERR_EXTENSIONS_REQUIRE_VERSION_3 */
2282b077aed3SPierre Pronchery         if (!X509_set_version(cert, X509_VERSION_3))
2283b077aed3SPierre Pronchery             goto end;
2284b077aed3SPierre Pronchery 
2285b077aed3SPierre Pronchery         /*
2286b077aed3SPierre Pronchery          * Add default SKID before such that default AKID can make use of it
2287b077aed3SPierre Pronchery          * in case the certificate is self-signed
2288b077aed3SPierre Pronchery          */
2289b077aed3SPierre Pronchery         /* Prevent X509_V_ERR_MISSING_SUBJECT_KEY_IDENTIFIER */
2290b077aed3SPierre Pronchery         if (!adapt_keyid_ext(cert, ext_ctx, "subjectKeyIdentifier", "hash", 1))
2291b077aed3SPierre Pronchery             goto end;
2292b077aed3SPierre Pronchery         /* Prevent X509_V_ERR_MISSING_AUTHORITY_KEY_IDENTIFIER */
2293b077aed3SPierre Pronchery         ERR_set_mark();
2294b077aed3SPierre Pronchery         self_sign = X509_check_private_key(cert, pkey);
2295b077aed3SPierre Pronchery         ERR_pop_to_mark();
2296b077aed3SPierre Pronchery         if (!adapt_keyid_ext(cert, ext_ctx, "authorityKeyIdentifier",
2297b077aed3SPierre Pronchery                              "keyid, issuer", !self_sign))
2298b077aed3SPierre Pronchery             goto end;
2299b077aed3SPierre Pronchery     }
2300b077aed3SPierre Pronchery 
2301b077aed3SPierre Pronchery     if (mctx != NULL && do_sign_init(mctx, pkey, md, sigopts) > 0)
2302b077aed3SPierre Pronchery         rv = (X509_sign_ctx(cert, mctx) > 0);
2303b077aed3SPierre Pronchery  end:
2304b077aed3SPierre Pronchery     EVP_MD_CTX_free(mctx);
2305b077aed3SPierre Pronchery     return rv;
2306b077aed3SPierre Pronchery }
2307b077aed3SPierre Pronchery 
2308b077aed3SPierre Pronchery /* Sign the certificate request info */
do_X509_REQ_sign(X509_REQ * x,EVP_PKEY * pkey,const char * md,STACK_OF (OPENSSL_STRING)* sigopts)2309b077aed3SPierre Pronchery int do_X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const char *md,
2310b077aed3SPierre Pronchery                      STACK_OF(OPENSSL_STRING) *sigopts)
2311b077aed3SPierre Pronchery {
2312b077aed3SPierre Pronchery     int rv = 0;
2313b077aed3SPierre Pronchery     EVP_MD_CTX *mctx = EVP_MD_CTX_new();
2314b077aed3SPierre Pronchery 
2315b077aed3SPierre Pronchery     if (do_sign_init(mctx, pkey, md, sigopts) > 0)
2316b077aed3SPierre Pronchery         rv = (X509_REQ_sign_ctx(x, mctx) > 0);
2317b077aed3SPierre Pronchery     EVP_MD_CTX_free(mctx);
2318b077aed3SPierre Pronchery     return rv;
2319b077aed3SPierre Pronchery }
2320b077aed3SPierre Pronchery 
2321b077aed3SPierre Pronchery /* Sign the CRL info */
do_X509_CRL_sign(X509_CRL * x,EVP_PKEY * pkey,const char * md,STACK_OF (OPENSSL_STRING)* sigopts)2322b077aed3SPierre Pronchery int do_X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const char *md,
2323b077aed3SPierre Pronchery                      STACK_OF(OPENSSL_STRING) *sigopts)
2324b077aed3SPierre Pronchery {
2325b077aed3SPierre Pronchery     int rv = 0;
2326b077aed3SPierre Pronchery     EVP_MD_CTX *mctx = EVP_MD_CTX_new();
2327b077aed3SPierre Pronchery 
2328b077aed3SPierre Pronchery     if (do_sign_init(mctx, pkey, md, sigopts) > 0)
2329b077aed3SPierre Pronchery         rv = (X509_CRL_sign_ctx(x, mctx) > 0);
2330b077aed3SPierre Pronchery     EVP_MD_CTX_free(mctx);
2331b077aed3SPierre Pronchery     return rv;
2332b077aed3SPierre Pronchery }
2333b077aed3SPierre Pronchery 
2334b077aed3SPierre Pronchery /*
2335b077aed3SPierre Pronchery  * do_X509_verify returns 1 if the signature is valid,
2336b077aed3SPierre Pronchery  * 0 if the signature check fails, or -1 if error occurs.
2337b077aed3SPierre Pronchery  */
do_X509_verify(X509 * x,EVP_PKEY * pkey,STACK_OF (OPENSSL_STRING)* vfyopts)2338b077aed3SPierre Pronchery int do_X509_verify(X509 *x, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *vfyopts)
2339b077aed3SPierre Pronchery {
2340b077aed3SPierre Pronchery     int rv = 0;
2341b077aed3SPierre Pronchery 
2342b077aed3SPierre Pronchery     if (do_x509_init(x, vfyopts) > 0)
2343b077aed3SPierre Pronchery         rv = X509_verify(x, pkey);
2344b077aed3SPierre Pronchery     else
2345b077aed3SPierre Pronchery         rv = -1;
2346b077aed3SPierre Pronchery     return rv;
2347b077aed3SPierre Pronchery }
2348b077aed3SPierre Pronchery 
2349b077aed3SPierre Pronchery /*
2350b077aed3SPierre Pronchery  * do_X509_REQ_verify returns 1 if the signature is valid,
2351b077aed3SPierre Pronchery  * 0 if the signature check fails, or -1 if error occurs.
2352b077aed3SPierre Pronchery  */
do_X509_REQ_verify(X509_REQ * x,EVP_PKEY * pkey,STACK_OF (OPENSSL_STRING)* vfyopts)2353b077aed3SPierre Pronchery int do_X509_REQ_verify(X509_REQ *x, EVP_PKEY *pkey,
2354b077aed3SPierre Pronchery                        STACK_OF(OPENSSL_STRING) *vfyopts)
2355b077aed3SPierre Pronchery {
2356b077aed3SPierre Pronchery     int rv = 0;
2357b077aed3SPierre Pronchery 
2358b077aed3SPierre Pronchery     if (do_x509_req_init(x, vfyopts) > 0)
2359b077aed3SPierre Pronchery         rv = X509_REQ_verify_ex(x, pkey,
2360b077aed3SPierre Pronchery                                  app_get0_libctx(), app_get0_propq());
2361b077aed3SPierre Pronchery     else
2362b077aed3SPierre Pronchery         rv = -1;
2363b077aed3SPierre Pronchery     return rv;
2364b077aed3SPierre Pronchery }
2365b077aed3SPierre Pronchery 
2366b077aed3SPierre Pronchery /* Get first http URL from a DIST_POINT structure */
2367b077aed3SPierre Pronchery 
get_dp_url(DIST_POINT * dp)2368b077aed3SPierre Pronchery static const char *get_dp_url(DIST_POINT *dp)
2369b077aed3SPierre Pronchery {
2370b077aed3SPierre Pronchery     GENERAL_NAMES *gens;
2371b077aed3SPierre Pronchery     GENERAL_NAME *gen;
2372b077aed3SPierre Pronchery     int i, gtype;
2373b077aed3SPierre Pronchery     ASN1_STRING *uri;
2374b077aed3SPierre Pronchery     if (!dp->distpoint || dp->distpoint->type != 0)
2375b077aed3SPierre Pronchery         return NULL;
2376b077aed3SPierre Pronchery     gens = dp->distpoint->name.fullname;
2377b077aed3SPierre Pronchery     for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
2378b077aed3SPierre Pronchery         gen = sk_GENERAL_NAME_value(gens, i);
2379b077aed3SPierre Pronchery         uri = GENERAL_NAME_get0_value(gen, &gtype);
2380b077aed3SPierre Pronchery         if (gtype == GEN_URI && ASN1_STRING_length(uri) > 6) {
2381b077aed3SPierre Pronchery             const char *uptr = (const char *)ASN1_STRING_get0_data(uri);
2382b077aed3SPierre Pronchery 
2383b077aed3SPierre Pronchery             if (IS_HTTP(uptr)) /* can/should not use HTTPS here */
2384b077aed3SPierre Pronchery                 return uptr;
2385b077aed3SPierre Pronchery         }
2386b077aed3SPierre Pronchery     }
2387b077aed3SPierre Pronchery     return NULL;
2388b077aed3SPierre Pronchery }
2389b077aed3SPierre Pronchery 
2390b077aed3SPierre Pronchery /*
2391b077aed3SPierre Pronchery  * Look through a CRLDP structure and attempt to find an http URL to
2392b077aed3SPierre Pronchery  * downloads a CRL from.
2393b077aed3SPierre Pronchery  */
2394b077aed3SPierre Pronchery 
load_crl_crldp(STACK_OF (DIST_POINT)* crldp)2395b077aed3SPierre Pronchery static X509_CRL *load_crl_crldp(STACK_OF(DIST_POINT) *crldp)
2396b077aed3SPierre Pronchery {
2397b077aed3SPierre Pronchery     int i;
2398b077aed3SPierre Pronchery     const char *urlptr = NULL;
2399b077aed3SPierre Pronchery     for (i = 0; i < sk_DIST_POINT_num(crldp); i++) {
2400b077aed3SPierre Pronchery         DIST_POINT *dp = sk_DIST_POINT_value(crldp, i);
2401b077aed3SPierre Pronchery         urlptr = get_dp_url(dp);
2402b077aed3SPierre Pronchery         if (urlptr != NULL)
2403b077aed3SPierre Pronchery             return load_crl(urlptr, FORMAT_UNDEF, 0, "CRL via CDP");
2404b077aed3SPierre Pronchery     }
2405b077aed3SPierre Pronchery     return NULL;
2406b077aed3SPierre Pronchery }
2407b077aed3SPierre Pronchery 
2408b077aed3SPierre Pronchery /*
2409b077aed3SPierre Pronchery  * Example of downloading CRLs from CRLDP:
2410b077aed3SPierre Pronchery  * not usable for real world as it always downloads and doesn't cache anything.
2411b077aed3SPierre Pronchery  */
2412b077aed3SPierre Pronchery 
STACK_OF(X509_CRL)2413b077aed3SPierre Pronchery static STACK_OF(X509_CRL) *crls_http_cb(const X509_STORE_CTX *ctx,
2414b077aed3SPierre Pronchery                                         const X509_NAME *nm)
2415b077aed3SPierre Pronchery {
2416b077aed3SPierre Pronchery     X509 *x;
2417b077aed3SPierre Pronchery     STACK_OF(X509_CRL) *crls = NULL;
2418b077aed3SPierre Pronchery     X509_CRL *crl;
2419b077aed3SPierre Pronchery     STACK_OF(DIST_POINT) *crldp;
2420b077aed3SPierre Pronchery 
2421b077aed3SPierre Pronchery     crls = sk_X509_CRL_new_null();
2422b077aed3SPierre Pronchery     if (!crls)
2423b077aed3SPierre Pronchery         return NULL;
2424b077aed3SPierre Pronchery     x = X509_STORE_CTX_get_current_cert(ctx);
2425b077aed3SPierre Pronchery     crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, NULL, NULL);
2426b077aed3SPierre Pronchery     crl = load_crl_crldp(crldp);
2427b077aed3SPierre Pronchery     sk_DIST_POINT_pop_free(crldp, DIST_POINT_free);
2428b077aed3SPierre Pronchery     if (!crl) {
2429b077aed3SPierre Pronchery         sk_X509_CRL_free(crls);
2430b077aed3SPierre Pronchery         return NULL;
2431b077aed3SPierre Pronchery     }
2432b077aed3SPierre Pronchery     sk_X509_CRL_push(crls, crl);
2433b077aed3SPierre Pronchery     /* Try to download delta CRL */
2434b077aed3SPierre Pronchery     crldp = X509_get_ext_d2i(x, NID_freshest_crl, NULL, NULL);
2435b077aed3SPierre Pronchery     crl = load_crl_crldp(crldp);
2436b077aed3SPierre Pronchery     sk_DIST_POINT_pop_free(crldp, DIST_POINT_free);
2437b077aed3SPierre Pronchery     if (crl)
2438b077aed3SPierre Pronchery         sk_X509_CRL_push(crls, crl);
2439b077aed3SPierre Pronchery     return crls;
2440b077aed3SPierre Pronchery }
2441b077aed3SPierre Pronchery 
store_setup_crl_download(X509_STORE * st)2442b077aed3SPierre Pronchery void store_setup_crl_download(X509_STORE *st)
2443b077aed3SPierre Pronchery {
2444b077aed3SPierre Pronchery     X509_STORE_set_lookup_crls_cb(st, crls_http_cb);
2445b077aed3SPierre Pronchery }
2446b077aed3SPierre Pronchery 
2447b077aed3SPierre Pronchery #ifndef OPENSSL_NO_SOCK
tls_error_hint(void)2448b077aed3SPierre Pronchery static const char *tls_error_hint(void)
2449b077aed3SPierre Pronchery {
2450b077aed3SPierre Pronchery     unsigned long err = ERR_peek_error();
2451b077aed3SPierre Pronchery 
2452b077aed3SPierre Pronchery     if (ERR_GET_LIB(err) != ERR_LIB_SSL)
2453b077aed3SPierre Pronchery         err = ERR_peek_last_error();
2454b077aed3SPierre Pronchery     if (ERR_GET_LIB(err) != ERR_LIB_SSL)
2455b077aed3SPierre Pronchery         return NULL;
2456b077aed3SPierre Pronchery 
2457b077aed3SPierre Pronchery     switch (ERR_GET_REASON(err)) {
2458b077aed3SPierre Pronchery     case SSL_R_WRONG_VERSION_NUMBER:
2459b077aed3SPierre Pronchery         return "The server does not support (a suitable version of) TLS";
2460b077aed3SPierre Pronchery     case SSL_R_UNKNOWN_PROTOCOL:
2461b077aed3SPierre Pronchery         return "The server does not support HTTPS";
2462b077aed3SPierre Pronchery     case SSL_R_CERTIFICATE_VERIFY_FAILED:
2463b077aed3SPierre Pronchery         return "Cannot authenticate server via its TLS certificate, likely due to mismatch with our trusted TLS certs or missing revocation status";
2464b077aed3SPierre Pronchery     case SSL_AD_REASON_OFFSET + TLS1_AD_UNKNOWN_CA:
2465b077aed3SPierre Pronchery         return "Server did not accept our TLS certificate, likely due to mismatch with server's trust anchor or missing revocation status";
2466b077aed3SPierre Pronchery     case SSL_AD_REASON_OFFSET + SSL3_AD_HANDSHAKE_FAILURE:
2467b077aed3SPierre Pronchery         return "TLS handshake failure. Possibly the server requires our TLS certificate but did not receive it";
2468b077aed3SPierre Pronchery     default: /* no error or no hint available for error */
2469b077aed3SPierre Pronchery         return NULL;
2470b077aed3SPierre Pronchery     }
2471b077aed3SPierre Pronchery }
2472b077aed3SPierre Pronchery 
2473b077aed3SPierre Pronchery /* HTTP callback function that supports TLS connection also via HTTPS proxy */
app_http_tls_cb(BIO * bio,void * arg,int connect,int detail)2474b077aed3SPierre Pronchery BIO *app_http_tls_cb(BIO *bio, void *arg, int connect, int detail)
2475b077aed3SPierre Pronchery {
2476b077aed3SPierre Pronchery     APP_HTTP_TLS_INFO *info = (APP_HTTP_TLS_INFO *)arg;
2477b077aed3SPierre Pronchery     SSL_CTX *ssl_ctx = info->ssl_ctx;
2478b077aed3SPierre Pronchery 
2479b077aed3SPierre Pronchery     if (ssl_ctx == NULL) /* not using TLS */
2480b077aed3SPierre Pronchery         return bio;
2481b077aed3SPierre Pronchery     if (connect) {
2482b077aed3SPierre Pronchery         SSL *ssl;
2483b077aed3SPierre Pronchery         BIO *sbio = NULL;
2484b077aed3SPierre Pronchery         X509_STORE *ts = SSL_CTX_get_cert_store(ssl_ctx);
2485b077aed3SPierre Pronchery         X509_VERIFY_PARAM *vpm = X509_STORE_get0_param(ts);
2486b077aed3SPierre Pronchery         const char *host = vpm == NULL ? NULL :
2487b077aed3SPierre Pronchery             X509_VERIFY_PARAM_get0_host(vpm, 0 /* first hostname */);
2488b077aed3SPierre Pronchery 
2489b077aed3SPierre Pronchery         /* adapt after fixing callback design flaw, see #17088 */
2490b077aed3SPierre Pronchery         if ((info->use_proxy
2491b077aed3SPierre Pronchery              && !OSSL_HTTP_proxy_connect(bio, info->server, info->port,
2492b077aed3SPierre Pronchery                                          NULL, NULL, /* no proxy credentials */
2493b077aed3SPierre Pronchery                                          info->timeout, bio_err, opt_getprog()))
2494b077aed3SPierre Pronchery                 || (sbio = BIO_new(BIO_f_ssl())) == NULL) {
2495b077aed3SPierre Pronchery             return NULL;
2496b077aed3SPierre Pronchery         }
2497b077aed3SPierre Pronchery         if (ssl_ctx == NULL || (ssl = SSL_new(ssl_ctx)) == NULL) {
2498b077aed3SPierre Pronchery             BIO_free(sbio);
2499b077aed3SPierre Pronchery             return NULL;
2500b077aed3SPierre Pronchery         }
2501b077aed3SPierre Pronchery 
2502b077aed3SPierre Pronchery         if (vpm != NULL)
2503b077aed3SPierre Pronchery             SSL_set_tlsext_host_name(ssl, host /* may be NULL */);
2504b077aed3SPierre Pronchery 
2505b077aed3SPierre Pronchery         SSL_set_connect_state(ssl);
2506b077aed3SPierre Pronchery         BIO_set_ssl(sbio, ssl, BIO_CLOSE);
2507b077aed3SPierre Pronchery 
2508b077aed3SPierre Pronchery         bio = BIO_push(sbio, bio);
2509b077aed3SPierre Pronchery     }
2510b077aed3SPierre Pronchery     if (!connect) {
2511b077aed3SPierre Pronchery         const char *hint;
2512b077aed3SPierre Pronchery         BIO *cbio;
2513b077aed3SPierre Pronchery 
2514b077aed3SPierre Pronchery         if (!detail) { /* disconnecting after error */
2515b077aed3SPierre Pronchery             hint = tls_error_hint();
2516b077aed3SPierre Pronchery             if (hint != NULL)
2517b077aed3SPierre Pronchery                 ERR_add_error_data(2, " : ", hint);
2518b077aed3SPierre Pronchery         }
2519b077aed3SPierre Pronchery         if (ssl_ctx != NULL) {
2520b077aed3SPierre Pronchery             (void)ERR_set_mark();
2521b077aed3SPierre Pronchery             BIO_ssl_shutdown(bio);
2522b077aed3SPierre Pronchery             cbio = BIO_pop(bio); /* connect+HTTP BIO */
2523b077aed3SPierre Pronchery             BIO_free(bio); /* SSL BIO */
2524b077aed3SPierre Pronchery             (void)ERR_pop_to_mark(); /* hide SSL_R_READ_BIO_NOT_SET etc. */
2525b077aed3SPierre Pronchery             bio = cbio;
2526b077aed3SPierre Pronchery         }
2527b077aed3SPierre Pronchery     }
2528b077aed3SPierre Pronchery     return bio;
2529b077aed3SPierre Pronchery }
2530b077aed3SPierre Pronchery 
APP_HTTP_TLS_INFO_free(APP_HTTP_TLS_INFO * info)2531b077aed3SPierre Pronchery void APP_HTTP_TLS_INFO_free(APP_HTTP_TLS_INFO *info)
2532b077aed3SPierre Pronchery {
2533b077aed3SPierre Pronchery     if (info != NULL) {
2534b077aed3SPierre Pronchery         SSL_CTX_free(info->ssl_ctx);
2535b077aed3SPierre Pronchery         OPENSSL_free(info);
2536b077aed3SPierre Pronchery     }
2537b077aed3SPierre Pronchery }
2538b077aed3SPierre Pronchery 
app_http_get_asn1(const char * url,const char * proxy,const char * no_proxy,SSL_CTX * ssl_ctx,const STACK_OF (CONF_VALUE)* headers,long timeout,const char * expected_content_type,const ASN1_ITEM * it)2539b077aed3SPierre Pronchery ASN1_VALUE *app_http_get_asn1(const char *url, const char *proxy,
2540b077aed3SPierre Pronchery                               const char *no_proxy, SSL_CTX *ssl_ctx,
2541b077aed3SPierre Pronchery                               const STACK_OF(CONF_VALUE) *headers,
2542b077aed3SPierre Pronchery                               long timeout, const char *expected_content_type,
2543b077aed3SPierre Pronchery                               const ASN1_ITEM *it)
2544b077aed3SPierre Pronchery {
2545b077aed3SPierre Pronchery     APP_HTTP_TLS_INFO info;
2546b077aed3SPierre Pronchery     char *server;
2547b077aed3SPierre Pronchery     char *port;
2548b077aed3SPierre Pronchery     int use_ssl;
2549b077aed3SPierre Pronchery     BIO *mem;
2550b077aed3SPierre Pronchery     ASN1_VALUE *resp = NULL;
2551b077aed3SPierre Pronchery 
2552b077aed3SPierre Pronchery     if (url == NULL || it == NULL) {
2553b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_HTTP, ERR_R_PASSED_NULL_PARAMETER);
2554b077aed3SPierre Pronchery         return NULL;
2555b077aed3SPierre Pronchery     }
2556b077aed3SPierre Pronchery 
2557b077aed3SPierre Pronchery     if (!OSSL_HTTP_parse_url(url, &use_ssl, NULL /* userinfo */, &server, &port,
2558b077aed3SPierre Pronchery                              NULL /* port_num, */, NULL, NULL, NULL))
2559b077aed3SPierre Pronchery         return NULL;
2560b077aed3SPierre Pronchery     if (use_ssl && ssl_ctx == NULL) {
2561b077aed3SPierre Pronchery         ERR_raise_data(ERR_LIB_HTTP, ERR_R_PASSED_NULL_PARAMETER,
2562b077aed3SPierre Pronchery                        "missing SSL_CTX");
2563b077aed3SPierre Pronchery         goto end;
2564b077aed3SPierre Pronchery     }
2565b077aed3SPierre Pronchery     if (!use_ssl && ssl_ctx != NULL) {
2566b077aed3SPierre Pronchery         ERR_raise_data(ERR_LIB_HTTP, ERR_R_PASSED_INVALID_ARGUMENT,
2567b077aed3SPierre Pronchery                        "SSL_CTX given but use_ssl == 0");
2568b077aed3SPierre Pronchery         goto end;
2569b077aed3SPierre Pronchery     }
2570b077aed3SPierre Pronchery 
2571b077aed3SPierre Pronchery     info.server = server;
2572b077aed3SPierre Pronchery     info.port = port;
2573b077aed3SPierre Pronchery     info.use_proxy = /* workaround for callback design flaw, see #17088 */
2574b077aed3SPierre Pronchery         OSSL_HTTP_adapt_proxy(proxy, no_proxy, server, use_ssl) != NULL;
2575b077aed3SPierre Pronchery     info.timeout = timeout;
2576b077aed3SPierre Pronchery     info.ssl_ctx = ssl_ctx;
2577b077aed3SPierre Pronchery     mem = OSSL_HTTP_get(url, proxy, no_proxy, NULL /* bio */, NULL /* rbio */,
2578b077aed3SPierre Pronchery                         app_http_tls_cb, &info, 0 /* buf_size */, headers,
2579b077aed3SPierre Pronchery                         expected_content_type, 1 /* expect_asn1 */,
2580b077aed3SPierre Pronchery                         OSSL_HTTP_DEFAULT_MAX_RESP_LEN, timeout);
2581b077aed3SPierre Pronchery     resp = ASN1_item_d2i_bio(it, mem, NULL);
2582b077aed3SPierre Pronchery     BIO_free(mem);
2583b077aed3SPierre Pronchery 
2584b077aed3SPierre Pronchery  end:
2585b077aed3SPierre Pronchery     OPENSSL_free(server);
2586b077aed3SPierre Pronchery     OPENSSL_free(port);
2587b077aed3SPierre Pronchery     return resp;
2588b077aed3SPierre Pronchery 
2589b077aed3SPierre Pronchery }
2590b077aed3SPierre Pronchery 
app_http_post_asn1(const char * host,const char * port,const char * path,const char * proxy,const char * no_proxy,SSL_CTX * ssl_ctx,const STACK_OF (CONF_VALUE)* headers,const char * content_type,ASN1_VALUE * req,const ASN1_ITEM * req_it,const char * expected_content_type,long timeout,const ASN1_ITEM * rsp_it)2591b077aed3SPierre Pronchery ASN1_VALUE *app_http_post_asn1(const char *host, const char *port,
2592b077aed3SPierre Pronchery                                const char *path, const char *proxy,
2593b077aed3SPierre Pronchery                                const char *no_proxy, SSL_CTX *ssl_ctx,
2594b077aed3SPierre Pronchery                                const STACK_OF(CONF_VALUE) *headers,
2595b077aed3SPierre Pronchery                                const char *content_type,
2596b077aed3SPierre Pronchery                                ASN1_VALUE *req, const ASN1_ITEM *req_it,
2597b077aed3SPierre Pronchery                                const char *expected_content_type,
2598b077aed3SPierre Pronchery                                long timeout, const ASN1_ITEM *rsp_it)
2599b077aed3SPierre Pronchery {
2600b077aed3SPierre Pronchery     int use_ssl = ssl_ctx != NULL;
2601b077aed3SPierre Pronchery     APP_HTTP_TLS_INFO info;
2602b077aed3SPierre Pronchery     BIO *rsp, *req_mem = ASN1_item_i2d_mem_bio(req_it, req);
2603b077aed3SPierre Pronchery     ASN1_VALUE *res;
2604b077aed3SPierre Pronchery 
2605b077aed3SPierre Pronchery     if (req_mem == NULL)
2606b077aed3SPierre Pronchery         return NULL;
2607b077aed3SPierre Pronchery 
2608b077aed3SPierre Pronchery     info.server = host;
2609b077aed3SPierre Pronchery     info.port = port;
2610b077aed3SPierre Pronchery     info.use_proxy = /* workaround for callback design flaw, see #17088 */
2611b077aed3SPierre Pronchery         OSSL_HTTP_adapt_proxy(proxy, no_proxy, host, use_ssl) != NULL;
2612b077aed3SPierre Pronchery     info.timeout = timeout;
2613b077aed3SPierre Pronchery     info.ssl_ctx = ssl_ctx;
2614b077aed3SPierre Pronchery     rsp = OSSL_HTTP_transfer(NULL, host, port, path, use_ssl,
2615b077aed3SPierre Pronchery                              proxy, no_proxy, NULL /* bio */, NULL /* rbio */,
2616b077aed3SPierre Pronchery                              app_http_tls_cb, &info,
2617b077aed3SPierre Pronchery                              0 /* buf_size */, headers, content_type, req_mem,
2618b077aed3SPierre Pronchery                              expected_content_type, 1 /* expect_asn1 */,
2619b077aed3SPierre Pronchery                              OSSL_HTTP_DEFAULT_MAX_RESP_LEN, timeout,
2620b077aed3SPierre Pronchery                              0 /* keep_alive */);
2621b077aed3SPierre Pronchery     BIO_free(req_mem);
2622b077aed3SPierre Pronchery     res = ASN1_item_d2i_bio(rsp_it, rsp, NULL);
2623b077aed3SPierre Pronchery     BIO_free(rsp);
2624b077aed3SPierre Pronchery     return res;
2625b077aed3SPierre Pronchery }
2626b077aed3SPierre Pronchery 
2627b077aed3SPierre Pronchery #endif
2628b077aed3SPierre Pronchery 
2629b077aed3SPierre Pronchery /*
2630b077aed3SPierre Pronchery  * Platform-specific sections
2631b077aed3SPierre Pronchery  */
2632b077aed3SPierre Pronchery #if defined(_WIN32)
2633b077aed3SPierre Pronchery # ifdef fileno
2634b077aed3SPierre Pronchery #  undef fileno
2635b077aed3SPierre Pronchery #  define fileno(a) (int)_fileno(a)
2636b077aed3SPierre Pronchery # endif
2637b077aed3SPierre Pronchery 
2638b077aed3SPierre Pronchery # include <windows.h>
2639b077aed3SPierre Pronchery # include <tchar.h>
2640b077aed3SPierre Pronchery 
WIN32_rename(const char * from,const char * to)2641b077aed3SPierre Pronchery static int WIN32_rename(const char *from, const char *to)
2642b077aed3SPierre Pronchery {
2643b077aed3SPierre Pronchery     TCHAR *tfrom = NULL, *tto;
2644b077aed3SPierre Pronchery     DWORD err;
2645b077aed3SPierre Pronchery     int ret = 0;
2646b077aed3SPierre Pronchery 
2647b077aed3SPierre Pronchery     if (sizeof(TCHAR) == 1) {
2648b077aed3SPierre Pronchery         tfrom = (TCHAR *)from;
2649b077aed3SPierre Pronchery         tto = (TCHAR *)to;
2650b077aed3SPierre Pronchery     } else {                    /* UNICODE path */
2651b077aed3SPierre Pronchery 
2652b077aed3SPierre Pronchery         size_t i, flen = strlen(from) + 1, tlen = strlen(to) + 1;
2653b077aed3SPierre Pronchery         tfrom = malloc(sizeof(*tfrom) * (flen + tlen));
2654b077aed3SPierre Pronchery         if (tfrom == NULL)
2655b077aed3SPierre Pronchery             goto err;
2656b077aed3SPierre Pronchery         tto = tfrom + flen;
2657b077aed3SPierre Pronchery # if !defined(_WIN32_WCE) || _WIN32_WCE>=101
2658b077aed3SPierre Pronchery         if (!MultiByteToWideChar(CP_ACP, 0, from, flen, (WCHAR *)tfrom, flen))
2659b077aed3SPierre Pronchery # endif
2660b077aed3SPierre Pronchery             for (i = 0; i < flen; i++)
2661b077aed3SPierre Pronchery                 tfrom[i] = (TCHAR)from[i];
2662b077aed3SPierre Pronchery # if !defined(_WIN32_WCE) || _WIN32_WCE>=101
2663b077aed3SPierre Pronchery         if (!MultiByteToWideChar(CP_ACP, 0, to, tlen, (WCHAR *)tto, tlen))
2664b077aed3SPierre Pronchery # endif
2665b077aed3SPierre Pronchery             for (i = 0; i < tlen; i++)
2666b077aed3SPierre Pronchery                 tto[i] = (TCHAR)to[i];
2667b077aed3SPierre Pronchery     }
2668b077aed3SPierre Pronchery 
2669b077aed3SPierre Pronchery     if (MoveFile(tfrom, tto))
2670b077aed3SPierre Pronchery         goto ok;
2671b077aed3SPierre Pronchery     err = GetLastError();
2672b077aed3SPierre Pronchery     if (err == ERROR_ALREADY_EXISTS || err == ERROR_FILE_EXISTS) {
2673b077aed3SPierre Pronchery         if (DeleteFile(tto) && MoveFile(tfrom, tto))
2674b077aed3SPierre Pronchery             goto ok;
2675b077aed3SPierre Pronchery         err = GetLastError();
2676b077aed3SPierre Pronchery     }
2677b077aed3SPierre Pronchery     if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
2678b077aed3SPierre Pronchery         errno = ENOENT;
2679b077aed3SPierre Pronchery     else if (err == ERROR_ACCESS_DENIED)
2680b077aed3SPierre Pronchery         errno = EACCES;
2681b077aed3SPierre Pronchery     else
2682b077aed3SPierre Pronchery         errno = EINVAL;         /* we could map more codes... */
2683b077aed3SPierre Pronchery  err:
2684b077aed3SPierre Pronchery     ret = -1;
2685b077aed3SPierre Pronchery  ok:
2686b077aed3SPierre Pronchery     if (tfrom != NULL && tfrom != (TCHAR *)from)
2687b077aed3SPierre Pronchery         free(tfrom);
2688b077aed3SPierre Pronchery     return ret;
2689b077aed3SPierre Pronchery }
2690b077aed3SPierre Pronchery #endif
2691b077aed3SPierre Pronchery 
2692b077aed3SPierre Pronchery /* app_tminterval section */
2693b077aed3SPierre Pronchery #if defined(_WIN32)
app_tminterval(int stop,int usertime)2694b077aed3SPierre Pronchery double app_tminterval(int stop, int usertime)
2695b077aed3SPierre Pronchery {
2696b077aed3SPierre Pronchery     FILETIME now;
2697b077aed3SPierre Pronchery     double ret = 0;
2698b077aed3SPierre Pronchery     static ULARGE_INTEGER tmstart;
2699b077aed3SPierre Pronchery     static int warning = 1;
2700b077aed3SPierre Pronchery # ifdef _WIN32_WINNT
2701b077aed3SPierre Pronchery     static HANDLE proc = NULL;
2702b077aed3SPierre Pronchery 
2703b077aed3SPierre Pronchery     if (proc == NULL) {
2704b077aed3SPierre Pronchery         if (check_winnt())
2705b077aed3SPierre Pronchery             proc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,
2706b077aed3SPierre Pronchery                                GetCurrentProcessId());
2707b077aed3SPierre Pronchery         if (proc == NULL)
2708b077aed3SPierre Pronchery             proc = (HANDLE) - 1;
2709b077aed3SPierre Pronchery     }
2710b077aed3SPierre Pronchery 
2711b077aed3SPierre Pronchery     if (usertime && proc != (HANDLE) - 1) {
2712b077aed3SPierre Pronchery         FILETIME junk;
2713b077aed3SPierre Pronchery         GetProcessTimes(proc, &junk, &junk, &junk, &now);
2714b077aed3SPierre Pronchery     } else
2715b077aed3SPierre Pronchery # endif
2716b077aed3SPierre Pronchery     {
2717b077aed3SPierre Pronchery         SYSTEMTIME systime;
2718b077aed3SPierre Pronchery 
2719b077aed3SPierre Pronchery         if (usertime && warning) {
2720b077aed3SPierre Pronchery             BIO_printf(bio_err, "To get meaningful results, run "
2721b077aed3SPierre Pronchery                        "this program on idle system.\n");
2722b077aed3SPierre Pronchery             warning = 0;
2723b077aed3SPierre Pronchery         }
2724b077aed3SPierre Pronchery         GetSystemTime(&systime);
2725b077aed3SPierre Pronchery         SystemTimeToFileTime(&systime, &now);
2726b077aed3SPierre Pronchery     }
2727b077aed3SPierre Pronchery 
2728b077aed3SPierre Pronchery     if (stop == TM_START) {
2729b077aed3SPierre Pronchery         tmstart.u.LowPart = now.dwLowDateTime;
2730b077aed3SPierre Pronchery         tmstart.u.HighPart = now.dwHighDateTime;
2731b077aed3SPierre Pronchery     } else {
2732b077aed3SPierre Pronchery         ULARGE_INTEGER tmstop;
2733b077aed3SPierre Pronchery 
2734b077aed3SPierre Pronchery         tmstop.u.LowPart = now.dwLowDateTime;
2735b077aed3SPierre Pronchery         tmstop.u.HighPart = now.dwHighDateTime;
2736b077aed3SPierre Pronchery 
2737b077aed3SPierre Pronchery         ret = (__int64)(tmstop.QuadPart - tmstart.QuadPart) * 1e-7;
2738b077aed3SPierre Pronchery     }
2739b077aed3SPierre Pronchery 
2740b077aed3SPierre Pronchery     return ret;
2741b077aed3SPierre Pronchery }
2742b077aed3SPierre Pronchery #elif defined(OPENSSL_SYS_VXWORKS)
2743b077aed3SPierre Pronchery # include <time.h>
2744b077aed3SPierre Pronchery 
app_tminterval(int stop,int usertime)2745b077aed3SPierre Pronchery double app_tminterval(int stop, int usertime)
2746b077aed3SPierre Pronchery {
2747b077aed3SPierre Pronchery     double ret = 0;
2748b077aed3SPierre Pronchery # ifdef CLOCK_REALTIME
2749b077aed3SPierre Pronchery     static struct timespec tmstart;
2750b077aed3SPierre Pronchery     struct timespec now;
2751b077aed3SPierre Pronchery # else
2752b077aed3SPierre Pronchery     static unsigned long tmstart;
2753b077aed3SPierre Pronchery     unsigned long now;
2754b077aed3SPierre Pronchery # endif
2755b077aed3SPierre Pronchery     static int warning = 1;
2756b077aed3SPierre Pronchery 
2757b077aed3SPierre Pronchery     if (usertime && warning) {
2758b077aed3SPierre Pronchery         BIO_printf(bio_err, "To get meaningful results, run "
2759b077aed3SPierre Pronchery                    "this program on idle system.\n");
2760b077aed3SPierre Pronchery         warning = 0;
2761b077aed3SPierre Pronchery     }
2762b077aed3SPierre Pronchery # ifdef CLOCK_REALTIME
2763b077aed3SPierre Pronchery     clock_gettime(CLOCK_REALTIME, &now);
2764b077aed3SPierre Pronchery     if (stop == TM_START)
2765b077aed3SPierre Pronchery         tmstart = now;
2766b077aed3SPierre Pronchery     else
2767b077aed3SPierre Pronchery         ret = ((now.tv_sec + now.tv_nsec * 1e-9)
2768b077aed3SPierre Pronchery                - (tmstart.tv_sec + tmstart.tv_nsec * 1e-9));
2769b077aed3SPierre Pronchery # else
2770b077aed3SPierre Pronchery     now = tickGet();
2771b077aed3SPierre Pronchery     if (stop == TM_START)
2772b077aed3SPierre Pronchery         tmstart = now;
2773b077aed3SPierre Pronchery     else
2774b077aed3SPierre Pronchery         ret = (now - tmstart) / (double)sysClkRateGet();
2775b077aed3SPierre Pronchery # endif
2776b077aed3SPierre Pronchery     return ret;
2777b077aed3SPierre Pronchery }
2778b077aed3SPierre Pronchery 
2779b077aed3SPierre Pronchery #elif defined(_SC_CLK_TCK)      /* by means of unistd.h */
2780b077aed3SPierre Pronchery # include <sys/times.h>
2781b077aed3SPierre Pronchery 
app_tminterval(int stop,int usertime)2782b077aed3SPierre Pronchery double app_tminterval(int stop, int usertime)
2783b077aed3SPierre Pronchery {
2784b077aed3SPierre Pronchery     double ret = 0;
2785b077aed3SPierre Pronchery     struct tms rus;
2786b077aed3SPierre Pronchery     clock_t now = times(&rus);
2787b077aed3SPierre Pronchery     static clock_t tmstart;
2788b077aed3SPierre Pronchery 
2789b077aed3SPierre Pronchery     if (usertime)
2790b077aed3SPierre Pronchery         now = rus.tms_utime;
2791b077aed3SPierre Pronchery 
2792b077aed3SPierre Pronchery     if (stop == TM_START) {
2793b077aed3SPierre Pronchery         tmstart = now;
2794b077aed3SPierre Pronchery     } else {
2795b077aed3SPierre Pronchery         long int tck = sysconf(_SC_CLK_TCK);
2796b077aed3SPierre Pronchery         ret = (now - tmstart) / (double)tck;
2797b077aed3SPierre Pronchery     }
2798b077aed3SPierre Pronchery 
2799b077aed3SPierre Pronchery     return ret;
2800b077aed3SPierre Pronchery }
2801b077aed3SPierre Pronchery 
2802b077aed3SPierre Pronchery #else
2803b077aed3SPierre Pronchery # include <sys/time.h>
2804b077aed3SPierre Pronchery # include <sys/resource.h>
2805b077aed3SPierre Pronchery 
app_tminterval(int stop,int usertime)2806b077aed3SPierre Pronchery double app_tminterval(int stop, int usertime)
2807b077aed3SPierre Pronchery {
2808b077aed3SPierre Pronchery     double ret = 0;
2809b077aed3SPierre Pronchery     struct rusage rus;
2810b077aed3SPierre Pronchery     struct timeval now;
2811b077aed3SPierre Pronchery     static struct timeval tmstart;
2812b077aed3SPierre Pronchery 
2813b077aed3SPierre Pronchery     if (usertime)
2814b077aed3SPierre Pronchery         getrusage(RUSAGE_SELF, &rus), now = rus.ru_utime;
2815b077aed3SPierre Pronchery     else
2816b077aed3SPierre Pronchery         gettimeofday(&now, NULL);
2817b077aed3SPierre Pronchery 
2818b077aed3SPierre Pronchery     if (stop == TM_START)
2819b077aed3SPierre Pronchery         tmstart = now;
2820b077aed3SPierre Pronchery     else
2821b077aed3SPierre Pronchery         ret = ((now.tv_sec + now.tv_usec * 1e-6)
2822b077aed3SPierre Pronchery                - (tmstart.tv_sec + tmstart.tv_usec * 1e-6));
2823b077aed3SPierre Pronchery 
2824b077aed3SPierre Pronchery     return ret;
2825b077aed3SPierre Pronchery }
2826b077aed3SPierre Pronchery #endif
2827b077aed3SPierre Pronchery 
app_access(const char * name,int flag)2828b077aed3SPierre Pronchery int app_access(const char* name, int flag)
2829b077aed3SPierre Pronchery {
2830b077aed3SPierre Pronchery #ifdef _WIN32
2831b077aed3SPierre Pronchery     return _access(name, flag);
2832b077aed3SPierre Pronchery #else
2833b077aed3SPierre Pronchery     return access(name, flag);
2834b077aed3SPierre Pronchery #endif
2835b077aed3SPierre Pronchery }
2836b077aed3SPierre Pronchery 
app_isdir(const char * name)2837b077aed3SPierre Pronchery int app_isdir(const char *name)
2838b077aed3SPierre Pronchery {
2839b077aed3SPierre Pronchery     return opt_isdir(name);
2840b077aed3SPierre Pronchery }
2841b077aed3SPierre Pronchery 
2842b077aed3SPierre Pronchery /* raw_read|write section */
2843b077aed3SPierre Pronchery #if defined(__VMS)
2844b077aed3SPierre Pronchery # include "vms_term_sock.h"
2845b077aed3SPierre Pronchery static int stdin_sock = -1;
2846b077aed3SPierre Pronchery 
close_stdin_sock(void)2847b077aed3SPierre Pronchery static void close_stdin_sock(void)
2848b077aed3SPierre Pronchery {
2849b077aed3SPierre Pronchery     TerminalSocket (TERM_SOCK_DELETE, &stdin_sock);
2850b077aed3SPierre Pronchery }
2851b077aed3SPierre Pronchery 
fileno_stdin(void)2852b077aed3SPierre Pronchery int fileno_stdin(void)
2853b077aed3SPierre Pronchery {
2854b077aed3SPierre Pronchery     if (stdin_sock == -1) {
2855b077aed3SPierre Pronchery         TerminalSocket(TERM_SOCK_CREATE, &stdin_sock);
2856b077aed3SPierre Pronchery         atexit(close_stdin_sock);
2857b077aed3SPierre Pronchery     }
2858b077aed3SPierre Pronchery 
2859b077aed3SPierre Pronchery     return stdin_sock;
2860b077aed3SPierre Pronchery }
2861b077aed3SPierre Pronchery #else
fileno_stdin(void)2862b077aed3SPierre Pronchery int fileno_stdin(void)
2863b077aed3SPierre Pronchery {
2864b077aed3SPierre Pronchery     return fileno(stdin);
2865b077aed3SPierre Pronchery }
2866b077aed3SPierre Pronchery #endif
2867b077aed3SPierre Pronchery 
fileno_stdout(void)2868b077aed3SPierre Pronchery int fileno_stdout(void)
2869b077aed3SPierre Pronchery {
2870b077aed3SPierre Pronchery     return fileno(stdout);
2871b077aed3SPierre Pronchery }
2872b077aed3SPierre Pronchery 
2873b077aed3SPierre Pronchery #if defined(_WIN32) && defined(STD_INPUT_HANDLE)
raw_read_stdin(void * buf,int siz)2874b077aed3SPierre Pronchery int raw_read_stdin(void *buf, int siz)
2875b077aed3SPierre Pronchery {
2876b077aed3SPierre Pronchery     DWORD n;
2877b077aed3SPierre Pronchery     if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), buf, siz, &n, NULL))
2878b077aed3SPierre Pronchery         return n;
2879b077aed3SPierre Pronchery     else
2880b077aed3SPierre Pronchery         return -1;
2881b077aed3SPierre Pronchery }
2882b077aed3SPierre Pronchery #elif defined(__VMS)
2883b077aed3SPierre Pronchery # include <sys/socket.h>
2884b077aed3SPierre Pronchery 
raw_read_stdin(void * buf,int siz)2885b077aed3SPierre Pronchery int raw_read_stdin(void *buf, int siz)
2886b077aed3SPierre Pronchery {
2887b077aed3SPierre Pronchery     return recv(fileno_stdin(), buf, siz, 0);
2888b077aed3SPierre Pronchery }
2889b077aed3SPierre Pronchery #else
2890b077aed3SPierre Pronchery # if defined(__TANDEM)
2891b077aed3SPierre Pronchery #  if defined(OPENSSL_TANDEM_FLOSS)
2892b077aed3SPierre Pronchery #   include <floss.h(floss_read)>
2893b077aed3SPierre Pronchery #  endif
2894b077aed3SPierre Pronchery # endif
raw_read_stdin(void * buf,int siz)2895b077aed3SPierre Pronchery int raw_read_stdin(void *buf, int siz)
2896b077aed3SPierre Pronchery {
2897b077aed3SPierre Pronchery     return read(fileno_stdin(), buf, siz);
2898b077aed3SPierre Pronchery }
2899b077aed3SPierre Pronchery #endif
2900b077aed3SPierre Pronchery 
2901b077aed3SPierre Pronchery #if defined(_WIN32) && defined(STD_OUTPUT_HANDLE)
raw_write_stdout(const void * buf,int siz)2902b077aed3SPierre Pronchery int raw_write_stdout(const void *buf, int siz)
2903b077aed3SPierre Pronchery {
2904b077aed3SPierre Pronchery     DWORD n;
2905b077aed3SPierre Pronchery     if (WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, siz, &n, NULL))
2906b077aed3SPierre Pronchery         return n;
2907b077aed3SPierre Pronchery     else
2908b077aed3SPierre Pronchery         return -1;
2909b077aed3SPierre Pronchery }
2910b077aed3SPierre Pronchery #elif defined(OPENSSL_SYS_TANDEM) && defined(OPENSSL_THREADS) && defined(_SPT_MODEL_)
2911b077aed3SPierre Pronchery # if defined(__TANDEM)
2912b077aed3SPierre Pronchery #  if defined(OPENSSL_TANDEM_FLOSS)
2913b077aed3SPierre Pronchery #   include <floss.h(floss_write)>
2914b077aed3SPierre Pronchery #  endif
2915b077aed3SPierre Pronchery # endif
raw_write_stdout(const void * buf,int siz)2916b077aed3SPierre Pronchery int raw_write_stdout(const void *buf,int siz)
2917b077aed3SPierre Pronchery {
2918b077aed3SPierre Pronchery 	return write(fileno(stdout),(void*)buf,siz);
2919b077aed3SPierre Pronchery }
2920b077aed3SPierre Pronchery #else
2921b077aed3SPierre Pronchery # if defined(__TANDEM)
2922b077aed3SPierre Pronchery #  if defined(OPENSSL_TANDEM_FLOSS)
2923b077aed3SPierre Pronchery #   include <floss.h(floss_write)>
2924b077aed3SPierre Pronchery #  endif
2925b077aed3SPierre Pronchery # endif
raw_write_stdout(const void * buf,int siz)2926b077aed3SPierre Pronchery int raw_write_stdout(const void *buf, int siz)
2927b077aed3SPierre Pronchery {
2928b077aed3SPierre Pronchery     return write(fileno_stdout(), buf, siz);
2929b077aed3SPierre Pronchery }
2930b077aed3SPierre Pronchery #endif
2931b077aed3SPierre Pronchery 
2932b077aed3SPierre Pronchery /*
2933b077aed3SPierre Pronchery  * Centralized handling of input and output files with format specification
2934b077aed3SPierre Pronchery  * The format is meant to show what the input and output is supposed to be,
2935b077aed3SPierre Pronchery  * and is therefore a show of intent more than anything else.  However, it
2936b077aed3SPierre Pronchery  * does impact behavior on some platforms, such as differentiating between
2937b077aed3SPierre Pronchery  * text and binary input/output on non-Unix platforms
2938b077aed3SPierre Pronchery  */
dup_bio_in(int format)2939b077aed3SPierre Pronchery BIO *dup_bio_in(int format)
2940b077aed3SPierre Pronchery {
2941b077aed3SPierre Pronchery     return BIO_new_fp(stdin,
2942b077aed3SPierre Pronchery                       BIO_NOCLOSE | (FMT_istext(format) ? BIO_FP_TEXT : 0));
2943b077aed3SPierre Pronchery }
2944b077aed3SPierre Pronchery 
dup_bio_out(int format)2945b077aed3SPierre Pronchery BIO *dup_bio_out(int format)
2946b077aed3SPierre Pronchery {
2947b077aed3SPierre Pronchery     BIO *b = BIO_new_fp(stdout,
2948b077aed3SPierre Pronchery                         BIO_NOCLOSE | (FMT_istext(format) ? BIO_FP_TEXT : 0));
2949b077aed3SPierre Pronchery     void *prefix = NULL;
2950b077aed3SPierre Pronchery 
2951b077aed3SPierre Pronchery     if (b == NULL)
2952b077aed3SPierre Pronchery         return NULL;
2953b077aed3SPierre Pronchery 
2954b077aed3SPierre Pronchery #ifdef OPENSSL_SYS_VMS
2955b077aed3SPierre Pronchery     if (FMT_istext(format))
2956b077aed3SPierre Pronchery         b = BIO_push(BIO_new(BIO_f_linebuffer()), b);
2957b077aed3SPierre Pronchery #endif
2958b077aed3SPierre Pronchery 
2959b077aed3SPierre Pronchery     if (FMT_istext(format)
2960b077aed3SPierre Pronchery         && (prefix = getenv("HARNESS_OSSL_PREFIX")) != NULL) {
2961b077aed3SPierre Pronchery         b = BIO_push(BIO_new(BIO_f_prefix()), b);
2962b077aed3SPierre Pronchery         BIO_set_prefix(b, prefix);
2963b077aed3SPierre Pronchery     }
2964b077aed3SPierre Pronchery 
2965b077aed3SPierre Pronchery     return b;
2966b077aed3SPierre Pronchery }
2967b077aed3SPierre Pronchery 
dup_bio_err(int format)2968b077aed3SPierre Pronchery BIO *dup_bio_err(int format)
2969b077aed3SPierre Pronchery {
2970b077aed3SPierre Pronchery     BIO *b = BIO_new_fp(stderr,
2971b077aed3SPierre Pronchery                         BIO_NOCLOSE | (FMT_istext(format) ? BIO_FP_TEXT : 0));
2972b077aed3SPierre Pronchery #ifdef OPENSSL_SYS_VMS
2973b077aed3SPierre Pronchery     if (b != NULL && FMT_istext(format))
2974b077aed3SPierre Pronchery         b = BIO_push(BIO_new(BIO_f_linebuffer()), b);
2975b077aed3SPierre Pronchery #endif
2976b077aed3SPierre Pronchery     return b;
2977b077aed3SPierre Pronchery }
2978b077aed3SPierre Pronchery 
unbuffer(FILE * fp)2979b077aed3SPierre Pronchery void unbuffer(FILE *fp)
2980b077aed3SPierre Pronchery {
2981b077aed3SPierre Pronchery /*
2982b077aed3SPierre Pronchery  * On VMS, setbuf() will only take 32-bit pointers, and a compilation
2983b077aed3SPierre Pronchery  * with /POINTER_SIZE=64 will give off a MAYLOSEDATA2 warning here.
2984b077aed3SPierre Pronchery  * However, we trust that the C RTL will never give us a FILE pointer
2985b077aed3SPierre Pronchery  * above the first 4 GB of memory, so we simply turn off the warning
2986b077aed3SPierre Pronchery  * temporarily.
2987b077aed3SPierre Pronchery  */
2988b077aed3SPierre Pronchery #if defined(OPENSSL_SYS_VMS) && defined(__DECC)
2989b077aed3SPierre Pronchery # pragma environment save
2990b077aed3SPierre Pronchery # pragma message disable maylosedata2
2991b077aed3SPierre Pronchery #endif
2992b077aed3SPierre Pronchery     setbuf(fp, NULL);
2993b077aed3SPierre Pronchery #if defined(OPENSSL_SYS_VMS) && defined(__DECC)
2994b077aed3SPierre Pronchery # pragma environment restore
2995b077aed3SPierre Pronchery #endif
2996b077aed3SPierre Pronchery }
2997b077aed3SPierre Pronchery 
modestr(char mode,int format)2998b077aed3SPierre Pronchery static const char *modestr(char mode, int format)
2999b077aed3SPierre Pronchery {
3000b077aed3SPierre Pronchery     OPENSSL_assert(mode == 'a' || mode == 'r' || mode == 'w');
3001b077aed3SPierre Pronchery 
3002b077aed3SPierre Pronchery     switch (mode) {
3003b077aed3SPierre Pronchery     case 'a':
3004b077aed3SPierre Pronchery         return FMT_istext(format) ? "a" : "ab";
3005b077aed3SPierre Pronchery     case 'r':
3006b077aed3SPierre Pronchery         return FMT_istext(format) ? "r" : "rb";
3007b077aed3SPierre Pronchery     case 'w':
3008b077aed3SPierre Pronchery         return FMT_istext(format) ? "w" : "wb";
3009b077aed3SPierre Pronchery     }
3010b077aed3SPierre Pronchery     /* The assert above should make sure we never reach this point */
3011b077aed3SPierre Pronchery     return NULL;
3012b077aed3SPierre Pronchery }
3013b077aed3SPierre Pronchery 
modeverb(char mode)3014b077aed3SPierre Pronchery static const char *modeverb(char mode)
3015b077aed3SPierre Pronchery {
3016b077aed3SPierre Pronchery     switch (mode) {
3017b077aed3SPierre Pronchery     case 'a':
3018b077aed3SPierre Pronchery         return "appending";
3019b077aed3SPierre Pronchery     case 'r':
3020b077aed3SPierre Pronchery         return "reading";
3021b077aed3SPierre Pronchery     case 'w':
3022b077aed3SPierre Pronchery         return "writing";
3023b077aed3SPierre Pronchery     }
3024b077aed3SPierre Pronchery     return "(doing something)";
3025b077aed3SPierre Pronchery }
3026b077aed3SPierre Pronchery 
3027b077aed3SPierre Pronchery /*
3028b077aed3SPierre Pronchery  * Open a file for writing, owner-read-only.
3029b077aed3SPierre Pronchery  */
bio_open_owner(const char * filename,int format,int private)3030b077aed3SPierre Pronchery BIO *bio_open_owner(const char *filename, int format, int private)
3031b077aed3SPierre Pronchery {
3032b077aed3SPierre Pronchery     FILE *fp = NULL;
3033b077aed3SPierre Pronchery     BIO *b = NULL;
3034b077aed3SPierre Pronchery     int textmode, bflags;
3035b077aed3SPierre Pronchery #ifndef OPENSSL_NO_POSIX_IO
3036b077aed3SPierre Pronchery     int fd = -1, mode;
3037b077aed3SPierre Pronchery #endif
3038b077aed3SPierre Pronchery 
3039b077aed3SPierre Pronchery     if (!private || filename == NULL || strcmp(filename, "-") == 0)
3040b077aed3SPierre Pronchery         return bio_open_default(filename, 'w', format);
3041b077aed3SPierre Pronchery 
3042b077aed3SPierre Pronchery     textmode = FMT_istext(format);
3043b077aed3SPierre Pronchery #ifndef OPENSSL_NO_POSIX_IO
3044b077aed3SPierre Pronchery     mode = O_WRONLY;
3045b077aed3SPierre Pronchery # ifdef O_CREAT
3046b077aed3SPierre Pronchery     mode |= O_CREAT;
3047b077aed3SPierre Pronchery # endif
3048b077aed3SPierre Pronchery # ifdef O_TRUNC
3049b077aed3SPierre Pronchery     mode |= O_TRUNC;
3050b077aed3SPierre Pronchery # endif
3051b077aed3SPierre Pronchery     if (!textmode) {
3052b077aed3SPierre Pronchery # ifdef O_BINARY
3053b077aed3SPierre Pronchery         mode |= O_BINARY;
3054b077aed3SPierre Pronchery # elif defined(_O_BINARY)
3055b077aed3SPierre Pronchery         mode |= _O_BINARY;
3056b077aed3SPierre Pronchery # endif
3057b077aed3SPierre Pronchery     }
3058b077aed3SPierre Pronchery 
3059b077aed3SPierre Pronchery # ifdef OPENSSL_SYS_VMS
3060b077aed3SPierre Pronchery     /* VMS doesn't have O_BINARY, it just doesn't make sense.  But,
3061b077aed3SPierre Pronchery      * it still needs to know that we're going binary, or fdopen()
3062b077aed3SPierre Pronchery      * will fail with "invalid argument"...  so we tell VMS what the
3063b077aed3SPierre Pronchery      * context is.
3064b077aed3SPierre Pronchery      */
3065b077aed3SPierre Pronchery     if (!textmode)
3066b077aed3SPierre Pronchery         fd = open(filename, mode, 0600, "ctx=bin");
3067b077aed3SPierre Pronchery     else
3068b077aed3SPierre Pronchery # endif
3069b077aed3SPierre Pronchery         fd = open(filename, mode, 0600);
3070b077aed3SPierre Pronchery     if (fd < 0)
3071b077aed3SPierre Pronchery         goto err;
3072b077aed3SPierre Pronchery     fp = fdopen(fd, modestr('w', format));
3073b077aed3SPierre Pronchery #else   /* OPENSSL_NO_POSIX_IO */
3074b077aed3SPierre Pronchery     /* Have stdio but not Posix IO, do the best we can */
3075b077aed3SPierre Pronchery     fp = fopen(filename, modestr('w', format));
3076b077aed3SPierre Pronchery #endif  /* OPENSSL_NO_POSIX_IO */
3077b077aed3SPierre Pronchery     if (fp == NULL)
3078b077aed3SPierre Pronchery         goto err;
3079b077aed3SPierre Pronchery     bflags = BIO_CLOSE;
3080b077aed3SPierre Pronchery     if (textmode)
3081b077aed3SPierre Pronchery         bflags |= BIO_FP_TEXT;
3082b077aed3SPierre Pronchery     b = BIO_new_fp(fp, bflags);
3083b077aed3SPierre Pronchery     if (b != NULL)
3084b077aed3SPierre Pronchery         return b;
3085b077aed3SPierre Pronchery 
3086b077aed3SPierre Pronchery  err:
3087b077aed3SPierre Pronchery     BIO_printf(bio_err, "%s: Can't open \"%s\" for writing, %s\n",
3088b077aed3SPierre Pronchery                opt_getprog(), filename, strerror(errno));
3089b077aed3SPierre Pronchery     ERR_print_errors(bio_err);
3090b077aed3SPierre Pronchery     /* If we have fp, then fdopen took over fd, so don't close both. */
3091b077aed3SPierre Pronchery     if (fp != NULL)
3092b077aed3SPierre Pronchery         fclose(fp);
3093b077aed3SPierre Pronchery #ifndef OPENSSL_NO_POSIX_IO
3094b077aed3SPierre Pronchery     else if (fd >= 0)
3095b077aed3SPierre Pronchery         close(fd);
3096b077aed3SPierre Pronchery #endif
3097b077aed3SPierre Pronchery     return NULL;
3098b077aed3SPierre Pronchery }
3099b077aed3SPierre Pronchery 
bio_open_default_(const char * filename,char mode,int format,int quiet)3100b077aed3SPierre Pronchery static BIO *bio_open_default_(const char *filename, char mode, int format,
3101b077aed3SPierre Pronchery                               int quiet)
3102b077aed3SPierre Pronchery {
3103b077aed3SPierre Pronchery     BIO *ret;
3104b077aed3SPierre Pronchery 
3105b077aed3SPierre Pronchery     if (filename == NULL || strcmp(filename, "-") == 0) {
3106b077aed3SPierre Pronchery         ret = mode == 'r' ? dup_bio_in(format) : dup_bio_out(format);
3107b077aed3SPierre Pronchery         if (quiet) {
3108b077aed3SPierre Pronchery             ERR_clear_error();
3109b077aed3SPierre Pronchery             return ret;
3110b077aed3SPierre Pronchery         }
3111b077aed3SPierre Pronchery         if (ret != NULL)
3112b077aed3SPierre Pronchery             return ret;
3113b077aed3SPierre Pronchery         BIO_printf(bio_err,
3114b077aed3SPierre Pronchery                    "Can't open %s, %s\n",
3115b077aed3SPierre Pronchery                    mode == 'r' ? "stdin" : "stdout", strerror(errno));
3116b077aed3SPierre Pronchery     } else {
3117b077aed3SPierre Pronchery         ret = BIO_new_file(filename, modestr(mode, format));
3118b077aed3SPierre Pronchery         if (quiet) {
3119b077aed3SPierre Pronchery             ERR_clear_error();
3120b077aed3SPierre Pronchery             return ret;
3121b077aed3SPierre Pronchery         }
3122b077aed3SPierre Pronchery         if (ret != NULL)
3123b077aed3SPierre Pronchery             return ret;
3124b077aed3SPierre Pronchery         BIO_printf(bio_err,
3125b077aed3SPierre Pronchery                    "Can't open \"%s\" for %s, %s\n",
3126b077aed3SPierre Pronchery                    filename, modeverb(mode), strerror(errno));
3127b077aed3SPierre Pronchery     }
3128b077aed3SPierre Pronchery     ERR_print_errors(bio_err);
3129b077aed3SPierre Pronchery     return NULL;
3130b077aed3SPierre Pronchery }
3131b077aed3SPierre Pronchery 
bio_open_default(const char * filename,char mode,int format)3132b077aed3SPierre Pronchery BIO *bio_open_default(const char *filename, char mode, int format)
3133b077aed3SPierre Pronchery {
3134b077aed3SPierre Pronchery     return bio_open_default_(filename, mode, format, 0);
3135b077aed3SPierre Pronchery }
3136b077aed3SPierre Pronchery 
bio_open_default_quiet(const char * filename,char mode,int format)3137b077aed3SPierre Pronchery BIO *bio_open_default_quiet(const char *filename, char mode, int format)
3138b077aed3SPierre Pronchery {
3139b077aed3SPierre Pronchery     return bio_open_default_(filename, mode, format, 1);
3140b077aed3SPierre Pronchery }
3141b077aed3SPierre Pronchery 
wait_for_async(SSL * s)3142b077aed3SPierre Pronchery void wait_for_async(SSL *s)
3143b077aed3SPierre Pronchery {
3144b077aed3SPierre Pronchery     /* On Windows select only works for sockets, so we simply don't wait  */
3145b077aed3SPierre Pronchery #ifndef OPENSSL_SYS_WINDOWS
3146b077aed3SPierre Pronchery     int width = 0;
3147b077aed3SPierre Pronchery     fd_set asyncfds;
3148b077aed3SPierre Pronchery     OSSL_ASYNC_FD *fds;
3149b077aed3SPierre Pronchery     size_t numfds;
3150b077aed3SPierre Pronchery     size_t i;
3151b077aed3SPierre Pronchery 
3152b077aed3SPierre Pronchery     if (!SSL_get_all_async_fds(s, NULL, &numfds))
3153b077aed3SPierre Pronchery         return;
3154b077aed3SPierre Pronchery     if (numfds == 0)
3155b077aed3SPierre Pronchery         return;
3156b077aed3SPierre Pronchery     fds = app_malloc(sizeof(OSSL_ASYNC_FD) * numfds, "allocate async fds");
3157b077aed3SPierre Pronchery     if (!SSL_get_all_async_fds(s, fds, &numfds)) {
3158b077aed3SPierre Pronchery         OPENSSL_free(fds);
3159b077aed3SPierre Pronchery         return;
3160b077aed3SPierre Pronchery     }
3161b077aed3SPierre Pronchery 
3162b077aed3SPierre Pronchery     FD_ZERO(&asyncfds);
3163b077aed3SPierre Pronchery     for (i = 0; i < numfds; i++) {
3164b077aed3SPierre Pronchery         if (width <= (int)fds[i])
3165b077aed3SPierre Pronchery             width = (int)fds[i] + 1;
3166b077aed3SPierre Pronchery         openssl_fdset((int)fds[i], &asyncfds);
3167b077aed3SPierre Pronchery     }
3168b077aed3SPierre Pronchery     select(width, (void *)&asyncfds, NULL, NULL, NULL);
3169b077aed3SPierre Pronchery     OPENSSL_free(fds);
3170b077aed3SPierre Pronchery #endif
3171b077aed3SPierre Pronchery }
3172b077aed3SPierre Pronchery 
3173b077aed3SPierre Pronchery /* if OPENSSL_SYS_WINDOWS is defined then so is OPENSSL_SYS_MSDOS */
3174b077aed3SPierre Pronchery #if defined(OPENSSL_SYS_MSDOS)
has_stdin_waiting(void)3175b077aed3SPierre Pronchery int has_stdin_waiting(void)
3176b077aed3SPierre Pronchery {
3177b077aed3SPierre Pronchery # if defined(OPENSSL_SYS_WINDOWS)
3178b077aed3SPierre Pronchery     HANDLE inhand = GetStdHandle(STD_INPUT_HANDLE);
3179b077aed3SPierre Pronchery     DWORD events = 0;
3180b077aed3SPierre Pronchery     INPUT_RECORD inputrec;
3181b077aed3SPierre Pronchery     DWORD insize = 1;
3182b077aed3SPierre Pronchery     BOOL peeked;
3183b077aed3SPierre Pronchery 
3184b077aed3SPierre Pronchery     if (inhand == INVALID_HANDLE_VALUE) {
3185b077aed3SPierre Pronchery         return 0;
3186b077aed3SPierre Pronchery     }
3187b077aed3SPierre Pronchery 
3188b077aed3SPierre Pronchery     peeked = PeekConsoleInput(inhand, &inputrec, insize, &events);
3189b077aed3SPierre Pronchery     if (!peeked) {
3190b077aed3SPierre Pronchery         /* Probably redirected input? _kbhit() does not work in this case */
3191b077aed3SPierre Pronchery         if (!feof(stdin)) {
3192b077aed3SPierre Pronchery             return 1;
3193b077aed3SPierre Pronchery         }
3194b077aed3SPierre Pronchery         return 0;
3195b077aed3SPierre Pronchery     }
3196b077aed3SPierre Pronchery # endif
3197b077aed3SPierre Pronchery     return _kbhit();
3198b077aed3SPierre Pronchery }
3199b077aed3SPierre Pronchery #endif
3200b077aed3SPierre Pronchery 
3201b077aed3SPierre Pronchery /* Corrupt a signature by modifying final byte */
corrupt_signature(const ASN1_STRING * signature)3202b077aed3SPierre Pronchery void corrupt_signature(const ASN1_STRING *signature)
3203b077aed3SPierre Pronchery {
3204b077aed3SPierre Pronchery         unsigned char *s = signature->data;
3205b077aed3SPierre Pronchery         s[signature->length - 1] ^= 0x1;
3206b077aed3SPierre Pronchery }
3207b077aed3SPierre Pronchery 
set_cert_times(X509 * x,const char * startdate,const char * enddate,int days)3208b077aed3SPierre Pronchery int set_cert_times(X509 *x, const char *startdate, const char *enddate,
3209b077aed3SPierre Pronchery                    int days)
3210b077aed3SPierre Pronchery {
3211b077aed3SPierre Pronchery     if (startdate == NULL || strcmp(startdate, "today") == 0) {
3212b077aed3SPierre Pronchery         if (X509_gmtime_adj(X509_getm_notBefore(x), 0) == NULL)
3213b077aed3SPierre Pronchery             return 0;
3214b077aed3SPierre Pronchery     } else {
3215b077aed3SPierre Pronchery         if (!ASN1_TIME_set_string_X509(X509_getm_notBefore(x), startdate))
3216b077aed3SPierre Pronchery             return 0;
3217b077aed3SPierre Pronchery     }
3218b077aed3SPierre Pronchery     if (enddate == NULL) {
3219b077aed3SPierre Pronchery         if (X509_time_adj_ex(X509_getm_notAfter(x), days, 0, NULL)
3220b077aed3SPierre Pronchery             == NULL)
3221b077aed3SPierre Pronchery             return 0;
3222b077aed3SPierre Pronchery     } else if (!ASN1_TIME_set_string_X509(X509_getm_notAfter(x), enddate)) {
3223b077aed3SPierre Pronchery         return 0;
3224b077aed3SPierre Pronchery     }
3225b077aed3SPierre Pronchery     return 1;
3226b077aed3SPierre Pronchery }
3227b077aed3SPierre Pronchery 
set_crl_lastupdate(X509_CRL * crl,const char * lastupdate)3228b077aed3SPierre Pronchery int set_crl_lastupdate(X509_CRL *crl, const char *lastupdate)
3229b077aed3SPierre Pronchery {
3230b077aed3SPierre Pronchery     int ret = 0;
3231b077aed3SPierre Pronchery     ASN1_TIME *tm = ASN1_TIME_new();
3232b077aed3SPierre Pronchery 
3233b077aed3SPierre Pronchery     if (tm == NULL)
3234b077aed3SPierre Pronchery         goto end;
3235b077aed3SPierre Pronchery 
3236b077aed3SPierre Pronchery     if (lastupdate == NULL) {
3237b077aed3SPierre Pronchery         if (X509_gmtime_adj(tm, 0) == NULL)
3238b077aed3SPierre Pronchery             goto end;
3239b077aed3SPierre Pronchery     } else {
3240b077aed3SPierre Pronchery         if (!ASN1_TIME_set_string_X509(tm, lastupdate))
3241b077aed3SPierre Pronchery             goto end;
3242b077aed3SPierre Pronchery     }
3243b077aed3SPierre Pronchery 
3244b077aed3SPierre Pronchery     if (!X509_CRL_set1_lastUpdate(crl, tm))
3245b077aed3SPierre Pronchery         goto end;
3246b077aed3SPierre Pronchery 
3247b077aed3SPierre Pronchery     ret = 1;
3248b077aed3SPierre Pronchery end:
3249b077aed3SPierre Pronchery     ASN1_TIME_free(tm);
3250b077aed3SPierre Pronchery     return ret;
3251b077aed3SPierre Pronchery }
3252b077aed3SPierre Pronchery 
set_crl_nextupdate(X509_CRL * crl,const char * nextupdate,long days,long hours,long secs)3253b077aed3SPierre Pronchery int set_crl_nextupdate(X509_CRL *crl, const char *nextupdate,
3254b077aed3SPierre Pronchery                        long days, long hours, long secs)
3255b077aed3SPierre Pronchery {
3256b077aed3SPierre Pronchery     int ret = 0;
3257b077aed3SPierre Pronchery     ASN1_TIME *tm = ASN1_TIME_new();
3258b077aed3SPierre Pronchery 
3259b077aed3SPierre Pronchery     if (tm == NULL)
3260b077aed3SPierre Pronchery         goto end;
3261b077aed3SPierre Pronchery 
3262b077aed3SPierre Pronchery     if (nextupdate == NULL) {
3263b077aed3SPierre Pronchery         if (X509_time_adj_ex(tm, days, hours * 60 * 60 + secs, NULL) == NULL)
3264b077aed3SPierre Pronchery             goto end;
3265b077aed3SPierre Pronchery     } else {
3266b077aed3SPierre Pronchery         if (!ASN1_TIME_set_string_X509(tm, nextupdate))
3267b077aed3SPierre Pronchery             goto end;
3268b077aed3SPierre Pronchery     }
3269b077aed3SPierre Pronchery 
3270b077aed3SPierre Pronchery     if (!X509_CRL_set1_nextUpdate(crl, tm))
3271b077aed3SPierre Pronchery         goto end;
3272b077aed3SPierre Pronchery 
3273b077aed3SPierre Pronchery     ret = 1;
3274b077aed3SPierre Pronchery end:
3275b077aed3SPierre Pronchery     ASN1_TIME_free(tm);
3276b077aed3SPierre Pronchery     return ret;
3277b077aed3SPierre Pronchery }
3278b077aed3SPierre Pronchery 
make_uppercase(char * string)3279b077aed3SPierre Pronchery void make_uppercase(char *string)
3280b077aed3SPierre Pronchery {
3281b077aed3SPierre Pronchery     int i;
3282b077aed3SPierre Pronchery 
3283b077aed3SPierre Pronchery     for (i = 0; string[i] != '\0'; i++)
3284b077aed3SPierre Pronchery         string[i] = toupper((unsigned char)string[i]);
3285b077aed3SPierre Pronchery }
3286b077aed3SPierre Pronchery 
3287b077aed3SPierre Pronchery /* This function is defined here due to visibility of bio_err */
opt_printf_stderr(const char * fmt,...)3288b077aed3SPierre Pronchery int opt_printf_stderr(const char *fmt, ...)
3289b077aed3SPierre Pronchery {
3290b077aed3SPierre Pronchery     va_list ap;
3291b077aed3SPierre Pronchery     int ret;
3292b077aed3SPierre Pronchery 
3293b077aed3SPierre Pronchery     va_start(ap, fmt);
3294b077aed3SPierre Pronchery     ret = BIO_vprintf(bio_err, fmt, ap);
3295b077aed3SPierre Pronchery     va_end(ap);
3296b077aed3SPierre Pronchery     return ret;
3297b077aed3SPierre Pronchery }
3298b077aed3SPierre Pronchery 
app_params_new_from_opts(STACK_OF (OPENSSL_STRING)* opts,const OSSL_PARAM * paramdefs)3299b077aed3SPierre Pronchery OSSL_PARAM *app_params_new_from_opts(STACK_OF(OPENSSL_STRING) *opts,
3300b077aed3SPierre Pronchery                                      const OSSL_PARAM *paramdefs)
3301b077aed3SPierre Pronchery {
3302b077aed3SPierre Pronchery     OSSL_PARAM *params = NULL;
3303b077aed3SPierre Pronchery     size_t sz = (size_t)sk_OPENSSL_STRING_num(opts);
3304b077aed3SPierre Pronchery     size_t params_n;
3305b077aed3SPierre Pronchery     char *opt = "", *stmp, *vtmp = NULL;
3306b077aed3SPierre Pronchery     int found = 1;
3307b077aed3SPierre Pronchery 
3308b077aed3SPierre Pronchery     if (opts == NULL)
3309b077aed3SPierre Pronchery         return NULL;
3310b077aed3SPierre Pronchery 
3311b077aed3SPierre Pronchery     params = OPENSSL_zalloc(sizeof(OSSL_PARAM) * (sz + 1));
3312b077aed3SPierre Pronchery     if (params == NULL)
3313b077aed3SPierre Pronchery         return NULL;
3314b077aed3SPierre Pronchery 
3315b077aed3SPierre Pronchery     for (params_n = 0; params_n < sz; params_n++) {
3316b077aed3SPierre Pronchery         opt = sk_OPENSSL_STRING_value(opts, (int)params_n);
3317b077aed3SPierre Pronchery         if ((stmp = OPENSSL_strdup(opt)) == NULL
3318b077aed3SPierre Pronchery             || (vtmp = strchr(stmp, ':')) == NULL)
3319b077aed3SPierre Pronchery             goto err;
3320b077aed3SPierre Pronchery         /* Replace ':' with 0 to terminate the string pointed to by stmp */
3321b077aed3SPierre Pronchery         *vtmp = 0;
3322b077aed3SPierre Pronchery         /* Skip over the separator so that vmtp points to the value */
3323b077aed3SPierre Pronchery         vtmp++;
3324b077aed3SPierre Pronchery         if (!OSSL_PARAM_allocate_from_text(&params[params_n], paramdefs,
3325b077aed3SPierre Pronchery                                            stmp, vtmp, strlen(vtmp), &found))
3326b077aed3SPierre Pronchery             goto err;
3327b077aed3SPierre Pronchery         OPENSSL_free(stmp);
3328b077aed3SPierre Pronchery     }
3329b077aed3SPierre Pronchery     params[params_n] = OSSL_PARAM_construct_end();
3330b077aed3SPierre Pronchery     return params;
3331b077aed3SPierre Pronchery err:
3332b077aed3SPierre Pronchery     OPENSSL_free(stmp);
3333b077aed3SPierre Pronchery     BIO_printf(bio_err, "Parameter %s '%s'\n", found ? "error" : "unknown",
3334b077aed3SPierre Pronchery                opt);
3335b077aed3SPierre Pronchery     ERR_print_errors(bio_err);
3336b077aed3SPierre Pronchery     app_params_free(params);
3337b077aed3SPierre Pronchery     return NULL;
3338b077aed3SPierre Pronchery }
3339b077aed3SPierre Pronchery 
app_params_free(OSSL_PARAM * params)3340b077aed3SPierre Pronchery void app_params_free(OSSL_PARAM *params)
3341b077aed3SPierre Pronchery {
3342b077aed3SPierre Pronchery     int i;
3343b077aed3SPierre Pronchery 
3344b077aed3SPierre Pronchery     if (params != NULL) {
3345b077aed3SPierre Pronchery         for (i = 0; params[i].key != NULL; ++i)
3346b077aed3SPierre Pronchery             OPENSSL_free(params[i].data);
3347b077aed3SPierre Pronchery         OPENSSL_free(params);
3348b077aed3SPierre Pronchery     }
3349b077aed3SPierre Pronchery }
3350b077aed3SPierre Pronchery 
app_keygen(EVP_PKEY_CTX * ctx,const char * alg,int bits,int verbose)3351b077aed3SPierre Pronchery EVP_PKEY *app_keygen(EVP_PKEY_CTX *ctx, const char *alg, int bits, int verbose)
3352b077aed3SPierre Pronchery {
3353b077aed3SPierre Pronchery     EVP_PKEY *res = NULL;
3354b077aed3SPierre Pronchery 
3355b077aed3SPierre Pronchery     if (verbose && alg != NULL) {
3356b077aed3SPierre Pronchery         BIO_printf(bio_err, "Generating %s key", alg);
3357b077aed3SPierre Pronchery         if (bits > 0)
3358b077aed3SPierre Pronchery             BIO_printf(bio_err, " with %d bits\n", bits);
3359b077aed3SPierre Pronchery         else
3360b077aed3SPierre Pronchery             BIO_printf(bio_err, "\n");
3361b077aed3SPierre Pronchery     }
3362b077aed3SPierre Pronchery     if (!RAND_status())
3363b077aed3SPierre Pronchery         BIO_printf(bio_err, "Warning: generating random key material may take a long time\n"
3364b077aed3SPierre Pronchery                    "if the system has a poor entropy source\n");
3365b077aed3SPierre Pronchery     if (EVP_PKEY_keygen(ctx, &res) <= 0)
3366*ad991e4cSEd Maste         BIO_printf(bio_err, "%s: Error generating %s key\n", opt_getprog(),
3367b077aed3SPierre Pronchery                    alg != NULL ? alg : "asymmetric");
3368b077aed3SPierre Pronchery     return res;
3369b077aed3SPierre Pronchery }
3370b077aed3SPierre Pronchery 
app_paramgen(EVP_PKEY_CTX * ctx,const char * alg)3371b077aed3SPierre Pronchery EVP_PKEY *app_paramgen(EVP_PKEY_CTX *ctx, const char *alg)
3372b077aed3SPierre Pronchery {
3373b077aed3SPierre Pronchery     EVP_PKEY *res = NULL;
3374b077aed3SPierre Pronchery 
3375b077aed3SPierre Pronchery     if (!RAND_status())
3376b077aed3SPierre Pronchery         BIO_printf(bio_err, "Warning: generating random key parameters may take a long time\n"
3377b077aed3SPierre Pronchery                    "if the system has a poor entropy source\n");
3378b077aed3SPierre Pronchery     if (EVP_PKEY_paramgen(ctx, &res) <= 0)
3379*ad991e4cSEd Maste         BIO_printf(bio_err, "%s: Generating %s key parameters failed\n",
3380b077aed3SPierre Pronchery                    opt_getprog(), alg != NULL ? alg : "asymmetric");
3381b077aed3SPierre Pronchery     return res;
3382b077aed3SPierre Pronchery }
3383b077aed3SPierre Pronchery 
3384b077aed3SPierre Pronchery /*
3385b077aed3SPierre Pronchery  * Return non-zero if the legacy path is still an option.
3386b077aed3SPierre Pronchery  * This decision is based on the global command line operations and the
3387b077aed3SPierre Pronchery  * behaviour thus far.
3388b077aed3SPierre Pronchery  */
opt_legacy_okay(void)3389b077aed3SPierre Pronchery int opt_legacy_okay(void)
3390b077aed3SPierre Pronchery {
3391b077aed3SPierre Pronchery     int provider_options = opt_provider_option_given();
3392b077aed3SPierre Pronchery     int libctx = app_get0_libctx() != NULL || app_get0_propq() != NULL;
3393b077aed3SPierre Pronchery     /*
3394b077aed3SPierre Pronchery      * Having a provider option specified or a custom library context or
3395b077aed3SPierre Pronchery      * property query, is a sure sign we're not using legacy.
3396b077aed3SPierre Pronchery      */
3397b077aed3SPierre Pronchery     if (provider_options || libctx)
3398b077aed3SPierre Pronchery         return 0;
3399b077aed3SPierre Pronchery     return 1;
3400b077aed3SPierre Pronchery }
3401