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