engine.c revision 160815
133965Sjdp/* apps/engine.c -*- mode: C; c-file-style: "eay" -*- */ 233965Sjdp/* Written by Richard Levitte <richard@levitte.org> for the OpenSSL 377298Sobrien * project 2000. 477298Sobrien */ 533965Sjdp/* ==================================================================== 633965Sjdp * Copyright (c) 2000 The OpenSSL Project. All rights reserved. 733965Sjdp * 833965Sjdp * Redistribution and use in source and binary forms, with or without 933965Sjdp * modification, are permitted provided that the following conditions 1033965Sjdp * are met: 1133965Sjdp * 1233965Sjdp * 1. Redistributions of source code must retain the above copyright 1333965Sjdp * notice, this list of conditions and the following disclaimer. 1433965Sjdp * 1533965Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1633965Sjdp * notice, this list of conditions and the following disclaimer in 1733965Sjdp * the documentation and/or other materials provided with the 1860484Sobrien * distribution. 1960484Sobrien * 2033965Sjdp * 3. All advertising materials mentioning features or use of this 2133965Sjdp * software must display the following acknowledgment: 2233965Sjdp * "This product includes software developed by the OpenSSL Project 2333965Sjdp * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 2433965Sjdp * 2533965Sjdp * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 2633965Sjdp * endorse or promote products derived from this software without 2733965Sjdp * prior written permission. For written permission, please contact 2833965Sjdp * licensing@OpenSSL.org. 2933965Sjdp * 3033965Sjdp * 5. Products derived from this software may not be called "OpenSSL" 3133965Sjdp * nor may "OpenSSL" appear in their names without prior written 3233965Sjdp * permission of the OpenSSL Project. 3333965Sjdp * 3433965Sjdp * 6. Redistributions of any form whatsoever must retain the following 3533965Sjdp * acknowledgment: 3633965Sjdp * "This product includes software developed by the OpenSSL Project 3733965Sjdp * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 3833965Sjdp * 3933965Sjdp * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 4033965Sjdp * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4133965Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 4233965Sjdp * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 4333965Sjdp * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 4433965Sjdp * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 4533965Sjdp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 4633965Sjdp * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4733965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 4877298Sobrien * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 4933965Sjdp * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 5033965Sjdp * OF THE POSSIBILITY OF SUCH DAMAGE. 5133965Sjdp * ==================================================================== 5233965Sjdp * 5333965Sjdp * This product includes cryptographic software written by Eric Young 5433965Sjdp * (eay@cryptsoft.com). This product includes software written by Tim 5533965Sjdp * Hudson (tjh@cryptsoft.com). 5633965Sjdp * 5733965Sjdp */ 5833965Sjdp 5933965Sjdp#ifndef OPENSSL_NO_ENGINE 6033965Sjdp 6133965Sjdp#include <stdio.h> 6233965Sjdp#include <stdlib.h> 6333965Sjdp#include <string.h> 6433965Sjdp#ifdef OPENSSL_NO_STDIO 6533965Sjdp#define APPS_WIN16 6633965Sjdp#endif 6733965Sjdp#include "apps.h" 6833965Sjdp#include <openssl/err.h> 6933965Sjdp#include <openssl/engine.h> 7033965Sjdp#include <openssl/ssl.h> 7133965Sjdp 7233965Sjdp#undef PROG 7333965Sjdp#define PROG engine_main 7460484Sobrien 7533965Sjdpstatic const char *engine_usage[]={ 7677298Sobrien"usage: engine opts [engine ...]\n", 7733965Sjdp" -v[v[v[v]]] - verbose mode, for each engine, list its 'control commands'\n", 7833965Sjdp" -vv will additionally display each command's description\n", 7933965Sjdp" -vvv will also add the input flags for each command\n", 8033965Sjdp" -vvvv will also show internal input flags\n", 8133965Sjdp" -c - for each engine, also list the capabilities\n", 8233965Sjdp" -t[t] - for each engine, check that they are really available\n", 8333965Sjdp" -tt will display error trace for unavailable engines\n", 8433965Sjdp" -pre <cmd> - runs command 'cmd' against the ENGINE before any attempts\n", 8533965Sjdp" to load it (if -t is used)\n", 8633965Sjdp" -post <cmd> - runs command 'cmd' against the ENGINE after loading it\n", 8733965Sjdp" (only used if -t is also provided)\n", 8833965Sjdp" NB: -pre and -post will be applied to all ENGINEs supplied on the command\n", 8933965Sjdp" line, or all supported ENGINEs if none are specified.\n", 9033965Sjdp" Eg. '-pre \"SO_PATH:/lib/libdriver.so\"' calls command \"SO_PATH\" with\n", 9133965Sjdp" argument \"/lib/libdriver.so\".\n", 9233965SjdpNULL 9333965Sjdp}; 9433965Sjdp 9533965Sjdpstatic void identity(void *ptr) 9633965Sjdp { 9733965Sjdp return; 9833965Sjdp } 9933965Sjdp 10060484Sobrienstatic int append_buf(char **buf, const char *s, int *size, int step) 10133965Sjdp { 10233965Sjdp int l = strlen(s); 10333965Sjdp 10433965Sjdp if (*buf == NULL) 10533965Sjdp { 10633965Sjdp *size = step; 10733965Sjdp *buf = OPENSSL_malloc(*size); 10833965Sjdp if (*buf == NULL) 10933965Sjdp return 0; 11033965Sjdp **buf = '\0'; 11133965Sjdp } 11233965Sjdp 11333965Sjdp if (**buf != '\0') 11433965Sjdp l += 2; /* ", " */ 11533965Sjdp 11633965Sjdp if (strlen(*buf) + strlen(s) >= (unsigned int)*size) 11733965Sjdp { 11860484Sobrien *size += step; 11933965Sjdp *buf = OPENSSL_realloc(*buf, *size); 12033965Sjdp } 12160484Sobrien 12233965Sjdp if (*buf == NULL) 12333965Sjdp return 0; 12433965Sjdp 12533965Sjdp if (**buf != '\0') 12633965Sjdp BUF_strlcat(*buf, ", ", *size); 12733965Sjdp BUF_strlcat(*buf, s, *size); 12833965Sjdp 12933965Sjdp return 1; 13033965Sjdp } 13133965Sjdp 13233965Sjdpstatic int util_flags(BIO *bio_out, unsigned int flags, const char *indent) 13333965Sjdp { 13433965Sjdp int started = 0, err = 0; 13533965Sjdp /* Indent before displaying input flags */ 13633965Sjdp BIO_printf(bio_out, "%s%s(input flags): ", indent, indent); 13733965Sjdp if(flags == 0) 13833965Sjdp { 13933965Sjdp BIO_printf(bio_out, "<no flags>\n"); 14033965Sjdp return 1; 14133965Sjdp } 14233965Sjdp /* If the object is internal, mark it in a way that shows instead of 14333965Sjdp * having it part of all the other flags, even if it really is. */ 14433965Sjdp if(flags & ENGINE_CMD_FLAG_INTERNAL) 14533965Sjdp { 14660484Sobrien BIO_printf(bio_out, "[Internal] "); 14733965Sjdp } 14833965Sjdp 14933965Sjdp if(flags & ENGINE_CMD_FLAG_NUMERIC) 15033965Sjdp { 15133965Sjdp if(started) 15233965Sjdp { 15333965Sjdp BIO_printf(bio_out, "|"); 15433965Sjdp err = 1; 15533965Sjdp } 15633965Sjdp BIO_printf(bio_out, "NUMERIC"); 15733965Sjdp started = 1; 15833965Sjdp } 15933965Sjdp /* Now we check that no combinations of the mutually exclusive NUMERIC, 16033965Sjdp * STRING, and NO_INPUT flags have been used. Future flags that can be 16133965Sjdp * OR'd together with these would need to added after these to preserve 16233965Sjdp * the testing logic. */ 16333965Sjdp if(flags & ENGINE_CMD_FLAG_STRING) 16433965Sjdp { 16533965Sjdp if(started) 16633965Sjdp { 16733965Sjdp BIO_printf(bio_out, "|"); 16833965Sjdp err = 1; 16933965Sjdp } 17033965Sjdp BIO_printf(bio_out, "STRING"); 17133965Sjdp started = 1; 17233965Sjdp } 17333965Sjdp if(flags & ENGINE_CMD_FLAG_NO_INPUT) 17433965Sjdp { 17533965Sjdp if(started) 17660484Sobrien { 17760484Sobrien BIO_printf(bio_out, "|"); 17833965Sjdp err = 1; 17933965Sjdp } 18033965Sjdp BIO_printf(bio_out, "NO_INPUT"); 18133965Sjdp started = 1; 18233965Sjdp } 18333965Sjdp /* Check for unknown flags */ 18433965Sjdp flags = flags & ~ENGINE_CMD_FLAG_NUMERIC & 18533965Sjdp ~ENGINE_CMD_FLAG_STRING & 18633965Sjdp ~ENGINE_CMD_FLAG_NO_INPUT & 18733965Sjdp ~ENGINE_CMD_FLAG_INTERNAL; 18833965Sjdp if(flags) 18933965Sjdp { 19033965Sjdp if(started) BIO_printf(bio_out, "|"); 19133965Sjdp BIO_printf(bio_out, "<0x%04X>", flags); 19233965Sjdp } 19333965Sjdp if(err) 19433965Sjdp BIO_printf(bio_out, " <illegal flags!>"); 19533965Sjdp BIO_printf(bio_out, "\n"); 19633965Sjdp return 1; 19733965Sjdp } 19833965Sjdp 19933965Sjdpstatic int util_verbose(ENGINE *e, int verbose, BIO *bio_out, const char *indent) 20033965Sjdp { 20133965Sjdp static const int line_wrap = 78; 20233965Sjdp int num; 20333965Sjdp int ret = 0; 20433965Sjdp char *name = NULL; 20533965Sjdp char *desc = NULL; 20660484Sobrien int flags; 20733965Sjdp int xpos = 0; 20833965Sjdp STACK *cmds = NULL; 20933965Sjdp if(!ENGINE_ctrl(e, ENGINE_CTRL_HAS_CTRL_FUNCTION, 0, NULL, NULL) || 21033965Sjdp ((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_FIRST_CMD_TYPE, 21133965Sjdp 0, NULL, NULL)) <= 0)) 21233965Sjdp { 21333965Sjdp#if 0 21433965Sjdp BIO_printf(bio_out, "%s<no control commands>\n", indent); 21533965Sjdp#endif 21633965Sjdp return 1; 21733965Sjdp } 21833965Sjdp 21933965Sjdp cmds = sk_new_null(); 22033965Sjdp 22133965Sjdp if(!cmds) 22233965Sjdp goto err; 22333965Sjdp 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; 291err: 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 298static 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 342int MAIN(int, char **); 343 344int 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; 418skip_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 484skip_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 494skip_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; 526end: 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 539static void *dummy=&dummy; 540# endif 541 542#endif 543