github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/net/proxy/reality/client.go (about)

     1  package reality
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"crypto/aes"
     7  	"crypto/cipher"
     8  	"crypto/ecdh"
     9  	"crypto/ed25519"
    10  	"crypto/hmac"
    11  	"crypto/sha256"
    12  	"crypto/sha512"
    13  	"crypto/tls"
    14  	"crypto/x509"
    15  	"encoding/base64"
    16  	"encoding/binary"
    17  	"encoding/hex"
    18  	"fmt"
    19  	"io"
    20  	"math/rand/v2"
    21  	"net"
    22  	"net/http"
    23  	"reflect"
    24  	"strings"
    25  	"time"
    26  	"unsafe"
    27  
    28  	"github.com/Asutorufa/yuhaiin/pkg/log"
    29  	"github.com/Asutorufa/yuhaiin/pkg/net/netapi"
    30  	"github.com/Asutorufa/yuhaiin/pkg/protos/node/point"
    31  	"github.com/Asutorufa/yuhaiin/pkg/protos/node/protocol"
    32  	"github.com/Asutorufa/yuhaiin/pkg/utils/relay"
    33  	utls "github.com/refraction-networking/utls"
    34  	"golang.org/x/crypto/chacha20poly1305"
    35  	"golang.org/x/crypto/hkdf"
    36  	"golang.org/x/net/http2"
    37  )
    38  
    39  //go:linkname aesgcmPreferred github.com/refraction-networking/utls.aesgcmPreferred
    40  func aesgcmPreferred(ciphers []uint16) bool
    41  
    42  type RealityClient struct {
    43  	netapi.EmptyDispatch
    44  	proxy     netapi.Proxy
    45  	utls      *utls.Config
    46  	publicKey []byte
    47  	shortID   [8]byte
    48  
    49  	// TODO: remove debug log
    50  	Deubg bool
    51  }
    52  
    53  func init() {
    54  	point.RegisterProtocol(NewRealityClient)
    55  }
    56  
    57  func NewRealityClient(config *protocol.Protocol_Reality) point.WrapProxy {
    58  	return func(p netapi.Proxy) (netapi.Proxy, error) {
    59  		publicKey, err := base64.RawURLEncoding.DecodeString(config.Reality.PublicKey)
    60  		if err != nil {
    61  			return nil, fmt.Errorf("decode public_key failed: %w", err)
    62  		}
    63  		if len(publicKey) != 32 {
    64  			return nil, fmt.Errorf("invalid public_key")
    65  		}
    66  		var shortID [8]byte
    67  		decodedLen, err := hex.Decode(shortID[:], []byte(config.Reality.ShortId))
    68  		if err != nil {
    69  			return nil, fmt.Errorf("decode short_id failed: %w", err)
    70  		}
    71  		if decodedLen > 8 {
    72  			return nil, fmt.Errorf("invalid short_id")
    73  		}
    74  		return &RealityClient{
    75  			proxy: p,
    76  			utls: &utls.Config{
    77  				ServerName: config.Reality.ServerName,
    78  			},
    79  			publicKey: publicKey,
    80  			shortID:   shortID,
    81  			Deubg:     config.Reality.Debug,
    82  		}, nil
    83  	}
    84  }
    85  
    86  func (e *RealityClient) Conn(ctx context.Context, addr netapi.Address) (net.Conn, error) {
    87  	con, err := e.proxy.Conn(ctx, addr)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  
    92  	conn, err := e.ClientHandshake(ctx, con)
    93  	if err != nil {
    94  		con.Close()
    95  		return nil, fmt.Errorf("handshake failed: %w", err)
    96  	}
    97  
    98  	return conn, nil
    99  }
   100  
   101  func (e *RealityClient) PacketConn(ctx context.Context, addr netapi.Address) (net.PacketConn, error) {
   102  	return e.proxy.PacketConn(ctx, addr)
   103  }
   104  
   105  func (e *RealityClient) ClientHandshake(ctx context.Context, conn net.Conn) (net.Conn, error) {
   106  	verifier := &realityVerifier{
   107  		serverName: e.utls.ServerName,
   108  	}
   109  	uConfig := e.utls.Clone()
   110  	uConfig.InsecureSkipVerify = true
   111  	uConfig.SessionTicketsDisabled = true
   112  	uConfig.VerifyPeerCertificate = verifier.VerifyPeerCertificate
   113  	uConn := utls.UClient(conn, uConfig, utls.HelloChrome_Auto)
   114  	verifier.UConn = uConn
   115  	err := uConn.BuildHandshakeState()
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	if len(uConfig.NextProtos) > 0 {
   121  		for _, extension := range uConn.Extensions {
   122  			if alpnExtension, isALPN := extension.(*utls.ALPNExtension); isALPN {
   123  				alpnExtension.AlpnProtocols = uConfig.NextProtos
   124  				break
   125  			}
   126  		}
   127  	}
   128  
   129  	hello := uConn.HandshakeState.Hello
   130  	hello.SessionId = make([]byte, 32)
   131  	copy(hello.Raw[39:], hello.SessionId)
   132  
   133  	var nowTime time.Time
   134  	if uConfig.Time != nil {
   135  		nowTime = uConfig.Time()
   136  	} else {
   137  		nowTime = time.Now()
   138  	}
   139  	binary.BigEndian.PutUint64(hello.SessionId, uint64(nowTime.Unix()))
   140  
   141  	hello.SessionId[0] = 1
   142  	hello.SessionId[1] = 8
   143  	hello.SessionId[2] = 1
   144  	binary.BigEndian.PutUint32(hello.SessionId[4:], uint32(time.Now().Unix()))
   145  	copy(hello.SessionId[8:], e.shortID[:])
   146  
   147  	if e.Deubg {
   148  		log.Debug("REALITY", "hello.sessionId[:16]", hello.SessionId[:16])
   149  	}
   150  	peerKey, err := ecdh.X25519().NewPublicKey(e.publicKey)
   151  	// peerKey, err := uConn.HandshakeState.State13.EcdheKey.Curve().NewPublicKey(e.publicKey)
   152  	if err != nil {
   153  		return nil, fmt.Errorf("new ecdhe public key failed: %w", err)
   154  	}
   155  	authKey, err := uConn.HandshakeState.State13.EcdheKey.ECDH(peerKey)
   156  	if err != nil {
   157  		return nil, fmt.Errorf("ecdh key failed: %w", err)
   158  	}
   159  	verifier.authKey = authKey
   160  	_, err = hkdf.New(sha256.New, authKey, hello.Random[:20], []byte("REALITY")).Read(authKey)
   161  	if err != nil {
   162  		return nil, err
   163  	}
   164  
   165  	var aead cipher.AEAD
   166  	if aesgcmPreferred(hello.CipherSuites) {
   167  		block, _ := aes.NewCipher(authKey)
   168  		aead, _ = cipher.NewGCM(block)
   169  	} else {
   170  		aead, _ = chacha20poly1305.New(authKey)
   171  	}
   172  
   173  	aead.Seal(hello.SessionId[:0], hello.Random[20:], hello.SessionId[:16], hello.Raw)
   174  	copy(hello.Raw[39:], hello.SessionId)
   175  
   176  	if e.Deubg {
   177  		log.Debug("REALITY", "hello.sessionId", hello.SessionId)
   178  		log.Debug("REALITY", "uConn.AuthKey", authKey)
   179  	}
   180  
   181  	err = uConn.HandshakeContext(ctx)
   182  	if err != nil {
   183  		return nil, fmt.Errorf("handshake failed: %w", err)
   184  	}
   185  
   186  	if e.Deubg {
   187  		log.Debug("REALITY", "Conn.Verified", verifier.verified)
   188  	}
   189  
   190  	if !verifier.verified {
   191  		go realityClientFallback(uConn, e.utls.ServerName, utls.HelloChrome_Auto)
   192  		return nil, fmt.Errorf("reality verification failed")
   193  	}
   194  
   195  	return uConn, nil
   196  }
   197  
   198  func realityClientFallback(uConn net.Conn, serverName string, fingerprint utls.ClientHelloID) {
   199  	defer uConn.Close()
   200  	client := &http.Client{
   201  		Transport: &http2.Transport{
   202  			DialTLSContext: func(ctx context.Context, network, addr string, config *tls.Config) (net.Conn, error) {
   203  				return uConn, nil
   204  			},
   205  		},
   206  	}
   207  	request, _ := http.NewRequest("GET", "https://"+serverName, nil)
   208  	request.Header.Set("User-Agent", fingerprint.Client)
   209  	request.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", rand.IntN(32)+30)})
   210  	response, err := client.Do(request)
   211  	if err != nil {
   212  		return
   213  	}
   214  	_, _ = relay.Copy(io.Discard, response.Body)
   215  	response.Body.Close()
   216  }
   217  
   218  type realityVerifier struct {
   219  	*utls.UConn
   220  	serverName string
   221  	authKey    []byte
   222  	verified   bool
   223  }
   224  
   225  func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
   226  	p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates")
   227  	certs := *(*([]*x509.Certificate))(unsafe.Pointer(uintptr(unsafe.Pointer(c.Conn)) + p.Offset))
   228  	if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok {
   229  		h := hmac.New(sha512.New, c.authKey)
   230  		h.Write(pub)
   231  		if bytes.Equal(h.Sum(nil), certs[0].Signature) {
   232  			c.verified = true
   233  			return nil
   234  		}
   235  	}
   236  	opts := x509.VerifyOptions{
   237  		DNSName:       c.serverName,
   238  		Intermediates: x509.NewCertPool(),
   239  	}
   240  	for _, cert := range certs[1:] {
   241  		opts.Intermediates.AddCert(cert)
   242  	}
   243  	if _, err := certs[0].Verify(opts); err != nil {
   244  		return err
   245  	}
   246  	return nil
   247  }