Validate ASN.1 times according to RFC 5280

Refuse to parse times that are invalid according to RFC 5280, with
a few exceptions for compatibility. This can affect test code that
relies on making and parsing certificates that contain invalid times.

Update-Note: Certificates containing invalid ASN.1 times will no longer parse.

Bug: 491, 427

Change-Id: I2a3fe3a4d359ac662340a225d05b360718eb8c29
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/52665
Commit-Queue: Bob Beck <bbe@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/asn1/a_utctm.c b/crypto/asn1/a_utctm.c
index 21ea2cc..ea984c5 100644
--- a/crypto/asn1/a_utctm.c
+++ b/crypto/asn1/a_utctm.c
@@ -55,106 +55,26 @@
  * [including the GNU Public Licence.] */
 
 #include <openssl/asn1.h>
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
 
 #include <string.h>
 #include <time.h>
 
-#include <openssl/err.h>
-#include <openssl/mem.h>
-
 #include "internal.h"
 
-
 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;
-
-    if (d->type != V_ASN1_UTCTIME)
-        return (0);
-    l = d->length;
-    a = (char *)d->data;
-    o = 0;
-
-    if (l < 11)
-        goto err;
-    for (i = 0; i < 6; i++) {
-        if ((i == 5) && ((a[o] == 'Z') || (a[o] == '+') || (a[o] == '-'))) {
-            i++;
-            if (tm)
-                tm->tm_sec = 0;
-            break;
-        }
-        if ((a[o] < '0') || (a[o] > '9'))
-            goto err;
-        n = a[o] - '0';
-        if (++o > l)
-            goto err;
-
-        if ((a[o] < '0') || (a[o] > '9'))
-            goto err;
-        n = (n * 10) + a[o] - '0';
-        if (++o > l)
-            goto err;
-
-        if ((n < min[i]) || (n > max[i]))
-            goto err;
-        if (tm) {
-            switch (i) {
-            case 0:
-                tm->tm_year = n < 50 ? n + 100 : n;
-                break;
-            case 1:
-                tm->tm_mon = n - 1;
-                break;
-            case 2:
-                tm->tm_mday = n;
-                break;
-            case 3:
-                tm->tm_hour = n;
-                break;
-            case 4:
-                tm->tm_min = n;
-                break;
-            case 5:
-                tm->tm_sec = n;
-                break;
-            }
-        }
+    if (d->type != V_ASN1_UTCTIME) {
+        return 0;
     }
-    if (a[o] == 'Z')
-        o++;
-    else if ((a[o] == '+') || (a[o] == '-')) {
-        int offsign = a[o] == '-' ? 1 : -1, offset = 0;
-        o++;
-        if (o + 4 > l)
-            goto err;
-        for (i = 6; i < 8; i++) {
-            if ((a[o] < '0') || (a[o] > '9'))
-                goto err;
-            n = a[o] - '0';
-            o++;
-            if ((a[o] < '0') || (a[o] > '9'))
-                goto err;
-            n = (n * 10) + a[o] - '0';
-            if ((n < min[i]) || (n > max[i]))
-                goto err;
-            if (tm) {
-                if (i == 6)
-                    offset = n * 3600;
-                else if (i == 7)
-                    offset += n * 60;
-            }
-            o++;
-        }
-        if (offset && !OPENSSL_gmtime_adj(tm, 0, offset * offsign))
-            return 0;
+    CBS cbs;
+    CBS_init(&cbs, d->data, (size_t)d->length);
+    if (!CBS_parse_utc_time(&cbs, tm, /*allow_timezone_offset=*/1)) {
+        return 0;
     }
-    return o == l;
- err:
-    return 0;
+    return 1;
 }
 
 int ASN1_UTCTIME_check(const ASN1_UTCTIME *d)