diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc index 2ee01248..4653f734 100644 --- a/ssl/ssl_test.cc +++ b/ssl/ssl_test.cc @@ -1941,197 +1941,106 @@ TEST_P(SSLVersionTest, RetainOnlySHA256OfCerts) { EXPECT_EQ(Bytes(cert_sha256), Bytes(session->peer_sha256)); } -static bool ClientHelloMatches(uint16_t version, const uint8_t *expected, - size_t expected_len) { - bssl::UniquePtr ctx(SSL_CTX_new(TLS_method())); - // Our default cipher list varies by CPU capabilities, so manually place the - // ChaCha20 ciphers in front. - const char* cipher_list = "CHACHA20:ALL"; - if (!ctx || - // SSLv3 is off by default. - !SSL_CTX_set_min_proto_version(ctx.get(), SSL3_VERSION) || - !SSL_CTX_set_max_proto_version(ctx.get(), version) || - !SSL_CTX_set_strict_cipher_list(ctx.get(), cipher_list)) { - return false; - } - - bssl::UniquePtr ssl(SSL_new(ctx.get())); - if (!ssl) { - return false; - } - std::vector 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; - } - OPENSSL_memset(client_hello.data() + kRandomOffset, 0, SSL3_RANDOM_SIZE); - - if (client_hello.size() != expected_len || - OPENSSL_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, 0x3b, - 0x01, - 0x00, 0x00, 0x37, - 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, 0x10, - 0xc0, 0x09, - 0xc0, 0x13, - 0xc0, 0x0a, - 0xc0, 0x14, - 0x00, 0x2f, - 0x00, 0x35, - 0x00, 0x0a, - 0x00, 0xff, 0x01, 0x00, - }; - if (!ClientHelloMatches(SSL3_VERSION, kSSL3ClientHello, - sizeof(kSSL3ClientHello))) { - return false; - } - - static const uint8_t kTLS1ClientHello[] = { - 0x16, - 0x03, 0x01, - 0x00, 0x5a, - 0x01, - 0x00, 0x00, 0x56, - 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, 0x0e, - 0xc0, 0x09, - 0xc0, 0x13, - 0xc0, 0x0a, - 0xc0, 0x14, - 0x00, 0x2f, - 0x00, 0x35, - 0x00, 0x0a, +// Tests that our ClientHellos do not change unexpectedly. These are purely +// change detection tests. If they fail as part of an intentional ClientHello +// change, update the test vector. +TEST(SSLTest, ClientHello) { + struct { + uint16_t max_version; + std::vector expected; + } kTests[] = { + {SSL3_VERSION, + {0x16, 0x03, 0x00, 0x00, 0x3b, 0x01, 0x00, 0x00, 0x37, 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, 0x10, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x0a, 0xc0, 0x14, 0x00, + 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x00, 0xff, 0x01, 0x00}}, + {TLS1_VERSION, + {0x16, 0x03, 0x01, 0x00, 0x5a, 0x01, 0x00, 0x00, 0x56, 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, 0x0e, 0xc0, 0x09, + 0xc0, 0x13, 0xc0, 0x0a, 0xc0, 0x14, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 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, 0x5a, - 0x01, - 0x00, 0x00, 0x56, - 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, 0x0e, - 0xc0, 0x09, - 0xc0, 0x13, - 0xc0, 0x0a, - 0xc0, 0x14, - 0x00, 0x2f, - 0x00, 0x35, - 0x00, 0x0a, + 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18}}, + {TLS1_1_VERSION, + {0x16, 0x03, 0x01, 0x00, 0x5a, 0x01, 0x00, 0x00, 0x56, 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, 0x0e, 0xc0, 0x09, + 0xc0, 0x13, 0xc0, 0x0a, 0xc0, 0x14, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 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; - } - - // kTLS12ClientHello assumes RSA-PSS, which is disabled for Android system - // builds. -#if defined(BORINGSSL_ANDROID_SYSTEM) - return true; + 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18}}, + // This test assumes RSA-PSS, which is disabled for Android system builds. +#if !defined(BORINGSSL_ANDROID_SYSTEM) + {TLS1_2_VERSION, + {0x16, 0x03, 0x01, 0x00, 0x8e, 0x01, 0x00, 0x00, 0x8a, 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, 0x2a, 0xcc, 0xa9, + 0xcc, 0xa8, 0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30, 0xc0, 0x09, + 0xc0, 0x23, 0xc0, 0x13, 0xc0, 0x27, 0xc0, 0x0a, 0xc0, 0x24, 0xc0, 0x14, + 0xc0, 0x28, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x35, + 0x00, 0x3d, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x37, 0xff, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, + 0x14, 0x00, 0x12, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, + 0x05, 0x05, 0x01, 0x08, 0x06, 0x06, 0x01, 0x02, 0x01, 0x00, 0x0b, 0x00, + 0x02, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, + 0x17, 0x00, 0x18}}, #endif - - static const uint8_t kTLS12ClientHello[] = { - 0x16, - 0x03, 0x01, - 0x00, 0x8e, - 0x01, - 0x00, 0x00, 0x8a, - 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, 0x2a, - 0xcc, 0xa9, - 0xcc, 0xa8, - 0xc0, 0x2b, - 0xc0, 0x2f, - 0xc0, 0x2c, - 0xc0, 0x30, - 0xc0, 0x09, - 0xc0, 0x23, - 0xc0, 0x13, - 0xc0, 0x27, - 0xc0, 0x0a, - 0xc0, 0x24, - 0xc0, 0x14, - 0xc0, 0x28, - 0x00, 0x9c, - 0x00, 0x9d, - 0x00, 0x2f, - 0x00, 0x3c, - 0x00, 0x35, - 0x00, 0x3d, - 0x00, 0x0a, - 0x01, 0x00, 0x00, 0x37, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00, - 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x14, 0x00, 0x12, 0x04, - 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x08, - 0x06, 0x06, 0x01, 0x02, 0x01, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, - 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, + // TODO(davidben): Add a change detector for TLS 1.3 once the spec and our + // implementation has settled enough that it won't change. }; - if (!ClientHelloMatches(TLS1_2_VERSION, kTLS12ClientHello, - sizeof(kTLS12ClientHello))) { - return false; + + for (const auto &t : kTests) { + SCOPED_TRACE(t.max_version); + + bssl::UniquePtr ctx(SSL_CTX_new(TLS_method())); + ASSERT_TRUE(ctx); + // Our default cipher list varies by CPU capabilities, so manually place the + // ChaCha20 ciphers in front. + const char *cipher_list = "CHACHA20:ALL"; + // SSLv3 is off by default. + ASSERT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), SSL3_VERSION)); + ASSERT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), t.max_version)); + ASSERT_TRUE(SSL_CTX_set_strict_cipher_list(ctx.get(), cipher_list)); + + bssl::UniquePtr ssl(SSL_new(ctx.get())); + ASSERT_TRUE(ssl); + std::vector client_hello; + ASSERT_TRUE(GetClientHello(ssl.get(), &client_hello)); + + // Zero the client_random. + constexpr size_t kRandomOffset = 1 + 2 + 2 + // record header + 1 + 3 + // handshake message header + 2; // client_version + ASSERT_GE(client_hello.size(), kRandomOffset + SSL3_RANDOM_SIZE); + OPENSSL_memset(client_hello.data() + kRandomOffset, 0, SSL3_RANDOM_SIZE); + + if (client_hello != t.expected) { + ADD_FAILURE() << "ClientHellos did not match."; + // Print the value manually so it is easier to update the test vector. + for (size_t i = 0; i < client_hello.size(); i += 12) { + printf(" %c", i == 0 ? '{' : ' '); + for (size_t j = i; j < client_hello.size() && j < i + 12; j++) { + if (j > i) { + printf(" "); + } + printf("0x%02x", client_hello[j]); + if (j < client_hello.size() - 1) { + printf(","); + } + } + if (i + 12 >= client_hello.size()) { + printf("}}"); + } + printf("\n"); + } + } } - - // 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; } static bssl::UniquePtr g_last_session; @@ -3846,8 +3755,7 @@ TEST(SSLTest, AllTests) { !TestPaddingExtension(TLS1_3_VERSION, TLS1_2_VERSION) || // Test the padding extension at TLS 1.3 with a TLS 1.3 session, so there // will be a PSK binder after the padding extension. - !TestPaddingExtension(TLS1_3_VERSION, TLS1_3_DRAFT_VERSION) || - !TestClientHello()) { + !TestPaddingExtension(TLS1_3_VERSION, TLS1_3_DRAFT_VERSION)) { ADD_FAILURE() << "Tests failed"; } }