错误信息
remote error: tls: unknown certificate authority
Go 服务器记录的日志为“http: TLS handshake error from <client>: remote error: tls: unknown certificate authority”。在我们的测试中,OpenSSL 3.5 客户端通过 TLS 1.3 拒绝同一张证书时,Go 1.27 服务器记录的却是“local error: tls: bad record MAC”;而 Go 客户端发送的是 bad_certificate(记录为“remote error: tls: bad certificate”)。
Go crypto/tls — TLS alert 48 (unknown_ca) received from the peer, e.g. an OpenSSL-based client rejecting a Go server's certificate
含义
对端发送了 TLS 告警 48(unknown_ca):它无法为收到的证书构建出一条通向自己所信任 CA 的证书链。出现在 Go 服务器的日志中时,它表示某个客户端(基于 OpenSSL 的客户端:curl、Python、Ruby、PHP、作为代理的 nginx)在 TLS 1.2 握手期间拒绝了服务器的证书。出现在 Go 客户端中时,它表示服务器在双向 TLS 中拒绝了客户端证书。
原因
客户端不信任签发证书的 CA
常见客户端机器或容器中没有的私有 CA 或公司 CA。
Go 服务器只发送了叶子证书
常见ListenAndServeTLS 发送的正是文件中的那些证书;如果文件中只有叶子证书,客户端就无法追溯到根证书。
双向 TLS:服务器不信任客户端的 CA
偶见在客户端一侧,这个告警表示服务器的 ClientCAs 中不包含客户端证书的颁发者。
修复方法
- 1.
从客户端检查服务器提供的证书链
如果只发送了叶子证书,就修复文件;如果证书链终止于私有根证书,就在客户端上安装该根证书。
bash openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:|Verify return code' - 2.
在 Go 中提供完整证书链
把叶子证书及其中间证书放进传给 ListenAndServeTLS(或 tls.LoadX509KeyPair)的 PEM 文件中。
go // Leaf + intermediates in one file; Go sends every certificate in it srv := &http.Server{Addr: ":443"} log.Fatal(srv.ListenAndServeTLS("fullchain.pem", "server.key")) - 3.
在客户端上安装私有根证书
对于内部服务,把公司根证书分发到调用该服务器的系统和容器中。
bash # Private CA: install the root on the clients (Debian/Ubuntu example) sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt && sudo update-ca-certificates