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