1 |
/* apps/engine.c -*- mode: C; c-file-style: "eay" -*- */ |
2 |
/* |
3 |
* Written by Richard Levitte <richard@levitte.org> for the OpenSSL project |
4 |
* 2000. |
5 |
*/ |
6 |
/* ==================================================================== |
7 |
* Copyright (c) 2000 The OpenSSL Project. All rights reserved. |
8 |
* |
9 |
* Redistribution and use in source and binary forms, with or without |
10 |
* modification, are permitted provided that the following conditions |
11 |
* are met: |
12 |
* |
13 |
* 1. Redistributions of source code must retain the above copyright |
14 |
* notice, this list of conditions and the following disclaimer. |
15 |
* |
16 |
* 2. Redistributions in binary form must reproduce the above copyright |
17 |
* notice, this list of conditions and the following disclaimer in |
18 |
* the documentation and/or other materials provided with the |
19 |
* distribution. |
20 |
* |
21 |
* 3. All advertising materials mentioning features or use of this |
22 |
* software must display the following acknowledgment: |
23 |
* "This product includes software developed by the OpenSSL Project |
24 |
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" |
25 |
* |
26 |
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
27 |
* endorse or promote products derived from this software without |
28 |
* prior written permission. For written permission, please contact |
29 |
* licensing@OpenSSL.org. |
30 |
* |
31 |
* 5. Products derived from this software may not be called "OpenSSL" |
32 |
* nor may "OpenSSL" appear in their names without prior written |
33 |
* permission of the OpenSSL Project. |
34 |
* |
35 |
* 6. Redistributions of any form whatsoever must retain the following |
36 |
* acknowledgment: |
37 |
* "This product includes software developed by the OpenSSL Project |
38 |
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" |
39 |
* |
40 |
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
41 |
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
42 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
43 |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
44 |
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
45 |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
46 |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
47 |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
48 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
49 |
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
50 |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
51 |
* OF THE POSSIBILITY OF SUCH DAMAGE. |
52 |
* ==================================================================== |
53 |
* |
54 |
* This product includes cryptographic software written by Eric Young |
55 |
* (eay@cryptsoft.com). This product includes software written by Tim |
56 |
* Hudson (tjh@cryptsoft.com). |
57 |
* |
58 |
*/ |
59 |
|
60 |
#include <stdio.h> |
61 |
#include <stdlib.h> |
62 |
#include <string.h> |
63 |
#ifdef OPENSSL_NO_STDIO |
64 |
# define APPS_WIN16 |
65 |
#endif |
66 |
#include "apps.h" |
67 |
#include <openssl/err.h> |
68 |
#ifndef OPENSSL_NO_ENGINE |
69 |
# include <openssl/engine.h> |
70 |
# include <openssl/ssl.h> |
71 |
|
72 |
# undef PROG |
73 |
# define PROG engine_main |
74 |
|
75 |
static const 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[t] - for each engine, check that they are really available\n", |
83 |
" -tt will display error trace for unavailable engines\n", |
84 |
" -pre <cmd> - runs command 'cmd' against the ENGINE before any attempts\n", |
85 |
" to load it (if -t is used)\n", |
86 |
" -post <cmd> - runs command 'cmd' against the ENGINE after loading it\n", |
87 |
" (only used if -t is also provided)\n", |
88 |
" NB: -pre and -post will be applied to all ENGINEs supplied on the command\n", |
89 |
" line, or all supported ENGINEs if none are specified.\n", |
90 |
" Eg. '-pre \"SO_PATH:/lib/libdriver.so\"' calls command \"SO_PATH\" with\n", |
91 |
" argument \"/lib/libdriver.so\".\n", |
92 |
NULL |
93 |
}; |
94 |
|
95 |
static void identity(char *ptr) |
96 |
{ |
97 |
return; |
98 |
} |
99 |
|
100 |
static int append_buf(char **buf, const char *s, int *size, int step) |
101 |
{ |
102 |
if (*buf == NULL) { |
103 |
*size = step; |
104 |
*buf = OPENSSL_malloc(*size); |
105 |
if (*buf == NULL) |
106 |
return 0; |
107 |
**buf = '\0'; |
108 |
} |
109 |
|
110 |
if (strlen(*buf) + strlen(s) >= (unsigned int)*size) { |
111 |
*size += step; |
112 |
*buf = OPENSSL_realloc(*buf, *size); |
113 |
} |
114 |
|
115 |
if (*buf == NULL) |
116 |
return 0; |
117 |
|
118 |
if (**buf != '\0') |
119 |
BUF_strlcat(*buf, ", ", *size); |
120 |
BUF_strlcat(*buf, s, *size); |
121 |
|
122 |
return 1; |
123 |
} |
124 |
|
125 |
static int util_flags(BIO *bio_out, unsigned int flags, const char *indent) |
126 |
{ |
127 |
int started = 0, err = 0; |
128 |
/* Indent before displaying input flags */ |
129 |
BIO_printf(bio_out, "%s%s(input flags): ", indent, indent); |
130 |
if (flags == 0) { |
131 |
BIO_printf(bio_out, "<no flags>\n"); |
132 |
return 1; |
133 |
} |
134 |
/* |
135 |
* If the object is internal, mark it in a way that shows instead of |
136 |
* having it part of all the other flags, even if it really is. |
137 |
*/ |
138 |
if (flags & ENGINE_CMD_FLAG_INTERNAL) { |
139 |
BIO_printf(bio_out, "[Internal] "); |
140 |
} |
141 |
|
142 |
if (flags & ENGINE_CMD_FLAG_NUMERIC) { |
143 |
BIO_printf(bio_out, "NUMERIC"); |
144 |
started = 1; |
145 |
} |
146 |
/* |
147 |
* Now we check that no combinations of the mutually exclusive NUMERIC, |
148 |
* STRING, and NO_INPUT flags have been used. Future flags that can be |
149 |
* OR'd together with these would need to added after these to preserve |
150 |
* the testing logic. |
151 |
*/ |
152 |
if (flags & ENGINE_CMD_FLAG_STRING) { |
153 |
if (started) { |
154 |
BIO_printf(bio_out, "|"); |
155 |
err = 1; |
156 |
} |
157 |
BIO_printf(bio_out, "STRING"); |
158 |
started = 1; |
159 |
} |
160 |
if (flags & ENGINE_CMD_FLAG_NO_INPUT) { |
161 |
if (started) { |
162 |
BIO_printf(bio_out, "|"); |
163 |
err = 1; |
164 |
} |
165 |
BIO_printf(bio_out, "NO_INPUT"); |
166 |
started = 1; |
167 |
} |
168 |
/* Check for unknown flags */ |
169 |
flags = flags & ~ENGINE_CMD_FLAG_NUMERIC & |
170 |
~ENGINE_CMD_FLAG_STRING & |
171 |
~ENGINE_CMD_FLAG_NO_INPUT & ~ENGINE_CMD_FLAG_INTERNAL; |
172 |
if (flags) { |
173 |
if (started) |
174 |
BIO_printf(bio_out, "|"); |
175 |
BIO_printf(bio_out, "<0x%04X>", flags); |
176 |
} |
177 |
if (err) |
178 |
BIO_printf(bio_out, " <illegal flags!>"); |
179 |
BIO_printf(bio_out, "\n"); |
180 |
return 1; |
181 |
} |
182 |
|
183 |
static int util_verbose(ENGINE *e, int verbose, BIO *bio_out, |
184 |
const char *indent) |
185 |
{ |
186 |
static const int line_wrap = 78; |
187 |
int num; |
188 |
int ret = 0; |
189 |
char *name = NULL; |
190 |
char *desc = NULL; |
191 |
int flags; |
192 |
int xpos = 0; |
193 |
STACK_OF(OPENSSL_STRING) *cmds = NULL; |
194 |
if (!ENGINE_ctrl(e, ENGINE_CTRL_HAS_CTRL_FUNCTION, 0, NULL, NULL) || |
195 |
((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_FIRST_CMD_TYPE, |
196 |
0, NULL, NULL)) <= 0)) { |
197 |
# if 0 |
198 |
BIO_printf(bio_out, "%s<no control commands>\n", indent); |
199 |
# endif |
200 |
return 1; |
201 |
} |
202 |
|
203 |
cmds = sk_OPENSSL_STRING_new_null(); |
204 |
|
205 |
if (!cmds) |
206 |
goto err; |
207 |
do { |
208 |
int len; |
209 |
/* Get the command input flags */ |
210 |
if ((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, |
211 |
NULL, NULL)) < 0) |
212 |
goto err; |
213 |
if (!(flags & ENGINE_CMD_FLAG_INTERNAL) || verbose >= 4) { |
214 |
/* Get the command name */ |
215 |
if ((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_LEN_FROM_CMD, num, |
216 |
NULL, NULL)) <= 0) |
217 |
goto err; |
218 |
if ((name = OPENSSL_malloc(len + 1)) == NULL) |
219 |
goto err; |
220 |
if (ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_FROM_CMD, num, name, |
221 |
NULL) <= 0) |
222 |
goto err; |
223 |
/* Get the command description */ |
224 |
if ((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_LEN_FROM_CMD, num, |
225 |
NULL, NULL)) < 0) |
226 |
goto err; |
227 |
if (len > 0) { |
228 |
if ((desc = OPENSSL_malloc(len + 1)) == NULL) |
229 |
goto err; |
230 |
if (ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_FROM_CMD, num, desc, |
231 |
NULL) <= 0) |
232 |
goto err; |
233 |
} |
234 |
/* Now decide on the output */ |
235 |
if (xpos == 0) |
236 |
/* Do an indent */ |
237 |
xpos = BIO_puts(bio_out, indent); |
238 |
else |
239 |
/* Otherwise prepend a ", " */ |
240 |
xpos += BIO_printf(bio_out, ", "); |
241 |
if (verbose == 1) { |
242 |
/* |
243 |
* We're just listing names, comma-delimited |
244 |
*/ |
245 |
if ((xpos > (int)strlen(indent)) && |
246 |
(xpos + (int)strlen(name) > line_wrap)) { |
247 |
BIO_printf(bio_out, "\n"); |
248 |
xpos = BIO_puts(bio_out, indent); |
249 |
} |
250 |
xpos += BIO_printf(bio_out, "%s", name); |
251 |
} else { |
252 |
/* We're listing names plus descriptions */ |
253 |
BIO_printf(bio_out, "%s: %s\n", name, |
254 |
(desc == NULL) ? "<no description>" : desc); |
255 |
/* ... and sometimes input flags */ |
256 |
if ((verbose >= 3) && !util_flags(bio_out, flags, indent)) |
257 |
goto err; |
258 |
xpos = 0; |
259 |
} |
260 |
} |
261 |
OPENSSL_free(name); |
262 |
name = NULL; |
263 |
if (desc) { |
264 |
OPENSSL_free(desc); |
265 |
desc = NULL; |
266 |
} |
267 |
/* Move to the next command */ |
268 |
num = ENGINE_ctrl(e, ENGINE_CTRL_GET_NEXT_CMD_TYPE, num, NULL, NULL); |
269 |
} while (num > 0); |
270 |
if (xpos > 0) |
271 |
BIO_printf(bio_out, "\n"); |
272 |
ret = 1; |
273 |
err: |
274 |
if (cmds) |
275 |
sk_OPENSSL_STRING_pop_free(cmds, identity); |
276 |
if (name) |
277 |
OPENSSL_free(name); |
278 |
if (desc) |
279 |
OPENSSL_free(desc); |
280 |
return ret; |
281 |
} |
282 |
|
283 |
static void util_do_cmds(ENGINE *e, STACK_OF(OPENSSL_STRING) *cmds, |
284 |
BIO *bio_out, const char *indent) |
285 |
{ |
286 |
int loop, res, num = sk_OPENSSL_STRING_num(cmds); |
287 |
|
288 |
if (num < 0) { |
289 |
BIO_printf(bio_out, "[Error]: internal stack error\n"); |
290 |
return; |
291 |
} |
292 |
for (loop = 0; loop < num; loop++) { |
293 |
char buf[256]; |
294 |
const char *cmd, *arg; |
295 |
cmd = sk_OPENSSL_STRING_value(cmds, loop); |
296 |
res = 1; /* assume success */ |
297 |
/* Check if this command has no ":arg" */ |
298 |
if ((arg = strstr(cmd, ":")) == NULL) { |
299 |
if (!ENGINE_ctrl_cmd_string(e, cmd, NULL, 0)) |
300 |
res = 0; |
301 |
} else { |
302 |
if ((int)(arg - cmd) > 254) { |
303 |
BIO_printf(bio_out, "[Error]: command name too long\n"); |
304 |
return; |
305 |
} |
306 |
memcpy(buf, cmd, (int)(arg - cmd)); |
307 |
buf[arg - cmd] = '\0'; |
308 |
arg++; /* Move past the ":" */ |
309 |
/* Call the command with the argument */ |
310 |
if (!ENGINE_ctrl_cmd_string(e, buf, arg, 0)) |
311 |
res = 0; |
312 |
} |
313 |
if (res) |
314 |
BIO_printf(bio_out, "[Success]: %s\n", cmd); |
315 |
else { |
316 |
BIO_printf(bio_out, "[Failure]: %s\n", cmd); |
317 |
ERR_print_errors(bio_out); |
318 |
} |
319 |
} |
320 |
} |
321 |
|
322 |
int MAIN(int, char **); |
323 |
|
324 |
int MAIN(int argc, char **argv) |
325 |
{ |
326 |
int ret = 1, i; |
327 |
const char **pp; |
328 |
int verbose = 0, list_cap = 0, test_avail = 0, test_avail_noise = 0; |
329 |
ENGINE *e; |
330 |
STACK_OF(OPENSSL_STRING) *engines = sk_OPENSSL_STRING_new_null(); |
331 |
STACK_OF(OPENSSL_STRING) *pre_cmds = sk_OPENSSL_STRING_new_null(); |
332 |
STACK_OF(OPENSSL_STRING) *post_cmds = sk_OPENSSL_STRING_new_null(); |
333 |
int badops = 1; |
334 |
BIO *bio_out = NULL; |
335 |
const char *indent = " "; |
336 |
|
337 |
apps_startup(); |
338 |
SSL_load_error_strings(); |
339 |
|
340 |
if (bio_err == NULL) |
341 |
bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); |
342 |
|
343 |
if (!load_config(bio_err, NULL)) |
344 |
goto end; |
345 |
bio_out = BIO_new_fp(stdout, BIO_NOCLOSE); |
346 |
# ifdef OPENSSL_SYS_VMS |
347 |
{ |
348 |
BIO *tmpbio = BIO_new(BIO_f_linebuffer()); |
349 |
bio_out = BIO_push(tmpbio, bio_out); |
350 |
} |
351 |
# endif |
352 |
|
353 |
argc--; |
354 |
argv++; |
355 |
while (argc >= 1) { |
356 |
if (strncmp(*argv, "-v", 2) == 0) { |
357 |
if (strspn(*argv + 1, "v") < strlen(*argv + 1)) |
358 |
goto skip_arg_loop; |
359 |
if ((verbose = strlen(*argv + 1)) > 4) |
360 |
goto skip_arg_loop; |
361 |
} else if (strcmp(*argv, "-c") == 0) |
362 |
list_cap = 1; |
363 |
else if (strncmp(*argv, "-t", 2) == 0) { |
364 |
test_avail = 1; |
365 |
if (strspn(*argv + 1, "t") < strlen(*argv + 1)) |
366 |
goto skip_arg_loop; |
367 |
if ((test_avail_noise = strlen(*argv + 1) - 1) > 1) |
368 |
goto skip_arg_loop; |
369 |
} else if (strcmp(*argv, "-pre") == 0) { |
370 |
argc--; |
371 |
argv++; |
372 |
if (argc == 0) |
373 |
goto skip_arg_loop; |
374 |
sk_OPENSSL_STRING_push(pre_cmds, *argv); |
375 |
} else if (strcmp(*argv, "-post") == 0) { |
376 |
argc--; |
377 |
argv++; |
378 |
if (argc == 0) |
379 |
goto skip_arg_loop; |
380 |
sk_OPENSSL_STRING_push(post_cmds, *argv); |
381 |
} else if ((strncmp(*argv, "-h", 2) == 0) || |
382 |
(strcmp(*argv, "-?") == 0)) |
383 |
goto skip_arg_loop; |
384 |
else |
385 |
sk_OPENSSL_STRING_push(engines, *argv); |
386 |
argc--; |
387 |
argv++; |
388 |
} |
389 |
/* Looks like everything went OK */ |
390 |
badops = 0; |
391 |
skip_arg_loop: |
392 |
|
393 |
if (badops) { |
394 |
for (pp = engine_usage; (*pp != NULL); pp++) |
395 |
BIO_printf(bio_err, "%s", *pp); |
396 |
goto end; |
397 |
} |
398 |
|
399 |
if (sk_OPENSSL_STRING_num(engines) == 0) { |
400 |
for (e = ENGINE_get_first(); e != NULL; e = ENGINE_get_next(e)) { |
401 |
sk_OPENSSL_STRING_push(engines, (char *)ENGINE_get_id(e)); |
402 |
} |
403 |
} |
404 |
|
405 |
for (i = 0; i < sk_OPENSSL_STRING_num(engines); i++) { |
406 |
const char *id = sk_OPENSSL_STRING_value(engines, i); |
407 |
if ((e = ENGINE_by_id(id)) != NULL) { |
408 |
const char *name = ENGINE_get_name(e); |
409 |
/* |
410 |
* Do "id" first, then "name". Easier to auto-parse. |
411 |
*/ |
412 |
BIO_printf(bio_out, "(%s) %s\n", id, name); |
413 |
util_do_cmds(e, pre_cmds, bio_out, indent); |
414 |
if (strcmp(ENGINE_get_id(e), id) != 0) { |
415 |
BIO_printf(bio_out, "Loaded: (%s) %s\n", |
416 |
ENGINE_get_id(e), ENGINE_get_name(e)); |
417 |
} |
418 |
if (list_cap) { |
419 |
int cap_size = 256; |
420 |
char *cap_buf = NULL; |
421 |
int k, n; |
422 |
const int *nids; |
423 |
ENGINE_CIPHERS_PTR fn_c; |
424 |
ENGINE_DIGESTS_PTR fn_d; |
425 |
ENGINE_PKEY_METHS_PTR fn_pk; |
426 |
|
427 |
if (ENGINE_get_RSA(e) != NULL |
428 |
&& !append_buf(&cap_buf, "RSA", &cap_size, 256)) |
429 |
goto end; |
430 |
if (ENGINE_get_DSA(e) != NULL |
431 |
&& !append_buf(&cap_buf, "DSA", &cap_size, 256)) |
432 |
goto end; |
433 |
if (ENGINE_get_DH(e) != NULL |
434 |
&& !append_buf(&cap_buf, "DH", &cap_size, 256)) |
435 |
goto end; |
436 |
if (ENGINE_get_RAND(e) != NULL |
437 |
&& !append_buf(&cap_buf, "RAND", &cap_size, 256)) |
438 |
goto end; |
439 |
|
440 |
fn_c = ENGINE_get_ciphers(e); |
441 |
if (!fn_c) |
442 |
goto skip_ciphers; |
443 |
n = fn_c(e, NULL, &nids, 0); |
444 |
for (k = 0; k < n; ++k) |
445 |
if (!append_buf(&cap_buf, |
446 |
OBJ_nid2sn(nids[k]), &cap_size, 256)) |
447 |
goto end; |
448 |
|
449 |
skip_ciphers: |
450 |
fn_d = ENGINE_get_digests(e); |
451 |
if (!fn_d) |
452 |
goto skip_digests; |
453 |
n = fn_d(e, NULL, &nids, 0); |
454 |
for (k = 0; k < n; ++k) |
455 |
if (!append_buf(&cap_buf, |
456 |
OBJ_nid2sn(nids[k]), &cap_size, 256)) |
457 |
goto end; |
458 |
|
459 |
skip_digests: |
460 |
fn_pk = ENGINE_get_pkey_meths(e); |
461 |
if (!fn_pk) |
462 |
goto skip_pmeths; |
463 |
n = fn_pk(e, NULL, &nids, 0); |
464 |
for (k = 0; k < n; ++k) |
465 |
if (!append_buf(&cap_buf, |
466 |
OBJ_nid2sn(nids[k]), &cap_size, 256)) |
467 |
goto end; |
468 |
skip_pmeths: |
469 |
if (cap_buf && (*cap_buf != '\0')) |
470 |
BIO_printf(bio_out, " [%s]\n", cap_buf); |
471 |
|
472 |
OPENSSL_free(cap_buf); |
473 |
} |
474 |
if (test_avail) { |
475 |
BIO_printf(bio_out, "%s", indent); |
476 |
if (ENGINE_init(e)) { |
477 |
BIO_printf(bio_out, "[ available ]\n"); |
478 |
util_do_cmds(e, post_cmds, bio_out, indent); |
479 |
ENGINE_finish(e); |
480 |
} else { |
481 |
BIO_printf(bio_out, "[ unavailable ]\n"); |
482 |
if (test_avail_noise) |
483 |
ERR_print_errors_fp(stdout); |
484 |
ERR_clear_error(); |
485 |
} |
486 |
} |
487 |
if ((verbose > 0) && !util_verbose(e, verbose, bio_out, indent)) |
488 |
goto end; |
489 |
ENGINE_free(e); |
490 |
} else |
491 |
ERR_print_errors(bio_err); |
492 |
} |
493 |
|
494 |
ret = 0; |
495 |
end: |
496 |
|
497 |
ERR_print_errors(bio_err); |
498 |
sk_OPENSSL_STRING_pop_free(engines, identity); |
499 |
sk_OPENSSL_STRING_pop_free(pre_cmds, identity); |
500 |
sk_OPENSSL_STRING_pop_free(post_cmds, identity); |
501 |
if (bio_out != NULL) |
502 |
BIO_free_all(bio_out); |
503 |
apps_shutdown(); |
504 |
OPENSSL_EXIT(ret); |
505 |
} |
506 |
#else |
507 |
|
508 |
# if PEDANTIC |
509 |
static void *dummy = &dummy; |
510 |
# endif |
511 |
|
512 |
#endif |