aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland Shoemaker <roland@golang.org>2023-08-08 18:25:59 -0700
committerGopher Robot <gobot@golang.org>2023-08-16 17:14:51 +0000
commitcaca5f126b95276259c5c20ac1a01091ae9bf931 (patch)
tree2f7074a710e4781ccf47af6d1cfba596dc9406b6
parentc08a5fa413a34111c9a37fd9e545de27ab0978b1 (diff)
downloadgo-caca5f126b95276259c5c20ac1a01091ae9bf931.tar.gz
go-caca5f126b95276259c5c20ac1a01091ae9bf931.zip
[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>
-rw-r--r--src/crypto/tls/conn.go5
-rw-r--r--src/crypto/tls/handshake_client.go24
-rw-r--r--src/crypto/tls/handshake_client_test.go47
-rw-r--r--src/crypto/tls/handshake_server.go9
4 files changed, 66 insertions, 19 deletions
diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
index 73f0c1771e..31e9867a97 100644
--- a/src/crypto/tls/conn.go
+++ b/src/crypto/tls/conn.go
@@ -1413,6 +1413,11 @@ func (c *Conn) closeNotify() error {
//
// For control over canceling or setting a timeout on a handshake, use
// 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 {
return c.HandshakeContext(context.Background())
}
diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
index 1c3d16714b..5a524556a2 100644
--- a/src/crypto/tls/handshake_client.go
+++ b/src/crypto/tls/handshake_client.go
@@ -16,8 +16,10 @@ import (
"errors"
"fmt"
"hash"
+ "internal/godebug"
"io"
"net"
+ "strconv"
"strings"
"sync/atomic"
"time"
@@ -857,9 +859,18 @@ func (hs *clientHandshakeState) sendFinished(out []byte) error {
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.
-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
// c.verifiedChains and c.peerCertificates or sending the appropriate alert.
@@ -871,9 +882,12 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
c.sendAlert(alertBadCertificate)
return errors.New("tls: failed to parse certificate from server: " + err.Error())
}
- if cert.PublicKeyAlgorithm == x509.RSA && cert.PublicKey.(*rsa.PublicKey).N.BitLen() > maxRSAKeySize {
- c.sendAlert(alertBadCertificate)
- return fmt.Errorf("tls: server sent certificate containing RSA key larger than %d bits", maxRSAKeySize)
+ if cert.PublicKeyAlgorithm == x509.RSA {
+ n := cert.PublicKey.(*rsa.PublicKey).N.BitLen()
+ 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
}
diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
index 6b5b61aed5..d0afc72e10 100644
--- a/src/crypto/tls/handshake_client_test.go
+++ b/src/crypto/tls/handshake_client_test.go
@@ -2678,19 +2678,44 @@ u58=
-----END CERTIFICATE-----`
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"
- err := c.verifyServerCertificate([][]byte{testCert.Bytes})
- if err == nil || err.Error() != expectedErr {
- t.Errorf("Conn.verifyServerCertificate unexpected error: want %q, got %q", expectedErr, err)
- }
+ c := &Conn{conn: &discardConn{}, config: testConfig.Clone()}
+
+ err := c.verifyServerCertificate([][]byte{testCert.Bytes})
+ if tc.expectedServerErr == "" && err != nil {
+ t.Errorf("Conn.verifyServerCertificate unexpected error: %s", err)
+ } else if tc.expectedServerErr != "" && (err == nil || err.Error() != tc.expectedServerErr) {
+ t.Errorf("Conn.verifyServerCertificate unexpected error: want %q, got %q", tc.expectedServerErr, err)
+ }
- expectedErr = "tls: client sent certificate containing RSA key larger than 8192 bits"
- err = c.processCertsFromClient(Certificate{Certificate: [][]byte{testCert.Bytes}})
- if err == nil || err.Error() != expectedErr {
- t.Errorf("Conn.processCertsFromClient unexpected error: want %q, got %q", expectedErr, 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)
+ }
+ })
}
}
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
index f0524af962..65e3635c75 100644
--- a/src/crypto/tls/handshake_server.go
+++ b/src/crypto/tls/handshake_server.go
@@ -819,9 +819,12 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
c.sendAlert(alertBadCertificate)
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 {
- c.sendAlert(alertBadCertificate)
- return fmt.Errorf("tls: client sent certificate containing RSA key larger than %d bits", maxRSAKeySize)
+ if certs[i].PublicKeyAlgorithm == x509.RSA {
+ n := certs[i].PublicKey.(*rsa.PublicKey).N.BitLen()
+ if max, ok := checkKeySize(n); !ok {
+ c.sendAlert(alertBadCertificate)
+ return fmt.Errorf("tls: client sent certificate containing RSA key larger than %d bits", max)
+ }
}
}