diff --git a/go.mod b/go.mod index cffb067a..cf588985 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/http v0.1.6 github.com/metacubex/jls-quic-go v0.0.0-20260712113821-d34e6f9b4c7f - github.com/metacubex/jls-tls v0.0.0-20260712171131-15870a03ac51 + github.com/metacubex/jls-tls v0.0.0-20260716010121-e13c4e54a728 github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604 github.com/metacubex/mhurl v0.1.0 github.com/metacubex/mlkem v0.1.0 diff --git a/go.sum b/go.sum index b219457e..b9fd2733 100644 --- a/go.sum +++ b/go.sum @@ -133,8 +133,8 @@ github.com/metacubex/http v0.1.6 h1:xvXuvXMCMxCWMF5nEJF4yiKvXL+p2atWMzs37e80m1I= github.com/metacubex/http v0.1.6/go.mod h1:Nxx0zZAo2AhRfanyL+fmmK6ACMtVsfpwIl1aFAik2Eg= github.com/metacubex/jls-quic-go v0.0.0-20260712113821-d34e6f9b4c7f h1:ywMFrpfRTU6oiRYhn2PGefm/RWdtdwsD13sDFmrJ6+s= github.com/metacubex/jls-quic-go v0.0.0-20260712113821-d34e6f9b4c7f/go.mod h1:fXVJbX1dv67OpH+jGaecl7DYRj6KDLwOya8OSUPBIxo= -github.com/metacubex/jls-tls v0.0.0-20260712171131-15870a03ac51 h1:xTFfQ+fybBXCl8mkp6ojGp+tCrfIa2ZEqSrx+4unTVM= -github.com/metacubex/jls-tls v0.0.0-20260712171131-15870a03ac51/go.mod h1:mmqs889W/TqPlfNRDa2UyJvRiLyiTJIEnWHkcj3SKB8= +github.com/metacubex/jls-tls v0.0.0-20260716010121-e13c4e54a728 h1:4IbvO5xjKMJLs5GmLl0fYI+lDcJxAoZ3hJtaqq2/YC0= +github.com/metacubex/jls-tls v0.0.0-20260716010121-e13c4e54a728/go.mod h1:mmqs889W/TqPlfNRDa2UyJvRiLyiTJIEnWHkcj3SKB8= github.com/metacubex/jsonv2 v0.0.0-20260518173308-f4597c22f1df h1:S0vBzqjXok24VopstOgPd1JdgglW9tXehrqvwpQWbQ8= github.com/metacubex/jsonv2 v0.0.0-20260518173308-f4597c22f1df/go.mod h1:F4sVXat6QjPXkNsKRDyyG3BhSkxPFFnRPEIwmmyCgbg= github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604 h1:hJwCVlE3ojViC35MGHB+FBr8TuIf3BUFn2EQ1VIamsI= diff --git a/transport/jls/utls.go b/transport/jls/utls.go index 88db4a52..8006d1eb 100644 --- a/transport/jls/utls.go +++ b/transport/jls/utls.go @@ -18,20 +18,16 @@ import ( "github.com/metacubex/http" "github.com/metacubex/randv2" utls "github.com/metacubex/utls" - "golang.org/x/crypto/cryptobyte" ) const ( - jlsClientHelloType = 1 - jlsServerHelloType = 2 - jlsHandshakeHeaderLen = 4 - jlsHelloLegacyVersionLen = 2 - jlsHelloRandomLen = 32 - jlsHelloRandomOffset = jlsHandshakeHeaderLen + jlsHelloLegacyVersionLen - jlsRandomSeedLen = jlsHelloRandomLen / 2 - jlsExtensionPreSharedKey = 41 - jlsExtensionSupportedVers = 43 - jlsExtensionKeyShare = 51 + jlsClientHelloType = 1 + jlsServerHelloType = 2 + jlsHandshakeHeaderLen = 4 + jlsHelloLegacyVersionLen = 2 + jlsHelloRandomLen = 32 + jlsHelloRandomOffset = jlsHandshakeHeaderLen + jlsHelloLegacyVersionLen + jlsRandomSeedLen = jlsHelloRandomLen / 2 ) func newUTLSClient(ctx context.Context, conn net.Conn, config *ClientConfig) (net.Conn, bool, error) { @@ -254,80 +250,8 @@ func jlsServerHelloAuthData(raw []byte) ([]byte, error) { if err != nil { return nil, err } - - s := cryptobyte.String(msg) - var messageType, compressionMethod uint8 - var legacyVersion, cipherSuite uint16 - var body, sessionID, extensions cryptobyte.String - var random []byte - if !s.ReadUint8(&messageType) || - !s.ReadUint24LengthPrefixed(&body) || - !s.Empty() || - !body.ReadUint16(&legacyVersion) || - !body.ReadBytes(&random, jlsHelloRandomLen) || - !body.ReadUint8LengthPrefixed(&sessionID) || - !body.ReadUint16(&cipherSuite) || - !body.ReadUint8(&compressionMethod) || - !body.ReadUint16LengthPrefixed(&extensions) || - !body.Empty() { - return nil, errors.New("jls: invalid uTLS server hello") - } - - type extension struct { - typeID uint16 - wire []byte - } - extensionBytes := extensions - parsed := make([]extension, 0, 3) - for len(extensions) > 0 { - remaining := extensions - var typeID uint16 - var data cryptobyte.String - if !extensions.ReadUint16(&typeID) || !extensions.ReadUint16LengthPrefixed(&data) { - return nil, errors.New("jls: invalid uTLS server hello extensions") - } - wireLen := len(remaining) - len(extensions) - parsed = append(parsed, extension{typeID: typeID, wire: remaining[:wireLen]}) - } - - // rustls decodes ServerHello extensions into fields and serializes them in - // this order when it calculates the JLS random. The wire order is irrelevant - // to TLS but not to JLS, whose authentication input must match byte for byte. - canonicalTypes := [...]uint16{ - jlsExtensionKeyShare, - jlsExtensionPreSharedKey, - jlsExtensionSupportedVers, - } - canonical := make(map[uint16][]byte, len(canonicalTypes)) - for _, ext := range parsed { - for _, typeID := range canonicalTypes { - if ext.typeID == typeID { - canonical[typeID] = ext.wire - break - } - } - } - - // Reinsert the canonical extensions at their first original position. Their - // encoded bytes and all unrelated extensions remain untouched, and the total - // length does not change. - extensionOffset := len(msg) - len(extensionBytes) - result := append([]byte(nil), msg[:extensionOffset]...) - canonicalWritten := false - for _, ext := range parsed { - if _, ok := canonical[ext.typeID]; ok { - if !canonicalWritten { - for _, typeID := range canonicalTypes { - result = append(result, canonical[typeID]...) - } - canonicalWritten = true - } - continue - } - result = append(result, ext.wire...) - } - zeroJLSBytes(result[jlsHelloRandomOffset : jlsHelloRandomOffset+jlsHelloRandomLen]) - return result, nil + zeroJLSBytes(msg[jlsHelloRandomOffset : jlsHelloRandomOffset+jlsHelloRandomLen]) + return msg, nil } func cloneJLSHello(raw []byte, messageType byte) ([]byte, error) {