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