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