Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/apps/openssl.c
104185 views
1
/*
2
* Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
3
*
4
* Licensed under the Apache License 2.0 (the "License"). You may not use
5
* this file except in compliance with the License. You can obtain a copy
6
* in the file LICENSE in the source distribution or at
7
* https://www.openssl.org/source/license.html
8
*/
9
10
#include "internal/e_os.h"
11
12
#include <stdio.h>
13
#include <stdlib.h>
14
#include "internal/common.h"
15
#include <openssl/bio.h>
16
#include <openssl/crypto.h>
17
#include <openssl/trace.h>
18
#include <openssl/lhash.h>
19
#include <openssl/conf.h>
20
#include <openssl/x509.h>
21
#include <openssl/pem.h>
22
#include <openssl/ssl.h>
23
#ifndef OPENSSL_NO_ENGINE
24
#include <openssl/engine.h>
25
#endif
26
#include <openssl/err.h>
27
/* Needed to get the other O_xxx flags. */
28
#ifdef OPENSSL_SYS_VMS
29
#include <unixio.h>
30
#endif
31
#include "apps.h"
32
#include "progs.h"
33
34
/*
35
* The LHASH callbacks ("hash" & "cmp") have been replaced by functions with
36
* the base prototypes (we cast each variable inside the function to the
37
* required type of "FUNCTION*"). This removes the necessity for
38
* macro-generated wrapper functions.
39
*/
40
static LHASH_OF(FUNCTION) *prog_init(void);
41
static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]);
42
char *default_config_file = NULL;
43
44
BIO *bio_in = NULL;
45
BIO *bio_out = NULL;
46
BIO *bio_err = NULL;
47
48
static void warn_deprecated(const FUNCTION *fp)
49
{
50
if (fp->deprecated_version != NULL)
51
BIO_printf(bio_err, "The command %s was deprecated in version %s.",
52
fp->name, fp->deprecated_version);
53
else
54
BIO_printf(bio_err, "The command %s is deprecated.", fp->name);
55
if (strcmp(fp->deprecated_alternative, DEPRECATED_NO_ALTERNATIVE) != 0)
56
BIO_printf(bio_err, " Use '%s' instead.", fp->deprecated_alternative);
57
BIO_printf(bio_err, "\n");
58
}
59
60
static int apps_startup(void)
61
{
62
const char *use_libctx = NULL;
63
#ifdef SIGPIPE
64
signal(SIGPIPE, SIG_IGN);
65
#endif
66
67
/* Set non-default library initialisation settings */
68
if (!OPENSSL_init_ssl(OPENSSL_INIT_ENGINE_ALL_BUILTIN
69
| OPENSSL_INIT_LOAD_CONFIG,
70
NULL))
71
return 0;
72
73
(void)setup_ui_method();
74
(void)setup_engine_loader();
75
76
/*
77
* NOTE: This is an undocumented feature required for testing only.
78
* There are no guarantees that it will exist in future builds.
79
*/
80
use_libctx = getenv("OPENSSL_TEST_LIBCTX");
81
if (use_libctx != NULL) {
82
/* Set this to "1" to create a global libctx */
83
if (strcmp(use_libctx, "1") == 0) {
84
if (app_create_libctx() == NULL)
85
return 0;
86
}
87
}
88
89
return 1;
90
}
91
92
static void apps_shutdown(void)
93
{
94
app_providers_cleanup();
95
OSSL_LIB_CTX_free(app_get0_libctx());
96
destroy_engine_loader();
97
destroy_ui_method();
98
}
99
100
#ifndef OPENSSL_NO_TRACE
101
typedef struct tracedata_st {
102
BIO *bio;
103
unsigned int ingroup : 1;
104
} tracedata;
105
106
static size_t internal_trace_cb(const char *buf, size_t cnt,
107
int category, int cmd, void *vdata)
108
{
109
int ret = 0;
110
tracedata *trace_data = vdata;
111
char buffer[256], *hex;
112
CRYPTO_THREAD_ID tid;
113
114
switch (cmd) {
115
case OSSL_TRACE_CTRL_BEGIN:
116
if (trace_data->ingroup) {
117
BIO_printf(bio_err, "ERROR: tracing already started\n");
118
return 0;
119
}
120
trace_data->ingroup = 1;
121
122
tid = CRYPTO_THREAD_get_current_id();
123
hex = OPENSSL_buf2hexstr((const unsigned char *)&tid, sizeof(tid));
124
BIO_snprintf(buffer, sizeof(buffer), "TRACE[%s]:%s: ",
125
hex == NULL ? "<null>" : hex,
126
OSSL_trace_get_category_name(category));
127
OPENSSL_free(hex);
128
BIO_set_prefix(trace_data->bio, buffer);
129
break;
130
case OSSL_TRACE_CTRL_WRITE:
131
if (!trace_data->ingroup) {
132
BIO_printf(bio_err, "ERROR: writing when tracing not started\n");
133
return 0;
134
}
135
136
ret = BIO_write(trace_data->bio, buf, cnt);
137
break;
138
case OSSL_TRACE_CTRL_END:
139
if (!trace_data->ingroup) {
140
BIO_printf(bio_err, "ERROR: finishing when tracing not started\n");
141
return 0;
142
}
143
trace_data->ingroup = 0;
144
145
BIO_set_prefix(trace_data->bio, NULL);
146
147
break;
148
}
149
150
return ret < 0 ? 0 : ret;
151
}
152
153
DEFINE_STACK_OF(tracedata)
154
static STACK_OF(tracedata) *trace_data_stack;
155
156
static void tracedata_free(tracedata *data)
157
{
158
BIO_free_all(data->bio);
159
OPENSSL_free(data);
160
}
161
162
static void cleanup_trace(void)
163
{
164
sk_tracedata_pop_free(trace_data_stack, tracedata_free);
165
}
166
167
static void setup_trace_category(int category)
168
{
169
BIO *channel;
170
tracedata *trace_data;
171
BIO *bio = NULL;
172
173
if (OSSL_trace_enabled(category))
174
return;
175
176
bio = BIO_new(BIO_f_prefix());
177
channel = BIO_push(bio, dup_bio_err(FORMAT_TEXT));
178
trace_data = OPENSSL_zalloc(sizeof(*trace_data));
179
180
if (trace_data == NULL
181
|| bio == NULL
182
|| (trace_data->bio = channel) == NULL
183
|| OSSL_trace_set_callback(category, internal_trace_cb,
184
trace_data)
185
== 0
186
|| sk_tracedata_push(trace_data_stack, trace_data) == 0) {
187
188
fprintf(stderr,
189
"warning: unable to setup trace callback for category '%s'.\n",
190
OSSL_trace_get_category_name(category));
191
192
OSSL_trace_set_callback(category, NULL, NULL);
193
BIO_free_all(channel);
194
}
195
}
196
197
static void setup_trace(const char *str)
198
{
199
char *val;
200
201
/*
202
* We add this handler as early as possible to ensure it's executed
203
* as late as possible, i.e. after the TRACE code has done its cleanup
204
* (which happens last in OPENSSL_cleanup).
205
*/
206
atexit(cleanup_trace);
207
208
trace_data_stack = sk_tracedata_new_null();
209
val = OPENSSL_strdup(str);
210
211
if (val != NULL) {
212
char *valp = val;
213
char *item;
214
215
for (valp = val; (item = strtok(valp, ",")) != NULL; valp = NULL) {
216
int category = OSSL_trace_get_category_num(item);
217
218
if (category == OSSL_TRACE_CATEGORY_ALL) {
219
while (++category < OSSL_TRACE_CATEGORY_NUM)
220
setup_trace_category(category);
221
break;
222
} else if (category > 0) {
223
setup_trace_category(category);
224
} else {
225
fprintf(stderr,
226
"warning: unknown trace category: '%s'.\n", item);
227
}
228
}
229
}
230
231
OPENSSL_free(val);
232
}
233
#endif /* OPENSSL_NO_TRACE */
234
235
static char *help_argv[] = { "help", NULL };
236
static char *version_argv[] = { "version", NULL };
237
238
int main(int argc, char *argv[])
239
{
240
FUNCTION f, *fp;
241
LHASH_OF(FUNCTION) *prog = NULL;
242
char *pname;
243
const char *fname;
244
ARGS arg;
245
int global_help = 0;
246
int global_version = 0;
247
int ret = 0;
248
249
arg.argv = NULL;
250
arg.size = 0;
251
252
/* Set up some of the environment. */
253
bio_in = dup_bio_in(FORMAT_TEXT);
254
bio_out = dup_bio_out(FORMAT_TEXT);
255
bio_err = dup_bio_err(FORMAT_TEXT);
256
257
#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
258
argv = copy_argv(&argc, argv);
259
#elif defined(_WIN32)
260
/* Replace argv[] with UTF-8 encoded strings. */
261
win32_utf8argv(&argc, &argv);
262
#endif
263
264
#ifndef OPENSSL_NO_TRACE
265
setup_trace(getenv("OPENSSL_TRACE"));
266
#endif
267
268
if ((fname = "apps_startup", !apps_startup())
269
|| (fname = "prog_init", (prog = prog_init()) == NULL)) {
270
BIO_printf(bio_err,
271
"FATAL: Startup failure (dev note: %s()) for %s\n",
272
fname, argv[0]);
273
ERR_print_errors(bio_err);
274
ret = 1;
275
goto end;
276
}
277
pname = opt_progname(argv[0]);
278
279
default_config_file = CONF_get1_default_config_file();
280
if (default_config_file == NULL)
281
app_bail_out("%s: could not get default config file\n", pname);
282
283
/* first check the program name */
284
f.name = pname;
285
fp = lh_FUNCTION_retrieve(prog, &f);
286
if (fp == NULL) {
287
/* We assume we've been called as 'openssl ...' */
288
global_help = argc > 1
289
&& (strcmp(argv[1], "-help") == 0 || strcmp(argv[1], "--help") == 0
290
|| strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--h") == 0);
291
global_version = argc > 1
292
&& (strcmp(argv[1], "-version") == 0 || strcmp(argv[1], "--version") == 0
293
|| strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--v") == 0);
294
295
argc--;
296
argv++;
297
opt_appname(argc == 1 || global_help ? "help" : global_version ? "version"
298
: argv[0]);
299
} else {
300
argv[0] = pname;
301
}
302
303
/*
304
* If there's no command, assume "help". If there's an override for help
305
* or version run those, otherwise run the command given.
306
*/
307
ret = (argc == 0) || global_help
308
? do_cmd(prog, 1, help_argv)
309
: global_version
310
? do_cmd(prog, 1, version_argv)
311
: do_cmd(prog, argc, argv);
312
313
end:
314
OPENSSL_free(default_config_file);
315
lh_FUNCTION_free(prog);
316
OPENSSL_free(arg.argv);
317
if (!app_RAND_write())
318
ret = EXIT_FAILURE;
319
320
BIO_free(bio_in);
321
BIO_free_all(bio_out);
322
apps_shutdown();
323
BIO_free_all(bio_err);
324
EXIT(ret);
325
}
326
327
typedef enum HELP_CHOICE {
328
OPT_hERR = -1,
329
OPT_hEOF = 0,
330
OPT_hHELP
331
} HELP_CHOICE;
332
333
const OPTIONS help_options[] = {
334
{ OPT_HELP_STR, 1, '-', "Usage: help [options] [command]\n" },
335
336
OPT_SECTION("General"),
337
{ "help", OPT_hHELP, '-', "Display this summary" },
338
339
OPT_PARAMETERS(),
340
{ "command", 0, 0, "Name of command to display help (optional)" },
341
{ NULL }
342
};
343
344
int help_main(int argc, char **argv)
345
{
346
FUNCTION *fp;
347
int i, nl;
348
FUNC_TYPE tp;
349
char *prog;
350
HELP_CHOICE o;
351
DISPLAY_COLUMNS dc;
352
char *new_argv[3];
353
354
prog = opt_init(argc, argv, help_options);
355
while ((o = opt_next()) != OPT_hEOF) {
356
switch (o) {
357
case OPT_hERR:
358
case OPT_hEOF:
359
BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
360
return 1;
361
case OPT_hHELP:
362
opt_help(help_options);
363
return 0;
364
}
365
}
366
367
/* One optional argument, the command to get help for. */
368
if (opt_num_rest() == 1) {
369
new_argv[0] = opt_rest()[0];
370
new_argv[1] = "--help";
371
new_argv[2] = NULL;
372
return do_cmd(prog_init(), 2, new_argv);
373
}
374
if (!opt_check_rest_arg(NULL)) {
375
BIO_printf(bio_err, "Usage: %s\n", prog);
376
return 1;
377
}
378
379
calculate_columns(functions, &dc);
380
BIO_printf(bio_err, "%s:\n\nStandard commands", prog);
381
i = 0;
382
tp = FT_none;
383
for (fp = functions; fp->name != NULL; fp++) {
384
nl = 0;
385
if (i++ % dc.columns == 0) {
386
BIO_printf(bio_err, "\n");
387
nl = 1;
388
}
389
if (fp->type != tp) {
390
tp = fp->type;
391
if (!nl)
392
BIO_printf(bio_err, "\n");
393
if (tp == FT_md) {
394
i = 1;
395
BIO_printf(bio_err,
396
"\nMessage Digest commands (see the `dgst' command for more details)\n");
397
} else if (tp == FT_cipher) {
398
i = 1;
399
BIO_printf(bio_err,
400
"\nCipher commands (see the `enc' command for more details)\n");
401
}
402
}
403
BIO_printf(bio_err, "%-*s", dc.width, fp->name);
404
}
405
BIO_printf(bio_err, "\n\n");
406
return 0;
407
}
408
409
static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[])
410
{
411
FUNCTION f, *fp;
412
413
if (argc <= 0 || argv[0] == NULL)
414
return 0;
415
memset(&f, 0, sizeof(f));
416
f.name = argv[0];
417
fp = lh_FUNCTION_retrieve(prog, &f);
418
if (fp == NULL) {
419
if (EVP_get_digestbyname(argv[0])) {
420
f.type = FT_md;
421
f.func = dgst_main;
422
fp = &f;
423
} else if (EVP_get_cipherbyname(argv[0])) {
424
f.type = FT_cipher;
425
f.func = enc_main;
426
fp = &f;
427
}
428
}
429
if (fp != NULL) {
430
if (fp->deprecated_alternative != NULL)
431
warn_deprecated(fp);
432
return fp->func(argc, argv);
433
}
434
f.name = argv[0];
435
if (CHECK_AND_SKIP_PREFIX(f.name, "no-")) {
436
/*
437
* User is asking if foo is unsupported, by trying to "run" the
438
* no-foo command. Strange.
439
*/
440
if (lh_FUNCTION_retrieve(prog, &f) == NULL) {
441
BIO_printf(bio_out, "%s\n", argv[0]);
442
return 0;
443
}
444
BIO_printf(bio_out, "%s\n", argv[0] + 3);
445
return 1;
446
}
447
448
BIO_printf(bio_err, "Invalid command '%s'; type \"help\" for a list.\n",
449
argv[0]);
450
return 1;
451
}
452
453
static int function_cmp(const FUNCTION *a, const FUNCTION *b)
454
{
455
return strncmp(a->name, b->name, 8);
456
}
457
458
static unsigned long function_hash(const FUNCTION *a)
459
{
460
return OPENSSL_LH_strhash(a->name);
461
}
462
463
static int SortFnByName(const void *_f1, const void *_f2)
464
{
465
const FUNCTION *f1 = _f1;
466
const FUNCTION *f2 = _f2;
467
468
if (f1->type != f2->type)
469
return f1->type - f2->type;
470
return strcmp(f1->name, f2->name);
471
}
472
473
static LHASH_OF(FUNCTION) *prog_init(void)
474
{
475
static LHASH_OF(FUNCTION) *ret = NULL;
476
static int prog_inited = 0;
477
FUNCTION *f;
478
size_t i;
479
480
if (prog_inited)
481
return ret;
482
483
prog_inited = 1;
484
485
/* Sort alphabetically within category. For nicer help displays. */
486
for (i = 0, f = functions; f->name != NULL; ++f, ++i)
487
;
488
qsort(functions, i, sizeof(*functions), SortFnByName);
489
490
if ((ret = lh_FUNCTION_new(function_hash, function_cmp)) == NULL)
491
return NULL;
492
493
for (f = functions; f->name != NULL; f++)
494
(void)lh_FUNCTION_insert(ret, f);
495
return ret;
496
}
497
498