Splitting finish_message to finish_message/queue_message.

This is to allow for PSK binders to be munged into the ClientHello as part of
draft 18.

BUG=112

Change-Id: Ic4fd3b70fa45669389b6aaf55e61d5839f296748
Reviewed-on: https://boringssl-review.googlesource.com/12228
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_both.c b/ssl/d1_both.c
index eae657c..82ee58c 100644
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -736,21 +736,22 @@
   return 1;
 }
 
-int dtls1_finish_message(SSL *ssl, CBB *cbb) {
-  uint8_t *msg = NULL;
-  size_t len;
-  if (!CBB_finish(cbb, &msg, &len) ||
-      len > 0xffffffffu ||
-      len < DTLS1_HM_HEADER_LENGTH) {
+int dtls1_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg,
+                         size_t *out_len) {
+  if (!CBB_finish(cbb, out_msg, out_len) ||
+      *out_len < DTLS1_HM_HEADER_LENGTH) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-    OPENSSL_free(msg);
+    OPENSSL_free(*out_msg);
     return 0;
   }
 
   /* Fix up the header. Copy the fragment length into the total message
    * length. */
-  memcpy(msg + 1, msg + DTLS1_HM_HEADER_LENGTH - 3, 3);
+  memcpy(*out_msg + 1, *out_msg + DTLS1_HM_HEADER_LENGTH - 3, 3);
+  return 1;
+}
 
+int dtls1_queue_message(SSL *ssl, uint8_t *msg, size_t len) {
   ssl3_update_handshake_hash(ssl, msg, len);
 
   ssl->d1->handshake_write_seq++;
diff --git a/ssl/dtls_method.c b/ssl/dtls_method.c
index 9d791b5..8026579 100644
--- a/ssl/dtls_method.c
+++ b/ssl/dtls_method.c
@@ -142,6 +142,7 @@
     dtls1_supports_cipher,
     dtls1_init_message,
     dtls1_finish_message,
+    dtls1_queue_message,
     dtls1_write_message,
     dtls1_send_change_cipher_spec,
     dtls1_expect_flight,
diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c
index 64d3941..3583be4 100644
--- a/ssl/handshake_client.c
+++ b/ssl/handshake_client.c
@@ -764,7 +764,7 @@
   CBB body;
   if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CLIENT_HELLO) ||
       !ssl_add_client_hello_body(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
@@ -1676,7 +1676,7 @@
 
   /* The message must be added to the finished hash before calculating the
    * master secret. */
-  if (!ssl->method->finish_message(ssl, &cbb)) {
+  if (!ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
   ssl->state = SSL3_ST_CW_KEY_EXCH_B;
@@ -1793,7 +1793,7 @@
   }
 
   if (!CBB_did_write(&child, sig_len) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
@@ -1822,7 +1822,7 @@
                      ssl->s3->next_proto_negotiated_len) ||
       !CBB_add_u8_length_prefixed(&body, &child) ||
       !CBB_add_bytes(&child, kZero, padding_len) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     CBB_cleanup(&cbb);
     return -1;
@@ -1851,7 +1851,7 @@
   CBB cbb, body;
   if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) ||
       !tls1_write_channel_id(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     CBB_cleanup(&cbb);
     return -1;
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index f0469d4..e9da90e 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -964,7 +964,7 @@
       !CBB_add_u16(&body, ssl_cipher_get_value(ssl->s3->tmp.new_cipher)) ||
       !CBB_add_u8(&body, 0 /* no compression */) ||
       !ssl_add_serverhello_tlsext(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     CBB_cleanup(&cbb);
     return -1;
@@ -1003,7 +1003,7 @@
       !CBB_add_u24_length_prefixed(&body, &ocsp_response) ||
       !CBB_add_bytes(&ocsp_response, ssl->ctx->ocsp_response,
                      ssl->ctx->ocsp_response_length) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     CBB_cleanup(&cbb);
     return -1;
@@ -1184,7 +1184,7 @@
     }
   }
 
-  if (!ssl->method->finish_message(ssl, &cbb)) {
+  if (!ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
@@ -1266,7 +1266,7 @@
   }
 
   if (!ssl_add_client_CA_list(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
@@ -1286,7 +1286,7 @@
 
   CBB cbb, body;
   if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO_DONE) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     CBB_cleanup(&cbb);
     return -1;
@@ -1849,7 +1849,7 @@
       CBB_add_u32(&body, session->timeout) &&
       CBB_add_u16_length_prefixed(&body, &ticket) &&
       ssl_encrypt_ticket(ssl, &ticket, session) &&
-      ssl->method->finish_message(ssl, &cbb);
+      ssl_complete_message(ssl, &cbb);
 
   SSL_SESSION_free(session_copy);
   CBB_cleanup(&cbb);
diff --git a/ssl/internal.h b/ssl/internal.h
index 6b57971..64cc597 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1268,9 +1268,15 @@
    * root CBB to be passed into |finish_message|. |*body| is set to a child CBB
    * the caller should write to. It returns one on success and zero on error. */
   int (*init_message)(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
-  /* finish_message finishes a handshake message and prepares it to be
-   * written. It returns one on success and zero on error. */
-  int (*finish_message)(SSL *ssl, CBB *cbb);
+  /* finish_message finishes a handshake message. It sets |*out_msg| to a
+   * newly-allocated buffer with the serialized message. The caller must
+   * release it with |OPENSSL_free| when done. It returns one on success and
+   * zero on error. */
+  int (*finish_message)(SSL *ssl, CBB *cbb, uint8_t **out_msg, size_t *out_len);
+  /* queue_message queues a handshake message and prepares it to be written. It
+   * takes ownership of |msg| and releases it with |OPENSSL_free| when done. It
+   * returns one on success and zero on error. */
+  int (*queue_message)(SSL *ssl, uint8_t *msg, size_t len);
   /* write_message writes the next message to the transport. It returns one on
    * success and <= 0 on error. */
   int (*write_message)(SSL *ssl);
@@ -1720,16 +1726,23 @@
 int ssl3_connect(SSL *ssl);
 
 int ssl3_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
-int ssl3_finish_message(SSL *ssl, CBB *cbb);
+int ssl3_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg, size_t *out_len);
+int ssl3_queue_message(SSL *ssl, uint8_t *msg, size_t len);
 int ssl3_write_message(SSL *ssl);
 
 void ssl3_expect_flight(SSL *ssl);
 void ssl3_received_flight(SSL *ssl);
 
 int dtls1_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
-int dtls1_finish_message(SSL *ssl, CBB *cbb);
+int dtls1_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg,
+                         size_t *out_len);
+int dtls1_queue_message(SSL *ssl, uint8_t *msg, size_t len);
 int dtls1_write_message(SSL *ssl);
 
+/* ssl_complete_message calls |finish_message| and |queue_message| on |cbb| to
+ * queue the message for writing. */
+int ssl_complete_message(SSL *ssl, CBB *cbb);
+
 /* dtls1_get_record reads a new input record. On success, it places it in
  * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if
  * more data is needed. */
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 11aeed0..4cb37bc 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -205,18 +205,21 @@
   return 1;
 }
 
-int ssl3_finish_message(SSL *ssl, CBB *cbb) {
-  if (ssl->s3->pending_message != NULL) {
+int ssl3_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg,
+                        size_t *out_len) {
+  if (!CBB_finish(cbb, out_msg, out_len)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    OPENSSL_free(*out_msg);
     return 0;
   }
+  return 1;
+}
 
-  uint8_t *msg = NULL;
-  size_t len;
-  if (!CBB_finish(cbb, &msg, &len) ||
+int ssl3_queue_message(SSL *ssl, uint8_t *msg, size_t len) {
+  if (ssl->s3->pending_message != NULL ||
       len > 0xffffffffu) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     OPENSSL_free(msg);
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     return 0;
   }
 
@@ -227,6 +230,17 @@
   return 1;
 }
 
+int ssl_complete_message(SSL *ssl, CBB *cbb) {
+  uint8_t *msg = NULL;
+  size_t len;
+  if (!ssl->method->finish_message(ssl, cbb, &msg, &len) ||
+      !ssl->method->queue_message(ssl, msg, len)) {
+    return 0;
+  }
+
+  return 1;
+}
+
 int ssl3_write_message(SSL *ssl) {
   if (ssl->s3->pending_message == NULL) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
@@ -284,7 +298,7 @@
   CBB cbb, body;
   if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_FINISHED) ||
       !CBB_add_bytes(&body, finished, finished_len) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     CBB_cleanup(&cbb);
     return -1;
@@ -352,7 +366,7 @@
   CBB cbb, body;
   if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CERTIFICATE) ||
       !ssl_add_cert_chain(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
     CBB_cleanup(&cbb);
     return 0;
diff --git a/ssl/tls13_both.c b/ssl/tls13_both.c
index 75be849..56ca9fc 100644
--- a/ssl/tls13_both.c
+++ b/ssl/tls13_both.c
@@ -329,7 +329,7 @@
       /* The request context is always empty in the handshake. */
       !CBB_add_u8(&body, 0) ||
       !ssl_add_cert_chain(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     CBB_cleanup(&cbb);
     return 0;
   }
@@ -387,7 +387,7 @@
   }
 
   if (!CBB_did_write(&child, sig_len) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
@@ -412,7 +412,7 @@
   CBB cbb, body;
   if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_FINISHED) ||
       !CBB_add_bytes(&body, verify_data, verify_data_len) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     CBB_cleanup(&cbb);
     return 0;
   }
diff --git a/ssl/tls13_client.c b/ssl/tls13_client.c
index fd60bd3..4b0b56b 100644
--- a/ssl/tls13_client.c
+++ b/ssl/tls13_client.c
@@ -168,7 +168,7 @@
   CBB cbb, body;
   if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CLIENT_HELLO) ||
       !ssl_add_client_hello_body(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     CBB_cleanup(&cbb);
     return ssl_hs_error;
   }
@@ -602,7 +602,7 @@
   CBB cbb, body;
   if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) ||
       !tls1_write_channel_id(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     CBB_cleanup(&cbb);
     return ssl_hs_error;
   }
diff --git a/ssl/tls13_server.c b/ssl/tls13_server.c
index 49f8c00..446dd1c 100644
--- a/ssl/tls13_server.c
+++ b/ssl/tls13_server.c
@@ -310,7 +310,7 @@
       !CBB_add_u16(&extensions, TLSEXT_TYPE_key_share) ||
       !CBB_add_u16(&extensions, 2 /* length */) ||
       !CBB_add_u16(&extensions, group_id) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     CBB_cleanup(&cbb);
     return ssl_hs_error;
   }
@@ -378,7 +378,7 @@
     }
   }
 
-  if (!ssl->method->finish_message(ssl, &cbb)) {
+  if (!ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
@@ -400,7 +400,7 @@
   if (!ssl->method->init_message(ssl, &cbb, &body,
                                  SSL3_MT_ENCRYPTED_EXTENSIONS) ||
       !ssl_add_serverhello_tlsext(ssl, &body) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     CBB_cleanup(&cbb);
     return ssl_hs_error;
   }
@@ -445,7 +445,7 @@
 
   if (!ssl_add_client_CA_list(ssl, &body) ||
       !CBB_add_u16(&body, 0 /* empty certificate_extensions. */) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
+      !ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
@@ -637,7 +637,7 @@
     goto err;
   }
 
-  if (!ssl->method->finish_message(ssl, &cbb)) {
+  if (!ssl_complete_message(ssl, &cbb)) {
     goto err;
   }
 
diff --git a/ssl/tls_method.c b/ssl/tls_method.c
index 8bcdf8f..0c7a952 100644
--- a/ssl/tls_method.c
+++ b/ssl/tls_method.c
@@ -140,6 +140,7 @@
     ssl3_supports_cipher,
     ssl3_init_message,
     ssl3_finish_message,
+    ssl3_queue_message,
     ssl3_write_message,
     ssl3_send_change_cipher_spec,
     ssl3_expect_flight,