2 * Written by Richard Levitte <richard@levitte.org> for the OpenSSL project
5 /* ====================================================================
6 * Copyright (c) 2000 The OpenSSL Project. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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
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/)"
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.
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.
34 * 6. Redistributions of any form whatsoever must retain the following
36 * "This product includes software developed by the OpenSSL Project
37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
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 * ====================================================================
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).
63 #include <openssl/err.h>
64 #ifndef OPENSSL_NO_ENGINE
65 # include <openssl/engine.h>
66 # include <openssl/ssl.h>
68 typedef enum OPTION_choice
{
69 OPT_ERR
= -1, OPT_EOF
= 0, OPT_HELP
,
70 OPT_C
, OPT_T
, OPT_TT
, OPT_PRE
, OPT_POST
,
71 OPT_V
= 100, OPT_VV
, OPT_VVV
, OPT_VVVV
74 OPTIONS engine_options
[] = {
75 {"help", OPT_HELP
, '-', "Display this summary"},
76 {"vvvv", OPT_VVVV
, '-', "Also show internal input flags"},
77 {"vvv", OPT_VVV
, '-', "Also add the input flags for each command"},
78 {"vv", OPT_VV
, '-', "Also display each command's description"},
79 {"v", OPT_V
, '-', "For each engine, list its 'control commands'"},
80 {"c", OPT_C
, '-', "List the capabilities of each engine"},
81 {"t", OPT_T
, '-', "Check that each engine is available"},
82 {"tt", OPT_TT
, '-', "Display error trace for unavailable engines"},
83 {"pre", OPT_PRE
, 's', "Run command against the ENGINE before loading it"},
84 {"post", OPT_POST
, 's', "Run command against the ENGINE after loading it"},
85 {OPT_MORE_STR
, OPT_EOF
, 1,
86 "Commands are like \"SO_PATH:/lib/libdriver.so\""},
90 static void identity(char *ptr
)
95 static int append_buf(char **buf
, const char *s
, int *size
, int step
)
99 *buf
= app_malloc(*size
, "engine buffer");
103 if (strlen(*buf
) + strlen(s
) >= (unsigned int)*size
) {
105 *buf
= OPENSSL_realloc(*buf
, *size
);
112 OPENSSL_strlcat(*buf
, ", ", *size
);
113 OPENSSL_strlcat(*buf
, s
, *size
);
118 static int util_flags(BIO
*out
, unsigned int flags
, const char *indent
)
120 int started
= 0, err
= 0;
121 /* Indent before displaying input flags */
122 BIO_printf(out
, "%s%s(input flags): ", indent
, indent
);
124 BIO_printf(out
, "<no flags>\n");
128 * If the object is internal, mark it in a way that shows instead of
129 * having it part of all the other flags, even if it really is.
131 if (flags
& ENGINE_CMD_FLAG_INTERNAL
) {
132 BIO_printf(out
, "[Internal] ");
135 if (flags
& ENGINE_CMD_FLAG_NUMERIC
) {
136 BIO_printf(out
, "NUMERIC");
140 * Now we check that no combinations of the mutually exclusive NUMERIC,
141 * STRING, and NO_INPUT flags have been used. Future flags that can be
142 * OR'd together with these would need to added after these to preserve
145 if (flags
& ENGINE_CMD_FLAG_STRING
) {
147 BIO_printf(out
, "|");
150 BIO_printf(out
, "STRING");
153 if (flags
& ENGINE_CMD_FLAG_NO_INPUT
) {
155 BIO_printf(out
, "|");
158 BIO_printf(out
, "NO_INPUT");
161 /* Check for unknown flags */
162 flags
= flags
& ~ENGINE_CMD_FLAG_NUMERIC
&
163 ~ENGINE_CMD_FLAG_STRING
&
164 ~ENGINE_CMD_FLAG_NO_INPUT
& ~ENGINE_CMD_FLAG_INTERNAL
;
167 BIO_printf(out
, "|");
168 BIO_printf(out
, "<0x%04X>", flags
);
171 BIO_printf(out
, " <illegal flags!>");
172 BIO_printf(out
, "\n");
176 static int util_verbose(ENGINE
*e
, int verbose
, BIO
*out
, const char *indent
)
178 static const int line_wrap
= 78;
185 STACK_OF(OPENSSL_STRING
) *cmds
= NULL
;
186 if (!ENGINE_ctrl(e
, ENGINE_CTRL_HAS_CTRL_FUNCTION
, 0, NULL
, NULL
) ||
187 ((num
= ENGINE_ctrl(e
, ENGINE_CTRL_GET_FIRST_CMD_TYPE
,
188 0, NULL
, NULL
)) <= 0)) {
192 cmds
= sk_OPENSSL_STRING_new_null();
198 /* Get the command input flags */
199 if ((flags
= ENGINE_ctrl(e
, ENGINE_CTRL_GET_CMD_FLAGS
, num
,
202 if (!(flags
& ENGINE_CMD_FLAG_INTERNAL
) || verbose
>= 4) {
203 /* Get the command name */
204 if ((len
= ENGINE_ctrl(e
, ENGINE_CTRL_GET_NAME_LEN_FROM_CMD
, num
,
207 name
= app_malloc(len
+ 1, "name buffer");
208 if (ENGINE_ctrl(e
, ENGINE_CTRL_GET_NAME_FROM_CMD
, num
, name
,
211 /* Get the command description */
212 if ((len
= ENGINE_ctrl(e
, ENGINE_CTRL_GET_DESC_LEN_FROM_CMD
, num
,
216 desc
= app_malloc(len
+ 1, "description buffer");
217 if (ENGINE_ctrl(e
, ENGINE_CTRL_GET_DESC_FROM_CMD
, num
, desc
,
221 /* Now decide on the output */
224 xpos
= BIO_puts(out
, indent
);
226 /* Otherwise prepend a ", " */
227 xpos
+= BIO_printf(out
, ", ");
230 * We're just listing names, comma-delimited
232 if ((xpos
> (int)strlen(indent
)) &&
233 (xpos
+ (int)strlen(name
) > line_wrap
)) {
234 BIO_printf(out
, "\n");
235 xpos
= BIO_puts(out
, indent
);
237 xpos
+= BIO_printf(out
, "%s", name
);
239 /* We're listing names plus descriptions */
240 BIO_printf(out
, "%s: %s\n", name
,
241 (desc
== NULL
) ? "<no description>" : desc
);
242 /* ... and sometimes input flags */
243 if ((verbose
>= 3) && !util_flags(out
, flags
, indent
))
252 /* Move to the next command */
253 num
= ENGINE_ctrl(e
, ENGINE_CTRL_GET_NEXT_CMD_TYPE
, num
, NULL
, NULL
);
256 BIO_printf(out
, "\n");
259 sk_OPENSSL_STRING_pop_free(cmds
, identity
);
265 static void util_do_cmds(ENGINE
*e
, STACK_OF(OPENSSL_STRING
) *cmds
,
266 BIO
*out
, const char *indent
)
268 int loop
, res
, num
= sk_OPENSSL_STRING_num(cmds
);
271 BIO_printf(out
, "[Error]: internal stack error\n");
274 for (loop
= 0; loop
< num
; loop
++) {
276 const char *cmd
, *arg
;
277 cmd
= sk_OPENSSL_STRING_value(cmds
, loop
);
278 res
= 1; /* assume success */
279 /* Check if this command has no ":arg" */
280 if ((arg
= strstr(cmd
, ":")) == NULL
) {
281 if (!ENGINE_ctrl_cmd_string(e
, cmd
, NULL
, 0))
284 if ((int)(arg
- cmd
) > 254) {
285 BIO_printf(out
, "[Error]: command name too long\n");
288 memcpy(buf
, cmd
, (int)(arg
- cmd
));
289 buf
[arg
- cmd
] = '\0';
290 arg
++; /* Move past the ":" */
291 /* Call the command with the argument */
292 if (!ENGINE_ctrl_cmd_string(e
, buf
, arg
, 0))
296 BIO_printf(out
, "[Success]: %s\n", cmd
);
298 BIO_printf(out
, "[Failure]: %s\n", cmd
);
299 ERR_print_errors(out
);
304 int engine_main(int argc
, char **argv
)
307 int verbose
= 0, list_cap
= 0, test_avail
= 0, test_avail_noise
= 0;
309 STACK_OF(OPENSSL_STRING
) *engines
= sk_OPENSSL_STRING_new_null();
310 STACK_OF(OPENSSL_STRING
) *pre_cmds
= sk_OPENSSL_STRING_new_null();
311 STACK_OF(OPENSSL_STRING
) *post_cmds
= sk_OPENSSL_STRING_new_null();
313 const char *indent
= " ";
317 out
= dup_bio_out(FORMAT_TEXT
);
318 prog
= opt_init(argc
, argv
, engine_options
);
319 if (!engines
|| !pre_cmds
|| !post_cmds
)
321 while ((o
= opt_next()) != OPT_EOF
) {
325 BIO_printf(bio_err
, "%s: Use -help for summary.\n", prog
);
328 opt_help(engine_options
);
335 /* Convert to an integer from one to four. */
336 i
= (int)(o
- OPT_V
) + 1;
349 sk_OPENSSL_STRING_push(pre_cmds
, opt_arg());
352 sk_OPENSSL_STRING_push(post_cmds
, opt_arg());
356 argc
= opt_num_rest();
358 for ( ; *argv
; argv
++)
359 sk_OPENSSL_STRING_push(engines
, *argv
);
361 if (sk_OPENSSL_STRING_num(engines
) == 0) {
362 for (e
= ENGINE_get_first(); e
!= NULL
; e
= ENGINE_get_next(e
)) {
363 sk_OPENSSL_STRING_push(engines
, (char *)ENGINE_get_id(e
));
367 for (i
= 0; i
< sk_OPENSSL_STRING_num(engines
); i
++) {
368 const char *id
= sk_OPENSSL_STRING_value(engines
, i
);
369 if ((e
= ENGINE_by_id(id
)) != NULL
) {
370 const char *name
= ENGINE_get_name(e
);
372 * Do "id" first, then "name". Easier to auto-parse.
374 BIO_printf(out
, "(%s) %s\n", id
, name
);
375 util_do_cmds(e
, pre_cmds
, out
, indent
);
376 if (strcmp(ENGINE_get_id(e
), id
) != 0) {
377 BIO_printf(out
, "Loaded: (%s) %s\n",
378 ENGINE_get_id(e
), ENGINE_get_name(e
));
382 char *cap_buf
= NULL
;
385 ENGINE_CIPHERS_PTR fn_c
;
386 ENGINE_DIGESTS_PTR fn_d
;
387 ENGINE_PKEY_METHS_PTR fn_pk
;
389 if (ENGINE_get_RSA(e
) != NULL
390 && !append_buf(&cap_buf
, "RSA", &cap_size
, 256))
392 if (ENGINE_get_DSA(e
) != NULL
393 && !append_buf(&cap_buf
, "DSA", &cap_size
, 256))
395 if (ENGINE_get_DH(e
) != NULL
396 && !append_buf(&cap_buf
, "DH", &cap_size
, 256))
398 if (ENGINE_get_RAND(e
) != NULL
399 && !append_buf(&cap_buf
, "RAND", &cap_size
, 256))
402 fn_c
= ENGINE_get_ciphers(e
);
405 n
= fn_c(e
, NULL
, &nids
, 0);
406 for (k
= 0; k
< n
; ++k
)
407 if (!append_buf(&cap_buf
,
408 OBJ_nid2sn(nids
[k
]), &cap_size
, 256))
412 fn_d
= ENGINE_get_digests(e
);
415 n
= fn_d(e
, NULL
, &nids
, 0);
416 for (k
= 0; k
< n
; ++k
)
417 if (!append_buf(&cap_buf
,
418 OBJ_nid2sn(nids
[k
]), &cap_size
, 256))
422 fn_pk
= ENGINE_get_pkey_meths(e
);
425 n
= fn_pk(e
, NULL
, &nids
, 0);
426 for (k
= 0; k
< n
; ++k
)
427 if (!append_buf(&cap_buf
,
428 OBJ_nid2sn(nids
[k
]), &cap_size
, 256))
431 if (cap_buf
&& (*cap_buf
!= '\0'))
432 BIO_printf(out
, " [%s]\n", cap_buf
);
434 OPENSSL_free(cap_buf
);
437 BIO_printf(out
, "%s", indent
);
438 if (ENGINE_init(e
)) {
439 BIO_printf(out
, "[ available ]\n");
440 util_do_cmds(e
, post_cmds
, out
, indent
);
443 BIO_printf(out
, "[ unavailable ]\n");
444 if (test_avail_noise
)
445 ERR_print_errors_fp(stdout
);
449 if ((verbose
> 0) && !util_verbose(e
, verbose
, out
, indent
))
453 ERR_print_errors(bio_err
);
459 ERR_print_errors(bio_err
);
460 sk_OPENSSL_STRING_pop_free(engines
, identity
);
461 sk_OPENSSL_STRING_pop_free(pre_cmds
, identity
);
462 sk_OPENSSL_STRING_pop_free(post_cmds
, identity
);
469 static void *dummy
= &dummy
;