diff --git a/transport/internet/tls/config.go b/transport/internet/tls/config.go index 9038cd281..5fc87d38f 100644 --- a/transport/internet/tls/config.go +++ b/transport/internet/tls/config.go @@ -13,6 +13,7 @@ import ( "sync" "time" + utls "github.com/refraction-networking/utls" "github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/ocsp" @@ -22,6 +23,7 @@ import ( ) var globalSessionCache = tls.NewLRUClientSessionCache(128) +var uGlobalSessionCache = utls.NewLRUClientSessionCache(128) // ParseCertificate converts a cert.Certificate to Certificate. func ParseCertificate(c *cert.Certificate) *Certificate { @@ -280,12 +282,10 @@ func (c *Config) parseServerName() string { return c.ServerName } -func (r *RandCarrier) verifyPeerCert(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) (err error) { - // extract x509 certificates from rawCerts (verifiedChains will be nil if InsecureSkipVerify is true) - certs := make([]*x509.Certificate, len(rawCerts)) - for i, asn1Data := range rawCerts { - certs[i], _ = x509.ParseCertificate(asn1Data) - } +// Note: Remember to update uVerifyConnectionAdapter if this function needs more fields in the future. +func (r *RandCarrier) verifyConnection(cs tls.ConnectionState) error { + certs := cs.PeerCertificates + // extract x509 certificates from cs.PeerCertificates if len(certs) == 0 { return errors.New("unexpected certs") } @@ -325,7 +325,7 @@ func (r *RandCarrier) verifyPeerCert(rawCerts [][]byte, verifiedChains [][]*x509 } } if verifyResult == foundCA { - errors.New("peer cert is invalid (against pinned CA and verifyPeerCertByName)") + return errors.New("peer cert is invalid (against pinned CA and verifyPeerCertByName)") } return errors.New("peer cert is invalid (against root CAs and verifyPeerCertByName)") } @@ -352,6 +352,18 @@ func (r *RandCarrier) verifyPeerCert(rawCerts [][]byte, verifiedChains [][]*x509 return nil // r.PinnedPeerCertSha256==nil && r.verifyPeerCertByName==nil } +func uVerifyConnectionAdapter(f func(tls.ConnectionState) error) func(utls.ConnectionState) error { + if f == nil { + return nil + } + return func(cs utls.ConnectionState) error { + standardCS := tls.ConnectionState{ + PeerCertificates: cs.PeerCertificates, + } + return f(standardCS) + } +} + type RandCarrier struct { Config *tls.Config RootCAs *x509.CertPool @@ -389,7 +401,7 @@ func (c *Config) GetTLSConfig(opts ...Option) *tls.Config { RootCAs: root, NextProtos: slices.Clone(c.NextProtocol), SessionTicketsDisabled: !c.EnableSessionResumption, - VerifyPeerCertificate: randCarrier.verifyPeerCert, + VerifyConnection: randCarrier.verifyConnection, } randCarrier.Config = config if len(c.VerifyPeerCertByName) > 0 { diff --git a/transport/internet/tls/pin_test.go b/transport/internet/tls/pin_test.go index 50568df65..4b265772d 100644 --- a/transport/internet/tls/pin_test.go +++ b/transport/internet/tls/pin_test.go @@ -110,15 +110,15 @@ func TestVerifyPeerLeafCert(t *testing.T) { PinnedPeerCertSha256: [][]byte{leafHash[:]}, } - rawCerts := [][]byte{leaf.Raw} - err := r.verifyPeerCert(rawCerts, nil) + cs := tls.ConnectionState{PeerCertificates: []*x509.Certificate{leaf}} + err := r.verifyConnection(cs) if err != nil { t.Fatal("expected to verify leaf cert signed by pinned CA, but got error:", err) } // make the pinned hash incorrect r.PinnedPeerCertSha256[0][0] += 1 - err = r.verifyPeerCert(rawCerts, nil) + err = r.verifyConnection(cs) if err == nil { t.Fatal("expected to fail verifying leaf cert with incorrect pinned CA hash, but got no error") } @@ -138,15 +138,15 @@ func TestVerifyPeerCACert(t *testing.T) { PinnedPeerCertSha256: [][]byte{caHash[:]}, } - rawCerts := [][]byte{leaf.Raw, ca.Raw} - err := r.verifyPeerCert(rawCerts, nil) + cs := tls.ConnectionState{PeerCertificates: []*x509.Certificate{leaf, ca}} + err := r.verifyConnection(cs) if err != nil { t.Fatal("expected to verify leaf cert signed by pinned CA, but got error:", err) } // make the pinned hash incorrect r.PinnedPeerCertSha256[0][0] += 1 - err = r.verifyPeerCert(rawCerts, nil) + err = r.verifyConnection(cs) if err == nil { t.Fatal("expected to fail verifying leaf cert with incorrect pinned CA hash, but got no error") } diff --git a/transport/internet/tls/tls.go b/transport/internet/tls/tls.go index df5d1cbd7..7d8cee067 100644 --- a/transport/internet/tls/tls.go +++ b/transport/internet/tls/tls.go @@ -152,11 +152,16 @@ func copyConfig(c *tls.Config) *utls.Config { RootCAs: c.RootCAs, ServerName: c.ServerName, InsecureSkipVerify: c.InsecureSkipVerify, - VerifyPeerCertificate: c.VerifyPeerCertificate, + VerifyConnection: uVerifyConnectionAdapter(c.VerifyConnection), + SessionTicketsDisabled: c.SessionTicketsDisabled, KeyLogWriter: c.KeyLogWriter, EncryptedClientHelloConfigList: c.EncryptedClientHelloConfigList, NextProtos: c.NextProtos, } + if c.ClientSessionCache != nil { + config.ClientSessionCache = uGlobalSessionCache + } + return config }