Maximize time_t when intmax_t is available
authorViktor Dukhovni <openssl-users@dukhovni.org>
Wed, 13 Jan 2016 02:13:34 +0000 (21:13 -0500)
committerViktor Dukhovni <openssl-users@dukhovni.org>
Wed, 13 Jan 2016 02:37:39 +0000 (21:37 -0500)
Well, I'm not actually changing time_t, just changing how time_t
valued opt values are converted from string to time_t.

Reviewed-by: Rich Salz <rsalz@openssl.org>
apps/apps.h
apps/opt.c
include/openssl/ossl_typ.h

index e25965891871ebdc622e8b521647077165205ed4..3ab453bef8ba52b8c895fc2919d8f6fef441c922 100644 (file)
 # include <assert.h>
 
 # include <openssl/e_os2.h>
+# include <openssl/ossl_typ.h>
 # include <openssl/bio.h>
 # include <openssl/x509.h>
 # include <openssl/lhash.h>
@@ -185,7 +186,7 @@ void wait_for_async(SSL *s);
         { "purpose", OPT_V_PURPOSE, 's' }, \
         { "verify_name", OPT_V_VERIFY_NAME, 's' }, \
         { "verify_depth", OPT_V_VERIFY_DEPTH, 'p' }, \
-        { "attime", OPT_V_ATTIME, 'p' }, \
+        { "attime", OPT_V_ATTIME, 'M' }, \
         { "verify_hostname", OPT_V_VERIFY_HOSTNAME, 's' }, \
         { "verify_email", OPT_V_VERIFY_EMAIL, 's' }, \
         { "verify_ip", OPT_V_VERIFY_IP, 's' }, \
@@ -384,6 +385,10 @@ int opt_format(const char *s, unsigned long flags, int *result);
 int opt_int(const char *arg, int *result);
 int opt_ulong(const char *arg, unsigned long *result);
 int opt_long(const char *arg, long *result);
+#if defined(INTMAX_MAX) && defined(UINTMAX_MAX)
+int opt_imax(const char *arg, intmax_t *result);
+int opt_umax(const char *arg, uintmax_t *result);
+#endif
 int opt_pair(const char *arg, const OPT_PAIR * pairs, int *result);
 int opt_cipher(const char *name, const EVP_CIPHER **cipherp);
 int opt_md(const char *name, const EVP_MD **mdp);
index 1bd3965b438c10c05277daba3a83b95eb1449dd5..b814d989b2b6b9822d4caf90ee6ca71635ff241e 100644 (file)
@@ -75,6 +75,11 @@ static const OPTIONS *unknown;
 static const OPTIONS *opts;
 static char prog[40];
 
+#if !defined(INTMAX_MAX) || !defined(UINTMAX_MAX)
+#define opt_imax opt_long
+#define opt_umax opt_ulong
+#endif
+
 /*
  * Return the simple name of the program; removing various platform gunk.
  */
@@ -181,10 +186,13 @@ 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 'F': case 'M':
+        case 'L': case 'U': case 'f': 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) {
@@ -389,6 +397,53 @@ int opt_long(const char *value, long *result)
     return 1;
 }
 
+#if 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.
  */
@@ -422,8 +477,8 @@ enum range { OPT_V_ENUM };
 
 int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
 {
-    long l;
     int i;
+    ossl_intmax_t t = 0;
     ASN1_OBJECT *otmp;
     X509_PURPOSE *xptmp;
     const X509_VERIFY_PARAM *vtmp;
@@ -469,10 +524,14 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
             X509_VERIFY_PARAM_set_depth(vpm, i);
         break;
     case OPT_V_ATTIME:
-        /* If we have C99 we could use intmax_t for all time_t values */
-        opt_long(opt_arg(), &l);
-        if (l)
-            X509_VERIFY_PARAM_set_time(vpm, (time_t)l);
+        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))
@@ -562,7 +621,10 @@ int opt_next(void)
     char *p;
     const OPTIONS *o;
     int ival;
-    unsigned long uval;
+    long lval;
+    unsigned long ulval;
+    ossl_intmax_t imval;
+    ossl_uintmax_t umval;
 
     /* Look at current arg; at end of the list? */
     arg = NULL;
@@ -649,8 +711,32 @@ int opt_next(void)
                 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':
-            if (!opt_ulong(arg, &uval)) {
+            if (!opt_ulong(arg, &ulval)) {
                 BIO_printf(bio_err,
                            "%s: Invalid number \"%s\" for -%s\n",
                            prog, arg, o->name);
index ed7c2a853c289ee998fcecbc029c296920455229..f754136bfe704aafa60220bbedd503d9d1acca97 100644 (file)
@@ -55,6 +55,8 @@
 #ifndef HEADER_OPENSSL_TYPES_H
 # define HEADER_OPENSSL_TYPES_H
 
+#include <limits.h>
+
 #ifdef  __cplusplus
 extern "C" {
 #endif
@@ -199,6 +201,20 @@ typedef struct ocsp_req_ctx_st OCSP_REQ_CTX;
 typedef struct ocsp_response_st OCSP_RESPONSE;
 typedef struct ocsp_responder_id_st OCSP_RESPID;
 
+#if defined(INTMAX_MAX) && defined(UINTMAX_MAX)
+typedef intmax_t ossl_intmax_t;
+typedef uintmax_t ossl_uintmax_t;
+#else
+/*
+ * Not long long, because the C-library can only be expected to provide
+ * strtoll(), strtoull() at the same time as intmax_t and strtoimax(),
+ * strtoumax().  Since we use these for parsing arguments, we need the
+ * conversion functions, not just the sizes.
+ */
+typedef long ossl_intmax_t;
+typedef unsigned long ossl_uintmax_t;
+#endif
+
 #ifdef  __cplusplus
 }
 #endif