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{