Main Page | Class List | Directories | File List | Class Members | File Members

engine.c

Go to the documentation of this file.
00001 /* apps/engine.c -*- mode: C; c-file-style: "eay" -*- */
00002 /* Written by Richard Levitte <richard@levitte.org> for the OpenSSL
00003  * project 2000.
00004  */
00005 /* ====================================================================
00006  * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  *
00012  * 1. Redistributions of source code must retain the above copyright
00013  *    notice, this list of conditions and the following disclaimer. 
00014  *
00015  * 2. Redistributions in binary form must reproduce the above copyright
00016  *    notice, this list of conditions and the following disclaimer in
00017  *    the documentation and/or other materials provided with the
00018  *    distribution.
00019  *
00020  * 3. All advertising materials mentioning features or use of this
00021  *    software must display the following acknowledgment:
00022  *    "This product includes software developed by the OpenSSL Project
00023  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
00024  *
00025  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
00026  *    endorse or promote products derived from this software without
00027  *    prior written permission. For written permission, please contact
00028  *    licensing@OpenSSL.org.
00029  *
00030  * 5. Products derived from this software may not be called "OpenSSL"
00031  *    nor may "OpenSSL" appear in their names without prior written
00032  *    permission of the OpenSSL Project.
00033  *
00034  * 6. Redistributions of any form whatsoever must retain the following
00035  *    acknowledgment:
00036  *    "This product includes software developed by the OpenSSL Project
00037  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
00038  *
00039  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
00040  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00041  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00042  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
00043  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00044  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00045  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00046  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00047  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00048  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00049  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00050  * OF THE POSSIBILITY OF SUCH DAMAGE.
00051  * ====================================================================
00052  *
00053  * This product includes cryptographic software written by Eric Young
00054  * (eay@cryptsoft.com).  This product includes software written by Tim
00055  * Hudson (tjh@cryptsoft.com).
00056  *
00057  */
00058 
00059 #ifndef OPENSSL_NO_ENGINE
00060 
00061 #include <stdio.h>
00062 #include <stdlib.h>
00063 #include <string.h>
00064 #ifdef OPENSSL_NO_STDIO
00065 #define APPS_WIN16
00066 #endif
00067 #include "apps.h"
00068 #include <openssl/err.h>
00069 #include <openssl/engine.h>
00070 #include <openssl/ssl.h>
00071 
00072 #undef PROG
00073 #define PROG    engine_main
00074 
00075 static const char *engine_usage[]={
00076 "usage: engine opts [engine ...]\n",
00077 " -v[v[v[v]]] - verbose mode, for each engine, list its 'control commands'\n",
00078 "               -vv will additionally display each command's description\n",
00079 "               -vvv will also add the input flags for each command\n",
00080 "               -vvvv will also show internal input flags\n",
00081 " -c          - for each engine, also list the capabilities\n",
00082 " -t[t]       - for each engine, check that they are really available\n",
00083 "               -tt will display error trace for unavailable engines\n",
00084 " -pre <cmd>  - runs command 'cmd' against the ENGINE before any attempts\n",
00085 "               to load it (if -t is used)\n",
00086 " -post <cmd> - runs command 'cmd' against the ENGINE after loading it\n",
00087 "               (only used if -t is also provided)\n",
00088 " NB: -pre and -post will be applied to all ENGINEs supplied on the command\n",
00089 " line, or all supported ENGINEs if none are specified.\n",
00090 " Eg. '-pre \"SO_PATH:/lib/libdriver.so\"' calls command \"SO_PATH\" with\n",
00091 " argument \"/lib/libdriver.so\".\n",
00092 NULL
00093 };
00094 
00095 static void identity(void *ptr)
00096         {
00097         return;
00098         }
00099 
00100 static int append_buf(char **buf, const char *s, int *size, int step)
00101         {
00102         int l = strlen(s);
00103 
00104         if (*buf == NULL)
00105                 {
00106                 *size = step;
00107                 *buf = OPENSSL_malloc(*size);
00108                 if (*buf == NULL)
00109                         return 0;
00110                 **buf = '\0';
00111                 }
00112 
00113         if (**buf != '\0')
00114                 l += 2;         /* ", " */
00115 
00116         if (strlen(*buf) + strlen(s) >= (unsigned int)*size)
00117                 {
00118                 *size += step;
00119                 *buf = OPENSSL_realloc(*buf, *size);
00120                 }
00121 
00122         if (*buf == NULL)
00123                 return 0;
00124 
00125         if (**buf != '\0')
00126                 BUF_strlcat(*buf, ", ", *size);
00127         BUF_strlcat(*buf, s, *size);
00128 
00129         return 1;
00130         }
00131 
00132 static int util_flags(BIO *bio_out, unsigned int flags, const char *indent)
00133         {
00134         int started = 0, err = 0;
00135         /* Indent before displaying input flags */
00136         BIO_printf(bio_out, "%s%s(input flags): ", indent, indent);
00137         if(flags == 0)
00138                 {
00139                 BIO_printf(bio_out, "<no flags>\n");
00140                 return 1;
00141                 }
00142         /* If the object is internal, mark it in a way that shows instead of
00143          * having it part of all the other flags, even if it really is. */
00144         if(flags & ENGINE_CMD_FLAG_INTERNAL)
00145                 {
00146                 BIO_printf(bio_out, "[Internal] ");
00147                 }
00148 
00149         if(flags & ENGINE_CMD_FLAG_NUMERIC)
00150                 {
00151                 if(started)
00152                         {
00153                         BIO_printf(bio_out, "|");
00154                         err = 1;
00155                         }
00156                 BIO_printf(bio_out, "NUMERIC");
00157                 started = 1;
00158                 }
00159         /* Now we check that no combinations of the mutually exclusive NUMERIC,
00160          * STRING, and NO_INPUT flags have been used. Future flags that can be
00161          * OR'd together with these would need to added after these to preserve
00162          * the testing logic. */
00163         if(flags & ENGINE_CMD_FLAG_STRING)
00164                 {
00165                 if(started)
00166                         {
00167                         BIO_printf(bio_out, "|");
00168                         err = 1;
00169                         }
00170                 BIO_printf(bio_out, "STRING");
00171                 started = 1;
00172                 }
00173         if(flags & ENGINE_CMD_FLAG_NO_INPUT)
00174                 {
00175                 if(started)
00176                         {
00177                         BIO_printf(bio_out, "|");
00178                         err = 1;
00179                         }
00180                 BIO_printf(bio_out, "NO_INPUT");
00181                 started = 1;
00182                 }
00183         /* Check for unknown flags */
00184         flags = flags & ~ENGINE_CMD_FLAG_NUMERIC &
00185                         ~ENGINE_CMD_FLAG_STRING &
00186                         ~ENGINE_CMD_FLAG_NO_INPUT &
00187                         ~ENGINE_CMD_FLAG_INTERNAL;
00188         if(flags)
00189                 {
00190                 if(started) BIO_printf(bio_out, "|");
00191                 BIO_printf(bio_out, "<0x%04X>", flags);
00192                 }
00193         if(err)
00194                 BIO_printf(bio_out, "  <illegal flags!>");
00195         BIO_printf(bio_out, "\n");
00196         return 1;
00197         }
00198 
00199 static int util_verbose(ENGINE *e, int verbose, BIO *bio_out, const char *indent)
00200         {
00201         static const int line_wrap = 78;
00202         int num;
00203         int ret = 0;
00204         char *name = NULL;
00205         char *desc = NULL;
00206         int flags;
00207         int xpos = 0;
00208         STACK *cmds = NULL;
00209         if(!ENGINE_ctrl(e, ENGINE_CTRL_HAS_CTRL_FUNCTION, 0, NULL, NULL) ||
00210                         ((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_FIRST_CMD_TYPE,
00211                                         0, NULL, NULL)) <= 0))
00212                 {
00213 #if 0
00214                 BIO_printf(bio_out, "%s<no control commands>\n", indent);
00215 #endif
00216                 return 1;
00217                 }
00218 
00219         cmds = sk_new_null();
00220 
00221         if(!cmds)
00222                 goto err;
00223         do {
00224                 int len;
00225                 /* Get the command input flags */
00226                 if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num,
00227                                         NULL, NULL)) < 0)
00228                         goto err;
00229                 if (!(flags & ENGINE_CMD_FLAG_INTERNAL) || verbose >= 4)
00230                         {
00231                         /* Get the command name */
00232                         if((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_LEN_FROM_CMD, num,
00233                                 NULL, NULL)) <= 0)
00234                                 goto err;
00235                         if((name = OPENSSL_malloc(len + 1)) == NULL)
00236                                 goto err;
00237                         if(ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_FROM_CMD, num, name,
00238                                 NULL) <= 0)
00239                                 goto err;
00240                         /* Get the command description */
00241                         if((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_LEN_FROM_CMD, num,
00242                                 NULL, NULL)) < 0)
00243                                 goto err;
00244                         if(len > 0)
00245                                 {
00246                                 if((desc = OPENSSL_malloc(len + 1)) == NULL)
00247                                         goto err;
00248                                 if(ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_FROM_CMD, num, desc,
00249                                         NULL) <= 0)
00250                                         goto err;
00251                                 }
00252                         /* Now decide on the output */
00253                         if(xpos == 0)
00254                                 /* Do an indent */
00255                                 xpos = BIO_printf(bio_out, indent);
00256                         else
00257                                 /* Otherwise prepend a ", " */
00258                                 xpos += BIO_printf(bio_out, ", ");
00259                         if(verbose == 1)
00260                                 {
00261                                 /* We're just listing names, comma-delimited */
00262                                 if((xpos > (int)strlen(indent)) &&
00263                                         (xpos + (int)strlen(name) > line_wrap))
00264                                         {
00265                                         BIO_printf(bio_out, "\n");
00266                                         xpos = BIO_printf(bio_out, indent);
00267                                         }
00268                                 xpos += BIO_printf(bio_out, "%s", name);
00269                                 }
00270                         else
00271                                 {
00272                                 /* We're listing names plus descriptions */
00273                                 BIO_printf(bio_out, "%s: %s\n", name,
00274                                         (desc == NULL) ? "<no description>" : desc);
00275                                 /* ... and sometimes input flags */
00276                                 if((verbose >= 3) && !util_flags(bio_out, flags,
00277                                         indent))
00278                                         goto err;
00279                                 xpos = 0;
00280                                 }
00281                         }
00282                 OPENSSL_free(name); name = NULL;
00283                 if(desc) { OPENSSL_free(desc); desc = NULL; }
00284                 /* Move to the next command */
00285                 num = ENGINE_ctrl(e, ENGINE_CTRL_GET_NEXT_CMD_TYPE,
00286                                         num, NULL, NULL);
00287                 } while(num > 0);
00288         if(xpos > 0)
00289                 BIO_printf(bio_out, "\n");
00290         ret = 1;
00291 err:
00292         if(cmds) sk_pop_free(cmds, identity);
00293         if(name) OPENSSL_free(name);
00294         if(desc) OPENSSL_free(desc);
00295         return ret;
00296         }
00297 
00298 static void util_do_cmds(ENGINE *e, STACK *cmds, BIO *bio_out, const char *indent)
00299         {
00300         int loop, res, num = sk_num(cmds);
00301         if(num < 0)
00302                 {
00303                 BIO_printf(bio_out, "[Error]: internal stack error\n");
00304                 return;
00305                 }
00306         for(loop = 0; loop < num; loop++)
00307                 {
00308                 char buf[256];
00309                 const char *cmd, *arg;
00310                 cmd = sk_value(cmds, loop);
00311                 res = 1; /* assume success */
00312                 /* Check if this command has no ":arg" */
00313                 if((arg = strstr(cmd, ":")) == NULL)
00314                         {
00315                         if(!ENGINE_ctrl_cmd_string(e, cmd, NULL, 0))
00316                                 res = 0;
00317                         }
00318                 else
00319                         {
00320                         if((int)(arg - cmd) > 254)
00321                                 {
00322                                 BIO_printf(bio_out,"[Error]: command name too long\n");
00323                                 return;
00324                                 }
00325                         memcpy(buf, cmd, (int)(arg - cmd));
00326                         buf[arg-cmd] = '\0';
00327                         arg++; /* Move past the ":" */
00328                         /* Call the command with the argument */
00329                         if(!ENGINE_ctrl_cmd_string(e, buf, arg, 0))
00330                                 res = 0;
00331                         }
00332                 if(res)
00333                         BIO_printf(bio_out, "[Success]: %s\n", cmd);
00334                 else
00335                         {
00336                         BIO_printf(bio_out, "[Failure]: %s\n", cmd);
00337                         ERR_print_errors(bio_out);
00338                         }
00339                 }
00340         }
00341 
00342 int MAIN(int, char **);
00343 
00344 int MAIN(int argc, char **argv)
00345         {
00346         int ret=1,i;
00347         const char **pp;
00348         int verbose=0, list_cap=0, test_avail=0, test_avail_noise = 0;
00349         ENGINE *e;
00350         STACK *engines = sk_new_null();
00351         STACK *pre_cmds = sk_new_null();
00352         STACK *post_cmds = sk_new_null();
00353         int badops=1;
00354         BIO *bio_out=NULL;
00355         const char *indent = "     ";
00356 
00357         apps_startup();
00358         SSL_load_error_strings();
00359 
00360         if (bio_err == NULL)
00361                 bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
00362 
00363         if (!load_config(bio_err, NULL))
00364                 goto end;
00365         bio_out=BIO_new_fp(stdout,BIO_NOCLOSE);
00366 #ifdef OPENSSL_SYS_VMS
00367         {
00368         BIO *tmpbio = BIO_new(BIO_f_linebuffer());
00369         bio_out = BIO_push(tmpbio, bio_out);
00370         }
00371 #endif
00372 
00373         argc--;
00374         argv++;
00375         while (argc >= 1)
00376                 {
00377                 if (strncmp(*argv,"-v",2) == 0)
00378                         {
00379                         if(strspn(*argv + 1, "v") < strlen(*argv + 1))
00380                                 goto skip_arg_loop;
00381                         if((verbose=strlen(*argv + 1)) > 4)
00382                                 goto skip_arg_loop;
00383                         }
00384                 else if (strcmp(*argv,"-c") == 0)
00385                         list_cap=1;
00386                 else if (strncmp(*argv,"-t",2) == 0)
00387                         {
00388                         test_avail=1;
00389                         if(strspn(*argv + 1, "t") < strlen(*argv + 1))
00390                                 goto skip_arg_loop;
00391                         if((test_avail_noise = strlen(*argv + 1) - 1) > 1)
00392                                 goto skip_arg_loop;
00393                         }
00394                 else if (strcmp(*argv,"-pre") == 0)
00395                         {
00396                         argc--; argv++;
00397                         if (argc == 0)
00398                                 goto skip_arg_loop;
00399                         sk_push(pre_cmds,*argv);
00400                         }
00401                 else if (strcmp(*argv,"-post") == 0)
00402                         {
00403                         argc--; argv++;
00404                         if (argc == 0)
00405                                 goto skip_arg_loop;
00406                         sk_push(post_cmds,*argv);
00407                         }
00408                 else if ((strncmp(*argv,"-h",2) == 0) ||
00409                                 (strcmp(*argv,"-?") == 0))
00410                         goto skip_arg_loop;
00411                 else
00412                         sk_push(engines,*argv);
00413                 argc--;
00414                 argv++;
00415                 }
00416         /* Looks like everything went OK */
00417         badops = 0;
00418 skip_arg_loop:
00419 
00420         if (badops)
00421                 {
00422                 for (pp=engine_usage; (*pp != NULL); pp++)
00423                         BIO_printf(bio_err,"%s",*pp);
00424                 goto end;
00425                 }
00426 
00427         if (sk_num(engines) == 0)
00428                 {
00429                 for(e = ENGINE_get_first(); e != NULL; e = ENGINE_get_next(e))
00430                         {
00431                         sk_push(engines,(char *)ENGINE_get_id(e));
00432                         }
00433                 }
00434 
00435         for (i=0; i<sk_num(engines); i++)
00436                 {
00437                 const char *id = sk_value(engines,i);
00438                 if ((e = ENGINE_by_id(id)) != NULL)
00439                         {
00440                         const char *name = ENGINE_get_name(e);
00441                         /* Do "id" first, then "name". Easier to auto-parse. */
00442                         BIO_printf(bio_out, "(%s) %s\n", id, name);
00443                         util_do_cmds(e, pre_cmds, bio_out, indent);
00444                         if (strcmp(ENGINE_get_id(e), id) != 0)
00445                                 {
00446                                 BIO_printf(bio_out, "Loaded: (%s) %s\n",
00447                                         ENGINE_get_id(e), ENGINE_get_name(e));
00448                                 }
00449                         if (list_cap)
00450                                 {
00451                                 int cap_size = 256;
00452                                 char *cap_buf = NULL;
00453                                 int k,n;
00454                                 const int *nids;
00455                                 ENGINE_CIPHERS_PTR fn_c;
00456                                 ENGINE_DIGESTS_PTR fn_d;
00457 
00458                                 if (ENGINE_get_RSA(e) != NULL
00459                                         && !append_buf(&cap_buf, "RSA",
00460                                                 &cap_size, 256))
00461                                         goto end;
00462                                 if (ENGINE_get_DSA(e) != NULL
00463                                         && !append_buf(&cap_buf, "DSA",
00464                                                 &cap_size, 256))
00465                                         goto end;
00466                                 if (ENGINE_get_DH(e) != NULL
00467                                         && !append_buf(&cap_buf, "DH",
00468                                                 &cap_size, 256))
00469                                         goto end;
00470                                 if (ENGINE_get_RAND(e) != NULL
00471                                         && !append_buf(&cap_buf, "RAND",
00472                                                 &cap_size, 256))
00473                                         goto end;
00474 
00475                                 fn_c = ENGINE_get_ciphers(e);
00476                                 if(!fn_c) goto skip_ciphers;
00477                                 n = fn_c(e, NULL, &nids, 0);
00478                                 for(k=0 ; k < n ; ++k)
00479                                         if(!append_buf(&cap_buf,
00480                                                        OBJ_nid2sn(nids[k]),
00481                                                        &cap_size, 256))
00482                                                 goto end;
00483 
00484 skip_ciphers:
00485                                 fn_d = ENGINE_get_digests(e);
00486                                 if(!fn_d) goto skip_digests;
00487                                 n = fn_d(e, NULL, &nids, 0);
00488                                 for(k=0 ; k < n ; ++k)
00489                                         if(!append_buf(&cap_buf,
00490                                                        OBJ_nid2sn(nids[k]),
00491                                                        &cap_size, 256))
00492                                                 goto end;
00493 
00494 skip_digests:
00495                                 if (cap_buf && (*cap_buf != '\0'))
00496                                         BIO_printf(bio_out, " [%s]\n", cap_buf);
00497 
00498                                 OPENSSL_free(cap_buf);
00499                                 }
00500                         if(test_avail)
00501                                 {
00502                                 BIO_printf(bio_out, "%s", indent);
00503                                 if (ENGINE_init(e))
00504                                         {
00505                                         BIO_printf(bio_out, "[ available ]\n");
00506                                         util_do_cmds(e, post_cmds, bio_out, indent);
00507                                         ENGINE_finish(e);
00508                                         }
00509                                 else
00510                                         {
00511                                         BIO_printf(bio_out, "[ unavailable ]\n");
00512                                         if(test_avail_noise)
00513                                                 ERR_print_errors_fp(stdout);
00514                                         ERR_clear_error();
00515                                         }
00516                                 }
00517                         if((verbose > 0) && !util_verbose(e, verbose, bio_out, indent))
00518                                 goto end;
00519                         ENGINE_free(e);
00520                         }
00521                 else
00522                         ERR_print_errors(bio_err);
00523                 }
00524 
00525         ret=0;
00526 end:
00527 
00528         ERR_print_errors(bio_err);
00529         sk_pop_free(engines, identity);
00530         sk_pop_free(pre_cmds, identity);
00531         sk_pop_free(post_cmds, identity);
00532         if (bio_out != NULL) BIO_free_all(bio_out);
00533         apps_shutdown();
00534         OPENSSL_EXIT(ret);
00535         }
00536 #else
00537 
00538 # if PEDANTIC
00539 static void *dummy=&dummy;
00540 # endif
00541 
00542 #endif

© sourcejam.com 2005-2008