Skip to content

Commit a6c6e59

Browse files
committed
crypto/tls: enforce TLS 1.3 (and TLS 1.2) downgrade protection checks
Fixes #37763 Change-Id: Ic6bcc9af0d164966f4ae31087998e5b546540038 Reviewed-on: https://go-review.googlesource.com/c/go/+/231038 Run-TryBot: Filippo Valsorda <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Katie Hockman <[email protected]>
1 parent b4ecafc commit a6c6e59

File tree

4 files changed

+63
-2
lines changed

4 files changed

+63
-2
lines changed

Diff for: src/crypto/tls/common.go

+4
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,10 @@ const (
207207
downgradeCanaryTLS11 = "DOWNGRD\x00"
208208
)
209209

210+
// testingOnlyForceDowngradeCanary is set in tests to force the server side to
211+
// include downgrade canaries even if it's using its highers supported version.
212+
var testingOnlyForceDowngradeCanary bool
213+
210214
// ConnectionState records basic TLS details about the connection.
211215
type ConnectionState struct {
212216
Version uint16 // TLS version used by the connection (e.g. VersionTLS12)

Diff for: src/crypto/tls/handshake_client.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
5454
return nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion")
5555
}
5656

57-
clientHelloVersion := supportedVersions[0]
57+
clientHelloVersion := config.maxSupportedVersion()
5858
// The version at the beginning of the ClientHello was capped at TLS 1.2
5959
// for compatibility reasons. The supported_versions extension is used
6060
// to negotiate versions now. See RFC 8446, Section 4.2.1.
@@ -181,6 +181,18 @@ func (c *Conn) clientHandshake() (err error) {
181181
return err
182182
}
183183

184+
// If we are negotiating a protocol version that's lower than what we
185+
// support, check for the server downgrade canaries.
186+
// See RFC 8446, Section 4.1.3.
187+
maxVers := c.config.maxSupportedVersion()
188+
tls12Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS12
189+
tls11Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS11
190+
if maxVers == VersionTLS13 && c.vers <= VersionTLS12 && (tls12Downgrade || tls11Downgrade) ||
191+
maxVers == VersionTLS12 && c.vers <= VersionTLS11 && tls11Downgrade {
192+
c.sendAlert(alertIllegalParameter)
193+
return errors.New("tls: downgrade attempt detected, possibly due to a MitM attack or a broken middlebox")
194+
}
195+
184196
if c.vers == VersionTLS13 {
185197
hs := &clientHandshakeStateTLS13{
186198
c: c,

Diff for: src/crypto/tls/handshake_client_test.go

+45
Original file line numberDiff line numberDiff line change
@@ -1984,3 +1984,48 @@ func TestCloseClientConnectionOnIdleServer(t *testing.T) {
19841984
t.Errorf("Error expected, but no error returned")
19851985
}
19861986
}
1987+
1988+
func testDowngradeCanary(t *testing.T, clientVersion, serverVersion uint16) error {
1989+
defer func() { testingOnlyForceDowngradeCanary = false }()
1990+
testingOnlyForceDowngradeCanary = true
1991+
1992+
clientConfig := testConfig.Clone()
1993+
clientConfig.MaxVersion = clientVersion
1994+
serverConfig := testConfig.Clone()
1995+
serverConfig.MaxVersion = serverVersion
1996+
_, _, err := testHandshake(t, clientConfig, serverConfig)
1997+
return err
1998+
}
1999+
2000+
func TestDowngradeCanary(t *testing.T) {
2001+
if err := testDowngradeCanary(t, VersionTLS13, VersionTLS12); err == nil {
2002+
t.Errorf("downgrade from TLS 1.3 to TLS 1.2 was not detected")
2003+
}
2004+
if testing.Short() {
2005+
t.Skip("skipping the rest of the checks in short mode")
2006+
}
2007+
if err := testDowngradeCanary(t, VersionTLS13, VersionTLS11); err == nil {
2008+
t.Errorf("downgrade from TLS 1.3 to TLS 1.1 was not detected")
2009+
}
2010+
if err := testDowngradeCanary(t, VersionTLS13, VersionTLS10); err == nil {
2011+
t.Errorf("downgrade from TLS 1.3 to TLS 1.0 was not detected")
2012+
}
2013+
if err := testDowngradeCanary(t, VersionTLS12, VersionTLS11); err == nil {
2014+
t.Errorf("downgrade from TLS 1.2 to TLS 1.1 was not detected")
2015+
}
2016+
if err := testDowngradeCanary(t, VersionTLS12, VersionTLS10); err == nil {
2017+
t.Errorf("downgrade from TLS 1.2 to TLS 1.0 was not detected")
2018+
}
2019+
if err := testDowngradeCanary(t, VersionTLS13, VersionTLS13); err != nil {
2020+
t.Errorf("server unexpectedly sent downgrade canary for TLS 1.3")
2021+
}
2022+
if err := testDowngradeCanary(t, VersionTLS12, VersionTLS12); err != nil {
2023+
t.Errorf("client didn't ignore expected TLS 1.2 canary")
2024+
}
2025+
if err := testDowngradeCanary(t, VersionTLS11, VersionTLS11); err != nil {
2026+
t.Errorf("client unexpectedly reacted to a canary in TLS 1.1")
2027+
}
2028+
if err := testDowngradeCanary(t, VersionTLS10, VersionTLS10); err != nil {
2029+
t.Errorf("client unexpectedly reacted to a canary in TLS 1.0")
2030+
}
2031+
}

Diff for: src/crypto/tls/handshake_server.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ func (hs *serverHandshakeState) processClientHello() error {
193193
serverRandom := hs.hello.random
194194
// Downgrade protection canaries. See RFC 8446, Section 4.1.3.
195195
maxVers := c.config.maxSupportedVersion()
196-
if maxVers >= VersionTLS12 && c.vers < maxVers {
196+
if maxVers >= VersionTLS12 && c.vers < maxVers || testingOnlyForceDowngradeCanary {
197197
if c.vers == VersionTLS12 {
198198
copy(serverRandom[24:], downgradeCanaryTLS12)
199199
} else {

0 commit comments

Comments
 (0)