Skip to content

net/http/httptest: StartTLS() does not use GetCertificate if provided #73512

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

Closed
jsnctl opened this issue Apr 27, 2025 · 3 comments
Closed

net/http/httptest: StartTLS() does not use GetCertificate if provided #73512

jsnctl opened this issue Apr 27, 2025 · 3 comments

Comments

@jsnctl
Copy link

jsnctl commented Apr 27, 2025

Go version

go version go1.23.0 linux/amd64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/jsnctl/.cache/go-build'
GOENV='/home/jsnctl/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/jsnctl/.gvm/pkgsets/go1.23/global/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/jsnctl/.gvm/pkgsets/go1.23/global'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/jsnctl/.gvm/gos/go1.23'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/jsnctl/.gvm/gos/go1.23/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.23.0'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/jsnctl/.config/go/telemetry'
GCCGO='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-build1880694650=/tmp/go-build -gno-record-gcc-switches'

What did you do?

When using httptest.NewUnstartedServer, I'd expect tls.Config{GetCertificate: } to inject a cert if provided when invoking StartTLS()

What did you see happen?

Instead, StartTLS() injects a default TLS certificate if the config is empty of Certificate instances. You can see this directly here in the function itself

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

This is recreatable on Go playground 1.24.0

package main

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"net/http/httptest"
)

func main() {
	dummy := &tls.Certificate{}
	srv := httptest.NewUnstartedServer(nil)
	srv.TLS = &tls.Config{
		GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
			return dummy, nil
		},
	}
	srv.StartTLS()

	if &srv.TLS.Certificates[0] != dummy {
		fmt.Println("not equal")
		c, _ := x509.ParseCertificate(srv.TLS.Certificates[0].Certificate[0])
		fmt.Printf("%s, %s", c.Issuer, c.DNSNames)
	}
}

Output

not equal
O=Acme Co, [example.com *.example.com]

https://go.dev/play/p/Zq1vaLxW6QH

What did you expect to see?

When providing a GetCertificate value, I'd expect ServeTLS to use the function provided when called. I think this should be possible by checking whether tls.Config has a value for GetCertificate (and injecting the default if not as well as the Certificates slice being empty)

@jsnctl
Copy link
Author

jsnctl commented Apr 27, 2025

I'm happy to provide the patch here if this is agreed to not be expected behaviour. Thanks!

@rittneje
Copy link
Contributor

Is this a duplicate of #63812?

@jsnctl
Copy link
Author

jsnctl commented Apr 27, 2025

Thanks, yeah looks it. We can close here

@jsnctl jsnctl closed this as not planned Won't fix, can't repro, duplicate, stale Apr 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants