]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/tls: allow 256KiB certificate messages
authorRoland Shoemaker <roland@golang.org>
Wed, 15 May 2024 17:51:44 +0000 (10:51 -0700)
committerGopher Robot <gobot@golang.org>
Thu, 23 May 2024 00:30:52 +0000 (00:30 +0000)
During handshake, lift the message length limit, but only for
certificate messages.

Fixes #50773

Change-Id: Ida9d83f4219c4386ca71ed3ef72b22259665a187
Reviewed-on: https://go-review.googlesource.com/c/go/+/585402
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
src/crypto/tls/common.go
src/crypto/tls/conn.go
src/crypto/tls/tls_test.go

index 945b3ddb68642fb0a5f9d8f58c3f0ff2c0058f65..601d5b8e4c4a45a0b05c3bbbd9e51747eb5136b3 100644 (file)
@@ -59,12 +59,13 @@ func VersionName(version uint16) string {
 }
 
 const (
-       maxPlaintext       = 16384        // maximum plaintext payload length
-       maxCiphertext      = 16384 + 2048 // maximum ciphertext payload length
-       maxCiphertextTLS13 = 16384 + 256  // maximum ciphertext length in TLS 1.3
-       recordHeaderLen    = 5            // record header length
-       maxHandshake       = 65536        // maximum handshake we support (protocol max is 16 MB)
-       maxUselessRecords  = 16           // maximum number of consecutive non-advancing records
+       maxPlaintext               = 16384        // maximum plaintext payload length
+       maxCiphertext              = 16384 + 2048 // maximum ciphertext payload length
+       maxCiphertextTLS13         = 16384 + 256  // maximum ciphertext length in TLS 1.3
+       recordHeaderLen            = 5            // record header length
+       maxHandshake               = 65536        // maximum handshake we support (protocol max is 16 MB)
+       maxHandshakeCertificateMsg = 262144       // maximum certificate message size (256 KiB)
+       maxUselessRecords          = 16           // maximum number of consecutive non-advancing records
 )
 
 // TLS record types.
index 3ffd26d8ef616a8d4070f5cb5322979adf2ed022..850b56f793023a8139955531eb87fb0447659ee7 100644 (file)
@@ -1089,10 +1089,22 @@ func (c *Conn) readHandshake(transcript transcriptHash) (any, error) {
                return nil, err
        }
        data := c.hand.Bytes()
+
+       maxHandshakeSize := maxHandshake
+       // hasVers indicates we're past the first message, forcing someone trying to
+       // make us just allocate a large buffer to at least do the initial part of
+       // the handshake first.
+       if c.haveVers && data[0] == typeCertificate {
+               // Since certificate messages are likely to be the only messages that
+               // can be larger than maxHandshake, we use a special limit for just
+               // those messages.
+               maxHandshakeSize = maxHandshakeCertificateMsg
+       }
+
        n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
-       if n > maxHandshake {
+       if n > maxHandshakeSize {
                c.sendAlertLocked(alertInternalError)
-               return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake))
+               return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshakeSize))
        }
        if err := c.readHandshakeBytes(4 + n); err != nil {
                return nil, err
index 158b45997688d315ce2e36780e0bbd3dc32fa926..320ef7031e2af8696d006ded79a0bf1ac96e2567 100644 (file)
@@ -13,6 +13,7 @@ import (
        "crypto/rand"
        "crypto/x509"
        "crypto/x509/pkix"
+       "encoding/asn1"
        "encoding/json"
        "encoding/pem"
        "errors"
@@ -2002,3 +2003,58 @@ func TestX509KeyPairPopulateCertificate(t *testing.T) {
                }
        })
 }
+
+func TestEarlyLargeCertMsg(t *testing.T) {
+       client, server := localPipe(t)
+
+       go func() {
+               if _, err := client.Write([]byte{byte(recordTypeHandshake), 3, 4, 0, 4, typeCertificate, 1, 255, 255}); err != nil {
+                       t.Log(err)
+               }
+       }()
+
+       expectedErr := "tls: handshake message of length 131071 bytes exceeds maximum of 65536 bytes"
+       servConn := Server(server, testConfig)
+       err := servConn.Handshake()
+       if err == nil {
+               t.Fatal("unexpected success")
+       }
+       if err.Error() != expectedErr {
+               t.Fatalf("unexpected error: got %q, want %q", err, expectedErr)
+       }
+}
+
+func TestLargeCertMsg(t *testing.T) {
+       k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+       if err != nil {
+               t.Fatal(err)
+       }
+       tmpl := &x509.Certificate{
+               SerialNumber: big.NewInt(1),
+               Subject:      pkix.Name{CommonName: "test"},
+               ExtraExtensions: []pkix.Extension{
+                       {
+                               Id: asn1.ObjectIdentifier{1, 2, 3},
+                               // Ballast to inflate the certificate beyond the
+                               // regular handshake record size.
+                               Value: make([]byte, 65536),
+                       },
+               },
+       }
+       cert, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       clientConfig, serverConfig := testConfig.Clone(), testConfig.Clone()
+       clientConfig.InsecureSkipVerify = true
+       serverConfig.Certificates = []Certificate{
+               {
+                       Certificate: [][]byte{cert},
+                       PrivateKey:  k,
+               },
+       }
+       if _, _, err := testHandshake(t, clientConfig, serverConfig); err != nil {
+               t.Fatalf("unexpected failure :%s", err)
+       }
+}