Implement TLS 1.3 anti-downgrade signal.
Change-Id: Ib4739350948ec339457d993daef582748ed8f100
Reviewed-on: https://boringssl-review.googlesource.com/30924
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc
index cb9b6de..ebf86a9 100644
--- a/ssl/handshake_client.cc
+++ b/ssl/handshake_client.cc
@@ -588,19 +588,23 @@
OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_random),
SSL3_RANDOM_SIZE);
- // Measure, but do not enforce, the TLS 1.3 anti-downgrade feature, with a
- // different value.
- //
- // For draft TLS 1.3 versions, it is not safe to deploy this feature. However,
- // some TLS terminators are non-compliant and copy the origin server's value,
- // so we wish to measure eventual compatibility impact.
+ // Enforce the TLS 1.3 anti-downgrade feature.
if (!ssl->s3->initial_handshake_complete &&
- hs->max_version >= TLS1_3_VERSION &&
- OPENSSL_memcmp(ssl->s3->server_random + SSL3_RANDOM_SIZE -
- sizeof(kDraftDowngradeRandom),
- kDraftDowngradeRandom,
- sizeof(kDraftDowngradeRandom)) == 0) {
- ssl->s3->draft_downgrade = true;
+ ssl_supports_version(hs, TLS1_3_VERSION)) {
+ static_assert(
+ sizeof(kTLS12DowngradeRandom) == 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) {
+ ssl->s3->tls13_downgrade = true;
+ if (!ssl->ctx->ignore_tls13_downgrade) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_TLS13_DOWNGRADE);
+ ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ return ssl_hs_error;
+ }
+ }
}
if (!ssl->s3->initial_handshake_complete && ssl->session != NULL &&
@@ -1477,18 +1481,32 @@
static bool can_false_start(const SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- // False Start only for TLS 1.2 with an ECDHE+AEAD cipher.
+ // False Start bypasses the Finished check's downgrade protection. This can
+ // enable attacks where we send data under weaker settings than supported
+ // (e.g. the Logjam attack). Thus we require TLS 1.2 with an ECDHE+AEAD
+ // cipher, our strongest settings before TLS 1.3.
+ //
+ // Now that TLS 1.3 exists, we would like to avoid similar attacks between
+ // TLS 1.2 and TLS 1.3, but there are too many TLS 1.2 deployments to
+ // sacrifice False Start on them. TLS 1.3's downgrade signal fixes this, but
+ // |SSL_CTX_set_ignore_tls13_downgrade| can disable it due to compatibility
+ // issues.
+ //
+ // |SSL_CTX_set_ignore_tls13_downgrade| normally still retains Finished-based
+ // downgrade protection, but False Start bypasses that. Thus, we disable False
+ // Start based on the TLS 1.3 downgrade signal, even if otherwise unenforced.
if (SSL_is_dtls(ssl) ||
SSL_version(ssl) != TLS1_2_VERSION ||
hs->new_cipher->algorithm_mkey != SSL_kECDHE ||
- hs->new_cipher->algorithm_mac != SSL_AEAD) {
+ hs->new_cipher->algorithm_mac != SSL_AEAD ||
+ ssl->s3->tls13_downgrade) {
return false;
}
// Additionally require ALPN or NPN by default.
//
// TODO(davidben): Can this constraint be relaxed globally now that cipher
- // suite requirements have been relaxed?
+ // suite requirements have been tightened?
if (!ssl->ctx->false_start_allowed_without_alpn &&
ssl->s3->alpn_selected.empty() &&
ssl->s3->next_proto_negotiated.empty()) {