]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - crypto/asn1/a_time.c
X509: Enable printing cert even with invalid validity times, saying 'Bad time value'
[thirdparty/openssl.git] / crypto / asn1 / a_time.c
index 1babb9636054c627598989fa207bf7525514c331..aebbf53fd075d014d91ee21999101d7e23c25971 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1999-2020 The OpenSSL Project Authors. All Rights Reserved.
  *
- * Licensed under the OpenSSL license (the "License").  You may not use
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
  * in the file LICENSE in the source distribution or at
  * https://www.openssl.org/source/license.html
 
 #include <stdio.h>
 #include <time.h>
-#include "internal/ctype.h"
+#include "crypto/asn1.h"
+#include "crypto/ctype.h"
 #include "internal/cryptlib.h"
 #include <openssl/asn1t.h>
-#include "asn1_locl.h"
+#include "asn1_local.h"
 
 IMPLEMENT_ASN1_MSTRING(ASN1_TIME, B_ASN1_TIME)
 
 IMPLEMENT_ASN1_FUNCTIONS(ASN1_TIME)
+IMPLEMENT_ASN1_DUP_FUNCTION(ASN1_TIME)
 
 static int is_utc(const int year)
 {
@@ -67,7 +69,7 @@ static void determine_days(struct tm *tm)
     }
     c = y / 100;
     y %= 100;
-    /* Zeller's congruance */
+    /* Zeller's congruence */
     tm->tm_wday = (d + (13 * m) / 5 + y + y / 4 + c / 4 + 5 * c + 6) % 7;
 }
 
@@ -79,7 +81,11 @@ int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *d)
     char *a;
     int n, i, i2, l, o, min_l = 11, strict = 0, end = 6, btz = 5, md;
     struct tm tmp;
-
+#if defined(CHARSET_EBCDIC)
+    const char upper_z = 0x5A, num_zero = 0x30, period = 0x2E, minus = 0x2D, plus = 0x2B;
+#else
+    const char upper_z = 'Z', num_zero = '0', period = '.', minus = '-', plus = '+';
+#endif
     /*
      * ASN1_STRING_FLAG_X509_TIME is used to enforce RFC 5280
      * time string format, in which:
@@ -120,20 +126,20 @@ int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *d)
     if (l < min_l)
         goto err;
     for (i = 0; i < end; i++) {
-        if (!strict && (i == btz) && ((a[o] == 'Z') || (a[o] == '+') || (a[o] == '-'))) {
+        if (!strict && (i == btz) && ((a[o] == upper_z) || (a[o] == plus) || (a[o] == minus))) {
             i++;
             break;
         }
-        if (!ossl_isdigit(a[o]))
+        if (!ascii_isdigit(a[o]))
             goto err;
-        n = a[o] - '0';
+        n = a[o] - num_zero;
         /* incomplete 2-digital number */
         if (++o == l)
             goto err;
 
-        if (!ossl_isdigit(a[o]))
+        if (!ascii_isdigit(a[o]))
             goto err;
-        n = (n * 10) + a[o] - '0';
+        n = (n * 10) + a[o] - num_zero;
         /* no more bytes to read, but we haven't seen time-zone yet */
         if (++o == l)
             goto err;
@@ -185,14 +191,14 @@ int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *d)
      * Optional fractional seconds: decimal point followed by one or more
      * digits.
      */
-    if (d->type == V_ASN1_GENERALIZEDTIME && a[o] == '.') {
+    if (d->type == V_ASN1_GENERALIZEDTIME && a[o] == period) {
         if (strict)
             /* RFC 5280 forbids fractional seconds */
             goto err;
         if (++o == l)
             goto err;
         i = o;
-        while ((o < l) && ossl_isdigit(a[o]))
+        while ((o < l) && ascii_isdigit(a[o]))
             o++;
         /* Must have at least one digit after decimal point */
         if (i == o)
@@ -207,10 +213,10 @@ int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *d)
      * 'o' can point to '\0' is either the subsequent if or the first
      * else if is true.
      */
-    if (a[o] == 'Z') {
+    if (a[o] == upper_z) {
         o++;
-    } else if (!strict && ((a[o] == '+') || (a[o] == '-'))) {
-        int offsign = a[o] == '-' ? 1 : -1;
+    } else if (!strict && ((a[o] == plus) || (a[o] == minus))) {
+        int offsign = a[o] == minus ? 1 : -1;
         int offset = 0;
 
         o++;
@@ -223,13 +229,13 @@ int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *d)
         if (o + 4 != l)
             goto err;
         for (i = end; i < end + 2; i++) {
-            if (!ossl_isdigit(a[o]))
+            if (!ascii_isdigit(a[o]))
                 goto err;
-            n = a[o] - '0';
+            n = a[o] - num_zero;
             o++;
-            if (!ossl_isdigit(a[o]))
+            if (!ascii_isdigit(a[o]))
                 goto err;
-            n = (n * 10) + a[o] - '0';
+            n = (n * 10) + a[o] - num_zero;
             i2 = (d->type == V_ASN1_UTCTIME) ? i + 1 : i;
             if ((n < min[i2]) || (n > max[i2]))
                 goto err;
@@ -300,7 +306,7 @@ ASN1_TIME *asn1_time_from_tm(ASN1_TIME *s, struct tm *ts, int type)
                                     ts->tm_mday, ts->tm_hour, ts->tm_min,
                                     ts->tm_sec);
 
-#ifdef CHARSET_EBCDIC_not
+#ifdef CHARSET_EBCDIC
     ebcdic2ascii(tmps->data, tmps->data, tmps->length);
 #endif
     return tmps;
@@ -323,7 +329,7 @@ ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, time_t t,
 
     ts = OPENSSL_gmtime(&t, &data);
     if (ts == NULL) {
-        ASN1err(ASN1_F_ASN1_TIME_ADJ, ASN1_R_ERROR_GETTING_TIME);
+        ERR_raise(ERR_LIB_ASN1, ASN1_R_ERROR_GETTING_TIME);
         return NULL;
     }
     if (offset_day || offset_sec) {
@@ -462,20 +468,27 @@ static const char _asn1_mon[12][4] = {
     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
 };
 
+/* returns 1 on success, 0 on BIO write error or parse failure */
 int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm)
+{
+    return asn1_time_print_ex(bp, tm) > 0;
+}
+
+/* returns 0 on BIO write error, else -1 in case of parse failure, else 1 */
+int asn1_time_print_ex(BIO *bp, const ASN1_TIME *tm)
 {
     char *v;
     int gmt = 0, l;
     struct tm stm;
+    const char upper_z = 0x5A, period = 0x2E;
 
-    if (!asn1_time_to_tm(&stm, tm)) {
-        /* asn1_time_to_tm will check the time type */
-        goto err;
-    }
+    /* asn1_time_to_tm will check the time type */
+    if (!asn1_time_to_tm(&stm, tm))
+        return BIO_write(bp, "Bad time value", 14) ? -1 : 0;
 
     l = tm->length;
     v = (char *)tm->data;
-    if (v[l - 1] == 'Z')
+    if (v[l - 1] == upper_z)
         gmt = 1;
 
     if (tm->type == V_ASN1_GENERALIZEDTIME) {
@@ -486,10 +499,10 @@ int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm)
          * Try to parse fractional seconds. '14' is the place of
          * 'fraction point' in a GeneralizedTime string.
          */
-        if (tm->length > 15 && v[14] == '.') {
+        if (tm->length > 15 && v[14] == period) {
             f = &v[14];
             f_len = 1;
-            while (14 + f_len < l && ossl_isdigit(f[f_len]))
+            while (14 + f_len < l && ascii_isdigit(f[f_len]))
                 ++f_len;
         }
 
@@ -503,9 +516,6 @@ int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm)
                           stm.tm_min, stm.tm_sec, stm.tm_year + 1900,
                           (gmt ? " GMT" : "")) > 0;
     }
- err:
-    BIO_write(bp, "Bad time value", 14);
-    return 0;
 }
 
 int ASN1_TIME_cmp_time_t(const ASN1_TIME *s, time_t t)