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