Check algo_strength using SSL_STRONG_MASK
[openssl.git] / apps / opt.c
index df2bea5504bbf74bff27b791b005835735e6bcd2..f4eba2dca0ddf4de91ee0005d84db230b16a1497 100644 (file)
 
 /* #define COMPILE_STANDALONE_TEST_DRIVER  */
 #include "apps.h"
-#include <assert.h>
 #include <string.h>
 #if !defined(OPENSSL_SYS_MSDOS)
 # include OPENSSL_UNISTD
 #endif
-#include <unistd.h>
+
 #include <stdlib.h>
 #include <errno.h>
 #include <ctype.h>
+#include <limits.h>
 #include <openssl/bio.h>
 
 #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);