1 /* apps/engine.c -*- mode: C; c-file-style: "eay" -*- */ 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 int l = strlen(s); 103 104 if (*buf == NULL) { 105 *size = step; 106 *buf = OPENSSL_malloc(*size); 107 if (*buf == NULL) 108 return 0; 109 **buf = '\0'; 110 } 111 112 if (**buf != '\0') 113 l += 2; /* ", " */ 114 115 if (strlen(*buf) + strlen(s) >= (unsigned int)*size) { 116 *size += step; 117 *buf = OPENSSL_realloc(*buf, *size); 118 } 119 120 if (*buf == NULL) 121 return 0; 122 123 if (**buf != '\0') 124 BUF_strlcat(*buf, ", ", *size); 125 BUF_strlcat(*buf, s, *size); 126 127 return 1; 128 } 129 130 static int util_flags(BIO *bio_out, unsigned int flags, const char *indent) 131 { 132 int started = 0, err = 0; 133 /* Indent before displaying input flags */ 134 BIO_printf(bio_out, "%s%s(input flags): ", indent, indent); 135 if (flags == 0) { 136 BIO_printf(bio_out, "<no flags>\n"); 137 return 1; 138 } 139 /* 140 * If the object is internal, mark it in a way that shows instead of 141 * having it part of all the other flags, even if it really is. 142 */ 143 if (flags & ENGINE_CMD_FLAG_INTERNAL) { 144 BIO_printf(bio_out, "[Internal] "); 145 } 146 147 if (flags & ENGINE_CMD_FLAG_NUMERIC) { 148 BIO_printf(bio_out, "NUMERIC"); 149 started = 1; 150 } 151 /* 152 * Now we check that no combinations of the mutually exclusive NUMERIC, 153 * STRING, and NO_INPUT flags have been used. Future flags that can be 154 * OR'd together with these would need to added after these to preserve 155 * the testing logic. 156 */ 157 if (flags & ENGINE_CMD_FLAG_STRING) { 158 if (started) { 159 BIO_printf(bio_out, "|"); 160 err = 1; 161 } 162 BIO_printf(bio_out, "STRING"); 163 started = 1; 164 } 165 if (flags & ENGINE_CMD_FLAG_NO_INPUT) { 166 if (started) { 167 BIO_printf(bio_out, "|"); 168 err = 1; 169 } 170 BIO_printf(bio_out, "NO_INPUT"); 171 started = 1; 172 } 173 /* Check for unknown flags */ 174 flags = flags & ~ENGINE_CMD_FLAG_NUMERIC & 175 ~ENGINE_CMD_FLAG_STRING & 176 ~ENGINE_CMD_FLAG_NO_INPUT & ~ENGINE_CMD_FLAG_INTERNAL; 177 if (flags) { 178 if (started) 179 BIO_printf(bio_out, "|"); 180 BIO_printf(bio_out, "<0x%04X>", flags); 181 } 182 if (err) 183 BIO_printf(bio_out, " <illegal flags!>"); 184 BIO_printf(bio_out, "\n"); 185 return 1; 186 } 187 188 static int util_verbose(ENGINE *e, int verbose, BIO *bio_out, 189 const char *indent) 190 { 191 static const int line_wrap = 78; 192 int num; 193 int ret = 0; 194 char *name = NULL; 195 char *desc = NULL; 196 int flags; 197 int xpos = 0; 198 STACK_OF(OPENSSL_STRING) *cmds = NULL; 199 if (!ENGINE_ctrl(e, ENGINE_CTRL_HAS_CTRL_FUNCTION, 0, NULL, NULL) || 200 ((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_FIRST_CMD_TYPE, 201 0, NULL, NULL)) <= 0)) { 202 # if 0 203 BIO_printf(bio_out, "%s<no control commands>\n", indent); 204 # endif 205 return 1; 206 } 207 208 cmds = sk_OPENSSL_STRING_new_null(); 209 210 if (!cmds) 211 goto err; 212 do { 213 int len; 214 /* Get the command input flags */ 215 if ((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, 216 NULL, NULL)) < 0) 217 goto err; 218 if (!(flags & ENGINE_CMD_FLAG_INTERNAL) || verbose >= 4) { 219 /* Get the command name */ 220 if ((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_LEN_FROM_CMD, num, 221 NULL, NULL)) <= 0) 222 goto err; 223 if ((name = OPENSSL_malloc(len + 1)) == NULL) 224 goto err; 225 if (ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_FROM_CMD, num, name, 226 NULL) <= 0) 227 goto err; 228 /* Get the command description */ 229 if ((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_LEN_FROM_CMD, num, 230 NULL, NULL)) < 0) 231 goto err; 232 if (len > 0) { 233 if ((desc = OPENSSL_malloc(len + 1)) == NULL) 234 goto err; 235 if (ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_FROM_CMD, num, desc, 236 NULL) <= 0) 237 goto err; 238 } 239 /* Now decide on the output */ 240 if (xpos == 0) 241 /* Do an indent */ 242 xpos = BIO_puts(bio_out, indent); 243 else 244 /* Otherwise prepend a ", " */ 245 xpos += BIO_printf(bio_out, ", "); 246 if (verbose == 1) { 247 /* 248 * We're just listing names, comma-delimited 249 */ 250 if ((xpos > (int)strlen(indent)) && 251 (xpos + (int)strlen(name) > line_wrap)) { 252 BIO_printf(bio_out, "\n"); 253 xpos = BIO_puts(bio_out, indent); 254 } 255 xpos += BIO_printf(bio_out, "%s", name); 256 } else { 257 /* We're listing names plus descriptions */ 258 BIO_printf(bio_out, "%s: %s\n", name, 259 (desc == NULL) ? "<no description>" : desc); 260 /* ... and sometimes input flags */ 261 if ((verbose >= 3) && !util_flags(bio_out, flags, indent)) 262 goto err; 263 xpos = 0; 264 } 265 } 266 OPENSSL_free(name); 267 name = NULL; 268 if (desc) { 269 OPENSSL_free(desc); 270 desc = NULL; 271 } 272 /* Move to the next command */ 273 num = ENGINE_ctrl(e, ENGINE_CTRL_GET_NEXT_CMD_TYPE, num, NULL, NULL); 274 } while (num > 0); 275 if (xpos > 0) 276 BIO_printf(bio_out, "\n"); 277 ret = 1; 278 err: 279 if (cmds) 280 sk_OPENSSL_STRING_pop_free(cmds, identity); 281 if (name) 282 OPENSSL_free(name); 283 if (desc) 284 OPENSSL_free(desc); 285 return ret; 286 } 287 288 static void util_do_cmds(ENGINE *e, STACK_OF(OPENSSL_STRING) *cmds, 289 BIO *bio_out, const char *indent) 290 { 291 int loop, res, num = sk_OPENSSL_STRING_num(cmds); 292 293 if (num < 0) { 294 BIO_printf(bio_out, "[Error]: internal stack error\n"); 295 return; 296 } 297 for (loop = 0; loop < num; loop++) { 298 char buf[256]; 299 const char *cmd, *arg; 300 cmd = sk_OPENSSL_STRING_value(cmds, loop); 301 res = 1; /* assume success */ 302 /* Check if this command has no ":arg" */ 303 if ((arg = strstr(cmd, ":")) == NULL) { 304 if (!ENGINE_ctrl_cmd_string(e, cmd, NULL, 0)) 305 res = 0; 306 } else { 307 if ((int)(arg - cmd) > 254) { 308 BIO_printf(bio_out, "[Error]: command name too long\n"); 309 return; 310 } 311 memcpy(buf, cmd, (int)(arg - cmd)); 312 buf[arg - cmd] = '\0'; 313 arg++; /* Move past the ":" */ 314 /* Call the command with the argument */ 315 if (!ENGINE_ctrl_cmd_string(e, buf, arg, 0)) 316 res = 0; 317 } 318 if (res) 319 BIO_printf(bio_out, "[Success]: %s\n", cmd); 320 else { 321 BIO_printf(bio_out, "[Failure]: %s\n", cmd); 322 ERR_print_errors(bio_out); 323 } 324 } 325 } 326 327 int MAIN(int, char **); 328 329 int MAIN(int argc, char **argv) 330 { 331 int ret = 1, i; 332 const char **pp; 333 int verbose = 0, list_cap = 0, test_avail = 0, test_avail_noise = 0; 334 ENGINE *e; 335 STACK_OF(OPENSSL_STRING) *engines = sk_OPENSSL_STRING_new_null(); 336 STACK_OF(OPENSSL_STRING) *pre_cmds = sk_OPENSSL_STRING_new_null(); 337 STACK_OF(OPENSSL_STRING) *post_cmds = sk_OPENSSL_STRING_new_null(); 338 int badops = 1; 339 BIO *bio_out = NULL; 340 const char *indent = " "; 341 342 apps_startup(); 343 SSL_load_error_strings(); 344 345 if (bio_err == NULL) 346 bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); 347 348 if (!load_config(bio_err, NULL)) 349 goto end; 350 bio_out = BIO_new_fp(stdout, BIO_NOCLOSE); 351 # ifdef OPENSSL_SYS_VMS 352 { 353 BIO *tmpbio = BIO_new(BIO_f_linebuffer()); 354 bio_out = BIO_push(tmpbio, bio_out); 355 } 356 # endif 357 358 argc--; 359 argv++; 360 while (argc >= 1) { 361 if (strncmp(*argv, "-v", 2) == 0) { 362 if (strspn(*argv + 1, "v") < strlen(*argv + 1)) 363 goto skip_arg_loop; 364 if ((verbose = strlen(*argv + 1)) > 4) 365 goto skip_arg_loop; 366 } else if (strcmp(*argv, "-c") == 0) 367 list_cap = 1; 368 else if (strncmp(*argv, "-t", 2) == 0) { 369 test_avail = 1; 370 if (strspn(*argv + 1, "t") < strlen(*argv + 1)) 371 goto skip_arg_loop; 372 if ((test_avail_noise = strlen(*argv + 1) - 1) > 1) 373 goto skip_arg_loop; 374 } else if (strcmp(*argv, "-pre") == 0) { 375 argc--; 376 argv++; 377 if (argc == 0) 378 goto skip_arg_loop; 379 sk_OPENSSL_STRING_push(pre_cmds, *argv); 380 } else if (strcmp(*argv, "-post") == 0) { 381 argc--; 382 argv++; 383 if (argc == 0) 384 goto skip_arg_loop; 385 sk_OPENSSL_STRING_push(post_cmds, *argv); 386 } else if ((strncmp(*argv, "-h", 2) == 0) || 387 (strcmp(*argv, "-?") == 0)) 388 goto skip_arg_loop; 389 else 390 sk_OPENSSL_STRING_push(engines, *argv); 391 argc--; 392 argv++; 393 } 394 /* Looks like everything went OK */ 395 badops = 0; 396 skip_arg_loop: 397 398 if (badops) { 399 for (pp = engine_usage; (*pp != NULL); pp++) 400 BIO_printf(bio_err, "%s", *pp); 401 goto end; 402 } 403 404 if (sk_OPENSSL_STRING_num(engines) == 0) { 405 for (e = ENGINE_get_first(); e != NULL; e = ENGINE_get_next(e)) { 406 sk_OPENSSL_STRING_push(engines, (char *)ENGINE_get_id(e)); 407 } 408 } 409 410 for (i = 0; i < sk_OPENSSL_STRING_num(engines); i++) { 411 const char *id = sk_OPENSSL_STRING_value(engines, i); 412 if ((e = ENGINE_by_id(id)) != NULL) { 413 const char *name = ENGINE_get_name(e); 414 /* 415 * Do "id" first, then "name". Easier to auto-parse. 416 */ 417 BIO_printf(bio_out, "(%s) %s\n", id, name); 418 util_do_cmds(e, pre_cmds, bio_out, indent); 419 if (strcmp(ENGINE_get_id(e), id) != 0) { 420 BIO_printf(bio_out, "Loaded: (%s) %s\n", 421 ENGINE_get_id(e), ENGINE_get_name(e)); 422 } 423 if (list_cap) { 424 int cap_size = 256; 425 char *cap_buf = NULL; 426 int k, n; 427 const int *nids; 428 ENGINE_CIPHERS_PTR fn_c; 429 ENGINE_DIGESTS_PTR fn_d; 430 ENGINE_PKEY_METHS_PTR fn_pk; 431 432 if (ENGINE_get_RSA(e) != NULL 433 && !append_buf(&cap_buf, "RSA", &cap_size, 256)) 434 goto end; 435 if (ENGINE_get_DSA(e) != NULL 436 && !append_buf(&cap_buf, "DSA", &cap_size, 256)) 437 goto end; 438 if (ENGINE_get_DH(e) != NULL 439 && !append_buf(&cap_buf, "DH", &cap_size, 256)) 440 goto end; 441 if (ENGINE_get_RAND(e) != NULL 442 && !append_buf(&cap_buf, "RAND", &cap_size, 256)) 443 goto end; 444 445 fn_c = ENGINE_get_ciphers(e); 446 if (!fn_c) 447 goto skip_ciphers; 448 n = fn_c(e, NULL, &nids, 0); 449 for (k = 0; k < n; ++k) 450 if (!append_buf(&cap_buf, 451 OBJ_nid2sn(nids[k]), &cap_size, 256)) 452 goto end; 453 454 skip_ciphers: 455 fn_d = ENGINE_get_digests(e); 456 if (!fn_d) 457 goto skip_digests; 458 n = fn_d(e, NULL, &nids, 0); 459 for (k = 0; k < n; ++k) 460 if (!append_buf(&cap_buf, 461 OBJ_nid2sn(nids[k]), &cap_size, 256)) 462 goto end; 463 464 skip_digests: 465 fn_pk = ENGINE_get_pkey_meths(e); 466 if (!fn_pk) 467 goto skip_pmeths; 468 n = fn_pk(e, NULL, &nids, 0); 469 for (k = 0; k < n; ++k) 470 if (!append_buf(&cap_buf, 471 OBJ_nid2sn(nids[k]), &cap_size, 256)) 472 goto end; 473 skip_pmeths: 474 if (cap_buf && (*cap_buf != '\0')) 475 BIO_printf(bio_out, " [%s]\n", cap_buf); 476 477 OPENSSL_free(cap_buf); 478 } 479 if (test_avail) { 480 BIO_printf(bio_out, "%s", indent); 481 if (ENGINE_init(e)) { 482 BIO_printf(bio_out, "[ available ]\n"); 483 util_do_cmds(e, post_cmds, bio_out, indent); 484 ENGINE_finish(e); 485 } else { 486 BIO_printf(bio_out, "[ unavailable ]\n"); 487 if (test_avail_noise) 488 ERR_print_errors_fp(stdout); 489 ERR_clear_error(); 490 } 491 } 492 if ((verbose > 0) && !util_verbose(e, verbose, bio_out, indent)) 493 goto end; 494 ENGINE_free(e); 495 } else 496 ERR_print_errors(bio_err); 497 } 498 499 ret = 0; 500 end: 501 502 ERR_print_errors(bio_err); 503 sk_OPENSSL_STRING_pop_free(engines, identity); 504 sk_OPENSSL_STRING_pop_free(pre_cmds, identity); 505 sk_OPENSSL_STRING_pop_free(post_cmds, identity); 506 if (bio_out != NULL) 507 BIO_free_all(bio_out); 508 apps_shutdown(); 509 OPENSSL_EXIT(ret); 510 } 511 #else 512 513 # if PEDANTIC 514 static void *dummy = &dummy; 515 # endif 516 517 #endif 518