Typo: should check mgf1md
[oweals/openssl.git] / crypto / asn1 / a_utctm.c
index 7916e300ef0509a523b7712d2d2382ca5c4c21b0..5a4b1742f7391bd4108db49a1569685fbc60e860 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -18,18 +18,32 @@ int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
     static const int min[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };
     static const int max[8] = { 99, 12, 31, 23, 59, 59, 12, 59 };
     char *a;
-    int n, i, l, o;
+    int n, i, l, o, min_l = 11, strict = 0;
 
     if (d->type != V_ASN1_UTCTIME)
-        return (0);
+        return 0;
     l = d->length;
     a = (char *)d->data;
     o = 0;
 
-    if (l < 11)
+    /*
+     * ASN1_STRING_FLAG_X509_TIME is used to enforce RFC 5280
+     * time string format, in which:
+     *
+     * 1. "seconds" is a 'MUST'
+     * 2. "Zulu" timezone is a 'MUST'
+     * 3. "+|-" is not allowed to indicate a time zone
+     */
+
+    if (d->flags & ASN1_STRING_FLAG_X509_TIME) {
+        min_l = 13;
+        strict = 1;
+    }
+
+    if (l < min_l)
         goto err;
     for (i = 0; i < 6; i++) {
-        if ((i == 5) && ((a[o] == 'Z') || (a[o] == '+') || (a[o] == '-'))) {
+        if (!strict && (i == 5) && ((a[o] == 'Z') || (a[o] == '+') || (a[o] == '-'))) {
             i++;
             if (tm)
                 tm->tm_sec = 0;
@@ -38,13 +52,15 @@ int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
         if ((a[o] < '0') || (a[o] > '9'))
             goto err;
         n = a[o] - '0';
-        if (++o > l)
+        /* incomplete 2-digital number */
+        if (++o == l)
             goto err;
 
         if ((a[o] < '0') || (a[o] > '9'))
             goto err;
         n = (n * 10) + a[o] - '0';
-        if (++o > l)
+        /* no more bytes to read, but we haven't seen time-zone yet */
+        if (++o == l)
             goto err;
 
         if ((n < min[i]) || (n > max[i]))
@@ -72,12 +88,18 @@ int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
             }
         }
     }
-    if (a[o] == 'Z')
+
+    /*
+     * 'o' will never point to '\0' at this point, the only chance
+     * 'o' can point th '\0' is either the subsequent if or the first
+     * else if is true.
+     */
+    if (a[o] == 'Z') {
         o++;
-    else if ((a[o] == '+') || (a[o] == '-')) {
-        int offsign = a[o] == '-' ? -1 : 1, offset = 0;
+    } else if (!strict && ((a[o] == '+') || (a[o] == '-'))) {
+        int offsign = a[o] == '-' ? 1 : -1, offset = 0;
         o++;
-        if (o + 4 > l)
+        if (o + 4 != l)
             goto err;
         for (i = 6; i < 8; i++) {
             if ((a[o] < '0') || (a[o] > '9'))
@@ -99,6 +121,9 @@ int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
         }
         if (offset && !OPENSSL_gmtime_adj(tm, 0, offset * offsign))
             return 0;
+    } else {
+        /* not Z, or not +/- in non-strict mode */
+        return 0;
     }
     return o == l;
  err:
@@ -117,15 +142,17 @@ int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str)
     t.type = V_ASN1_UTCTIME;
     t.length = strlen(str);
     t.data = (unsigned char *)str;
+    t.flags = 0;
+
     if (ASN1_UTCTIME_check(&t)) {
         if (s != NULL) {
             if (!ASN1_STRING_set((ASN1_STRING *)s, str, t.length))
                 return 0;
             s->type = V_ASN1_UTCTIME;
         }
-        return (1);
-    } else
-        return (0);
+        return 1;
+    }
+    return 0;
 }
 
 ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t)
@@ -139,7 +166,7 @@ ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t,
     char *p;
     struct tm *ts;
     struct tm data;
-    size_t len = 20;
+    const size_t len = 20;
     int free_s = 0;
 
     if (s == NULL) {
@@ -172,15 +199,14 @@ ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t,
         s->data = (unsigned char *)p;
     }
 
-    BIO_snprintf(p, len, "%02d%02d%02d%02d%02d%02dZ", ts->tm_year % 100,
-                 ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min,
-                 ts->tm_sec);
-    s->length = strlen(p);
+    s->length = BIO_snprintf(p, len, "%02d%02d%02d%02d%02d%02dZ",
+                             ts->tm_year % 100, ts->tm_mon + 1, ts->tm_mday,
+                             ts->tm_hour, ts->tm_min, ts->tm_sec);
     s->type = V_ASN1_UTCTIME;
 #ifdef CHARSET_EBCDIC_not
     ebcdic2ascii(s->data, s->data, s->length);
 #endif
-    return (s);
+    return s;
  err:
     if (free_s)
         ASN1_UTCTIME_free(s);
@@ -245,10 +271,9 @@ int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm)
     if (BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s",
                    _asn1_mon[M - 1], d, h, m, s, y + 1900,
                    (gmt) ? " GMT" : "") <= 0)
-        return (0);
-    else
-        return (1);
+        return 0;
+    return 1;
  err:
     BIO_write(bp, "Bad time value", 14);
-    return (0);
+    return 0;
 }