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

5
Last change on this file since d1dac78 was d1dac78, checked in by Christian Mauderer <christian.mauderer@…>, on 03/26/19 at 10:08:47

bin/openssl: Port to RTEMS.

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