Problem Description
In Golang's crypto/tls implementation, the function decodeInnerClientHello contains the following code:
if len(inner.supportedVersions) != 1 || (len(inner.supportedVersions) >= 1 && inner.supportedVersions[0] != VersionTLS13) {
return nil, errors.New("tls: client sent encrypted_client_hello extension and offered incompatible versions")
}
This logic requires supportedVersions to contain exactly one version, which must be TLS 1.3, otherwise, the connection is rejected.
However, Chrome and Edge use the GREASE mechanism, which means supportedVersions may contain multiple values, such as:
supported_versions: [GREASE, TLS 1.3]
Since len(inner.supportedVersions) != 1, Golang incorrectly rejects these connections, causing Chrome and Edge to fail when accessing a Golang Web server with ECH enabled, while Firefox works fine.
Steps to Reproduce
Start a Golang crypto/tls server with ECH enabled.
Try accessing the server using Chrome or Edge.
The connection fails with a TLS error in Chrome.
Try accessing the server using Firefox.
The connection works fine.
Expected Behavior
The server should accept connections as long as supportedVersions contains TLS 1.3, rather than rejecting them due to the GREASE mechanism.
Suggested Fix
Modify decodeInnerClientHello logic to:
Ignore GREASE values (i.e., values with the format 0xXAXA).
Allow multiple versions in supportedVersions, as long as TLS 1.3 is included.
Proposed Code Change
hasTLS13 := false
for _, v := range inner.supportedVersions {
if v == VersionTLS13 {
hasTLS13 = true
break
}
}
if !hasTLS13 {
return nil, errors.New("tls: client sent encrypted_client_hello extension but did not offer TLS 1.3")
}
This ensures compatibility with Chrome and Edge while maintaining ECH security.
Related Fix Proposal
🔗 Gerrit CL: https://go-review.googlesource.com/c/go/+/648015
Problem Description
In Golang's crypto/tls implementation, the function decodeInnerClientHello contains the following code:
This logic requires supportedVersions to contain exactly one version, which must be TLS 1.3, otherwise, the connection is rejected.
However, Chrome and Edge use the GREASE mechanism, which means supportedVersions may contain multiple values, such as:
supported_versions: [GREASE, TLS 1.3]
Since len(inner.supportedVersions) != 1, Golang incorrectly rejects these connections, causing Chrome and Edge to fail when accessing a Golang Web server with ECH enabled, while Firefox works fine.
Steps to Reproduce
Start a Golang crypto/tls server with ECH enabled.
Try accessing the server using Chrome or Edge.
The connection fails with a TLS error in Chrome.
Try accessing the server using Firefox.
The connection works fine.
Expected Behavior
The server should accept connections as long as supportedVersions contains TLS 1.3, rather than rejecting them due to the GREASE mechanism.
Suggested Fix
Modify decodeInnerClientHello logic to:
Ignore GREASE values (i.e., values with the format 0xXAXA).
Allow multiple versions in supportedVersions, as long as TLS 1.3 is included.
Proposed Code Change
This ensures compatibility with Chrome and Edge while maintaining ECH security.
Related Fix Proposal
🔗 Gerrit CL: https://go-review.googlesource.com/c/go/+/648015