Skip to content

crypto/tls: does not send an unknown_ca alert to server if server's certificate verification fails #76019

@meilin-shi

Description

@meilin-shi

Go version

go1.24.3

Output of go env in your module/workspace:

AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE='on'
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/test/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/test/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1419648978=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/dev/null'
GOMODCACHE='/home/test/go/pkg/mod'
GONOPROXY='gitlab.xxx.net'
GONOSUMDB='gitlab.xxx.net'
GOOS='linux'
GOPATH='/home/test/go'
GOPRIVATE='gitlab.xxx.net'
GOPROXY='https://mirrors.xxx.net/repository/goproxy,direct'
GOROOT='/usr/local/go'
GOSUMDB='off'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/test/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.3'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

Do a https request, verify the server's certificate and capture the packets with Wireshark.
The code looks like:


import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
)

func main() {
	// 硬编码证书路径和URL(在实际使用中可以改为参数)
	caCertPath := "/etc/ssl/certs/ssl-cert-snakeoil.pem"
	url := "https://example.com"

	// 创建只使用指定CA证书的TLS配置
	tlsConfig, err := createTLSConfigWithOnlyCert(caCertPath)
	if err != nil {
		log.Fatalf("创建TLS配置失败: %v", err)
	}

	// 创建HTTP客户端
	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: tlsConfig,
		},
	}

	// 发送GET请求
	resp, err := client.Get(url)
	if err != nil {
		log.Fatalf("请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 读取并输出响应
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatalf("读取响应失败: %v", err)
	}

	fmt.Printf("状态码: %d\n", resp.StatusCode)
	fmt.Printf("响应体:\n%s\n", body)
}

func createTLSConfigWithOnlyCert(certFile string) (*tls.Config, error) {
	caCert, err := os.ReadFile(certFile)
	if err != nil {
		return nil, fmt.Errorf("读取CA证书失败: %w", err)
	}

	certPool := x509.NewCertPool()
	if !certPool.AppendCertsFromPEM(caCert) {
		return nil, fmt.Errorf("解析CA证书失败")
	}

	return &tls.Config{
		RootCAs:    certPool,
		ServerName: "example.com",
	}, nil
}

What did you see happen?

When using curl to verify the server's certificate, if the verification fails, using Wireshark to capture packets will show an error message of "Unknown CA". However, when using a program written in Golang to verify the server's certificate and then using Wireshark to capture packets, this error does not appear.

What did you expect to see?

Wireshark should capture a Unknown CA alert

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugReportIssues describing a possible bug in the Go implementation.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

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions