#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
+#include <limits.h>
#include <openssl/bio.h>
#define MAX_OPT_HELP_WIDTH 30
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;
}
/* 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) {
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;
}
/* 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;
+}
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \
+ defined(INTMAX_MAX) && defined(UINTMAX_MAX)
- *result = strtol(value, &endptr, base);
- if (*endptr) {
- BIO_printf(bio_err,
- "%s: Bad char %c in number %s\n", prog, *endptr, value);
+/* 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;
}
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;
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());
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))
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);
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;
}
/* 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':
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",
static const char *valtype2param(const OPTIONS *o)
{
switch (o->valtype) {
+ case 0:
case '-':
return "";
case 's':
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";
}