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