Add a function for Conscrypt to use

That will convert nonstandard times to posix times.

Change-Id: I7c09a8d4175ee372ab9f3453e02628c303686888
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/75167
Commit-Queue: Bob Beck <bbe@google.com>
Auto-Submit: Bob Beck <bbe@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/asn1/a_time.cc b/crypto/asn1/a_time.cc
index 6ab5d93..563bf22 100644
--- a/crypto/asn1/a_time.cc
+++ b/crypto/asn1/a_time.cc
@@ -186,6 +186,14 @@
   return OPENSSL_gmtime_diff(out_days, out_seconds, &tm_from, &tm_to);
 }
 
+int ASN1_TIME_to_posix_nonstandard(const ASN1_TIME *t, int64_t *out_time) {
+  struct tm tm;
+  if (!asn1_time_to_tm(&tm, t, /*allow_timezone_offset=*/1)) {
+    return 0;
+  }
+  return OPENSSL_tm_to_posix(&tm, out_time);
+}
+
 // The functions below do *not* permissively allow the use of four digit
 // timezone offsets in UTC times, as is done elsewhere in the code. They are
 // both new API, and used internally to X509_cmp_time. This is to discourage the
diff --git a/crypto/asn1/asn1_test.cc b/crypto/asn1/asn1_test.cc
index 79cbead..870de38 100644
--- a/crypto/asn1/asn1_test.cc
+++ b/crypto/asn1/asn1_test.cc
@@ -1185,6 +1185,11 @@
   // behind the epoch.
   EXPECT_EQ(ASN1_UTCTIME_cmp_time_t(s.get(), (4 * 60 * 60 * -1)), 0);
 
+  int64_t posix_time;
+  EXPECT_FALSE(ASN1_TIME_to_posix(s.get(), &posix_time));
+  ASSERT_TRUE(ASN1_TIME_to_posix_nonstandard(s.get(), &posix_time));
+  EXPECT_EQ(posix_time, (4 * 60 * 60 * -1));
+
   // Conscrypt expects a utc time with an arbitrary offset to be
   // accepted by ASN1_TIME_to_generalizedtime.
   bssl::UniquePtr<ASN1_STRING> g(
diff --git a/include/openssl/asn1.h b/include/openssl/asn1.h
index 0abef05..57cdf6c 100644
--- a/include/openssl/asn1.h
+++ b/include/openssl/asn1.h
@@ -1326,14 +1326,22 @@
 OPENSSL_EXPORT int ASN1_TIME_set_string_X509(ASN1_TIME *s, const char *str);
 
 // ASN1_TIME_to_time_t converts |t| to a time_t value in |out|. On
-// success, one is returned. On failure zero is returned. This function
+// success, one is returned. On failure, zero is returned. This function
 // will fail if the time can not be represented in a time_t.
 OPENSSL_EXPORT int ASN1_TIME_to_time_t(const ASN1_TIME *t, time_t *out);
 
 // ASN1_TIME_to_posix converts |t| to a POSIX time value in |out|. On
-// success, one is returned. On failure zero is returned.
+// success, one is returned. On failure, zero is returned.
 OPENSSL_EXPORT int ASN1_TIME_to_posix(const ASN1_TIME *t, int64_t *out);
 
+// ASN1_TIME_to_posix_nonstandard converts |t| to a POSIX time value in
+// |out|. It is exactly the same as |ASN1_TIME_to_posix| but allows for
+// non-standard four-digit timezone offsets on UTC times. On success, one is
+// returned. On failure, zero is returned. |ASN1_TIME_to_posix| should normally
+// be used instead of this function.
+OPENSSL_EXPORT int ASN1_TIME_to_posix_nonstandard(
+    const ASN1_TIME *t, int64_t *out);
+
 // TODO(davidben): Expand and document function prototypes generated in macros.