Only allow SSL_set_session before the handshake.

Otherwise things break horribly. Explicitly abort to help catch bugs.

Change-Id: I66e2bf8808199b3331b3adde68d73758a601eb8c
Reviewed-on: https://boringssl-review.googlesource.com/10761
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index ce2ba41..4ff25ce 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1683,7 +1683,9 @@
 
 /* SSL_set_session, for a client, configures |ssl| to offer to resume |session|
  * in the initial handshake and returns one. The caller retains ownership of
- * |session|. */
+ * |session|.
+ *
+ * It is an error to call this function after the handshake has begun. */
 OPENSSL_EXPORT int SSL_set_session(SSL *ssl, SSL_SESSION *session);
 
 /* SSL_get_session returns a non-owning pointer to |ssl|'s session. For
diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c
index 9a5cd02..c8177b4 100644
--- a/ssl/handshake_client.c
+++ b/ssl/handshake_client.c
@@ -728,7 +728,7 @@
         ssl->session->not_resumable ||
         !ssl_session_is_time_valid(ssl, ssl->session) ||
         session_version < min_version || session_version > max_version) {
-      SSL_set_session(ssl, NULL);
+      ssl_set_session(ssl, NULL);
     }
   }
 
@@ -896,7 +896,7 @@
   } else {
     /* The session wasn't resumed. Create a fresh SSL_SESSION to
      * fill out. */
-    SSL_set_session(ssl, NULL);
+    ssl_set_session(ssl, NULL);
     if (!ssl_get_new_session(ssl, 0 /* client */)) {
       goto f_err;
     }
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index c5bd4be..f7c127d 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -719,7 +719,7 @@
       session = NULL;
       ssl->s3->session_reused = 1;
     } else {
-      SSL_set_session(ssl, NULL);
+      ssl_set_session(ssl, NULL);
       if (!ssl_get_new_session(ssl, 1 /* server */)) {
         goto err;
       }
diff --git a/ssl/internal.h b/ssl/internal.h
index 660ba79..f285682 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1262,6 +1262,8 @@
  * it has expired. */
 int ssl_session_is_time_valid(const SSL *ssl, const SSL_SESSION *session);
 
+void ssl_set_session(SSL *ssl, SSL_SESSION *session);
+
 enum ssl_session_result_t {
   ssl_session_success,
   ssl_session_error,
diff --git a/ssl/ssl_session.c b/ssl/ssl_session.c
index 3a56dcd..78dfeab 100644
--- a/ssl/ssl_session.c
+++ b/ssl/ssl_session.c
@@ -136,6 +136,7 @@
 #include <openssl/ssl.h>
 
 #include <assert.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include <openssl/err.h>
@@ -482,7 +483,7 @@
 
   SSL_SESSION_free(ssl->s3->new_session);
   ssl->s3->new_session = session;
-  SSL_set_session(ssl, NULL);
+  ssl_set_session(ssl, NULL);
   return 1;
 
 err:
@@ -792,8 +793,18 @@
 }
 
 int SSL_set_session(SSL *ssl, SSL_SESSION *session) {
+  /* SSL_set_session may only be called before the handshake has started. */
+  if (ssl->state != SSL_ST_INIT || ssl->s3->initial_handshake_complete) {
+    abort();
+  }
+
+  ssl_set_session(ssl, session);
+  return 1;
+}
+
+void ssl_set_session(SSL *ssl, SSL_SESSION *session) {
   if (ssl->session == session) {
-    return 1;
+    return;
   }
 
   SSL_SESSION_free(ssl->session);
@@ -801,8 +812,6 @@
   if (session != NULL) {
     SSL_SESSION_up_ref(session);
   }
-
-  return 1;
 }
 
 long SSL_CTX_set_timeout(SSL_CTX *ctx, long timeout) {
diff --git a/ssl/tls13_client.c b/ssl/tls13_client.c
index d2d99a7..8dfb5da 100644
--- a/ssl/tls13_client.c
+++ b/ssl/tls13_client.c
@@ -228,7 +228,7 @@
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
       return ssl_hs_error;
     }
-    SSL_set_session(ssl, NULL);
+    ssl_set_session(ssl, NULL);
   } else {
     if (!ssl_get_new_session(ssl, 0)) {
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);