external/boringssl: Sync to 9113e0996fd445ce187ae9dfeabfc95805b947a2.
This includes the following changes:
https://boringssl.googlesource.com/boringssl/+log/fa3aadcd40ec4fd27a6e9492ef099b3dcc6eb2af..9113e0996fd445ce187ae9dfeabfc95805b947a2
Test: atest CtsLibcoreTestCases
Change-Id: I31ed8a7c9481e7b42f0454f0ee64c26e17a85d52
diff --git a/src/ssl/handshake.cc b/src/ssl/handshake.cc
index b1da056..058a793 100644
--- a/src/ssl/handshake.cc
+++ b/src/ssl/handshake.cc
@@ -147,7 +147,8 @@
pending_private_key_op(false),
grease_seeded(false),
handback(false),
- cert_compression_negotiated(false) {
+ cert_compression_negotiated(false),
+ apply_jdk11_workaround(false) {
assert(ssl);
}
diff --git a/src/ssl/handshake_client.cc b/src/ssl/handshake_client.cc
index 24331ba..c1d54bd 100644
--- a/src/ssl/handshake_client.cc
+++ b/src/ssl/handshake_client.cc
@@ -177,6 +177,7 @@
enum ssl_client_hs_state_t {
state_start_connect = 0,
state_enter_early_data,
+ state_early_reverify_server_certificate,
state_read_hello_verify_request,
state_read_server_hello,
state_tls13,
@@ -466,10 +467,26 @@
// Stash the early data session, so connection properties may be queried out
// of it.
- hs->in_early_data = true;
hs->early_session = UpRef(ssl->session);
- hs->can_early_write = true;
+ hs->state = state_early_reverify_server_certificate;
+ return ssl_hs_ok;
+}
+static enum ssl_hs_wait_t do_early_reverify_server_certificate(SSL_HANDSHAKE *hs) {
+ if (hs->ssl->ctx->reverify_on_resume) {
+ switch (ssl_reverify_peer_cert(hs)) {
+ case ssl_verify_ok:
+ break;
+ case ssl_verify_invalid:
+ return ssl_hs_error;
+ case ssl_verify_retry:
+ hs->state = state_early_reverify_server_certificate;
+ return ssl_hs_certificate_verify;
+ }
+ }
+
+ hs->in_early_data = true;
+ hs->can_early_write = true;
hs->state = state_read_server_hello;
return ssl_hs_early_return;
}
@@ -595,10 +612,14 @@
static_assert(
sizeof(kTLS12DowngradeRandom) == sizeof(kTLS13DowngradeRandom),
"downgrade signals have different size");
+ static_assert(
+ sizeof(kJDK11DowngradeRandom) == sizeof(kTLS13DowngradeRandom),
+ "downgrade signals have different size");
auto suffix =
MakeConstSpan(ssl->s3->server_random, sizeof(ssl->s3->server_random))
.subspan(SSL3_RANDOM_SIZE - sizeof(kTLS13DowngradeRandom));
- if (suffix == kTLS12DowngradeRandom || suffix == kTLS13DowngradeRandom) {
+ if (suffix == kTLS12DowngradeRandom || suffix == kTLS13DowngradeRandom ||
+ suffix == kJDK11DowngradeRandom) {
ssl->s3->tls13_downgrade = true;
if (!hs->config->ignore_tls13_downgrade) {
OPENSSL_PUT_ERROR(SSL, SSL_R_TLS13_DOWNGRADE);
@@ -1692,6 +1713,9 @@
case state_enter_early_data:
ret = do_enter_early_data(hs);
break;
+ case state_early_reverify_server_certificate:
+ ret = do_early_reverify_server_certificate(hs);
+ break;
case state_read_hello_verify_request:
ret = do_read_hello_verify_request(hs);
break;
@@ -1775,6 +1799,8 @@
return "TLS client start_connect";
case state_enter_early_data:
return "TLS client enter_early_data";
+ case state_early_reverify_server_certificate:
+ return "TLS client early_reverify_server_certificate";
case state_read_hello_verify_request:
return "TLS client read_hello_verify_request";
case state_read_server_hello:
diff --git a/src/ssl/handshake_server.cc b/src/ssl/handshake_server.cc
index c546088..c4f3b75 100644
--- a/src/ssl/handshake_server.cc
+++ b/src/ssl/handshake_server.cc
@@ -401,6 +401,109 @@
return ssl_hs_ok;
}
+// is_probably_jdk11_with_tls13 returns whether |client_hello| was probably sent
+// from a JDK 11 client (11.0.1 or earlier) with both TLS 1.3 and a prior
+// version enabled.
+static bool is_probably_jdk11_with_tls13(const SSL_CLIENT_HELLO *client_hello) {
+ // JDK 11 ClientHellos contain a number of unusual properties which should
+ // limit false positives.
+
+ // JDK 11 does not support ChaCha20-Poly1305. This is unusual: many modern
+ // clients implement ChaCha20-Poly1305.
+ if (ssl_client_cipher_list_contains_cipher(
+ client_hello, TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) {
+ return false;
+ }
+
+ // JDK 11 always sends extensions in a particular order.
+ constexpr uint16_t kMaxFragmentLength = 0x0001;
+ constexpr uint16_t kStatusRequestV2 = 0x0011;
+ static CONSTEXPR_ARRAY struct {
+ uint16_t id;
+ bool required;
+ } kJavaExtensions[] = {
+ {TLSEXT_TYPE_server_name, false},
+ {kMaxFragmentLength, false},
+ {TLSEXT_TYPE_status_request, false},
+ {TLSEXT_TYPE_supported_groups, true},
+ {TLSEXT_TYPE_ec_point_formats, false},
+ {TLSEXT_TYPE_signature_algorithms, true},
+ // Java always sends signature_algorithms_cert.
+ {TLSEXT_TYPE_signature_algorithms_cert, true},
+ {TLSEXT_TYPE_application_layer_protocol_negotiation, false},
+ {kStatusRequestV2, false},
+ {TLSEXT_TYPE_extended_master_secret, false},
+ {TLSEXT_TYPE_supported_versions, true},
+ {TLSEXT_TYPE_cookie, false},
+ {TLSEXT_TYPE_psk_key_exchange_modes, true},
+ {TLSEXT_TYPE_key_share, true},
+ {TLSEXT_TYPE_renegotiate, false},
+ {TLSEXT_TYPE_pre_shared_key, false},
+ };
+ Span<const uint8_t> sigalgs, sigalgs_cert;
+ bool has_status_request = false, has_status_request_v2 = false;
+ CBS extensions, supported_groups;
+ CBS_init(&extensions, client_hello->extensions, client_hello->extensions_len);
+ for (const auto &java_extension : kJavaExtensions) {
+ CBS copy = extensions;
+ uint16_t id;
+ if (CBS_get_u16(©, &id) && id == java_extension.id) {
+ // The next extension is the one we expected.
+ extensions = copy;
+ CBS body;
+ if (!CBS_get_u16_length_prefixed(&extensions, &body)) {
+ return false;
+ }
+ switch (id) {
+ case TLSEXT_TYPE_status_request:
+ has_status_request = true;
+ break;
+ case kStatusRequestV2:
+ has_status_request_v2 = true;
+ break;
+ case TLSEXT_TYPE_signature_algorithms:
+ sigalgs = body;
+ break;
+ case TLSEXT_TYPE_signature_algorithms_cert:
+ sigalgs_cert = body;
+ break;
+ case TLSEXT_TYPE_supported_groups:
+ supported_groups = body;
+ break;
+ }
+ } else if (java_extension.required) {
+ return false;
+ }
+ }
+ if (CBS_len(&extensions) != 0) {
+ return false;
+ }
+
+ // JDK 11 never advertises X25519. It is not offered by default, and
+ // -Djdk.tls.namedGroups=x25519 does not work. This is unusual: many modern
+ // clients implement X25519.
+ while (CBS_len(&supported_groups) > 0) {
+ uint16_t group;
+ if (!CBS_get_u16(&supported_groups, &group) ||
+ group == SSL_CURVE_X25519) {
+ return false;
+ }
+ }
+
+ if (// JDK 11 always sends the same contents in signature_algorithms and
+ // signature_algorithms_cert. This is unusual: signature_algorithms_cert,
+ // if omitted, is treated as if it were signature_algorithms.
+ sigalgs != sigalgs_cert ||
+ // When TLS 1.2 or below is enabled, JDK 11 sends status_request_v2 iff it
+ // sends status_request. This is unusual: status_request_v2 is not widely
+ // implemented.
+ has_status_request != has_status_request_v2) {
+ return false;
+ }
+
+ return true;
+}
+
static enum ssl_hs_wait_t do_read_client_hello(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
@@ -446,6 +549,11 @@
return ssl_hs_error;
}
+ if (hs->config->jdk11_workaround &&
+ is_probably_jdk11_with_tls13(&client_hello)) {
+ hs->apply_jdk11_workaround = true;
+ }
+
uint8_t alert = SSL_AD_DECODE_ERROR;
if (!negotiate_version(hs, &alert, &client_hello)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
@@ -674,6 +782,12 @@
return ssl_hs_ok;
}
+static void copy_suffix(Span<uint8_t> out, Span<const uint8_t> in) {
+ out = out.subspan(out.size() - in.size());
+ assert(out.size() == in.size());
+ OPENSSL_memcpy(out.data(), in.data(), in.size());
+}
+
static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
@@ -705,13 +819,18 @@
// Implement the TLS 1.3 anti-downgrade feature.
if (ssl_supports_version(hs, TLS1_3_VERSION)) {
if (ssl_protocol_version(ssl) == TLS1_2_VERSION) {
- OPENSSL_memcpy(ssl->s3->server_random + SSL3_RANDOM_SIZE -
- sizeof(kTLS13DowngradeRandom),
- kTLS13DowngradeRandom, sizeof(kTLS13DowngradeRandom));
+ if (hs->apply_jdk11_workaround) {
+ // JDK 11 implements the TLS 1.3 downgrade signal, so we cannot send it
+ // here. However, the signal is only effective if all TLS 1.2
+ // ServerHellos produced by the server are marked. Thus we send a
+ // different non-standard signal for the time being, until JDK 11.0.2 is
+ // released and clients have updated.
+ copy_suffix(ssl->s3->server_random, kJDK11DowngradeRandom);
+ } else {
+ copy_suffix(ssl->s3->server_random, kTLS13DowngradeRandom);
+ }
} else {
- OPENSSL_memcpy(ssl->s3->server_random + SSL3_RANDOM_SIZE -
- sizeof(kTLS12DowngradeRandom),
- kTLS12DowngradeRandom, sizeof(kTLS12DowngradeRandom));
+ copy_suffix(ssl->s3->server_random, kTLS12DowngradeRandom);
}
}
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index fa86bda..f8a2ea7 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -1040,6 +1040,7 @@
extern const uint8_t kHelloRetryRequest[SSL3_RANDOM_SIZE];
extern const uint8_t kTLS12DowngradeRandom[8];
extern const uint8_t kTLS13DowngradeRandom[8];
+extern const uint8_t kJDK11DowngradeRandom[8];
// ssl_max_handshake_message_len returns the maximum number of bytes permitted
// in a handshake message for |ssl|.
@@ -1596,6 +1597,10 @@
// cert_compression_negotiated is true iff |cert_compression_alg_id| is valid.
bool cert_compression_negotiated : 1;
+ // apply_jdk11_workaround is true if the peer is probably a JDK 11 client
+ // which implemented TLS 1.3 incorrectly.
+ bool apply_jdk11_workaround : 1;
+
// client_version is the value sent or received in the ClientHello version.
uint16_t client_version = 0;
@@ -2489,7 +2494,11 @@
// ignore_tls13_downgrade is whether the connection should continue when the
// server random signals a downgrade.
- bool ignore_tls13_downgrade:1;
+ bool ignore_tls13_downgrade : 1;
+
+ // jdk11_workaround is whether to disable TLS 1.3 for JDK 11 clients, as a
+ // workaround for https://bugs.openjdk.java.net/browse/JDK-8211806.
+ bool jdk11_workaround : 1;
};
// From RFC 8446, used in determining PSK modes.
diff --git a/src/ssl/ssl_asn1.cc b/src/ssl/ssl_asn1.cc
index caccef4..669f776 100644
--- a/src/ssl/ssl_asn1.cc
+++ b/src/ssl/ssl_asn1.cc
@@ -80,13 +80,6 @@
* OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
* OTHERWISE. */
-// Per C99, various stdint.h macros are unavailable in C++ unless some macros
-// are defined. C++11 overruled this decision, but older Android NDKs still
-// require it.
-#if !defined(__STDC_LIMIT_MACROS)
-#define __STDC_LIMIT_MACROS
-#endif
-
#include <openssl/ssl.h>
#include <limits.h>
diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc
index 8a88802..b9c823d 100644
--- a/src/ssl/ssl_lib.cc
+++ b/src/ssl/ssl_lib.cc
@@ -711,7 +711,8 @@
retain_only_sha256_of_client_certs(false),
handoff(false),
shed_handshake_config(false),
- ignore_tls13_downgrade(false) {
+ ignore_tls13_downgrade(false),
+ jdk11_workaround(false) {
assert(ssl);
}
@@ -948,6 +949,33 @@
return 1;
}
+int SSL_process_quic_post_handshake(SSL *ssl) {
+ ssl_reset_error_state(ssl);
+
+ if (SSL_in_init(ssl)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
+ // Replay post-handshake message errors.
+ if (!check_read_error(ssl)) {
+ return 0;
+ }
+
+ // Process any buffered post-handshake messages.
+ SSLMessage msg;
+ while (ssl->method->get_message(ssl, &msg)) {
+ // Handle the post-handshake message and try again.
+ if (!ssl_do_post_handshake(ssl, msg)) {
+ ssl_set_read_error(ssl);
+ return 0;
+ }
+ ssl->method->next_message(ssl);
+ }
+
+ return 1;
+}
+
static int ssl_read_impl(SSL *ssl) {
ssl_reset_error_state(ssl);
@@ -2748,6 +2776,13 @@
ssl->config->shed_handshake_config = !!enable;
}
+void SSL_set_jdk11_workaround(SSL *ssl, int enable) {
+ if (!ssl->config) {
+ return;
+ }
+ ssl->config->jdk11_workaround = !!enable;
+}
+
int SSL_clear(SSL *ssl) {
if (!ssl->config) {
return 0; // SSL_clear may not be used after shedding config.
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index f945898..470379c 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -4727,6 +4727,21 @@
return true;
}
+ bool CreateSecondClientAndServer() {
+ client_.reset(SSL_new(client_ctx_.get()));
+ server_.reset(SSL_new(server_ctx_.get()));
+ if (!client_ || !server_) {
+ return false;
+ }
+
+ SSL_set_connect_state(client_.get());
+ SSL_set_accept_state(server_.get());
+
+ ex_data_.Set(client_.get(), second_transport_.client());
+ ex_data_.Set(server_.get(), second_transport_.server());
+ return true;
+ }
+
// The following functions may be configured on an |SSL_QUIC_METHOD| as
// default implementations.
@@ -4760,6 +4775,7 @@
static UnownedSSLExData<MockQUICTransport> ex_data_;
MockQUICTransportPair transport_;
+ MockQUICTransportPair second_transport_;
bssl::UniquePtr<SSL> client_;
bssl::UniquePtr<SSL> server_;
@@ -4776,6 +4792,10 @@
SendAlertCallback,
};
+ g_last_session = nullptr;
+
+ SSL_CTX_set_session_cache_mode(client_ctx_.get(), SSL_SESS_CACHE_BOTH);
+ SSL_CTX_sess_set_new_cb(client_ctx_.get(), SaveLastSession);
ASSERT_TRUE(SSL_CTX_set_quic_method(client_ctx_.get(), &quic_method));
ASSERT_TRUE(SSL_CTX_set_quic_method(server_ctx_.get(), &quic_method));
ASSERT_TRUE(CreateClientAndServer());
@@ -4807,13 +4827,43 @@
EXPECT_FALSE(transport_.server()->has_alert());
// The server sent NewSessionTicket messages in the handshake.
- //
- // TODO(davidben,svaldez): Add an API for the client to consume post-handshake
- // messages and update these tests.
- std::vector<uint8_t> new_session_ticket;
- ASSERT_TRUE(transport_.client()->ReadHandshakeData(
- &new_session_ticket, ssl_encryption_application));
- EXPECT_FALSE(new_session_ticket.empty());
+ EXPECT_FALSE(g_last_session);
+ ASSERT_TRUE(ProvideHandshakeData(client_.get()));
+ EXPECT_EQ(SSL_process_quic_post_handshake(client_.get()), 1);
+ EXPECT_TRUE(g_last_session);
+
+ // Create a second connection to verify resumption works.
+ ASSERT_TRUE(CreateSecondClientAndServer());
+ bssl::UniquePtr<SSL_SESSION> session = std::move(g_last_session);
+ SSL_set_session(client_.get(), session.get());
+
+ for (;;) {
+ ASSERT_TRUE(ProvideHandshakeData(client_.get()));
+ int client_ret = SSL_do_handshake(client_.get());
+ if (client_ret != 1) {
+ ASSERT_EQ(client_ret, -1);
+ ASSERT_EQ(SSL_get_error(client_.get(), client_ret), SSL_ERROR_WANT_READ);
+ }
+
+ ASSERT_TRUE(ProvideHandshakeData(server_.get()));
+ int server_ret = SSL_do_handshake(server_.get());
+ if (server_ret != 1) {
+ ASSERT_EQ(server_ret, -1);
+ ASSERT_EQ(SSL_get_error(server_.get(), server_ret), SSL_ERROR_WANT_READ);
+ }
+
+ if (client_ret == 1 && server_ret == 1) {
+ break;
+ }
+ }
+
+ EXPECT_EQ(SSL_do_handshake(client_.get()), 1);
+ EXPECT_EQ(SSL_do_handshake(server_.get()), 1);
+ EXPECT_TRUE(transport_.SecretsMatch(ssl_encryption_application));
+ EXPECT_FALSE(transport_.client()->has_alert());
+ EXPECT_FALSE(transport_.server()->has_alert());
+ EXPECT_TRUE(SSL_session_reused(client_.get()));
+ EXPECT_TRUE(SSL_session_reused(server_.get()));
}
// Test only releasing data to QUIC one byte at a time on request, to maximize
@@ -5073,6 +5123,56 @@
SSL_provide_quic_data(client_.get(), ssl_encryption_initial, &b, 1));
}
+// Provide invalid post-handshake data.
+TEST_F(QUICMethodTest, BadPostHandshake) {
+ const SSL_QUIC_METHOD quic_method = {
+ SetEncryptionSecretsCallback,
+ AddHandshakeDataCallback,
+ FlushFlightCallback,
+ SendAlertCallback,
+ };
+
+ g_last_session = nullptr;
+
+ SSL_CTX_set_session_cache_mode(client_ctx_.get(), SSL_SESS_CACHE_BOTH);
+ SSL_CTX_sess_set_new_cb(client_ctx_.get(), SaveLastSession);
+ ASSERT_TRUE(SSL_CTX_set_quic_method(client_ctx_.get(), &quic_method));
+ ASSERT_TRUE(SSL_CTX_set_quic_method(server_ctx_.get(), &quic_method));
+ ASSERT_TRUE(CreateClientAndServer());
+
+ for (;;) {
+ ASSERT_TRUE(ProvideHandshakeData(client_.get()));
+ int client_ret = SSL_do_handshake(client_.get());
+ if (client_ret != 1) {
+ ASSERT_EQ(client_ret, -1);
+ ASSERT_EQ(SSL_get_error(client_.get(), client_ret), SSL_ERROR_WANT_READ);
+ }
+
+ ASSERT_TRUE(ProvideHandshakeData(server_.get()));
+ int server_ret = SSL_do_handshake(server_.get());
+ if (server_ret != 1) {
+ ASSERT_EQ(server_ret, -1);
+ ASSERT_EQ(SSL_get_error(server_.get(), server_ret), SSL_ERROR_WANT_READ);
+ }
+
+ if (client_ret == 1 && server_ret == 1) {
+ break;
+ }
+ }
+
+ EXPECT_EQ(SSL_do_handshake(client_.get()), 1);
+ EXPECT_EQ(SSL_do_handshake(server_.get()), 1);
+ EXPECT_TRUE(transport_.SecretsMatch(ssl_encryption_application));
+ EXPECT_FALSE(transport_.client()->has_alert());
+ EXPECT_FALSE(transport_.server()->has_alert());
+
+ // Junk sent as part of post-handshake data should cause an error.
+ uint8_t kJunk[] = {0x17, 0x0, 0x0, 0x4, 0xB, 0xE, 0xE, 0xF};
+ ASSERT_TRUE(SSL_provide_quic_data(client_.get(), ssl_encryption_application,
+ kJunk, sizeof(kJunk)));
+ EXPECT_EQ(SSL_process_quic_post_handshake(client_.get()), 0);
+}
+
// TODO(davidben): Convert this file to GTest properly.
TEST(SSLTest, AllTests) {
if (!TestSSL_SESSIONEncoding(kOpenSSLSession) ||
diff --git a/src/ssl/ssl_versions.cc b/src/ssl/ssl_versions.cc
index 7df7fe7..8616967 100644
--- a/src/ssl/ssl_versions.cc
+++ b/src/ssl/ssl_versions.cc
@@ -340,6 +340,18 @@
continue;
}
+ // JDK 11, prior to 11.0.2, has a buggy TLS 1.3 implementation which fails
+ // to send SNI when offering 1.3 sessions. Disable TLS 1.3 for such
+ // clients. We apply this logic here rather than |ssl_supports_version| so
+ // the downgrade signal continues to query the true capabilities. (The
+ // workaround is a limitation of the peer's capabilities rather than our
+ // own.)
+ //
+ // See https://bugs.openjdk.java.net/browse/JDK-8211806.
+ if (versions[i] == TLS1_3_VERSION && hs->apply_jdk11_workaround) {
+ continue;
+ }
+
CBS copy = *peer_versions;
while (CBS_len(©) != 0) {
uint16_t version;
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index dc12559..675a08a 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -12,10 +12,6 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
-#if !defined(__STDC_FORMAT_MACROS)
-#define __STDC_FORMAT_MACROS
-#endif
-
#include <openssl/base.h>
#if !defined(OPENSSL_WINDOWS)
@@ -708,6 +704,7 @@
// Reset the connection and try again at 1-RTT.
SSL_reset_early_data_reject(ssl.get());
+ GetTestState(ssl.get())->cert_verified = false;
// After reseting, the socket should report it is no longer in an early data
// state.
diff --git a/src/ssl/test/runner/chacha20_poly1305_test.go b/src/ssl/test/runner/chacha20_poly1305_test.go
index 38c4b70..b59bb02 100644
--- a/src/ssl/test/runner/chacha20_poly1305_test.go
+++ b/src/ssl/test/runner/chacha20_poly1305_test.go
@@ -16,7 +16,6 @@
import (
"bytes"
- "encoding/hex"
"testing"
)
@@ -80,14 +79,6 @@
}
}
-func decodeHexOrPanic(in string) []byte {
- out, err := hex.DecodeString(in)
- if err != nil {
- panic(err)
- }
- return out
-}
-
var chaCha20Poly1305TestVectors = []struct {
key, input, nonce, ad, output string
}{
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index 702814d..73b8889 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -1626,6 +1626,25 @@
// SendCertUncompressedLength, if not zero, sets the uncompressed length that
// will be sent in the compressed certificate message.
SendCertUncompressedLength uint32
+
+ // SendClientHelloWithFixes, if not nil, sends the specified byte string
+ // instead of the ClientHello. This string is incorporated into the
+ // transcript as if it were the real ClientHello, but the handshake will
+ // otherwise behave as if this was not sent in terms of what ciphers it
+ // will accept, etc.
+ //
+ // The input is modified to match key share entries. DefaultCurves must
+ // be configured to match. The random and session ID fields are
+ // extracted from the ClientHello.
+ SendClientHelloWithFixes []byte
+
+ // SendJDK11DowngradeRandom, if true, causes the server to send the JDK
+ // 11 downgrade signal.
+ SendJDK11DowngradeRandom bool
+
+ // ExpectJDK11DowngradeRandom is whether the client should expect the
+ // server to send the JDK 11 downgrade signal.
+ ExpectJDK11DowngradeRandom bool
}
func (c *Config) serverInit() {
@@ -2067,6 +2086,9 @@
// See RFC 8446, section 4.1.3.
downgradeTLS13 = []byte{0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01}
downgradeTLS12 = []byte{0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x00}
+
+ // This is a non-standard randomly-generated value.
+ downgradeJDK11 = []byte{0xed, 0xbf, 0xb4, 0xa8, 0xc2, 0x47, 0x10, 0xff}
)
func containsGREASE(values []uint16) bool {
diff --git a/src/ssl/test/runner/fuzzer_mode.json b/src/ssl/test/runner/fuzzer_mode.json
index a840f37..1a154c2 100644
--- a/src/ssl/test/runner/fuzzer_mode.json
+++ b/src/ssl/test/runner/fuzzer_mode.json
@@ -44,8 +44,7 @@
"EarlyData-ALPNOmitted1-Server-*": "Trial decryption does not work with the NULL cipher.",
"EarlyData-ALPNOmitted2-Server-*": "Trial decryption does not work with the NULL cipher.",
"*-EarlyData-RejectUnfinishedWrite-Client-*": "Trial decryption does not work with the NULL cipher.",
- "EarlyData-Reject-Client-*": "Trial decryption does not work with the NULL cipher.",
- "EarlyData-RejectTicket-Client-*": "Trial decryption does not work with the NULL cipher.",
+ "EarlyData-Reject*-Client-*": "Trial decryption does not work with the NULL cipher.",
"CustomExtensions-Server-EarlyDataOffered": "Trial decryption does not work with the NULL cipher.",
"Renegotiate-Client-BadExt*": "Fuzzer mode does not check renegotiation_info.",
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index 4dfa469..ab1f4dd 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -49,6 +49,32 @@
panic("Unknown ClientHello version.")
}
+func fixClientHellos(hello *clientHelloMsg, in []byte) ([]byte, error) {
+ ret := append([]byte{}, in...)
+ newHello := new(clientHelloMsg)
+ if !newHello.unmarshal(ret) {
+ return nil, errors.New("tls: invalid ClientHello")
+ }
+
+ hello.random = newHello.random
+ hello.sessionId = newHello.sessionId
+
+ // Replace |ret|'s key shares with those of |hello|. For simplicity, we
+ // require their lengths match, which is satisfied by matching the
+ // DefaultCurves setting to the selection in the replacement
+ // ClientHello.
+ bb := newByteBuilder()
+ hello.marshalKeyShares(bb)
+ keyShares := bb.finish()
+ if len(keyShares) != len(newHello.keySharesRaw) {
+ return nil, errors.New("tls: ClientHello key share length is inconsistent with DefaultCurves setting")
+ }
+ // |newHello.keySharesRaw| aliases |ret|.
+ copy(newHello.keySharesRaw, keyShares)
+
+ return ret, nil
+}
+
func (c *Conn) clientHandshake() error {
if c.config == nil {
c.config = defaultConfig()
@@ -405,7 +431,14 @@
}
generatePSKBinders(version, hello, pskCipherSuite, session.masterSecret, []byte{}, []byte{}, c.config)
}
- helloBytes = hello.marshal()
+ if c.config.Bugs.SendClientHelloWithFixes != nil {
+ helloBytes, err = fixClientHellos(hello, c.config.Bugs.SendClientHelloWithFixes)
+ if err != nil {
+ return err
+ }
+ } else {
+ helloBytes = hello.marshal()
+ }
if c.config.Bugs.PartialClientFinishedWithClientHello {
// Include one byte of Finished. We can compute it
@@ -604,21 +637,30 @@
_, supportsTLS13 := c.config.isSupportedVersion(VersionTLS13, false)
// Check for downgrade signals in the server random, per RFC 8446, section 4.1.3.
+ gotDowngrade := serverHello.random[len(serverHello.random)-8:]
if (supportsTLS13 || c.config.Bugs.CheckTLS13DowngradeRandom) && !c.config.Bugs.IgnoreTLS13DowngradeRandom {
if c.vers <= VersionTLS12 && c.config.maxVersion(c.isDTLS) >= VersionTLS13 {
- if bytes.Equal(serverHello.random[len(serverHello.random)-8:], downgradeTLS13) {
+ if bytes.Equal(gotDowngrade, downgradeTLS13) {
c.sendAlert(alertProtocolVersion)
return errors.New("tls: downgrade from TLS 1.3 detected")
}
}
if c.vers <= VersionTLS11 && c.config.maxVersion(c.isDTLS) >= VersionTLS12 {
- if bytes.Equal(serverHello.random[len(serverHello.random)-8:], downgradeTLS12) {
+ if bytes.Equal(gotDowngrade, downgradeTLS12) {
c.sendAlert(alertProtocolVersion)
return errors.New("tls: downgrade from TLS 1.2 detected")
}
}
}
+ if bytes.Equal(gotDowngrade, downgradeJDK11) != c.config.Bugs.ExpectJDK11DowngradeRandom {
+ c.sendAlert(alertProtocolVersion)
+ if c.config.Bugs.ExpectJDK11DowngradeRandom {
+ return errors.New("tls: server did not send a JDK 11 downgrade signal")
+ }
+ return errors.New("tls: server sent an unexpected JDK 11 downgrade signal")
+ }
+
suite := mutualCipherSuite(hello.cipherSuites, serverHello.cipherSuite)
if suite == nil {
c.sendAlert(alertHandshakeFailure)
diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go
index edc5a92..e0867a5 100644
--- a/src/ssl/test/runner/handshake_messages.go
+++ b/src/ssl/test/runner/handshake_messages.go
@@ -266,6 +266,7 @@
supportedPoints []uint8
hasKeyShares bool
keyShares []keyShareEntry
+ keySharesRaw []byte
trailingKeyShareData bool
pskIdentities []pskIdentity
pskKEModes []byte
@@ -352,6 +353,18 @@
eqUint16s(m.compressedCertAlgs, m1.compressedCertAlgs)
}
+func (m *clientHelloMsg) marshalKeyShares(bb *byteBuilder) {
+ keyShares := bb.addU16LengthPrefixed()
+ for _, keyShare := range m.keyShares {
+ keyShares.addU16(uint16(keyShare.group))
+ keyExchange := keyShares.addU16LengthPrefixed()
+ keyExchange.addBytes(keyShare.keyExchange)
+ }
+ if m.trailingKeyShareData {
+ keyShares.addU8(0)
+ }
+}
+
func (m *clientHelloMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -456,17 +469,7 @@
if m.hasKeyShares {
extensions.addU16(extensionKeyShare)
keyShareList := extensions.addU16LengthPrefixed()
-
- keyShares := keyShareList.addU16LengthPrefixed()
- for _, keyShare := range m.keyShares {
- keyShares.addU16(uint16(keyShare.group))
- keyExchange := keyShares.addU16LengthPrefixed()
- keyExchange.addBytes(keyShare.keyExchange)
- }
-
- if m.trailingKeyShareData {
- keyShares.addU8(0)
- }
+ m.marshalKeyShares(keyShareList)
}
if len(m.pskKEModes) > 0 {
extensions.addU16(extensionPSKKeyExchangeModes)
@@ -763,11 +766,12 @@
m.sessionTicket = []byte(body)
case extensionKeyShare:
// https://tools.ietf.org/html/rfc8446#section-4.2.8
+ m.hasKeyShares = true
+ m.keySharesRaw = body
var keyShares byteReader
if !body.readU16LengthPrefixed(&keyShares) || len(body) != 0 {
return false
}
- m.hasKeyShares = true
for len(keyShares) > 0 {
var entry keyShareEntry
var group uint16
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 4950a4f..6a75242 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -1182,6 +1182,9 @@
copy(hs.hello.random[len(hs.hello.random)-8:], downgradeTLS12)
}
}
+ if config.Bugs.SendJDK11DowngradeRandom {
+ copy(hs.hello.random[len(hs.hello.random)-8:], downgradeJDK11)
+ }
if len(hs.clientHello.sessionId) == 0 && c.config.Bugs.ExpectClientHelloSessionID {
return false, errors.New("tls: expected non-empty session ID from client")
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index 9631e6e..fadc890 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -42,6 +42,8 @@
"sync"
"syscall"
"time"
+
+ "boringssl.googlesource.com/boringssl/util/testresult"
)
var (
@@ -303,6 +305,14 @@
return ret
}
+func decodeHexOrPanic(in string) []byte {
+ ret, err := hex.DecodeString(in)
+ if err != nil {
+ panic(err)
+ }
+ return ret
+}
+
type testType int
const (
@@ -908,7 +918,7 @@
for i, v := range buf {
if v != testMessage[i]^0xff {
- return fmt.Errorf("bad reply contents at byte %d", i)
+ return fmt.Errorf("bad reply contents at byte %d; got %q and wanted %q", i, buf, testMessage)
}
}
}
@@ -5016,6 +5026,165 @@
}, flags...),
resumeSession: true,
})
+ if vers.version >= VersionTLS13 {
+ tests = append(tests, testCase{
+ testType: testType,
+ name: "EarlyData-RejectTicket-Client-Reverify" + suffix,
+ config: Config{
+ MaxVersion: vers.version,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeConfig: &Config{
+ MaxVersion: vers.version,
+ MaxEarlyDataSize: 16384,
+ SessionTicketsDisabled: true,
+ },
+ tls13Variant: vers.tls13Variant,
+ resumeSession: true,
+ expectResumeRejected: true,
+ flags: append([]string{
+ "-enable-early-data",
+ "-expect-ticket-supports-early-data",
+ "-reverify-on-resume",
+ "-on-resume-shim-writes-first",
+ // Session tickets are disabled, so the runner will not send a ticket.
+ "-on-retry-expect-no-session",
+ "-expect-reject-early-data",
+ }, flags...),
+ })
+ tests = append(tests, testCase{
+ testType: testType,
+ name: "EarlyData-Reject0RTT-Client-Reverify" + suffix,
+ config: Config{
+ MaxVersion: vers.version,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeConfig: &Config{
+ MaxVersion: vers.version,
+ MaxEarlyDataSize: 16384,
+ Bugs: ProtocolBugs{
+ AlwaysRejectEarlyData: true,
+ },
+ },
+ tls13Variant: vers.tls13Variant,
+ resumeSession: true,
+ expectResumeRejected: false,
+ flags: append([]string{
+ "-enable-early-data",
+ "-expect-reject-early-data",
+ "-expect-ticket-supports-early-data",
+ "-reverify-on-resume",
+ "-on-resume-shim-writes-first",
+ }, flags...),
+ })
+ tests = append(tests, testCase{
+ testType: testType,
+ name: "EarlyData-RejectTicket-Client-ReverifyFails" + suffix,
+ config: Config{
+ MaxVersion: vers.version,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeConfig: &Config{
+ MaxVersion: vers.version,
+ MaxEarlyDataSize: 16384,
+ SessionTicketsDisabled: true,
+ },
+ tls13Variant: vers.tls13Variant,
+ resumeSession: true,
+ expectResumeRejected: true,
+ shouldFail: true,
+ expectedError: ":CERTIFICATE_VERIFY_FAILED:",
+ flags: append([]string{
+ "-enable-early-data",
+ "-expect-ticket-supports-early-data",
+ "-reverify-on-resume",
+ "-on-resume-shim-writes-first",
+ // Session tickets are disabled, so the runner will not send a ticket.
+ "-on-retry-expect-no-session",
+ "-on-retry-verify-fail",
+ "-expect-reject-early-data",
+ }, flags...),
+ })
+ tests = append(tests, testCase{
+ testType: testType,
+ name: "EarlyData-Reject0RTT-Client-ReverifyFails" + suffix,
+ config: Config{
+ MaxVersion: vers.version,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeConfig: &Config{
+ MaxVersion: vers.version,
+ MaxEarlyDataSize: 16384,
+ Bugs: ProtocolBugs{
+ AlwaysRejectEarlyData: true,
+ },
+ },
+ tls13Variant: vers.tls13Variant,
+ resumeSession: true,
+ expectResumeRejected: false,
+ shouldFail: true,
+ expectedError: ":CERTIFICATE_VERIFY_FAILED:",
+ flags: append([]string{
+ "-enable-early-data",
+ "-expect-reject-early-data",
+ "-expect-ticket-supports-early-data",
+ "-reverify-on-resume",
+ "-on-resume-shim-writes-first",
+ "-on-retry-verify-fail",
+ }, flags...),
+ })
+ // This tests that we only call the verify callback once.
+ tests = append(tests, testCase{
+ testType: testType,
+ name: "EarlyData-Accept0RTT-Client-Reverify" + suffix,
+ config: Config{
+ MaxVersion: vers.version,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeConfig: &Config{
+ MaxVersion: vers.version,
+ MaxEarlyDataSize: 16384,
+ Bugs: ProtocolBugs{
+ ExpectEarlyData: [][]byte{[]byte("hello")},
+ },
+ },
+ tls13Variant: vers.tls13Variant,
+ resumeSession: true,
+ expectResumeRejected: false,
+ flags: append([]string{
+ "-enable-early-data",
+ "-expect-ticket-supports-early-data",
+ "-reverify-on-resume",
+ "-on-resume-shim-writes-first",
+ }, flags...),
+ })
+ tests = append(tests, testCase{
+ testType: testType,
+ name: "EarlyData-Accept0RTT-Client-ReverifyFails" + suffix,
+ config: Config{
+ MaxVersion: vers.version,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeConfig: &Config{
+ MaxVersion: vers.version,
+ MaxEarlyDataSize: 16384,
+ Bugs: ProtocolBugs{
+ ExpectEarlyData: [][]byte{[]byte("hello")},
+ },
+ },
+ tls13Variant: vers.tls13Variant,
+ resumeSession: true,
+ shouldFail: true,
+ expectedError: ":CERTIFICATE_VERIFY_FAILED:",
+ flags: append([]string{
+ "-enable-early-data",
+ "-expect-ticket-supports-early-data",
+ "-reverify-on-resume",
+ "-on-resume-verify-fail",
+ "-on-resume-shim-writes-first",
+ }, flags...),
+ })
+ }
}
}
}
@@ -14467,6 +14636,162 @@
}
}
+func addJDK11WorkaroundTests() {
+ // Test the client treats the JDK 11 downgrade random like the usual one.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "Client-RejectJDK11DowngradeRandom",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendJDK11DowngradeRandom: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":TLS13_DOWNGRADE:",
+ expectedLocalError: "remote error: illegal parameter",
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "Client-AcceptJDK11DowngradeRandom",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendJDK11DowngradeRandom: true,
+ },
+ },
+ flags: []string{"-max-version", strconv.Itoa(VersionTLS12)},
+ })
+
+ var clientHelloTests = []struct {
+ clientHello []byte
+ isJDK11 bool
+ }{
+ {
+ // A default JDK 11 ClientHello.
+ decodeHexOrPanic("010001a9030336a379aa355a22a064b4402760efae1c73977b0b4c975efc7654c35677723dde201fe3f8a2bca60418a68f72463ea19f3c241e7cbfceb347e451a62bd2417d8981005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff01000106000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002b0009080304030303020301002d000201010033004700450017004104721f007464cb08a0f36e093ad178eb78d6968df20077b2dd882694a85dc4c9884caf5092db41f16cc3f8d41f59426992fa5e32cfb9ad08deee752cdd95b1a6b5"),
+ true,
+ },
+ {
+ // The above with supported_versions and
+ // psk_key_exchange_modes in the wrong order.
+ decodeHexOrPanic("010001a9030336a379aa355a22a064b4402760efae1c73977b0b4c975efc7654c35677723dde201fe3f8a2bca60418a68f72463ea19f3c241e7cbfceb347e451a62bd2417d8981005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff01000106000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002d00020101002b00090803040303030203010033004700450017004104721f007464cb08a0f36e093ad178eb78d6968df20077b2dd882694a85dc4c9884caf5092db41f16cc3f8d41f59426992fa5e32cfb9ad08deee752cdd95b1a6b5"),
+ false,
+ },
+ {
+ // The above with a padding extension added at the end.
+ decodeHexOrPanic("010001b4030336a379aa355a22a064b4402760efae1c73977b0b4c975efc7654c35677723dde201fe3f8a2bca60418a68f72463ea19f3c241e7cbfceb347e451a62bd2417d8981005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff01000111000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002b0009080304030303020301002d000201010033004700450017004104721f007464cb08a0f36e093ad178eb78d6968df20077b2dd882694a85dc4c9884caf5092db41f16cc3f8d41f59426992fa5e32cfb9ad08deee752cdd95b1a6b50015000770616464696e67"),
+ false,
+ },
+ {
+ // A JDK 11 ClientHello offering a TLS 1.3 PSK.
+ decodeHexOrPanic("0100024c0303a8d71b20f060545a398226e807d21371a7a02b7ca2f96f476c2dea7e5860c5a400005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff010001c9000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002b0009080304030303020301002d000201010033004700450017004104aaec585ea9e121b24710a23560571322b2cf8ab8cd14e5762ef0486d8a6d0ecd721d8f2abda2eb8ed5ab7195505660450f49bba94bbf0c3f0070a531d9a1be4f002900cb00a600a0e6f7586d9a2bf64a54c1adf55a2f76657047e8e88e26629e2e7b9d630941e06fd87792770f6834e159a70b252157a9b4b082183f24629c8ff5049088b07ce37c49de8cf752a2ed7a545aff63bdc7a1b18e1bc201f23f159ee75d4987a04e00f840824f764691ab83a20e3032646e793065874cdb46138a52f50ed71406f399f96f9309eba4e5b1966148c22a63dc4aa1364269dd41dd5cc0e848d07af0095622c52cfcfc00212009cc315259e2328d65ad17a3de7c182c7874140a9356fecdd4614657806cd659"),
+ true,
+ },
+ {
+ // A JDK 11 ClientHello offering a TLS 1.2 session.
+ decodeHexOrPanic("010001a903038cdec49f4836d064a75046c93f22d0b9c2cf4900917332e6f0e1f41d692d3146201a3e99047492285ec65ab4e0eeee59f8f9d1eb7687398887bcd7b81353e93923005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff01000106000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002b0009080304030303020301002d0002010100330047004500170041041c83c42fcd8fc06265b9f6e4f076f7e7ee17ace915c587845c0e1bc8cd177f904befeb611b682cae4702509a5f5d0c7162a282b8152d843169b91136e7c6f3e7"),
+ true,
+ },
+ {
+ // A JDK 11 ClientHello with EMS disabled.
+ decodeHexOrPanic("010001a50303323a857c324a9ef57d6e2544d129073830385cb1dc75ea79f6a2ec8ae09d2e7320f85fdd081678874c67ebab235e6d6a81d947f690bc0af9be4d39854ed67d9ef9005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff01000102000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b040105010601040203030301030202030201020200110009000702000400000000002b0009080304030303020301002d0002010100330047004500170041049c904c4850b495d75522f955d79e9cabea065c90279d6037a101a4c4ee712afc93ad0df5d12d287d53e458c7075d9a3ce3969c939bb62222bda779cecf54a603"),
+ true,
+ },
+ {
+ // A JDK 11 ClientHello with OCSP stapling disabled.
+ decodeHexOrPanic("0100019303038a50481dc85ee4f6581670821c50f2b3d34ac3251dc6e9b751bfd2521ab47ab02069a963c5486034c37ae0577ddb4c2db28cab592380ef8e4599d1305148712112005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff010000f0000000080006000003736e69000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b040105010601040203030301030202030201020200170000002b0009080304030303020301002d00020101003300470045001700410438a97824f842c549e3c339322d8b2dbaa85d10bd7bca9c969376cb0c60b1e929eb4d13db38dcb0082ad8c637b24f55466a9acbb0b63634c1f431ec8342cf720d"),
+ true,
+ },
+ {
+ // A JDK 11 ClientHello configured with a smaller set of
+ // ciphers.
+ decodeHexOrPanic("0100015603036f5706bbdf1dcae671cd9be043603f5ed20f8fc195b426504cafb4f353edb0012007aabd35e588bc2504a72eda42cbbf89d69cfc0a6a1d77db0d757606f1f4811800061301c02bc02f01000107000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002b00050403040303002d000201010033004700450017004104d283f3d5a90259b61d43ea1511211f568ce5d18457326b717e1f9d6b7d1476f2b51cdc3c798d3bdfba5095edff0ffd0540f6bc0c324bd9744f3b3f24317496e3ff01000100"),
+ true,
+ },
+ {
+ // The above with TLS_CHACHA20_POLY1305_SHA256 added,
+ // which JDK 11 does not support.
+ decodeHexOrPanic("0100015803036f5706bbdf1dcae671cd9be043603f5ed20f8fc195b426504cafb4f353edb0012007aabd35e588bc2504a72eda42cbbf89d69cfc0a6a1d77db0d757606f1f48118000813011303c02bc02f01000107000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002b00050403040303002d000201010033004700450017004104d283f3d5a90259b61d43ea1511211f568ce5d18457326b717e1f9d6b7d1476f2b51cdc3c798d3bdfba5095edff0ffd0540f6bc0c324bd9744f3b3f24317496e3ff01000100"),
+ false,
+ },
+ {
+ // The above with X25519 added, which JDK 11 does not
+ // support.
+ decodeHexOrPanic("0100015803036f5706bbdf1dcae671cd9be043603f5ed20f8fc195b426504cafb4f353edb0012007aabd35e588bc2504a72eda42cbbf89d69cfc0a6a1d77db0d757606f1f4811800061301c02bc02f01000109000000080006000003736e69000500050100000000000a00220020001d0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020011000900070200040000000000170000002b00050403040303002d000201010033004700450017004104d283f3d5a90259b61d43ea1511211f568ce5d18457326b717e1f9d6b7d1476f2b51cdc3c798d3bdfba5095edff0ffd0540f6bc0c324bd9744f3b3f24317496e3ff01000100"),
+ false,
+ },
+ {
+ // A JDK 11 ClientHello with ALPN protocols configured.
+ decodeHexOrPanic("010001bb0303c0e0ea707b00c5311eb09cabd58626692cebfaefaef7265637e4550811dae16220da86d6eea04e214e873675223f08a6926bcf79f16d866280bdbab85e9e09c3ff005a13011302c02cc02bc030009dc02ec032009f00a3c02f009cc02dc031009e00a2c024c028003dc026c02a006b006ac00ac0140035c005c00f00390038c023c027003cc025c02900670040c009c013002fc004c00e0033003200ff01000118000000080006000003736e69000500050100000000000a0020001e0017001800190009000a000b000c000d000e001601000101010201030104000b00020100000d002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020032002800260403050306030804080508060809080a080b04010501060104020303030103020203020102020010000e000c02683208687474702f312e310011000900070200040000000000170000002b0009080304030303020301002d00020101003300470045001700410416def07c1d66ddde5fc9dcc328c8e77022d321c590c0d30cb41d515b38dca34540819a216c6c053bd47b9068f4f6b960f03647de4e36e8b7ffeea78f7252e3d9"),
+ true,
+ },
+ }
+ for i, t := range clientHelloTests {
+ expectedVersion := uint16(VersionTLS13)
+ if t.isJDK11 {
+ expectedVersion = VersionTLS12
+ }
+
+ // In each of these tests, we set DefaultCurves to P-256 to
+ // match the test inputs. SendClientHelloWithFixes requires the
+ // key_shares extension to match in type.
+
+ // With the workaround enabled, we should negotiate TLS 1.2 on
+ // JDK 11 ClientHellos.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: fmt.Sprintf("Server-JDK11-%d", i),
+ config: Config{
+ MaxVersion: VersionTLS13,
+ DefaultCurves: []CurveID{CurveP256},
+ Bugs: ProtocolBugs{
+ SendClientHelloWithFixes: t.clientHello,
+ ExpectJDK11DowngradeRandom: t.isJDK11,
+ },
+ },
+ expectedVersion: expectedVersion,
+ flags: []string{"-jdk11-workaround"},
+ })
+
+ // With the workaround disabled, we always negotiate TLS 1.3.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: fmt.Sprintf("Server-JDK11-NoWorkaround-%d", i),
+ config: Config{
+ MaxVersion: VersionTLS13,
+ DefaultCurves: []CurveID{CurveP256},
+ Bugs: ProtocolBugs{
+ SendClientHelloWithFixes: t.clientHello,
+ ExpectJDK11DowngradeRandom: false,
+ },
+ },
+ expectedVersion: VersionTLS13,
+ })
+
+ // If the server does not support TLS 1.3, the workaround should
+ // be a no-op. In particular, it should not send the downgrade
+ // signal.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: fmt.Sprintf("Server-JDK11-TLS12-%d", i),
+ config: Config{
+ MaxVersion: VersionTLS13,
+ DefaultCurves: []CurveID{CurveP256},
+ Bugs: ProtocolBugs{
+ SendClientHelloWithFixes: t.clientHello,
+ ExpectJDK11DowngradeRandom: false,
+ },
+ },
+ expectedVersion: VersionTLS12,
+ flags: []string{
+ "-jdk11-workaround",
+ "-max-version", strconv.Itoa(VersionTLS12),
+ },
+ })
+ }
+}
+
func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) {
defer wg.Done()
@@ -14502,10 +14827,10 @@
err error
}
-func statusPrinter(doneChan chan *testOutput, statusChan chan statusMsg, total int) {
+func statusPrinter(doneChan chan *testresult.Results, statusChan chan statusMsg, total int) {
var started, done, failed, unimplemented, lineLen int
- testOutput := newTestOutput()
+ testOutput := testresult.NewResults()
for msg := range statusChan {
if !*pipe {
// Erase the previous status line.
@@ -14528,18 +14853,22 @@
fmt.Printf("UNIMPLEMENTED (%s)\n", msg.test.name)
}
unimplemented++
- testOutput.addResult(msg.test.name, "UNIMPLEMENTED")
+ if *allowUnimplemented {
+ testOutput.AddSkip(msg.test.name)
+ } else {
+ testOutput.AddResult(msg.test.name, "SKIP")
+ }
} else {
fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
failed++
- testOutput.addResult(msg.test.name, "FAIL")
+ testOutput.AddResult(msg.test.name, "FAIL")
}
} else {
if *pipe {
// Print each test instead of a status line.
fmt.Printf("PASSED (%s)\n", msg.test.name)
}
- testOutput.addResult(msg.test.name, "PASS")
+ testOutput.AddResult(msg.test.name, "PASS")
}
}
@@ -14596,6 +14925,7 @@
addExtraHandshakeTests()
addOmitExtensionsTests()
addCertCompressionTests()
+ addJDK11WorkaroundTests()
testCases = append(testCases, convertToSplitHandshakeTests(testCases)...)
@@ -14603,7 +14933,7 @@
statusChan := make(chan statusMsg, *numWorkers)
testChan := make(chan *testCase, *numWorkers)
- doneChan := make(chan *testOutput)
+ doneChan := make(chan *testresult.Results)
if len(*shimConfigFile) != 0 {
encoded, err := ioutil.ReadFile(*shimConfigFile)
@@ -14676,16 +15006,12 @@
fmt.Printf("\n")
if *jsonOutput != "" {
- if err := testOutput.writeTo(*jsonOutput); err != nil {
+ if err := testOutput.WriteToFile(*jsonOutput); err != nil {
fmt.Fprintf(os.Stderr, "Error: %s\n", err)
}
}
- if !*allowUnimplemented && testOutput.NumFailuresByType["UNIMPLEMENTED"] > 0 {
- os.Exit(1)
- }
-
- if !testOutput.noneFailed {
+ if !testOutput.HasUnexpectedResults() {
os.Exit(1)
}
}
diff --git a/src/ssl/test/runner/test_output.go b/src/ssl/test/runner/test_output.go
deleted file mode 100644
index eb54638..0000000
--- a/src/ssl/test/runner/test_output.go
+++ /dev/null
@@ -1,79 +0,0 @@
-/* Copyright (c) 2015, Google Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
-
-package runner
-
-import (
- "encoding/json"
- "os"
- "time"
-)
-
-// testOutput is a representation of Chromium's JSON test result format. See
-// https://www.chromium.org/developers/the-json-test-results-format
-type testOutput struct {
- Version int `json:"version"`
- Interrupted bool `json:"interrupted"`
- PathDelimiter string `json:"path_delimiter"`
- SecondsSinceEpoch float64 `json:"seconds_since_epoch"`
- NumFailuresByType map[string]int `json:"num_failures_by_type"`
- Tests map[string]testResult `json:"tests"`
- noneFailed bool
-}
-
-type testResult struct {
- Actual string `json:"actual"`
- Expected string `json:"expected"`
- IsUnexpected bool `json:"is_unexpected"`
-}
-
-func newTestOutput() *testOutput {
- return &testOutput{
- Version: 3,
- PathDelimiter: ".",
- SecondsSinceEpoch: float64(time.Now().UnixNano()) / float64(time.Second/time.Nanosecond),
- NumFailuresByType: make(map[string]int),
- Tests: make(map[string]testResult),
- noneFailed: true,
- }
-}
-
-func (t *testOutput) addResult(name, result string) {
- if _, found := t.Tests[name]; found {
- panic(name)
- }
- t.Tests[name] = testResult{
- Actual: result,
- Expected: "PASS",
- IsUnexpected: result != "PASS",
- }
- t.NumFailuresByType[result]++
- if result != "PASS" && result != "UNIMPLEMENTED" {
- t.noneFailed = false
- }
-}
-
-func (t *testOutput) writeTo(name string) error {
- file, err := os.Create(name)
- if err != nil {
- return err
- }
- defer file.Close()
- out, err := json.MarshalIndent(t, "", " ")
- if err != nil {
- return err
- }
- _, err = file.Write(out)
- return err
-}
diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc
index 52e6cf7..7447d5a 100644
--- a/src/ssl/test/test_config.cc
+++ b/src/ssl/test/test_config.cc
@@ -146,6 +146,7 @@
{ "-is-handshaker-supported", &TestConfig::is_handshaker_supported },
{ "-handshaker-resume", &TestConfig::handshaker_resume },
{ "-reverify-on-resume", &TestConfig::reverify_on_resume },
+ { "-jdk11-workaround", &TestConfig::jdk11_workaround },
};
const Flag<std::string> kStringFlags[] = {
@@ -1624,6 +1625,9 @@
return nullptr;
}
}
+ if (jdk11_workaround) {
+ SSL_set_jdk11_workaround(ssl.get(), 1);
+ }
if (session != NULL) {
if (!is_server) {
diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h
index b65ca42..bffe911 100644
--- a/src/ssl/test/test_config.h
+++ b/src/ssl/test/test_config.h
@@ -169,6 +169,7 @@
bool is_handshaker_supported = false;
bool handshaker_resume = false;
std::string handshaker_path;
+ bool jdk11_workaround = false;
int argc;
char **argv;
diff --git a/src/ssl/tls13_both.cc b/src/ssl/tls13_both.cc
index 299fc14..6baeaf7 100644
--- a/src/ssl/tls13_both.cc
+++ b/src/ssl/tls13_both.cc
@@ -43,12 +43,15 @@
0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c,
};
+// See RFC 8446, section 4.1.3.
const uint8_t kTLS12DowngradeRandom[8] = {0x44, 0x4f, 0x57, 0x4e,
0x47, 0x52, 0x44, 0x00};
-
const uint8_t kTLS13DowngradeRandom[8] = {0x44, 0x4f, 0x57, 0x4e,
0x47, 0x52, 0x44, 0x01};
+// This is a non-standard randomly-generated value.
+const uint8_t kJDK11DowngradeRandom[8] = {0xed, 0xbf, 0xb4, 0xa8,
+ 0xc2, 0x47, 0x10, 0xff};
bool tls13_get_cert_verify_signature_input(
SSL_HANDSHAKE *hs, Array<uint8_t> *out,
diff --git a/src/ssl/tls13_client.cc b/src/ssl/tls13_client.cc
index fb56001..0d3e877 100644
--- a/src/ssl/tls13_client.cc
+++ b/src/ssl/tls13_client.cc
@@ -465,7 +465,7 @@
SSL *const ssl = hs->ssl;
// CertificateRequest may only be sent in non-resumption handshakes.
if (ssl->s3->session_reused) {
- if (ssl->ctx->reverify_on_resume) {
+ if (ssl->ctx->reverify_on_resume && !ssl->s3->early_data_accepted) {
hs->tls13_state = state_server_certificate_reverify;
return ssl_hs_ok;
}
diff --git a/src/ssl/tls13_server.cc b/src/ssl/tls13_server.cc
index 969d4b1..b4c4ca5 100644
--- a/src/ssl/tls13_server.cc
+++ b/src/ssl/tls13_server.cc
@@ -12,13 +12,6 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
-// Per C99, various stdint.h macros are unavailable in C++ unless some macros
-// are defined. C++11 overruled this decision, but older Android NDKs still
-// require it.
-#if !defined(__STDC_LIMIT_MACROS)
-#define __STDC_LIMIT_MACROS
-#endif
-
#include <openssl/ssl.h>
#include <assert.h>