github.com/kelleygo/clashcore@v1.0.2/component/tls/reality.go (about) 1 package tls 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/binary" 16 "errors" 17 "net" 18 "net/http" 19 "reflect" 20 "strings" 21 "time" 22 "unsafe" 23 24 "github.com/kelleygo/clashcore/common/utils" 25 "github.com/kelleygo/clashcore/log" 26 "github.com/kelleygo/clashcore/ntp" 27 28 utls "github.com/sagernet/utls" 29 "github.com/zhangyunhao116/fastrand" 30 "golang.org/x/crypto/chacha20poly1305" 31 "golang.org/x/crypto/hkdf" 32 "golang.org/x/net/http2" 33 ) 34 35 const RealityMaxShortIDLen = 8 36 37 type RealityConfig struct { 38 PublicKey *ecdh.PublicKey 39 ShortID [RealityMaxShortIDLen]byte 40 } 41 42 //go:linkname aesgcmPreferred crypto/tls.aesgcmPreferred 43 func aesgcmPreferred(ciphers []uint16) bool 44 45 func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string, tlsConfig *tls.Config, realityConfig *RealityConfig) (net.Conn, error) { 46 retry := 0 47 for fingerprint, exists := GetFingerprint(ClientFingerprint); exists; retry++ { 48 verifier := &realityVerifier{ 49 serverName: tlsConfig.ServerName, 50 } 51 uConfig := &utls.Config{ 52 ServerName: tlsConfig.ServerName, 53 InsecureSkipVerify: true, 54 SessionTicketsDisabled: true, 55 VerifyPeerCertificate: verifier.VerifyPeerCertificate, 56 } 57 clientID := utls.ClientHelloID{ 58 Client: fingerprint.Client, 59 Version: fingerprint.Version, 60 Seed: fingerprint.Seed, 61 } 62 uConn := utls.UClient(conn, uConfig, clientID) 63 verifier.UConn = uConn 64 err := uConn.BuildHandshakeState() 65 if err != nil { 66 return nil, err 67 } 68 69 hello := uConn.HandshakeState.Hello 70 rawSessionID := hello.Raw[39 : 39+32] // the location of session ID 71 for i := range rawSessionID { // https://github.com/golang/go/issues/5373 72 rawSessionID[i] = 0 73 } 74 75 binary.BigEndian.PutUint64(hello.SessionId, uint64(ntp.Now().Unix())) 76 77 copy(hello.SessionId[8:], realityConfig.ShortID[:]) 78 hello.SessionId[0] = 1 79 hello.SessionId[1] = 8 80 hello.SessionId[2] = 2 81 82 //log.Debugln("REALITY hello.sessionId[:16]: %v", hello.SessionId[:16]) 83 84 ecdheKey := uConn.HandshakeState.State13.EcdheKey 85 if ecdheKey == nil { 86 // WTF??? 87 if retry > 2 { 88 return nil, errors.New("nil ecdheKey") 89 } 90 continue // retry 91 } 92 authKey, err := ecdheKey.ECDH(realityConfig.PublicKey) 93 if err != nil { 94 return nil, err 95 } 96 if authKey == nil { 97 return nil, errors.New("nil auth_key") 98 } 99 verifier.authKey = authKey 100 _, err = hkdf.New(sha256.New, authKey, hello.Random[:20], []byte("REALITY")).Read(authKey) 101 if err != nil { 102 return nil, err 103 } 104 var aeadCipher cipher.AEAD 105 if aesgcmPreferred(hello.CipherSuites) { 106 aesBlock, _ := aes.NewCipher(authKey) 107 aeadCipher, _ = cipher.NewGCM(aesBlock) 108 } else { 109 aeadCipher, _ = chacha20poly1305.New(authKey) 110 } 111 aeadCipher.Seal(hello.SessionId[:0], hello.Random[20:], hello.SessionId[:16], hello.Raw) 112 copy(hello.Raw[39:], hello.SessionId) 113 //log.Debugln("REALITY hello.sessionId: %v", hello.SessionId) 114 //log.Debugln("REALITY uConn.AuthKey: %v", authKey) 115 116 err = uConn.HandshakeContext(ctx) 117 if err != nil { 118 return nil, err 119 } 120 121 log.Debugln("REALITY Authentication: %v, AEAD: %T", verifier.verified, aeadCipher) 122 123 if !verifier.verified { 124 go realityClientFallback(uConn, uConfig.ServerName, clientID) 125 return nil, errors.New("REALITY authentication failed") 126 } 127 128 return uConn, nil 129 } 130 return nil, errors.New("unknown uTLS fingerprint") 131 } 132 133 func realityClientFallback(uConn net.Conn, serverName string, fingerprint utls.ClientHelloID) { 134 defer uConn.Close() 135 client := http.Client{ 136 Transport: &http2.Transport{ 137 DialTLSContext: func(ctx context.Context, network, addr string, config *tls.Config) (net.Conn, error) { 138 return uConn, nil 139 }, 140 }, 141 } 142 request, _ := http.NewRequest("GET", "https://"+serverName, nil) 143 request.Header.Set("User-Agent", fingerprint.Client) 144 request.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", fastrand.Intn(32)+30)}) 145 response, err := client.Do(request) 146 if err != nil { 147 return 148 } 149 //_, _ = io.Copy(io.Discard, response.Body) 150 time.Sleep(time.Duration(5+fastrand.Int63n(10)) * time.Second) 151 response.Body.Close() 152 client.CloseIdleConnections() 153 } 154 155 type realityVerifier struct { 156 *utls.UConn 157 serverName string 158 authKey []byte 159 verified bool 160 } 161 162 var pOffset = utils.MustOK(reflect.TypeOf((*utls.Conn)(nil)).Elem().FieldByName("peerCertificates")).Offset 163 164 func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 165 //p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates") 166 certs := *(*[]*x509.Certificate)(unsafe.Add(unsafe.Pointer(c.Conn), pOffset)) 167 if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok { 168 h := hmac.New(sha512.New, c.authKey) 169 h.Write(pub) 170 if bytes.Equal(h.Sum(nil), certs[0].Signature) { 171 c.verified = true 172 return nil 173 } 174 } 175 opts := x509.VerifyOptions{ 176 DNSName: c.serverName, 177 Intermediates: x509.NewCertPool(), 178 } 179 for _, cert := range certs[1:] { 180 opts.Intermediates.AddCert(cert) 181 } 182 if _, err := certs[0].Verify(opts); err != nil { 183 return err 184 } 185 return nil 186 }