"Fossies" - the Fresh Open Source Software Archive

Member "openssl-1.1.1g/apps/engine.c" (21 Apr 2020, 15934 Bytes) of package /linux/misc/openssl-1.1.1g.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "engine.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.1.1f_vs_1.1.1g.

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