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