Reject the ECH extension in TLS 1.2 ServerHello.
The ECH server extension is defined for TLS 1.3 EncryptedExtensions, not
TLS 1.2 ServerHello.
Bug: 275
Change-Id: Ie6e76c238075d70e6a0694ec0192df07da3457d1
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/47910
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc
index 44c96e8..3553276 100644
--- a/ssl/t1_lib.cc
+++ b/ssl/t1_lib.cc
@@ -688,10 +688,19 @@
static bool ext_ech_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
CBS *contents) {
+ SSL *const ssl = hs->ssl;
if (contents == NULL) {
return true;
}
+ // The ECH extension may not be sent in TLS 1.2 ServerHello, only TLS 1.3
+ // EncryptedExtension.
+ if (ssl_protocol_version(ssl) < TLS1_3_VERSION) {
+ *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ return false;
+ }
+
// If the client only sent GREASE, we must check the extension syntactically.
CBS ech_configs;
if (!CBS_get_u16_length_prefixed(contents, &ech_configs) ||
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 4e84a0e..ae07dc0 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -859,6 +859,10 @@
// retry configs.
SendECHRetryConfigs []byte
+ // SendECHRetryConfigsInTLS12ServerHello, if true, causes the ECH server to
+ // send retry configs in the TLS 1.2 ServerHello.
+ SendECHRetryConfigsInTLS12ServerHello bool
+
// SendInvalidECHIsInner, if not empty, causes the client to send the
// specified byte string in the ech_is_inner extension.
SendInvalidECHIsInner []byte
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index ef21c24..8622bfa 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -428,10 +428,6 @@
return errors.New("tls: expected client to send ClientECH")
}
- if hs.clientHello.clientECH != nil && len(config.Bugs.SendECHRetryConfigs) > 0 {
- encryptedExtensions.extensions.echRetryConfigs = config.Bugs.SendECHRetryConfigs
- }
-
// Select the cipher suite.
var preferenceList, supportedList []uint16
if config.PreferServerCipherSuites {
@@ -1528,6 +1524,10 @@
serverExtensions.serverNameAck = c.config.Bugs.SendServerNameAck
+ if (c.vers >= VersionTLS13 || c.config.Bugs.SendECHRetryConfigsInTLS12ServerHello) && hs.clientHello.clientECH != nil && len(config.Bugs.SendECHRetryConfigs) > 0 {
+ serverExtensions.echRetryConfigs = config.Bugs.SendECHRetryConfigs
+ }
+
return nil
}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 176fdd9..2a861f3 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -16887,11 +16887,11 @@
0x05, 0x04, 0x03, 0x02, 0x01,
}
- validAndInvalidConfigsBuilder := newByteBuilder()
- validAndInvalidConfigsBody := validAndInvalidConfigsBuilder.addU16LengthPrefixed()
- validAndInvalidConfigsBody.addBytes(MarshalECHConfig(&retryConfigValid))
- validAndInvalidConfigsBody.addBytes(retryConfigUnsupportedVersion)
- validAndInvalidConfigs := validAndInvalidConfigsBuilder.finish()
+ validAndUnsupportedConfigsBuilder := newByteBuilder()
+ validAndUnsupportedConfigsBody := validAndUnsupportedConfigsBuilder.addU16LengthPrefixed()
+ validAndUnsupportedConfigsBody.addBytes(MarshalECHConfig(&retryConfigValid))
+ validAndUnsupportedConfigsBody.addBytes(retryConfigUnsupportedVersion)
+ validAndUnsupportedConfigs := validAndUnsupportedConfigsBuilder.finish()
// Test that the client accepts a well-formed encrypted_client_hello
// extension in response to ECH GREASE. The response includes one ECHConfig
@@ -16905,15 +16905,37 @@
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
ExpectClientECH: true,
- // Include an additional well-formed ECHConfig with an invalid
- // version. This ensures the client can iterate over the retry
- // configs.
- SendECHRetryConfigs: validAndInvalidConfigs,
+ // Include an additional well-formed ECHConfig with an
+ // unsupported version. This ensures the client can skip
+ // unsupported configs.
+ SendECHRetryConfigs: validAndUnsupportedConfigs,
},
},
flags: []string{"-enable-ech-grease"},
})
+ if protocol != quic {
+ // Test that the client rejects retry configs in TLS 1.2.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ protocol: protocol,
+ name: prefix + "ECH-GREASE-Client-TLS12-Retry-Configs",
+ config: Config{
+ MinVersion: VersionTLS12,
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ExpectClientECH: true,
+ SendECHRetryConfigs: validAndUnsupportedConfigs,
+ SendECHRetryConfigsInTLS12ServerHello: true,
+ },
+ },
+ flags: []string{"-enable-ech-grease"},
+ shouldFail: true,
+ expectedLocalError: "remote error: unsupported extension",
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ })
+ }
+
// Test that the client aborts with a decode_error alert when it receives a
// syntactically-invalid encrypted_client_hello extension from the server.
testCases = append(testCases, testCase{