Get rid of time_t usage internally, change to int64_t

We still keep time_t stuff around for calling time() and
for external interfaces that are meant to give you time_t
values, but we stop using time_t internally. For publicly
exposed and used inputs that rely on time_t, _posix versions are
added to support providing times as an int64_t, and internal
use is changed to use the _posix version.

Several legacy functions which are extensivly used and
and use pointers to time_t are retained for compatibility,
along with posix time versions of them which we use exclusively.

This fixes the tests which were disabled on 32 bit platorms
to always run.

Update-Note: This is a potentially breaking change for things
that bind to the ASN1_[UTC|GENERALIZED]TIME_set and ASN1_TIME_adj
family of functions (and can not type convert a time_t to an
int64).

Bug: 416

Change-Id: Ic4daba5a299d8f35191853742640750a1ecc53d6
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/54765
Commit-Queue: Bob Beck <bbe@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/asn1/a_gentm.c b/crypto/asn1/a_gentm.c
index 096e912..ff1f97c 100644
--- a/crypto/asn1/a_gentm.c
+++ b/crypto/asn1/a_gentm.c
@@ -58,6 +58,7 @@
 #include <openssl/bytestring.h>
 #include <openssl/err.h>
 #include <openssl/mem.h>
+#include <openssl/time.h>
 
 #include <string.h>
 #include <time.h>
@@ -98,15 +99,15 @@
 }
 
 ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s,
-                                               time_t t) {
-  return ASN1_GENERALIZEDTIME_adj(s, t, 0, 0);
+                                               int64_t posix_time) {
+  return ASN1_GENERALIZEDTIME_adj(s, posix_time, 0, 0);
 }
 
 ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s,
-                                               time_t t, int offset_day,
+                                               int64_t posix_time, int offset_day,
                                                long offset_sec) {
   struct tm data;
-  if (!OPENSSL_gmtime(&t, &data)) {
+  if (!OPENSSL_posix_to_tm(posix_time, &data)) {
     return NULL;
   }
 
diff --git a/crypto/asn1/a_time.c b/crypto/asn1/a_time.c
index 643584b..87bf092 100644
--- a/crypto/asn1/a_time.c
+++ b/crypto/asn1/a_time.c
@@ -74,29 +74,31 @@
 
 IMPLEMENT_ASN1_FUNCTIONS_const(ASN1_TIME)
 
-ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t) {
-  return ASN1_TIME_adj(s, t, 0, 0);
+ASN1_TIME *ASN1_TIME_set_posix(ASN1_TIME *s, int64_t posix_time) {
+  return ASN1_TIME_adj(s, posix_time, 0, 0);
 }
 
-ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, time_t t, int offset_day,
-                         long offset_sec) {
-  struct tm *ts;
-  struct tm data;
+ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t time) {
+  return ASN1_TIME_adj(s, time, 0, 0);
+}
 
-  ts = OPENSSL_gmtime(&t, &data);
-  if (ts == NULL) {
+ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, int64_t posix_time, int offset_day,
+                         long offset_sec) {
+  struct tm tm;
+
+  if (!OPENSSL_posix_to_tm(posix_time, &tm)) {
     OPENSSL_PUT_ERROR(ASN1, ASN1_R_ERROR_GETTING_TIME);
     return NULL;
   }
   if (offset_day || offset_sec) {
-    if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec)) {
+    if (!OPENSSL_gmtime_adj(&tm, offset_day, offset_sec)) {
       return NULL;
     }
   }
-  if ((ts->tm_year >= 50) && (ts->tm_year < 150)) {
-    return ASN1_UTCTIME_adj(s, t, offset_day, offset_sec);
+  if ((tm.tm_year >= 50) && (tm.tm_year < 150)) {
+    return ASN1_UTCTIME_adj(s, posix_time, offset_day, offset_sec);
   }
-  return ASN1_GENERALIZEDTIME_adj(s, t, offset_day, offset_sec);
+  return ASN1_GENERALIZEDTIME_adj(s, posix_time, offset_day, offset_sec);
 }
 
 int ASN1_TIME_check(const ASN1_TIME *t) {
@@ -172,9 +174,7 @@
 static int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *t,
                            int allow_timezone_offset) {
   if (t == NULL) {
-    time_t now_t;
-    time(&now_t);
-    if (OPENSSL_gmtime(&now_t, tm)) {
+    if (OPENSSL_posix_to_tm(time(NULL), tm)) {
       return 1;
     }
     return 0;
diff --git a/crypto/asn1/a_utctm.c b/crypto/asn1/a_utctm.c
index d8d26ff..45c4081 100644
--- a/crypto/asn1/a_utctm.c
+++ b/crypto/asn1/a_utctm.c
@@ -58,6 +58,7 @@
 #include <openssl/bytestring.h>
 #include <openssl/err.h>
 #include <openssl/mem.h>
+#include <openssl/time.h>
 
 #include <string.h>
 #include <time.h>
@@ -98,14 +99,14 @@
   return 1;
 }
 
-ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t) {
-  return ASN1_UTCTIME_adj(s, t, 0, 0);
+ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, int64_t posix_time) {
+  return ASN1_UTCTIME_adj(s, posix_time, 0, 0);
 }
 
-ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, int offset_day,
+ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, int64_t posix_time, int offset_day,
                                long offset_sec) {
   struct tm data;
-  if (!OPENSSL_gmtime(&t, &data)) {
+  if (!OPENSSL_posix_to_tm(posix_time, &data)) {
     return NULL;
   }
 
@@ -151,7 +152,7 @@
     return -2;
   }
 
-  if (!OPENSSL_gmtime(&t, &ttm)) {
+  if (!OPENSSL_posix_to_tm(t, &ttm)) {
     return -2;
   }
 
diff --git a/crypto/asn1/asn1_test.cc b/crypto/asn1/asn1_test.cc
index 3bb7b34..47d2356 100644
--- a/crypto/asn1/asn1_test.cc
+++ b/crypto/asn1/asn1_test.cc
@@ -922,7 +922,7 @@
                      ASN1_STRING_get0_data(str) + ASN1_STRING_length(str));
 }
 
-static bool ASN1Time_check_time_t(const ASN1_TIME *s, time_t t) {
+static bool ASN1Time_check_posix(const ASN1_TIME *s, int64_t t) {
   struct tm stm, ttm;
   int day, sec;
 
@@ -940,7 +940,7 @@
     default:
       return false;
   }
-  if (!OPENSSL_gmtime(&t, &ttm) ||
+  if (!OPENSSL_posix_to_tm(t, &ttm) ||
       !OPENSSL_gmtime_diff(&day, &sec, &ttm, &stm)) {
     return false;
   }
@@ -964,37 +964,35 @@
 
 TEST(ASN1Test, SetTime) {
   static const struct {
-    time_t time;
+    int64_t time;
     const char *generalized;
     const char *utc;
     const char *printed;
   } kTests[] = {
-    {-631152001, "19491231235959Z", nullptr, "Dec 31 23:59:59 1949 GMT"},
-    {-631152000, "19500101000000Z", "500101000000Z",
-     "Jan  1 00:00:00 1950 GMT"},
-    {0, "19700101000000Z", "700101000000Z", "Jan  1 00:00:00 1970 GMT"},
-    {981173106, "20010203040506Z", "010203040506Z", "Feb  3 04:05:06 2001 GMT"},
-    {951804000, "20000229060000Z", "000229060000Z", "Feb 29 06:00:00 2000 GMT"},
-    // NASA says this is the correct time for posterity.
-    {-16751025, "19690621025615Z", "690621025615Z", "Jun 21 02:56:15 1969 GMT"},
-    // -1 is sometimes used as an error value. Ensure we correctly handle it.
-    {-1, "19691231235959Z", "691231235959Z", "Dec 31 23:59:59 1969 GMT"},
-#if defined(OPENSSL_64_BIT)
-    // TODO(https://crbug.com/boringssl/416): These cases overflow 32-bit
-    // |time_t| and do not consistently work on 32-bit platforms. For now,
-    // disable the tests on 32-bit. Re-enable them once the bug is fixed.
-    {2524607999, "20491231235959Z", "491231235959Z",
-     "Dec 31 23:59:59 2049 GMT"},
-    {2524608000, "20500101000000Z", nullptr, "Jan  1 00:00:00 2050 GMT"},
-    // Test boundary conditions.
-    {-62167219200, "00000101000000Z", nullptr, "Jan  1 00:00:00 0 GMT"},
-    {-62167219201, nullptr, nullptr, nullptr},
-    {253402300799, "99991231235959Z", nullptr, "Dec 31 23:59:59 9999 GMT"},
-    {253402300800, nullptr, nullptr, nullptr},
-#endif
+      {-631152001, "19491231235959Z", nullptr, "Dec 31 23:59:59 1949 GMT"},
+      {-631152000, "19500101000000Z", "500101000000Z",
+       "Jan  1 00:00:00 1950 GMT"},
+      {0, "19700101000000Z", "700101000000Z", "Jan  1 00:00:00 1970 GMT"},
+      {981173106, "20010203040506Z", "010203040506Z",
+       "Feb  3 04:05:06 2001 GMT"},
+      {951804000, "20000229060000Z", "000229060000Z",
+       "Feb 29 06:00:00 2000 GMT"},
+      // NASA says this is the correct time for posterity.
+      {-16751025, "19690621025615Z", "690621025615Z",
+       "Jun 21 02:56:15 1969 GMT"},
+      // -1 is sometimes used as an error value. Ensure we correctly handle it.
+      {-1, "19691231235959Z", "691231235959Z", "Dec 31 23:59:59 1969 GMT"},
+      {2524607999, "20491231235959Z", "491231235959Z",
+       "Dec 31 23:59:59 2049 GMT"},
+      {2524608000, "20500101000000Z", nullptr, "Jan  1 00:00:00 2050 GMT"},
+      // Test boundary conditions.
+      {-62167219200, "00000101000000Z", nullptr, "Jan  1 00:00:00 0 GMT"},
+      {-62167219201, nullptr, nullptr, nullptr},
+      {253402300799, "99991231235959Z", nullptr, "Dec 31 23:59:59 9999 GMT"},
+      {253402300800, nullptr, nullptr, nullptr},
   };
   for (const auto &t : kTests) {
-    time_t tt;
+    int64_t tt;
     SCOPED_TRACE(t.time);
 
     bssl::UniquePtr<ASN1_UTCTIME> utc(ASN1_UTCTIME_set(nullptr, t.time));
@@ -1002,8 +1000,8 @@
       ASSERT_TRUE(utc);
       EXPECT_EQ(V_ASN1_UTCTIME, ASN1_STRING_type(utc.get()));
       EXPECT_EQ(t.utc, ASN1StringToStdString(utc.get()));
-      EXPECT_TRUE(ASN1Time_check_time_t(utc.get(), t.time));
-      EXPECT_EQ(ASN1_TIME_to_time_t(utc.get(), &tt), 1);
+      EXPECT_TRUE(ASN1Time_check_posix(utc.get(), t.time));
+      EXPECT_EQ(ASN1_TIME_to_posix(utc.get(), &tt), 1);
       EXPECT_EQ(tt, t.time);
       EXPECT_EQ(PrintStringToBIO(utc.get(), &ASN1_UTCTIME_print), t.printed);
       EXPECT_EQ(PrintStringToBIO(utc.get(), &ASN1_TIME_print), t.printed);
@@ -1017,8 +1015,8 @@
       ASSERT_TRUE(generalized);
       EXPECT_EQ(V_ASN1_GENERALIZEDTIME, ASN1_STRING_type(generalized.get()));
       EXPECT_EQ(t.generalized, ASN1StringToStdString(generalized.get()));
-      EXPECT_TRUE(ASN1Time_check_time_t(generalized.get(), t.time));
-      EXPECT_EQ(ASN1_TIME_to_time_t(generalized.get(), &tt), 1);
+      EXPECT_TRUE(ASN1Time_check_posix(generalized.get(), t.time));
+      EXPECT_EQ(ASN1_TIME_to_posix(generalized.get(), &tt), 1);
       EXPECT_EQ(tt, t.time);
       EXPECT_EQ(
           PrintStringToBIO(generalized.get(), &ASN1_GENERALIZEDTIME_print),
@@ -1029,7 +1027,7 @@
       EXPECT_FALSE(generalized);
     }
 
-    bssl::UniquePtr<ASN1_TIME> choice(ASN1_TIME_set(nullptr, t.time));
+    bssl::UniquePtr<ASN1_TIME> choice(ASN1_TIME_set_posix(nullptr, t.time));
     if (t.generalized) {
       ASSERT_TRUE(choice);
       if (t.utc) {
@@ -1039,8 +1037,8 @@
         EXPECT_EQ(V_ASN1_GENERALIZEDTIME, ASN1_STRING_type(choice.get()));
         EXPECT_EQ(t.generalized, ASN1StringToStdString(choice.get()));
       }
-      EXPECT_TRUE(ASN1Time_check_time_t(choice.get(), t.time));
-      EXPECT_EQ(ASN1_TIME_to_time_t(choice.get(), &tt), 1);
+      EXPECT_TRUE(ASN1Time_check_posix(choice.get(), t.time));
+      EXPECT_EQ(ASN1_TIME_to_posix(choice.get(), &tt), 1);
       EXPECT_EQ(tt, t.time);
     } else {
       EXPECT_FALSE(choice);
diff --git a/crypto/x509/internal.h b/crypto/x509/internal.h
index 6c594ec..407dcd7 100644
--- a/crypto/x509/internal.h
+++ b/crypto/x509/internal.h
@@ -228,7 +228,7 @@
 
 struct X509_VERIFY_PARAM_st {
   char *name;
-  time_t check_time;                // Time to use
+  int64_t check_time;               // POSIX time to use
   unsigned long inh_flags;          // Inheritance flags
   unsigned long flags;              // Various verify flags
   int purpose;                      // purpose to check untrusted certificates
diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc
index 0e681aa..96c80b3 100644
--- a/crypto/x509/x509_test.cc
+++ b/crypto/x509/x509_test.cc
@@ -1099,7 +1099,7 @@
   return stack;
 }
 
-static const time_t kReferenceTime = 1474934400 /* Sep 27th, 2016 */;
+static const int64_t kReferenceTime = 1474934400 /* Sep 27th, 2016 */;
 
 static int Verify(
     X509 *leaf, const std::vector<X509 *> &roots,
@@ -1133,7 +1133,7 @@
   X509_STORE_CTX_set0_crls(ctx.get(), crls_stack.get());
 
   X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(ctx.get());
-  X509_VERIFY_PARAM_set_time(param, kReferenceTime);
+  X509_VERIFY_PARAM_set_time_posix(param, kReferenceTime);
   if (configure_callback) {
     configure_callback(param);
   }
@@ -1484,7 +1484,7 @@
   EXPECT_EQ(X509_V_ERR_CRL_HAS_EXPIRED,
             Verify(leaf.get(), {root.get()}, {root.get()}, {basic_crl.get()},
                    X509_V_FLAG_CRL_CHECK, [](X509_VERIFY_PARAM *param) {
-                     X509_VERIFY_PARAM_set_time(
+                     X509_VERIFY_PARAM_set_time_posix(
                          param, kReferenceTime + 2 * 30 * 24 * 3600);
                    }));
 
@@ -1493,7 +1493,7 @@
             Verify(leaf.get(), {root.get()}, {root.get()}, {basic_crl.get()},
                    X509_V_FLAG_CRL_CHECK | X509_V_FLAG_NO_CHECK_TIME,
                    [](X509_VERIFY_PARAM *param) {
-                     X509_VERIFY_PARAM_set_time(
+                     X509_VERIFY_PARAM_set_time_posix(
                          param, kReferenceTime + 2 * 30 * 24 * 3600);
                    }));
 
@@ -2096,7 +2096,7 @@
         ASSERT_TRUE(X509_CRL_set_version(crl.get(), X509_CRL_VERSION_2));
         bssl::UniquePtr<ASN1_TIME> last_update(ASN1_TIME_new());
         ASSERT_TRUE(last_update);
-        ASSERT_TRUE(ASN1_TIME_set(last_update.get(), kReferenceTime));
+        ASSERT_TRUE(ASN1_TIME_set_posix(last_update.get(), kReferenceTime));
         ASSERT_TRUE(X509_CRL_set1_lastUpdate(crl.get(), last_update.get()));
         bssl::UniquePtr<X509_NAME> issuer(X509_NAME_new());
         ASSERT_TRUE(issuer);
@@ -3979,13 +3979,13 @@
   // The following are measured in seconds relative to kReferenceTime. The
   // validity periods are staggered so we can independently test both leaf and
   // root time checks.
-  const time_t kSecondsInDay = 24 * 3600;
-  const time_t kRootStart = -30 * kSecondsInDay;
-  const time_t kIntermediateStart = -20 * kSecondsInDay;
-  const time_t kLeafStart = -10 * kSecondsInDay;
-  const time_t kIntermediateEnd = 10 * kSecondsInDay;
-  const time_t kLeafEnd = 20 * kSecondsInDay;
-  const time_t kRootEnd = 30 * kSecondsInDay;
+  const int64_t kSecondsInDay = 24 * 3600;
+  const int64_t kRootStart = -30 * kSecondsInDay;
+  const int64_t kIntermediateStart = -20 * kSecondsInDay;
+  const int64_t kLeafStart = -10 * kSecondsInDay;
+  const int64_t kIntermediateEnd = 10 * kSecondsInDay;
+  const int64_t kLeafEnd = 20 * kSecondsInDay;
+  const int64_t kRootEnd = 30 * kSecondsInDay;
 
   bssl::UniquePtr<X509> root =
       MakeTestCert("Root", "Root", key.get(), /*is_ca=*/true);
@@ -4023,9 +4023,9 @@
   ASSERT_TRUE(X509_sign(leaf.get(), key.get(), EVP_sha256()));
 
   struct VerifyAt {
-    time_t time;
+    int64_t time;
     void operator()(X509_VERIFY_PARAM *param) const {
-      X509_VERIFY_PARAM_set_time(param, time);
+      X509_VERIFY_PARAM_set_time_posix(param, time);
     }
   };
 
diff --git a/crypto/x509/x509_time_test.cc b/crypto/x509/x509_time_test.cc
index fcd51c8..c0327d2 100644
--- a/crypto/x509/x509_time_test.cc
+++ b/crypto/x509/x509_time_test.cc
@@ -20,7 +20,7 @@
 struct TestData {
   const char *data;
   int type;
-  time_t cmp_time;
+  int64_t cmp_time;
   // -1 if asn1_time <= cmp_time, 1 if asn1_time > cmp_time, 0 if error.
   int expected;
 };
@@ -211,6 +211,85 @@
         0,
         0,
     },
+    // Test limits and unusual cases.
+    {
+        "99991231235959Z", V_ASN1_GENERALIZEDTIME,
+        // Test a very large positive time with the largest representable time
+        253402300799,
+        -1,  // TODO(bbe): This is *technically* wrong by rfc5280.
+    },
+    {
+        "99991231235959Z", V_ASN1_GENERALIZEDTIME,
+        // one second after the largest possible time should still compare
+        // correctly
+        253402300800,
+        -1,  // TODO(bbe): This is *technically* wrong by rfc5280.
+    },
+    {
+        "99991231235959Z",
+        V_ASN1_GENERALIZEDTIME,
+        // Test one second before the largest time
+        253402300798,
+        1,
+    },
+    {
+        "700101000000Z",
+        V_ASN1_UTCTIME,
+        // The epoch, which should not fail. a time of 0 must be valid.
+        0,
+        -1,
+    },
+    {
+        "700101000000Z",
+        V_ASN1_UTCTIME,
+        // One second before the epoch should compare correctly.
+        -1,
+        1,
+    },
+    {
+        "700101000000Z",
+        V_ASN1_UTCTIME,
+        // One second after the epoch should compare correctly.
+        1,
+        -1,
+    },
+    {
+        "690621025615Z",
+        V_ASN1_UTCTIME,
+        // Test a negative time, we use a time from NASA, close to but not quite
+        // at the epoch.
+        -16751025,
+        -1,
+    },
+    {
+        "690621025615Z",
+        V_ASN1_UTCTIME,
+        // Test one small second before our negative time.
+        -16751026,
+        1,
+    },
+    {
+        "690621025615Z",
+        V_ASN1_UTCTIME,
+        // Test one giant second after our negative time.
+        -16751024,
+        -1,
+    },
+    {
+        "00000101000000Z",
+        V_ASN1_GENERALIZEDTIME,
+        // Test a very large negative time with the earliest representable time
+        -62167219200,
+        -1,
+    },
+    {
+        "00000101000000Z",
+        V_ASN1_GENERALIZEDTIME,
+        // Test one second after the earliest time.
+        -62167219199,
+        -1,
+    },
+
 };
 
 TEST(X509TimeTest, TestCmpTime) {
@@ -224,8 +303,7 @@
     t.data = (unsigned char*) test.data;
     t.length = strlen(test.data);
 
-    EXPECT_EQ(test.expected,
-              X509_cmp_time(&t, &test.cmp_time));
+    EXPECT_EQ(test.expected, X509_cmp_time_posix(&t, test.cmp_time));
   }
 }
 
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 7638d0d..9288292 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -978,14 +978,14 @@
   if (notify) {
     ctx->current_crl = crl;
   }
-  time_t *ptime;
+  int64_t ptime;
   if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) {
-    ptime = &ctx->param->check_time;
+    ptime = ctx->param->check_time;
   } else {
-    ptime = NULL;
+    ptime = time(NULL);
   }
 
-  int i = X509_cmp_time(X509_CRL_get0_lastUpdate(crl), ptime);
+  int i = X509_cmp_time_posix(X509_CRL_get0_lastUpdate(crl), ptime);
   if (i == 0) {
     if (!notify) {
       return 0;
@@ -1007,7 +1007,7 @@
   }
 
   if (X509_CRL_get0_nextUpdate(crl)) {
-    i = X509_cmp_time(X509_CRL_get0_nextUpdate(crl), ptime);
+    i = X509_cmp_time_posix(X509_CRL_get0_nextUpdate(crl), ptime);
 
     if (i == 0) {
       if (!notify) {
@@ -1724,14 +1724,14 @@
     return 1;
   }
 
-  time_t *ptime;
+  int64_t ptime;
   if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) {
-    ptime = &ctx->param->check_time;
+    ptime = ctx->param->check_time;
   } else {
-    ptime = NULL;
+    ptime = time(NULL);
   }
 
-  int i = X509_cmp_time(X509_get_notBefore(x), ptime);
+  int i = X509_cmp_time_posix(X509_get_notBefore(x), ptime);
   if (i == 0) {
     ctx->error = X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD;
     ctx->current_cert = x;
@@ -1748,7 +1748,7 @@
     }
   }
 
-  i = X509_cmp_time(X509_get_notAfter(x), ptime);
+  i = X509_cmp_time_posix(X509_get_notAfter(x), ptime);
   if (i == 0) {
     ctx->error = X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD;
     ctx->current_cert = x;
@@ -1851,17 +1851,21 @@
 }
 
 int X509_cmp_current_time(const ASN1_TIME *ctm) {
-  return X509_cmp_time(ctm, NULL);
+  return X509_cmp_time_posix(ctm, time(NULL));
 }
 
 int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time) {
+  int64_t compare_time = (cmp_time == NULL) ? time(NULL) : *cmp_time;
+  return X509_cmp_time_posix(ctm, compare_time);
+}
+
+int X509_cmp_time_posix(const ASN1_TIME *ctm, int64_t cmp_time) {
   int64_t ctm_time;
   if (!ASN1_TIME_to_posix(ctm, &ctm_time)) {
     return 0;
   }
-  int64_t compare_time = (cmp_time == NULL) ? time(NULL) : *cmp_time;
   // The return value 0 is reserved for errors.
-  return (ctm_time - compare_time <= 0) ? -1 : 1;
+  return (ctm_time - cmp_time <= 0) ? -1 : 1;
 }
 
 ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long offset_sec) {
@@ -1874,12 +1878,12 @@
 
 ASN1_TIME *X509_time_adj_ex(ASN1_TIME *s, int offset_day, long offset_sec,
                             time_t *in_tm) {
-  time_t t = 0;
+  int64_t t = 0;
 
   if (in_tm) {
     t = *in_tm;
   } else {
-    time(&t);
+    t = time(NULL);
   }
 
   return ASN1_TIME_adj(s, t, offset_day, offset_sec);
@@ -2307,12 +2311,19 @@
   X509_VERIFY_PARAM_set_flags(ctx->param, flags);
 }
 
-void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags,
-                             time_t t) {
-  X509_VERIFY_PARAM_set_time(ctx->param, t);
+void X509_STORE_CTX_set_time_posix(X509_STORE_CTX *ctx, unsigned long flags,
+                             int64_t t) {
+  X509_VERIFY_PARAM_set_time_posix(ctx->param, t);
 }
 
-X509 *X509_STORE_CTX_get0_cert(X509_STORE_CTX *ctx) { return ctx->cert; }
+void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags,
+                             time_t t) {
+  X509_STORE_CTX_set_time_posix(ctx, flags, t);
+}
+
+X509 *X509_STORE_CTX_get0_cert(X509_STORE_CTX *ctx) {
+  return ctx->cert;
+}
 
 void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx,
                                   int (*verify_cb)(int, X509_STORE_CTX *)) {
diff --git a/crypto/x509/x509_vpm.c b/crypto/x509/x509_vpm.c
index 8ea2c6a..d985cb7 100644
--- a/crypto/x509/x509_vpm.c
+++ b/crypto/x509/x509_vpm.c
@@ -378,11 +378,15 @@
   param->depth = depth;
 }
 
-void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t) {
+void X509_VERIFY_PARAM_set_time_posix(X509_VERIFY_PARAM *param, int64_t t) {
   param->check_time = t;
   param->flags |= X509_V_FLAG_USE_CHECK_TIME;
 }
 
+void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t) {
+  X509_VERIFY_PARAM_set_time_posix(param, t);
+}
+
 int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param,
                                   ASN1_OBJECT *policy) {
   if (!param->policies) {
diff --git a/include/openssl/asn1.h b/include/openssl/asn1.h
index 6c7c1a8..26634a8 100644
--- a/include/openssl/asn1.h
+++ b/include/openssl/asn1.h
@@ -1202,20 +1202,23 @@
 // ASN1_UTCTIME_check returns one if |a| is a valid UTCTime and zero otherwise.
 OPENSSL_EXPORT int ASN1_UTCTIME_check(const ASN1_UTCTIME *a);
 
-// ASN1_UTCTIME_set represents |t| as a UTCTime and writes the result to |s|. It
-// returns |s| on success and NULL on error. If |s| is NULL, it returns a
-// newly-allocated |ASN1_UTCTIME| instead.
+// ASN1_UTCTIME_set represents |posix_time| as a UTCTime and writes the result
+// to |s|. It returns |s| on success and NULL on error. If |s| is NULL, it
+// returns a newly-allocated |ASN1_UTCTIME| instead.
 //
 // Note this function may fail if the time is out of range for UTCTime.
-OPENSSL_EXPORT ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t);
+OPENSSL_EXPORT ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s,
+                                              int64_t posix_time);
 
-// ASN1_UTCTIME_adj adds |offset_day| days and |offset_sec| seconds to |t| and
-// writes the result to |s| as a UTCTime. It returns |s| on success and NULL on
-// error. If |s| is NULL, it returns a newly-allocated |ASN1_UTCTIME| instead.
+// ASN1_UTCTIME_adj adds |offset_day| days and |offset_sec| seconds to
+// |posix_time| and writes the result to |s| as a UTCTime. It returns |s| on
+// success and NULL on error. If |s| is NULL, it returns a newly-allocated
+// |ASN1_UTCTIME| instead.
 //
 // Note this function may fail if the time overflows or is out of range for
 // UTCTime.
-OPENSSL_EXPORT ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t,
+OPENSSL_EXPORT ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s,
+                                              int64_t posix_time,
                                               int offset_day, long offset_sec);
 
 // ASN1_UTCTIME_set_string sets |s| to a UTCTime whose contents are a copy of
@@ -1258,23 +1261,24 @@
 // zero otherwise.
 OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *a);
 
-// ASN1_GENERALIZEDTIME_set represents |t| as a GeneralizedTime and writes the
-// result to |s|. It returns |s| on success and NULL on error. If |s| is NULL,
-// it returns a newly-allocated |ASN1_GENERALIZEDTIME| instead.
+// ASN1_GENERALIZEDTIME_set represents |posix_time| as a GeneralizedTime and
+// writes the result to |s|. It returns |s| on success and NULL on error. If |s|
+// is NULL, it returns a newly-allocated |ASN1_GENERALIZEDTIME| instead.
 //
 // Note this function may fail if the time is out of range for GeneralizedTime.
 OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(
-    ASN1_GENERALIZEDTIME *s, time_t t);
+    ASN1_GENERALIZEDTIME *s, int64_t posix_time);
 
 // ASN1_GENERALIZEDTIME_adj adds |offset_day| days and |offset_sec| seconds to
-// |t| and writes the result to |s| as a GeneralizedTime. It returns |s| on
-// success and NULL on error. If |s| is NULL, it returns a newly-allocated
-// |ASN1_GENERALIZEDTIME| instead.
+// |posix_time| and writes the result to |s| as a GeneralizedTime. It returns
+// |s| on success and NULL on error. If |s| is NULL, it returns a
+// newly-allocated |ASN1_GENERALIZEDTIME| instead.
 //
 // Note this function may fail if the time overflows or is out of range for
 // GeneralizedTime.
 OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(
-    ASN1_GENERALIZEDTIME *s, time_t t, int offset_day, long offset_sec);
+    ASN1_GENERALIZEDTIME *s, int64_t posix_time, int offset_day,
+    long offset_sec);
 
 // ASN1_GENERALIZEDTIME_set_string sets |s| to a GeneralizedTime whose contents
 // are a copy of |str|. It returns one on success and zero on error or if |str|
@@ -1324,24 +1328,29 @@
 OPENSSL_EXPORT int ASN1_TIME_diff(int *out_days, int *out_seconds,
                                   const ASN1_TIME *from, const ASN1_TIME *to);
 
-// ASN1_TIME_set represents |t| as a GeneralizedTime or UTCTime and writes
-// the result to |s|. As in RFC 5280, section 4.1.2.5, it uses UTCTime when the
-// time fits and GeneralizedTime otherwise. It returns |s| on success and NULL
-// on error. If |s| is NULL, it returns a newly-allocated |ASN1_TIME| instead.
-//
-// Note this function may fail if the time is out of range for GeneralizedTime.
-OPENSSL_EXPORT ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t);
-
-// ASN1_TIME_adj adds |offset_day| days and |offset_sec| seconds to
-// |t| and writes the result to |s|. As in RFC 5280, section 4.1.2.5, it uses
+// ASN1_TIME_set_posix represents |posix_time| as a GeneralizedTime or UTCTime
+// and writes the result to |s|. As in RFC 5280, section 4.1.2.5, it uses
 // UTCTime when the time fits and GeneralizedTime otherwise. It returns |s| on
 // success and NULL on error. If |s| is NULL, it returns a newly-allocated
-// |ASN1_GENERALIZEDTIME| instead.
+// |ASN1_TIME| instead.
+//
+// Note this function may fail if the time is out of range for GeneralizedTime.
+OPENSSL_EXPORT ASN1_TIME *ASN1_TIME_set_posix(ASN1_TIME *s, int64_t posix_time);
+
+// ASN1_TIME_set is exactly the same as |ASN1_TIME_set_posix| but with a
+// time_t as input for compatibility.
+OPENSSL_EXPORT ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t time);
+
+// ASN1_TIME_adj adds |offset_day| days and |offset_sec| seconds to
+// |posix_time| and writes the result to |s|. As in RFC 5280, section 4.1.2.5,
+// it uses UTCTime when the time fits and GeneralizedTime otherwise. It returns
+// |s| on success and NULL on error. If |s| is NULL, it returns a
+// newly-allocated |ASN1_GENERALIZEDTIME| instead.
 //
 // Note this function may fail if the time overflows or is out of range for
 // GeneralizedTime.
-OPENSSL_EXPORT ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, time_t t, int offset_day,
-                                        long offset_sec);
+OPENSSL_EXPORT ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, int64_t posix_time,
+                                        int offset_day, long offset_sec);
 
 // ASN1_TIME_check returns one if |t| is a valid UTCTime or GeneralizedTime, and
 // zero otherwise. |t|'s type determines which check is performed. This
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index 32ddcee..179c570 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -1837,6 +1837,14 @@
 // error, not equality.
 OPENSSL_EXPORT int X509_cmp_time(const ASN1_TIME *s, time_t *t);
 
+// X509_cmp_time_posix compares |s| against |t|. On success, it returns a
+// negative number if |s| <= |t| and a positive number if |s| > |t|. On error,
+// it returns zero.
+//
+// WARNING: Unlike most comparison functions, this function returns zero on
+// error, not equality.
+OPENSSL_EXPORT int X509_cmp_time_posix(const ASN1_TIME *s, int64_t t);
+
 // X509_cmp_current_time behaves like |X509_cmp_time| but compares |s| against
 // the current time.
 OPENSSL_EXPORT int X509_cmp_current_time(const ASN1_TIME *s);
@@ -2770,6 +2778,9 @@
                                              unsigned long flags);
 OPENSSL_EXPORT void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx,
                                             unsigned long flags, time_t t);
+OPENSSL_EXPORT void X509_STORE_CTX_set_time_posix(X509_STORE_CTX *ctx,
+                                                  unsigned long flags,
+                                                  int64_t t);
 OPENSSL_EXPORT void X509_STORE_CTX_set_verify_cb(
     X509_STORE_CTX *ctx, int (*verify_cb)(int, X509_STORE_CTX *));
 
@@ -2804,6 +2815,8 @@
                                                 int depth);
 OPENSSL_EXPORT void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param,
                                                time_t t);
+OPENSSL_EXPORT void X509_VERIFY_PARAM_set_time_posix(X509_VERIFY_PARAM *param,
+                                                     int64_t t);
 OPENSSL_EXPORT int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param,
                                                  ASN1_OBJECT *policy);
 OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_policies(