1 /* 2 * Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 /* We need to use some engine deprecated APIs */ 11 #define OPENSSL_SUPPRESS_DEPRECATED 12 13 #include <openssl/opensslconf.h> 14 15 #include "apps.h" 16 #include "progs.h" 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <openssl/err.h> 21 #include <openssl/engine.h> 22 #include <openssl/ssl.h> 23 #include <openssl/store.h> 24 25 typedef enum OPTION_choice { 26 OPT_COMMON, 27 OPT_C, OPT_T, OPT_TT, OPT_PRE, OPT_POST, 28 OPT_V = 100, OPT_VV, OPT_VVV, OPT_VVVV 29 } OPTION_CHOICE; 30 31 const OPTIONS engine_options[] = { 32 {OPT_HELP_STR, 1, '-', "Usage: %s [options] engine...\n"}, 33 34 OPT_SECTION("General"), 35 {"help", OPT_HELP, '-', "Display this summary"}, 36 {"t", OPT_T, '-', "Check that specified engine is available"}, 37 {"pre", OPT_PRE, 's', "Run command against the ENGINE before loading it"}, 38 {"post", OPT_POST, 's', "Run command against the ENGINE after loading it"}, 39 40 OPT_SECTION("Output"), 41 {"v", OPT_V, '-', "List 'control commands' For each specified engine"}, 42 {"vv", OPT_VV, '-', "Also display each command's description"}, 43 {"vvv", OPT_VVV, '-', "Also add the input flags for each command"}, 44 {"vvvv", OPT_VVVV, '-', "Also show internal input flags"}, 45 {"c", OPT_C, '-', "List the capabilities of specified engine"}, 46 {"tt", OPT_TT, '-', "Display error trace for unavailable engines"}, 47 {OPT_MORE_STR, OPT_EOF, 1, 48 "Commands are like \"SO_PATH:/lib/libdriver.so\""}, 49 50 OPT_PARAMETERS(), 51 {"engine", 0, 0, "ID of engine(s) to load"}, 52 {NULL} 53 }; 54 55 static int append_buf(char **buf, int *size, const char *s) 56 { 57 const int expand = 256; 58 int len = strlen(s) + 1; 59 char *p = *buf; 60 61 if (p == NULL) { 62 *size = ((len + expand - 1) / expand) * expand; 63 p = *buf = app_malloc(*size, "engine buffer"); 64 } else { 65 const int blen = strlen(p); 66 67 if (blen > 0) 68 len += 2 + blen; 69 70 if (len > *size) { 71 *size = ((len + expand - 1) / expand) * expand; 72 p = OPENSSL_realloc(p, *size); 73 if (p == NULL) { 74 OPENSSL_free(*buf); 75 *buf = NULL; 76 return 0; 77 } 78 *buf = p; 79 } 80 81 if (blen > 0) { 82 p += blen; 83 *p++ = ','; 84 *p++ = ' '; 85 } 86 } 87 88 strcpy(p, s); 89 return 1; 90 } 91 92 static int util_flags(BIO *out, unsigned int flags, const char *indent) 93 { 94 int started = 0, err = 0; 95 /* Indent before displaying input flags */ 96 BIO_printf(out, "%s%s(input flags): ", indent, indent); 97 if (flags == 0) { 98 BIO_printf(out, "<no flags>\n"); 99 return 1; 100 } 101 /* 102 * If the object is internal, mark it in a way that shows instead of 103 * having it part of all the other flags, even if it really is. 104 */ 105 if (flags & ENGINE_CMD_FLAG_INTERNAL) { 106 BIO_printf(out, "[Internal] "); 107 } 108 109 if (flags & ENGINE_CMD_FLAG_NUMERIC) { 110 BIO_printf(out, "NUMERIC"); 111 started = 1; 112 } 113 /* 114 * Now we check that no combinations of the mutually exclusive NUMERIC, 115 * STRING, and NO_INPUT flags have been used. Future flags that can be 116 * OR'd together with these would need to added after these to preserve 117 * the testing logic. 118 */ 119 if (flags & ENGINE_CMD_FLAG_STRING) { 120 if (started) { 121 BIO_printf(out, "|"); 122 err = 1; 123 } 124 BIO_printf(out, "STRING"); 125 started = 1; 126 } 127 if (flags & ENGINE_CMD_FLAG_NO_INPUT) { 128 if (started) { 129 BIO_printf(out, "|"); 130 err = 1; 131 } 132 BIO_printf(out, "NO_INPUT"); 133 started = 1; 134 } 135 /* Check for unknown flags */ 136 flags = flags & ~ENGINE_CMD_FLAG_NUMERIC & 137 ~ENGINE_CMD_FLAG_STRING & 138 ~ENGINE_CMD_FLAG_NO_INPUT & ~ENGINE_CMD_FLAG_INTERNAL; 139 if (flags) { 140 if (started) 141 BIO_printf(out, "|"); 142 BIO_printf(out, "<0x%04X>", flags); 143 } 144 if (err) 145 BIO_printf(out, " <illegal flags!>"); 146 BIO_printf(out, "\n"); 147 return 1; 148 } 149 150 static int util_verbose(ENGINE *e, int verbose, BIO *out, const char *indent) 151 { 152 static const int line_wrap = 78; 153 int num; 154 int ret = 0; 155 char *name = NULL; 156 char *desc = NULL; 157 int flags; 158 int xpos = 0; 159 STACK_OF(OPENSSL_STRING) *cmds = NULL; 160 if (!ENGINE_ctrl(e, ENGINE_CTRL_HAS_CTRL_FUNCTION, 0, NULL, NULL) || 161 ((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_FIRST_CMD_TYPE, 162 0, NULL, NULL)) <= 0)) { 163 return 1; 164 } 165 166 cmds = sk_OPENSSL_STRING_new_null(); 167 if (cmds == NULL) 168 goto err; 169 170 do { 171 int len; 172 /* Get the command input flags */ 173 if ((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, 174 NULL, NULL)) < 0) 175 goto err; 176 if (!(flags & ENGINE_CMD_FLAG_INTERNAL) || verbose >= 4) { 177 /* Get the command name */ 178 if ((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_LEN_FROM_CMD, num, 179 NULL, NULL)) <= 0) 180 goto err; 181 name = app_malloc(len + 1, "name buffer"); 182 if (ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_FROM_CMD, num, name, 183 NULL) <= 0) 184 goto err; 185 /* Get the command description */ 186 if ((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_LEN_FROM_CMD, num, 187 NULL, NULL)) < 0) 188 goto err; 189 if (len > 0) { 190 desc = app_malloc(len + 1, "description buffer"); 191 if (ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_FROM_CMD, num, desc, 192 NULL) <= 0) 193 goto err; 194 } 195 /* Now decide on the output */ 196 if (xpos == 0) 197 /* Do an indent */ 198 xpos = BIO_puts(out, indent); 199 else 200 /* Otherwise prepend a ", " */ 201 xpos += BIO_printf(out, ", "); 202 if (verbose == 1) { 203 /* 204 * We're just listing names, comma-delimited 205 */ 206 if ((xpos > (int)strlen(indent)) && 207 (xpos + (int)strlen(name) > line_wrap)) { 208 BIO_printf(out, "\n"); 209 xpos = BIO_puts(out, indent); 210 } 211 xpos += BIO_printf(out, "%s", name); 212 } else { 213 /* We're listing names plus descriptions */ 214 BIO_printf(out, "%s: %s\n", name, 215 (desc == NULL) ? "<no description>" : desc); 216 /* ... and sometimes input flags */ 217 if ((verbose >= 3) && !util_flags(out, flags, indent)) 218 goto err; 219 xpos = 0; 220 } 221 } 222 OPENSSL_free(name); 223 name = NULL; 224 OPENSSL_free(desc); 225 desc = NULL; 226 /* Move to the next command */ 227 num = ENGINE_ctrl(e, ENGINE_CTRL_GET_NEXT_CMD_TYPE, num, NULL, NULL); 228 } while (num > 0); 229 if (xpos > 0) 230 BIO_printf(out, "\n"); 231 ret = 1; 232 err: 233 sk_OPENSSL_STRING_free(cmds); 234 OPENSSL_free(name); 235 OPENSSL_free(desc); 236 return ret; 237 } 238 239 static void util_do_cmds(ENGINE *e, STACK_OF(OPENSSL_STRING) *cmds, 240 BIO *out, const char *indent) 241 { 242 int loop, res, num = sk_OPENSSL_STRING_num(cmds); 243 244 if (num < 0) { 245 BIO_printf(out, "[Error]: internal stack error\n"); 246 return; 247 } 248 for (loop = 0; loop < num; loop++) { 249 char buf[256]; 250 const char *cmd, *arg; 251 cmd = sk_OPENSSL_STRING_value(cmds, loop); 252 res = 1; /* assume success */ 253 /* Check if this command has no ":arg" */ 254 if ((arg = strstr(cmd, ":")) == NULL) { 255 if (!ENGINE_ctrl_cmd_string(e, cmd, NULL, 0)) 256 res = 0; 257 } else { 258 if ((int)(arg - cmd) > 254) { 259 BIO_printf(out, "[Error]: command name too long\n"); 260 return; 261 } 262 memcpy(buf, cmd, (int)(arg - cmd)); 263 buf[arg - cmd] = '\0'; 264 arg++; /* Move past the ":" */ 265 /* Call the command with the argument */ 266 if (!ENGINE_ctrl_cmd_string(e, buf, arg, 0)) 267 res = 0; 268 } 269 if (res) { 270 BIO_printf(out, "[Success]: %s\n", cmd); 271 } else { 272 BIO_printf(out, "[Failure]: %s\n", cmd); 273 ERR_print_errors(out); 274 } 275 } 276 } 277 278 struct util_store_cap_data { 279 ENGINE *engine; 280 char **cap_buf; 281 int *cap_size; 282 int ok; 283 }; 284 static void util_store_cap(const OSSL_STORE_LOADER *loader, void *arg) 285 { 286 struct util_store_cap_data *ctx = arg; 287 288 if (OSSL_STORE_LOADER_get0_engine(loader) == ctx->engine) { 289 char buf[256]; 290 BIO_snprintf(buf, sizeof(buf), "STORE(%s)", 291 OSSL_STORE_LOADER_get0_scheme(loader)); 292 if (!append_buf(ctx->cap_buf, ctx->cap_size, buf)) 293 ctx->ok = 0; 294 } 295 } 296 297 int engine_main(int argc, char **argv) 298 { 299 int ret = 1, i; 300 int verbose = 0, list_cap = 0, test_avail = 0, test_avail_noise = 0; 301 ENGINE *e; 302 STACK_OF(OPENSSL_CSTRING) *engines = sk_OPENSSL_CSTRING_new_null(); 303 STACK_OF(OPENSSL_STRING) *pre_cmds = sk_OPENSSL_STRING_new_null(); 304 STACK_OF(OPENSSL_STRING) *post_cmds = sk_OPENSSL_STRING_new_null(); 305 BIO *out; 306 const char *indent = " "; 307 OPTION_CHOICE o; 308 char *prog; 309 char *argv1; 310 311 out = dup_bio_out(FORMAT_TEXT); 312 if (engines == NULL || pre_cmds == NULL || post_cmds == NULL) 313 goto end; 314 315 /* Remember the original command name, parse/skip any leading engine 316 * names, and then setup to parse the rest of the line as flags. */ 317 prog = argv[0]; 318 while ((argv1 = argv[1]) != NULL && *argv1 != '-') { 319 sk_OPENSSL_CSTRING_push(engines, argv1); 320 argc--; 321 argv++; 322 } 323 argv[0] = prog; 324 opt_init(argc, argv, engine_options); 325 326 while ((o = opt_next()) != OPT_EOF) { 327 switch (o) { 328 case OPT_EOF: 329 case OPT_ERR: 330 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 331 goto end; 332 case OPT_HELP: 333 opt_help(engine_options); 334 ret = 0; 335 goto end; 336 case OPT_VVVV: 337 case OPT_VVV: 338 case OPT_VV: 339 case OPT_V: 340 /* Convert to an integer from one to four. */ 341 i = (int)(o - OPT_V) + 1; 342 if (verbose < i) 343 verbose = i; 344 break; 345 case OPT_C: 346 list_cap = 1; 347 break; 348 case OPT_TT: 349 test_avail_noise++; 350 /* fall thru */ 351 case OPT_T: 352 test_avail++; 353 break; 354 case OPT_PRE: 355 sk_OPENSSL_STRING_push(pre_cmds, opt_arg()); 356 break; 357 case OPT_POST: 358 sk_OPENSSL_STRING_push(post_cmds, opt_arg()); 359 break; 360 } 361 } 362 363 /* Any remaining arguments are engine names. */ 364 argc = opt_num_rest(); 365 argv = opt_rest(); 366 for ( ; *argv; argv++) { 367 if (**argv == '-') { 368 BIO_printf(bio_err, "%s: Cannot mix flags and engine names.\n", 369 prog); 370 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 371 goto end; 372 } 373 sk_OPENSSL_CSTRING_push(engines, *argv); 374 } 375 376 if (sk_OPENSSL_CSTRING_num(engines) == 0) { 377 for (e = ENGINE_get_first(); e != NULL; e = ENGINE_get_next(e)) { 378 sk_OPENSSL_CSTRING_push(engines, ENGINE_get_id(e)); 379 } 380 } 381 382 ret = 0; 383 for (i = 0; i < sk_OPENSSL_CSTRING_num(engines); i++) { 384 const char *id = sk_OPENSSL_CSTRING_value(engines, i); 385 if ((e = ENGINE_by_id(id)) != NULL) { 386 const char *name = ENGINE_get_name(e); 387 /* 388 * Do "id" first, then "name". Easier to auto-parse. 389 */ 390 BIO_printf(out, "(%s) %s\n", id, name); 391 util_do_cmds(e, pre_cmds, out, indent); 392 if (strcmp(ENGINE_get_id(e), id) != 0) { 393 BIO_printf(out, "Loaded: (%s) %s\n", 394 ENGINE_get_id(e), ENGINE_get_name(e)); 395 } 396 if (list_cap) { 397 int cap_size = 256; 398 char *cap_buf = NULL; 399 int k, n; 400 const int *nids; 401 ENGINE_CIPHERS_PTR fn_c; 402 ENGINE_DIGESTS_PTR fn_d; 403 ENGINE_PKEY_METHS_PTR fn_pk; 404 405 if (ENGINE_get_RSA(e) != NULL 406 && !append_buf(&cap_buf, &cap_size, "RSA")) 407 goto end; 408 if (ENGINE_get_DSA(e) != NULL 409 && !append_buf(&cap_buf, &cap_size, "DSA")) 410 goto end; 411 if (ENGINE_get_DH(e) != NULL 412 && !append_buf(&cap_buf, &cap_size, "DH")) 413 goto end; 414 if (ENGINE_get_RAND(e) != NULL 415 && !append_buf(&cap_buf, &cap_size, "RAND")) 416 goto end; 417 418 fn_c = ENGINE_get_ciphers(e); 419 if (fn_c == NULL) 420 goto skip_ciphers; 421 n = fn_c(e, NULL, &nids, 0); 422 for (k = 0; k < n; ++k) 423 if (!append_buf(&cap_buf, &cap_size, OBJ_nid2sn(nids[k]))) 424 goto end; 425 426 skip_ciphers: 427 fn_d = ENGINE_get_digests(e); 428 if (fn_d == NULL) 429 goto skip_digests; 430 n = fn_d(e, NULL, &nids, 0); 431 for (k = 0; k < n; ++k) 432 if (!append_buf(&cap_buf, &cap_size, OBJ_nid2sn(nids[k]))) 433 goto end; 434 435 skip_digests: 436 fn_pk = ENGINE_get_pkey_meths(e); 437 if (fn_pk == NULL) 438 goto skip_pmeths; 439 n = fn_pk(e, NULL, &nids, 0); 440 for (k = 0; k < n; ++k) 441 if (!append_buf(&cap_buf, &cap_size, OBJ_nid2sn(nids[k]))) 442 goto end; 443 skip_pmeths: 444 { 445 struct util_store_cap_data store_ctx; 446 447 store_ctx.engine = e; 448 store_ctx.cap_buf = &cap_buf; 449 store_ctx.cap_size = &cap_size; 450 store_ctx.ok = 1; 451 452 OSSL_STORE_do_all_loaders(util_store_cap, &store_ctx); 453 if (!store_ctx.ok) 454 goto end; 455 } 456 if (cap_buf != NULL && (*cap_buf != '\0')) 457 BIO_printf(out, " [%s]\n", cap_buf); 458 459 OPENSSL_free(cap_buf); 460 } 461 if (test_avail) { 462 BIO_printf(out, "%s", indent); 463 if (ENGINE_init(e)) { 464 BIO_printf(out, "[ available ]\n"); 465 util_do_cmds(e, post_cmds, out, indent); 466 ENGINE_finish(e); 467 } else { 468 BIO_printf(out, "[ unavailable ]\n"); 469 if (test_avail_noise) 470 ERR_print_errors_fp(stdout); 471 ERR_clear_error(); 472 } 473 } 474 if ((verbose > 0) && !util_verbose(e, verbose, out, indent)) 475 goto end; 476 ENGINE_free(e); 477 } else { 478 ERR_print_errors(bio_err); 479 /* because exit codes above 127 have special meaning on Unix */ 480 if (++ret > 127) 481 ret = 127; 482 } 483 } 484 485 end: 486 487 ERR_print_errors(bio_err); 488 sk_OPENSSL_CSTRING_free(engines); 489 sk_OPENSSL_STRING_free(pre_cmds); 490 sk_OPENSSL_STRING_free(post_cmds); 491 BIO_free_all(out); 492 return ret; 493 } 494