source: rtems-libbsd/freebsd/crypto/openssl/apps/engine.c @ 0a699e7

5-freebsd-126-freebsd-12
Last change on this file since 0a699e7 was 0a699e7, checked in by Christian Mauderer <christian.mauderer@…>, on 03/28/19 at 06:13:59

bin/openssl: Import from FreeBSD.

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