Work around a Java client bug when rotating certificates.

The Java client implementation of the 3SHAKE mitigation incorrectly
rejects initial handshakes when all of the following are true:

1. The ClientHello offered a session.
2. The session was successfully resumed previously.
3. The server declines the session.
4. The server sends a certificate with a different SAN list than in the
   previous session.

(Note the 3SHAKE mitigation is to reject certificates changes on
renegotiation, while Java's logic applies to initial handshakes as
well.)

The end result is long-lived Java clients break on some certificate
rotations. Fingerprint Java clients and decline all offered sessions.
This avoids (2) while still introducing new sessions to clear any
existing problematic sessions.

See also b/65323005.

Change-Id: Ib2b84c69b5ecba285ffb8c4d03de5626838d794e
Reviewed-on: https://boringssl-review.googlesource.com/20184
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>
This commit is contained in:
David Benjamin 2017-09-11 15:21:43 -04:00 committed by CQ bot account: commit-bot@chromium.org
parent 1682126fd8
commit aba057a4e0
7 changed files with 329 additions and 21 deletions

View File

@ -1440,8 +1440,11 @@ int ssl_log_secret(const SSL *ssl, const char *label, const uint8_t *secret,
// ClientHello functions.
int ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out,
const SSLMessage &msg);
// ssl_client_hello_init parses |msg| as a ClientHello and writes the result to
// |*out|. It returns one on success and zero on error. This function is
// exported for unit tests.
OPENSSL_EXPORT int ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out,
const SSLMessage &msg);
int ssl_client_hello_get_extension(const SSL_CLIENT_HELLO *client_hello,
CBS *out, uint16_t extension_type);
@ -1449,6 +1452,10 @@ int ssl_client_hello_get_extension(const SSL_CLIENT_HELLO *client_hello,
int ssl_client_cipher_list_contains_cipher(const SSL_CLIENT_HELLO *client_hello,
uint16_t id);
// ssl_is_probably_java returns true if |client_hello| looks like a Java
// ClientHello and false otherwise. This function is exported for tests.
OPENSSL_EXPORT bool ssl_is_probably_java(const SSL_CLIENT_HELLO *client_hello);
// GREASE.

View File

@ -721,6 +721,73 @@ static enum ssl_hs_wait_t ssl_lookup_session(
return ssl_hs_ok;
}
bool ssl_is_probably_java(const SSL_CLIENT_HELLO *client_hello) {
CBS extension, groups;
if (SSL_is_dtls(client_hello->ssl) ||
!ssl_client_hello_get_extension(client_hello, &extension,
TLSEXT_TYPE_supported_groups) ||
!CBS_get_u16_length_prefixed(&extension, &groups) ||
CBS_len(&extension) != 0) {
return false;
}
// Original Java curve list.
static const uint8_t kCurveList1[] = {
0x00, 0x17, 0x00, 0x01, 0x00, 0x03, 0x00, 0x13, 0x00, 0x15,
0x00, 0x06, 0x00, 0x07, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x18,
0x00, 0x0b, 0x00, 0x0c, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x0e,
0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x02, 0x00, 0x12,
0x00, 0x04, 0x00, 0x05, 0x00, 0x14, 0x00, 0x08, 0x00, 0x16};
// Newer Java curve list.
static const uint8_t kCurveList2[] = {
0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0a,
0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x16};
// IcedTea curve list.
static const uint8_t kCurveList3[] = {0x00, 0x17, 0x00, 0x18, 0x00, 0x19};
auto groups_span = MakeConstSpan(CBS_data(&groups), CBS_len(&groups));
if (groups_span != kCurveList1 && groups_span != kCurveList2 &&
groups_span != kCurveList3) {
return false;
}
// Java has a very distinctive curve list, but IcedTea patches it to a more
// standard [P-256, P-384, P-521]. Additionally check the extension
// order. This is more likely to lead to false positives but false positives
// only mean a loss of resumption. Any client new enough to support one of
// X25519, extended master secret, session tickets, or TLS 1.3 will be
// unaffected.
//
// Java sends different extensions depending on configuration and version, but
// those which are present are always in the same order. Check if the
// extensions are an ordered subset of |kJavaExtensions|.
static const uint16_t kJavaExtensions[] = {
TLSEXT_TYPE_supported_groups,
TLSEXT_TYPE_ec_point_formats,
TLSEXT_TYPE_signature_algorithms,
TLSEXT_TYPE_server_name,
17 /* status_request_v2 */,
TLSEXT_TYPE_status_request,
TLSEXT_TYPE_application_layer_protocol_negotiation,
TLSEXT_TYPE_renegotiate,
};
CBS extensions;
CBS_init(&extensions, client_hello->extensions, client_hello->extensions_len);
for (uint16_t expected : kJavaExtensions) {
CBS extensions_copy = extensions, body;
uint16_t type;
// Peek at the next extension.
if (CBS_get_u16(&extensions_copy, &type) &&
CBS_get_u16_length_prefixed(&extensions_copy, &body) &&
type == expected) {
extensions = extensions_copy;
}
}
return CBS_len(&extensions) == 0;
}
enum ssl_hs_wait_t ssl_get_prev_session(SSL *ssl,
UniquePtr<SSL_SESSION> *out_session,
bool *out_tickets_supported,
@ -728,8 +795,6 @@ enum ssl_hs_wait_t ssl_get_prev_session(SSL *ssl,
const SSL_CLIENT_HELLO *client_hello) {
// This is used only by servers.
assert(ssl->server);
UniquePtr<SSL_SESSION> session;
bool renew_ticket = false;
// If tickets are disabled, always behave as if no tickets are present.
const uint8_t *ticket = NULL;
@ -739,6 +804,32 @@ enum ssl_hs_wait_t ssl_get_prev_session(SSL *ssl,
ssl->version > SSL3_VERSION &&
SSL_early_callback_ctx_extension_get(
client_hello, TLSEXT_TYPE_session_ticket, &ticket, &ticket_len);
if (ssl_is_probably_java(client_hello)) {
// The Java client implementation of the 3SHAKE mitigation incorrectly
// rejects initial handshakes when all of the following are true:
//
// 1. The ClientHello offered a session.
// 2. The session was successfully resumed previously.
// 3. The server declines the session.
// 4. The server sends a certificate with a different SAN list than in the
// previous session.
//
// (Note the 3SHAKE mitigation is to reject certificates changes on
// renegotiation, while Java's logic applies to initial handshakes as well.)
//
// The end result is long-lived Java clients break on some certificate
// rotations. Fingerprint Java clients and decline all offered
// sessions. This avoids (2) while still introducing new sessions to clear
// any existing problematic sessions.
*out_session = nullptr;
*out_tickets_supported = tickets_supported;
*out_renew_ticket = false;
return ssl_hs_ok;
}
UniquePtr<SSL_SESSION> session;
bool renew_ticket = false;
if (tickets_supported && ticket_len > 0) {
switch (ssl_process_ticket(ssl, &session, &renew_ticket, ticket, ticket_len,
client_hello->session_id,

View File

@ -3816,6 +3816,179 @@ TEST(SSLTest, NoCiphersAvailable) {
EXPECT_EQ(SSL_R_NO_CIPHERS_AVAILABLE, ERR_GET_REASON(err));
}
TEST(SSLTest, IsProbablyJava) {
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
ASSERT_TRUE(ctx);
bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
ASSERT_TRUE(ssl);
const struct {
const char *name;
std::vector<uint8_t> in;
bool is_probably_java;
} kTests[] = {
{"JDK 6 with IcedTea curve list",
{0x03, 0x01, 0x59, 0xb3, 0x10, 0xea, 0x17, 0xfe, 0x9e, 0x69, 0x7e, 0x79,
0xc7, 0x33, 0x10, 0x81, 0x73, 0x9e, 0xe7, 0xbf, 0x78, 0x4a, 0x33, 0x76,
0x12, 0x1f, 0xc5, 0x6d, 0x28, 0x8d, 0xd7, 0x60, 0xf0, 0x5e, 0x00, 0x00,
0x2c, 0xc0, 0x0a, 0xc0, 0x14, 0x00, 0x35, 0xc0, 0x05, 0xc0, 0x0f, 0x00,
0x39, 0x00, 0x38, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x2f, 0xc0, 0x04, 0xc0,
0x0e, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x08, 0xc0, 0x12, 0x00, 0x0a, 0xc0,
0x03, 0xc0, 0x0d, 0x00, 0x16, 0x00, 0x13, 0x00, 0xff, 0x01, 0x00, 0x00,
0x12, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00},
true},
{"JDK 7 with IcedTea curve list",
{0x03, 0x03, 0x59, 0xb3, 0x10, 0xc8, 0x03, 0x7d, 0x10, 0x5a, 0x6b, 0x6e,
0x84, 0xa5, 0xbe, 0x6e, 0xe2, 0xd0, 0xb4, 0xb5, 0xcf, 0x6d, 0xa1, 0x58,
0xb5, 0xc0, 0x05, 0x63, 0xf6, 0x81, 0xda, 0xc2, 0xa0, 0xb0, 0x00, 0x00,
0x48, 0xc0, 0x24, 0xc0, 0x28, 0x00, 0x3d, 0xc0, 0x26, 0xc0, 0x2a, 0x00,
0x6b, 0x00, 0x6a, 0xc0, 0x0a, 0xc0, 0x14, 0x00, 0x35, 0xc0, 0x05, 0xc0,
0x0f, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x23, 0xc0, 0x27, 0x00, 0x3c, 0xc0,
0x25, 0xc0, 0x29, 0x00, 0x67, 0x00, 0x40, 0xc0, 0x09, 0xc0, 0x13, 0x00,
0x2f, 0xc0, 0x04, 0xc0, 0x0e, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x08, 0xc0,
0x12, 0x00, 0x0a, 0xc0, 0x03, 0xc0, 0x0d, 0x00, 0x16, 0x00, 0x13, 0x00,
0xff, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00,
0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00,
0x0d, 0x00, 0x18, 0x00, 0x16, 0x06, 0x03, 0x06, 0x01, 0x05, 0x03, 0x05,
0x01, 0x04, 0x03, 0x04, 0x01, 0x03, 0x03, 0x03, 0x01, 0x02, 0x03, 0x02,
0x01, 0x02, 0x02},
true},
{"JDK 8",
{0x03, 0x03, 0x59, 0xb3, 0x10, 0xfc, 0xc7, 0xcb, 0x36, 0x85, 0x8c, 0x00,
0xd6, 0xa7, 0x5b, 0xfb, 0x98, 0xbe, 0xf9, 0xa3, 0xa0, 0x01, 0xff, 0x35,
0xb9, 0x1a, 0xc1, 0x72, 0xf1, 0x51, 0x4b, 0x49, 0x96, 0x1a, 0x00, 0x00,
0x70, 0xc0, 0x24, 0xc0, 0x28, 0x00, 0x3d, 0xc0, 0x26, 0xc0, 0x2a, 0x00,
0x6b, 0x00, 0x6a, 0xc0, 0x0a, 0xc0, 0x14, 0x00, 0x35, 0xc0, 0x05, 0xc0,
0x0f, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x23, 0xc0, 0x27, 0x00, 0x3c, 0xc0,
0x25, 0xc0, 0x29, 0x00, 0x67, 0x00, 0x40, 0xc0, 0x09, 0xc0, 0x13, 0x00,
0x2f, 0xc0, 0x04, 0xc0, 0x0e, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x2c, 0xc0,
0x2b, 0xc0, 0x30, 0x00, 0x9d, 0xc0, 0x2e, 0xc0, 0x32, 0x00, 0x9f, 0x00,
0xa3, 0xc0, 0x2f, 0x00, 0x9c, 0xc0, 0x2d, 0xc0, 0x31, 0x00, 0x9e, 0x00,
0xa2, 0xc0, 0x08, 0xc0, 0x12, 0x00, 0x0a, 0xc0, 0x03, 0xc0, 0x0d, 0x00,
0x16, 0x00, 0x13, 0xc0, 0x07, 0xc0, 0x11, 0x00, 0x05, 0xc0, 0x02, 0xc0,
0x0c, 0x00, 0x04, 0x00, 0xff, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x0a, 0x00,
0x34, 0x00, 0x32, 0x00, 0x17, 0x00, 0x01, 0x00, 0x03, 0x00, 0x13, 0x00,
0x15, 0x00, 0x06, 0x00, 0x07, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x18, 0x00,
0x0b, 0x00, 0x0c, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00,
0x10, 0x00, 0x11, 0x00, 0x02, 0x00, 0x12, 0x00, 0x04, 0x00, 0x05, 0x00,
0x14, 0x00, 0x08, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00,
0x0d, 0x00, 0x1a, 0x00, 0x18, 0x06, 0x03, 0x06, 0x01, 0x05, 0x03, 0x05,
0x01, 0x04, 0x03, 0x04, 0x01, 0x03, 0x03, 0x03, 0x01, 0x02, 0x03, 0x02,
0x01, 0x02, 0x02, 0x01, 0x01},
true},
{"JDK 9",
{0x03, 0x03, 0x0c, 0xe6, 0x06, 0xc6, 0x5d, 0x38, 0xb4, 0x5e, 0x3a, 0xd5,
0xb0, 0x5f, 0x5b, 0x84, 0x3b, 0xff, 0x86, 0x4f, 0xb0, 0x3f, 0xc1, 0xfd,
0x08, 0xf0, 0x97, 0xf3, 0x56, 0x44, 0x08, 0xe2, 0xdd, 0x2a, 0x00, 0x00,
0x64, 0xc0, 0x2c, 0xc0, 0x2b, 0xc0, 0x30, 0x00, 0x9d, 0xc0, 0x2e, 0xc0,
0x32, 0x00, 0x9f, 0x00, 0xa3, 0xc0, 0x2f, 0x00, 0x9c, 0xc0, 0x2d, 0xc0,
0x31, 0x00, 0x9e, 0x00, 0xa2, 0xc0, 0x24, 0xc0, 0x28, 0x00, 0x3d, 0xc0,
0x26, 0xc0, 0x2a, 0x00, 0x6b, 0x00, 0x6a, 0xc0, 0x0a, 0xc0, 0x14, 0x00,
0x35, 0xc0, 0x05, 0xc0, 0x0f, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x23, 0xc0,
0x27, 0x00, 0x3c, 0xc0, 0x25, 0xc0, 0x29, 0x00, 0x67, 0x00, 0x40, 0xc0,
0x09, 0xc0, 0x13, 0x00, 0x2f, 0xc0, 0x04, 0xc0, 0x0e, 0x00, 0x33, 0x00,
0x32, 0xc0, 0x08, 0xc0, 0x12, 0x00, 0x0a, 0xc0, 0x03, 0xc0, 0x0d, 0x00,
0x16, 0x00, 0x13, 0x00, 0xff, 0x01, 0x00, 0x00, 0x5d, 0x00, 0x0a, 0x00,
0x16, 0x00, 0x14, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x09, 0x00,
0x0a, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x16, 0x00,
0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a, 0x06,
0x03, 0x06, 0x01, 0x05, 0x03, 0x05, 0x01, 0x04, 0x03, 0x04, 0x01, 0x04,
0x02, 0x03, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x03, 0x02, 0x01, 0x02,
0x02, 0x00, 0x11, 0x00, 0x10, 0x00, 0x0e, 0x02, 0x00, 0x04, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
0x05, 0x01, 0x00, 0x00, 0x00, 0x00},
true},
{"JDK 9 with SNI and ALPN enabled and no SCSV cipher",
{0x03, 0x03, 0x37, 0xa6, 0x4b, 0x58, 0x02, 0xd0, 0x77, 0xe4, 0x48, 0xaf,
0x90, 0x50, 0x45, 0xd5, 0x2f, 0xe7, 0x98, 0x5d, 0x54, 0x93, 0x85, 0x3a,
0xde, 0xb6, 0xaa, 0x47, 0xef, 0x7f, 0xb5, 0x52, 0xe6, 0xf8, 0x00, 0x00,
0x02, 0xc0, 0x24, 0x01, 0x00, 0x00, 0x87, 0x00, 0x0a, 0x00, 0x16, 0x00,
0x14, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0a, 0x00,
0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x0b, 0x00,
0x02, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a, 0x06, 0x03, 0x06,
0x01, 0x05, 0x03, 0x05, 0x01, 0x04, 0x03, 0x04, 0x01, 0x04, 0x02, 0x03,
0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x03, 0x02, 0x01, 0x02, 0x02, 0x00,
0x00, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x00, 0x0b, 0x65, 0x78, 0x61, 0x6d,
0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x11, 0x00, 0x10, 0x00,
0x0e, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x00, 0x0d, 0x00, 0x0b, 0x07, 0x68, 0x74, 0x74, 0x70, 0x31,
0x2e, 0x31, 0x02, 0x68, 0x32, 0xff, 0x01, 0x00, 0x01, 0x00},
true},
{"JDK 9 with EMS extension appended",
{0x03, 0x03, 0x0c, 0xe6, 0x06, 0xc6, 0x5d, 0x38, 0xb4, 0x5e, 0x3a, 0xd5,
0xb0, 0x5f, 0x5b, 0x84, 0x3b, 0xff, 0x86, 0x4f, 0xb0, 0x3f, 0xc1, 0xfd,
0x08, 0xf0, 0x97, 0xf3, 0x56, 0x44, 0x08, 0xe2, 0xdd, 0x2a, 0x00, 0x00,
0x64, 0xc0, 0x2c, 0xc0, 0x2b, 0xc0, 0x30, 0x00, 0x9d, 0xc0, 0x2e, 0xc0,
0x32, 0x00, 0x9f, 0x00, 0xa3, 0xc0, 0x2f, 0x00, 0x9c, 0xc0, 0x2d, 0xc0,
0x31, 0x00, 0x9e, 0x00, 0xa2, 0xc0, 0x24, 0xc0, 0x28, 0x00, 0x3d, 0xc0,
0x26, 0xc0, 0x2a, 0x00, 0x6b, 0x00, 0x6a, 0xc0, 0x0a, 0xc0, 0x14, 0x00,
0x35, 0xc0, 0x05, 0xc0, 0x0f, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x23, 0xc0,
0x27, 0x00, 0x3c, 0xc0, 0x25, 0xc0, 0x29, 0x00, 0x67, 0x00, 0x40, 0xc0,
0x09, 0xc0, 0x13, 0x00, 0x2f, 0xc0, 0x04, 0xc0, 0x0e, 0x00, 0x33, 0x00,
0x32, 0xc0, 0x08, 0xc0, 0x12, 0x00, 0x0a, 0xc0, 0x03, 0xc0, 0x0d, 0x00,
0x16, 0x00, 0x13, 0x00, 0xff, 0x01, 0x00, 0x00, 0x61, 0x00, 0x0a, 0x00,
0x16, 0x00, 0x14, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x09, 0x00,
0x0a, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x16, 0x00,
0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a, 0x06,
0x03, 0x06, 0x01, 0x05, 0x03, 0x05, 0x01, 0x04, 0x03, 0x04, 0x01, 0x04,
0x02, 0x03, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x03, 0x02, 0x01, 0x02,
0x02, 0x00, 0x11, 0x00, 0x10, 0x00, 0x0e, 0x02, 0x00, 0x04, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00},
false},
{"Chrome 61",
{0x03, 0x03, 0x33, 0x43, 0x8a, 0x6f, 0x76, 0xdd, 0x84, 0x3f, 0x8d, 0xaa,
0x43, 0xf1, 0x86, 0xee, 0xdd, 0x97, 0x96, 0x54, 0xf6, 0x17, 0x2c, 0xde,
0x69, 0xfe, 0x5e, 0x53, 0xaa, 0x47, 0xee, 0xad, 0xd7, 0x47, 0x00, 0x00,
0x1c, 0x3a, 0x3a, 0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30, 0xcc,
0xa9, 0xcc, 0xa8, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d, 0x00,
0x2f, 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x77, 0x8a, 0x8a, 0x00,
0x00, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0c,
0x00, 0x00, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74,
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, 0x05, 0x00, 0x05,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00,
0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f,
0x31, 0x2e, 0x31, 0x75, 0x50, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x01,
0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x4a, 0x4a, 0x00, 0x1d, 0x00,
0x17, 0x00, 0x18, 0x6a, 0x6a, 0x00, 0x01, 0x00},
false},
{"Firefox 55",
{0x03, 0x03, 0x06, 0x8e, 0xf8, 0xf7, 0x7a, 0xfd, 0xce, 0x45, 0xb0, 0x39,
0xbe, 0xa4, 0x55, 0x27, 0xe2, 0x80, 0xc4, 0x0a, 0xbd, 0xce, 0x56, 0x7a,
0xbc, 0x1f, 0x26, 0x2f, 0xfa, 0xb9, 0xa1, 0x7e, 0xe6, 0xde, 0x00, 0x00,
0x1e, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x2c, 0xc0,
0x30, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x33, 0x00,
0x39, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x6a, 0x00,
0x00, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x68, 0x6f, 0x73, 0x74, 0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00,
0x01, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17,
0x00, 0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23,
0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08,
0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x16, 0x04,
0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x04,
0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03, 0x02, 0x01},
false},
};
for (const auto &t : kTests) {
SCOPED_TRACE(t.name);
bssl::SSLMessage msg;
msg.is_v2_hello = false;
msg.type = SSL3_MT_CLIENT_HELLO;
CBS_init(&msg.body, t.in.data(), t.in.size());
CBS_init(&msg.raw, nullptr, 0); // unused
SSL_CLIENT_HELLO client_hello;
ASSERT_TRUE(bssl::ssl_client_hello_init(ssl.get(), &client_hello, msg));
EXPECT_EQ(t.is_probably_java, bssl::ssl_is_probably_java(&client_hello));
}
}
// TODO(davidben): Convert this file to GTest properly.
TEST(SSLTest, AllTests) {
if (!TestSSL_SESSIONEncoding(kOpenSSLSession) ||

View File

@ -1442,6 +1442,11 @@ type ProtocolBugs struct {
// PadClientHello, if non-zero, pads the ClientHello to a multiple of
// that many bytes.
PadClientHello int
// SendOnlyECExtensions omits all extensions except supported_groups and
// ec_point_formats, in order to trigger the Java ClientHello
// fingerprint.
SendOnlyECExtensions bool
}
func (c *Config) serverInit() {

View File

@ -97,6 +97,7 @@ func (c *Conn) clientHandshake() error {
pskBinderFirst: c.config.Bugs.PSKBinderFirst,
omitExtensions: c.config.Bugs.OmitExtensions,
emptyExtensions: c.config.Bugs.EmptyExtensions,
sendOnlyECExtensions: c.config.Bugs.SendOnlyECExtensions,
}
if maxVersion >= VersionTLS13 {

View File

@ -176,6 +176,7 @@ type clientHelloMsg struct {
omitExtensions bool
emptyExtensions bool
pad int
sendOnlyECExtensions bool
}
func (m *clientHelloMsg) equal(i interface{}) bool {
@ -224,7 +225,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
m.pskBinderFirst == m1.pskBinderFirst &&
m.omitExtensions == m1.omitExtensions &&
m.emptyExtensions == m1.emptyExtensions &&
m.pad == m1.pad
m.pad == m1.pad &&
m.sendOnlyECExtensions == m1.sendOnlyECExtensions
}
func (m *clientHelloMsg) marshal() []byte {
@ -312,22 +314,6 @@ func (m *clientHelloMsg) marshal() []byte {
certificateStatusRequest.addU16(0) // ResponderID length
certificateStatusRequest.addU16(0) // Extensions length
}
if len(m.supportedCurves) > 0 {
// http://tools.ietf.org/html/rfc4492#section-5.1.1
extensions.addU16(extensionSupportedCurves)
supportedCurvesList := extensions.addU16LengthPrefixed()
supportedCurves := supportedCurvesList.addU16LengthPrefixed()
for _, curve := range m.supportedCurves {
supportedCurves.addU16(uint16(curve))
}
}
if len(m.supportedPoints) > 0 {
// http://tools.ietf.org/html/rfc4492#section-5.1.2
extensions.addU16(extensionSupportedPoints)
supportedPointsList := extensions.addU16LengthPrefixed()
supportedPoints := supportedPointsList.addU8LengthPrefixed()
supportedPoints.addBytes(m.supportedPoints)
}
if m.hasKeyShares {
extensions.addU16(extensionKeyShare)
keyShareList := extensions.addU16LengthPrefixed()
@ -440,6 +426,30 @@ func (m *clientHelloMsg) marshal() []byte {
customExt := extensions.addU16LengthPrefixed()
customExt.addBytes([]byte(m.customExtension))
}
// Discard all extensions but the curve-related ones to trigger the Java
// fingerprinter.
if m.sendOnlyECExtensions {
hello.discardChild()
extensions = hello.addU16LengthPrefixed()
}
if len(m.supportedCurves) > 0 {
// http://tools.ietf.org/html/rfc4492#section-5.1.1
extensions.addU16(extensionSupportedCurves)
supportedCurvesList := extensions.addU16LengthPrefixed()
supportedCurves := supportedCurvesList.addU16LengthPrefixed()
for _, curve := range m.supportedCurves {
supportedCurves.addU16(uint16(curve))
}
}
if len(m.supportedPoints) > 0 {
// http://tools.ietf.org/html/rfc4492#section-5.1.2
extensions.addU16(extensionSupportedPoints)
supportedPointsList := extensions.addU16LengthPrefixed()
supportedPoints := supportedPointsList.addU8LengthPrefixed()
supportedPoints.addBytes(m.supportedPoints)
}
// The PSK extension must be last (draft-ietf-tls-tls13-18 section 4.2.6).
if len(m.pskIdentities) > 0 && !m.pskBinderFirst {
extensions.addU16(extensionPreSharedKey)
@ -456,6 +466,8 @@ func (m *clientHelloMsg) marshal() []byte {
}
}
// This must be swapped with PSK (with some length computation) if we
// ever need to support PadClientHello and TLS 1.3.
if m.pad != 0 && hello.len()%m.pad != 0 {
extensions.addU16(extensionPadding)
padding := extensions.addU16LengthPrefixed()

View File

@ -2790,6 +2790,25 @@ read alert 1 0
shouldFail: true,
expectedLocalError: "local error: record overflow",
},
{
// Test that Java-like ClientHellos are provided session
// IDs but resumption is always declined. This is to
// workaround a bug that causes connection failures when
// certificates rotate.
testType: serverTest,
name: "JavaWorkaround",
config: Config{
MaxVersion: VersionTLS12,
CurvePreferences: []CurveID{CurveP256, CurveP384, CurveP521},
SessionTicketsDisabled: true,
Bugs: ProtocolBugs{
SendOnlyECExtensions: true,
},
},
flags: []string{"-expect-session-id"},
resumeSession: true,
expectResumeRejected: true,
},
}
testCases = append(testCases, basicTests...)