diff --git a/dialer/mtls/dialer.go b/dialer/mtls/dialer.go index f7052a6..be5fd1c 100644 --- a/dialer/mtls/dialer.go +++ b/dialer/mtls/dialer.go @@ -2,8 +2,8 @@ package mtls import ( "context" - "crypto/tls" "errors" + tls "github.com/refraction-networking/utls" "net" "sync" "time" @@ -123,7 +123,20 @@ func (d *mtlsDialer) Handshake(ctx context.Context, conn net.Conn, options ...di } func (d *mtlsDialer) initSession(ctx context.Context, conn net.Conn) (*muxSession, error) { - tlsConn := tls.Client(conn, d.options.TLSConfig) + tlsConfig := d.options.TLSConfig + var utlsConf = &tls.Config{InsecureSkipVerify: tlsConfig.InsecureSkipVerify, ServerName: tlsConfig.ServerName, ClientAuth: tls.ClientAuthType(tlsConfig.ClientAuth), ClientCAs: tlsConfig.ClientCAs, RootCAs: tlsConfig.RootCAs} + if len(tlsConfig.Certificates) > 0 { + for _, certificate := range tlsConfig.Certificates { + utlsConf.Certificates = append(utlsConf.Certificates, tls.Certificate{ + Certificate: certificate.Certificate, + PrivateKey: certificate.PrivateKey, + OCSPStaple: certificate.OCSPStaple, + SignedCertificateTimestamps: certificate.SignedCertificateTimestamps, + Leaf: certificate.Leaf, + }) + } + } + tlsConn := tls.UClient(conn, utlsConf, tls.HelloChrome_Auto) if err := tlsConn.HandshakeContext(ctx); err != nil { return nil, err } diff --git a/dialer/mws/dialer.go b/dialer/mws/dialer.go index cdd1105..68d076e 100644 --- a/dialer/mws/dialer.go +++ b/dialer/mws/dialer.go @@ -3,6 +3,8 @@ package mws import ( "context" "errors" + "github.com/go-gost/x/util" + tls "github.com/refraction-networking/utls" "net" "net/url" "sync" @@ -158,6 +160,28 @@ func (d *mwsDialer) initSession(ctx context.Context, host string, conn net.Conn, if d.tlsEnabled { url.Scheme = "wss" dialer.TLSClientConfig = d.options.TLSConfig + tlsConfig := d.options.TLSConfig + dialer.NetDialTLSContext = func(ctx context.Context, network, addr string) (net.Conn, error) { + utlsConf := &tls.Config{InsecureSkipVerify: tlsConfig.InsecureSkipVerify, ServerName: tlsConfig.ServerName, ClientAuth: tls.ClientAuthType(tlsConfig.ClientAuth), ClientCAs: tlsConfig.ClientCAs, RootCAs: tlsConfig.RootCAs} + if len(tlsConfig.Certificates) > 0 { + for _, certificate := range tlsConfig.Certificates { + utlsConf.Certificates = append(utlsConf.Certificates, tls.Certificate{ + Certificate: certificate.Certificate, + PrivateKey: certificate.PrivateKey, + OCSPStaple: certificate.OCSPStaple, + SignedCertificateTimestamps: certificate.SignedCertificateTimestamps, + Leaf: certificate.Leaf, + }) + } + } + client := tls.UClient(conn, utlsConf, tls.HelloCustom) + client.ApplyPreset(util.NewWsSpec()) + err := client.Handshake() + if err != nil { + return nil, err + } + return client, nil + } } if d.md.handshakeTimeout > 0 { diff --git a/dialer/tls/dialer.go b/dialer/tls/dialer.go index ebf990e..01fc7ae 100644 --- a/dialer/tls/dialer.go +++ b/dialer/tls/dialer.go @@ -70,7 +70,7 @@ func (d *tlsDialer) Handshake(ctx context.Context, conn net.Conn, options ...dia }) } } - tlsConn := tls.UClient(conn, utlsConf, tls.HelloChrome_102) + tlsConn := tls.UClient(conn, utlsConf, tls.HelloChrome_Auto) if err := tlsConn.HandshakeContext(ctx); err != nil { conn.Close() return nil, err diff --git a/dialer/ws/dialer.go b/dialer/ws/dialer.go index cac0dbc..04f80e9 100644 --- a/dialer/ws/dialer.go +++ b/dialer/ws/dialer.go @@ -2,6 +2,7 @@ package ws import ( "context" + "github.com/go-gost/x/util" tls "github.com/refraction-networking/utls" "net" "net/url" @@ -111,7 +112,7 @@ func (d *wsDialer) Handshake(ctx context.Context, conn net.Conn, options ...dial } } client := tls.UClient(conn, utlsConf, tls.HelloCustom) - client.ApplyPreset(newWsSpec()) + client.ApplyPreset(util.NewWsSpec()) err := client.Handshake() if err != nil { return nil, err @@ -159,76 +160,3 @@ func (d *wsDialer) keepalive(conn ws_util.WebsocketConn) { conn.SetWriteDeadline(time.Time{}) } } - -func newWsSpec() *tls.ClientHelloSpec { - return &tls.ClientHelloSpec{ - CipherSuites: []uint16{ - tls.GREASE_PLACEHOLDER, - tls.TLS_AES_128_GCM_SHA256, - tls.TLS_AES_256_GCM_SHA384, - tls.TLS_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, - tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, - tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - tls.TLS_RSA_WITH_AES_128_GCM_SHA256, - tls.TLS_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_RSA_WITH_AES_128_CBC_SHA, - tls.TLS_RSA_WITH_AES_256_CBC_SHA, - }, - CompressionMethods: []byte{ - 0x00, // compressionNone - }, - Extensions: []tls.TLSExtension{ - &tls.UtlsGREASEExtension{}, - &tls.SNIExtension{}, - &tls.ExtendedMasterSecretExtension{}, - &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, - &tls.SupportedCurvesExtension{[]tls.CurveID{ - tls.GREASE_PLACEHOLDER, - tls.X25519, - tls.CurveP256, - tls.CurveP384, - }}, - &tls.SupportedPointsExtension{SupportedPoints: []byte{ - 0x00, // pointFormatUncompressed - }}, - &tls.SessionTicketExtension{}, - &tls.ALPNExtension{AlpnProtocols: []string{"http/1.1"}}, - &tls.StatusRequestExtension{}, - &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ - tls.ECDSAWithP256AndSHA256, - tls.PSSWithSHA256, - tls.PKCS1WithSHA256, - tls.ECDSAWithP384AndSHA384, - tls.PSSWithSHA384, - tls.PKCS1WithSHA384, - tls.PSSWithSHA512, - tls.PKCS1WithSHA512, - }}, - &tls.SCTExtension{}, - &tls.KeyShareExtension{[]tls.KeyShare{ - {Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}}, - {Group: tls.X25519}, - }}, - &tls.PSKKeyExchangeModesExtension{[]uint8{ - tls.PskModeDHE, - }}, - &tls.SupportedVersionsExtension{[]uint16{ - tls.GREASE_PLACEHOLDER, - tls.VersionTLS13, - tls.VersionTLS12, - }}, - &tls.UtlsCompressCertExtension{[]tls.CertCompressionAlgo{ - tls.CertCompressionBrotli, - }}, - &tls.ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}}, - &tls.UtlsGREASEExtension{}, - &tls.UtlsPaddingExtension{GetPaddingLen: tls.BoringPaddingStyle}, - }, - } -} diff --git a/util/utls.go b/util/utls.go new file mode 100644 index 0000000..ac5f93f --- /dev/null +++ b/util/utls.go @@ -0,0 +1,76 @@ +package util + +import tls "github.com/refraction-networking/utls" + +func NewWsSpec() *tls.ClientHelloSpec { + return &tls.ClientHelloSpec{ + CipherSuites: []uint16{ + tls.GREASE_PLACEHOLDER, + tls.TLS_AES_128_GCM_SHA256, + tls.TLS_AES_256_GCM_SHA384, + tls.TLS_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + tls.TLS_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_RSA_WITH_AES_128_CBC_SHA, + tls.TLS_RSA_WITH_AES_256_CBC_SHA, + }, + CompressionMethods: []byte{ + 0x00, // compressionNone + }, + Extensions: []tls.TLSExtension{ + &tls.UtlsGREASEExtension{}, + &tls.SNIExtension{}, + &tls.ExtendedMasterSecretExtension{}, + &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, + &tls.SupportedCurvesExtension{[]tls.CurveID{ + tls.GREASE_PLACEHOLDER, + tls.X25519, + tls.CurveP256, + tls.CurveP384, + }}, + &tls.SupportedPointsExtension{SupportedPoints: []byte{ + 0x00, // pointFormatUncompressed + }}, + &tls.SessionTicketExtension{}, + &tls.ALPNExtension{AlpnProtocols: []string{"http/1.1"}}, + &tls.StatusRequestExtension{}, + &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ + tls.ECDSAWithP256AndSHA256, + tls.PSSWithSHA256, + tls.PKCS1WithSHA256, + tls.ECDSAWithP384AndSHA384, + tls.PSSWithSHA384, + tls.PKCS1WithSHA384, + tls.PSSWithSHA512, + tls.PKCS1WithSHA512, + }}, + &tls.SCTExtension{}, + &tls.KeyShareExtension{[]tls.KeyShare{ + {Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}}, + {Group: tls.X25519}, + }}, + &tls.PSKKeyExchangeModesExtension{[]uint8{ + tls.PskModeDHE, + }}, + &tls.SupportedVersionsExtension{[]uint16{ + tls.GREASE_PLACEHOLDER, + tls.VersionTLS13, + tls.VersionTLS12, + }}, + &tls.UtlsCompressCertExtension{[]tls.CertCompressionAlgo{ + tls.CertCompressionBrotli, + }}, + &tls.ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}}, + &tls.UtlsGREASEExtension{}, + &tls.UtlsPaddingExtension{GetPaddingLen: tls.BoringPaddingStyle}, + }, + } +}