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