mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-09-23 01:27:04 +00:00
Safe resume with pinCA & support session resume in uTLS
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
utls "github.com/refraction-networking/utls"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/ocsp"
|
"github.com/xtls/xray-core/common/ocsp"
|
||||||
@@ -22,6 +23,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var globalSessionCache = tls.NewLRUClientSessionCache(128)
|
var globalSessionCache = tls.NewLRUClientSessionCache(128)
|
||||||
|
var uGlobalSessionCache = utls.NewLRUClientSessionCache(128)
|
||||||
|
|
||||||
// ParseCertificate converts a cert.Certificate to Certificate.
|
// ParseCertificate converts a cert.Certificate to Certificate.
|
||||||
func ParseCertificate(c *cert.Certificate) *Certificate {
|
func ParseCertificate(c *cert.Certificate) *Certificate {
|
||||||
@@ -280,12 +282,10 @@ func (c *Config) parseServerName() string {
|
|||||||
return c.ServerName
|
return c.ServerName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RandCarrier) verifyPeerCert(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) (err error) {
|
// Note: Remember to update uVerifyConnectionAdapter if this function needs more fields in the future.
|
||||||
// extract x509 certificates from rawCerts (verifiedChains will be nil if InsecureSkipVerify is true)
|
func (r *RandCarrier) verifyConnection(cs tls.ConnectionState) error {
|
||||||
certs := make([]*x509.Certificate, len(rawCerts))
|
certs := cs.PeerCertificates
|
||||||
for i, asn1Data := range rawCerts {
|
// extract x509 certificates from cs.PeerCertificates
|
||||||
certs[i], _ = x509.ParseCertificate(asn1Data)
|
|
||||||
}
|
|
||||||
if len(certs) == 0 {
|
if len(certs) == 0 {
|
||||||
return errors.New("unexpected certs")
|
return errors.New("unexpected certs")
|
||||||
}
|
}
|
||||||
@@ -325,7 +325,7 @@ func (r *RandCarrier) verifyPeerCert(rawCerts [][]byte, verifiedChains [][]*x509
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if verifyResult == foundCA {
|
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)")
|
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
|
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 {
|
type RandCarrier struct {
|
||||||
Config *tls.Config
|
Config *tls.Config
|
||||||
RootCAs *x509.CertPool
|
RootCAs *x509.CertPool
|
||||||
@@ -389,7 +401,7 @@ func (c *Config) GetTLSConfig(opts ...Option) *tls.Config {
|
|||||||
RootCAs: root,
|
RootCAs: root,
|
||||||
NextProtos: slices.Clone(c.NextProtocol),
|
NextProtos: slices.Clone(c.NextProtocol),
|
||||||
SessionTicketsDisabled: !c.EnableSessionResumption,
|
SessionTicketsDisabled: !c.EnableSessionResumption,
|
||||||
VerifyPeerCertificate: randCarrier.verifyPeerCert,
|
VerifyConnection: randCarrier.verifyConnection,
|
||||||
}
|
}
|
||||||
randCarrier.Config = config
|
randCarrier.Config = config
|
||||||
if len(c.VerifyPeerCertByName) > 0 {
|
if len(c.VerifyPeerCertByName) > 0 {
|
||||||
|
|||||||
@@ -110,15 +110,15 @@ func TestVerifyPeerLeafCert(t *testing.T) {
|
|||||||
PinnedPeerCertSha256: [][]byte{leafHash[:]},
|
PinnedPeerCertSha256: [][]byte{leafHash[:]},
|
||||||
}
|
}
|
||||||
|
|
||||||
rawCerts := [][]byte{leaf.Raw}
|
cs := tls.ConnectionState{PeerCertificates: []*x509.Certificate{leaf}}
|
||||||
err := r.verifyPeerCert(rawCerts, nil)
|
err := r.verifyConnection(cs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("expected to verify leaf cert signed by pinned CA, but got error:", err)
|
t.Fatal("expected to verify leaf cert signed by pinned CA, but got error:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// make the pinned hash incorrect
|
// make the pinned hash incorrect
|
||||||
r.PinnedPeerCertSha256[0][0] += 1
|
r.PinnedPeerCertSha256[0][0] += 1
|
||||||
err = r.verifyPeerCert(rawCerts, nil)
|
err = r.verifyConnection(cs)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected to fail verifying leaf cert with incorrect pinned CA hash, but got no error")
|
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[:]},
|
PinnedPeerCertSha256: [][]byte{caHash[:]},
|
||||||
}
|
}
|
||||||
|
|
||||||
rawCerts := [][]byte{leaf.Raw, ca.Raw}
|
cs := tls.ConnectionState{PeerCertificates: []*x509.Certificate{leaf, ca}}
|
||||||
err := r.verifyPeerCert(rawCerts, nil)
|
err := r.verifyConnection(cs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("expected to verify leaf cert signed by pinned CA, but got error:", err)
|
t.Fatal("expected to verify leaf cert signed by pinned CA, but got error:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// make the pinned hash incorrect
|
// make the pinned hash incorrect
|
||||||
r.PinnedPeerCertSha256[0][0] += 1
|
r.PinnedPeerCertSha256[0][0] += 1
|
||||||
err = r.verifyPeerCert(rawCerts, nil)
|
err = r.verifyConnection(cs)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected to fail verifying leaf cert with incorrect pinned CA hash, but got no error")
|
t.Fatal("expected to fail verifying leaf cert with incorrect pinned CA hash, but got no error")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,11 +152,16 @@ func copyConfig(c *tls.Config) *utls.Config {
|
|||||||
RootCAs: c.RootCAs,
|
RootCAs: c.RootCAs,
|
||||||
ServerName: c.ServerName,
|
ServerName: c.ServerName,
|
||||||
InsecureSkipVerify: c.InsecureSkipVerify,
|
InsecureSkipVerify: c.InsecureSkipVerify,
|
||||||
VerifyPeerCertificate: c.VerifyPeerCertificate,
|
VerifyConnection: uVerifyConnectionAdapter(c.VerifyConnection),
|
||||||
|
SessionTicketsDisabled: c.SessionTicketsDisabled,
|
||||||
KeyLogWriter: c.KeyLogWriter,
|
KeyLogWriter: c.KeyLogWriter,
|
||||||
EncryptedClientHelloConfigList: c.EncryptedClientHelloConfigList,
|
EncryptedClientHelloConfigList: c.EncryptedClientHelloConfigList,
|
||||||
NextProtos: c.NextProtos,
|
NextProtos: c.NextProtos,
|
||||||
}
|
}
|
||||||
|
if c.ClientSessionCache != nil {
|
||||||
|
config.ClientSessionCache = uGlobalSessionCache
|
||||||
|
}
|
||||||
|
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user