From: Roland Shoemaker Date: Mon, 29 Aug 2022 16:40:50 +0000 (-0700) Subject: crypto/tls: use certificate cache in client X-Git-Tag: go1.20rc1~397 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=72ce9ba9cb640f1a2184389d1dc146d731882328;p=gostls13.git crypto/tls: use certificate cache in client In verifyServerCertificate parse certificates using the global certificate cache. This should signficiantly reduce memory usage in TLS clients which make concurrent connections which reuse certificates (anywhere in the chain) since there will only ever be one copy of the certificate at once. Fixes #46035 Change-Id: Icf5153d0ea3c14a0bdc8b26c794f21153bf95f85 Reviewed-on: https://go-review.googlesource.com/c/go/+/426455 Reviewed-by: Heschi Kreinick Reviewed-by: Bryan Mills Run-TryBot: Roland Shoemaker TryBot-Result: Gopher Robot Reviewed-by: Filippo Valsorda --- diff --git a/src/crypto/tls/cache.go b/src/crypto/tls/cache.go index aa44173c80..2bdf2d9a01 100644 --- a/src/crypto/tls/cache.go +++ b/src/crypto/tls/cache.go @@ -39,6 +39,8 @@ type certCache struct { sync.Map } +var clientCertCache = new(certCache) + // activeCert is a handle to a certificate held in the cache. Once there are // no alive activeCerts for a given certificate, the certificate is removed // from the cache by a finalizer. diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go index 21f693995e..03c72633be 100644 --- a/src/crypto/tls/conn.go +++ b/src/crypto/tls/conn.go @@ -49,6 +49,9 @@ type Conn struct { ocspResponse []byte // stapled OCSP response scts [][]byte // signed certificate timestamps from server peerCertificates []*x509.Certificate + // activeCertHandles contains the cache handles to certificates in + // peerCertificates that are used to track active references. + activeCertHandles []*activeCert // verifiedChains contains the certificate chains that we built, as // opposed to the ones presented by the server. verifiedChains [][]*x509.Certificate diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go index 721143cb75..2e3b693199 100644 --- a/src/crypto/tls/handshake_client.go +++ b/src/crypto/tls/handshake_client.go @@ -849,14 +849,16 @@ func (hs *clientHandshakeState) sendFinished(out []byte) error { // verifyServerCertificate parses and verifies the provided chain, setting // c.verifiedChains and c.peerCertificates or sending the appropriate alert. func (c *Conn) verifyServerCertificate(certificates [][]byte) error { + activeHandles := make([]*activeCert, len(certificates)) certs := make([]*x509.Certificate, len(certificates)) for i, asn1Data := range certificates { - cert, err := x509.ParseCertificate(asn1Data) + cert, err := clientCertCache.newCert(asn1Data) if err != nil { c.sendAlert(alertBadCertificate) return errors.New("tls: failed to parse certificate from server: " + err.Error()) } - certs[i] = cert + activeHandles[i] = cert + certs[i] = cert.cert } if !c.config.InsecureSkipVerify { @@ -886,6 +888,7 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error { return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey) } + c.activeCertHandles = activeHandles c.peerCertificates = certs if c.config.VerifyPeerCertificate != nil {