xref: /freebsd/crypto/openssl/apps/storeutl.c (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
1e71b7053SJung-uk Kim /*
2*b077aed3SPierre Pronchery  * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
3e71b7053SJung-uk Kim  *
4*b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5e71b7053SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
6e71b7053SJung-uk Kim  * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim  * https://www.openssl.org/source/license.html
8e71b7053SJung-uk Kim  */
9e71b7053SJung-uk Kim 
10e71b7053SJung-uk Kim #include <openssl/opensslconf.h>
11e71b7053SJung-uk Kim 
12e71b7053SJung-uk Kim #include "apps.h"
13e71b7053SJung-uk Kim #include "progs.h"
14e71b7053SJung-uk Kim #include <openssl/err.h>
15e71b7053SJung-uk Kim #include <openssl/pem.h>
16e71b7053SJung-uk Kim #include <openssl/store.h>
17e71b7053SJung-uk Kim #include <openssl/x509v3.h>      /* s2i_ASN1_INTEGER */
18e71b7053SJung-uk Kim 
19e71b7053SJung-uk Kim static int process(const char *uri, const UI_METHOD *uimeth, PW_CB_DATA *uidata,
20e71b7053SJung-uk Kim                    int expected, int criterion, OSSL_STORE_SEARCH *search,
21e71b7053SJung-uk Kim                    int text, int noout, int recursive, int indent, BIO *out,
22*b077aed3SPierre Pronchery                    const char *prog, OSSL_LIB_CTX *libctx);
23e71b7053SJung-uk Kim 
24e71b7053SJung-uk Kim typedef enum OPTION_choice {
25*b077aed3SPierre Pronchery     OPT_COMMON,
26*b077aed3SPierre Pronchery     OPT_ENGINE, OPT_OUT, OPT_PASSIN,
27e71b7053SJung-uk Kim     OPT_NOOUT, OPT_TEXT, OPT_RECURSIVE,
28e71b7053SJung-uk Kim     OPT_SEARCHFOR_CERTS, OPT_SEARCHFOR_KEYS, OPT_SEARCHFOR_CRLS,
29e71b7053SJung-uk Kim     OPT_CRITERION_SUBJECT, OPT_CRITERION_ISSUER, OPT_CRITERION_SERIAL,
30e71b7053SJung-uk Kim     OPT_CRITERION_FINGERPRINT, OPT_CRITERION_ALIAS,
31*b077aed3SPierre Pronchery     OPT_MD, OPT_PROV_ENUM
32e71b7053SJung-uk Kim } OPTION_CHOICE;
33e71b7053SJung-uk Kim 
34e71b7053SJung-uk Kim const OPTIONS storeutl_options[] = {
35*b077aed3SPierre Pronchery     {OPT_HELP_STR, 1, '-', "Usage: %s [options] uri\n"},
36*b077aed3SPierre Pronchery 
37*b077aed3SPierre Pronchery     OPT_SECTION("General"),
38e71b7053SJung-uk Kim     {"help", OPT_HELP, '-', "Display this summary"},
39*b077aed3SPierre Pronchery     {"", OPT_MD, '-', "Any supported digest"},
40*b077aed3SPierre Pronchery #ifndef OPENSSL_NO_ENGINE
41*b077aed3SPierre Pronchery     {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
42*b077aed3SPierre Pronchery #endif
43*b077aed3SPierre Pronchery 
44*b077aed3SPierre Pronchery     OPT_SECTION("Search"),
45e71b7053SJung-uk Kim     {"certs", OPT_SEARCHFOR_CERTS, '-', "Search for certificates only"},
46e71b7053SJung-uk Kim     {"keys", OPT_SEARCHFOR_KEYS, '-', "Search for keys only"},
47e71b7053SJung-uk Kim     {"crls", OPT_SEARCHFOR_CRLS, '-', "Search for CRLs only"},
48e71b7053SJung-uk Kim     {"subject", OPT_CRITERION_SUBJECT, 's', "Search by subject"},
49e71b7053SJung-uk Kim     {"issuer", OPT_CRITERION_ISSUER, 's', "Search by issuer and serial, issuer name"},
50e71b7053SJung-uk Kim     {"serial", OPT_CRITERION_SERIAL, 's', "Search by issuer and serial, serial number"},
51e71b7053SJung-uk Kim     {"fingerprint", OPT_CRITERION_FINGERPRINT, 's', "Search by public key fingerprint, given in hex"},
52e71b7053SJung-uk Kim     {"alias", OPT_CRITERION_ALIAS, 's', "Search by alias"},
53e71b7053SJung-uk Kim     {"r", OPT_RECURSIVE, '-', "Recurse through names"},
54*b077aed3SPierre Pronchery 
55*b077aed3SPierre Pronchery     OPT_SECTION("Input"),
56*b077aed3SPierre Pronchery     {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
57*b077aed3SPierre Pronchery 
58*b077aed3SPierre Pronchery     OPT_SECTION("Output"),
59*b077aed3SPierre Pronchery     {"out", OPT_OUT, '>', "Output file - default stdout"},
60*b077aed3SPierre Pronchery     {"text", OPT_TEXT, '-', "Print a text form of the objects"},
61*b077aed3SPierre Pronchery     {"noout", OPT_NOOUT, '-', "No PEM output, just status"},
62*b077aed3SPierre Pronchery 
63*b077aed3SPierre Pronchery     OPT_PROV_OPTIONS,
64*b077aed3SPierre Pronchery 
65*b077aed3SPierre Pronchery     OPT_PARAMETERS(),
66*b077aed3SPierre Pronchery     {"uri", 0, 0, "URI of the store object"},
67e71b7053SJung-uk Kim     {NULL}
68e71b7053SJung-uk Kim };
69e71b7053SJung-uk Kim 
storeutl_main(int argc,char * argv[])70e71b7053SJung-uk Kim int storeutl_main(int argc, char *argv[])
71e71b7053SJung-uk Kim {
72e71b7053SJung-uk Kim     int ret = 1, noout = 0, text = 0, recursive = 0;
73e71b7053SJung-uk Kim     char *outfile = NULL, *passin = NULL, *passinarg = NULL;
74e71b7053SJung-uk Kim     BIO *out = NULL;
75e71b7053SJung-uk Kim     ENGINE *e = NULL;
76e71b7053SJung-uk Kim     OPTION_CHOICE o;
77e71b7053SJung-uk Kim     char *prog = opt_init(argc, argv, storeutl_options);
78e71b7053SJung-uk Kim     PW_CB_DATA pw_cb_data;
79e71b7053SJung-uk Kim     int expected = 0;
80e71b7053SJung-uk Kim     int criterion = 0;
81e71b7053SJung-uk Kim     X509_NAME *subject = NULL, *issuer = NULL;
82e71b7053SJung-uk Kim     ASN1_INTEGER *serial = NULL;
83e71b7053SJung-uk Kim     unsigned char *fingerprint = NULL;
84e71b7053SJung-uk Kim     size_t fingerprintlen = 0;
85*b077aed3SPierre Pronchery     char *alias = NULL, *digestname = NULL;
86e71b7053SJung-uk Kim     OSSL_STORE_SEARCH *search = NULL;
87*b077aed3SPierre Pronchery     EVP_MD *digest = NULL;
88*b077aed3SPierre Pronchery     OSSL_LIB_CTX *libctx = app_get0_libctx();
89e71b7053SJung-uk Kim 
90e71b7053SJung-uk Kim     while ((o = opt_next()) != OPT_EOF) {
91e71b7053SJung-uk Kim         switch (o) {
92e71b7053SJung-uk Kim         case OPT_EOF:
93e71b7053SJung-uk Kim         case OPT_ERR:
94e71b7053SJung-uk Kim  opthelp:
95e71b7053SJung-uk Kim             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
96e71b7053SJung-uk Kim             goto end;
97e71b7053SJung-uk Kim         case OPT_HELP:
98e71b7053SJung-uk Kim             opt_help(storeutl_options);
99e71b7053SJung-uk Kim             ret = 0;
100e71b7053SJung-uk Kim             goto end;
101e71b7053SJung-uk Kim         case OPT_OUT:
102e71b7053SJung-uk Kim             outfile = opt_arg();
103e71b7053SJung-uk Kim             break;
104e71b7053SJung-uk Kim         case OPT_PASSIN:
105e71b7053SJung-uk Kim             passinarg = opt_arg();
106e71b7053SJung-uk Kim             break;
107e71b7053SJung-uk Kim         case OPT_NOOUT:
108e71b7053SJung-uk Kim             noout = 1;
109e71b7053SJung-uk Kim             break;
110e71b7053SJung-uk Kim         case OPT_TEXT:
111e71b7053SJung-uk Kim             text = 1;
112e71b7053SJung-uk Kim             break;
113e71b7053SJung-uk Kim         case OPT_RECURSIVE:
114e71b7053SJung-uk Kim             recursive = 1;
115e71b7053SJung-uk Kim             break;
116e71b7053SJung-uk Kim         case OPT_SEARCHFOR_CERTS:
117e71b7053SJung-uk Kim         case OPT_SEARCHFOR_KEYS:
118e71b7053SJung-uk Kim         case OPT_SEARCHFOR_CRLS:
119e71b7053SJung-uk Kim             if (expected != 0) {
120e71b7053SJung-uk Kim                 BIO_printf(bio_err, "%s: only one search type can be given.\n",
121e71b7053SJung-uk Kim                            prog);
122e71b7053SJung-uk Kim                 goto end;
123e71b7053SJung-uk Kim             }
124e71b7053SJung-uk Kim             {
125e71b7053SJung-uk Kim                 static const struct {
126e71b7053SJung-uk Kim                     enum OPTION_choice choice;
127e71b7053SJung-uk Kim                     int type;
128e71b7053SJung-uk Kim                 } map[] = {
129e71b7053SJung-uk Kim                     {OPT_SEARCHFOR_CERTS, OSSL_STORE_INFO_CERT},
130e71b7053SJung-uk Kim                     {OPT_SEARCHFOR_KEYS, OSSL_STORE_INFO_PKEY},
131e71b7053SJung-uk Kim                     {OPT_SEARCHFOR_CRLS, OSSL_STORE_INFO_CRL},
132e71b7053SJung-uk Kim                 };
133e71b7053SJung-uk Kim                 size_t i;
134e71b7053SJung-uk Kim 
135e71b7053SJung-uk Kim                 for (i = 0; i < OSSL_NELEM(map); i++) {
136e71b7053SJung-uk Kim                     if (o == map[i].choice) {
137e71b7053SJung-uk Kim                         expected = map[i].type;
138e71b7053SJung-uk Kim                         break;
139e71b7053SJung-uk Kim                     }
140e71b7053SJung-uk Kim                 }
141e71b7053SJung-uk Kim                 /*
142e71b7053SJung-uk Kim                  * If expected wasn't set at this point, it means the map
143da327cd2SJung-uk Kim                  * isn't synchronised with the possible options leading here.
144e71b7053SJung-uk Kim                  */
145e71b7053SJung-uk Kim                 OPENSSL_assert(expected != 0);
146e71b7053SJung-uk Kim             }
147e71b7053SJung-uk Kim             break;
148e71b7053SJung-uk Kim         case OPT_CRITERION_SUBJECT:
149e71b7053SJung-uk Kim             if (criterion != 0) {
150e71b7053SJung-uk Kim                 BIO_printf(bio_err, "%s: criterion already given.\n",
151e71b7053SJung-uk Kim                            prog);
152e71b7053SJung-uk Kim                 goto end;
153e71b7053SJung-uk Kim             }
154e71b7053SJung-uk Kim             criterion = OSSL_STORE_SEARCH_BY_NAME;
155e71b7053SJung-uk Kim             if (subject != NULL) {
156e71b7053SJung-uk Kim                 BIO_printf(bio_err, "%s: subject already given.\n",
157e71b7053SJung-uk Kim                            prog);
158e71b7053SJung-uk Kim                 goto end;
159e71b7053SJung-uk Kim             }
160*b077aed3SPierre Pronchery             subject = parse_name(opt_arg(), MBSTRING_UTF8, 1, "subject");
161*b077aed3SPierre Pronchery             if (subject == NULL)
162e71b7053SJung-uk Kim                 goto end;
163e71b7053SJung-uk Kim             break;
164e71b7053SJung-uk Kim         case OPT_CRITERION_ISSUER:
165e71b7053SJung-uk Kim             if (criterion != 0
166*b077aed3SPierre Pronchery                 && criterion != OSSL_STORE_SEARCH_BY_ISSUER_SERIAL) {
167e71b7053SJung-uk Kim                 BIO_printf(bio_err, "%s: criterion already given.\n",
168e71b7053SJung-uk Kim                            prog);
169e71b7053SJung-uk Kim                 goto end;
170e71b7053SJung-uk Kim             }
171e71b7053SJung-uk Kim             criterion = OSSL_STORE_SEARCH_BY_ISSUER_SERIAL;
172e71b7053SJung-uk Kim             if (issuer != NULL) {
173e71b7053SJung-uk Kim                 BIO_printf(bio_err, "%s: issuer already given.\n",
174e71b7053SJung-uk Kim                            prog);
175e71b7053SJung-uk Kim                 goto end;
176e71b7053SJung-uk Kim             }
177*b077aed3SPierre Pronchery             issuer = parse_name(opt_arg(), MBSTRING_UTF8, 1, "issuer");
178*b077aed3SPierre Pronchery             if (issuer == NULL)
179e71b7053SJung-uk Kim                 goto end;
180e71b7053SJung-uk Kim             break;
181e71b7053SJung-uk Kim         case OPT_CRITERION_SERIAL:
182e71b7053SJung-uk Kim             if (criterion != 0
183*b077aed3SPierre Pronchery                 && criterion != OSSL_STORE_SEARCH_BY_ISSUER_SERIAL) {
184e71b7053SJung-uk Kim                 BIO_printf(bio_err, "%s: criterion already given.\n",
185e71b7053SJung-uk Kim                            prog);
186e71b7053SJung-uk Kim                 goto end;
187e71b7053SJung-uk Kim             }
188e71b7053SJung-uk Kim             criterion = OSSL_STORE_SEARCH_BY_ISSUER_SERIAL;
189e71b7053SJung-uk Kim             if (serial != NULL) {
190e71b7053SJung-uk Kim                 BIO_printf(bio_err, "%s: serial number already given.\n",
191e71b7053SJung-uk Kim                            prog);
192e71b7053SJung-uk Kim                 goto end;
193e71b7053SJung-uk Kim             }
194e71b7053SJung-uk Kim             if ((serial = s2i_ASN1_INTEGER(NULL, opt_arg())) == NULL) {
195e71b7053SJung-uk Kim                 BIO_printf(bio_err, "%s: can't parse serial number argument.\n",
196e71b7053SJung-uk Kim                            prog);
197e71b7053SJung-uk Kim                 goto end;
198e71b7053SJung-uk Kim             }
199e71b7053SJung-uk Kim             break;
200e71b7053SJung-uk Kim         case OPT_CRITERION_FINGERPRINT:
201e71b7053SJung-uk Kim             if (criterion != 0
202e71b7053SJung-uk Kim                 || (criterion == OSSL_STORE_SEARCH_BY_KEY_FINGERPRINT
203e71b7053SJung-uk Kim                     && fingerprint != NULL)) {
204e71b7053SJung-uk Kim                 BIO_printf(bio_err, "%s: criterion already given.\n",
205e71b7053SJung-uk Kim                            prog);
206e71b7053SJung-uk Kim                 goto end;
207e71b7053SJung-uk Kim             }
208e71b7053SJung-uk Kim             criterion = OSSL_STORE_SEARCH_BY_KEY_FINGERPRINT;
209e71b7053SJung-uk Kim             if (fingerprint != NULL) {
210e71b7053SJung-uk Kim                 BIO_printf(bio_err, "%s: fingerprint already given.\n",
211e71b7053SJung-uk Kim                            prog);
212e71b7053SJung-uk Kim                 goto end;
213e71b7053SJung-uk Kim             }
214e71b7053SJung-uk Kim             {
215e71b7053SJung-uk Kim                 long tmplen = 0;
216e71b7053SJung-uk Kim 
217e71b7053SJung-uk Kim                 if ((fingerprint = OPENSSL_hexstr2buf(opt_arg(), &tmplen))
218e71b7053SJung-uk Kim                     == NULL) {
219e71b7053SJung-uk Kim                     BIO_printf(bio_err,
220e71b7053SJung-uk Kim                                "%s: can't parse fingerprint argument.\n",
221e71b7053SJung-uk Kim                                prog);
222e71b7053SJung-uk Kim                     goto end;
223e71b7053SJung-uk Kim                 }
224e71b7053SJung-uk Kim                 fingerprintlen = (size_t)tmplen;
225e71b7053SJung-uk Kim             }
226e71b7053SJung-uk Kim             break;
227e71b7053SJung-uk Kim         case OPT_CRITERION_ALIAS:
228e71b7053SJung-uk Kim             if (criterion != 0) {
229e71b7053SJung-uk Kim                 BIO_printf(bio_err, "%s: criterion already given.\n",
230e71b7053SJung-uk Kim                            prog);
231e71b7053SJung-uk Kim                 goto end;
232e71b7053SJung-uk Kim             }
233e71b7053SJung-uk Kim             criterion = OSSL_STORE_SEARCH_BY_ALIAS;
234e71b7053SJung-uk Kim             if (alias != NULL) {
235e71b7053SJung-uk Kim                 BIO_printf(bio_err, "%s: alias already given.\n",
236e71b7053SJung-uk Kim                            prog);
237e71b7053SJung-uk Kim                 goto end;
238e71b7053SJung-uk Kim             }
239e71b7053SJung-uk Kim             if ((alias = OPENSSL_strdup(opt_arg())) == NULL) {
240e71b7053SJung-uk Kim                 BIO_printf(bio_err, "%s: can't parse alias argument.\n",
241e71b7053SJung-uk Kim                            prog);
242e71b7053SJung-uk Kim                 goto end;
243e71b7053SJung-uk Kim             }
244e71b7053SJung-uk Kim             break;
245e71b7053SJung-uk Kim         case OPT_ENGINE:
246e71b7053SJung-uk Kim             e = setup_engine(opt_arg(), 0);
247e71b7053SJung-uk Kim             break;
248e71b7053SJung-uk Kim         case OPT_MD:
249*b077aed3SPierre Pronchery             digestname = opt_unknown();
250*b077aed3SPierre Pronchery             break;
251*b077aed3SPierre Pronchery         case OPT_PROV_CASES:
252*b077aed3SPierre Pronchery             if (!opt_provider(o))
253*b077aed3SPierre Pronchery                 goto end;
254*b077aed3SPierre Pronchery             break;
255e71b7053SJung-uk Kim         }
256e71b7053SJung-uk Kim     }
257*b077aed3SPierre Pronchery 
258*b077aed3SPierre Pronchery     /* One argument, the URI */
259e71b7053SJung-uk Kim     argc = opt_num_rest();
260e71b7053SJung-uk Kim     argv = opt_rest();
261*b077aed3SPierre Pronchery     if (argc != 1)
262e71b7053SJung-uk Kim         goto opthelp;
263*b077aed3SPierre Pronchery 
264*b077aed3SPierre Pronchery     if (digestname != NULL) {
265*b077aed3SPierre Pronchery         if (!opt_md(digestname, &digest))
266e71b7053SJung-uk Kim             goto opthelp;
267e71b7053SJung-uk Kim     }
268e71b7053SJung-uk Kim 
269e71b7053SJung-uk Kim     if (criterion != 0) {
270e71b7053SJung-uk Kim         switch (criterion) {
271e71b7053SJung-uk Kim         case OSSL_STORE_SEARCH_BY_NAME:
272e71b7053SJung-uk Kim             if ((search = OSSL_STORE_SEARCH_by_name(subject)) == NULL) {
273e71b7053SJung-uk Kim                 ERR_print_errors(bio_err);
274e71b7053SJung-uk Kim                 goto end;
275e71b7053SJung-uk Kim             }
276e71b7053SJung-uk Kim             break;
277e71b7053SJung-uk Kim         case OSSL_STORE_SEARCH_BY_ISSUER_SERIAL:
278e71b7053SJung-uk Kim             if (issuer == NULL || serial == NULL) {
279e71b7053SJung-uk Kim                 BIO_printf(bio_err,
280e71b7053SJung-uk Kim                            "%s: both -issuer and -serial must be given.\n",
281e71b7053SJung-uk Kim                            prog);
282e71b7053SJung-uk Kim                 goto end;
283e71b7053SJung-uk Kim             }
284e71b7053SJung-uk Kim             if ((search = OSSL_STORE_SEARCH_by_issuer_serial(issuer, serial))
285e71b7053SJung-uk Kim                 == NULL) {
286e71b7053SJung-uk Kim                 ERR_print_errors(bio_err);
287e71b7053SJung-uk Kim                 goto end;
288e71b7053SJung-uk Kim             }
289e71b7053SJung-uk Kim             break;
290e71b7053SJung-uk Kim         case OSSL_STORE_SEARCH_BY_KEY_FINGERPRINT:
291e71b7053SJung-uk Kim             if ((search = OSSL_STORE_SEARCH_by_key_fingerprint(digest,
292e71b7053SJung-uk Kim                                                                fingerprint,
293e71b7053SJung-uk Kim                                                                fingerprintlen))
294e71b7053SJung-uk Kim                 == NULL) {
295e71b7053SJung-uk Kim                 ERR_print_errors(bio_err);
296e71b7053SJung-uk Kim                 goto end;
297e71b7053SJung-uk Kim             }
298e71b7053SJung-uk Kim             break;
299e71b7053SJung-uk Kim         case OSSL_STORE_SEARCH_BY_ALIAS:
300e71b7053SJung-uk Kim             if ((search = OSSL_STORE_SEARCH_by_alias(alias)) == NULL) {
301e71b7053SJung-uk Kim                 ERR_print_errors(bio_err);
302e71b7053SJung-uk Kim                 goto end;
303e71b7053SJung-uk Kim             }
304e71b7053SJung-uk Kim             break;
305e71b7053SJung-uk Kim         }
306e71b7053SJung-uk Kim     }
307e71b7053SJung-uk Kim 
308e71b7053SJung-uk Kim     if (!app_passwd(passinarg, NULL, &passin, NULL)) {
309e71b7053SJung-uk Kim         BIO_printf(bio_err, "Error getting passwords\n");
310e71b7053SJung-uk Kim         goto end;
311e71b7053SJung-uk Kim     }
312e71b7053SJung-uk Kim     pw_cb_data.password = passin;
313e71b7053SJung-uk Kim     pw_cb_data.prompt_info = argv[0];
314e71b7053SJung-uk Kim 
315e71b7053SJung-uk Kim     out = bio_open_default(outfile, 'w', FORMAT_TEXT);
316e71b7053SJung-uk Kim     if (out == NULL)
317e71b7053SJung-uk Kim         goto end;
318e71b7053SJung-uk Kim 
319e71b7053SJung-uk Kim     ret = process(argv[0], get_ui_method(), &pw_cb_data,
320e71b7053SJung-uk Kim                   expected, criterion, search,
321*b077aed3SPierre Pronchery                   text, noout, recursive, 0, out, prog, libctx);
322e71b7053SJung-uk Kim 
323e71b7053SJung-uk Kim  end:
324*b077aed3SPierre Pronchery     EVP_MD_free(digest);
325e71b7053SJung-uk Kim     OPENSSL_free(fingerprint);
326e71b7053SJung-uk Kim     OPENSSL_free(alias);
327e71b7053SJung-uk Kim     ASN1_INTEGER_free(serial);
328e71b7053SJung-uk Kim     X509_NAME_free(subject);
329e71b7053SJung-uk Kim     X509_NAME_free(issuer);
330e71b7053SJung-uk Kim     OSSL_STORE_SEARCH_free(search);
331e71b7053SJung-uk Kim     BIO_free_all(out);
332e71b7053SJung-uk Kim     OPENSSL_free(passin);
333e71b7053SJung-uk Kim     release_engine(e);
334e71b7053SJung-uk Kim     return ret;
335e71b7053SJung-uk Kim }
336e71b7053SJung-uk Kim 
indent_printf(int indent,BIO * bio,const char * format,...)337e71b7053SJung-uk Kim static int indent_printf(int indent, BIO *bio, const char *format, ...)
338e71b7053SJung-uk Kim {
339e71b7053SJung-uk Kim     va_list args;
340e71b7053SJung-uk Kim     int ret;
341e71b7053SJung-uk Kim 
342e71b7053SJung-uk Kim     va_start(args, format);
343e71b7053SJung-uk Kim 
344e71b7053SJung-uk Kim     ret = BIO_printf(bio, "%*s", indent, "") + BIO_vprintf(bio, format, args);
345e71b7053SJung-uk Kim 
346e71b7053SJung-uk Kim     va_end(args);
347e71b7053SJung-uk Kim     return ret;
348e71b7053SJung-uk Kim }
349e71b7053SJung-uk Kim 
process(const char * uri,const UI_METHOD * uimeth,PW_CB_DATA * uidata,int expected,int criterion,OSSL_STORE_SEARCH * search,int text,int noout,int recursive,int indent,BIO * out,const char * prog,OSSL_LIB_CTX * libctx)350e71b7053SJung-uk Kim static int process(const char *uri, const UI_METHOD *uimeth, PW_CB_DATA *uidata,
351e71b7053SJung-uk Kim                    int expected, int criterion, OSSL_STORE_SEARCH *search,
352e71b7053SJung-uk Kim                    int text, int noout, int recursive, int indent, BIO *out,
353*b077aed3SPierre Pronchery                    const char *prog, OSSL_LIB_CTX *libctx)
354e71b7053SJung-uk Kim {
355e71b7053SJung-uk Kim     OSSL_STORE_CTX *store_ctx = NULL;
356e71b7053SJung-uk Kim     int ret = 1, items = 0;
357e71b7053SJung-uk Kim 
358*b077aed3SPierre Pronchery     if ((store_ctx = OSSL_STORE_open_ex(uri, libctx, app_get0_propq(), uimeth, uidata,
359*b077aed3SPierre Pronchery                                         NULL, NULL, NULL))
360e71b7053SJung-uk Kim         == NULL) {
361e71b7053SJung-uk Kim         BIO_printf(bio_err, "Couldn't open file or uri %s\n", uri);
362e71b7053SJung-uk Kim         ERR_print_errors(bio_err);
363e71b7053SJung-uk Kim         return ret;
364e71b7053SJung-uk Kim     }
365e71b7053SJung-uk Kim 
366e71b7053SJung-uk Kim     if (expected != 0) {
367e71b7053SJung-uk Kim         if (!OSSL_STORE_expect(store_ctx, expected)) {
368e71b7053SJung-uk Kim             ERR_print_errors(bio_err);
369e71b7053SJung-uk Kim             goto end2;
370e71b7053SJung-uk Kim         }
371e71b7053SJung-uk Kim     }
372e71b7053SJung-uk Kim 
373e71b7053SJung-uk Kim     if (criterion != 0) {
374e71b7053SJung-uk Kim         if (!OSSL_STORE_supports_search(store_ctx, criterion)) {
375e71b7053SJung-uk Kim             BIO_printf(bio_err,
376e71b7053SJung-uk Kim                        "%s: the store scheme doesn't support the given search criteria.\n",
377e71b7053SJung-uk Kim                        prog);
378e71b7053SJung-uk Kim             goto end2;
379e71b7053SJung-uk Kim         }
380e71b7053SJung-uk Kim 
381e71b7053SJung-uk Kim         if (!OSSL_STORE_find(store_ctx, search)) {
382e71b7053SJung-uk Kim             ERR_print_errors(bio_err);
383e71b7053SJung-uk Kim             goto end2;
384e71b7053SJung-uk Kim         }
385e71b7053SJung-uk Kim     }
386e71b7053SJung-uk Kim 
387e71b7053SJung-uk Kim     /* From here on, we count errors, and we'll return the count at the end */
388e71b7053SJung-uk Kim     ret = 0;
389e71b7053SJung-uk Kim 
390e71b7053SJung-uk Kim     for (;;) {
391e71b7053SJung-uk Kim         OSSL_STORE_INFO *info = OSSL_STORE_load(store_ctx);
392e71b7053SJung-uk Kim         int type = info == NULL ? 0 : OSSL_STORE_INFO_get_type(info);
393e71b7053SJung-uk Kim         const char *infostr =
394e71b7053SJung-uk Kim             info == NULL ? NULL : OSSL_STORE_INFO_type_string(type);
395e71b7053SJung-uk Kim 
396e71b7053SJung-uk Kim         if (info == NULL) {
397e71b7053SJung-uk Kim             if (OSSL_STORE_error(store_ctx)) {
398e71b7053SJung-uk Kim                 if (recursive)
399e71b7053SJung-uk Kim                     ERR_clear_error();
400e71b7053SJung-uk Kim                 else
401e71b7053SJung-uk Kim                     ERR_print_errors(bio_err);
402*b077aed3SPierre Pronchery                 if (OSSL_STORE_eof(store_ctx))
403*b077aed3SPierre Pronchery                     break;
404e71b7053SJung-uk Kim                 ret++;
405e71b7053SJung-uk Kim                 continue;
406e71b7053SJung-uk Kim             }
407e71b7053SJung-uk Kim 
408*b077aed3SPierre Pronchery             if (OSSL_STORE_eof(store_ctx))
409*b077aed3SPierre Pronchery                 break;
410*b077aed3SPierre Pronchery 
411e71b7053SJung-uk Kim             BIO_printf(bio_err,
412e71b7053SJung-uk Kim                        "ERROR: OSSL_STORE_load() returned NULL without "
413e71b7053SJung-uk Kim                        "eof or error indications\n");
414e71b7053SJung-uk Kim             BIO_printf(bio_err, "       This is an error in the loader\n");
415e71b7053SJung-uk Kim             ERR_print_errors(bio_err);
416e71b7053SJung-uk Kim             ret++;
417e71b7053SJung-uk Kim             break;
418e71b7053SJung-uk Kim         }
419e71b7053SJung-uk Kim 
420e71b7053SJung-uk Kim         if (type == OSSL_STORE_INFO_NAME) {
421e71b7053SJung-uk Kim             const char *name = OSSL_STORE_INFO_get0_NAME(info);
422e71b7053SJung-uk Kim             const char *desc = OSSL_STORE_INFO_get0_NAME_description(info);
423e71b7053SJung-uk Kim             indent_printf(indent, bio_out, "%d: %s: %s\n", items, infostr,
424e71b7053SJung-uk Kim                           name);
425e71b7053SJung-uk Kim             if (desc != NULL)
426e71b7053SJung-uk Kim                 indent_printf(indent, bio_out, "%s\n", desc);
427e71b7053SJung-uk Kim         } else {
428e71b7053SJung-uk Kim             indent_printf(indent, bio_out, "%d: %s\n", items, infostr);
429e71b7053SJung-uk Kim         }
430e71b7053SJung-uk Kim 
431e71b7053SJung-uk Kim         /*
432e71b7053SJung-uk Kim          * Unfortunately, PEM_X509_INFO_write_bio() is sorely lacking in
433e71b7053SJung-uk Kim          * functionality, so we must figure out how exactly to write things
434e71b7053SJung-uk Kim          * ourselves...
435e71b7053SJung-uk Kim          */
436e71b7053SJung-uk Kim         switch (type) {
437e71b7053SJung-uk Kim         case OSSL_STORE_INFO_NAME:
438e71b7053SJung-uk Kim             if (recursive) {
439e71b7053SJung-uk Kim                 const char *suburi = OSSL_STORE_INFO_get0_NAME(info);
440e71b7053SJung-uk Kim                 ret += process(suburi, uimeth, uidata,
441e71b7053SJung-uk Kim                                expected, criterion, search,
442*b077aed3SPierre Pronchery                                text, noout, recursive, indent + 2, out, prog,
443*b077aed3SPierre Pronchery                                libctx);
444e71b7053SJung-uk Kim             }
445e71b7053SJung-uk Kim             break;
446e71b7053SJung-uk Kim         case OSSL_STORE_INFO_PARAMS:
447e71b7053SJung-uk Kim             if (text)
448e71b7053SJung-uk Kim                 EVP_PKEY_print_params(out, OSSL_STORE_INFO_get0_PARAMS(info),
449e71b7053SJung-uk Kim                                       0, NULL);
450e71b7053SJung-uk Kim             if (!noout)
451e71b7053SJung-uk Kim                 PEM_write_bio_Parameters(out,
452e71b7053SJung-uk Kim                                          OSSL_STORE_INFO_get0_PARAMS(info));
453e71b7053SJung-uk Kim             break;
454*b077aed3SPierre Pronchery         case OSSL_STORE_INFO_PUBKEY:
455*b077aed3SPierre Pronchery             if (text)
456*b077aed3SPierre Pronchery                 EVP_PKEY_print_public(out, OSSL_STORE_INFO_get0_PUBKEY(info),
457*b077aed3SPierre Pronchery                                       0, NULL);
458*b077aed3SPierre Pronchery             if (!noout)
459*b077aed3SPierre Pronchery                 PEM_write_bio_PUBKEY(out, OSSL_STORE_INFO_get0_PUBKEY(info));
460*b077aed3SPierre Pronchery             break;
461e71b7053SJung-uk Kim         case OSSL_STORE_INFO_PKEY:
462e71b7053SJung-uk Kim             if (text)
463e71b7053SJung-uk Kim                 EVP_PKEY_print_private(out, OSSL_STORE_INFO_get0_PKEY(info),
464e71b7053SJung-uk Kim                                        0, NULL);
465e71b7053SJung-uk Kim             if (!noout)
466e71b7053SJung-uk Kim                 PEM_write_bio_PrivateKey(out, OSSL_STORE_INFO_get0_PKEY(info),
467e71b7053SJung-uk Kim                                          NULL, NULL, 0, NULL, NULL);
468e71b7053SJung-uk Kim             break;
469e71b7053SJung-uk Kim         case OSSL_STORE_INFO_CERT:
470e71b7053SJung-uk Kim             if (text)
471e71b7053SJung-uk Kim                 X509_print(out, OSSL_STORE_INFO_get0_CERT(info));
472e71b7053SJung-uk Kim             if (!noout)
473e71b7053SJung-uk Kim                 PEM_write_bio_X509(out, OSSL_STORE_INFO_get0_CERT(info));
474e71b7053SJung-uk Kim             break;
475e71b7053SJung-uk Kim         case OSSL_STORE_INFO_CRL:
476e71b7053SJung-uk Kim             if (text)
477e71b7053SJung-uk Kim                 X509_CRL_print(out, OSSL_STORE_INFO_get0_CRL(info));
478e71b7053SJung-uk Kim             if (!noout)
479e71b7053SJung-uk Kim                 PEM_write_bio_X509_CRL(out, OSSL_STORE_INFO_get0_CRL(info));
480e71b7053SJung-uk Kim             break;
481e71b7053SJung-uk Kim         default:
482e71b7053SJung-uk Kim             BIO_printf(bio_err, "!!! Unknown code\n");
483e71b7053SJung-uk Kim             ret++;
484e71b7053SJung-uk Kim             break;
485e71b7053SJung-uk Kim         }
486e71b7053SJung-uk Kim         items++;
487e71b7053SJung-uk Kim         OSSL_STORE_INFO_free(info);
488e71b7053SJung-uk Kim     }
489e71b7053SJung-uk Kim     indent_printf(indent, out, "Total found: %d\n", items);
490e71b7053SJung-uk Kim 
491e71b7053SJung-uk Kim  end2:
492e71b7053SJung-uk Kim     if (!OSSL_STORE_close(store_ctx)) {
493e71b7053SJung-uk Kim         ERR_print_errors(bio_err);
494e71b7053SJung-uk Kim         ret++;
495e71b7053SJung-uk Kim     }
496e71b7053SJung-uk Kim 
497e71b7053SJung-uk Kim     return ret;
498e71b7053SJung-uk Kim }
499