aboutsummaryrefslogtreecommitdiff
path: root/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'ssl')
-rw-r--r--ssl/handshake_server.cc16
-rw-r--r--ssl/test/runner/common.go3
-rw-r--r--ssl/test/runner/handshake_client.go4
-rw-r--r--ssl/test/runner/runner.go50
-rw-r--r--ssl/test/test_config.cc21
-rw-r--r--ssl/test/test_config.h2
6 files changed, 93 insertions, 3 deletions
diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc
index afa0927..508f9bf 100644
--- a/ssl/handshake_server.cc
+++ b/ssl/handshake_server.cc
@@ -613,6 +613,10 @@ static bool extract_sni(SSL_HANDSHAKE *hs, uint8_t *out_alert,
if (!ssl_client_hello_get_extension(client_hello, &sni,
TLSEXT_TYPE_server_name)) {
// No SNI extension to parse.
+ //
+ // Clear state in case we previously extracted SNI from ClientHelloOuter.
+ ssl->s3->hostname.reset();
+ hs->should_ack_sni = false;
return true;
}
@@ -686,7 +690,10 @@ static enum ssl_hs_wait_t do_read_client_hello(SSL_HANDSHAKE *hs) {
}
uint8_t alert = SSL_AD_DECODE_ERROR;
- if (!decrypt_ech(hs, &alert, &client_hello)) {
+ // We check for rejection status in case we've rewound the state machine after
+ // determining `ClientHelloInner` is invalid.
+ if (ssl->s3->ech_status != ssl_ech_rejected &&
+ !decrypt_ech(hs, &alert, &client_hello)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return ssl_hs_error;
}
@@ -722,6 +729,13 @@ static enum ssl_hs_wait_t do_read_client_hello_after_ech(SSL_HANDSHAKE *hs) {
case ssl_select_cert_retry:
return ssl_hs_certificate_selection_pending;
+ case ssl_select_cert_disable_ech:
+ hs->ech_client_hello_buf.Reset();
+ hs->ech_keys = nullptr;
+ hs->state = state12_read_client_hello;
+ ssl->s3->ech_status = ssl_ech_rejected;
+ return ssl_hs_ok;
+
case ssl_select_cert_error:
// Connection rejected.
OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 3a8caa1..6bdd664 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -1965,6 +1965,9 @@ type ProtocolBugs struct {
// EncryptSessionTicketKey, if non-nil, is the ticket key to use when
// encrypting tickets.
EncryptSessionTicketKey *[32]byte
+
+ // OmitPublicName omits the server name extension from ClientHelloOuter.
+ OmitPublicName bool
}
func (c *Config) serverInit() {
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index a0a81f9..a7ab0e2 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -583,6 +583,10 @@ func (hs *clientHandshakeState) createClientHello(innerHello *clientHelloMsg, ec
hello.serverName = c.config.ServerName
}
+ if !isInner && c.config.Bugs.OmitPublicName {
+ hello.serverName = ""
+ }
+
disableEMS := c.config.Bugs.NoExtendedMasterSecret
if c.cipherSuite != nil {
disableEMS = c.config.Bugs.NoExtendedMasterSecretOnRenegotiation
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 3aab605..18ed78b 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -17343,6 +17343,56 @@ write hs 4
},
})
+ // Test that we successfully rewind the TLS state machine and disable ECH in the
+ // case that the select_cert_cb signals that ECH is not possible for the SNI in
+ // ClientHelloInner.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ protocol: protocol,
+ name: prefix + "ECH-Server-FailCallbackNeedRewind",
+ config: Config{
+ ServerName: "secret.example",
+ ClientECHConfig: echConfig.ECHConfig,
+ },
+ flags: []string{
+ "-async",
+ "-fail-early-callback-ech-rewind",
+ "-ech-server-config", base64FlagValue(echConfig.ECHConfig.Raw),
+ "-ech-server-key", base64FlagValue(echConfig.Key),
+ "-ech-is-retry-config", "1",
+ "-expect-server-name", "public.example",
+ },
+ expectations: connectionExpectations{
+ echAccepted: false,
+ },
+ })
+
+ // Test that we correctly handle falling back to a ClientHelloOuter with
+ // no SNI (public name).
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ protocol: protocol,
+ name: prefix + "ECH-Server-RewindWithNoPublicName",
+ config: Config{
+ ServerName: "secret.example",
+ ClientECHConfig: echConfig.ECHConfig,
+ Bugs: ProtocolBugs{
+ OmitPublicName: true,
+ },
+ },
+ flags: []string{
+ "-async",
+ "-fail-early-callback-ech-rewind",
+ "-ech-server-config", base64FlagValue(echConfig.ECHConfig.Raw),
+ "-ech-server-key", base64FlagValue(echConfig.Key),
+ "-ech-is-retry-config", "1",
+ "-expect-no-server-name",
+ },
+ expectations: connectionExpectations{
+ echAccepted: false,
+ },
+ })
+
// Test ECH-enabled server with two ECHConfigs can decrypt client's ECH when
// it uses the second ECHConfig.
testCases = append(testCases, testCase{
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 24b1bdd..dfe1cb4 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -354,6 +354,7 @@ const Flag<TestConfig> *FindFlag(const char *name) {
BoolFlag("-implicit-handshake", &TestConfig::implicit_handshake),
BoolFlag("-use-early-callback", &TestConfig::use_early_callback),
BoolFlag("-fail-early-callback", &TestConfig::fail_early_callback),
+ BoolFlag("-fail-early-callback-ech-rewind", &TestConfig::fail_early_callback_ech_rewind),
BoolFlag("-install-ddos-callback", &TestConfig::install_ddos_callback),
BoolFlag("-fail-ddos-callback", &TestConfig::fail_ddos_callback),
BoolFlag("-fail-cert-callback", &TestConfig::fail_cert_callback),
@@ -374,6 +375,8 @@ const Flag<TestConfig> *FindFlag(const char *name) {
&TestConfig::expect_reject_early_data),
BoolFlag("-expect-no-offer-early-data",
&TestConfig::expect_no_offer_early_data),
+ BoolFlag("-expect-no-server-name",
+ &TestConfig::expect_no_server_name),
BoolFlag("-use-ticket-callback", &TestConfig::use_ticket_callback),
BoolFlag("-renew-ticket", &TestConfig::renew_ticket),
BoolFlag("-enable-early-data", &TestConfig::enable_early_data),
@@ -1581,9 +1584,23 @@ static enum ssl_select_cert_result_t SelectCertificateCallback(
TestState *test_state = GetTestState(ssl);
test_state->early_callback_called = true;
+ // Invoke the rewind before we sanity check SNI because we will
+ // end up calling the select_cert_cb twice with two different SNIs.
+ if (SSL_ech_accepted(ssl) && config->fail_early_callback_ech_rewind) {
+ return ssl_select_cert_disable_ech;
+ }
+
+ const char *server_name =
+ SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+
+ if (config->expect_no_server_name && server_name != nullptr) {
+ fprintf(stderr,
+ "Expected no server name but got %s.\n",
+ server_name);
+ return ssl_select_cert_error;
+ }
+
if (!config->expect_server_name.empty()) {
- const char *server_name =
- SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if (server_name == nullptr ||
std::string(server_name) != config->expect_server_name) {
fprintf(stderr,
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index 89656d1..607f58d 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -118,6 +118,7 @@ struct TestConfig {
bool implicit_handshake = false;
bool use_early_callback = false;
bool fail_early_callback = false;
+ bool fail_early_callback_ech_rewind = false;
bool install_ddos_callback = false;
bool fail_ddos_callback = false;
bool fail_cert_callback = false;
@@ -134,6 +135,7 @@ struct TestConfig {
bool expect_accept_early_data = false;
bool expect_reject_early_data = false;
bool expect_no_offer_early_data = false;
+ bool expect_no_server_name = false;
bool use_ticket_callback = false;
bool renew_ticket = false;
bool enable_early_data = false;