Add tests to ensure our ClientHello does not change.

We'll need to update it on occasion, but we should not update our
default ClientHello without noticing.

Change-Id: I19ca52fdbe10e3ac14413fecd16be2e58af5a1f6
Reviewed-on: https://boringssl-review.googlesource.com/9075
Reviewed-by: Steven Valdez <svaldez@google.com>
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 86e7942..0dc0884 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -796,6 +796,29 @@
   return session;
 }
 
+static bool GetClientHello(SSL *ssl, std::vector<uint8_t> *out) {
+  ScopedBIO bio(BIO_new(BIO_s_mem()));
+  if (!bio) {
+    return false;
+  }
+  // Do not configure a reading BIO, but record what's written to a memory BIO.
+  SSL_set_bio(ssl, nullptr /* rbio */, BIO_up_ref(bio.get()));
+  int ret = SSL_connect(ssl);
+  if (ret > 0) {
+    // SSL_connect should fail without a BIO to write to.
+    return false;
+  }
+  ERR_clear_error();
+
+  const uint8_t *client_hello;
+  size_t client_hello_len;
+  if (!BIO_mem_contents(bio.get(), &client_hello, &client_hello_len)) {
+    return false;
+  }
+  *out = std::vector<uint8_t>(client_hello, client_hello + client_hello_len);
+  return true;
+}
+
 // GetClientHelloLen creates a client SSL connection with a ticket of length
 // |ticket_len| and records the ClientHello. It returns the length of the
 // ClientHello, not including the record header, on success and zero on error.
@@ -806,26 +829,15 @@
     return 0;
   }
   ScopedSSL ssl(SSL_new(ctx.get()));
-  ScopedBIO bio(BIO_new(BIO_s_mem()));
-  if (!ssl || !bio || !SSL_set_session(ssl.get(), session.get())) {
+  if (!ssl || !SSL_set_session(ssl.get(), session.get())) {
     return 0;
   }
-  // Do not configure a reading BIO, but record what's written to a memory BIO.
-  SSL_set_bio(ssl.get(), nullptr /* rbio */, BIO_up_ref(bio.get()));
-  int ret = SSL_connect(ssl.get());
-  if (ret > 0) {
-    // SSL_connect should fail without a BIO to write to.
+  std::vector<uint8_t> client_hello;
+  if (!GetClientHello(ssl.get(), &client_hello) ||
+      client_hello.size() <= SSL3_RT_HEADER_LENGTH) {
     return 0;
   }
-  ERR_clear_error();
-
-  const uint8_t *unused;
-  size_t client_hello_len;
-  if (!BIO_mem_contents(bio.get(), &unused, &client_hello_len) ||
-      client_hello_len <= SSL3_RT_HEADER_LENGTH) {
-    return 0;
-  }
-  return client_hello_len - SSL3_RT_HEADER_LENGTH;
+  return client_hello.size() - SSL3_RT_HEADER_LENGTH;
 }
 
 struct PaddingTest {
@@ -1575,6 +1587,131 @@
   return true;
 }
 
+static bool ClientHelloMatches(uint16_t version, const uint8_t *expected,
+                               size_t expected_len) {
+  ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method()));
+  if (!ctx) {
+    return false;
+  }
+  SSL_CTX_set_max_version(ctx.get(), version);
+  // Our default cipher list varies by CPU capabilities, so manually place the
+  // ChaCha20 ciphers in front.
+  if (!SSL_CTX_set_cipher_list(ctx.get(), "CHACHA20:ALL")) {
+    return false;
+  }
+  ScopedSSL ssl(SSL_new(ctx.get()));
+  if (!ssl) {
+    return false;
+  }
+  std::vector<uint8_t> client_hello;
+  if (!GetClientHello(ssl.get(), &client_hello)) {
+    return false;
+  }
+
+  // Zero the client_random.
+  constexpr size_t kRandomOffset = 1 + 2 + 2 +  // record header
+                                   1 + 3 +      // handshake message header
+                                   2;           // client_version
+  if (client_hello.size() < kRandomOffset + SSL3_RANDOM_SIZE) {
+    fprintf(stderr, "ClientHello for version %04x too short.\n", version);
+    return false;
+  }
+  memset(client_hello.data() + kRandomOffset, 0, SSL3_RANDOM_SIZE);
+
+  if (client_hello.size() != expected_len ||
+      memcmp(client_hello.data(), expected, expected_len) != 0) {
+    fprintf(stderr, "ClientHello for version %04x did not match:\n", version);
+    fprintf(stderr, "Got:\n\t");
+    for (size_t i = 0; i < client_hello.size(); i++) {
+      fprintf(stderr, "0x%02x, ", client_hello[i]);
+    }
+    fprintf(stderr, "\nWanted:\n\t");
+    for (size_t i = 0; i < expected_len; i++) {
+      fprintf(stderr, "0x%02x, ", expected[i]);
+    }
+    fprintf(stderr, "\n");
+    return false;
+  }
+
+  return true;
+}
+
+// Tests that our ClientHellos do not change unexpectedly.
+static bool TestClientHello() {
+  static const uint8_t kSSL3ClientHello[] = {
+      0x16, 0x03, 0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x43, 0x03, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x1c, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x33, 0xc0, 0x0a, 0xc0,
+      0x14, 0x00, 0x39, 0xc0, 0x07, 0xc0, 0x11, 0x00, 0x2f, 0x00, 0x35,
+      0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x00, 0xff, 0x01, 0x00,
+  };
+  if (!ClientHelloMatches(SSL3_VERSION, kSSL3ClientHello,
+                          sizeof(kSSL3ClientHello))) {
+    return false;
+  }
+
+  static const uint8_t kTLS1ClientHello[] = {
+      0x16, 0x03, 0x01, 0x00, 0x66, 0x01, 0x00, 0x00, 0x62, 0x03, 0x01, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xc0, 0x09,
+      0xc0, 0x13, 0x00, 0x33, 0xc0, 0x0a, 0xc0, 0x14, 0x00, 0x39, 0xc0, 0x07,
+      0xc0, 0x11, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x04,
+      0x01, 0x00, 0x00, 0x1f, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00,
+      0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00,
+      0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
+  };
+  if (!ClientHelloMatches(TLS1_VERSION, kTLS1ClientHello,
+                          sizeof(kTLS1ClientHello))) {
+    return false;
+  }
+
+  static const uint8_t kTLS11ClientHello[] = {
+      0x16, 0x03, 0x01, 0x00, 0x66, 0x01, 0x00, 0x00, 0x62, 0x03, 0x02, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xc0, 0x09,
+      0xc0, 0x13, 0x00, 0x33, 0xc0, 0x0a, 0xc0, 0x14, 0x00, 0x39, 0xc0, 0x07,
+      0xc0, 0x11, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x04,
+      0x01, 0x00, 0x00, 0x1f, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00,
+      0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00,
+      0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
+  };
+  if (!ClientHelloMatches(TLS1_1_VERSION, kTLS11ClientHello,
+                          sizeof(kTLS11ClientHello))) {
+    return false;
+  }
+
+  static const uint8_t kTLS12ClientHello[] = {
+      0x16, 0x03, 0x01, 0x00, 0xa4, 0x01, 0x00, 0x00, 0xa0, 0x03, 0x03, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0xcc, 0xa9,
+      0xcc, 0xa8, 0xcc, 0x14, 0xcc, 0x13, 0xc0, 0x2b, 0xc0, 0x2f, 0x00, 0x9e,
+      0xc0, 0x2c, 0xc0, 0x30, 0x00, 0x9f, 0xc0, 0x09, 0xc0, 0x23, 0xc0, 0x13,
+      0xc0, 0x27, 0x00, 0x33, 0x00, 0x67, 0xc0, 0x0a, 0xc0, 0x24, 0xc0, 0x14,
+      0xc0, 0x28, 0x00, 0x39, 0x00, 0x6b, 0xc0, 0x07, 0xc0, 0x11, 0x00, 0x9c,
+      0x00, 0x9d, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x0a,
+      0x00, 0x05, 0x00, 0x04, 0x01, 0x00, 0x00, 0x35, 0xff, 0x01, 0x00, 0x01,
+      0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00,
+      0x12, 0x00, 0x10, 0x06, 0x01, 0x06, 0x03, 0x05, 0x01, 0x05, 0x03, 0x04,
+      0x01, 0x04, 0x03, 0x02, 0x01, 0x02, 0x03, 0x00, 0x0b, 0x00, 0x02, 0x01,
+      0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00,
+      0x18,
+  };
+  if (!ClientHelloMatches(TLS1_2_VERSION, kTLS12ClientHello,
+                          sizeof(kTLS12ClientHello))) {
+    return false;
+  }
+
+  // TODO(davidben): Add a change detector for TLS 1.3 once the spec and our
+  // implementation has settled enough that it won't change.
+
+  return true;
+}
+
 int main() {
   CRYPTO_library_init();
 
@@ -1605,7 +1742,8 @@
       !TestSetFD() ||
       !TestSetBIO() ||
       !TestGetPeerCertificate() ||
-      !TestRetainOnlySHA256OfCerts()) {
+      !TestRetainOnlySHA256OfCerts() ||
+      !TestClientHello()) {
     ERR_print_errors_fp(stderr);
     return 1;
   }