0fda9f7c29
Partially revertsd33d76168f
Don't fail when tracing is disabled Commitd33d76168f
fixed the problem that the initialization of libcrypto failed when tracing was disabled, because the unoperational ossl_trace_init() function returned a failure code. The problem was fixed by changing its return value from failure to success. As part of the fix the return values of other unimplemented trace API functions (like OSSL_trace_set_channel(),OSSL_trace_set_callback()) was changed from failure to success, too. This change was not necessary and is a bit problematic IMHO, because nobody expects an unimplemented function to pretend it succeeded. It's the application's duty to handle the case correctly when the trace API is not enabled (i.e., OPENSSL_NO_TRACE is defined), not the API's job to pretend success just to prevent the application from failing. Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from https://github.com/openssl/openssl/pull/8552)
1040 lines
27 KiB
C
1040 lines
27 KiB
C
/*
|
|
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
|
|
*
|
|
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
|
* this file except in compliance with the License. You can obtain a copy
|
|
* in the file LICENSE in the source distribution or at
|
|
* https://www.openssl.org/source/license.html
|
|
*/
|
|
|
|
#include <internal/cryptlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <openssl/bio.h>
|
|
#include <openssl/crypto.h>
|
|
#include <openssl/trace.h>
|
|
#include <openssl/lhash.h>
|
|
#include <openssl/conf.h>
|
|
#include <openssl/x509.h>
|
|
#include <openssl/pem.h>
|
|
#include <openssl/ssl.h>
|
|
#ifndef OPENSSL_NO_ENGINE
|
|
# include <openssl/engine.h>
|
|
#endif
|
|
#include <openssl/err.h>
|
|
#include "s_apps.h"
|
|
/* Needed to get the other O_xxx flags. */
|
|
#ifdef OPENSSL_SYS_VMS
|
|
# include <unixio.h>
|
|
#endif
|
|
#include "apps.h"
|
|
#define INCLUDE_FUNCTION_TABLE
|
|
#include "progs.h"
|
|
|
|
/* Structure to hold the number of columns to be displayed and the
|
|
* field width used to display them.
|
|
*/
|
|
typedef struct {
|
|
int columns;
|
|
int width;
|
|
} DISPLAY_COLUMNS;
|
|
|
|
/* Special sentinel to exit the program. */
|
|
#define EXIT_THE_PROGRAM (-1)
|
|
|
|
/*
|
|
* The LHASH callbacks ("hash" & "cmp") have been replaced by functions with
|
|
* the base prototypes (we cast each variable inside the function to the
|
|
* required type of "FUNCTION*"). This removes the necessity for
|
|
* macro-generated wrapper functions.
|
|
*/
|
|
static LHASH_OF(FUNCTION) *prog_init(void);
|
|
static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]);
|
|
static void list_pkey(void);
|
|
static void list_pkey_meth(void);
|
|
static void list_type(FUNC_TYPE ft, int one);
|
|
static void list_engines(void);
|
|
static void list_disabled(void);
|
|
char *default_config_file = NULL;
|
|
|
|
BIO *bio_in = NULL;
|
|
BIO *bio_out = NULL;
|
|
BIO *bio_err = NULL;
|
|
|
|
static void calculate_columns(DISPLAY_COLUMNS *dc)
|
|
{
|
|
FUNCTION *f;
|
|
int len, maxlen = 0;
|
|
|
|
for (f = functions; f->name != NULL; ++f)
|
|
if (f->type == FT_general || f->type == FT_md || f->type == FT_cipher)
|
|
if ((len = strlen(f->name)) > maxlen)
|
|
maxlen = len;
|
|
|
|
dc->width = maxlen + 2;
|
|
dc->columns = (80 - 1) / dc->width;
|
|
}
|
|
|
|
static int apps_startup(void)
|
|
{
|
|
#ifdef SIGPIPE
|
|
signal(SIGPIPE, SIG_IGN);
|
|
#endif
|
|
|
|
/* Set non-default library initialisation settings */
|
|
if (!OPENSSL_init_ssl(OPENSSL_INIT_ENGINE_ALL_BUILTIN
|
|
| OPENSSL_INIT_LOAD_CONFIG, NULL))
|
|
return 0;
|
|
|
|
setup_ui_method();
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void apps_shutdown(void)
|
|
{
|
|
destroy_ui_method();
|
|
}
|
|
|
|
static char *make_config_name(void)
|
|
{
|
|
const char *t;
|
|
size_t len;
|
|
char *p;
|
|
|
|
if ((t = getenv("OPENSSL_CONF")) != NULL)
|
|
return OPENSSL_strdup(t);
|
|
|
|
t = X509_get_default_cert_area();
|
|
len = strlen(t) + 1 + strlen(OPENSSL_CONF) + 1;
|
|
p = app_malloc(len, "config filename buffer");
|
|
strcpy(p, t);
|
|
#ifndef OPENSSL_SYS_VMS
|
|
strcat(p, "/");
|
|
#endif
|
|
strcat(p, OPENSSL_CONF);
|
|
|
|
return p;
|
|
}
|
|
|
|
|
|
#ifndef OPENSSL_NO_TRACE
|
|
typedef struct tracedata_st {
|
|
BIO *bio;
|
|
unsigned int ingroup:1;
|
|
} tracedata;
|
|
|
|
static size_t internal_trace_cb(const char *buf, size_t cnt,
|
|
int category, int cmd, void *vdata)
|
|
{
|
|
int ret = 0;
|
|
tracedata *trace_data = vdata;
|
|
union {
|
|
CRYPTO_THREAD_ID tid;
|
|
unsigned long ltid;
|
|
} tid;
|
|
char buffer[256];
|
|
|
|
switch (cmd) {
|
|
case OSSL_TRACE_CTRL_BEGIN:
|
|
if (!ossl_assert(!trace_data->ingroup))
|
|
return 0;
|
|
trace_data->ingroup = 1;
|
|
|
|
tid.ltid = 0;
|
|
tid.tid = CRYPTO_THREAD_get_current_id();
|
|
|
|
BIO_snprintf(buffer, sizeof(buffer), "TRACE[%lx]:%s: ", tid.ltid,
|
|
OSSL_trace_get_category_name(category));
|
|
BIO_ctrl(trace_data->bio, PREFIX_CTRL_SET_PREFIX,
|
|
strlen(buffer), buffer);
|
|
break;
|
|
case OSSL_TRACE_CTRL_WRITE:
|
|
if (!ossl_assert(trace_data->ingroup))
|
|
return 0;
|
|
|
|
ret = BIO_write(trace_data->bio, buf, cnt);
|
|
break;
|
|
case OSSL_TRACE_CTRL_END:
|
|
if (!ossl_assert(trace_data->ingroup))
|
|
return 0;
|
|
trace_data->ingroup = 0;
|
|
|
|
BIO_ctrl(trace_data->bio, PREFIX_CTRL_SET_PREFIX, 0, NULL);
|
|
|
|
break;
|
|
}
|
|
|
|
return ret < 0 ? 0 : ret;
|
|
}
|
|
|
|
DEFINE_STACK_OF(tracedata)
|
|
static STACK_OF(tracedata) *trace_data_stack;
|
|
|
|
static void tracedata_free(tracedata *data)
|
|
{
|
|
BIO_free_all(data->bio);
|
|
OPENSSL_free(data);
|
|
}
|
|
|
|
static STACK_OF(tracedata) *trace_data_stack;
|
|
|
|
static void cleanup_trace(void)
|
|
{
|
|
sk_tracedata_pop_free(trace_data_stack, tracedata_free);
|
|
}
|
|
|
|
static void setup_trace(const char *str)
|
|
{
|
|
char *val;
|
|
|
|
trace_data_stack = sk_tracedata_new_null();
|
|
val = OPENSSL_strdup(str);
|
|
|
|
if (val != NULL) {
|
|
char *valp = val;
|
|
char *item;
|
|
|
|
for (valp = val; (item = strtok(valp, ",")) != NULL; valp = NULL) {
|
|
int category = OSSL_trace_get_category_num(item);
|
|
|
|
if (category >= 0) {
|
|
BIO *channel = BIO_push(BIO_new(apps_bf_prefix()),
|
|
dup_bio_err(FORMAT_TEXT));
|
|
tracedata *trace_data = OPENSSL_zalloc(sizeof(*trace_data));
|
|
|
|
if (trace_data == NULL
|
|
|| (trace_data->bio = channel) == NULL
|
|
|| OSSL_trace_set_callback(category, internal_trace_cb,
|
|
trace_data) == 0
|
|
|| sk_tracedata_push(trace_data_stack, trace_data) == 0) {
|
|
OSSL_trace_set_callback(category, NULL, NULL);
|
|
BIO_free_all(channel);
|
|
fprintf(stderr,
|
|
"warning: unable to setup trace callback for category '%s'.\n",
|
|
item);
|
|
}
|
|
} else {
|
|
fprintf(stderr,
|
|
"warning: unknown trace category: '%s'.\n",
|
|
item);
|
|
}
|
|
}
|
|
}
|
|
|
|
OPENSSL_free(val);
|
|
atexit(cleanup_trace);
|
|
}
|
|
#endif /* OPENSSL_NO_TRACE */
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
FUNCTION f, *fp;
|
|
LHASH_OF(FUNCTION) *prog = NULL;
|
|
char *p, *pname;
|
|
char buf[1024];
|
|
const char *prompt;
|
|
ARGS arg;
|
|
int first, n, i, ret = 0;
|
|
|
|
arg.argv = NULL;
|
|
arg.size = 0;
|
|
|
|
/* Set up some of the environment. */
|
|
default_config_file = make_config_name();
|
|
bio_in = dup_bio_in(FORMAT_TEXT);
|
|
bio_out = dup_bio_out(FORMAT_TEXT);
|
|
bio_err = dup_bio_err(FORMAT_TEXT);
|
|
|
|
#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
|
|
argv = copy_argv(&argc, argv);
|
|
#elif defined(_WIN32)
|
|
/*
|
|
* Replace argv[] with UTF-8 encoded strings.
|
|
*/
|
|
win32_utf8argv(&argc, &argv);
|
|
#endif
|
|
|
|
/*
|
|
* We use the prefix method to get the trace output we want. Since some
|
|
* trace outputs happen with OPENSSL_cleanup(), which is run automatically
|
|
* after exit(), we need to destroy the prefix method as late as possible.
|
|
*/
|
|
atexit(destroy_prefix_method);
|
|
|
|
#ifndef OPENSSL_NO_TRACE
|
|
setup_trace(getenv("OPENSSL_TRACE"));
|
|
#endif
|
|
|
|
p = getenv("OPENSSL_DEBUG_MEMORY");
|
|
if (p != NULL && strcmp(p, "on") == 0)
|
|
CRYPTO_set_mem_debug(1);
|
|
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
|
|
|
|
if (getenv("OPENSSL_FIPS")) {
|
|
BIO_printf(bio_err, "FIPS mode not supported.\n");
|
|
return 1;
|
|
}
|
|
|
|
if (!apps_startup()) {
|
|
BIO_printf(bio_err,
|
|
"FATAL: Startup failure (dev note: apps_startup() failed)\n");
|
|
ERR_print_errors(bio_err);
|
|
ret = 1;
|
|
goto end;
|
|
}
|
|
|
|
prog = prog_init();
|
|
pname = opt_progname(argv[0]);
|
|
|
|
/* first check the program name */
|
|
f.name = pname;
|
|
fp = lh_FUNCTION_retrieve(prog, &f);
|
|
if (fp != NULL) {
|
|
argv[0] = pname;
|
|
ret = fp->func(argc, argv);
|
|
goto end;
|
|
}
|
|
|
|
/* If there is stuff on the command line, run with that. */
|
|
if (argc != 1) {
|
|
argc--;
|
|
argv++;
|
|
ret = do_cmd(prog, argc, argv);
|
|
if (ret < 0)
|
|
ret = 0;
|
|
goto end;
|
|
}
|
|
|
|
/* ok, lets enter interactive mode */
|
|
for (;;) {
|
|
ret = 0;
|
|
/* Read a line, continue reading if line ends with \ */
|
|
for (p = buf, n = sizeof(buf), i = 0, first = 1; n > 0; first = 0) {
|
|
prompt = first ? "OpenSSL> " : "> ";
|
|
p[0] = '\0';
|
|
#ifndef READLINE
|
|
fputs(prompt, stdout);
|
|
fflush(stdout);
|
|
if (!fgets(p, n, stdin))
|
|
goto end;
|
|
if (p[0] == '\0')
|
|
goto end;
|
|
i = strlen(p);
|
|
if (i <= 1)
|
|
break;
|
|
if (p[i - 2] != '\\')
|
|
break;
|
|
i -= 2;
|
|
p += i;
|
|
n -= i;
|
|
#else
|
|
{
|
|
extern char *readline(const char *);
|
|
extern void add_history(const char *cp);
|
|
char *text;
|
|
|
|
text = readline(prompt);
|
|
if (text == NULL)
|
|
goto end;
|
|
i = strlen(text);
|
|
if (i == 0 || i > n)
|
|
break;
|
|
if (text[i - 1] != '\\') {
|
|
p += strlen(strcpy(p, text));
|
|
free(text);
|
|
add_history(buf);
|
|
break;
|
|
}
|
|
|
|
text[i - 1] = '\0';
|
|
p += strlen(strcpy(p, text));
|
|
free(text);
|
|
n -= i;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (!chopup_args(&arg, buf)) {
|
|
BIO_printf(bio_err, "Can't parse (no memory?)\n");
|
|
break;
|
|
}
|
|
|
|
ret = do_cmd(prog, arg.argc, arg.argv);
|
|
if (ret == EXIT_THE_PROGRAM) {
|
|
ret = 0;
|
|
goto end;
|
|
}
|
|
if (ret != 0)
|
|
BIO_printf(bio_err, "error in %s\n", arg.argv[0]);
|
|
(void)BIO_flush(bio_out);
|
|
(void)BIO_flush(bio_err);
|
|
}
|
|
ret = 1;
|
|
end:
|
|
OPENSSL_free(default_config_file);
|
|
lh_FUNCTION_free(prog);
|
|
OPENSSL_free(arg.argv);
|
|
app_RAND_write();
|
|
|
|
BIO_free(bio_in);
|
|
BIO_free_all(bio_out);
|
|
apps_shutdown();
|
|
#ifndef OPENSSL_NO_CRYPTO_MDEBUG
|
|
if (CRYPTO_mem_leaks(bio_err) <= 0)
|
|
ret = 1;
|
|
#endif
|
|
BIO_free(bio_err);
|
|
EXIT(ret);
|
|
}
|
|
|
|
static void list_cipher_fn(const EVP_CIPHER *c,
|
|
const char *from, const char *to, void *arg)
|
|
{
|
|
if (c != NULL) {
|
|
BIO_printf(arg, "%s\n", EVP_CIPHER_name(c));
|
|
} else {
|
|
if (from == NULL)
|
|
from = "<undefined>";
|
|
if (to == NULL)
|
|
to = "<undefined>";
|
|
BIO_printf(arg, "%s => %s\n", from, to);
|
|
}
|
|
}
|
|
|
|
static void list_md_fn(const EVP_MD *m,
|
|
const char *from, const char *to, void *arg)
|
|
{
|
|
if (m != NULL) {
|
|
BIO_printf(arg, "%s\n", EVP_MD_name(m));
|
|
} else {
|
|
if (from == NULL)
|
|
from = "<undefined>";
|
|
if (to == NULL)
|
|
to = "<undefined>";
|
|
BIO_printf((BIO *)arg, "%s => %s\n", from, to);
|
|
}
|
|
}
|
|
|
|
static void list_mac_fn(const EVP_MAC *m,
|
|
const char *from, const char *to, void *arg)
|
|
{
|
|
if (m != NULL) {
|
|
BIO_printf(arg, "%s\n", EVP_MAC_name(m));
|
|
} else {
|
|
if (from == NULL)
|
|
from = "<undefined>";
|
|
if (to == NULL)
|
|
to = "<undefined>";
|
|
BIO_printf(arg, "%s => %s\n", from, to);
|
|
}
|
|
}
|
|
|
|
static void list_missing_help(void)
|
|
{
|
|
const FUNCTION *fp;
|
|
const OPTIONS *o;
|
|
|
|
for (fp = functions; fp->name != NULL; fp++) {
|
|
if ((o = fp->help) != NULL) {
|
|
/* If there is help, list what flags are not documented. */
|
|
for ( ; o->name != NULL; o++) {
|
|
if (o->helpstr == NULL)
|
|
BIO_printf(bio_out, "%s %s\n", fp->name, o->name);
|
|
}
|
|
} else if (fp->func != dgst_main) {
|
|
/* If not aliased to the dgst command, */
|
|
BIO_printf(bio_out, "%s *\n", fp->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void list_objects(void)
|
|
{
|
|
int max_nid = OBJ_new_nid(0);
|
|
int i;
|
|
char *oid_buf = NULL;
|
|
int oid_size = 0;
|
|
|
|
/* Skip 0, since that's NID_undef */
|
|
for (i = 1; i < max_nid; i++) {
|
|
const ASN1_OBJECT *obj = OBJ_nid2obj(i);
|
|
const char *sn = OBJ_nid2sn(i);
|
|
const char *ln = OBJ_nid2ln(i);
|
|
int n = 0;
|
|
|
|
/*
|
|
* If one of the retrieved objects somehow generated an error,
|
|
* we ignore it. The check for NID_undef below will detect the
|
|
* error and simply skip to the next NID.
|
|
*/
|
|
ERR_clear_error();
|
|
|
|
if (OBJ_obj2nid(obj) == NID_undef)
|
|
continue;
|
|
|
|
if ((n = OBJ_obj2txt(NULL, 0, obj, 1)) == 0) {
|
|
BIO_printf(bio_out, "# None-OID object: %s, %s\n", sn, ln);
|
|
continue;
|
|
}
|
|
if (n < 0)
|
|
break; /* Error */
|
|
|
|
if (n > oid_size) {
|
|
oid_buf = OPENSSL_realloc(oid_buf, n + 1);
|
|
if (oid_buf == NULL) {
|
|
BIO_printf(bio_err, "ERROR: Memory allocation\n");
|
|
break; /* Error */
|
|
}
|
|
oid_size = n + 1;
|
|
}
|
|
if (OBJ_obj2txt(oid_buf, oid_size, obj, 1) < 0)
|
|
break; /* Error */
|
|
if (ln == NULL || strcmp(sn, ln) == 0)
|
|
BIO_printf(bio_out, "%s = %s\n", sn, oid_buf);
|
|
else
|
|
BIO_printf(bio_out, "%s = %s, %s\n", sn, ln, oid_buf);
|
|
}
|
|
|
|
OPENSSL_free(oid_buf);
|
|
}
|
|
|
|
static void list_options_for_command(const char *command)
|
|
{
|
|
const FUNCTION *fp;
|
|
const OPTIONS *o;
|
|
|
|
for (fp = functions; fp->name != NULL; fp++)
|
|
if (strcmp(fp->name, command) == 0)
|
|
break;
|
|
if (fp->name == NULL) {
|
|
BIO_printf(bio_err, "Invalid command '%s'; type \"help\" for a list.\n",
|
|
command);
|
|
return;
|
|
}
|
|
|
|
if ((o = fp->help) == NULL)
|
|
return;
|
|
|
|
for ( ; o->name != NULL; o++) {
|
|
if (o->name == OPT_HELP_STR
|
|
|| o->name == OPT_MORE_STR
|
|
|| o->name[0] == '\0')
|
|
continue;
|
|
BIO_printf(bio_out, "%s %c\n", o->name, o->valtype);
|
|
}
|
|
}
|
|
|
|
|
|
/* Unified enum for help and list commands. */
|
|
typedef enum HELPLIST_CHOICE {
|
|
OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_ONE,
|
|
OPT_COMMANDS, OPT_DIGEST_COMMANDS, OPT_MAC_ALGORITHMS, OPT_OPTIONS,
|
|
OPT_DIGEST_ALGORITHMS, OPT_CIPHER_COMMANDS, OPT_CIPHER_ALGORITHMS,
|
|
OPT_PK_ALGORITHMS, OPT_PK_METHOD, OPT_ENGINES, OPT_DISABLED,
|
|
OPT_MISSING_HELP, OPT_OBJECTS
|
|
} HELPLIST_CHOICE;
|
|
|
|
const OPTIONS list_options[] = {
|
|
{"help", OPT_HELP, '-', "Display this summary"},
|
|
{"1", OPT_ONE, '-', "List in one column"},
|
|
{"commands", OPT_COMMANDS, '-', "List of standard commands"},
|
|
{"digest-commands", OPT_DIGEST_COMMANDS, '-',
|
|
"List of message digest commands"},
|
|
{"digest-algorithms", OPT_DIGEST_ALGORITHMS, '-',
|
|
"List of message digest algorithms"},
|
|
{"mac-algorithms", OPT_MAC_ALGORITHMS, '-',
|
|
"List of message authentication code algorithms"},
|
|
{"cipher-commands", OPT_CIPHER_COMMANDS, '-', "List of cipher commands"},
|
|
{"cipher-algorithms", OPT_CIPHER_ALGORITHMS, '-',
|
|
"List of cipher algorithms"},
|
|
{"public-key-algorithms", OPT_PK_ALGORITHMS, '-',
|
|
"List of public key algorithms"},
|
|
{"public-key-methods", OPT_PK_METHOD, '-',
|
|
"List of public key methods"},
|
|
{"engines", OPT_ENGINES, '-',
|
|
"List of loaded engines"},
|
|
{"disabled", OPT_DISABLED, '-',
|
|
"List of disabled features"},
|
|
{"missing-help", OPT_MISSING_HELP, '-',
|
|
"List missing detailed help strings"},
|
|
{"options", OPT_OPTIONS, 's',
|
|
"List options for specified command"},
|
|
{"objects", OPT_OBJECTS, '-',
|
|
"List built in objects (OID<->name mappings)"},
|
|
{NULL}
|
|
};
|
|
|
|
int list_main(int argc, char **argv)
|
|
{
|
|
char *prog;
|
|
HELPLIST_CHOICE o;
|
|
int one = 0, done = 0;
|
|
|
|
prog = opt_init(argc, argv, list_options);
|
|
while ((o = opt_next()) != OPT_EOF) {
|
|
switch (o) {
|
|
case OPT_EOF: /* Never hit, but suppresses warning */
|
|
case OPT_ERR:
|
|
opthelp:
|
|
BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
|
|
return 1;
|
|
case OPT_HELP:
|
|
opt_help(list_options);
|
|
break;
|
|
case OPT_ONE:
|
|
one = 1;
|
|
break;
|
|
case OPT_COMMANDS:
|
|
list_type(FT_general, one);
|
|
break;
|
|
case OPT_DIGEST_COMMANDS:
|
|
list_type(FT_md, one);
|
|
break;
|
|
case OPT_DIGEST_ALGORITHMS:
|
|
EVP_MD_do_all_sorted(list_md_fn, bio_out);
|
|
break;
|
|
case OPT_MAC_ALGORITHMS:
|
|
EVP_MAC_do_all_sorted(list_mac_fn, bio_out);
|
|
break;
|
|
case OPT_CIPHER_COMMANDS:
|
|
list_type(FT_cipher, one);
|
|
break;
|
|
case OPT_CIPHER_ALGORITHMS:
|
|
EVP_CIPHER_do_all_sorted(list_cipher_fn, bio_out);
|
|
break;
|
|
case OPT_PK_ALGORITHMS:
|
|
list_pkey();
|
|
break;
|
|
case OPT_PK_METHOD:
|
|
list_pkey_meth();
|
|
break;
|
|
case OPT_ENGINES:
|
|
list_engines();
|
|
break;
|
|
case OPT_DISABLED:
|
|
list_disabled();
|
|
break;
|
|
case OPT_MISSING_HELP:
|
|
list_missing_help();
|
|
break;
|
|
case OPT_OBJECTS:
|
|
list_objects();
|
|
break;
|
|
case OPT_OPTIONS:
|
|
list_options_for_command(opt_arg());
|
|
break;
|
|
}
|
|
done = 1;
|
|
}
|
|
if (opt_num_rest() != 0) {
|
|
BIO_printf(bio_err, "Extra arguments given.\n");
|
|
goto opthelp;
|
|
}
|
|
|
|
if (!done)
|
|
goto opthelp;
|
|
|
|
return 0;
|
|
}
|
|
|
|
typedef enum HELP_CHOICE {
|
|
OPT_hERR = -1, OPT_hEOF = 0, OPT_hHELP
|
|
} HELP_CHOICE;
|
|
|
|
const OPTIONS help_options[] = {
|
|
{OPT_HELP_STR, 1, '-', "Usage: help [options]\n"},
|
|
{OPT_HELP_STR, 1, '-', " help [command]\n"},
|
|
{"help", OPT_hHELP, '-', "Display this summary"},
|
|
{NULL}
|
|
};
|
|
|
|
|
|
int help_main(int argc, char **argv)
|
|
{
|
|
FUNCTION *fp;
|
|
int i, nl;
|
|
FUNC_TYPE tp;
|
|
char *prog;
|
|
HELP_CHOICE o;
|
|
DISPLAY_COLUMNS dc;
|
|
|
|
prog = opt_init(argc, argv, help_options);
|
|
while ((o = opt_next()) != OPT_hEOF) {
|
|
switch (o) {
|
|
case OPT_hERR:
|
|
case OPT_hEOF:
|
|
BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
|
|
return 1;
|
|
case OPT_hHELP:
|
|
opt_help(help_options);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (opt_num_rest() == 1) {
|
|
char *new_argv[3];
|
|
|
|
new_argv[0] = opt_rest()[0];
|
|
new_argv[1] = "--help";
|
|
new_argv[2] = NULL;
|
|
return do_cmd(prog_init(), 2, new_argv);
|
|
}
|
|
if (opt_num_rest() != 0) {
|
|
BIO_printf(bio_err, "Usage: %s\n", prog);
|
|
return 1;
|
|
}
|
|
|
|
calculate_columns(&dc);
|
|
BIO_printf(bio_err, "Standard commands");
|
|
i = 0;
|
|
tp = FT_none;
|
|
for (fp = functions; fp->name != NULL; fp++) {
|
|
nl = 0;
|
|
if (i++ % dc.columns == 0) {
|
|
BIO_printf(bio_err, "\n");
|
|
nl = 1;
|
|
}
|
|
if (fp->type != tp) {
|
|
tp = fp->type;
|
|
if (!nl)
|
|
BIO_printf(bio_err, "\n");
|
|
if (tp == FT_md) {
|
|
i = 1;
|
|
BIO_printf(bio_err,
|
|
"\nMessage Digest commands (see the `dgst' command for more details)\n");
|
|
} else if (tp == FT_cipher) {
|
|
i = 1;
|
|
BIO_printf(bio_err,
|
|
"\nCipher commands (see the `enc' command for more details)\n");
|
|
}
|
|
}
|
|
BIO_printf(bio_err, "%-*s", dc.width, fp->name);
|
|
}
|
|
BIO_printf(bio_err, "\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static void list_type(FUNC_TYPE ft, int one)
|
|
{
|
|
FUNCTION *fp;
|
|
int i = 0;
|
|
DISPLAY_COLUMNS dc;
|
|
|
|
memset(&dc, 0, sizeof(dc));
|
|
if (!one)
|
|
calculate_columns(&dc);
|
|
|
|
for (fp = functions; fp->name != NULL; fp++) {
|
|
if (fp->type != ft)
|
|
continue;
|
|
if (one) {
|
|
BIO_printf(bio_out, "%s\n", fp->name);
|
|
} else {
|
|
if (i % dc.columns == 0 && i > 0)
|
|
BIO_printf(bio_out, "\n");
|
|
BIO_printf(bio_out, "%-*s", dc.width, fp->name);
|
|
i++;
|
|
}
|
|
}
|
|
if (!one)
|
|
BIO_printf(bio_out, "\n\n");
|
|
}
|
|
|
|
static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[])
|
|
{
|
|
FUNCTION f, *fp;
|
|
|
|
if (argc <= 0 || argv[0] == NULL)
|
|
return 0;
|
|
f.name = argv[0];
|
|
fp = lh_FUNCTION_retrieve(prog, &f);
|
|
if (fp == NULL) {
|
|
if (EVP_get_digestbyname(argv[0])) {
|
|
f.type = FT_md;
|
|
f.func = dgst_main;
|
|
fp = &f;
|
|
} else if (EVP_get_cipherbyname(argv[0])) {
|
|
f.type = FT_cipher;
|
|
f.func = enc_main;
|
|
fp = &f;
|
|
}
|
|
}
|
|
if (fp != NULL) {
|
|
return fp->func(argc, argv);
|
|
}
|
|
if ((strncmp(argv[0], "no-", 3)) == 0) {
|
|
/*
|
|
* User is asking if foo is unsupported, by trying to "run" the
|
|
* no-foo command. Strange.
|
|
*/
|
|
f.name = argv[0] + 3;
|
|
if (lh_FUNCTION_retrieve(prog, &f) == NULL) {
|
|
BIO_printf(bio_out, "%s\n", argv[0]);
|
|
return 0;
|
|
}
|
|
BIO_printf(bio_out, "%s\n", argv[0] + 3);
|
|
return 1;
|
|
}
|
|
if (strcmp(argv[0], "quit") == 0 || strcmp(argv[0], "q") == 0 ||
|
|
strcmp(argv[0], "exit") == 0 || strcmp(argv[0], "bye") == 0)
|
|
/* Special value to mean "exit the program. */
|
|
return EXIT_THE_PROGRAM;
|
|
|
|
BIO_printf(bio_err, "Invalid command '%s'; type \"help\" for a list.\n",
|
|
argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
static void list_pkey(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) {
|
|
const EVP_PKEY_ASN1_METHOD *ameth;
|
|
int pkey_id, pkey_base_id, pkey_flags;
|
|
const char *pinfo, *pem_str;
|
|
ameth = EVP_PKEY_asn1_get0(i);
|
|
EVP_PKEY_asn1_get0_info(&pkey_id, &pkey_base_id, &pkey_flags,
|
|
&pinfo, &pem_str, ameth);
|
|
if (pkey_flags & ASN1_PKEY_ALIAS) {
|
|
BIO_printf(bio_out, "Name: %s\n", OBJ_nid2ln(pkey_id));
|
|
BIO_printf(bio_out, "\tAlias for: %s\n",
|
|
OBJ_nid2ln(pkey_base_id));
|
|
} else {
|
|
BIO_printf(bio_out, "Name: %s\n", pinfo);
|
|
BIO_printf(bio_out, "\tType: %s Algorithm\n",
|
|
pkey_flags & ASN1_PKEY_DYNAMIC ?
|
|
"External" : "Builtin");
|
|
BIO_printf(bio_out, "\tOID: %s\n", OBJ_nid2ln(pkey_id));
|
|
if (pem_str == NULL)
|
|
pem_str = "(none)";
|
|
BIO_printf(bio_out, "\tPEM string: %s\n", pem_str);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
static void list_pkey_meth(void)
|
|
{
|
|
size_t i;
|
|
size_t meth_count = EVP_PKEY_meth_get_count();
|
|
|
|
for (i = 0; i < meth_count; i++) {
|
|
const EVP_PKEY_METHOD *pmeth = EVP_PKEY_meth_get0(i);
|
|
int pkey_id, pkey_flags;
|
|
|
|
EVP_PKEY_meth_get0_info(&pkey_id, &pkey_flags, pmeth);
|
|
BIO_printf(bio_out, "%s\n", OBJ_nid2ln(pkey_id));
|
|
BIO_printf(bio_out, "\tType: %s Algorithm\n",
|
|
pkey_flags & ASN1_PKEY_DYNAMIC ? "External" : "Builtin");
|
|
}
|
|
}
|
|
|
|
static int function_cmp(const FUNCTION * a, const FUNCTION * b)
|
|
{
|
|
return strncmp(a->name, b->name, 8);
|
|
}
|
|
|
|
static unsigned long function_hash(const FUNCTION * a)
|
|
{
|
|
return OPENSSL_LH_strhash(a->name);
|
|
}
|
|
|
|
static int SortFnByName(const void *_f1, const void *_f2)
|
|
{
|
|
const FUNCTION *f1 = _f1;
|
|
const FUNCTION *f2 = _f2;
|
|
|
|
if (f1->type != f2->type)
|
|
return f1->type - f2->type;
|
|
return strcmp(f1->name, f2->name);
|
|
}
|
|
|
|
static void list_engines(void)
|
|
{
|
|
#ifndef OPENSSL_NO_ENGINE
|
|
ENGINE *e;
|
|
|
|
BIO_puts(bio_out, "Engines:\n");
|
|
e = ENGINE_get_first();
|
|
while (e) {
|
|
BIO_printf(bio_out, "%s\n", ENGINE_get_id(e));
|
|
e = ENGINE_get_next(e);
|
|
}
|
|
#else
|
|
BIO_puts(bio_out, "Engine support is disabled.\n");
|
|
#endif
|
|
}
|
|
|
|
static void list_disabled(void)
|
|
{
|
|
BIO_puts(bio_out, "Disabled algorithms:\n");
|
|
#ifdef OPENSSL_NO_ARIA
|
|
BIO_puts(bio_out, "ARIA\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_BF
|
|
BIO_puts(bio_out, "BF\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_BLAKE2
|
|
BIO_puts(bio_out, "BLAKE2\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_CAMELLIA
|
|
BIO_puts(bio_out, "CAMELLIA\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_CAST
|
|
BIO_puts(bio_out, "CAST\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_CMAC
|
|
BIO_puts(bio_out, "CMAC\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_CMS
|
|
BIO_puts(bio_out, "CMS\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_COMP
|
|
BIO_puts(bio_out, "COMP\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_DES
|
|
BIO_puts(bio_out, "DES\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_DGRAM
|
|
BIO_puts(bio_out, "DGRAM\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_DH
|
|
BIO_puts(bio_out, "DH\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_DSA
|
|
BIO_puts(bio_out, "DSA\n");
|
|
#endif
|
|
#if defined(OPENSSL_NO_DTLS)
|
|
BIO_puts(bio_out, "DTLS\n");
|
|
#endif
|
|
#if defined(OPENSSL_NO_DTLS1)
|
|
BIO_puts(bio_out, "DTLS1\n");
|
|
#endif
|
|
#if defined(OPENSSL_NO_DTLS1_2)
|
|
BIO_puts(bio_out, "DTLS1_2\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_EC
|
|
BIO_puts(bio_out, "EC\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_EC2M
|
|
BIO_puts(bio_out, "EC2M\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_ENGINE
|
|
BIO_puts(bio_out, "ENGINE\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_GOST
|
|
BIO_puts(bio_out, "GOST\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_IDEA
|
|
BIO_puts(bio_out, "IDEA\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_MD2
|
|
BIO_puts(bio_out, "MD2\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_MD4
|
|
BIO_puts(bio_out, "MD4\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_MD5
|
|
BIO_puts(bio_out, "MD5\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_MDC2
|
|
BIO_puts(bio_out, "MDC2\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_OCB
|
|
BIO_puts(bio_out, "OCB\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_OCSP
|
|
BIO_puts(bio_out, "OCSP\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_PSK
|
|
BIO_puts(bio_out, "PSK\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_RC2
|
|
BIO_puts(bio_out, "RC2\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_RC4
|
|
BIO_puts(bio_out, "RC4\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_RC5
|
|
BIO_puts(bio_out, "RC5\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_RMD160
|
|
BIO_puts(bio_out, "RMD160\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_RSA
|
|
BIO_puts(bio_out, "RSA\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_SCRYPT
|
|
BIO_puts(bio_out, "SCRYPT\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_SCTP
|
|
BIO_puts(bio_out, "SCTP\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_SEED
|
|
BIO_puts(bio_out, "SEED\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_SM2
|
|
BIO_puts(bio_out, "SM2\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_SM3
|
|
BIO_puts(bio_out, "SM3\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_SM4
|
|
BIO_puts(bio_out, "SM4\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_SOCK
|
|
BIO_puts(bio_out, "SOCK\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_SRP
|
|
BIO_puts(bio_out, "SRP\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_SRTP
|
|
BIO_puts(bio_out, "SRTP\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_SSL3
|
|
BIO_puts(bio_out, "SSL3\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_TLS1
|
|
BIO_puts(bio_out, "TLS1\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_TLS1_1
|
|
BIO_puts(bio_out, "TLS1_1\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_TLS1_2
|
|
BIO_puts(bio_out, "TLS1_2\n");
|
|
#endif
|
|
#ifdef OPENSSL_NO_WHIRLPOOL
|
|
BIO_puts(bio_out, "WHIRLPOOL\n");
|
|
#endif
|
|
#ifndef ZLIB
|
|
BIO_puts(bio_out, "ZLIB\n");
|
|
#endif
|
|
}
|
|
|
|
static LHASH_OF(FUNCTION) *prog_init(void)
|
|
{
|
|
static LHASH_OF(FUNCTION) *ret = NULL;
|
|
static int prog_inited = 0;
|
|
FUNCTION *f;
|
|
size_t i;
|
|
|
|
if (prog_inited)
|
|
return ret;
|
|
|
|
prog_inited = 1;
|
|
|
|
/* Sort alphabetically within category. For nicer help displays. */
|
|
for (i = 0, f = functions; f->name != NULL; ++f, ++i)
|
|
;
|
|
qsort(functions, i, sizeof(*functions), SortFnByName);
|
|
|
|
if ((ret = lh_FUNCTION_new(function_hash, function_cmp)) == NULL)
|
|
return NULL;
|
|
|
|
for (f = functions; f->name != NULL; f++)
|
|
(void)lh_FUNCTION_insert(ret, f);
|
|
return ret;
|
|
}
|