[release-branch.go1.19] crypto/tls: add GODEBUG to control max RSA key size

Add a new GODEBUG setting, tlsmaxrsasize, which allows controlling the
maximum RSA key size we will accept during TLS handshakes.

Fixes #61968

Change-Id: I52f060be132014d219f4cd438f59990011a35c96
Reviewed-on: https://go-review.googlesource.com/c/go/+/517495
Auto-Submit: Roland Shoemaker <roland@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
Run-TryBot: Roland Shoemaker <roland@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/518536
Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
This commit is contained in:
Roland Shoemaker 2023-08-08 18:25:59 -07:00 committed by Gopher Robot
parent c08a5fa413
commit caca5f126b
4 changed files with 66 additions and 19 deletions

View File

@ -1413,6 +1413,11 @@ func (c *Conn) closeNotify() error {
// //
// For control over canceling or setting a timeout on a handshake, use // For control over canceling or setting a timeout on a handshake, use
// HandshakeContext or the Dialer's DialContext method instead. // HandshakeContext or the Dialer's DialContext method instead.
//
// In order to avoid denial of service attacks, the maximum RSA key size allowed
// in certificates sent by either the TLS server or client is limited to 8192
// bits. This limit can be overridden by setting tlsmaxrsasize in the GODEBUG
// environment variable (e.g. GODEBUG=tlsmaxrsasize=4096).
func (c *Conn) Handshake() error { func (c *Conn) Handshake() error {
return c.HandshakeContext(context.Background()) return c.HandshakeContext(context.Background())
} }

View File

@ -16,8 +16,10 @@ import (
"errors" "errors"
"fmt" "fmt"
"hash" "hash"
"internal/godebug"
"io" "io"
"net" "net"
"strconv"
"strings" "strings"
"sync/atomic" "sync/atomic"
"time" "time"
@ -857,9 +859,18 @@ func (hs *clientHandshakeState) sendFinished(out []byte) error {
return nil return nil
} }
// maxRSAKeySize is the maximum RSA key size in bits that we are willing // defaultMaxRSAKeySize is the maximum RSA key size in bits that we are willing
// to verify the signatures of during a TLS handshake. // to verify the signatures of during a TLS handshake.
const maxRSAKeySize = 8192 const defaultMaxRSAKeySize = 8192
func checkKeySize(n int) (max int, ok bool) {
if v := godebug.Get("tlsmaxrsasize"); v != "" {
if max, err := strconv.Atoi(v); err == nil {
return max, n <= max
}
}
return defaultMaxRSAKeySize, n <= defaultMaxRSAKeySize
}
// verifyServerCertificate parses and verifies the provided chain, setting // verifyServerCertificate parses and verifies the provided chain, setting
// c.verifiedChains and c.peerCertificates or sending the appropriate alert. // c.verifiedChains and c.peerCertificates or sending the appropriate alert.
@ -871,9 +882,12 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
c.sendAlert(alertBadCertificate) c.sendAlert(alertBadCertificate)
return errors.New("tls: failed to parse certificate from server: " + err.Error()) return errors.New("tls: failed to parse certificate from server: " + err.Error())
} }
if cert.PublicKeyAlgorithm == x509.RSA && cert.PublicKey.(*rsa.PublicKey).N.BitLen() > maxRSAKeySize { if cert.PublicKeyAlgorithm == x509.RSA {
c.sendAlert(alertBadCertificate) n := cert.PublicKey.(*rsa.PublicKey).N.BitLen()
return fmt.Errorf("tls: server sent certificate containing RSA key larger than %d bits", maxRSAKeySize) if max, ok := checkKeySize(n); !ok {
c.sendAlert(alertBadCertificate)
return fmt.Errorf("tls: server sent certificate containing RSA key larger than %d bits", max)
}
} }
certs[i] = cert certs[i] = cert
} }

View File

@ -2678,19 +2678,44 @@ u58=
-----END CERTIFICATE-----` -----END CERTIFICATE-----`
func TestHandshakeRSATooBig(t *testing.T) { func TestHandshakeRSATooBig(t *testing.T) {
testCert, _ := pem.Decode([]byte(largeRSAKeyCertPEM)) for _, tc := range []struct {
name string
godebug string
expectedServerErr string
expectedClientErr string
}{
{
name: "key too large",
expectedServerErr: "tls: server sent certificate containing RSA key larger than 8192 bits",
expectedClientErr: "tls: client sent certificate containing RSA key larger than 8192 bits",
},
{
name: "acceptable key (GODEBUG=tlsmaxrsasize=8193)",
godebug: "tlsmaxrsasize=8193",
},
} {
t.Run(tc.name, func(t *testing.T) {
if tc.godebug != "" {
t.Setenv("GODEBUG", tc.godebug)
}
c := &Conn{conn: &discardConn{}, config: testConfig.Clone()} testCert, _ := pem.Decode([]byte(largeRSAKeyCertPEM))
expectedErr := "tls: server sent certificate containing RSA key larger than 8192 bits" c := &Conn{conn: &discardConn{}, config: testConfig.Clone()}
err := c.verifyServerCertificate([][]byte{testCert.Bytes})
if err == nil || err.Error() != expectedErr {
t.Errorf("Conn.verifyServerCertificate unexpected error: want %q, got %q", expectedErr, err)
}
expectedErr = "tls: client sent certificate containing RSA key larger than 8192 bits" err := c.verifyServerCertificate([][]byte{testCert.Bytes})
err = c.processCertsFromClient(Certificate{Certificate: [][]byte{testCert.Bytes}}) if tc.expectedServerErr == "" && err != nil {
if err == nil || err.Error() != expectedErr { t.Errorf("Conn.verifyServerCertificate unexpected error: %s", err)
t.Errorf("Conn.processCertsFromClient unexpected error: want %q, got %q", expectedErr, err) } else if tc.expectedServerErr != "" && (err == nil || err.Error() != tc.expectedServerErr) {
t.Errorf("Conn.verifyServerCertificate unexpected error: want %q, got %q", tc.expectedServerErr, err)
}
err = c.processCertsFromClient(Certificate{Certificate: [][]byte{testCert.Bytes}})
if tc.expectedClientErr == "" && err != nil {
t.Errorf("Conn.processCertsFromClient unexpected error: %s", err)
} else if tc.expectedClientErr != "" && (err == nil || err.Error() != tc.expectedClientErr) {
t.Errorf("Conn.processCertsFromClient unexpected error: want %q, got %q", tc.expectedClientErr, err)
}
})
} }
} }

View File

@ -819,9 +819,12 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
c.sendAlert(alertBadCertificate) c.sendAlert(alertBadCertificate)
return errors.New("tls: failed to parse client certificate: " + err.Error()) return errors.New("tls: failed to parse client certificate: " + err.Error())
} }
if certs[i].PublicKeyAlgorithm == x509.RSA && certs[i].PublicKey.(*rsa.PublicKey).N.BitLen() > maxRSAKeySize { if certs[i].PublicKeyAlgorithm == x509.RSA {
c.sendAlert(alertBadCertificate) n := certs[i].PublicKey.(*rsa.PublicKey).N.BitLen()
return fmt.Errorf("tls: client sent certificate containing RSA key larger than %d bits", maxRSAKeySize) if max, ok := checkKeySize(n); !ok {
c.sendAlert(alertBadCertificate)
return fmt.Errorf("tls: client sent certificate containing RSA key larger than %d bits", max)
}
} }
} }