Skip to content

crypto/tls: don't include supported_versions extension if MaxVersion < 1.3  #53384

@jameshartig

Description

@jameshartig

What version of Go are you using (go version)?

$ go version
go version go1.18.3 windows/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
set GO111MODULE=
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\james\AppData\Local\go-build
set GOENV=C:\Users\james\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\james\go\pkg\mod
set GONOPROXY=gerrit.levenlabs.com,gitlab.com/levenlabs
set GONOSUMDB=gerrit.levenlabs.com,gitlab.com/levenlabs
set GOOS=windows
set GOPATH=C:\Users\james\go;
set GOPRIVATE=gerrit.levenlabs.com,gitlab.com/levenlabs
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=C:\Program Files\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.18.3
set GCCGO=gccgo
set GOAMD64=v1
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=C:\Users\james\Dropbox\aftermath\backend\vigilante\go.mod
set GOWORK=
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0 -fdebug-prefix-map=C:\Users\james\AppData\Local\Temp\go-build1041663077=/tmp/go-build -gno-record-gcc-switches

What did you do?

If you make a TLS 1.2 ClientHello to some servers and include a supported_versions extension the server will report back a handshake failure. I was comparing why Go failed but openssl s_client ... -tls1_2 -cipher 'ECDHE-RSA-AES128-GCM-SHA256' worked and I figured out that the difference is that Go sends the supported_versions and openssl doesn't.

image

It seems that supported_versions is a TLS 1.3 extension so we probably shouldn't be including it when the MaxVersion is less than 1.3.

Here's a way to reproduce it against google.com:

package main

import (
	"crypto/tls"
	"net"
	"net/http"
	"time"
)

func main() {
	hc := &http.Client{
		Transport: &http.Transport{
			DialContext: (&net.Dialer{
				Timeout:   10 * time.Second,
				KeepAlive: 10 * time.Second,
			}).DialContext,
			MaxIdleConns:          1,
			IdleConnTimeout:       30 * time.Second,
			TLSHandshakeTimeout:   30 * time.Second,
			ExpectContinueTimeout: 1 * time.Second,
			TLSClientConfig: &tls.Config{
				MinVersion: tls.VersionTLS12,
				MaxVersion: tls.VersionTLS12,
				CipherSuites: []uint16{
					tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
					tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
				},
			},
		},
	}
	resp, err := hc.Get("https://google.com/")
	if err != nil {
		panic(err)
	}
	resp.Body.Close()
}

I realize the above is a contrived example but the fact that Google has this problem (and all GCP load balancers) seems to justify that it's not a random server that's misbehaving.

What did you expect to see?

I expected the program not to panic.

What did you see instead?

Instead I get panic: Get "https://google.com/": remote error: tls: handshake failure.

If I change marshal in handshake_messages.go to:

if len(m.supportedVersions) > 0 && m.supportedVersions[0] >= VersionTLS13 {

Then the above program no longer errors.

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions