sync: merge changes from go 1.23.4

This commit is contained in:
Mingye Chen 2025-01-07 15:55:09 -07:00
commit cefe226467
98 changed files with 8089 additions and 4530 deletions

View file

@ -8,16 +8,22 @@ import (
"bytes"
"context"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/json"
"errors"
"fmt"
"io"
"math"
"math/big"
"net"
"os"
"reflect"
"sort"
"slices"
"strings"
"testing"
"time"
@ -212,7 +218,7 @@ func TestDialTimeout(t *testing.T) {
t.Logf("Listener accepted a connection from %s", lconn.RemoteAddr())
lconn.Close()
}
// Close any spurious extra connecitions from the listener. (This is
// Close any spurious extra connections from the listener. (This is
// possible if there are, for example, stray Dial calls from other tests.)
for extraConn := range acceptc {
t.Logf("spurious extra connection from %s", extraConn.RemoteAddr())
@ -765,7 +771,7 @@ func TestWarningAlertFlood(t *testing.T) {
}
func TestCloneFuncFields(t *testing.T) {
const expectedCount = 8
const expectedCount = 9
called := 0
c1 := Config{
@ -801,6 +807,10 @@ func TestCloneFuncFields(t *testing.T) {
called |= 1 << 7
return nil, nil
},
EncryptedClientHelloRejectionVerify: func(ConnectionState) error {
called |= 1 << 8
return nil
},
}
c2 := c1.Clone()
@ -813,6 +823,7 @@ func TestCloneFuncFields(t *testing.T) {
c2.VerifyConnection(ConnectionState{})
c2.UnwrapSession(nil, ConnectionState{})
c2.WrapSession(ConnectionState{}, nil)
c2.EncryptedClientHelloRejectionVerify(ConnectionState{})
if called != (1<<expectedCount)-1 {
t.Fatalf("expected %d calls but saw calls %b", expectedCount, called)
@ -831,7 +842,7 @@ func TestCloneNonFuncFields(t *testing.T) {
switch fn := typ.Field(i).Name; fn {
case "Rand":
f.Set(reflect.ValueOf(io.Reader(os.Stdin)))
case "Time", "GetCertificate", "GetConfigForClient", "VerifyPeerCertificate", "VerifyConnection", "GetClientCertificate", "WrapSession", "UnwrapSession":
case "Time", "GetCertificate", "GetConfigForClient", "VerifyPeerCertificate", "VerifyConnection", "GetClientCertificate", "WrapSession", "UnwrapSession", "EncryptedClientHelloRejectionVerify":
// DeepEqual can't compare functions. If you add a
// function field to this list, you must also change
// TestCloneFuncFields to ensure that the func field is
@ -870,6 +881,8 @@ func TestCloneNonFuncFields(t *testing.T) {
f.Set(reflect.ValueOf(true))
case "Renegotiation":
f.Set(reflect.ValueOf(RenegotiateOnceAsClient))
case "EncryptedClientHelloConfigList":
f.Set(reflect.ValueOf([]byte{'x'}))
case "mutex", "autoSessionTicketKeys", "sessionTicketKeys":
continue // these are unexported fields that are handled separately
case "ApplicationSettings": // [UTLS] ALPS (Application Settings)
@ -1466,6 +1479,16 @@ func TestCipherSuites(t *testing.T) {
t.Errorf("%#04x: suite TLS 1.0-1.2, but SupportedVersions is %v", c.id, cc.SupportedVersions)
}
if cc.Insecure {
if slices.Contains(defaultCipherSuites(), c.id) {
t.Errorf("%#04x: insecure suite in default list", c.id)
}
} else {
if !slices.Contains(defaultCipherSuites(), c.id) {
t.Errorf("%#04x: secure suite not in default list", c.id)
}
}
if got := CipherSuiteName(c.id); got != cc.Name {
t.Errorf("%#04x: unexpected CipherSuiteName: got %q, expected %q", c.id, got, cc.Name)
}
@ -1499,9 +1522,6 @@ func TestCipherSuites(t *testing.T) {
if len(cipherSuitesPreferenceOrderNoAES) != len(cipherSuitesPreferenceOrder) {
t.Errorf("cipherSuitesPreferenceOrderNoAES is not the same size as cipherSuitesPreferenceOrder")
}
if len(defaultCipherSuites) >= len(defaultCipherSuitesWithRSAKex) {
t.Errorf("defaultCipherSuitesWithRSAKex should be longer than defaultCipherSuites")
}
// Check that disabled suites are marked insecure.
for _, badSuites := range []map[uint16]bool{disabledCipherSuites, rsaKexCiphers} {
@ -1542,61 +1562,71 @@ func TestCipherSuites(t *testing.T) {
}
// Check that the list is sorted according to the documented criteria.
isBetter := func(a, b int) bool {
aSuite, bSuite := cipherSuiteByID(prefOrder[a]), cipherSuiteByID(prefOrder[b])
aName, bName := CipherSuiteName(prefOrder[a]), CipherSuiteName(prefOrder[b])
isBetter := func(a, b uint16) int {
aSuite, bSuite := cipherSuiteByID(a), cipherSuiteByID(b)
aName, bName := CipherSuiteName(a), CipherSuiteName(b)
// * < RC4
if !strings.Contains(aName, "RC4") && strings.Contains(bName, "RC4") {
return true
return -1
} else if strings.Contains(aName, "RC4") && !strings.Contains(bName, "RC4") {
return false
return +1
}
// * < CBC_SHA256
if !strings.Contains(aName, "CBC_SHA256") && strings.Contains(bName, "CBC_SHA256") {
return true
return -1
} else if strings.Contains(aName, "CBC_SHA256") && !strings.Contains(bName, "CBC_SHA256") {
return false
return +1
}
// * < 3DES
if !strings.Contains(aName, "3DES") && strings.Contains(bName, "3DES") {
return true
return -1
} else if strings.Contains(aName, "3DES") && !strings.Contains(bName, "3DES") {
return false
return +1
}
// ECDHE < *
if aSuite.flags&suiteECDHE != 0 && bSuite.flags&suiteECDHE == 0 {
return true
return -1
} else if aSuite.flags&suiteECDHE == 0 && bSuite.flags&suiteECDHE != 0 {
return false
return +1
}
// AEAD < CBC
if aSuite.aead != nil && bSuite.aead == nil {
return true
return -1
} else if aSuite.aead == nil && bSuite.aead != nil {
return false
return +1
}
// AES < ChaCha20
if strings.Contains(aName, "AES") && strings.Contains(bName, "CHACHA20") {
return i == 0 // true for cipherSuitesPreferenceOrder
// negative for cipherSuitesPreferenceOrder
if i == 0 {
return -1
} else {
return +1
}
} else if strings.Contains(aName, "CHACHA20") && strings.Contains(bName, "AES") {
return i != 0 // true for cipherSuitesPreferenceOrderNoAES
// negative for cipherSuitesPreferenceOrderNoAES
if i != 0 {
return -1
} else {
return +1
}
}
// AES-128 < AES-256
if strings.Contains(aName, "AES_128") && strings.Contains(bName, "AES_256") {
return true
return -1
} else if strings.Contains(aName, "AES_256") && strings.Contains(bName, "AES_128") {
return false
return +1
}
// ECDSA < RSA
if aSuite.flags&suiteECSign != 0 && bSuite.flags&suiteECSign == 0 {
return true
return -1
} else if aSuite.flags&suiteECSign == 0 && bSuite.flags&suiteECSign != 0 {
return false
return +1
}
t.Fatalf("two ciphersuites are equal by all criteria: %v and %v", aName, bName)
panic("unreachable")
}
if !sort.SliceIsSorted(prefOrder, isBetter) {
if !slices.IsSortedFunc(prefOrder, isBetter) {
t.Error("preference order is not sorted according to the rules")
}
}
@ -1814,3 +1844,183 @@ func testVerifyCertificates(t *testing.T, version uint16) {
})
}
}
func TestHandshakeKyber(t *testing.T) {
if x25519Kyber768Draft00.String() != "X25519Kyber768Draft00" {
t.Fatalf("unexpected CurveID string: %v", x25519Kyber768Draft00.String())
}
var tests = []struct {
name string
clientConfig func(*Config)
serverConfig func(*Config)
preparation func(*testing.T)
expectClientSupport bool
expectKyber bool
expectHRR bool
}{
{
name: "Default",
expectClientSupport: true,
expectKyber: true,
expectHRR: false,
},
{
name: "ClientCurvePreferences",
clientConfig: func(config *Config) {
config.CurvePreferences = []CurveID{X25519}
},
expectClientSupport: false,
},
{
name: "ServerCurvePreferencesX25519",
serverConfig: func(config *Config) {
config.CurvePreferences = []CurveID{X25519}
},
expectClientSupport: true,
expectKyber: false,
expectHRR: false,
},
{
name: "ServerCurvePreferencesHRR",
serverConfig: func(config *Config) {
config.CurvePreferences = []CurveID{CurveP256}
},
expectClientSupport: true,
expectKyber: false,
expectHRR: true,
},
{
name: "ClientTLSv12",
clientConfig: func(config *Config) {
config.MaxVersion = VersionTLS12
},
expectClientSupport: false,
},
{
name: "ServerTLSv12",
serverConfig: func(config *Config) {
config.MaxVersion = VersionTLS12
},
expectClientSupport: true,
expectKyber: false,
},
}
baseConfig := testConfig.Clone()
baseConfig.CurvePreferences = nil
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if test.preparation != nil {
test.preparation(t)
} else {
t.Parallel()
}
serverConfig := baseConfig.Clone()
if test.serverConfig != nil {
test.serverConfig(serverConfig)
}
serverConfig.GetConfigForClient = func(hello *ClientHelloInfo) (*Config, error) {
if !test.expectClientSupport && slices.Contains(hello.SupportedCurves, x25519Kyber768Draft00) {
return nil, errors.New("client supports Kyber768Draft00")
} else if test.expectClientSupport && !slices.Contains(hello.SupportedCurves, x25519Kyber768Draft00) {
return nil, errors.New("client does not support Kyber768Draft00")
}
return nil, nil
}
clientConfig := baseConfig.Clone()
if test.clientConfig != nil {
test.clientConfig(clientConfig)
}
ss, cs, err := testHandshake(t, clientConfig, serverConfig)
if err != nil {
t.Fatal(err)
}
if test.expectKyber {
if ss.testingOnlyCurveID != x25519Kyber768Draft00 {
t.Errorf("got CurveID %v (server), expected %v", ss.testingOnlyCurveID, x25519Kyber768Draft00)
}
if cs.testingOnlyCurveID != x25519Kyber768Draft00 {
t.Errorf("got CurveID %v (client), expected %v", cs.testingOnlyCurveID, x25519Kyber768Draft00)
}
} else {
if ss.testingOnlyCurveID == x25519Kyber768Draft00 {
t.Errorf("got CurveID %v (server), expected not Kyber", ss.testingOnlyCurveID)
}
if cs.testingOnlyCurveID == x25519Kyber768Draft00 {
t.Errorf("got CurveID %v (client), expected not Kyber", cs.testingOnlyCurveID)
}
}
if test.expectHRR {
if !ss.testingOnlyDidHRR {
t.Error("server did not use HRR")
}
if !cs.testingOnlyDidHRR {
t.Error("client did not use HRR")
}
} else {
if ss.testingOnlyDidHRR {
t.Error("server used HRR")
}
if cs.testingOnlyDidHRR {
t.Error("client used HRR")
}
}
})
}
}
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)
}
}