Add tests for the padding extension.

This sort of test is more suitable for ssl_test than runner. This should
stress all the various cases around padding. Use tickets rather than
hostnames to inflate the ClientHello because there's a fairly tight
maximum hostname length.

Change-Id: Ibd43aaa7acb9bf5fa00a9d2548d2101e5bb147d3
Reviewed-on: https://boringssl-review.googlesource.com/5480
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
index 9f2ddb9..f31e5a1 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -549,6 +549,112 @@
   return true;
 }
 
+// CreateSessionWithTicket returns a sample |SSL_SESSION| with the ticket
+// replaced for one of length |ticket_len| or nullptr on failure.
+static ScopedSSL_SESSION CreateSessionWithTicket(size_t ticket_len) {
+  std::vector<uint8_t> der;
+  if (!DecodeBase64(&der, kOpenSSLSession)) {
+    return nullptr;
+  }
+  ScopedSSL_SESSION session(SSL_SESSION_from_bytes(bssl::vector_data(&der),
+                                                   der.size()));
+  if (!session) {
+    return nullptr;
+  }
+
+  // Swap out the ticket for a garbage one.
+  OPENSSL_free(session->tlsext_tick);
+  session->tlsext_tick = reinterpret_cast<uint8_t*>(OPENSSL_malloc(ticket_len));
+  if (session->tlsext_tick == nullptr) {
+    return nullptr;
+  }
+  memset(session->tlsext_tick, 'a', ticket_len);
+  session->tlsext_ticklen = ticket_len;
+  return session;
+}
+
+// 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.
+static size_t GetClientHelloLen(size_t ticket_len) {
+  ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method()));
+  ScopedSSL_SESSION session = CreateSessionWithTicket(ticket_len);
+  if (!ctx || !session) {
+    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())) {
+    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.
+    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;
+}
+
+struct PaddingTest {
+  size_t input_len, padded_len;
+};
+
+static const PaddingTest kPaddingTests[] = {
+    // ClientHellos of length below 0x100 do not require padding.
+    {0xfe, 0xfe},
+    {0xff, 0xff},
+    // ClientHellos of length 0x100 through 0x1fb are padded up to 0x200.
+    {0x100, 0x200},
+    {0x123, 0x200},
+    {0x1fb, 0x200},
+    // ClientHellos of length 0x1fc through 0x1ff get padded beyond 0x200. The
+    // padding extension takes a minimum of four bytes plus one required content
+    // byte. (To work around yet more server bugs, we avoid empty final
+    // extensions.)
+    {0x1fc, 0x201},
+    {0x1fd, 0x202},
+    {0x1fe, 0x203},
+    {0x1ff, 0x204},
+    // Finally, larger ClientHellos need no padding.
+    {0x200, 0x200},
+    {0x201, 0x201},
+};
+
+static bool TestPaddingExtension() {
+  // Sample a baseline length.
+  size_t base_len = GetClientHelloLen(1);
+  if (base_len == 0) {
+    return false;
+  }
+
+  for (const PaddingTest &test : kPaddingTests) {
+    if (base_len > test.input_len) {
+      fprintf(stderr, "Baseline ClientHello too long.\n");
+      return false;
+    }
+
+    size_t padded_len = GetClientHelloLen(1 + test.input_len - base_len);
+    if (padded_len != test.padded_len) {
+      fprintf(stderr, "%u-byte ClientHello padded to %u bytes, not %u.\n",
+              static_cast<unsigned>(test.input_len),
+              static_cast<unsigned>(padded_len),
+              static_cast<unsigned>(test.padded_len));
+      return false;
+    }
+  }
+  return true;
+}
+
 int main(void) {
   SSL_library_init();
 
@@ -566,7 +672,8 @@
       !TestDefaultVersion(0, &DTLS_method) ||
       !TestDefaultVersion(DTLS1_VERSION, &DTLSv1_method) ||
       !TestDefaultVersion(DTLS1_2_VERSION, &DTLSv1_2_method) ||
-      !TestCipherGetRFCName()) {
+      !TestCipherGetRFCName() ||
+      !TestPaddingExtension()) {
     ERR_print_errors_fp(stderr);
     return 1;
   }