From 62a994837a57a7d0c58bb364b580a389488446c9 Mon Sep 17 00:00:00 2001 From: Anit Gandhi Date: Mon, 21 Nov 2022 17:17:44 +0000 Subject: [PATCH] crypto/tls: improve client auth failure alerts This change makes it easier for clients to debug mutual TLS connection failures. Currently, there are a few situations where invalid client auth leads to a generic "bad certificate" alert. 3 specific situations have a more appropriate TLS alert code, based on the alert descriptions in the appendix of both RFC5246 and RFC8446. 1. The server is configured to require client auth, but no client cert was provided; the appropriate alert is "certificate required". This applies only to TLS 1.3, which first defined the certificate_required alert code. 2. The client provided a cert that was signed by an authority that is not in the server's trusted set of CAs; the appropriate alert is "unknown certificate authority". 3. The client provided an expired (or not yet valid) cert; the appropriate alert is "expired certificate". Otherwise, we still fall back to "bad certificate". Fixes #52113 Change-Id: I7d5860fe911cad8a1615f16bfe488a37e936dc36 GitHub-Last-Rev: 34eeab587b38549b2ba4a778f7f9894e9b715b43 GitHub-Pull-Request: golang/go#53251 Reviewed-on: https://go-review.googlesource.com/c/go/+/410496 Reviewed-by: Michael Knyszek Reviewed-by: Damien Neil Run-TryBot: Roland Shoemaker TryBot-Result: Gopher Robot Auto-Submit: Roland Shoemaker Reviewed-by: Roland Shoemaker --- src/crypto/tls/handshake_server.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go index 682cfc20619f6..f28b0e2532fb4 100644 --- a/src/crypto/tls/handshake_server.go +++ b/src/crypto/tls/handshake_server.go @@ -812,7 +812,11 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error { } if len(certs) == 0 && requiresClientCert(c.config.ClientAuth) { - c.sendAlert(alertBadCertificate) + if c.vers == VersionTLS13 { + c.sendAlert(alertCertificateRequired) + } else { + c.sendAlert(alertBadCertificate) + } return errors.New("tls: client didn't provide a certificate") } @@ -830,7 +834,14 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error { chains, err := certs[0].Verify(opts) if err != nil { - c.sendAlert(alertBadCertificate) + var errCertificateInvalid x509.CertificateInvalidError + if errors.As(err, &x509.UnknownAuthorityError{}) { + c.sendAlert(alertUnknownCA) + } else if errors.As(err, &errCertificateInvalid) && errCertificateInvalid.Reason == x509.Expired { + c.sendAlert(alertCertificateExpired) + } else { + c.sendAlert(alertBadCertificate) + } return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err} }