Compare commits

...

5 Commits

Author SHA1 Message Date
Roland Shoemaker
d5987bff8a [release-branch.go1.25] crypto/tls: check verifiedChains roots when resuming sessions
When resuming TLS sessions, on the server and client verify that the
chains stored in the session state (verifiedChains) are still acceptable
with regards to the Config by checking for the inclusion of the root in
either ClientCAs (server) or RootCAs (client). This prevents resuming
a session with a certificate chain that would be rejected during a full
handshake due to an untrusted root.

Updates #77113
Updates #77356
Updates CVE-2025-68121

Change-Id: I11fe00909ef1961c24ecf80bf5b97f7b1121d359
Reviewed-on: https://go-review.googlesource.com/c/go/+/737700
Auto-Submit: Roland Shoemaker <roland@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Coia Prant <coiaprant@gmail.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/740065
Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Nicholas Husin <nsh@golang.org>
2026-01-28 14:03:29 -08:00
Roland Shoemaker
c2d04c0994 [release-branch.go1.25] crypto/tls: add verifiedChains expiration checking during resumption
When resuming a session, check that the verifiedChains contain at least
one chain that is still valid at the time of resumption. If not, trigger
a new handshake.

Updates #77113
Updates #77356
Updates CVE-2025-68121

Change-Id: I14f585c43da17802513cbdd5b10c552d7a38b34e
Reviewed-on: https://go-review.googlesource.com/c/go/+/739321
Reviewed-by: Coia Prant <coiaprant@gmail.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/740064
Reviewed-by: Damien Neil <dneil@google.com>
Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-by: Nicholas Husin <nsh@golang.org>
2026-01-28 14:03:25 -08:00
Roland Shoemaker
6b1110a40f [release-branch.go1.25] Revert "crypto/tls: don't copy auto-rotated session ticket keys in Config.Clone"
This reverts CL 736709 (commit bba24719a4).

Updates #77113
Updates #77356
Updates CVE-2025-68121

Change-Id: I0261cb75e9adf9d0ac9890dc91ae8476b8988ba0
Reviewed-on: https://go-review.googlesource.com/c/go/+/739320
Reviewed-by: Coia Prant <coiaprant@gmail.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/740063
Reviewed-by: Nicholas Husin <nsh@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Nicholas Husin <husin@google.com>
2026-01-28 14:03:22 -08:00
Roland Shoemaker
0765a9d624 [release-branch.go1.25] crypto/x509: fix single label excluded name constraints handling
Only strip labels when both the domain and constraint have more than one
label.

Fixes #76935
Fixes #77323

Change-Id: Ifdaae2cbe0c57984bb7334a8f08fa33a800e7c27
Reviewed-on: https://go-review.googlesource.com/c/go/+/739400
Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2026-01-28 13:39:00 -08:00
Neal Patel
b19100991a [release-branch.go1.25] cmd/go: remove user-content from doc strings in cgo ASTs.
Thank you to RyotaK (https://ryotak.net) of GMO Flatt Security Inc. for reporting this issue.

Updates #76697
Fixes #77129
Fixes CVE-2025-61732

Change-Id: I9ecbef556f6e545fb152407041cd086c069f22d1
Reviewed-on: https://go-review.googlesource.com/c/go/+/740040
Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
2026-01-28 12:31:52 -08:00
9 changed files with 332 additions and 63 deletions

View File

@@ -301,17 +301,12 @@ func (f *File) saveExport(x interface{}, context astContext) {
error_(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name)
}
doc := ""
for _, c1 := range n.Doc.List {
if c1 != c {
doc += c1.Text + "\n"
}
}
f.ExpFunc = append(f.ExpFunc, &ExpFunc{
Func: n,
ExpName: name,
Doc: doc,
// Caution: Do not set the Doc field on purpose
// to ensure that there are no unintended artifacts
// in the binary. See https://go.dev/issue/76697.
})
break
}

View File

@@ -942,10 +942,6 @@ const maxSessionTicketLifetime = 7 * 24 * time.Hour
// Clone returns a shallow clone of c or nil if c is nil. It is safe to clone a [Config] that is
// being used concurrently by a TLS client or server.
//
// If Config.SessionTicketKey is unpopulated, and Config.SetSessionTicketKeys has not been
// called, the clone will not share the same auto-rotated session ticket keys as the original
// Config in order to prevent sessions from being resumed across Configs.
func (c *Config) Clone() *Config {
if c == nil {
return nil
@@ -986,8 +982,7 @@ func (c *Config) Clone() *Config {
EncryptedClientHelloRejectionVerify: c.EncryptedClientHelloRejectionVerify,
EncryptedClientHelloKeys: c.EncryptedClientHelloKeys,
sessionTicketKeys: c.sessionTicketKeys,
// We explicitly do not copy autoSessionTicketKeys, so that Configs do
// not share the same auto-rotated keys.
autoSessionTicketKeys: c.autoSessionTicketKeys,
}
}
@@ -1808,3 +1803,31 @@ func fipsAllowChain(chain []*x509.Certificate) bool {
return true
}
// anyValidVerifiedChain reports if at least one of the chains in verifiedChains
// is valid, as indicated by none of the certificates being expired and the root
// being in opts.Roots (or in the system root pool if opts.Roots is nil). If
// verifiedChains is empty, it returns false.
func anyValidVerifiedChain(verifiedChains [][]*x509.Certificate, opts x509.VerifyOptions) bool {
for _, chain := range verifiedChains {
if len(chain) == 0 {
continue
}
if slices.ContainsFunc(chain, func(cert *x509.Certificate) bool {
return opts.CurrentTime.Before(cert.NotBefore) || opts.CurrentTime.After(cert.NotAfter)
}) {
continue
}
// Since we already validated the chain, we only care that it is
// rooted in a CA in CAs, or in the system pool. On platforms where
// we control chain validation (e.g. not Windows or macOS) this is a
// simple lookup in the CertPool internal hash map. On other
// platforms, this may be more expensive, depending on how they
// implement verification of just root certificates.
root := chain[len(chain)-1]
if _, err := root.Verify(opts); err == nil {
return true
}
}
return false
}

View File

@@ -429,9 +429,6 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (
return nil, nil, nil, nil
}
// Check that the cached server certificate is not expired, and that it's
// valid for the ServerName. This should be ensured by the cache key, but
// protect the application from a faulty ClientSessionCache implementation.
if c.config.time().After(session.peerCertificates[0].NotAfter) {
// Expired certificate, delete the entry.
c.config.ClientSessionCache.Put(cacheKey, nil)
@@ -443,6 +440,18 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (
return nil, nil, nil, nil
}
if err := session.peerCertificates[0].VerifyHostname(c.config.ServerName); err != nil {
// This should be ensured by the cache key, but protect the
// application from a faulty ClientSessionCache implementation.
return nil, nil, nil, nil
}
opts := x509.VerifyOptions{
CurrentTime: c.config.time(),
Roots: c.config.RootCAs,
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
}
if !anyValidVerifiedChain(session.verifiedChains, opts) {
// No valid chains, delete the entry.
c.config.ClientSessionCache.Put(cacheKey, nil)
return nil, nil, nil, nil
}
}

View File

@@ -520,16 +520,16 @@ func (hs *serverHandshakeState) checkForResumption() error {
if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
return nil
}
if sessionHasClientCerts {
now := c.config.time()
for _, c := range sessionState.peerCertificates {
if now.After(c.NotAfter) {
return nil
}
}
if sessionHasClientCerts && c.config.time().After(sessionState.peerCertificates[0].NotAfter) {
return nil
}
opts := x509.VerifyOptions{
CurrentTime: c.config.time(),
Roots: c.config.ClientCAs,
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}
if sessionHasClientCerts && c.config.ClientAuth >= VerifyClientCertIfGiven &&
len(sessionState.verifiedChains) == 0 {
!anyValidVerifiedChain(sessionState.verifiedChains, opts) {
return nil
}

View File

@@ -2123,7 +2123,7 @@ func TestHandshakeContextHierarchy(t *testing.T) {
}
}
func TestHandshakeChainExpiryResumptionTLS12(t *testing.T) {
func TestHandshakeChainExpiryResumption(t *testing.T) {
t.Run("TLS1.2", func(t *testing.T) {
testHandshakeChainExpiryResumption(t, VersionTLS12)
})
@@ -2134,7 +2134,8 @@ func TestHandshakeChainExpiryResumptionTLS12(t *testing.T) {
func testHandshakeChainExpiryResumption(t *testing.T, version uint16) {
now := time.Now()
createChain := func(leafNotAfter, rootNotAfter time.Time) (certDER []byte, root *x509.Certificate) {
createChain := func(leafNotAfter, rootNotAfter time.Time) (leafDER, expiredLeafDER []byte, root *x509.Certificate) {
tmpl := &x509.Certificate{
Subject: pkix.Name{CommonName: "root"},
NotBefore: rootNotAfter.Add(-time.Hour * 24),
@@ -2158,39 +2159,177 @@ func testHandshakeChainExpiryResumption(t *testing.T, version uint16) {
NotAfter: leafNotAfter,
KeyUsage: x509.KeyUsageDigitalSignature,
}
certDER, err = x509.CreateCertificate(rand.Reader, tmpl, root, &testECDSAPrivateKey.PublicKey, testECDSAPrivateKey)
leafCertDER, err := x509.CreateCertificate(rand.Reader, tmpl, root, &testECDSAPrivateKey.PublicKey, testECDSAPrivateKey)
if err != nil {
t.Fatalf("CreateCertificate: %v", err)
}
tmpl.NotBefore, tmpl.NotAfter = leafNotAfter.Add(-time.Hour*24*365), leafNotAfter.Add(-time.Hour*24*364)
expiredLeafDERCertDER, err := x509.CreateCertificate(rand.Reader, tmpl, root, &testECDSAPrivateKey.PublicKey, testECDSAPrivateKey)
if err != nil {
t.Fatalf("CreateCertificate: %v", err)
}
return certDER, root
return leafCertDER, expiredLeafDERCertDER, root
}
testExpiration := func(name string, leafNotAfter, rootNotAfter time.Time) {
t.Run(name, func(t *testing.T) {
initialLeafDER, expiredLeafDER, initialRoot := createChain(leafNotAfter, rootNotAfter)
serverConfig := testConfig.Clone()
serverConfig.MaxVersion = version
serverConfig.Certificates = []Certificate{{
Certificate: [][]byte{initialLeafDER, expiredLeafDER},
PrivateKey: testECDSAPrivateKey,
}}
serverConfig.ClientCAs = x509.NewCertPool()
serverConfig.ClientCAs.AddCert(initialRoot)
serverConfig.ClientAuth = RequireAndVerifyClientCert
serverConfig.Time = func() time.Time {
return now
}
serverConfig.InsecureSkipVerify = false
serverConfig.ServerName = "expired-resume.example.com"
clientConfig := testConfig.Clone()
clientConfig.MaxVersion = version
clientConfig.Certificates = []Certificate{{
Certificate: [][]byte{initialLeafDER, expiredLeafDER},
PrivateKey: testECDSAPrivateKey,
}}
clientConfig.RootCAs = x509.NewCertPool()
clientConfig.RootCAs.AddCert(initialRoot)
clientConfig.ServerName = "expired-resume.example.com"
clientConfig.ClientSessionCache = NewLRUClientSessionCache(32)
clientConfig.InsecureSkipVerify = false
clientConfig.ServerName = "expired-resume.example.com"
clientConfig.Time = func() time.Time {
return now
}
testResume := func(t *testing.T, sc, cc *Config, expectResume bool) {
t.Helper()
ss, cs, err := testHandshake(t, cc, sc)
if err != nil {
t.Fatalf("handshake: %v", err)
}
if cs.DidResume != expectResume {
t.Fatalf("DidResume = %v; want %v", cs.DidResume, expectResume)
}
if ss.DidResume != expectResume {
t.Fatalf("DidResume = %v; want %v", cs.DidResume, expectResume)
}
}
testResume(t, serverConfig, clientConfig, false)
testResume(t, serverConfig, clientConfig, true)
expiredNow := time.Unix(0, min(leafNotAfter.UnixNano(), rootNotAfter.UnixNano())).Add(time.Minute)
freshLeafDER, expiredLeafDER, freshRoot := createChain(expiredNow.Add(time.Hour), expiredNow.Add(time.Hour))
clientConfig.Certificates = []Certificate{{
Certificate: [][]byte{freshLeafDER, expiredLeafDER},
PrivateKey: testECDSAPrivateKey,
}}
serverConfig.Time = func() time.Time {
return expiredNow
}
serverConfig.ClientCAs = x509.NewCertPool()
serverConfig.ClientCAs.AddCert(freshRoot)
testResume(t, serverConfig, clientConfig, false)
})
}
initialLeafDER, initialRoot := createChain(now.Add(time.Hour), now.Add(2*time.Hour))
testExpiration("LeafExpiresBeforeRoot", now.Add(2*time.Hour), now.Add(3*time.Hour))
testExpiration("LeafExpiresAfterRoot", now.Add(2*time.Hour), now.Add(time.Hour))
}
func TestHandshakeGetConfigForClientDifferentClientCAs(t *testing.T) {
t.Run("TLS1.2", func(t *testing.T) {
testHandshakeGetConfigForClientDifferentClientCAs(t, VersionTLS12)
})
t.Run("TLS1.3", func(t *testing.T) {
testHandshakeGetConfigForClientDifferentClientCAs(t, VersionTLS13)
})
}
func testHandshakeGetConfigForClientDifferentClientCAs(t *testing.T, version uint16) {
now := time.Now()
tmpl := &x509.Certificate{
Subject: pkix.Name{CommonName: "root"},
NotBefore: now.Add(-time.Hour * 24),
NotAfter: now.Add(time.Hour * 24),
IsCA: true,
BasicConstraintsValid: true,
}
rootDER, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &testECDSAPrivateKey.PublicKey, testECDSAPrivateKey)
if err != nil {
t.Fatalf("CreateCertificate: %v", err)
}
rootA, err := x509.ParseCertificate(rootDER)
if err != nil {
t.Fatalf("ParseCertificate: %v", err)
}
rootDER, err = x509.CreateCertificate(rand.Reader, tmpl, tmpl, &testECDSAPrivateKey.PublicKey, testECDSAPrivateKey)
if err != nil {
t.Fatalf("CreateCertificate: %v", err)
}
rootB, err := x509.ParseCertificate(rootDER)
if err != nil {
t.Fatalf("ParseCertificate: %v", err)
}
tmpl = &x509.Certificate{
Subject: pkix.Name{},
DNSNames: []string{"example.com"},
NotBefore: now.Add(-time.Hour * 24),
NotAfter: now.Add(time.Hour * 24),
KeyUsage: x509.KeyUsageDigitalSignature,
}
certDER, err := x509.CreateCertificate(rand.Reader, tmpl, rootA, &testECDSAPrivateKey.PublicKey, testECDSAPrivateKey)
if err != nil {
t.Fatalf("CreateCertificate: %v", err)
}
serverConfig := testConfig.Clone()
serverConfig.MaxVersion = version
serverConfig.Certificates = []Certificate{{
Certificate: [][]byte{initialLeafDER},
Certificate: [][]byte{certDER},
PrivateKey: testECDSAPrivateKey,
}}
serverConfig.ClientCAs = x509.NewCertPool()
serverConfig.ClientCAs.AddCert(initialRoot)
serverConfig.ClientAuth = RequireAndVerifyClientCert
serverConfig.Time = func() time.Time {
return now
}
serverConfig.ClientCAs = x509.NewCertPool()
serverConfig.ClientCAs.AddCert(rootA)
serverConfig.ClientAuth = RequireAndVerifyClientCert
switchConfig := false
serverConfig.GetConfigForClient = func(clientHello *ClientHelloInfo) (*Config, error) {
if !switchConfig {
return nil, nil
}
cfg := serverConfig.Clone()
cfg.ClientCAs = x509.NewCertPool()
cfg.ClientCAs.AddCert(rootB)
return cfg, nil
}
serverConfig.InsecureSkipVerify = false
serverConfig.ServerName = "example.com"
clientConfig := testConfig.Clone()
clientConfig.MaxVersion = version
clientConfig.Certificates = []Certificate{{
Certificate: [][]byte{initialLeafDER},
Certificate: [][]byte{certDER},
PrivateKey: testECDSAPrivateKey,
}}
clientConfig.RootCAs = x509.NewCertPool()
clientConfig.RootCAs.AddCert(initialRoot)
clientConfig.ServerName = "expired-resume.example.com"
clientConfig.ClientSessionCache = NewLRUClientSessionCache(32)
clientConfig.RootCAs = x509.NewCertPool()
clientConfig.RootCAs.AddCert(rootA)
clientConfig.Time = func() time.Time {
return now
}
clientConfig.InsecureSkipVerify = false
clientConfig.ServerName = "example.com"
testResume := func(t *testing.T, sc, cc *Config, expectResume bool) {
t.Helper()
@@ -2209,16 +2348,112 @@ func testHandshakeChainExpiryResumption(t *testing.T, version uint16) {
testResume(t, serverConfig, clientConfig, false)
testResume(t, serverConfig, clientConfig, true)
freshLeafDER, freshRoot := createChain(now.Add(2*time.Hour), now.Add(3*time.Hour))
clientConfig.Certificates = []Certificate{{
Certificate: [][]byte{freshLeafDER},
// Cause GetConfigForClient to return a config cloned from the base config,
// but with a different ClientCAs pool. This should cause resumption to fail.
switchConfig = true
testResume(t, serverConfig, clientConfig, false)
testResume(t, serverConfig, clientConfig, true)
}
func TestHandshakeChangeRootCAsResumption(t *testing.T) {
t.Run("TLS1.2", func(t *testing.T) {
testHandshakeChangeRootCAsResumption(t, VersionTLS12)
})
t.Run("TLS1.3", func(t *testing.T) {
testHandshakeChangeRootCAsResumption(t, VersionTLS13)
})
}
func testHandshakeChangeRootCAsResumption(t *testing.T, version uint16) {
now := time.Now()
tmpl := &x509.Certificate{
Subject: pkix.Name{CommonName: "root"},
NotBefore: now.Add(-time.Hour * 24),
NotAfter: now.Add(time.Hour * 24),
IsCA: true,
BasicConstraintsValid: true,
}
rootDER, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &testECDSAPrivateKey.PublicKey, testECDSAPrivateKey)
if err != nil {
t.Fatalf("CreateCertificate: %v", err)
}
rootA, err := x509.ParseCertificate(rootDER)
if err != nil {
t.Fatalf("ParseCertificate: %v", err)
}
rootDER, err = x509.CreateCertificate(rand.Reader, tmpl, tmpl, &testECDSAPrivateKey.PublicKey, testECDSAPrivateKey)
if err != nil {
t.Fatalf("CreateCertificate: %v", err)
}
rootB, err := x509.ParseCertificate(rootDER)
if err != nil {
t.Fatalf("ParseCertificate: %v", err)
}
tmpl = &x509.Certificate{
Subject: pkix.Name{},
DNSNames: []string{"example.com"},
NotBefore: now.Add(-time.Hour * 24),
NotAfter: now.Add(time.Hour * 24),
KeyUsage: x509.KeyUsageDigitalSignature,
}
certDER, err := x509.CreateCertificate(rand.Reader, tmpl, rootA, &testECDSAPrivateKey.PublicKey, testECDSAPrivateKey)
if err != nil {
t.Fatalf("CreateCertificate: %v", err)
}
serverConfig := testConfig.Clone()
serverConfig.MaxVersion = version
serverConfig.Certificates = []Certificate{{
Certificate: [][]byte{certDER},
PrivateKey: testECDSAPrivateKey,
}}
serverConfig.Time = func() time.Time {
return now.Add(1*time.Hour + 30*time.Minute)
return now
}
serverConfig.ClientCAs = x509.NewCertPool()
serverConfig.ClientCAs.AddCert(freshRoot)
serverConfig.ClientCAs.AddCert(rootA)
serverConfig.ClientAuth = RequireAndVerifyClientCert
serverConfig.InsecureSkipVerify = false
serverConfig.ServerName = "example.com"
clientConfig := testConfig.Clone()
clientConfig.MaxVersion = version
clientConfig.Certificates = []Certificate{{
Certificate: [][]byte{certDER},
PrivateKey: testECDSAPrivateKey,
}}
clientConfig.ClientSessionCache = NewLRUClientSessionCache(32)
clientConfig.RootCAs = x509.NewCertPool()
clientConfig.RootCAs.AddCert(rootA)
clientConfig.Time = func() time.Time {
return now
}
clientConfig.InsecureSkipVerify = false
clientConfig.ServerName = "example.com"
testResume := func(t *testing.T, sc, cc *Config, expectResume bool) {
t.Helper()
ss, cs, err := testHandshake(t, cc, sc)
if err != nil {
t.Fatalf("handshake: %v", err)
}
if cs.DidResume != expectResume {
t.Fatalf("DidResume = %v; want %v", cs.DidResume, expectResume)
}
if ss.DidResume != expectResume {
t.Fatalf("DidResume = %v; want %v", cs.DidResume, expectResume)
}
}
testResume(t, serverConfig, clientConfig, false)
testResume(t, serverConfig, clientConfig, true)
clientConfig = clientConfig.Clone()
clientConfig.RootCAs = x509.NewCertPool()
clientConfig.RootCAs.AddCert(rootB)
testResume(t, serverConfig, clientConfig, false)
testResume(t, serverConfig, clientConfig, true)
}

View File

@@ -15,6 +15,7 @@ import (
"crypto/internal/hpke"
"crypto/rsa"
"crypto/tls/internal/fips140tls"
"crypto/x509"
"errors"
"fmt"
"hash"
@@ -354,7 +355,6 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
return nil
}
pskIdentityLoop:
for i, identity := range hs.clientHello.pskIdentities {
if i >= maxClientPSKIdentities {
break
@@ -407,16 +407,16 @@ pskIdentityLoop:
if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
continue
}
if sessionHasClientCerts {
now := c.config.time()
for _, c := range sessionState.peerCertificates {
if now.After(c.NotAfter) {
continue pskIdentityLoop
}
}
if sessionHasClientCerts && c.config.time().After(sessionState.peerCertificates[0].NotAfter) {
continue
}
opts := x509.VerifyOptions{
CurrentTime: c.config.time(),
Roots: c.config.ClientCAs,
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}
if sessionHasClientCerts && c.config.ClientAuth >= VerifyClientCertIfGiven &&
len(sessionState.verifiedChains) == 0 {
!anyValidVerifiedChain(sessionState.verifiedChains, opts) {
continue
}

View File

@@ -935,8 +935,8 @@ func TestCloneNonFuncFields(t *testing.T) {
}
}
// Set the unexported fields related to session ticket keys, which are copied with Clone().
c1.autoSessionTicketKeys = []ticketKey{c1.ticketKeyFromBytes(c1.SessionTicketKey)}
c1.sessionTicketKeys = []ticketKey{c1.ticketKeyFromBytes(c1.SessionTicketKey)}
// We explicitly don't copy autoSessionTicketKeys in Clone, so don't set it.
c2 := c1.Clone()
if !reflect.DeepEqual(&c1, c2) {
@@ -2347,12 +2347,3 @@ func TestECH(t *testing.T) {
check()
}
func TestConfigCloneAutoSessionTicketKeys(t *testing.T) {
orig := &Config{}
orig.ticketKeys(nil)
clone := orig.Clone()
if slices.Equal(orig.autoSessionTicketKeys, clone.autoSessionTicketKeys) {
t.Fatal("autoSessionTicketKeys slice copied in Clone")
}
}

View File

@@ -1658,6 +1658,22 @@ var nameConstraintsTests = []nameConstraintsTest{
},
expectedError: "\"*.example.com\" is not permitted",
},
// #89: a TLD constraint doesn't exclude unrelated wildcards
{
roots: []constraintsSpec{
{
bad: []string{"dns:tld"},
},
},
intermediates: [][]constraintsSpec{
{
{},
},
},
leaf: leafSpec{
sans: []string{"dns:*.example.com"},
},
},
}
func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {

View File

@@ -546,7 +546,7 @@ func matchDomainConstraint(domain, constraint string, excluded bool, reversedDom
return false, nil
}
if excluded && wildcardDomain && len(domainLabels) > 1 && len(constraintLabels) > 0 {
if excluded && wildcardDomain && len(domainLabels) > 1 && len(constraintLabels) > 1 {
domainLabels = domainLabels[:len(domainLabels)-1]
constraintLabels = constraintLabels[:len(constraintLabels)-1]
}