crypto/tls: only set LocalCertificate when a certificate is presented

ConnectionState.LocalCertificate is documented to be populated only for
connections which are not resumed. However, the TLS 1.0-1.2 server
handshake set it in processClientHello, which runs before
checkForResumption, and nothing cleared it on the abbreviated handshake
path. Resumed pre-1.3 server connections therefore reported a
certificate chain that was never presented to the peer (also visible to
VerifyConnection and WrapSession during the handshake).

Set the field in doFullHandshake, where the Certificate message is
actually written, so it is populated if and only if a chain was
presented. TLS 1.3 is unaffected because pickCertificate already returns
early for PSK resumption.

Also pin MaxVersion in TestLocalCertificate and
TestLocalCertificateResumption: they previously set only MinVersion, so
every pre-1.3 subtest silently negotiated TLS 1.3 and the broken path
had no coverage. With MaxVersion pinned, the resumption test fails
without this fix at TLS 1.0-1.2.

Verified: strengthened resumption test fails on unpatched master at TLS
1.0/1.1/1.2 and passes with the fix; full `go test crypto/tls` passes;
standalone repro from the issue prints len(LocalCertificate)=0 for
resumed TLS 1.2 connections.

Fixes #79967

Change-Id: Ic5586b05da956c619526b8ef500fcaa4c019a2f3
GitHub-Last-Rev: c2ef0f1
GitHub-Pull-Request: #79968
Reviewed-on: https://go-review.googlesource.com/c/go/+/789862
Auto-Submit: Roland Shoemaker <roland@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
This commit is contained in:
yuhan6665
2026-09-10 23:08:30 -04:00
parent ed9b3f2b50
commit 629fee8742
+4 -4
View File
@@ -281,10 +281,6 @@ func (hs *serverHandshakeState) processClientHello() error {
return err
}
if hs.cert != nil {
hs.c.localCertificate = hs.cert.Certificate
}
if hs.clientHello.scts {
hs.hello.scts = hs.cert.SignedCertificateTimestamps
}
@@ -619,6 +615,10 @@ func (hs *serverHandshakeState) doFullHandshake() error {
certMsg := new(certificateMsg)
certMsg.certificates = hs.cert.Certificate
// Set localCertificate here, rather than at certificate selection time, so
// that it is only populated when a certificate is actually presented to the
// peer, and not on resumed connections.
c.localCertificate = hs.cert.Certificate
if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil {
return err
}