Don't use long for timestamps.

This is the first part to fixing the SSL stack to be 2038-clean.
Internal structures and functions are switched to use OPENSSL_timeval
which, unlike timeval and long, are suitable for timestamps on all
platforms.

It is generally accepted that the year is now sometime after 1970, so
use uint64_t for the timestamps to avoid worrying about serializing
negative numbers in SSL_SESSION.

A follow-up change will fix SSL_CTX_set_current_time_cb to use
OPENSSL_timeval. This will require some coordinating with WebRTC.
DTLSv1_get_timeout is left alone for compatibility and because it stores
time remaining rather than an absolute time.

BUG=155

Change-Id: I1a5054813300874b6f29e348f9cd8ca80f6b9729
Reviewed-on: https://boringssl-review.googlesource.com/13944
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index 9f91949..ef15252 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -147,32 +147,43 @@
     return 0;
   }
 
-  struct timeval timenow;
+  struct OPENSSL_timeval timenow;
   ssl_get_current_time(ssl, &timenow);
 
   /* If timer already expired, set remaining time to 0 */
   if (ssl->d1->next_timeout.tv_sec < timenow.tv_sec ||
       (ssl->d1->next_timeout.tv_sec == timenow.tv_sec &&
        ssl->d1->next_timeout.tv_usec <= timenow.tv_usec)) {
-    OPENSSL_memset(out, 0, sizeof(struct timeval));
+    OPENSSL_memset(out, 0, sizeof(*out));
     return 1;
   }
 
   /* Calculate time left until timer expires */
-  OPENSSL_memcpy(out, &ssl->d1->next_timeout, sizeof(struct timeval));
-  out->tv_sec -= timenow.tv_sec;
-  out->tv_usec -= timenow.tv_usec;
-  if (out->tv_usec < 0) {
-    out->tv_sec--;
-    out->tv_usec += 1000000;
+  struct OPENSSL_timeval ret;
+  OPENSSL_memcpy(&ret, &ssl->d1->next_timeout, sizeof(ret));
+  ret.tv_sec -= timenow.tv_sec;
+  if (ret.tv_usec >= timenow.tv_usec) {
+    ret.tv_usec -= timenow.tv_usec;
+  } else {
+    ret.tv_usec = 1000000 + ret.tv_usec - timenow.tv_usec;
+    ret.tv_sec--;
   }
 
   /* If remaining time is less than 15 ms, set it to 0 to prevent issues
-   * because of small devergences with socket timeouts. */
-  if (out->tv_sec == 0 && out->tv_usec < 15000) {
-    OPENSSL_memset(out, 0, sizeof(struct timeval));
+   * because of small divergences with socket timeouts. */
+  if (ret.tv_sec == 0 && ret.tv_usec < 15000) {
+    OPENSSL_memset(&ret, 0, sizeof(ret));
   }
 
+  /* Clamp the result in case of overflow. */
+  if (ret.tv_sec > INT_MAX) {
+    assert(0);
+    out->tv_sec = INT_MAX;
+  } else {
+    out->tv_sec = ret.tv_sec;
+  }
+
+  out->tv_usec = ret.tv_usec;
   return 1;
 }
 
@@ -204,7 +215,7 @@
 void dtls1_stop_timer(SSL *ssl) {
   /* Reset everything */
   ssl->d1->num_timeouts = 0;
-  OPENSSL_memset(&ssl->d1->next_timeout, 0, sizeof(struct timeval));
+  OPENSSL_memset(&ssl->d1->next_timeout, 0, sizeof(ssl->d1->next_timeout));
   ssl->d1->timeout_duration_ms = ssl->initial_timeout_duration_ms;
 
   /* Clear retransmission buffer */
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index 1b65662..e3a4e51 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -1058,7 +1058,7 @@
     ssl->s3->tlsext_channel_id_valid = 0;
   }
 
-  struct timeval now;
+  struct OPENSSL_timeval now;
   ssl_get_current_time(ssl, &now);
   ssl->s3->server_random[0] = now.tv_sec >> 24;
   ssl->s3->server_random[1] = now.tv_sec >> 16;
diff --git a/ssl/internal.h b/ssl/internal.h
index 144b680..dbeae92 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1720,6 +1720,11 @@
   uint8_t *reassembly;
 } hm_fragment;
 
+struct OPENSSL_timeval {
+  uint64_t tv_sec;
+  uint32_t tv_usec;
+};
+
 typedef struct dtls1_state_st {
   /* send_cookie is true if we are resending the ClientHello
    * with a cookie from a HelloVerifyRequest. */
@@ -1768,7 +1773,7 @@
 
   /* Indicates when the last handshake msg or heartbeat sent will
    * timeout. */
-  struct timeval next_timeout;
+  struct OPENSSL_timeval next_timeout;
 
   /* timeout_duration_ms is the timeout duration in milliseconds. */
   unsigned timeout_duration_ms;
@@ -2013,7 +2018,8 @@
 /* ssl_session_renew_timeout calls |ssl_session_rebase_time| and renews
  * |session|'s timeout to |timeout| (measured from the current time). The
  * renewal is clamped to the session's auth_timeout. */
-void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session, long timeout);
+void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session,
+                               uint32_t timeout);
 
 void ssl_cipher_preference_list_free(
     struct ssl_cipher_preference_list_st *cipher_list);
@@ -2203,7 +2209,7 @@
  * call this function before the version is determined. */
 uint16_t ssl3_protocol_version(const SSL *ssl);
 
-void ssl_get_current_time(const SSL *ssl, struct timeval *out_clock);
+void ssl_get_current_time(const SSL *ssl, struct OPENSSL_timeval *out_clock);
 
 /* ssl_reset_error_state resets state for |SSL_get_error|. */
 void ssl_reset_error_state(SSL *ssl);
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index 3533225..cfcc12a 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -210,28 +210,10 @@
       !CBB_add_bytes(&child, in->session_id,
                      for_ticket ? 0 : in->session_id_length) ||
       !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
-      !CBB_add_bytes(&child, in->master_key, in->master_key_length)) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-    goto err;
-  }
-
-  if (in->time < 0) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
-  }
-
-  if (!CBB_add_asn1(&session, &child, kTimeTag) ||
-      !CBB_add_asn1_uint64(&child, in->time)) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
-    goto err;
-  }
-
-  if (in->timeout < 0) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
-    goto err;
-  }
-
-  if (!CBB_add_asn1(&session, &child, kTimeoutTag) ||
+      !CBB_add_bytes(&child, in->master_key, in->master_key_length) ||
+      !CBB_add_asn1(&session, &child, kTimeTag) ||
+      !CBB_add_asn1_uint64(&child, in->time) ||
+      !CBB_add_asn1(&session, &child, kTimeoutTag) ||
       !CBB_add_asn1_uint64(&child, in->timeout)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     goto err;
@@ -634,19 +616,17 @@
   ret->master_key_length = CBS_len(&master_key);
 
   CBS child;
-  uint64_t time, timeout;
+  uint64_t timeout;
   if (!CBS_get_asn1(&session, &child, kTimeTag) ||
-      !CBS_get_asn1_uint64(&child, &time) ||
-      time > LONG_MAX ||
+      !CBS_get_asn1_uint64(&child, &ret->time) ||
       !CBS_get_asn1(&session, &child, kTimeoutTag) ||
       !CBS_get_asn1_uint64(&child, &timeout) ||
-      timeout > LONG_MAX) {
+      timeout > UINT32_MAX) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
     goto err;
   }
 
-  ret->time = (long)time;
-  ret->timeout = (long)timeout;
+  ret->timeout = (uint32_t)timeout;
 
   CBS peer;
   int has_peer;
@@ -811,8 +791,8 @@
                              kPeerSignatureAlgorithmTag, 0) ||
       !SSL_SESSION_parse_u32(&session, &ret->ticket_max_early_data,
                              kTicketMaxEarlyDataTag, 0) ||
-      !SSL_SESSION_parse_long(&session, &ret->auth_timeout, kAuthTimeoutTag,
-                              ret->timeout) ||
+      !SSL_SESSION_parse_u32(&session, &ret->auth_timeout, kAuthTimeoutTag,
+                             ret->timeout) ||
       !SSL_SESSION_parse_octet_string(&session, &ret->early_alpn,
                                       &ret->early_alpn_len, kEarlyALPNTag) ||
       CBS_len(&session) != 0) {
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index a37de06..75cac31 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1888,9 +1888,9 @@
     CRYPTO_MUTEX_unlock_write(&ctx->lock);
 
     if (flush_cache) {
-      struct timeval now;
+      struct OPENSSL_timeval now;
       ssl_get_current_time(ssl, &now);
-      SSL_CTX_flush_sessions(ctx, (long)now.tv_sec);
+      SSL_CTX_flush_sessions(ctx, now.tv_sec);
     }
   }
 }
@@ -2686,9 +2686,20 @@
   return SSL_set1_curves(ssl, &nid, 1);
 }
 
-void ssl_get_current_time(const SSL *ssl, struct timeval *out_clock) {
+void ssl_get_current_time(const SSL *ssl, struct OPENSSL_timeval *out_clock) {
   if (ssl->ctx->current_time_cb != NULL) {
-    ssl->ctx->current_time_cb(ssl, out_clock);
+    /* TODO(davidben): Update current_time_cb to use OPENSSL_timeval. See
+     * https://crbug.com/boringssl/155. */
+    struct timeval clock;
+    ssl->ctx->current_time_cb(ssl, &clock);
+    if (clock.tv_sec < 0) {
+      assert(0);
+      out_clock->tv_sec = 0;
+      out_clock->tv_usec = 0;
+    } else {
+      out_clock->tv_sec = (uint64_t)clock.tv_sec;
+      out_clock->tv_usec = (uint32_t)clock.tv_usec;
+    }
     return;
   }
 
@@ -2698,10 +2709,25 @@
 #elif defined(OPENSSL_WINDOWS)
   struct _timeb time;
   _ftime(&time);
-  out_clock->tv_sec = time.time;
-  out_clock->tv_usec = time.millitm * 1000;
+  if (time.time < 0) {
+    assert(0);
+    out_clock->tv_sec = 0;
+    out_clock->tv_usec = 0;
+  } else {
+    out_clock->tv_sec = time.time;
+    out_clock->tv_usec = time.millitm * 1000;
+  }
 #else
-  gettimeofday(out_clock, NULL);
+  struct timeval clock;
+  gettimeofday(&clock, NULL);
+  if (clock.tv_sec < 0) {
+    assert(0);
+    out_clock->tv_sec = 0;
+    out_clock->tv_usec = 0;
+  } else {
+    out_clock->tv_sec = (uint64_t)clock.tv_sec;
+    out_clock->tv_usec = (uint32_t)clock.tv_usec;
+  }
 #endif
 }
 
diff --git a/ssl/ssl_session.c b/ssl/ssl_session.c
index bbe88c3..c9390d2 100644
--- a/ssl/ssl_session.c
+++ b/ssl/ssl_session.c
@@ -173,7 +173,7 @@
   session->references = 1;
   session->timeout = SSL_DEFAULT_SESSION_TIMEOUT;
   session->auth_timeout = SSL_DEFAULT_SESSION_TIMEOUT;
-  session->time = (long)time(NULL);
+  session->time = time(NULL);
   CRYPTO_new_ex_data(&session->ex_data);
   return session;
 }
@@ -315,14 +315,12 @@
 }
 
 void ssl_session_rebase_time(SSL *ssl, SSL_SESSION *session) {
-  struct timeval now;
+  struct OPENSSL_timeval now;
   ssl_get_current_time(ssl, &now);
 
-  /* To avoid overflows and underflows, if we've gone back in time or any value
-   * is negative, update the time, but mark the session expired. */
-  if (session->time > now.tv_sec ||
-      session->time < 0 ||
-      now.tv_sec < 0) {
+  /* To avoid overflows and underflows, if we've gone back in time, update the
+   * time, but mark the session expired. */
+  if (session->time > now.tv_sec) {
     session->time = now.tv_sec;
     session->timeout = 0;
     session->auth_timeout = 0;
@@ -331,7 +329,7 @@
 
   /* Adjust the session time and timeouts. If the session has already expired,
    * clamp the timeouts at zero. */
-  long delta = now.tv_sec - session->time;
+  uint64_t delta = now.tv_sec - session->time;
   session->time = now.tv_sec;
   if (session->timeout < delta) {
     session->timeout = 0;
@@ -345,7 +343,8 @@
   }
 }
 
-void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session, long timeout) {
+void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session,
+                               uint32_t timeout) {
   /* Rebase the timestamp relative to the current time so |timeout| is measured
    * correctly. */
   ssl_session_rebase_time(ssl, session);
@@ -395,11 +394,11 @@
   return session->session_id;
 }
 
-long SSL_SESSION_get_timeout(const SSL_SESSION *session) {
+uint32_t SSL_SESSION_get_timeout(const SSL_SESSION *session) {
   return session->timeout;
 }
 
-long SSL_SESSION_get_time(const SSL_SESSION *session) {
+uint64_t SSL_SESSION_get_time(const SSL_SESSION *session) {
   if (session == NULL) {
     /* NULL should crash, but silently accept it here for compatibility. */
     return 0;
@@ -424,7 +423,7 @@
   return max_out;
 }
 
-long SSL_SESSION_set_time(SSL_SESSION *session, long time) {
+uint64_t SSL_SESSION_set_time(SSL_SESSION *session, uint64_t time) {
   if (session == NULL) {
     return 0;
   }
@@ -433,7 +432,7 @@
   return time;
 }
 
-long SSL_SESSION_set_timeout(SSL_SESSION *session, long timeout) {
+uint32_t SSL_SESSION_set_timeout(SSL_SESSION *session, uint32_t timeout) {
   if (session == NULL) {
     return 0;
   }
@@ -528,7 +527,7 @@
   session->ssl_version = ssl->version;
 
   /* Fill in the time from the |SSL_CTX|'s clock. */
-  struct timeval now;
+  struct OPENSSL_timeval now;
   ssl_get_current_time(ssl, &now);
   session->time = now.tv_sec;
 
@@ -689,15 +688,15 @@
     return 0;
   }
 
-  struct timeval now;
+  struct OPENSSL_timeval now;
   ssl_get_current_time(ssl, &now);
 
   /* Reject tickets from the future to avoid underflow. */
-  if ((long)now.tv_sec < session->time) {
+  if (now.tv_sec < session->time) {
     return 0;
   }
 
-  return session->timeout > (long)now.tv_sec - session->time;
+  return session->timeout > now.tv_sec - session->time;
 }
 
 int ssl_session_is_resumable(const SSL_HANDSHAKE *hs,
@@ -933,7 +932,7 @@
   }
 }
 
-long SSL_CTX_set_timeout(SSL_CTX *ctx, long timeout) {
+uint32_t SSL_CTX_set_timeout(SSL_CTX *ctx, uint32_t timeout) {
   if (ctx == NULL) {
     return 0;
   }
@@ -943,12 +942,12 @@
     timeout = SSL_DEFAULT_SESSION_TIMEOUT;
   }
 
-  long old_timeout = ctx->session_timeout;
+  uint32_t old_timeout = ctx->session_timeout;
   ctx->session_timeout = timeout;
   return old_timeout;
 }
 
-long SSL_CTX_get_timeout(const SSL_CTX *ctx) {
+uint32_t SSL_CTX_get_timeout(const SSL_CTX *ctx) {
   if (ctx == NULL) {
     return 0;
   }
@@ -956,13 +955,13 @@
   return ctx->session_timeout;
 }
 
-void SSL_CTX_set_session_psk_dhe_timeout(SSL_CTX *ctx, long timeout) {
+void SSL_CTX_set_session_psk_dhe_timeout(SSL_CTX *ctx, uint32_t timeout) {
   ctx->session_psk_dhe_timeout = timeout;
 }
 
 typedef struct timeout_param_st {
   SSL_CTX *ctx;
-  long time;
+  uint64_t time;
   LHASH_OF(SSL_SESSION) *cache;
 } TIMEOUT_PARAM;
 
@@ -970,6 +969,7 @@
   TIMEOUT_PARAM *param = void_param;
 
   if (param->time == 0 ||
+      session->time + session->timeout < session->time ||
       param->time > (session->time + session->timeout)) {
     /* timeout */
     /* The reason we don't call SSL_CTX_remove_session() is to
@@ -984,7 +984,7 @@
   }
 }
 
-void SSL_CTX_flush_sessions(SSL_CTX *ctx, long time) {
+void SSL_CTX_flush_sessions(SSL_CTX *ctx, uint64_t time) {
   TIMEOUT_PARAM tp;
 
   tp.ctx = ctx;
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index d6ef1ff..2a9f945 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1901,7 +1901,7 @@
     return 1;
   }
 
-  struct timeval now;
+  struct OPENSSL_timeval now;
   ssl_get_current_time(ssl, &now);
   uint32_t ticket_age = 1000 * (now.tv_sec - ssl->session->time);
   uint32_t obfuscated_ticket_age = ticket_age + ssl->session->ticket_age_add;
diff --git a/ssl/tls13_client.c b/ssl/tls13_client.c
index e178666..254c363 100644
--- a/ssl/tls13_client.c
+++ b/ssl/tls13_client.c
@@ -650,18 +650,9 @@
   }
 
   /* Cap the renewable lifetime by the server advertised value. This avoids
-   * wasting bandwidth on 0-RTT when we know the server will reject it.
-   *
-   * TODO(davidben): This dance where we're not sure if long or uint32_t is
-   * bigger is silly. session->timeout should not be a long to begin with.
-   * https://crbug.com/boringssl/155. */
-#if LONG_MAX < 0xffffffff
-  if (server_timeout > LONG_MAX) {
-    server_timeout = LONG_MAX;
-  }
-#endif
-  if (session->timeout > (long)server_timeout) {
-    session->timeout = (long)server_timeout;
+   * wasting bandwidth on 0-RTT when we know the server will reject it. */
+  if (session->timeout > server_timeout) {
+    session->timeout = server_timeout;
   }
 
   /* Parse out the extensions. */