Annotation of src/usr.bin/openssl/engine.c, Revision 1.1
1.1 ! jsing 1: /* $OpenBSD: engine.c,v 1.27 2014/07/14 00:35:10 deraadt Exp $ */
! 2: /* Written by Richard Levitte <richard@levitte.org> for the OpenSSL
! 3: * project 2000.
! 4: */
! 5: /* ====================================================================
! 6: * Copyright (c) 2000 The OpenSSL Project. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: *
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: *
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in
! 17: * the documentation and/or other materials provided with the
! 18: * distribution.
! 19: *
! 20: * 3. All advertising materials mentioning features or use of this
! 21: * software must display the following acknowledgment:
! 22: * "This product includes software developed by the OpenSSL Project
! 23: * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
! 24: *
! 25: * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
! 26: * endorse or promote products derived from this software without
! 27: * prior written permission. For written permission, please contact
! 28: * licensing@OpenSSL.org.
! 29: *
! 30: * 5. Products derived from this software may not be called "OpenSSL"
! 31: * nor may "OpenSSL" appear in their names without prior written
! 32: * permission of the OpenSSL Project.
! 33: *
! 34: * 6. Redistributions of any form whatsoever must retain the following
! 35: * acknowledgment:
! 36: * "This product includes software developed by the OpenSSL Project
! 37: * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
! 38: *
! 39: * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
! 40: * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 41: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 42: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
! 43: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
! 44: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 45: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
! 46: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 47: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
! 48: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 49: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
! 50: * OF THE POSSIBILITY OF SUCH DAMAGE.
! 51: * ====================================================================
! 52: *
! 53: * This product includes cryptographic software written by Eric Young
! 54: * (eay@cryptsoft.com). This product includes software written by Tim
! 55: * Hudson (tjh@cryptsoft.com).
! 56: *
! 57: */
! 58:
! 59: #include <stdio.h>
! 60: #include <stdlib.h>
! 61: #include <string.h>
! 62:
! 63: #include "apps.h"
! 64:
! 65: #ifndef OPENSSL_NO_ENGINE
! 66: #include <openssl/engine.h>
! 67: #include <openssl/err.h>
! 68: #include <openssl/ssl.h>
! 69:
! 70: static const char *engine_usage[] = {
! 71: "usage: engine opts [engine ...]\n",
! 72: " -v[v[v[v]]] - verbose mode, for each engine, list its 'control commands'\n",
! 73: " -vv will additionally display each command's description\n",
! 74: " -vvv will also add the input flags for each command\n",
! 75: " -vvvv will also show internal input flags\n",
! 76: " -c - for each engine, also list the capabilities\n",
! 77: " -t[t] - for each engine, check that they are really available\n",
! 78: " -tt will display error trace for unavailable engines\n",
! 79: " -pre <cmd> - runs command 'cmd' against the ENGINE before any attempts\n",
! 80: " to load it (if -t is used)\n",
! 81: " -post <cmd> - runs command 'cmd' against the ENGINE after loading it\n",
! 82: " (only used if -t is also provided)\n",
! 83: " NB: -pre and -post will be applied to all ENGINEs supplied on the command\n",
! 84: " line, or all supported ENGINEs if none are specified.\n",
! 85: " Eg. '-pre \"SO_PATH:/lib/libdriver.so\"' calls command \"SO_PATH\" with\n",
! 86: " argument \"/lib/libdriver.so\".\n",
! 87: NULL
! 88: };
! 89:
! 90: static void
! 91: identity(char *ptr)
! 92: {
! 93: return;
! 94: }
! 95:
! 96: static int
! 97: append_buf(char **buf, const char *s, int *size, int step)
! 98: {
! 99: int l = strlen(s);
! 100:
! 101: if (*buf == NULL) {
! 102: *size = step;
! 103: *buf = malloc(*size);
! 104: if (*buf == NULL)
! 105: return 0;
! 106: **buf = '\0';
! 107: }
! 108: if (**buf != '\0')
! 109: l += 2; /* ", " */
! 110:
! 111: if (strlen(*buf) + strlen(s) >= (unsigned int) *size) {
! 112: *size += step;
! 113: *buf = realloc(*buf, *size);
! 114: }
! 115: if (*buf == NULL)
! 116: return 0;
! 117:
! 118: if (**buf != '\0')
! 119: strlcat(*buf, ", ", *size);
! 120: strlcat(*buf, s, *size);
! 121:
! 122: return 1;
! 123: }
! 124:
! 125: static int
! 126: util_flags(BIO * bio_out, unsigned int flags, const char *indent)
! 127: {
! 128: int started = 0, err = 0;
! 129: /* Indent before displaying input flags */
! 130: BIO_printf(bio_out, "%s%s(input flags): ", indent, indent);
! 131: if (flags == 0) {
! 132: BIO_printf(bio_out, "<no flags>\n");
! 133: return 1;
! 134: }
! 135: /*
! 136: * If the object is internal, mark it in a way that shows instead of
! 137: * having it part of all the other flags, even if it really is.
! 138: */
! 139: if (flags & ENGINE_CMD_FLAG_INTERNAL) {
! 140: BIO_printf(bio_out, "[Internal] ");
! 141: }
! 142: if (flags & ENGINE_CMD_FLAG_NUMERIC) {
! 143: BIO_printf(bio_out, "NUMERIC");
! 144: started = 1;
! 145: }
! 146: /*
! 147: * Now we check that no combinations of the mutually exclusive
! 148: * NUMERIC, STRING, and NO_INPUT flags have been used. Future flags
! 149: * that can be OR'd together with these would need to added after
! 150: * these to preserve the testing logic.
! 151: */
! 152: if (flags & ENGINE_CMD_FLAG_STRING) {
! 153: if (started) {
! 154: BIO_printf(bio_out, "|");
! 155: err = 1;
! 156: }
! 157: BIO_printf(bio_out, "STRING");
! 158: started = 1;
! 159: }
! 160: if (flags & ENGINE_CMD_FLAG_NO_INPUT) {
! 161: if (started) {
! 162: BIO_printf(bio_out, "|");
! 163: err = 1;
! 164: }
! 165: BIO_printf(bio_out, "NO_INPUT");
! 166: started = 1;
! 167: }
! 168: /* Check for unknown flags */
! 169: flags = flags & ~ENGINE_CMD_FLAG_NUMERIC &
! 170: ~ENGINE_CMD_FLAG_STRING &
! 171: ~ENGINE_CMD_FLAG_NO_INPUT &
! 172: ~ENGINE_CMD_FLAG_INTERNAL;
! 173: if (flags) {
! 174: if (started)
! 175: BIO_printf(bio_out, "|");
! 176: BIO_printf(bio_out, "<0x%04X>", flags);
! 177: }
! 178: if (err)
! 179: BIO_printf(bio_out, " <illegal flags!>");
! 180: BIO_printf(bio_out, "\n");
! 181: return 1;
! 182: }
! 183:
! 184: static int
! 185: util_verbose(ENGINE * e, int verbose, BIO * bio_out, const char *indent)
! 186: {
! 187: static const int line_wrap = 78;
! 188: int num;
! 189: int ret = 0;
! 190: char *name = NULL;
! 191: char *desc = NULL;
! 192: int flags;
! 193: int xpos = 0;
! 194: STACK_OF(OPENSSL_STRING) * cmds = NULL;
! 195: if (!ENGINE_ctrl(e, ENGINE_CTRL_HAS_CTRL_FUNCTION, 0, NULL, NULL) ||
! 196: ((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_FIRST_CMD_TYPE,
! 197: 0, NULL, NULL)) <= 0)) {
! 198: #if 0
! 199: BIO_printf(bio_out, "%s<no control commands>\n", indent);
! 200: #endif
! 201: return 1;
! 202: }
! 203: cmds = sk_OPENSSL_STRING_new_null();
! 204:
! 205: if (!cmds)
! 206: goto err;
! 207: do {
! 208: int len;
! 209: /* Get the command input flags */
! 210: if ((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num,
! 211: NULL, NULL)) < 0)
! 212: goto err;
! 213: if (!(flags & ENGINE_CMD_FLAG_INTERNAL) || verbose >= 4) {
! 214: /* Get the command name */
! 215: if ((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_LEN_FROM_CMD, num,
! 216: NULL, NULL)) <= 0)
! 217: goto err;
! 218: if ((name = malloc(len + 1)) == NULL)
! 219: goto err;
! 220: if (ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_FROM_CMD, num, name,
! 221: NULL) <= 0)
! 222: goto err;
! 223: /* Get the command description */
! 224: if ((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_LEN_FROM_CMD, num,
! 225: NULL, NULL)) < 0)
! 226: goto err;
! 227: if (len > 0) {
! 228: if ((desc = malloc(len + 1)) == NULL)
! 229: goto err;
! 230: if (ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_FROM_CMD, num, desc,
! 231: NULL) <= 0)
! 232: goto err;
! 233: }
! 234: /* Now decide on the output */
! 235: if (xpos == 0)
! 236: /* Do an indent */
! 237: xpos = BIO_puts(bio_out, indent);
! 238: else
! 239: /* Otherwise prepend a ", " */
! 240: xpos += BIO_printf(bio_out, ", ");
! 241: if (verbose == 1) {
! 242: /* We're just listing names, comma-delimited */
! 243: if ((xpos > (int) strlen(indent)) &&
! 244: (xpos + (int) strlen(name) > line_wrap)) {
! 245: BIO_printf(bio_out, "\n");
! 246: xpos = BIO_puts(bio_out, indent);
! 247: }
! 248: xpos += BIO_printf(bio_out, "%s", name);
! 249: } else {
! 250: /* We're listing names plus descriptions */
! 251: BIO_printf(bio_out, "%s: %s\n", name,
! 252: (desc == NULL) ? "<no description>" : desc);
! 253: /* ... and sometimes input flags */
! 254: if ((verbose >= 3) && !util_flags(bio_out, flags,
! 255: indent))
! 256: goto err;
! 257: xpos = 0;
! 258: }
! 259: }
! 260: free(name);
! 261: name = NULL;
! 262: free(desc);
! 263: desc = NULL;
! 264:
! 265: /* Move to the next command */
! 266: num = ENGINE_ctrl(e, ENGINE_CTRL_GET_NEXT_CMD_TYPE,
! 267: num, NULL, NULL);
! 268: } while (num > 0);
! 269: if (xpos > 0)
! 270: BIO_printf(bio_out, "\n");
! 271: ret = 1;
! 272: err:
! 273: if (cmds)
! 274: sk_OPENSSL_STRING_pop_free(cmds, identity);
! 275: free(name);
! 276: free(desc);
! 277: return ret;
! 278: }
! 279:
! 280: static void
! 281: util_do_cmds(ENGINE * e, STACK_OF(OPENSSL_STRING) * cmds,
! 282: BIO * bio_out, const char *indent)
! 283: {
! 284: int loop, res, num = sk_OPENSSL_STRING_num(cmds);
! 285:
! 286: if (num < 0) {
! 287: BIO_printf(bio_out, "[Error]: internal stack error\n");
! 288: return;
! 289: }
! 290: for (loop = 0; loop < num; loop++) {
! 291: char buf[256];
! 292: const char *cmd, *arg;
! 293: cmd = sk_OPENSSL_STRING_value(cmds, loop);
! 294: res = 1; /* assume success */
! 295: /* Check if this command has no ":arg" */
! 296: if ((arg = strstr(cmd, ":")) == NULL) {
! 297: if (!ENGINE_ctrl_cmd_string(e, cmd, NULL, 0))
! 298: res = 0;
! 299: } else {
! 300: if ((int) (arg - cmd) > 254) {
! 301: BIO_printf(bio_out, "[Error]: command name too long\n");
! 302: return;
! 303: }
! 304: memcpy(buf, cmd, (int) (arg - cmd));
! 305: buf[arg - cmd] = '\0';
! 306: arg++; /* Move past the ":" */
! 307: /* Call the command with the argument */
! 308: if (!ENGINE_ctrl_cmd_string(e, buf, arg, 0))
! 309: res = 0;
! 310: }
! 311: if (res)
! 312: BIO_printf(bio_out, "[Success]: %s\n", cmd);
! 313: else {
! 314: BIO_printf(bio_out, "[Failure]: %s\n", cmd);
! 315: ERR_print_errors(bio_out);
! 316: }
! 317: }
! 318: }
! 319:
! 320: int engine_main(int, char **);
! 321:
! 322: int
! 323: engine_main(int argc, char **argv)
! 324: {
! 325: int ret = 1, i;
! 326: const char **pp;
! 327: int verbose = 0, list_cap = 0, test_avail = 0, test_avail_noise = 0;
! 328: ENGINE *e;
! 329: STACK_OF(OPENSSL_STRING) * engines = sk_OPENSSL_STRING_new_null();
! 330: STACK_OF(OPENSSL_STRING) * pre_cmds = sk_OPENSSL_STRING_new_null();
! 331: STACK_OF(OPENSSL_STRING) * post_cmds = sk_OPENSSL_STRING_new_null();
! 332: int badops = 1;
! 333: BIO *bio_out = NULL;
! 334: const char *indent = " ";
! 335:
! 336: bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
! 337:
! 338: argc--;
! 339: argv++;
! 340: while (argc >= 1) {
! 341: if (strncmp(*argv, "-v", 2) == 0) {
! 342: if (strspn(*argv + 1, "v") < strlen(*argv + 1))
! 343: goto skip_arg_loop;
! 344: if ((verbose = strlen(*argv + 1)) > 4)
! 345: goto skip_arg_loop;
! 346: } else if (strcmp(*argv, "-c") == 0)
! 347: list_cap = 1;
! 348: else if (strncmp(*argv, "-t", 2) == 0) {
! 349: test_avail = 1;
! 350: if (strspn(*argv + 1, "t") < strlen(*argv + 1))
! 351: goto skip_arg_loop;
! 352: if ((test_avail_noise = strlen(*argv + 1) - 1) > 1)
! 353: goto skip_arg_loop;
! 354: } else if (strcmp(*argv, "-pre") == 0) {
! 355: argc--;
! 356: argv++;
! 357: if (argc == 0)
! 358: goto skip_arg_loop;
! 359: sk_OPENSSL_STRING_push(pre_cmds, *argv);
! 360: } else if (strcmp(*argv, "-post") == 0) {
! 361: argc--;
! 362: argv++;
! 363: if (argc == 0)
! 364: goto skip_arg_loop;
! 365: sk_OPENSSL_STRING_push(post_cmds, *argv);
! 366: } else if ((strncmp(*argv, "-h", 2) == 0) ||
! 367: (strcmp(*argv, "-?") == 0))
! 368: goto skip_arg_loop;
! 369: else
! 370: sk_OPENSSL_STRING_push(engines, *argv);
! 371: argc--;
! 372: argv++;
! 373: }
! 374: /* Looks like everything went OK */
! 375: badops = 0;
! 376: skip_arg_loop:
! 377:
! 378: if (badops) {
! 379: for (pp = engine_usage; (*pp != NULL); pp++)
! 380: BIO_printf(bio_err, "%s", *pp);
! 381: goto end;
! 382: }
! 383: if (sk_OPENSSL_STRING_num(engines) == 0) {
! 384: for (e = ENGINE_get_first(); e != NULL; e = ENGINE_get_next(e)) {
! 385: sk_OPENSSL_STRING_push(engines, (char *) ENGINE_get_id(e));
! 386: }
! 387: }
! 388: for (i = 0; i < sk_OPENSSL_STRING_num(engines); i++) {
! 389: const char *id = sk_OPENSSL_STRING_value(engines, i);
! 390: if ((e = ENGINE_by_id(id)) != NULL) {
! 391: const char *name = ENGINE_get_name(e);
! 392: /* Do "id" first, then "name". Easier to auto-parse. */
! 393: BIO_printf(bio_out, "(%s) %s\n", id, name);
! 394: util_do_cmds(e, pre_cmds, bio_out, indent);
! 395: if (strcmp(ENGINE_get_id(e), id) != 0) {
! 396: BIO_printf(bio_out, "Loaded: (%s) %s\n",
! 397: ENGINE_get_id(e), ENGINE_get_name(e));
! 398: }
! 399: if (list_cap) {
! 400: int cap_size = 256;
! 401: char *cap_buf = NULL;
! 402: int k, n;
! 403: const int *nids;
! 404: ENGINE_CIPHERS_PTR fn_c;
! 405: ENGINE_DIGESTS_PTR fn_d;
! 406: ENGINE_PKEY_METHS_PTR fn_pk;
! 407:
! 408: if (ENGINE_get_RSA(e) != NULL
! 409: && !append_buf(&cap_buf, "RSA",
! 410: &cap_size, 256))
! 411: goto end;
! 412: if (ENGINE_get_DSA(e) != NULL
! 413: && !append_buf(&cap_buf, "DSA",
! 414: &cap_size, 256))
! 415: goto end;
! 416: if (ENGINE_get_DH(e) != NULL
! 417: && !append_buf(&cap_buf, "DH",
! 418: &cap_size, 256))
! 419: goto end;
! 420: if (ENGINE_get_RAND(e) != NULL
! 421: && !append_buf(&cap_buf, "RAND",
! 422: &cap_size, 256))
! 423: goto end;
! 424:
! 425: fn_c = ENGINE_get_ciphers(e);
! 426: if (!fn_c)
! 427: goto skip_ciphers;
! 428: n = fn_c(e, NULL, &nids, 0);
! 429: for (k = 0; k < n; ++k)
! 430: if (!append_buf(&cap_buf,
! 431: OBJ_nid2sn(nids[k]),
! 432: &cap_size, 256))
! 433: goto end;
! 434:
! 435: skip_ciphers:
! 436: fn_d = ENGINE_get_digests(e);
! 437: if (!fn_d)
! 438: goto skip_digests;
! 439: n = fn_d(e, NULL, &nids, 0);
! 440: for (k = 0; k < n; ++k)
! 441: if (!append_buf(&cap_buf,
! 442: OBJ_nid2sn(nids[k]),
! 443: &cap_size, 256))
! 444: goto end;
! 445:
! 446: skip_digests:
! 447: fn_pk = ENGINE_get_pkey_meths(e);
! 448: if (!fn_pk)
! 449: goto skip_pmeths;
! 450: n = fn_pk(e, NULL, &nids, 0);
! 451: for (k = 0; k < n; ++k)
! 452: if (!append_buf(&cap_buf,
! 453: OBJ_nid2sn(nids[k]),
! 454: &cap_size, 256))
! 455: goto end;
! 456: skip_pmeths:
! 457: if (cap_buf && (*cap_buf != '\0'))
! 458: BIO_printf(bio_out, " [%s]\n", cap_buf);
! 459:
! 460: free(cap_buf);
! 461: }
! 462: if (test_avail) {
! 463: BIO_printf(bio_out, "%s", indent);
! 464: if (ENGINE_init(e)) {
! 465: BIO_printf(bio_out, "[ available ]\n");
! 466: util_do_cmds(e, post_cmds, bio_out, indent);
! 467: ENGINE_finish(e);
! 468: } else {
! 469: BIO_printf(bio_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, bio_out, indent))
! 476: goto end;
! 477: ENGINE_free(e);
! 478: } else
! 479: ERR_print_errors(bio_err);
! 480: }
! 481:
! 482: ret = 0;
! 483: end:
! 484:
! 485: ERR_print_errors(bio_err);
! 486: sk_OPENSSL_STRING_pop_free(engines, identity);
! 487: sk_OPENSSL_STRING_pop_free(pre_cmds, identity);
! 488: sk_OPENSSL_STRING_pop_free(post_cmds, identity);
! 489: if (bio_out != NULL)
! 490: BIO_free_all(bio_out);
! 491:
! 492: return (ret);
! 493: }
! 494: #endif