Splitting SSL session state.

To prevent configuration/established session confusion, the handshake
session state is separated into the configured session (ssl->session)
and the newly created session (ssl->s3->new_session). Upon conclusion of
the handshake, the finalized session is stored
in (ssl->s3->established_session). During the handshake, any requests
for the session (SSL_get_session) return a non-resumable session, to
prevent resumption of a partially filled session. Sessions should only
be cached upon the completion of the full handshake, using the resulting
established_session. The semantics of accessors on the session are
maintained mid-renego.

Change-Id: I4358aecb71fce4fe14a6746c5af1416a69935078
Reviewed-on: https://boringssl-review.googlesource.com/8612
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/ssl_test.cc b/ssl/ssl_test.cc
index f26962f..5dd689b 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -30,6 +30,7 @@
 #include <openssl/ssl.h>
 #include <openssl/x509.h>
 
+#include "internal.h"
 #include "test/scoped_types.h"
 #include "../crypto/test/test_util.h"
 
@@ -1253,6 +1254,48 @@
 
   return true;
 }
+static bool TestSessionDuplication() {
+  ScopedSSL_CTX client_ctx(SSL_CTX_new(TLS_method()));
+  ScopedSSL_CTX server_ctx(SSL_CTX_new(TLS_method()));
+  if (!client_ctx || !server_ctx) {
+    return false;
+  }
+
+  ScopedX509 cert = GetTestCertificate();
+  ScopedEVP_PKEY key = GetTestKey();
+  if (!cert || !key ||
+      !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+      !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
+    return false;
+  }
+
+  ScopedSSL client, server;
+  if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
+                              server_ctx.get())) {
+    return false;
+  }
+
+  SSL_SESSION *session0 = SSL_get_session(client.get());
+  ScopedSSL_SESSION session1(SSL_SESSION_dup(session0, 1));
+  if (!session1) {
+    return false; 
+  }
+  
+  uint8_t *s0_bytes, *s1_bytes;
+  size_t s0_len, s1_len;
+
+  if (!SSL_SESSION_to_bytes(session0, &s0_bytes, &s0_len)) {
+    return false;
+  }
+  ScopedOpenSSLBytes free_s0(s0_bytes);
+
+  if (!SSL_SESSION_to_bytes(session1.get(), &s1_bytes, &s1_len)) {
+    return false;
+  }
+  ScopedOpenSSLBytes free_s1(s1_bytes);
+
+  return s0_len == s1_len && memcmp(s0_bytes, s1_bytes, s0_len) == 0;
+}
 
 static bool ExpectFDs(const SSL *ssl, int rfd, int wfd) {
   if (SSL_get_rfd(ssl) != rfd || SSL_get_wfd(ssl) != wfd) {
@@ -1501,6 +1544,7 @@
       !TestSequenceNumber(false /* TLS */) ||
       !TestSequenceNumber(true /* DTLS */) ||
       !TestOneSidedShutdown() ||
+      !TestSessionDuplication() ||
       !TestSetFD() ||
       !TestGetPeerCertificate() ||
       !TestRetainOnlySHA256OfCerts()) {