Remove begin_handshake and allocate init_buf lazily.

For TLS 1.3, we will need to process more complex post-handshake
messages. It is simplest if we use the same mechanism. In preparation,
allow ssl3_get_message to be called at any point.

Note that this stops reserving SSL3_RT_MAX_PLAIN_LENGTH in init_buf
right off the bat. Instead it will grow as-needed to accomodate the
handshake. SSL3_RT_MAX_PLAIN_LENGTH is rather larger than we probably
need to receive, particularly as a server, so this seems a good plan.

BUG=83

Change-Id: Id7f4024afc4c8a713b46b0d1625432315594350e
Reviewed-on: https://boringssl-review.googlesource.com/8985
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/ssl/dtls_method.c b/ssl/dtls_method.c
index cf26092..15d90f6 100644
--- a/ssl/dtls_method.c
+++ b/ssl/dtls_method.c
@@ -92,10 +92,6 @@
   return ~(version - 0x0201);
 }
 
-static int dtls1_begin_handshake(SSL *ssl) {
-  return 1;
-}
-
 static void dtls1_finish_handshake(SSL *ssl) {
   ssl->d1->handshake_read_seq = 0;
   ssl->d1->handshake_write_seq = 0;
@@ -141,7 +137,6 @@
     dtls1_version_to_wire,
     dtls1_new,
     dtls1_free,
-    dtls1_begin_handshake,
     dtls1_finish_handshake,
     dtls1_get_message,
     dtls1_hash_current_message,
diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c
index 6f9b2fc..fc4318e 100644
--- a/ssl/handshake_client.c
+++ b/ssl/handshake_client.c
@@ -201,8 +201,7 @@
         ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1);
 
         ssl->s3->hs = ssl_handshake_new(tls13_client_handshake);
-        if (ssl->s3->hs == NULL ||
-            !ssl->method->begin_handshake(ssl)) {
+        if (ssl->s3->hs == NULL) {
           ret = -1;
           goto end;
         }
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index 31a5030..4708dd0 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -202,8 +202,7 @@
         ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1);
 
         ssl->s3->hs = ssl_handshake_new(tls13_server_handshake);
-        if (ssl->s3->hs == NULL ||
-            !ssl->method->begin_handshake(ssl)) {
+        if (ssl->s3->hs == NULL) {
           ret = -1;
           goto end;
         }
diff --git a/ssl/internal.h b/ssl/internal.h
index f5180a7..2fb1492 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1039,9 +1039,6 @@
   uint16_t (*version_to_wire)(uint16_t version);
   int (*ssl_new)(SSL *ssl);
   void (*ssl_free)(SSL *ssl);
-  /* begin_handshake is called to start a new handshake. It returns one on
-   * success and zero on error. */
-  int (*begin_handshake)(SSL *ssl);
   /* finish_handshake is called when a handshake completes. */
   void (*finish_handshake)(SSL *ssl);
   /* ssl_get_message reads the next handshake message. If |msg_type| is not -1,
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 8092eb9..cb4356b 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -456,8 +456,15 @@
          rand_len);
 
   /* Write out an equivalent SSLv3 ClientHello. */
+  size_t max_v3_client_hello = SSL3_HM_HEADER_LENGTH + 2 /* version */ +
+                               SSL3_RANDOM_SIZE + 1 /* session ID length */ +
+                               2 /* cipher list length */ +
+                               CBS_len(&cipher_specs) / 3 * 2 +
+                               1 /* compression length */ + 1 /* compression */;
   CBB client_hello, hello_body, cipher_suites;
-  if (!CBB_init_fixed(&client_hello, (uint8_t *)ssl->init_buf->data,
+  CBB_zero(&client_hello);
+  if (!BUF_MEM_reserve(ssl->init_buf, max_v3_client_hello) ||
+      !CBB_init_fixed(&client_hello, (uint8_t *)ssl->init_buf->data,
                       ssl->init_buf->max) ||
       !CBB_add_u8(&client_hello, SSL3_MT_CLIENT_HELLO) ||
       !CBB_add_u24_length_prefixed(&client_hello, &hello_body) ||
@@ -512,6 +519,14 @@
 int ssl3_get_message(SSL *ssl, int msg_type,
                      enum ssl_hash_message_t hash_message) {
 again:
+  /* Re-create the handshake buffer if needed. */
+  if (ssl->init_buf == NULL) {
+    ssl->init_buf = BUF_MEM_new();
+    if (ssl->init_buf == NULL) {
+      return -1;
+    }
+  }
+
   if (ssl->server && !ssl->s3->v2_hello_done) {
     /* Bypass the record layer for the first message to handle V2ClientHello. */
     assert(hash_message == ssl_hash_message);
diff --git a/ssl/tls_method.c b/ssl/tls_method.c
index 70b6bd1..cd6b453 100644
--- a/ssl/tls_method.c
+++ b/ssl/tls_method.c
@@ -69,21 +69,6 @@
 
 static uint16_t ssl3_version_to_wire(uint16_t version) { return version; }
 
-static int ssl3_begin_handshake(SSL *ssl) {
-  if (ssl->init_buf != NULL) {
-    return 1;
-  }
-
-  BUF_MEM *buf = BUF_MEM_new();
-  if (buf == NULL || !BUF_MEM_reserve(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
-    BUF_MEM_free(buf);
-    return 0;
-  }
-
-  ssl->init_buf = buf;
-  return 1;
-}
-
 static void ssl3_finish_handshake(SSL *ssl) {
   BUF_MEM_free(ssl->init_buf);
   ssl->init_buf = NULL;
@@ -125,7 +110,6 @@
     ssl3_version_to_wire,
     ssl3_new,
     ssl3_free,
-    ssl3_begin_handshake,
     ssl3_finish_handshake,
     ssl3_get_message,
     ssl3_hash_current_message,