Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/http/httptest: Server does not check GetCertificate #63812

Open
mitar opened this issue Oct 29, 2023 · 4 comments
Open

net/http/httptest: Server does not check GetCertificate #63812

mitar opened this issue Oct 29, 2023 · 4 comments
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.

Comments

@mitar
Copy link
Contributor

mitar commented Oct 29, 2023

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

go version go1.21.3 linux/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
GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/mitar/.cache/go-build'
GOENV='/home/mitar/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/mitar/.go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/mitar/.go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.21.3'
GCCGO='/usr/bin/gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/dev/null'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build488527063=/tmp/go-build -gno-record-gcc-switches'

What did you do?

I am trying to test a http.Server instance with httptest's Server:

	ts := httptest.NewUnstartedServer(nil)
	ts.EnableHTTP2 = true
	ts.Config = server
	ts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})
	ts.TLS = server.TLSConfig.Clone()
	ts.StartTLS()

I want to check that server's TLS configuration works. Server's TLS configuration uses GetCertificate

What did you expect to see?

That once I call StartTLS is called, GetCertificate is called to obtain the certificate to configure the testing server and testing client.

What did you see instead?

StartTLS ignores and never calls GetCertificate but instead configures testing server and testing client to use testing certificate.

Discussion

I can call something like:

	cert, _ := ts.TLS.GetCertificate(nil) // or some other relevant ClientHelloInfo for 127.0.0.1
	ts.TLS.Certificates = []tls.Certificate{*cert}

before calling StartTLS. But ideally that should be called by StartTLS. This is documented in tls.Config:

	// Server configurations must set one of Certificates, GetCertificate or
	// GetConfigForClient.

Currently only Certificates is checked, but GetCertificate or GetConfigForClient are ignored.

My motivation is to do a test with golang.org/x/crypto/acme/autocert serving as manager against Pebble to test that http.Server's configuration and everything works correctly.

@seankhliao seankhliao added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Oct 29, 2023
@rittneje
Copy link

rittneje commented Oct 30, 2023

The source of the issue is here:

if len(s.TLS.Certificates) == 0 {
s.TLS.Certificates = []tls.Certificate{cert}
}

I guess it could also check if s.TLS.GetCertificate == nil. But then I don't know what the Certificate method is supposed to return in that case.

I'll also note that this behavior of httptest.Server seems to be completely undocumented.

@mitar
Copy link
Contributor Author

mitar commented Oct 30, 2023

I thnk GetCertificate should be called with 127.0.0.1 (or more precisely s.Listener.Addr()) as a parameter. That is what it gets set in s.URL. That can then be stored in s.certificate.

@rittneje
Copy link

GetCertificate takes an entire ClientHelloInfo, not just a hostname.

@mitar
Copy link
Contributor Author

mitar commented Oct 30, 2023

@rittneje, yes, I know. What I mean that it should be a dummy ClientHelloInfo with s.Listener.Addr().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

3 participants