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