Only have one ClientHello parser, not three.

Between TLS 1.2, TLS 1.3, and the early callback, we've got a lot of
ClientHello parsers. Unify everything on the early callback's parser. As
a side effect, this means we can parse a ClientHello fairly succinctly
from any function which will let us split up ClientHello states where
appropriate.

Change-Id: I2359b75f80926cc7d827570cf33f93029b39e525
Reviewed-on: https://boringssl-review.googlesource.com/10184
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 af77f99..d8c472d 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2919,6 +2919,9 @@
   SSL *ssl;
   const uint8_t *client_hello;
   size_t client_hello_len;
+  uint16_t version;
+  const uint8_t *random;
+  size_t random_len;
   const uint8_t *session_id;
   size_t session_id_len;
   const uint8_t *cipher_suites;
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index a6d26d1..d10d7f5 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -534,74 +534,54 @@
   int al = SSL_AD_INTERNAL_ERROR, ret = -1;
   const SSL_CIPHER *c;
   STACK_OF(SSL_CIPHER) *ciphers = NULL;
-  struct ssl_early_callback_ctx early_ctx;
-  CBS client_hello;
-  uint16_t client_wire_version;
-  CBS client_random, session_id, cipher_suites, compression_methods;
   SSL_SESSION *session = NULL;
 
-  /* We do this so that we will respond with our native type. If we are TLSv1
-   * and we get SSLv3, we will respond with TLSv1, This down switching should
-   * be handled by a different method. If we are SSLv3, we will respond with
-   * SSLv3, even if prompted with TLSv1. */
-  switch (ssl->state) {
-    case SSL3_ST_SR_CLNT_HELLO_A: {
-      int msg_ret = ssl->method->ssl_get_message(ssl, SSL3_MT_CLIENT_HELLO,
-                                                 ssl_hash_message);
-      if (msg_ret <= 0) {
-        return msg_ret;
-      }
-
-      ssl->state = SSL3_ST_SR_CLNT_HELLO_B;
+  if (ssl->state == SSL3_ST_SR_CLNT_HELLO_A) {
+    /* The first time around, read the ClientHello. */
+    int msg_ret = ssl->method->ssl_get_message(ssl, SSL3_MT_CLIENT_HELLO,
+                                               ssl_hash_message);
+    if (msg_ret <= 0) {
+      return msg_ret;
     }
-      /* fallthrough */
-    case SSL3_ST_SR_CLNT_HELLO_B:
-    case SSL3_ST_SR_CLNT_HELLO_C:
-      if (!ssl_early_callback_init(ssl, &early_ctx, ssl->init_msg,
-                                   ssl->init_num)) {
-        al = SSL_AD_DECODE_ERROR;
-        OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
-        goto f_err;
-      }
 
-      if (ssl->state == SSL3_ST_SR_CLNT_HELLO_B &&
-          ssl->ctx->select_certificate_cb != NULL) {
-        ssl->state = SSL3_ST_SR_CLNT_HELLO_C;
-        switch (ssl->ctx->select_certificate_cb(&early_ctx)) {
-          case 0:
-            ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING;
-            goto err;
-
-          case -1:
-            /* Connection rejected. */
-            al = SSL_AD_ACCESS_DENIED;
-            OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
-            goto f_err;
-
-          default:
-            /* fallthrough */;
-        }
-      }
-      ssl->state = SSL3_ST_SR_CLNT_HELLO_C;
-      break;
-
-    default:
-      OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE);
-      return -1;
+    ssl->state = SSL3_ST_SR_CLNT_HELLO_B;
   }
 
-  CBS_init(&client_hello, ssl->init_msg, ssl->init_num);
-  if (!CBS_get_u16(&client_hello, &client_wire_version)) {
+  struct ssl_early_callback_ctx client_hello;
+  if (!ssl_early_callback_init(ssl, &client_hello, ssl->init_msg,
+                               ssl->init_num)) {
     al = SSL_AD_DECODE_ERROR;
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     goto f_err;
   }
 
-  uint16_t client_version = ssl->method->version_from_wire(client_wire_version);
+  if (ssl->state == SSL3_ST_SR_CLNT_HELLO_B) {
+    /* Unlike other callbacks, the early callback is not run a second time if
+     * paused. */
+    ssl->state = SSL3_ST_SR_CLNT_HELLO_C;
 
-  /* use version from inside client hello, not from record header (may differ:
-   * see RFC 2246, Appendix E, second paragraph) */
-  ssl->client_version = client_wire_version;
+    /* Run the early callback. */
+    if (ssl->ctx->select_certificate_cb != NULL) {
+      switch (ssl->ctx->select_certificate_cb(&client_hello)) {
+        case 0:
+          ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING;
+          goto err;
+
+        case -1:
+          /* Connection rejected. */
+          al = SSL_AD_ACCESS_DENIED;
+          OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
+          goto f_err;
+
+        default:
+          /* fallthrough */;
+      }
+    }
+  }
+
+  uint16_t client_version =
+      ssl->method->version_from_wire(client_hello.version);
+  ssl->client_version = client_hello.version;
 
   uint16_t min_version, max_version;
   if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
@@ -642,30 +622,16 @@
     return 1;
   }
 
-  if (!CBS_get_bytes(&client_hello, &client_random, SSL3_RANDOM_SIZE) ||
-      !CBS_get_u8_length_prefixed(&client_hello, &session_id) ||
-      CBS_len(&session_id) > SSL_MAX_SSL_SESSION_ID_LENGTH) {
-    al = SSL_AD_DECODE_ERROR;
-    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-    goto f_err;
-  }
-
   /* Load the client random. */
-  memcpy(ssl->s3->client_random, CBS_data(&client_random), SSL3_RANDOM_SIZE);
-
-  if (SSL_is_dtls(ssl)) {
-    CBS cookie;
-
-    if (!CBS_get_u8_length_prefixed(&client_hello, &cookie) ||
-        CBS_len(&cookie) > DTLS1_COOKIE_LENGTH) {
-      al = SSL_AD_DECODE_ERROR;
-      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-      goto f_err;
-    }
+  if (client_hello.random_len != SSL3_RANDOM_SIZE) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    return -1;
   }
+  memcpy(ssl->s3->client_random, client_hello.random, client_hello.random_len);
 
   int send_new_ticket = 0;
-  switch (ssl_get_prev_session(ssl, &session, &send_new_ticket, &early_ctx)) {
+  switch (
+      ssl_get_prev_session(ssl, &session, &send_new_ticket, &client_hello)) {
     case ssl_session_success:
       break;
     case ssl_session_error:
@@ -683,7 +649,7 @@
   CBS ems;
   int have_extended_master_secret =
       ssl->version != SSL3_VERSION &&
-      ssl_early_callback_get_extension(&early_ctx, &ems,
+      ssl_early_callback_get_extension(&client_hello, &ems,
                                        TLSEXT_TYPE_extended_master_secret) &&
       CBS_len(&ems) == 0;
 
@@ -725,24 +691,14 @@
   }
 
   if (ssl->ctx->dos_protection_cb != NULL &&
-      ssl->ctx->dos_protection_cb(&early_ctx) == 0) {
+      ssl->ctx->dos_protection_cb(&client_hello) == 0) {
     /* Connection rejected for DOS reasons. */
     al = SSL_AD_ACCESS_DENIED;
     OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
     goto f_err;
   }
 
-  if (!CBS_get_u16_length_prefixed(&client_hello, &cipher_suites) ||
-      CBS_len(&cipher_suites) == 0 ||
-      CBS_len(&cipher_suites) % 2 != 0 ||
-      !CBS_get_u8_length_prefixed(&client_hello, &compression_methods) ||
-      CBS_len(&compression_methods) == 0) {
-    al = SSL_AD_DECODE_ERROR;
-    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-    goto f_err;
-  }
-
-  ciphers = ssl_bytes_to_cipher_list(ssl, &cipher_suites, max_version);
+  ciphers = ssl_parse_client_cipher_list(ssl, &client_hello, max_version);
   if (ciphers == NULL) {
     goto err;
   }
@@ -771,28 +727,19 @@
   }
 
   /* Only null compression is supported. */
-  if (memchr(CBS_data(&compression_methods), 0,
-             CBS_len(&compression_methods)) == NULL) {
+  if (memchr(client_hello.compression_methods, 0,
+             client_hello.compression_methods_len) == NULL) {
     al = SSL_AD_ILLEGAL_PARAMETER;
     OPENSSL_PUT_ERROR(SSL, SSL_R_NO_COMPRESSION_SPECIFIED);
     goto f_err;
   }
 
   /* TLS extensions. */
-  if (ssl->version >= SSL3_VERSION &&
-      !ssl_parse_clienthello_tlsext(ssl, &client_hello)) {
+  if (!ssl_parse_clienthello_tlsext(ssl, &client_hello)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
     goto err;
   }
 
-  /* There should be nothing left over in the record. */
-  if (CBS_len(&client_hello) != 0) {
-    /* wrong packet length */
-    al = SSL_AD_DECODE_ERROR;
-    OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH);
-    goto f_err;
-  }
-
   if (have_extended_master_secret != ssl->s3->tmp.extended_master_secret) {
     al = SSL_AD_INTERNAL_ERROR;
     OPENSSL_PUT_ERROR(SSL, SSL_R_EMS_STATE_INCONSISTENT);
diff --git a/ssl/internal.h b/ssl/internal.h
index f64dc62..77759e4 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -958,6 +958,20 @@
                    size_t secret_len);
 
 
+/* ClientHello functions. */
+
+int ssl_early_callback_init(SSL *ssl, struct ssl_early_callback_ctx *ctx,
+                            const uint8_t *in, size_t in_len);
+
+int ssl_early_callback_get_extension(const struct ssl_early_callback_ctx *ctx,
+                                     CBS *out, uint16_t extension_type);
+
+STACK_OF(SSL_CIPHER) *
+    ssl_parse_client_cipher_list(SSL *ssl,
+                                 const struct ssl_early_callback_ctx *ctx,
+                                 uint16_t max_version);
+
+
 /* Underdocumented functions.
  *
  * Functions below here haven't been touched up and may be underdocumented. */
@@ -1239,8 +1253,6 @@
 OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session,
                                             int include_ticket);
 
-STACK_OF(SSL_CIPHER) *
-    ssl_bytes_to_cipher_list(SSL *ssl, const CBS *cbs, uint16_t max_version);
 void ssl_cipher_preference_list_free(
     struct ssl_cipher_preference_list_st *cipher_list);
 struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *ssl);
@@ -1370,12 +1382,6 @@
 int tls1_generate_master_secret(SSL *ssl, uint8_t *out, const uint8_t *premaster,
                                 size_t premaster_len);
 
-int ssl_early_callback_init(SSL *ssl, struct ssl_early_callback_ctx *ctx,
-                            const uint8_t *in, size_t in_len);
-
-int ssl_early_callback_get_extension(const struct ssl_early_callback_ctx *ctx,
-                                     CBS *out, uint16_t extension_type);
-
 /* tls1_get_grouplist sets |*out_group_ids| and |*out_group_ids_len| to the
  * list of allowed group IDs. If |get_peer_groups| is non-zero, return the
  * peer's group list. Otherwise, return the preferred list. */
@@ -1412,7 +1418,8 @@
 int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len);
 
 int ssl_add_serverhello_tlsext(SSL *ssl, CBB *out);
-int ssl_parse_clienthello_tlsext(SSL *ssl, CBS *cbs);
+int ssl_parse_clienthello_tlsext(
+    SSL *ssl, const struct ssl_early_callback_ctx *client_hello);
 int ssl_parse_serverhello_tlsext(SSL *ssl, CBS *cbs);
 
 #define tlsext_tick_md EVP_sha256
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 6a2dae8..04477e5 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1630,21 +1630,15 @@
 }
 
 STACK_OF(SSL_CIPHER) *
-    ssl_bytes_to_cipher_list(SSL *ssl, const CBS *cbs, uint16_t max_version) {
-  CBS cipher_suites = *cbs;
-  const SSL_CIPHER *c;
-  STACK_OF(SSL_CIPHER) *sk;
+    ssl_parse_client_cipher_list(SSL *ssl,
+                                 const struct ssl_early_callback_ctx *ctx,
+                                 uint16_t max_version) {
+  CBS cipher_suites;
+  CBS_init(&cipher_suites, ctx->cipher_suites, ctx->cipher_suites_len);
 
-  if (ssl->s3) {
-    ssl->s3->send_connection_binding = 0;
-  }
+  ssl->s3->send_connection_binding = 0;
 
-  if (CBS_len(&cipher_suites) % 2 != 0) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
-    return NULL;
-  }
-
-  sk = sk_SSL_CIPHER_new_null();
+  STACK_OF(SSL_CIPHER) *sk = sk_SSL_CIPHER_new_null();
   if (sk == NULL) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     goto err;
@@ -1654,7 +1648,7 @@
     uint16_t cipher_suite;
 
     if (!CBS_get_u16(&cipher_suites, &cipher_suite)) {
-      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+      OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
       goto err;
     }
 
@@ -1680,7 +1674,7 @@
       continue;
     }
 
-    c = SSL_get_cipher_by_value(cipher_suite);
+    const SSL_CIPHER *c = SSL_get_cipher_by_value(cipher_suite);
     if (c != NULL && !sk_SSL_CIPHER_push(sk, c)) {
       OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
       goto err;
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 695f081..64b2dac 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -209,43 +209,39 @@
   ctx->client_hello = in;
   ctx->client_hello_len = in_len;
 
-  CBS client_hello, session_id, cipher_suites, compression_methods, extensions;
+  CBS client_hello, random, session_id;
   CBS_init(&client_hello, ctx->client_hello, ctx->client_hello_len);
-
-  if (/* Skip client version. */
-      !CBS_skip(&client_hello, 2) ||
-      /* Skip client nonce. */
-      !CBS_skip(&client_hello, 32) ||
-      /* Extract session_id. */
-      !CBS_get_u8_length_prefixed(&client_hello, &session_id)) {
+  if (!CBS_get_u16(&client_hello, &ctx->version) ||
+      !CBS_get_bytes(&client_hello, &random, SSL3_RANDOM_SIZE) ||
+      !CBS_get_u8_length_prefixed(&client_hello, &session_id) ||
+      CBS_len(&session_id) > SSL_MAX_SSL_SESSION_ID_LENGTH) {
     return 0;
   }
 
+  ctx->random = CBS_data(&random);
+  ctx->random_len = CBS_len(&random);
   ctx->session_id = CBS_data(&session_id);
   ctx->session_id_len = CBS_len(&session_id);
 
   /* Skip past DTLS cookie */
   if (SSL_is_dtls(ctx->ssl)) {
     CBS cookie;
-
-    if (!CBS_get_u8_length_prefixed(&client_hello, &cookie)) {
+    if (!CBS_get_u8_length_prefixed(&client_hello, &cookie) ||
+        CBS_len(&cookie) > DTLS1_COOKIE_LENGTH) {
       return 0;
     }
   }
 
-  /* Extract cipher_suites. */
+  CBS cipher_suites, compression_methods;
   if (!CBS_get_u16_length_prefixed(&client_hello, &cipher_suites) ||
-      CBS_len(&cipher_suites) < 2 || (CBS_len(&cipher_suites) & 1) != 0) {
-    return 0;
-  }
-  ctx->cipher_suites = CBS_data(&cipher_suites);
-  ctx->cipher_suites_len = CBS_len(&cipher_suites);
-
-  /* Extract compression_methods. */
-  if (!CBS_get_u8_length_prefixed(&client_hello, &compression_methods) ||
+      CBS_len(&cipher_suites) < 2 || (CBS_len(&cipher_suites) & 1) != 0 ||
+      !CBS_get_u8_length_prefixed(&client_hello, &compression_methods) ||
       CBS_len(&compression_methods) < 1) {
     return 0;
   }
+
+  ctx->cipher_suites = CBS_data(&cipher_suites);
+  ctx->cipher_suites_len = CBS_len(&cipher_suites);
   ctx->compression_methods = CBS_data(&compression_methods);
   ctx->compression_methods_len = CBS_len(&compression_methods);
 
@@ -258,11 +254,13 @@
   }
 
   /* Extract extensions and check it is valid. */
+  CBS extensions;
   if (!CBS_get_u16_length_prefixed(&client_hello, &extensions) ||
       !tls1_check_duplicate_extensions(&extensions) ||
       CBS_len(&client_hello) != 0) {
     return 0;
   }
+
   ctx->extensions = CBS_data(&extensions);
   ctx->extensions_len = CBS_len(&extensions);
 
@@ -2512,7 +2510,9 @@
   return 0;
 }
 
-static int ssl_scan_clienthello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) {
+static int ssl_scan_clienthello_tlsext(
+    SSL *ssl, const struct ssl_early_callback_ctx *client_hello,
+    int *out_alert) {
   size_t i;
   for (i = 0; i < kNumExtensions; i++) {
     if (kExtensions[i].init != NULL) {
@@ -2527,53 +2527,44 @@
    * sent as an SCSV. */
   assert(kExtensions[0].value == TLSEXT_TYPE_renegotiate);
 
-  /* There may be no extensions. */
-  if (CBS_len(cbs) != 0) {
-    /* Decode the extensions block and check it is valid. */
-    CBS extensions;
-    if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
-        !tls1_check_duplicate_extensions(&extensions)) {
+  CBS extensions;
+  CBS_init(&extensions, client_hello->extensions, client_hello->extensions_len);
+  while (CBS_len(&extensions) != 0) {
+    uint16_t type;
+    CBS extension;
+
+    /* Decode the next extension. */
+    if (!CBS_get_u16(&extensions, &type) ||
+        !CBS_get_u16_length_prefixed(&extensions, &extension)) {
       *out_alert = SSL_AD_DECODE_ERROR;
       return 0;
     }
 
-    while (CBS_len(&extensions) != 0) {
-      uint16_t type;
-      CBS extension;
+    /* RFC 5746 made the existence of extensions in SSL 3.0 somewhat
+     * ambiguous. Ignore all but the renegotiation_info extension. */
+    if (ssl->version == SSL3_VERSION && type != TLSEXT_TYPE_renegotiate) {
+      continue;
+    }
 
-      /* Decode the next extension. */
-      if (!CBS_get_u16(&extensions, &type) ||
-          !CBS_get_u16_length_prefixed(&extensions, &extension)) {
-        *out_alert = SSL_AD_DECODE_ERROR;
-        return 0;
-      }
+    unsigned ext_index;
+    const struct tls_extension *const ext =
+        tls_extension_find(&ext_index, type);
 
-      /* RFC 5746 made the existence of extensions in SSL 3.0 somewhat
-       * ambiguous. Ignore all but the renegotiation_info extension. */
-      if (ssl->version == SSL3_VERSION && type != TLSEXT_TYPE_renegotiate) {
-        continue;
-      }
-
-      unsigned ext_index;
-      const struct tls_extension *const ext =
-          tls_extension_find(&ext_index, type);
-
-      if (ext == NULL) {
-        if (!custom_ext_parse_clienthello(ssl, out_alert, type, &extension)) {
-          OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
-          return 0;
-        }
-        continue;
-      }
-
-      ssl->s3->tmp.extensions.received |= (1u << ext_index);
-      uint8_t alert = SSL_AD_DECODE_ERROR;
-      if (!ext->parse_clienthello(ssl, &alert, &extension)) {
-        *out_alert = alert;
+    if (ext == NULL) {
+      if (!custom_ext_parse_clienthello(ssl, out_alert, type, &extension)) {
         OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
-        ERR_add_error_dataf("extension: %u", (unsigned)type);
         return 0;
       }
+      continue;
+    }
+
+    ssl->s3->tmp.extensions.received |= (1u << ext_index);
+    uint8_t alert = SSL_AD_DECODE_ERROR;
+    if (!ext->parse_clienthello(ssl, &alert, &extension)) {
+      *out_alert = alert;
+      OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
+      ERR_add_error_dataf("extension: %u", (unsigned)type);
+      return 0;
     }
   }
 
@@ -2594,9 +2585,10 @@
   return 1;
 }
 
-int ssl_parse_clienthello_tlsext(SSL *ssl, CBS *cbs) {
+int ssl_parse_clienthello_tlsext(
+    SSL *ssl, const struct ssl_early_callback_ctx *client_hello) {
   int alert = -1;
-  if (ssl_scan_clienthello_tlsext(ssl, cbs, &alert) <= 0) {
+  if (ssl_scan_clienthello_tlsext(ssl, client_hello, &alert) <= 0) {
     ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
     return 0;
   }
diff --git a/ssl/tls13_server.c b/ssl/tls13_server.c
index 1ece104..96ceb79 100644
--- a/ssl/tls13_server.c
+++ b/ssl/tls13_server.c
@@ -105,36 +105,22 @@
     return ssl_hs_error;
   }
 
-  struct ssl_early_callback_ctx early_ctx;
-  if (!ssl_early_callback_init(ssl, &early_ctx, ssl->init_msg,
+  struct ssl_early_callback_ctx client_hello;
+  if (!ssl_early_callback_init(ssl, &client_hello, ssl->init_msg,
                                ssl->init_num)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
     return ssl_hs_error;
   }
 
-  CBS cbs, client_random, session_id, cipher_suites, compression_methods;
-  uint16_t client_wire_version;
-  CBS_init(&cbs, ssl->init_msg, ssl->init_num);
-  if (!CBS_get_u16(&cbs, &client_wire_version) ||
-      !CBS_get_bytes(&cbs, &client_random, SSL3_RANDOM_SIZE) ||
-      !CBS_get_u8_length_prefixed(&cbs, &session_id) ||
-      CBS_len(&session_id) > SSL_MAX_SSL_SESSION_ID_LENGTH) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-    return ssl_hs_error;
-  }
-
-  uint16_t min_version, max_version;
-  if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
-    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-    return ssl_hs_error;
-  }
-
   assert(ssl->s3->have_version);
 
   /* Load the client random. */
-  memcpy(ssl->s3->client_random, CBS_data(&client_random), SSL3_RANDOM_SIZE);
+  if (client_hello.random_len != SSL3_RANDOM_SIZE) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    return -1;
+  }
+  memcpy(ssl->s3->client_random, client_hello.random, client_hello.random_len);
 
   SSL_set_session(ssl, NULL);
   if (!ssl_get_new_session(ssl, 1 /* server */)) {
@@ -143,44 +129,27 @@
   }
 
   if (ssl->ctx->dos_protection_cb != NULL &&
-      ssl->ctx->dos_protection_cb(&early_ctx) == 0) {
+      ssl->ctx->dos_protection_cb(&client_hello) == 0) {
     /* Connection rejected for DOS reasons. */
     OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ACCESS_DENIED);
     return ssl_hs_error;
   }
 
-  if (!CBS_get_u16_length_prefixed(&cbs, &cipher_suites) ||
-      CBS_len(&cipher_suites) == 0 ||
-      CBS_len(&cipher_suites) % 2 != 0 ||
-      !CBS_get_u8_length_prefixed(&cbs, &compression_methods) ||
-      CBS_len(&compression_methods) == 0) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-    return ssl_hs_error;
-  }
-
   /* TLS 1.3 requires the peer only advertise the null compression. */
-  if (CBS_len(&compression_methods) != 1 ||
-      CBS_data(&compression_methods)[0] != 0) {
+  if (client_hello.compression_methods_len != 1 ||
+      client_hello.compression_methods[0] != 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMPRESSION_LIST);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
     return ssl_hs_error;
   }
 
   /* TLS extensions. */
-  if (!ssl_parse_clienthello_tlsext(ssl, &cbs)) {
+  if (!ssl_parse_clienthello_tlsext(ssl, &client_hello)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
     return ssl_hs_error;
   }
 
-  /* There should be nothing left over in the message. */
-  if (CBS_len(&cbs) != 0) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH);
-    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-    return ssl_hs_error;
-  }
-
   /* Let cert callback update server certificates if required.
    *
    * TODO(davidben): Can this get run earlier? */
@@ -197,8 +166,14 @@
     }
   }
 
+  uint16_t min_version, max_version;
+  if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+    return ssl_hs_error;
+  }
+
   STACK_OF(SSL_CIPHER) *ciphers =
-      ssl_bytes_to_cipher_list(ssl, &cipher_suites, max_version);
+      ssl_parse_client_cipher_list(ssl, &client_hello, max_version);
   if (ciphers == NULL) {
     return ssl_hs_error;
   }
@@ -232,7 +207,7 @@
 
   /* Resolve ECDHE and incorporate it into the secret. */
   int need_retry;
-  if (!resolve_ecdhe_secret(ssl, &need_retry, &early_ctx)) {
+  if (!resolve_ecdhe_secret(ssl, &need_retry, &client_hello)) {
     if (need_retry) {
       hs->state = state_send_hello_retry_request;
       return ssl_hs_ok;
@@ -276,8 +251,8 @@
     return ssl_hs_error;
   }
 
-  struct ssl_early_callback_ctx early_ctx;
-  if (!ssl_early_callback_init(ssl, &early_ctx, ssl->init_msg,
+  struct ssl_early_callback_ctx client_hello;
+  if (!ssl_early_callback_init(ssl, &client_hello, ssl->init_msg,
                                ssl->init_num)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
     ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
@@ -285,7 +260,7 @@
   }
 
   int need_retry;
-  if (!resolve_ecdhe_secret(ssl, &need_retry, &early_ctx)) {
+  if (!resolve_ecdhe_secret(ssl, &need_retry, &client_hello)) {
     if (need_retry) {
       /* Only send one HelloRetryRequest. */
       ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);