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