xref: /netbsd-src/crypto/external/bsd/openssl.old/dist/apps/engine.c (revision 4724848cf0da353df257f730694b7882798e5daf)
1c9496f6bSchristos /*
2*4724848cSchristos  * Copyright 2000-2020 The OpenSSL Project Authors. All Rights Reserved.
3c9496f6bSchristos  *
4*4724848cSchristos  * Licensed under the OpenSSL license (the "License").  You may not use
5*4724848cSchristos  * this file except in compliance with the License.  You can obtain a copy
6*4724848cSchristos  * in the file LICENSE in the source distribution or at
7*4724848cSchristos  * https://www.openssl.org/source/license.html
8c9496f6bSchristos  */
9c9496f6bSchristos 
10*4724848cSchristos #include <openssl/opensslconf.h>
11*4724848cSchristos #include "apps.h"
12*4724848cSchristos #include "progs.h"
13c9496f6bSchristos #include <stdio.h>
14c9496f6bSchristos #include <stdlib.h>
15c9496f6bSchristos #include <string.h>
16c9496f6bSchristos #include <openssl/err.h>
17c9496f6bSchristos #include <openssl/engine.h>
18c9496f6bSchristos #include <openssl/ssl.h>
19*4724848cSchristos #include <openssl/store.h>
20c9496f6bSchristos 
21*4724848cSchristos typedef enum OPTION_choice {
22*4724848cSchristos     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
23*4724848cSchristos     OPT_C, OPT_T, OPT_TT, OPT_PRE, OPT_POST,
24*4724848cSchristos     OPT_V = 100, OPT_VV, OPT_VVV, OPT_VVVV
25*4724848cSchristos } OPTION_CHOICE;
26c9496f6bSchristos 
27*4724848cSchristos const OPTIONS engine_options[] = {
28*4724848cSchristos     {OPT_HELP_STR, 1, '-', "Usage: %s [options] engine...\n"},
29*4724848cSchristos     {OPT_HELP_STR, 1, '-',
30*4724848cSchristos         "  engine... Engines to load\n"},
31*4724848cSchristos     {"help", OPT_HELP, '-', "Display this summary"},
32*4724848cSchristos     {"v", OPT_V, '-', "List 'control commands' For each specified engine"},
33*4724848cSchristos     {"vv", OPT_VV, '-', "Also display each command's description"},
34*4724848cSchristos     {"vvv", OPT_VVV, '-', "Also add the input flags for each command"},
35*4724848cSchristos     {"vvvv", OPT_VVVV, '-', "Also show internal input flags"},
36*4724848cSchristos     {"c", OPT_C, '-', "List the capabilities of specified engine"},
37*4724848cSchristos     {"t", OPT_T, '-', "Check that specified engine is available"},
38*4724848cSchristos     {"tt", OPT_TT, '-', "Display error trace for unavailable engines"},
39*4724848cSchristos     {"pre", OPT_PRE, 's', "Run command against the ENGINE before loading it"},
40*4724848cSchristos     {"post", OPT_POST, 's', "Run command against the ENGINE after loading it"},
41*4724848cSchristos     {OPT_MORE_STR, OPT_EOF, 1,
42*4724848cSchristos      "Commands are like \"SO_PATH:/lib/libdriver.so\""},
43*4724848cSchristos     {NULL}
44c9496f6bSchristos };
45c9496f6bSchristos 
append_buf(char ** buf,int * size,const char * s)46*4724848cSchristos static int append_buf(char **buf, int *size, const char *s)
47c9496f6bSchristos {
48*4724848cSchristos     const int expand = 256;
49*4724848cSchristos     int len = strlen(s) + 1;
50*4724848cSchristos     char *p = *buf;
51c9496f6bSchristos 
52*4724848cSchristos     if (p == NULL) {
53*4724848cSchristos         *size = ((len + expand - 1) / expand) * expand;
54*4724848cSchristos         p = *buf = app_malloc(*size, "engine buffer");
55*4724848cSchristos     } else {
56*4724848cSchristos         const int blen = strlen(p);
57*4724848cSchristos 
58*4724848cSchristos         if (blen > 0)
59*4724848cSchristos             len += 2 + blen;
60*4724848cSchristos 
61*4724848cSchristos         if (len > *size) {
62*4724848cSchristos             *size = ((len + expand - 1) / expand) * expand;
63*4724848cSchristos             p = OPENSSL_realloc(p, *size);
64*4724848cSchristos             if (p == NULL) {
65*4724848cSchristos                 OPENSSL_free(*buf);
66*4724848cSchristos                 *buf = NULL;
67c9496f6bSchristos                 return 0;
68*4724848cSchristos             }
69*4724848cSchristos             *buf = p;
70c9496f6bSchristos         }
71c9496f6bSchristos 
72*4724848cSchristos         if (blen > 0) {
73*4724848cSchristos             p += blen;
74*4724848cSchristos             *p++ = ',';
75*4724848cSchristos             *p++ = ' ';
76*4724848cSchristos         }
77c9496f6bSchristos     }
78c9496f6bSchristos 
79*4724848cSchristos     strcpy(p, s);
80c9496f6bSchristos     return 1;
81c9496f6bSchristos }
82c9496f6bSchristos 
util_flags(BIO * out,unsigned int flags,const char * indent)83*4724848cSchristos static int util_flags(BIO *out, unsigned int flags, const char *indent)
84c9496f6bSchristos {
85c9496f6bSchristos     int started = 0, err = 0;
86c9496f6bSchristos     /* Indent before displaying input flags */
87*4724848cSchristos     BIO_printf(out, "%s%s(input flags): ", indent, indent);
88c9496f6bSchristos     if (flags == 0) {
89*4724848cSchristos         BIO_printf(out, "<no flags>\n");
90c9496f6bSchristos         return 1;
91c9496f6bSchristos     }
92c9496f6bSchristos     /*
93c9496f6bSchristos      * If the object is internal, mark it in a way that shows instead of
94c9496f6bSchristos      * having it part of all the other flags, even if it really is.
95c9496f6bSchristos      */
96c9496f6bSchristos     if (flags & ENGINE_CMD_FLAG_INTERNAL) {
97*4724848cSchristos         BIO_printf(out, "[Internal] ");
98c9496f6bSchristos     }
99c9496f6bSchristos 
100c9496f6bSchristos     if (flags & ENGINE_CMD_FLAG_NUMERIC) {
101*4724848cSchristos         BIO_printf(out, "NUMERIC");
102c9496f6bSchristos         started = 1;
103c9496f6bSchristos     }
104c9496f6bSchristos     /*
105c9496f6bSchristos      * Now we check that no combinations of the mutually exclusive NUMERIC,
106c9496f6bSchristos      * STRING, and NO_INPUT flags have been used. Future flags that can be
107c9496f6bSchristos      * OR'd together with these would need to added after these to preserve
108c9496f6bSchristos      * the testing logic.
109c9496f6bSchristos      */
110c9496f6bSchristos     if (flags & ENGINE_CMD_FLAG_STRING) {
111c9496f6bSchristos         if (started) {
112*4724848cSchristos             BIO_printf(out, "|");
113c9496f6bSchristos             err = 1;
114c9496f6bSchristos         }
115*4724848cSchristos         BIO_printf(out, "STRING");
116c9496f6bSchristos         started = 1;
117c9496f6bSchristos     }
118c9496f6bSchristos     if (flags & ENGINE_CMD_FLAG_NO_INPUT) {
119c9496f6bSchristos         if (started) {
120*4724848cSchristos             BIO_printf(out, "|");
121c9496f6bSchristos             err = 1;
122c9496f6bSchristos         }
123*4724848cSchristos         BIO_printf(out, "NO_INPUT");
124c9496f6bSchristos         started = 1;
125c9496f6bSchristos     }
126c9496f6bSchristos     /* Check for unknown flags */
127c9496f6bSchristos     flags = flags & ~ENGINE_CMD_FLAG_NUMERIC &
128c9496f6bSchristos         ~ENGINE_CMD_FLAG_STRING &
129c9496f6bSchristos         ~ENGINE_CMD_FLAG_NO_INPUT & ~ENGINE_CMD_FLAG_INTERNAL;
130c9496f6bSchristos     if (flags) {
131c9496f6bSchristos         if (started)
132*4724848cSchristos             BIO_printf(out, "|");
133*4724848cSchristos         BIO_printf(out, "<0x%04X>", flags);
134c9496f6bSchristos     }
135c9496f6bSchristos     if (err)
136*4724848cSchristos         BIO_printf(out, "  <illegal flags!>");
137*4724848cSchristos     BIO_printf(out, "\n");
138c9496f6bSchristos     return 1;
139c9496f6bSchristos }
140c9496f6bSchristos 
util_verbose(ENGINE * e,int verbose,BIO * out,const char * indent)141*4724848cSchristos static int util_verbose(ENGINE *e, int verbose, BIO *out, const char *indent)
142c9496f6bSchristos {
143c9496f6bSchristos     static const int line_wrap = 78;
144c9496f6bSchristos     int num;
145c9496f6bSchristos     int ret = 0;
146c9496f6bSchristos     char *name = NULL;
147c9496f6bSchristos     char *desc = NULL;
148c9496f6bSchristos     int flags;
149c9496f6bSchristos     int xpos = 0;
150c9496f6bSchristos     STACK_OF(OPENSSL_STRING) *cmds = NULL;
151c9496f6bSchristos     if (!ENGINE_ctrl(e, ENGINE_CTRL_HAS_CTRL_FUNCTION, 0, NULL, NULL) ||
152c9496f6bSchristos         ((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_FIRST_CMD_TYPE,
153c9496f6bSchristos                             0, NULL, NULL)) <= 0)) {
154c9496f6bSchristos         return 1;
155c9496f6bSchristos     }
156c9496f6bSchristos 
157c9496f6bSchristos     cmds = sk_OPENSSL_STRING_new_null();
158*4724848cSchristos     if (cmds == NULL)
159c9496f6bSchristos         goto err;
160*4724848cSchristos 
161c9496f6bSchristos     do {
162c9496f6bSchristos         int len;
163c9496f6bSchristos         /* Get the command input flags */
164c9496f6bSchristos         if ((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num,
165c9496f6bSchristos                                  NULL, NULL)) < 0)
166c9496f6bSchristos             goto err;
167c9496f6bSchristos         if (!(flags & ENGINE_CMD_FLAG_INTERNAL) || verbose >= 4) {
168c9496f6bSchristos             /* Get the command name */
169c9496f6bSchristos             if ((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_LEN_FROM_CMD, num,
170c9496f6bSchristos                                    NULL, NULL)) <= 0)
171c9496f6bSchristos                 goto err;
172*4724848cSchristos             name = app_malloc(len + 1, "name buffer");
173c9496f6bSchristos             if (ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_FROM_CMD, num, name,
174c9496f6bSchristos                             NULL) <= 0)
175c9496f6bSchristos                 goto err;
176c9496f6bSchristos             /* Get the command description */
177c9496f6bSchristos             if ((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_LEN_FROM_CMD, num,
178c9496f6bSchristos                                    NULL, NULL)) < 0)
179c9496f6bSchristos                 goto err;
180c9496f6bSchristos             if (len > 0) {
181*4724848cSchristos                 desc = app_malloc(len + 1, "description buffer");
182c9496f6bSchristos                 if (ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_FROM_CMD, num, desc,
183c9496f6bSchristos                                 NULL) <= 0)
184c9496f6bSchristos                     goto err;
185c9496f6bSchristos             }
186c9496f6bSchristos             /* Now decide on the output */
187c9496f6bSchristos             if (xpos == 0)
188c9496f6bSchristos                 /* Do an indent */
189*4724848cSchristos                 xpos = BIO_puts(out, indent);
190c9496f6bSchristos             else
191c9496f6bSchristos                 /* Otherwise prepend a ", " */
192*4724848cSchristos                 xpos += BIO_printf(out, ", ");
193c9496f6bSchristos             if (verbose == 1) {
194c9496f6bSchristos                 /*
195c9496f6bSchristos                  * We're just listing names, comma-delimited
196c9496f6bSchristos                  */
197c9496f6bSchristos                 if ((xpos > (int)strlen(indent)) &&
198c9496f6bSchristos                     (xpos + (int)strlen(name) > line_wrap)) {
199*4724848cSchristos                     BIO_printf(out, "\n");
200*4724848cSchristos                     xpos = BIO_puts(out, indent);
201c9496f6bSchristos                 }
202*4724848cSchristos                 xpos += BIO_printf(out, "%s", name);
203c9496f6bSchristos             } else {
204c9496f6bSchristos                 /* We're listing names plus descriptions */
205*4724848cSchristos                 BIO_printf(out, "%s: %s\n", name,
206c9496f6bSchristos                            (desc == NULL) ? "<no description>" : desc);
207c9496f6bSchristos                 /* ... and sometimes input flags */
208*4724848cSchristos                 if ((verbose >= 3) && !util_flags(out, flags, indent))
209c9496f6bSchristos                     goto err;
210c9496f6bSchristos                 xpos = 0;
211c9496f6bSchristos             }
212c9496f6bSchristos         }
213c9496f6bSchristos         OPENSSL_free(name);
214c9496f6bSchristos         name = NULL;
215c9496f6bSchristos         OPENSSL_free(desc);
216c9496f6bSchristos         desc = NULL;
217c9496f6bSchristos         /* Move to the next command */
218c9496f6bSchristos         num = ENGINE_ctrl(e, ENGINE_CTRL_GET_NEXT_CMD_TYPE, num, NULL, NULL);
219c9496f6bSchristos     } while (num > 0);
220c9496f6bSchristos     if (xpos > 0)
221*4724848cSchristos         BIO_printf(out, "\n");
222c9496f6bSchristos     ret = 1;
223c9496f6bSchristos  err:
224*4724848cSchristos     sk_OPENSSL_STRING_free(cmds);
225c9496f6bSchristos     OPENSSL_free(name);
226c9496f6bSchristos     OPENSSL_free(desc);
227c9496f6bSchristos     return ret;
228c9496f6bSchristos }
229c9496f6bSchristos 
util_do_cmds(ENGINE * e,STACK_OF (OPENSSL_STRING)* cmds,BIO * out,const char * indent)230c9496f6bSchristos static void util_do_cmds(ENGINE *e, STACK_OF(OPENSSL_STRING) *cmds,
231*4724848cSchristos                          BIO *out, const char *indent)
232c9496f6bSchristos {
233c9496f6bSchristos     int loop, res, num = sk_OPENSSL_STRING_num(cmds);
234c9496f6bSchristos 
235c9496f6bSchristos     if (num < 0) {
236*4724848cSchristos         BIO_printf(out, "[Error]: internal stack error\n");
237c9496f6bSchristos         return;
238c9496f6bSchristos     }
239c9496f6bSchristos     for (loop = 0; loop < num; loop++) {
240c9496f6bSchristos         char buf[256];
241c9496f6bSchristos         const char *cmd, *arg;
242c9496f6bSchristos         cmd = sk_OPENSSL_STRING_value(cmds, loop);
243c9496f6bSchristos         res = 1;                /* assume success */
244c9496f6bSchristos         /* Check if this command has no ":arg" */
245c9496f6bSchristos         if ((arg = strstr(cmd, ":")) == NULL) {
246c9496f6bSchristos             if (!ENGINE_ctrl_cmd_string(e, cmd, NULL, 0))
247c9496f6bSchristos                 res = 0;
248c9496f6bSchristos         } else {
249c9496f6bSchristos             if ((int)(arg - cmd) > 254) {
250*4724848cSchristos                 BIO_printf(out, "[Error]: command name too long\n");
251c9496f6bSchristos                 return;
252c9496f6bSchristos             }
253c9496f6bSchristos             memcpy(buf, cmd, (int)(arg - cmd));
254c9496f6bSchristos             buf[arg - cmd] = '\0';
255c9496f6bSchristos             arg++;              /* Move past the ":" */
256c9496f6bSchristos             /* Call the command with the argument */
257c9496f6bSchristos             if (!ENGINE_ctrl_cmd_string(e, buf, arg, 0))
258c9496f6bSchristos                 res = 0;
259c9496f6bSchristos         }
260*4724848cSchristos         if (res) {
261*4724848cSchristos             BIO_printf(out, "[Success]: %s\n", cmd);
262*4724848cSchristos         } else {
263*4724848cSchristos             BIO_printf(out, "[Failure]: %s\n", cmd);
264*4724848cSchristos             ERR_print_errors(out);
265c9496f6bSchristos         }
266c9496f6bSchristos     }
267c9496f6bSchristos }
268c9496f6bSchristos 
269*4724848cSchristos struct util_store_cap_data {
270*4724848cSchristos     ENGINE *engine;
271*4724848cSchristos     char **cap_buf;
272*4724848cSchristos     int *cap_size;
273*4724848cSchristos     int ok;
274*4724848cSchristos };
util_store_cap(const OSSL_STORE_LOADER * loader,void * arg)275*4724848cSchristos static void util_store_cap(const OSSL_STORE_LOADER *loader, void *arg)
276*4724848cSchristos {
277*4724848cSchristos     struct util_store_cap_data *ctx = arg;
278c9496f6bSchristos 
279*4724848cSchristos     if (OSSL_STORE_LOADER_get0_engine(loader) == ctx->engine) {
280*4724848cSchristos         char buf[256];
281*4724848cSchristos         BIO_snprintf(buf, sizeof(buf), "STORE(%s)",
282*4724848cSchristos                      OSSL_STORE_LOADER_get0_scheme(loader));
283*4724848cSchristos         if (!append_buf(ctx->cap_buf, ctx->cap_size, buf))
284*4724848cSchristos             ctx->ok = 0;
285*4724848cSchristos     }
286*4724848cSchristos }
287*4724848cSchristos 
engine_main(int argc,char ** argv)288*4724848cSchristos int engine_main(int argc, char **argv)
289c9496f6bSchristos {
290c9496f6bSchristos     int ret = 1, i;
291c9496f6bSchristos     int verbose = 0, list_cap = 0, test_avail = 0, test_avail_noise = 0;
292c9496f6bSchristos     ENGINE *e;
293*4724848cSchristos     STACK_OF(OPENSSL_CSTRING) *engines = sk_OPENSSL_CSTRING_new_null();
294c9496f6bSchristos     STACK_OF(OPENSSL_STRING) *pre_cmds = sk_OPENSSL_STRING_new_null();
295c9496f6bSchristos     STACK_OF(OPENSSL_STRING) *post_cmds = sk_OPENSSL_STRING_new_null();
296*4724848cSchristos     BIO *out;
297c9496f6bSchristos     const char *indent = "     ";
298*4724848cSchristos     OPTION_CHOICE o;
299*4724848cSchristos     char *prog;
300*4724848cSchristos     char *argv1;
301c9496f6bSchristos 
302*4724848cSchristos     out = dup_bio_out(FORMAT_TEXT);
303*4724848cSchristos     if (engines == NULL || pre_cmds == NULL || post_cmds == NULL)
304c9496f6bSchristos         goto end;
305c9496f6bSchristos 
306*4724848cSchristos     /* Remember the original command name, parse/skip any leading engine
307*4724848cSchristos      * names, and then setup to parse the rest of the line as flags. */
308*4724848cSchristos     prog = argv[0];
309*4724848cSchristos     while ((argv1 = argv[1]) != NULL && *argv1 != '-') {
310*4724848cSchristos         sk_OPENSSL_CSTRING_push(engines, argv1);
311c9496f6bSchristos         argc--;
312c9496f6bSchristos         argv++;
313*4724848cSchristos     }
314*4724848cSchristos     argv[0] = prog;
315*4724848cSchristos     opt_init(argc, argv, engine_options);
316*4724848cSchristos 
317*4724848cSchristos     while ((o = opt_next()) != OPT_EOF) {
318*4724848cSchristos         switch (o) {
319*4724848cSchristos         case OPT_EOF:
320*4724848cSchristos         case OPT_ERR:
321*4724848cSchristos             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
322*4724848cSchristos             goto end;
323*4724848cSchristos         case OPT_HELP:
324*4724848cSchristos             opt_help(engine_options);
325*4724848cSchristos             ret = 0;
326*4724848cSchristos             goto end;
327*4724848cSchristos         case OPT_VVVV:
328*4724848cSchristos         case OPT_VVV:
329*4724848cSchristos         case OPT_VV:
330*4724848cSchristos         case OPT_V:
331*4724848cSchristos             /* Convert to an integer from one to four. */
332*4724848cSchristos             i = (int)(o - OPT_V) + 1;
333*4724848cSchristos             if (verbose < i)
334*4724848cSchristos                 verbose = i;
335*4724848cSchristos             break;
336*4724848cSchristos         case OPT_C:
337c9496f6bSchristos             list_cap = 1;
338*4724848cSchristos             break;
339*4724848cSchristos         case OPT_TT:
340*4724848cSchristos             test_avail_noise++;
341*4724848cSchristos             /* fall thru */
342*4724848cSchristos         case OPT_T:
343*4724848cSchristos             test_avail++;
344*4724848cSchristos             break;
345*4724848cSchristos         case OPT_PRE:
346*4724848cSchristos             sk_OPENSSL_STRING_push(pre_cmds, opt_arg());
347*4724848cSchristos             break;
348*4724848cSchristos         case OPT_POST:
349*4724848cSchristos             sk_OPENSSL_STRING_push(post_cmds, opt_arg());
350*4724848cSchristos             break;
351c9496f6bSchristos         }
352*4724848cSchristos     }
353c9496f6bSchristos 
354*4724848cSchristos     /* Allow any trailing parameters as engine names. */
355*4724848cSchristos     argc = opt_num_rest();
356*4724848cSchristos     argv = opt_rest();
357*4724848cSchristos     for ( ; *argv; argv++) {
358*4724848cSchristos         if (**argv == '-') {
359*4724848cSchristos             BIO_printf(bio_err, "%s: Cannot mix flags and engine names.\n",
360*4724848cSchristos                        prog);
361*4724848cSchristos             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
362c9496f6bSchristos             goto end;
363c9496f6bSchristos         }
364*4724848cSchristos         sk_OPENSSL_CSTRING_push(engines, *argv);
365*4724848cSchristos     }
366c9496f6bSchristos 
367*4724848cSchristos     if (sk_OPENSSL_CSTRING_num(engines) == 0) {
368c9496f6bSchristos         for (e = ENGINE_get_first(); e != NULL; e = ENGINE_get_next(e)) {
369*4724848cSchristos             sk_OPENSSL_CSTRING_push(engines, ENGINE_get_id(e));
370c9496f6bSchristos         }
371c9496f6bSchristos     }
372c9496f6bSchristos 
373*4724848cSchristos     ret = 0;
374*4724848cSchristos     for (i = 0; i < sk_OPENSSL_CSTRING_num(engines); i++) {
375*4724848cSchristos         const char *id = sk_OPENSSL_CSTRING_value(engines, i);
376c9496f6bSchristos         if ((e = ENGINE_by_id(id)) != NULL) {
377c9496f6bSchristos             const char *name = ENGINE_get_name(e);
378c9496f6bSchristos             /*
379c9496f6bSchristos              * Do "id" first, then "name". Easier to auto-parse.
380c9496f6bSchristos              */
381*4724848cSchristos             BIO_printf(out, "(%s) %s\n", id, name);
382*4724848cSchristos             util_do_cmds(e, pre_cmds, out, indent);
383c9496f6bSchristos             if (strcmp(ENGINE_get_id(e), id) != 0) {
384*4724848cSchristos                 BIO_printf(out, "Loaded: (%s) %s\n",
385c9496f6bSchristos                            ENGINE_get_id(e), ENGINE_get_name(e));
386c9496f6bSchristos             }
387c9496f6bSchristos             if (list_cap) {
388c9496f6bSchristos                 int cap_size = 256;
389c9496f6bSchristos                 char *cap_buf = NULL;
390c9496f6bSchristos                 int k, n;
391c9496f6bSchristos                 const int *nids;
392c9496f6bSchristos                 ENGINE_CIPHERS_PTR fn_c;
393c9496f6bSchristos                 ENGINE_DIGESTS_PTR fn_d;
394c9496f6bSchristos                 ENGINE_PKEY_METHS_PTR fn_pk;
395c9496f6bSchristos 
396c9496f6bSchristos                 if (ENGINE_get_RSA(e) != NULL
397*4724848cSchristos                     && !append_buf(&cap_buf, &cap_size, "RSA"))
398c9496f6bSchristos                     goto end;
399c9496f6bSchristos                 if (ENGINE_get_DSA(e) != NULL
400*4724848cSchristos                     && !append_buf(&cap_buf, &cap_size, "DSA"))
401c9496f6bSchristos                     goto end;
402c9496f6bSchristos                 if (ENGINE_get_DH(e) != NULL
403*4724848cSchristos                     && !append_buf(&cap_buf, &cap_size, "DH"))
404c9496f6bSchristos                     goto end;
405c9496f6bSchristos                 if (ENGINE_get_RAND(e) != NULL
406*4724848cSchristos                     && !append_buf(&cap_buf, &cap_size, "RAND"))
407c9496f6bSchristos                     goto end;
408c9496f6bSchristos 
409c9496f6bSchristos                 fn_c = ENGINE_get_ciphers(e);
410*4724848cSchristos                 if (fn_c == NULL)
411c9496f6bSchristos                     goto skip_ciphers;
412c9496f6bSchristos                 n = fn_c(e, NULL, &nids, 0);
413c9496f6bSchristos                 for (k = 0; k < n; ++k)
414*4724848cSchristos                     if (!append_buf(&cap_buf, &cap_size, OBJ_nid2sn(nids[k])))
415c9496f6bSchristos                         goto end;
416c9496f6bSchristos 
417c9496f6bSchristos  skip_ciphers:
418c9496f6bSchristos                 fn_d = ENGINE_get_digests(e);
419*4724848cSchristos                 if (fn_d == NULL)
420c9496f6bSchristos                     goto skip_digests;
421c9496f6bSchristos                 n = fn_d(e, NULL, &nids, 0);
422c9496f6bSchristos                 for (k = 0; k < n; ++k)
423*4724848cSchristos                     if (!append_buf(&cap_buf, &cap_size, OBJ_nid2sn(nids[k])))
424c9496f6bSchristos                         goto end;
425c9496f6bSchristos 
426c9496f6bSchristos  skip_digests:
427c9496f6bSchristos                 fn_pk = ENGINE_get_pkey_meths(e);
428*4724848cSchristos                 if (fn_pk == NULL)
429c9496f6bSchristos                     goto skip_pmeths;
430c9496f6bSchristos                 n = fn_pk(e, NULL, &nids, 0);
431c9496f6bSchristos                 for (k = 0; k < n; ++k)
432*4724848cSchristos                     if (!append_buf(&cap_buf, &cap_size, OBJ_nid2sn(nids[k])))
433c9496f6bSchristos                         goto end;
434c9496f6bSchristos  skip_pmeths:
435*4724848cSchristos                 {
436*4724848cSchristos                     struct util_store_cap_data store_ctx;
437*4724848cSchristos 
438*4724848cSchristos                     store_ctx.engine = e;
439*4724848cSchristos                     store_ctx.cap_buf = &cap_buf;
440*4724848cSchristos                     store_ctx.cap_size = &cap_size;
441*4724848cSchristos                     store_ctx.ok = 1;
442*4724848cSchristos 
443*4724848cSchristos                     OSSL_STORE_do_all_loaders(util_store_cap, &store_ctx);
444*4724848cSchristos                     if (!store_ctx.ok)
445*4724848cSchristos                         goto end;
446*4724848cSchristos                 }
447*4724848cSchristos                 if (cap_buf != NULL && (*cap_buf != '\0'))
448*4724848cSchristos                     BIO_printf(out, " [%s]\n", cap_buf);
449c9496f6bSchristos 
450c9496f6bSchristos                 OPENSSL_free(cap_buf);
451c9496f6bSchristos             }
452c9496f6bSchristos             if (test_avail) {
453*4724848cSchristos                 BIO_printf(out, "%s", indent);
454c9496f6bSchristos                 if (ENGINE_init(e)) {
455*4724848cSchristos                     BIO_printf(out, "[ available ]\n");
456*4724848cSchristos                     util_do_cmds(e, post_cmds, out, indent);
457c9496f6bSchristos                     ENGINE_finish(e);
458c9496f6bSchristos                 } else {
459*4724848cSchristos                     BIO_printf(out, "[ unavailable ]\n");
460c9496f6bSchristos                     if (test_avail_noise)
461c9496f6bSchristos                         ERR_print_errors_fp(stdout);
462c9496f6bSchristos                     ERR_clear_error();
463c9496f6bSchristos                 }
464c9496f6bSchristos             }
465*4724848cSchristos             if ((verbose > 0) && !util_verbose(e, verbose, out, indent))
466c9496f6bSchristos                 goto end;
467c9496f6bSchristos             ENGINE_free(e);
468*4724848cSchristos         } else {
469c9496f6bSchristos             ERR_print_errors(bio_err);
470*4724848cSchristos             /* because exit codes above 127 have special meaning on Unix */
471*4724848cSchristos             if (++ret > 127)
472*4724848cSchristos                 ret = 127;
473*4724848cSchristos         }
474c9496f6bSchristos     }
475c9496f6bSchristos 
476c9496f6bSchristos  end:
477c9496f6bSchristos 
478c9496f6bSchristos     ERR_print_errors(bio_err);
479*4724848cSchristos     sk_OPENSSL_CSTRING_free(engines);
480*4724848cSchristos     sk_OPENSSL_STRING_free(pre_cmds);
481*4724848cSchristos     sk_OPENSSL_STRING_free(post_cmds);
482*4724848cSchristos     BIO_free_all(out);
483*4724848cSchristos     return ret;
484c9496f6bSchristos }
485