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