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