diff --git a/component/tls/reality.go b/component/tls/reality.go index 41079e83..0bd08ca6 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -49,10 +49,6 @@ func GetRealityConn(ctx context.Context, conn net.Conn, fingerprint UClientHello VerifyPeerCertificate: verifier.VerifyPeerCertificate, } - if !realityConfig.SupportX25519MLKEM768 && fingerprint == HelloChrome_Auto { - fingerprint = HelloChrome_120 // old reality server doesn't work with X25519MLKEM768 - } - uConn := utls.UClient(conn, uConfig, fingerprint) verifier.UConn = uConn err := uConn.BuildHandshakeState() @@ -60,6 +56,13 @@ func GetRealityConn(ctx context.Context, conn net.Conn, fingerprint UClientHello return nil, err } + if !realityConfig.SupportX25519MLKEM768 { // for X25519MLKEM768 does not work properly with the old reality server + err = BuildRemovedX25519MLKEM768HandshakeState(uConn) + if err != nil { + return nil, err + } + } + hello := uConn.HandshakeState.Hello rawSessionID := hello.Raw[39 : 39+32] // the location of session ID for i := range rawSessionID { // https://github.com/golang/go/issues/5373 diff --git a/component/tls/utls.go b/component/tls/utls.go index 62c8b7e2..4574c526 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -13,6 +13,7 @@ import ( "github.com/metacubex/tls" utls "github.com/metacubex/utls" "github.com/mroth/weightedrand/v2" + "golang.org/x/exp/slices" ) type Conn = utls.Conn @@ -279,6 +280,32 @@ func BuildWebsocketHandshakeState(c *UConn) error { return nil } +func BuildRemovedX25519MLKEM768HandshakeState(c *UConn) error { + // Build the handshake state. This will apply every variable of the TLS of the + // fingerprint in the UConn + if err := c.BuildHandshakeState(); err != nil { + return err + } + // Iterate over extensions and check + for _, extension := range c.Extensions { + if ce, ok := extension.(*utls.SupportedCurvesExtension); ok { + ce.Curves = slices.DeleteFunc(ce.Curves, func(curveID utls.CurveID) bool { + return curveID == utls.X25519MLKEM768 + }) + } + if ks, ok := extension.(*utls.KeyShareExtension); ok { + ks.KeyShares = slices.DeleteFunc(ks.KeyShares, func(share utls.KeyShare) bool { + return share.Group == utls.X25519MLKEM768 + }) + } + } + // Rebuild the client hello + if err := c.BuildHandshakeState(); err != nil { + return err + } + return nil +} + var globalFingerprint string func SetGlobalFingerprint(fingerprint string) { diff --git a/transport/sing-shadowtls/shadowtls.go b/transport/sing-shadowtls/shadowtls.go index adf827e2..aee3e679 100644 --- a/transport/sing-shadowtls/shadowtls.go +++ b/transport/sing-shadowtls/shadowtls.go @@ -77,9 +77,6 @@ func uTLSHandshakeFunc(config *tls.Config, clientFingerprint string, version int return tlsConn.HandshakeContext(ctx) } if clientFingerprint, ok := tlsC.GetFingerprint(clientFingerprint); ok { - if version == 2 && clientFingerprint == tlsC.HelloChrome_Auto { - clientFingerprint = tlsC.HelloChrome_120 // ShadowTLS v2 not work with X25519MLKEM768 - } tlsConn := tlsC.UClient(conn, tlsConfig, clientFingerprint) if slices.Equal(tlsConfig.NextProtos, WsALPN) { err := tlsC.BuildWebsocketHandshakeState(tlsConn) @@ -87,6 +84,12 @@ func uTLSHandshakeFunc(config *tls.Config, clientFingerprint string, version int return err } } + if version == 2 { // ShadowTLS v2 not work with X25519MLKEM768 + err := tlsC.BuildRemovedX25519MLKEM768HandshakeState(tlsConn) + if err != nil { + return err + } + } return tlsConn.HandshakeContext(ctx) } tlsConn := tlsC.Client(conn, tlsConfig)