1/*
2 * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the OpenSSL license (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#include "apps.h"
10#include <string.h>
11#if !defined(OPENSSL_SYS_MSDOS)
12# include OPENSSL_UNISTD
13#endif
14
15#include <stdlib.h>
16#include <errno.h>
17#include <ctype.h>
18#include <limits.h>
19#include <openssl/bio.h>
20#include <openssl/x509v3.h>
21
22#define MAX_OPT_HELP_WIDTH 30
23const char OPT_HELP_STR[] = "--";
24const char OPT_MORE_STR[] = "---";
25
26/* Our state */
27static char **argv;
28static int argc;
29static int opt_index;
30static char *arg;
31static char *flag;
32static char *dunno;
33static const OPTIONS *unknown;
34static const OPTIONS *opts;
35static char prog[40];
36
37/*
38 * Return the simple name of the program; removing various platform gunk.
39 */
40#if defined(OPENSSL_SYS_WIN32)
41char *opt_progname(const char *argv0)
42{
43    size_t i, n;
44    const char *p;
45    char *q;
46
47    /* find the last '/', '\' or ':' */
48    for (p = argv0 + strlen(argv0); --p > argv0;)
49        if (*p == '/' || *p == '\\' || *p == ':') {
50            p++;
51            break;
52        }
53
54    /* Strip off trailing nonsense. */
55    n = strlen(p);
56    if (n > 4 &&
57        (strcmp(&p[n - 4], ".exe") == 0 || strcmp(&p[n - 4], ".EXE") == 0))
58        n -= 4;
59
60    /* Copy over the name, in lowercase. */
61    if (n > sizeof(prog) - 1)
62        n = sizeof(prog) - 1;
63    for (q = prog, i = 0; i < n; i++, p++)
64        *q++ = tolower((unsigned char)*p);
65    *q = '\0';
66    return prog;
67}
68
69#elif defined(OPENSSL_SYS_VMS)
70
71char *opt_progname(const char *argv0)
72{
73    const char *p, *q;
74
75    /* Find last special character sys:[foo.bar]openssl */
76    for (p = argv0 + strlen(argv0); --p > argv0;)
77        if (*p == ':' || *p == ']' || *p == '>') {
78            p++;
79            break;
80        }
81
82    q = strrchr(p, '.');
83    strncpy(prog, p, sizeof(prog) - 1);
84    prog[sizeof(prog) - 1] = '\0';
85    if (q != NULL && q - p < sizeof(prog))
86        prog[q - p] = '\0';
87    return prog;
88}
89
90#else
91
92char *opt_progname(const char *argv0)
93{
94    const char *p;
95
96    /* Could use strchr, but this is like the ones above. */
97    for (p = argv0 + strlen(argv0); --p > argv0;)
98        if (*p == '/') {
99            p++;
100            break;
101        }
102    strncpy(prog, p, sizeof(prog) - 1);
103    prog[sizeof(prog) - 1] = '\0';
104    return prog;
105}
106#endif
107
108char *opt_getprog(void)
109{
110    return prog;
111}
112
113/* Set up the arg parsing. */
114char *opt_init(int ac, char **av, const OPTIONS *o)
115{
116    /* Store state. */
117    argc = ac;
118    argv = av;
119    opt_index = 1;
120    opts = o;
121    opt_progname(av[0]);
122    unknown = NULL;
123
124    for (; o->name; ++o) {
125#ifndef NDEBUG
126        const OPTIONS *next;
127        int duplicated, i;
128#endif
129
130        if (o->name == OPT_HELP_STR || o->name == OPT_MORE_STR)
131            continue;
132#ifndef NDEBUG
133        i = o->valtype;
134
135        /* Make sure options are legit. */
136        assert(o->name[0] != '-');
137        assert(o->retval > 0);
138        switch (i) {
139        case   0: case '-': case '/': case '<': case '>': case 'E': case 'F':
140        case 'M': case 'U': case 'f': case 'l': case 'n': case 'p': case 's':
141        case 'u': case 'c':
142            break;
143        default:
144            assert(0);
145        }
146
147        /* Make sure there are no duplicates. */
148        for (next = o + 1; next->name; ++next) {
149            /*
150             * Some compilers inline strcmp and the assert string is too long.
151             */
152            duplicated = strcmp(o->name, next->name) == 0;
153            assert(!duplicated);
154        }
155#endif
156        if (o->name[0] == '\0') {
157            assert(unknown == NULL);
158            unknown = o;
159            assert(unknown->valtype == 0 || unknown->valtype == '-');
160        }
161    }
162    return prog;
163}
164
165static OPT_PAIR formats[] = {
166    {"PEM/DER", OPT_FMT_PEMDER},
167    {"pkcs12", OPT_FMT_PKCS12},
168    {"smime", OPT_FMT_SMIME},
169    {"engine", OPT_FMT_ENGINE},
170    {"msblob", OPT_FMT_MSBLOB},
171    {"nss", OPT_FMT_NSS},
172    {"text", OPT_FMT_TEXT},
173    {"http", OPT_FMT_HTTP},
174    {"pvk", OPT_FMT_PVK},
175    {NULL}
176};
177
178/* Print an error message about a failed format parse. */
179int opt_format_error(const char *s, unsigned long flags)
180{
181    OPT_PAIR *ap;
182
183    if (flags == OPT_FMT_PEMDER) {
184        BIO_printf(bio_err, "%s: Bad format \"%s\"; must be pem or der\n",
185                   prog, s);
186    } else {
187        BIO_printf(bio_err, "%s: Bad format \"%s\"; must be one of:\n",
188                   prog, s);
189        for (ap = formats; ap->name; ap++)
190            if (flags & ap->retval)
191                BIO_printf(bio_err, "   %s\n", ap->name);
192    }
193    return 0;
194}
195
196/* Parse a format string, put it into *result; return 0 on failure, else 1. */
197int opt_format(const char *s, unsigned long flags, int *result)
198{
199    switch (*s) {
200    default:
201        return 0;
202    case 'D':
203    case 'd':
204        if ((flags & OPT_FMT_PEMDER) == 0)
205            return opt_format_error(s, flags);
206        *result = FORMAT_ASN1;
207        break;
208    case 'T':
209    case 't':
210        if ((flags & OPT_FMT_TEXT) == 0)
211            return opt_format_error(s, flags);
212        *result = FORMAT_TEXT;
213        break;
214    case 'N':
215    case 'n':
216        if ((flags & OPT_FMT_NSS) == 0)
217            return opt_format_error(s, flags);
218        if (strcmp(s, "NSS") != 0 && strcmp(s, "nss") != 0)
219            return opt_format_error(s, flags);
220        *result = FORMAT_NSS;
221        break;
222    case 'S':
223    case 's':
224        if ((flags & OPT_FMT_SMIME) == 0)
225            return opt_format_error(s, flags);
226        *result = FORMAT_SMIME;
227        break;
228    case 'M':
229    case 'm':
230        if ((flags & OPT_FMT_MSBLOB) == 0)
231            return opt_format_error(s, flags);
232        *result = FORMAT_MSBLOB;
233        break;
234    case 'E':
235    case 'e':
236        if ((flags & OPT_FMT_ENGINE) == 0)
237            return opt_format_error(s, flags);
238        *result = FORMAT_ENGINE;
239        break;
240    case 'H':
241    case 'h':
242        if ((flags & OPT_FMT_HTTP) == 0)
243            return opt_format_error(s, flags);
244        *result = FORMAT_HTTP;
245        break;
246    case '1':
247        if ((flags & OPT_FMT_PKCS12) == 0)
248            return opt_format_error(s, flags);
249        *result = FORMAT_PKCS12;
250        break;
251    case 'P':
252    case 'p':
253        if (s[1] == '\0' || strcmp(s, "PEM") == 0 || strcmp(s, "pem") == 0) {
254            if ((flags & OPT_FMT_PEMDER) == 0)
255                return opt_format_error(s, flags);
256            *result = FORMAT_PEM;
257        } else if (strcmp(s, "PVK") == 0 || strcmp(s, "pvk") == 0) {
258            if ((flags & OPT_FMT_PVK) == 0)
259                return opt_format_error(s, flags);
260            *result = FORMAT_PVK;
261        } else if (strcmp(s, "P12") == 0 || strcmp(s, "p12") == 0
262                   || strcmp(s, "PKCS12") == 0 || strcmp(s, "pkcs12") == 0) {
263            if ((flags & OPT_FMT_PKCS12) == 0)
264                return opt_format_error(s, flags);
265            *result = FORMAT_PKCS12;
266        } else {
267            return 0;
268        }
269        break;
270    }
271    return 1;
272}
273
274/* Parse a cipher name, put it in *EVP_CIPHER; return 0 on failure, else 1. */
275int opt_cipher(const char *name, const EVP_CIPHER **cipherp)
276{
277    *cipherp = EVP_get_cipherbyname(name);
278    if (*cipherp != NULL)
279        return 1;
280    BIO_printf(bio_err, "%s: Unrecognized flag %s\n", prog, name);
281    return 0;
282}
283
284/*
285 * Parse message digest name, put it in *EVP_MD; return 0 on failure, else 1.
286 */
287int opt_md(const char *name, const EVP_MD **mdp)
288{
289    *mdp = EVP_get_digestbyname(name);
290    if (*mdp != NULL)
291        return 1;
292    BIO_printf(bio_err, "%s: Unrecognized flag %s\n", prog, name);
293    return 0;
294}
295
296/* Look through a list of name/value pairs. */
297int opt_pair(const char *name, const OPT_PAIR* pairs, int *result)
298{
299    const OPT_PAIR *pp;
300
301    for (pp = pairs; pp->name; pp++)
302        if (strcmp(pp->name, name) == 0) {
303            *result = pp->retval;
304            return 1;
305        }
306    BIO_printf(bio_err, "%s: Value must be one of:\n", prog);
307    for (pp = pairs; pp->name; pp++)
308        BIO_printf(bio_err, "\t%s\n", pp->name);
309    return 0;
310}
311
312/* Parse an int, put it into *result; return 0 on failure, else 1. */
313int opt_int(const char *value, int *result)
314{
315    long l;
316
317    if (!opt_long(value, &l))
318        return 0;
319    *result = (int)l;
320    if (*result != l) {
321        BIO_printf(bio_err, "%s: Value \"%s\" outside integer range\n",
322                   prog, value);
323        return 0;
324    }
325    return 1;
326}
327
328static void opt_number_error(const char *v)
329{
330    size_t i = 0;
331    struct strstr_pair_st {
332        char *prefix;
333        char *name;
334    } b[] = {
335        {"0x", "a hexadecimal"},
336        {"0X", "a hexadecimal"},
337        {"0", "an octal"}
338    };
339
340    for (i = 0; i < OSSL_NELEM(b); i++) {
341        if (strncmp(v, b[i].prefix, strlen(b[i].prefix)) == 0) {
342            BIO_printf(bio_err,
343                       "%s: Can't parse \"%s\" as %s number\n",
344                       prog, v, b[i].name);
345            return;
346        }
347    }
348    BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n", prog, v);
349    return;
350}
351
352/* Parse a long, put it into *result; return 0 on failure, else 1. */
353int opt_long(const char *value, long *result)
354{
355    int oerrno = errno;
356    long l;
357    char *endp;
358
359    errno = 0;
360    l = strtol(value, &endp, 0);
361    if (*endp
362            || endp == value
363            || ((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE)
364            || (l == 0 && errno != 0)) {
365        opt_number_error(value);
366        errno = oerrno;
367        return 0;
368    }
369    *result = l;
370    errno = oerrno;
371    return 1;
372}
373
374#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \
375    defined(INTMAX_MAX) && defined(UINTMAX_MAX)
376
377/* Parse an intmax_t, put it into *result; return 0 on failure, else 1. */
378int opt_imax(const char *value, intmax_t *result)
379{
380    int oerrno = errno;
381    intmax_t m;
382    char *endp;
383
384    errno = 0;
385    m = strtoimax(value, &endp, 0);
386    if (*endp
387            || endp == value
388            || ((m == INTMAX_MAX || m == INTMAX_MIN) && errno == ERANGE)
389            || (m == 0 && errno != 0)) {
390        opt_number_error(value);
391        errno = oerrno;
392        return 0;
393    }
394    *result = m;
395    errno = oerrno;
396    return 1;
397}
398
399/* Parse a uintmax_t, put it into *result; return 0 on failure, else 1. */
400int opt_umax(const char *value, uintmax_t *result)
401{
402    int oerrno = errno;
403    uintmax_t m;
404    char *endp;
405
406    errno = 0;
407    m = strtoumax(value, &endp, 0);
408    if (*endp
409            || endp == value
410            || (m == UINTMAX_MAX && errno == ERANGE)
411            || (m == 0 && errno != 0)) {
412        opt_number_error(value);
413        errno = oerrno;
414        return 0;
415    }
416    *result = m;
417    errno = oerrno;
418    return 1;
419}
420#endif
421
422/*
423 * Parse an unsigned long, put it into *result; return 0 on failure, else 1.
424 */
425int opt_ulong(const char *value, unsigned long *result)
426{
427    int oerrno = errno;
428    char *endptr;
429    unsigned long l;
430
431    errno = 0;
432    l = strtoul(value, &endptr, 0);
433    if (*endptr
434            || endptr == value
435            || ((l == ULONG_MAX) && errno == ERANGE)
436            || (l == 0 && errno != 0)) {
437        opt_number_error(value);
438        errno = oerrno;
439        return 0;
440    }
441    *result = l;
442    errno = oerrno;
443    return 1;
444}
445
446/*
447 * We pass opt as an int but cast it to "enum range" so that all the
448 * items in the OPT_V_ENUM enumeration are caught; this makes -Wswitch
449 * in gcc do the right thing.
450 */
451enum range { OPT_V_ENUM };
452
453int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
454{
455    int i;
456    ossl_intmax_t t = 0;
457    ASN1_OBJECT *otmp;
458    X509_PURPOSE *xptmp;
459    const X509_VERIFY_PARAM *vtmp;
460
461    assert(vpm != NULL);
462    assert(opt > OPT_V__FIRST);
463    assert(opt < OPT_V__LAST);
464
465    switch ((enum range)opt) {
466    case OPT_V__FIRST:
467    case OPT_V__LAST:
468        return 0;
469    case OPT_V_POLICY:
470        otmp = OBJ_txt2obj(opt_arg(), 0);
471        if (otmp == NULL) {
472            BIO_printf(bio_err, "%s: Invalid Policy %s\n", prog, opt_arg());
473            return 0;
474        }
475        X509_VERIFY_PARAM_add0_policy(vpm, otmp);
476        break;
477    case OPT_V_PURPOSE:
478        /* purpose name -> purpose index */
479        i = X509_PURPOSE_get_by_sname(opt_arg());
480        if (i < 0) {
481            BIO_printf(bio_err, "%s: Invalid purpose %s\n", prog, opt_arg());
482            return 0;
483        }
484
485        /* purpose index -> purpose object */
486        xptmp = X509_PURPOSE_get0(i);
487
488        /* purpose object -> purpose value */
489        i = X509_PURPOSE_get_id(xptmp);
490
491        if (!X509_VERIFY_PARAM_set_purpose(vpm, i)) {
492            BIO_printf(bio_err,
493                       "%s: Internal error setting purpose %s\n",
494                       prog, opt_arg());
495            return 0;
496        }
497        break;
498    case OPT_V_VERIFY_NAME:
499        vtmp = X509_VERIFY_PARAM_lookup(opt_arg());
500        if (vtmp == NULL) {
501            BIO_printf(bio_err, "%s: Invalid verify name %s\n",
502                       prog, opt_arg());
503            return 0;
504        }
505        X509_VERIFY_PARAM_set1(vpm, vtmp);
506        break;
507    case OPT_V_VERIFY_DEPTH:
508        i = atoi(opt_arg());
509        if (i >= 0)
510            X509_VERIFY_PARAM_set_depth(vpm, i);
511        break;
512    case OPT_V_VERIFY_AUTH_LEVEL:
513        i = atoi(opt_arg());
514        if (i >= 0)
515            X509_VERIFY_PARAM_set_auth_level(vpm, i);
516        break;
517    case OPT_V_ATTIME:
518        if (!opt_imax(opt_arg(), &t))
519            return 0;
520        if (t != (time_t)t) {
521            BIO_printf(bio_err, "%s: epoch time out of range %s\n",
522                       prog, opt_arg());
523            return 0;
524        }
525        X509_VERIFY_PARAM_set_time(vpm, (time_t)t);
526        break;
527    case OPT_V_VERIFY_HOSTNAME:
528        if (!X509_VERIFY_PARAM_set1_host(vpm, opt_arg(), 0))
529            return 0;
530        break;
531    case OPT_V_VERIFY_EMAIL:
532        if (!X509_VERIFY_PARAM_set1_email(vpm, opt_arg(), 0))
533            return 0;
534        break;
535    case OPT_V_VERIFY_IP:
536        if (!X509_VERIFY_PARAM_set1_ip_asc(vpm, opt_arg()))
537            return 0;
538        break;
539    case OPT_V_IGNORE_CRITICAL:
540        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_IGNORE_CRITICAL);
541        break;
542    case OPT_V_ISSUER_CHECKS:
543        /* NOP, deprecated */
544        break;
545    case OPT_V_CRL_CHECK:
546        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CRL_CHECK);
547        break;
548    case OPT_V_CRL_CHECK_ALL:
549        X509_VERIFY_PARAM_set_flags(vpm,
550                                    X509_V_FLAG_CRL_CHECK |
551                                    X509_V_FLAG_CRL_CHECK_ALL);
552        break;
553    case OPT_V_POLICY_CHECK:
554        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_POLICY_CHECK);
555        break;
556    case OPT_V_EXPLICIT_POLICY:
557        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXPLICIT_POLICY);
558        break;
559    case OPT_V_INHIBIT_ANY:
560        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_ANY);
561        break;
562    case OPT_V_INHIBIT_MAP:
563        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_MAP);
564        break;
565    case OPT_V_X509_STRICT:
566        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_X509_STRICT);
567        break;
568    case OPT_V_EXTENDED_CRL:
569        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXTENDED_CRL_SUPPORT);
570        break;
571    case OPT_V_USE_DELTAS:
572        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_USE_DELTAS);
573        break;
574    case OPT_V_POLICY_PRINT:
575        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NOTIFY_POLICY);
576        break;
577    case OPT_V_CHECK_SS_SIG:
578        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CHECK_SS_SIGNATURE);
579        break;
580    case OPT_V_TRUSTED_FIRST:
581        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_TRUSTED_FIRST);
582        break;
583    case OPT_V_SUITEB_128_ONLY:
584        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS_ONLY);
585        break;
586    case OPT_V_SUITEB_128:
587        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS);
588        break;
589    case OPT_V_SUITEB_192:
590        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_192_LOS);
591        break;
592    case OPT_V_PARTIAL_CHAIN:
593        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_PARTIAL_CHAIN);
594        break;
595    case OPT_V_NO_ALT_CHAINS:
596        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_ALT_CHAINS);
597        break;
598    case OPT_V_NO_CHECK_TIME:
599        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_CHECK_TIME);
600        break;
601    case OPT_V_ALLOW_PROXY_CERTS:
602        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_ALLOW_PROXY_CERTS);
603        break;
604    }
605    return 1;
606
607}
608
609/*
610 * Parse the next flag (and value if specified), return 0 if done, -1 on
611 * error, otherwise the flag's retval.
612 */
613int opt_next(void)
614{
615    char *p;
616    const OPTIONS *o;
617    int ival;
618    long lval;
619    unsigned long ulval;
620    ossl_intmax_t imval;
621    ossl_uintmax_t umval;
622
623    /* Look at current arg; at end of the list? */
624    arg = NULL;
625    p = argv[opt_index];
626    if (p == NULL)
627        return 0;
628
629    /* If word doesn't start with a -, we're done. */
630    if (*p != '-')
631        return 0;
632
633    /* Hit "--" ? We're done. */
634    opt_index++;
635    if (strcmp(p, "--") == 0)
636        return 0;
637
638    /* Allow -nnn and --nnn */
639    if (*++p == '-')
640        p++;
641    flag = p - 1;
642
643    /* If we have --flag=foo, snip it off */
644    if ((arg = strchr(p, '=')) != NULL)
645        *arg++ = '\0';
646    for (o = opts; o->name; ++o) {
647        /* If not this option, move on to the next one. */
648        if (strcmp(p, o->name) != 0)
649            continue;
650
651        /* If it doesn't take a value, make sure none was given. */
652        if (o->valtype == 0 || o->valtype == '-') {
653            if (arg) {
654                BIO_printf(bio_err,
655                           "%s: Option -%s does not take a value\n", prog, p);
656                return -1;
657            }
658            return o->retval;
659        }
660
661        /* Want a value; get the next param if =foo not used. */
662        if (arg == NULL) {
663            if (argv[opt_index] == NULL) {
664                BIO_printf(bio_err,
665                           "%s: Option -%s needs a value\n", prog, o->name);
666                return -1;
667            }
668            arg = argv[opt_index++];
669        }
670
671        /* Syntax-check value. */
672        switch (o->valtype) {
673        default:
674        case 's':
675            /* Just a string. */
676            break;
677        case '/':
678            if (app_isdir(arg) > 0)
679                break;
680            BIO_printf(bio_err, "%s: Not a directory: %s\n", prog, arg);
681            return -1;
682        case '<':
683            /* Input file. */
684            break;
685        case '>':
686            /* Output file. */
687            break;
688        case 'p':
689        case 'n':
690            if (!opt_int(arg, &ival)
691                    || (o->valtype == 'p' && ival <= 0)) {
692                BIO_printf(bio_err,
693                           "%s: Non-positive number \"%s\" for -%s\n",
694                           prog, arg, o->name);
695                return -1;
696            }
697            break;
698        case 'M':
699            if (!opt_imax(arg, &imval)) {
700                BIO_printf(bio_err,
701                           "%s: Invalid number \"%s\" for -%s\n",
702                           prog, arg, o->name);
703                return -1;
704            }
705            break;
706        case 'U':
707            if (!opt_umax(arg, &umval)) {
708                BIO_printf(bio_err,
709                           "%s: Invalid number \"%s\" for -%s\n",
710                           prog, arg, o->name);
711                return -1;
712            }
713            break;
714        case 'l':
715            if (!opt_long(arg, &lval)) {
716                BIO_printf(bio_err,
717                           "%s: Invalid number \"%s\" for -%s\n",
718                           prog, arg, o->name);
719                return -1;
720            }
721            break;
722        case 'u':
723            if (!opt_ulong(arg, &ulval)) {
724                BIO_printf(bio_err,
725                           "%s: Invalid number \"%s\" for -%s\n",
726                           prog, arg, o->name);
727                return -1;
728            }
729            break;
730        case 'c':
731        case 'E':
732        case 'F':
733        case 'f':
734            if (opt_format(arg,
735                           o->valtype == 'c' ? OPT_FMT_PDS :
736                           o->valtype == 'E' ? OPT_FMT_PDE :
737                           o->valtype == 'F' ? OPT_FMT_PEMDER
738                           : OPT_FMT_ANY, &ival))
739                break;
740            BIO_printf(bio_err,
741                       "%s: Invalid format \"%s\" for -%s\n",
742                       prog, arg, o->name);
743            return -1;
744        }
745
746        /* Return the flag value. */
747        return o->retval;
748    }
749    if (unknown != NULL) {
750        dunno = p;
751        return unknown->retval;
752    }
753    BIO_printf(bio_err, "%s: Option unknown option -%s\n", prog, p);
754    return -1;
755}
756
757/* Return the most recent flag parameter. */
758char *opt_arg(void)
759{
760    return arg;
761}
762
763/* Return the most recent flag. */
764char *opt_flag(void)
765{
766    return flag;
767}
768
769/* Return the unknown option. */
770char *opt_unknown(void)
771{
772    return dunno;
773}
774
775/* Return the rest of the arguments after parsing flags. */
776char **opt_rest(void)
777{
778    return &argv[opt_index];
779}
780
781/* How many items in remaining args? */
782int opt_num_rest(void)
783{
784    int i = 0;
785    char **pp;
786
787    for (pp = opt_rest(); *pp; pp++, i++)
788        continue;
789    return i;
790}
791
792/* Return a string describing the parameter type. */
793static const char *valtype2param(const OPTIONS *o)
794{
795    switch (o->valtype) {
796    case 0:
797    case '-':
798        return "";
799    case 's':
800        return "val";
801    case '/':
802        return "dir";
803    case '<':
804        return "infile";
805    case '>':
806        return "outfile";
807    case 'p':
808        return "+int";
809    case 'n':
810        return "int";
811    case 'l':
812        return "long";
813    case 'u':
814        return "ulong";
815    case 'E':
816        return "PEM|DER|ENGINE";
817    case 'F':
818        return "PEM|DER";
819    case 'f':
820        return "format";
821    case 'M':
822        return "intmax";
823    case 'U':
824        return "uintmax";
825    }
826    return "parm";
827}
828
829void opt_help(const OPTIONS *list)
830{
831    const OPTIONS *o;
832    int i;
833    int standard_prolog;
834    int width = 5;
835    char start[80 + 1];
836    char *p;
837    const char *help;
838
839    /* Starts with its own help message? */
840    standard_prolog = list[0].name != OPT_HELP_STR;
841
842    /* Find the widest help. */
843    for (o = list; o->name; o++) {
844        if (o->name == OPT_MORE_STR)
845            continue;
846        i = 2 + (int)strlen(o->name);
847        if (o->valtype != '-')
848            i += 1 + strlen(valtype2param(o));
849        if (i < MAX_OPT_HELP_WIDTH && i > width)
850            width = i;
851        assert(i < (int)sizeof(start));
852    }
853
854    if (standard_prolog)
855        BIO_printf(bio_err, "Usage: %s [options]\nValid options are:\n",
856                   prog);
857
858    /* Now let's print. */
859    for (o = list; o->name; o++) {
860        help = o->helpstr ? o->helpstr : "(No additional info)";
861        if (o->name == OPT_HELP_STR) {
862            BIO_printf(bio_err, help, prog);
863            continue;
864        }
865
866        /* Pad out prefix */
867        memset(start, ' ', sizeof(start) - 1);
868        start[sizeof(start) - 1] = '\0';
869
870        if (o->name == OPT_MORE_STR) {
871            /* Continuation of previous line; pad and print. */
872            start[width] = '\0';
873            BIO_printf(bio_err, "%s  %s\n", start, help);
874            continue;
875        }
876
877        /* Build up the "-flag [param]" part. */
878        p = start;
879        *p++ = ' ';
880        *p++ = '-';
881        if (o->name[0])
882            p += strlen(strcpy(p, o->name));
883        else
884            *p++ = '*';
885        if (o->valtype != '-') {
886            *p++ = ' ';
887            p += strlen(strcpy(p, valtype2param(o)));
888        }
889        *p = ' ';
890        if ((int)(p - start) >= MAX_OPT_HELP_WIDTH) {
891            *p = '\0';
892            BIO_printf(bio_err, "%s\n", start);
893            memset(start, ' ', sizeof(start));
894        }
895        start[width] = '\0';
896        BIO_printf(bio_err, "%s  %s\n", start, help);
897    }
898}
899