HelloRetryRequest getter
Adds getter indicating whether HelloRetryRequest was triggered
during TLSv1.3 handshake.
Change-Id: I84922188ded81ec89259b5f333c80494426759f8
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/37304
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index be83edf..b0ee69a 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -3946,6 +3946,11 @@
// mechanism would have aborted |ssl|'s handshake and zero otherwise.
OPENSSL_EXPORT int SSL_is_tls13_downgrade(const SSL *ssl);
+// SSL_used_hello_retry_request returns one if the TLS 1.3 HelloRetryRequest
+// message has been either sent by the server or received by the client. It
+// returns zero otherwise.
+OPENSSL_EXPORT int SSL_used_hello_retry_request(const SSL *ssl);
+
// SSL_set_jdk11_workaround configures whether to workaround various bugs in
// JDK 11's TLS 1.3 implementation by disabling TLS 1.3 for such clients.
//
diff --git a/ssl/handshake.cc b/ssl/handshake.cc
index 6791d2a..707c6d2 100644
--- a/ssl/handshake.cc
+++ b/ssl/handshake.cc
@@ -128,8 +128,6 @@
: ssl(ssl_arg),
scts_requested(false),
needs_psk_binder(false),
- received_hello_retry_request(false),
- sent_hello_retry_request(false),
handshake_finalized(false),
accept_psk_mode(false),
cert_request(false),
diff --git a/ssl/internal.h b/ssl/internal.h
index 7f163a4..5f81b22 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1693,9 +1693,6 @@
// be filled in.
bool needs_psk_binder : 1;
- bool received_hello_retry_request : 1;
- bool sent_hello_retry_request : 1;
-
// handshake_finalized is true once the handshake has completed, at which
// point accessors should use the established state.
bool handshake_finalized : 1;
@@ -2387,6 +2384,10 @@
// HelloRequest.
bool renegotiate_pending : 1;
+ // used_hello_retry_request is whether the handshake used a TLS 1.3
+ // HelloRetryRequest message.
+ bool used_hello_retry_request : 1;
+
// hs_buf is the buffer of handshake data to process.
UniquePtr<BUF_MEM> hs_buf;
diff --git a/ssl/s3_lib.cc b/ssl/s3_lib.cc
index f1f0ec7..6b0635b 100644
--- a/ssl/s3_lib.cc
+++ b/ssl/s3_lib.cc
@@ -181,7 +181,8 @@
token_binding_negotiated(false),
pq_experiment_signal_seen(false),
alert_dispatch(false),
- renegotiate_pending(false) {}
+ renegotiate_pending(false),
+ used_hello_retry_request(false) {}
SSL3_STATE::~SSL3_STATE() {}
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index 1af8506..1daf03f 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -2859,6 +2859,10 @@
int SSL_is_tls13_downgrade(const SSL *ssl) { return ssl->s3->tls13_downgrade; }
+int SSL_used_hello_retry_request(const SSL *ssl) {
+ return ssl->s3->used_hello_retry_request;
+}
+
void SSL_CTX_set_ignore_tls13_downgrade(SSL_CTX *ctx, int ignore) {
ctx->ignore_tls13_downgrade = !!ignore;
}
diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc
index e5a33dd..298dc9b 100644
--- a/ssl/t1_lib.cc
+++ b/ssl/t1_lib.cc
@@ -1845,7 +1845,7 @@
// Per RFC 8446 section 4.1.4, skip offering the session if the selected
// cipher in HelloRetryRequest does not match. This avoids performing the
// transcript hash transformation for multiple hashes.
- if (hs->received_hello_retry_request &&
+ if (ssl->s3 && ssl->s3->used_hello_retry_request &&
ssl->session->cipher->algorithm_prf != hs->new_cipher->algorithm_prf) {
return true;
}
@@ -2035,7 +2035,7 @@
SSL *const ssl = hs->ssl;
// The second ClientHello never offers early data, and we must have already
// filled in |early_data_reason| by this point.
- if (hs->received_hello_retry_request) {
+ if (ssl->s3->used_hello_retry_request) {
assert(ssl->s3->early_data_reason != ssl_early_data_unknown);
return true;
}
@@ -2089,7 +2089,7 @@
CBS *contents) {
SSL *const ssl = hs->ssl;
if (contents == NULL) {
- if (hs->early_data_offered && !hs->received_hello_retry_request) {
+ if (hs->early_data_offered && !ssl->s3->used_hello_retry_request) {
ssl->s3->early_data_reason = ssl->s3->session_reused
? ssl_early_data_peer_declined
: ssl_early_data_session_not_resumed;
@@ -2104,7 +2104,7 @@
// If we received an HRR, the second ClientHello never offers early data, so
// the extensions logic will automatically reject early data extensions as
// unsolicited. This covered by the ServerAcceptsEarlyDataOnHRR test.
- assert(!hs->received_hello_retry_request);
+ assert(!ssl->s3->used_hello_retry_request);
if (CBS_len(contents) != 0) {
*out_alert = SSL_AD_DECODE_ERROR;
@@ -2173,7 +2173,7 @@
uint16_t group_id = hs->retry_group;
uint16_t second_group_id = 0;
- if (hs->received_hello_retry_request) {
+ if (ssl->s3 && ssl->s3->used_hello_retry_request) {
// We received a HelloRetryRequest without a new curve, so there is no new
// share to append. Leave |hs->key_share| as-is.
if (group_id == 0 &&
@@ -2235,7 +2235,7 @@
// Save the contents of the extension to repeat it in the second
// ClientHello.
- if (!hs->received_hello_retry_request &&
+ if (ssl->s3 && !ssl->s3->used_hello_retry_request &&
!hs->key_share_bytes.CopyFrom(
MakeConstSpan(CBB_data(&kse_bytes), CBB_len(&kse_bytes)))) {
return false;
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 61de136..5748fb9 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -676,6 +676,12 @@
return false;
}
+ if ((config->expect_hrr && !SSL_used_hello_retry_request(ssl)) ||
+ (config->expect_no_hrr && SSL_used_hello_retry_request(ssl))) {
+ fprintf(stderr, "Got %sHRR, but wanted opposite.\n",
+ SSL_used_hello_retry_request(ssl) ? "" : "no ");
+ return false;
+ }
return true;
}
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index a4f787a..e78e9a2 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -145,12 +145,12 @@
type CurveID uint16
const (
- CurveP224 CurveID = 21
- CurveP256 CurveID = 23
- CurveP384 CurveID = 24
- CurveP521 CurveID = 25
- CurveX25519 CurveID = 29
- CurveCECPQ2 CurveID = 16696
+ CurveP224 CurveID = 21
+ CurveP256 CurveID = 23
+ CurveP384 CurveID = 24
+ CurveP521 CurveID = 25
+ CurveX25519 CurveID = 29
+ CurveCECPQ2 CurveID = 16696
)
// TLS Elliptic Curve Point Formats
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 18b01aa..660be0a 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -4383,6 +4383,7 @@
resumeSession: true,
// Ensure session tickets are used, not session IDs.
noSessionCache: true,
+ flags: []string{"-expect-no-hrr"},
})
tests = append(tests, testCase{
name: "Basic-Client-RenewTicket",
@@ -4414,7 +4415,10 @@
},
},
resumeSession: true,
- flags: []string{"-expect-no-session-id"},
+ flags: []string{
+ "-expect-no-session-id",
+ "-expect-no-hrr",
+ },
})
tests = append(tests, testCase{
testType: serverTest,
@@ -4482,6 +4486,7 @@
},
// Cover HelloRetryRequest during an ECDHE-PSK resumption.
resumeSession: true,
+ flags: []string{"-expect-hrr"},
})
tests = append(tests, testCase{
@@ -4495,6 +4500,7 @@
},
// Cover HelloRetryRequest during an ECDHE-PSK resumption.
resumeSession: true,
+ flags: []string{"-expect-hrr"},
})
tests = append(tests, testCase{
@@ -12538,6 +12544,7 @@
CurvePreferences: []CurveID{CurveX25519},
},
expectedCurveID: CurveX25519,
+ flags: []string{"-expect-hrr"},
})
testCases = append(testCases, testCase{
@@ -12551,6 +12558,7 @@
// Although the ClientHello did not predict our preferred curve,
// we always select it whether it is predicted or not.
expectedCurveID: CurveX25519,
+ flags: []string{"-expect-hrr"},
})
testCases = append(testCases, testCase{
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 23de5e9..a4a37e6 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -153,6 +153,8 @@
&TestConfig::expect_delegated_credential_used},
{"-enable-pq-experiment-signal", &TestConfig::enable_pq_experiment_signal},
{"-expect-pq-experiment-signal", &TestConfig::expect_pq_experiment_signal},
+ {"-expect-hrr", &TestConfig::expect_hrr},
+ {"-expect-no-hrr", &TestConfig::expect_no_hrr},
};
const Flag<std::string> kStringFlags[] = {
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index 8c25ed2..b94ca10 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -178,6 +178,8 @@
std::string expect_early_data_reason;
bool enable_pq_experiment_signal = false;
bool expect_pq_experiment_signal = false;
+ bool expect_hrr = false;
+ bool expect_no_hrr = false;
int argc;
char **argv;
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc
index 15c18c2..fa3f3a6 100644
--- a/ssl/tls13_client.cc
+++ b/ssl/tls13_client.cc
@@ -184,7 +184,7 @@
}
ssl->method->next_message(ssl);
- hs->received_hello_retry_request = true;
+ ssl->s3->used_hello_retry_request = true;
hs->tls13_state = state_send_second_client_hello;
// 0-RTT is rejected if we receive a HelloRetryRequest.
if (hs->in_early_data) {
@@ -269,8 +269,7 @@
}
// Check that the cipher matches the one in the HelloRetryRequest.
- if (hs->received_hello_retry_request &&
- hs->new_cipher != cipher) {
+ if (ssl->s3->used_hello_retry_request && hs->new_cipher != cipher) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return ssl_hs_error;
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc
index abacefc..d8115f5 100644
--- a/ssl/tls13_server.cc
+++ b/ssl/tls13_server.cc
@@ -515,7 +515,7 @@
return ssl_hs_error;
}
- hs->sent_hello_retry_request = true;
+ ssl->s3->used_hello_retry_request = true;
hs->tls13_state = state_read_second_client_hello;
return ssl_hs_flush;
}
@@ -612,7 +612,7 @@
return ssl_hs_error;
}
- if (!hs->sent_hello_retry_request &&
+ if (!ssl->s3->used_hello_retry_request &&
!ssl->method->add_change_cipher_spec(ssl)) {
return ssl_hs_error;
}