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