X-Git-Url: https://git.openssl.org/?a=blobdiff_plain;f=apps%2Fopt.c;h=f4eba2dca0ddf4de91ee0005d84db230b16a1497;hb=88a9614ba30e2d1f5b1b14df5814b824190d46f8;hp=df2bea5504bbf74bff27b791b005835735e6bcd2;hpb=88806cfc611935981e3752dccda1685022be2e2b;p=openssl.git diff --git a/apps/opt.c b/apps/opt.c index df2bea5504..f4eba2dca0 100644 --- a/apps/opt.c +++ b/apps/opt.c @@ -49,15 +49,15 @@ /* #define COMPILE_STANDALONE_TEST_DRIVER */ #include "apps.h" -#include #include #if !defined(OPENSSL_SYS_MSDOS) # include OPENSSL_UNISTD #endif -#include + #include #include #include +#include #include #define MAX_OPT_HELP_WIDTH 30 @@ -78,11 +78,10 @@ static char prog[40]; /* * Return the simple name of the program; removing various platform gunk. */ -#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_NETWARE) +#if defined(OPENSSL_SYS_WIN32) char *opt_progname(const char *argv0) { - int i; - int n; + size_t i, n; const char *p; char *q; @@ -96,19 +95,14 @@ char *opt_progname(const char *argv0) /* Strip off trailing nonsense. */ n = strlen(p); if (n > 4 && - (strcmp(&p[n - 4], ".exe") == 0 || strcmp(&p[n - 4], ".EXE") == 0) - n -= 4; -#if defined(OPENSSL_SYS_NETWARE) - if (n > 4 && - (strcmp(&p[n - 4], ".nlm") == 0 || strcmp(&p[n - 4], ".NLM") == 0) + (strcmp(&p[n - 4], ".exe") == 0 || strcmp(&p[n - 4], ".EXE") == 0)) n -= 4; -#endif /* Copy over the name, in lowercase. */ if (n > sizeof prog - 1) n = sizeof prog - 1; for (q = prog, i = 0; i < n; i++, p++) - q++ = isupper(*p) ? tolower(*p) : *p; + *q++ = isupper(*p) ? tolower(*p) : *p; *q = '\0'; return prog; } @@ -129,7 +123,7 @@ char *opt_progname(const char *argv0) q = strrchr(p, '.'); strncpy(prog, p, sizeof prog - 1); prog[sizeof prog - 1] = '\0'; - if (q == NULL || q - p >= sizeof prog) + if (q != NULL && q - p < sizeof prog) prog[q - p] = '\0'; return prog; } @@ -182,10 +176,14 @@ char *opt_init(int ac, char **av, const OPTIONS *o) /* Make sure options are legit. */ assert(o->name[0] != '-'); assert(o->retval > 0); - assert(i == 0 || i == '-' - || i == 'n' || i == 'p' || i == 'u' - || i == 's' || i == '<' || i == '>' || i == '/' - || i == 'f' || i == 'F'); + switch (i) { + case 0: case '-': case '/': case '<': case '>': case 'E': case 'F': + case 'M': case 'U': case 'f': case 'l': case 'n': case 'p': case 's': + case 'u': + break; + default: + assert(0); + } /* Make sure there are no duplicates. */ for (next = o + 1; next->name; ++next) { @@ -257,15 +255,11 @@ int opt_format(const char *s, unsigned long flags, int *result) break; case 'N': case 'n': - if (strcmp(s, "NSS") == 0 || strcmp(s, "nss") == 0) { - if ((flags & OPT_FMT_NSS) == 0) - return opt_format_error(s, flags); - *result = FORMAT_NSS; - } else { - if ((flags & OPT_FMT_NETSCAPE) == 0) - return opt_format_error(s, flags); - *result = FORMAT_NETSCAPE; - } + if ((flags & OPT_FMT_NSS) == 0) + return opt_format_error(s, flags); + if (strcmp(s, "NSS") != 0 && strcmp(s, "nss") != 0) + return opt_format_error(s, flags); + *result = FORMAT_NSS; break; case 'S': case 's': @@ -356,30 +350,16 @@ int opt_pair(const char *name, const OPT_PAIR* pairs, int *result) return 0; } -/* See if cp looks like a hex number, in case user left off the 0x */ -static int scanforhex(const char *cp) -{ - if (*cp == '0' && (cp[1] == 'x' || cp[1] == 'X')) - return 16; - for (; *cp; cp++) - /* Look for a hex digit that isn't a regular digit. */ - if (isxdigit(*cp) && !isdigit(*cp)) - return 16; - return 0; -} - /* Parse an int, put it into *result; return 0 on failure, else 1. */ int opt_int(const char *value, int *result) { - const char *fmt = "%d"; - int base = scanforhex(value); - - if (base == 16) - fmt = "%x"; - else if (*value == '0') - fmt = "%o"; - if (sscanf(value, fmt, result) != 1) { - BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n", + long l; + + if (!opt_long(value, &l)) + return 0; + *result = (int)l; + if (*result != l) { + BIO_printf(bio_err, "%s: Value \"%s\" outside integer range\n", prog, value); return 0; } @@ -389,32 +369,94 @@ int opt_int(const char *value, int *result) /* Parse a long, put it into *result; return 0 on failure, else 1. */ int opt_long(const char *value, long *result) { - char *endptr; - int base = scanforhex(value); + int oerrno = errno; + long l; + char *endp; + + l = strtol(value, &endp, 0); + if (*endp + || endp == value + || ((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE) + || (l == 0 && errno != 0)) { + BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n", + prog, value); + errno = oerrno; + return 0; + } + *result = l; + errno = oerrno; + return 1; +} - *result = strtol(value, &endptr, base); - if (*endptr) { - BIO_printf(bio_err, - "%s: Bad char %c in number %s\n", prog, *endptr, value); +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \ + defined(INTMAX_MAX) && defined(UINTMAX_MAX) + +/* Parse an intmax_t, put it into *result; return 0 on failure, else 1. */ +int opt_imax(const char *value, intmax_t *result) +{ + int oerrno = errno; + intmax_t m; + char *endp; + + m = strtoimax(value, &endp, 0); + if (*endp + || endp == value + || ((m == INTMAX_MAX || m == INTMAX_MIN) && errno == ERANGE) + || (m == 0 && errno != 0)) { + BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n", + prog, value); + errno = oerrno; return 0; } + *result = m; + errno = oerrno; return 1; } +/* Parse a uintmax_t, put it into *result; return 0 on failure, else 1. */ +int opt_umax(const char *value, uintmax_t *result) +{ + int oerrno = errno; + uintmax_t m; + char *endp; + + m = strtoumax(value, &endp, 0); + if (*endp + || endp == value + || (m == UINTMAX_MAX && errno == ERANGE) + || (m == 0 && errno != 0)) { + BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n", + prog, value); + errno = oerrno; + return 0; + } + *result = m; + errno = oerrno; + return 1; +} +#endif + /* * Parse an unsigned long, put it into *result; return 0 on failure, else 1. */ int opt_ulong(const char *value, unsigned long *result) { + int oerrno = errno; char *endptr; - int base = scanforhex(value); - - *result = strtoul(value, &endptr, base); - if (*endptr) { - BIO_printf(bio_err, - "%s: Bad char %c in number %s\n", prog, *endptr, value); + unsigned long l; + + l = strtoul(value, &endptr, 0); + if (*endptr + || endptr == value + || ((l == ULONG_MAX) && errno == ERANGE) + || (l == 0 && errno != 0)) { + BIO_printf(bio_err, "%s: Can't parse \"%s\" as an unsigned number\n", + prog, value); + errno = oerrno; return 0; } + *result = l; + errno = oerrno; return 1; } @@ -427,8 +469,8 @@ enum range { OPT_V_ENUM }; int opt_verify(int opt, X509_VERIFY_PARAM *vpm) { - unsigned long ul; int i; + ossl_intmax_t t = 0; ASN1_OBJECT *otmp; X509_PURPOSE *xptmp; const X509_VERIFY_PARAM *vtmp; @@ -450,14 +492,25 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm) X509_VERIFY_PARAM_add0_policy(vpm, otmp); break; case OPT_V_PURPOSE: + /* purpose name -> purpose index */ i = X509_PURPOSE_get_by_sname(opt_arg()); if (i < 0) { BIO_printf(bio_err, "%s: Invalid purpose %s\n", prog, opt_arg()); return 0; } + + /* purpose index -> purpose object */ xptmp = X509_PURPOSE_get0(i); + + /* purpose object -> purpose value */ i = X509_PURPOSE_get_id(xptmp); - X509_VERIFY_PARAM_set_purpose(vpm, i); + + if (!X509_VERIFY_PARAM_set_purpose(vpm, i)) { + BIO_printf(bio_err, + "%s: Internal error setting purpose %s\n", + prog, opt_arg()); + return 0; + } break; case OPT_V_VERIFY_NAME: vtmp = X509_VERIFY_PARAM_lookup(opt_arg()); @@ -474,9 +527,14 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm) X509_VERIFY_PARAM_set_depth(vpm, i); break; case OPT_V_ATTIME: - opt_ulong(opt_arg(), &ul); - if (ul) - X509_VERIFY_PARAM_set_time(vpm, (time_t)ul); + if (!opt_imax(opt_arg(), &t)) + return 0; + if (t != (time_t)t) { + BIO_printf(bio_err, "%s: epoch time out of range %s\n", + prog, opt_arg()); + return 0; + } + X509_VERIFY_PARAM_set_time(vpm, (time_t)t); break; case OPT_V_VERIFY_HOSTNAME: if (!X509_VERIFY_PARAM_set1_host(vpm, opt_arg(), 0)) @@ -494,7 +552,7 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm) X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_IGNORE_CRITICAL); break; case OPT_V_ISSUER_CHECKS: - X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CB_ISSUER_CHECK); + /* NOP, deprecated */ break; case OPT_V_CRL_CHECK: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CRL_CHECK); @@ -548,6 +606,10 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm) break; case OPT_V_NO_ALT_CHAINS: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_ALT_CHAINS); + break; + case OPT_V_NO_CHECK_TIME: + X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_CHECK_TIME); + break; } return 1; @@ -560,11 +622,12 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm) int opt_next(void) { char *p; - char *endptr; const OPTIONS *o; - int dummy; - int base; - long val; + int ival; + long lval; + unsigned long ulval; + ossl_intmax_t imval; + ossl_uintmax_t umval; /* Look at current arg; at end of the list? */ arg = NULL; @@ -615,10 +678,6 @@ int opt_next(void) } /* Syntax-check value. */ - /* - * Do some basic syntax-checking on the value. These tests aren't - * perfect (ignore range overflow) but they catch common failures. - */ switch (o->valtype) { default: case 's': @@ -647,35 +706,53 @@ int opt_next(void) return -1; case 'p': case 'n': - base = scanforhex(arg); - val = strtol(arg, &endptr, base); - if (*endptr == '\0') { - if (o->valtype == 'p' && val <= 0) { - BIO_printf(bio_err, - "%s: Non-positive number \"%s\" for -%s\n", - prog, arg, o->name); - return -1; - } - break; + if (!opt_int(arg, &ival) + || (o->valtype == 'p' && ival <= 0)) { + BIO_printf(bio_err, + "%s: Non-positive number \"%s\" for -%s\n", + prog, arg, o->name); + return -1; } - BIO_printf(bio_err, - "%s: Invalid number \"%s\" for -%s\n", - prog, arg, o->name); - return -1; + break; + case 'M': + if (!opt_imax(arg, &imval)) { + BIO_printf(bio_err, + "%s: Invalid number \"%s\" for -%s\n", + prog, arg, o->name); + return -1; + } + break; + case 'U': + if (!opt_umax(arg, &umval)) { + BIO_printf(bio_err, + "%s: Invalid number \"%s\" for -%s\n", + prog, arg, o->name); + return -1; + } + break; + case 'l': + if (!opt_long(arg, &lval)) { + BIO_printf(bio_err, + "%s: Invalid number \"%s\" for -%s\n", + prog, arg, o->name); + return -1; + } + break; case 'u': - base = scanforhex(arg); - strtoul(arg, &endptr, base); - if (*endptr == '\0') - break; - BIO_printf(bio_err, - "%s: Invalid number \"%s\" for -%s\n", - prog, arg, o->name); - return -1; - case 'f': + if (!opt_ulong(arg, &ulval)) { + BIO_printf(bio_err, + "%s: Invalid number \"%s\" for -%s\n", + prog, arg, o->name); + return -1; + } + break; + case 'E': case 'F': + case 'f': if (opt_format(arg, + o->valtype == 'E' ? OPT_FMT_PDE : o->valtype == 'F' ? OPT_FMT_PEMDER - : OPT_FMT_ANY, &dummy)) + : OPT_FMT_ANY, &ival)) break; BIO_printf(bio_err, "%s: Invalid format \"%s\" for -%s\n", @@ -733,6 +810,7 @@ int opt_num_rest(void) static const char *valtype2param(const OPTIONS *o) { switch (o->valtype) { + case 0: case '-': return ""; case 's': @@ -744,15 +822,23 @@ static const char *valtype2param(const OPTIONS *o) case '>': return "outfile"; case 'p': - return "pnum"; + return "+int"; case 'n': - return "num"; + return "int"; + case 'l': + return "long"; case 'u': - return "unum"; + return "ulong"; + case 'E': + return "PEM|DER|ENGINE"; case 'F': - return "der/pem"; + return "PEM|DER"; case 'f': return "format"; + case 'M': + return "intmax"; + case 'U': + return "uintmax"; } return "parm"; } @@ -795,7 +881,7 @@ void opt_help(const OPTIONS *list) } /* Pad out prefix */ - memset(start, ' ', sizeof start - 1); + memset(start, ' ', sizeof(start) - 1); start[sizeof start - 1] = '\0'; if (o->name == OPT_MORE_STR) { @@ -821,7 +907,7 @@ void opt_help(const OPTIONS *list) if ((int)(p - start) >= MAX_OPT_HELP_WIDTH) { *p = '\0'; BIO_printf(bio_err, "%s\n", start); - memset(start, ' ', sizeof start); + memset(start, ' ', sizeof(start)); } start[width] = '\0'; BIO_printf(bio_err, "%s %s\n", start, help);