Fix up some integer types in crypto/asn1

tag and utype are always accessed as int, so make the structs match.
Boolean ASN1_ITEMs put an ASN1_BOOLEAN in it->size, so add a cast. Also
fix the time set_string functions to call the underlying CBS parser
directly, so they don't need to put a strlen into an int.

Bug: 516
Change-Id: Ie10e7eaf58ec0b0dec59813a0ddcb0197fce1fd1
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/55449
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: Bob Beck <bbe@google.com>
diff --git a/crypto/asn1/a_gentm.c b/crypto/asn1/a_gentm.c
index 283ff7d..0104af0 100644
--- a/crypto/asn1/a_gentm.c
+++ b/crypto/asn1/a_gentm.c
@@ -81,22 +81,16 @@
 }
 
 int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str) {
-  ASN1_GENERALIZEDTIME t;
-
-  t.type = V_ASN1_GENERALIZEDTIME;
-  t.length = strlen(str);
-  t.data = (unsigned char *)str;
-  if (ASN1_GENERALIZEDTIME_check(&t)) {
-    if (s != NULL) {
-      if (!ASN1_STRING_set((ASN1_STRING *)s, (unsigned char *)str, t.length)) {
-        return 0;
-      }
-      s->type = V_ASN1_GENERALIZEDTIME;
-    }
-    return 1;
-  } else {
+  size_t len = strlen(str);
+  CBS cbs;
+  CBS_init(&cbs, (const uint8_t *)str, len);
+  if (!CBS_parse_generalized_time(&cbs, /*out_tm=*/NULL,
+                                  /*allow_timezone_offset=*/0) ||
+      !ASN1_STRING_set(s, str, len)) {
     return 0;
   }
+  s->type = V_ASN1_GENERALIZEDTIME;
+  return 1;
 }
 
 ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s,
diff --git a/crypto/asn1/a_object.c b/crypto/asn1/a_object.c
index c854fb8..8c420c6 100644
--- a/crypto/asn1/a_object.c
+++ b/crypto/asn1/a_object.c
@@ -107,8 +107,12 @@
 }
 
 static int write_str(BIO *bp, const char *str) {
-  int len = strlen(str);
-  return BIO_write(bp, str, len) == len ? len : -1;
+  size_t len = strlen(str);
+  if (len > INT_MAX) {
+    OPENSSL_PUT_ERROR(ASN1, ERR_R_OVERFLOW);
+    return -1;
+  }
+  return BIO_write(bp, str, (int)len) == (int)len ? (int)len : -1;
 }
 
 int i2a_ASN1_OBJECT(BIO *bp, const ASN1_OBJECT *a) {
diff --git a/crypto/asn1/a_strex.c b/crypto/asn1/a_strex.c
index c996acc..229de94 100644
--- a/crypto/asn1/a_strex.c
+++ b/crypto/asn1/a_strex.c
@@ -121,7 +121,7 @@
     return maybe_write(out, &u8, 1) ? 1 : -1;
   }
 
-  int len = strlen(buf);
+  int len = (int)strlen(buf);  // |buf| is guaranteed to be short.
   return maybe_write(out, buf, len) ? len : -1;
 }
 
diff --git a/crypto/asn1/a_time.c b/crypto/asn1/a_time.c
index 39b54a6..643584b 100644
--- a/crypto/asn1/a_time.c
+++ b/crypto/asn1/a_time.c
@@ -164,28 +164,9 @@
   return NULL;
 }
 
-
 int ASN1_TIME_set_string(ASN1_TIME *s, const char *str) {
-  ASN1_TIME t;
-
-  t.length = strlen(str);
-  t.data = (unsigned char *)str;
-  t.flags = 0;
-
-  t.type = V_ASN1_UTCTIME;
-
-  if (!ASN1_TIME_check(&t)) {
-    t.type = V_ASN1_GENERALIZEDTIME;
-    if (!ASN1_TIME_check(&t)) {
-      return 0;
-    }
-  }
-
-  if (s && !ASN1_STRING_copy((ASN1_STRING *)s, (ASN1_STRING *)&t)) {
-    return 0;
-  }
-
-  return 1;
+  return ASN1_UTCTIME_set_string(s, str) ||
+         ASN1_GENERALIZEDTIME_set_string(s, str);
 }
 
 static int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *t,
diff --git a/crypto/asn1/a_utctm.c b/crypto/asn1/a_utctm.c
index 201c654..bf09c90 100644
--- a/crypto/asn1/a_utctm.c
+++ b/crypto/asn1/a_utctm.c
@@ -82,22 +82,16 @@
 }
 
 int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str) {
-  ASN1_UTCTIME t;
-
-  t.type = V_ASN1_UTCTIME;
-  t.length = strlen(str);
-  t.data = (unsigned char *)str;
-  if (ASN1_UTCTIME_check(&t)) {
-    if (s != NULL) {
-      if (!ASN1_STRING_set((ASN1_STRING *)s, (unsigned char *)str, t.length)) {
-        return 0;
-      }
-      s->type = V_ASN1_UTCTIME;
-    }
-    return 1;
-  } else {
+  size_t len = strlen(str);
+  CBS cbs;
+  CBS_init(&cbs, (const uint8_t *)str, len);
+  if (!CBS_parse_utc_time(&cbs, /*out_tm=*/NULL,
+                          /*allow_timezone_offset=*/1) ||
+      !ASN1_STRING_set(s, str, len)) {
     return 0;
   }
+  s->type = V_ASN1_UTCTIME;
+  return 1;
 }
 
 ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t) {
diff --git a/crypto/asn1/asn1_test.cc b/crypto/asn1/asn1_test.cc
index 3182a85..fc17f40 100644
--- a/crypto/asn1/asn1_test.cc
+++ b/crypto/asn1/asn1_test.cc
@@ -1048,6 +1048,34 @@
   }
 }
 
+TEST(ASN1Test, TimeSetString) {
+  bssl::UniquePtr<ASN1_STRING> s(ASN1_STRING_new());
+  ASSERT_TRUE(s);
+
+  ASSERT_TRUE(ASN1_UTCTIME_set_string(s.get(), "700101000000Z"));
+  EXPECT_EQ(V_ASN1_UTCTIME, ASN1_STRING_type(s.get()));
+  EXPECT_EQ("700101000000Z", ASN1StringToStdString(s.get()));
+
+  ASSERT_TRUE(ASN1_GENERALIZEDTIME_set_string(s.get(), "19700101000000Z"));
+  EXPECT_EQ(V_ASN1_GENERALIZEDTIME, ASN1_STRING_type(s.get()));
+  EXPECT_EQ("19700101000000Z", ASN1StringToStdString(s.get()));
+
+  // |ASN1_TIME_set_string| accepts either format. It relies on there being no
+  // overlap between the two.
+  ASSERT_TRUE(ASN1_TIME_set_string(s.get(), "700101000000Z"));
+  EXPECT_EQ(V_ASN1_UTCTIME, ASN1_STRING_type(s.get()));
+  EXPECT_EQ("700101000000Z", ASN1StringToStdString(s.get()));
+
+  ASSERT_TRUE(ASN1_TIME_set_string(s.get(), "19700101000000Z"));
+  EXPECT_EQ(V_ASN1_GENERALIZEDTIME, ASN1_STRING_type(s.get()));
+  EXPECT_EQ("19700101000000Z", ASN1StringToStdString(s.get()));
+
+  // Invalid inputs are rejected.
+  EXPECT_FALSE(ASN1_UTCTIME_set_string(s.get(), "nope"));
+  EXPECT_FALSE(ASN1_GENERALIZEDTIME_set_string(s.get(), "nope"));
+  EXPECT_FALSE(ASN1_TIME_set_string(s.get(), "nope"));
+}
+
 TEST(ASN1Test, AdjTime) {
   struct tm tm1, tm2;
   int days, secs;
diff --git a/crypto/asn1/tasn_fre.c b/crypto/asn1/tasn_fre.c
index 3da1fa6..82c0a0c 100644
--- a/crypto/asn1/tasn_fre.c
+++ b/crypto/asn1/tasn_fre.c
@@ -218,7 +218,7 @@
 
     case V_ASN1_BOOLEAN:
       if (it) {
-        *(ASN1_BOOLEAN *)pval = it->size;
+        *(ASN1_BOOLEAN *)pval = (ASN1_BOOLEAN)it->size;
       } else {
         *(ASN1_BOOLEAN *)pval = -1;
       }
diff --git a/crypto/asn1/tasn_new.c b/crypto/asn1/tasn_new.c
index 97411c5..563674d 100644
--- a/crypto/asn1/tasn_new.c
+++ b/crypto/asn1/tasn_new.c
@@ -273,9 +273,6 @@
 // all the old functions.
 
 static int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it) {
-  ASN1_TYPE *typ;
-  int utype;
-
   if (!it) {
     return 0;
   }
@@ -284,6 +281,7 @@
   // |ASN1_PRIMITIVE_FUNCS| table of calbacks.
   assert(it->funcs == NULL);
 
+  int utype;
   if (it->itype == ASN1_ITYPE_MSTRING) {
     utype = -1;
   } else {
@@ -295,15 +293,15 @@
       return 1;
 
     case V_ASN1_BOOLEAN:
-      *(ASN1_BOOLEAN *)pval = it->size;
+      *(ASN1_BOOLEAN *)pval = (ASN1_BOOLEAN)it->size;
       return 1;
 
     case V_ASN1_NULL:
       *pval = (ASN1_VALUE *)1;
       return 1;
 
-    case V_ASN1_ANY:
-      typ = OPENSSL_malloc(sizeof(ASN1_TYPE));
+    case V_ASN1_ANY: {
+      ASN1_TYPE *typ = OPENSSL_malloc(sizeof(ASN1_TYPE));
       if (!typ) {
         return 0;
       }
@@ -311,6 +309,7 @@
       typ->type = -1;
       *pval = (ASN1_VALUE *)typ;
       break;
+    }
 
     default:
       *pval = (ASN1_VALUE *)ASN1_STRING_type_new(utype);
@@ -333,7 +332,7 @@
     utype = it->utype;
   }
   if (utype == V_ASN1_BOOLEAN) {
-    *(ASN1_BOOLEAN *)pval = it->size;
+    *(ASN1_BOOLEAN *)pval = (ASN1_BOOLEAN)it->size;
   } else {
     *pval = NULL;
   }
diff --git a/include/openssl/asn1t.h b/include/openssl/asn1t.h
index b32fe34..324eb57 100644
--- a/include/openssl/asn1t.h
+++ b/include/openssl/asn1t.h
@@ -349,7 +349,7 @@
 
 struct ASN1_TEMPLATE_st {
 uint32_t flags;		/* Various flags */
-long tag;			/* tag, not used if no tagging */
+int tag;			/* tag, not used if no tagging */
 unsigned long offset;		/* Offset of this field in structure */
 const char *field_name;		/* Field name */
 ASN1_ITEM_EXP *item;		/* Relevant ASN1_ITEM or ASN1_ADB */
@@ -455,7 +455,7 @@
 
 struct ASN1_ITEM_st {
 char itype;			/* The item type, primitive, SEQUENCE, CHOICE or extern */
-long utype;			/* underlying type */
+int utype;			/* underlying type */
 const ASN1_TEMPLATE *templates;	/* If SEQUENCE or CHOICE this contains the contents */
 long tcount;			/* Number of templates if SEQUENCE or CHOICE */
 const void *funcs;		/* functions that handle this type */