Refactor client TLS

This commit is contained in:
Qian Wang 2019-08-02 16:02:25 +01:00
parent 33f232475d
commit 1a628cb524
5 changed files with 38 additions and 47 deletions

View File

@ -16,7 +16,6 @@ import (
"time" "time"
"github.com/cbeuw/Cloak/internal/client" "github.com/cbeuw/Cloak/internal/client"
"github.com/cbeuw/Cloak/internal/client/TLS"
mux "github.com/cbeuw/Cloak/internal/multiplex" mux "github.com/cbeuw/Cloak/internal/multiplex"
"github.com/cbeuw/Cloak/internal/util" "github.com/cbeuw/Cloak/internal/util"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -51,7 +50,7 @@ func makeRemoteConn(sta *client.State) (net.Conn, []byte, error) {
// For android // For android
d := net.Dialer{Control: protector} d := net.Dialer{Control: protector}
clientHello, sharedSecret := TLS.ComposeClientHello(sta) clientHello, sharedSecret := client.ComposeClientHello(sta)
connectingIP := sta.RemoteHost connectingIP := sta.RemoteHost
if net.ParseIP(connectingIP).To4() == nil { if net.ParseIP(connectingIP).To4() == nil {
// IPv6 needs square brackets // IPv6 needs square brackets

View File

@ -1,13 +1,12 @@
package TLS package client
import ( import (
"encoding/binary" "encoding/binary"
"github.com/cbeuw/Cloak/internal/client"
"github.com/cbeuw/Cloak/internal/util" "github.com/cbeuw/Cloak/internal/util"
) )
type browser interface { type Browser interface {
composeClientHello() composeClientHello(*State) ([]byte, []byte)
} }
func makeServerName(serverName string) []byte { func makeServerName(serverName string) []byte {
@ -43,16 +42,8 @@ func addExtRec(typ []byte, data []byte) []byte {
return ret return ret
} }
// ComposeInitHandshake composes ClientHello with record layer // ComposeClientHello composes ClientHello with record layer
func ComposeInitHandshake(sta *client.State) ([]byte, []byte) { func ComposeClientHello(sta *State) ([]byte, []byte) {
var ch, sharedSecret []byte ch, sharedSecret := sta.Browser.composeClientHello(sta)
switch sta.BrowserSig {
case "chrome":
ch, sharedSecret = (&chrome{}).composeClientHello(sta)
case "firefox":
ch, sharedSecret = (&firefox{}).composeClientHello(sta)
default:
panic("Unsupported browser:" + sta.BrowserSig)
}
return util.AddRecordLayer(ch, []byte{0x16}, []byte{0x03, 0x01}), sharedSecret return util.AddRecordLayer(ch, []byte{0x16}, []byte{0x03, 0x01}), sharedSecret
} }

View File

@ -1,23 +1,19 @@
// Chrome 76 // Chrome 76
package TLS package client
import ( import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"math/rand" "math/rand"
"time" "time"
"github.com/cbeuw/Cloak/internal/client"
) )
type chrome struct { type Chrome struct{}
browser
}
func makeGREASE() []byte { func makeGREASE() []byte {
// see https://tools.ietf.org/html/draft-davidben-tls-grease-01 // see https://tools.ietf.org/html/draft-davidben-tls-grease-01
// This is exclusive to chrome. // This is exclusive to Chrome.
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
sixteenth := rand.Intn(16) sixteenth := rand.Intn(16)
monoGREASE := byte(sixteenth*16 + 0xA) monoGREASE := byte(sixteenth*16 + 0xA)
@ -25,7 +21,7 @@ func makeGREASE() []byte {
return doubleGREASE return doubleGREASE
} }
func (c *chrome) composeExtensions(sta *client.State, keyShare []byte) []byte { func (c *Chrome) composeExtensions(serverName string, keyShare []byte) []byte {
makeSupportedGroups := func() []byte { makeSupportedGroups := func() []byte {
suppGroupListLen := []byte{0x00, 0x08} suppGroupListLen := []byte{0x00, 0x08}
@ -51,13 +47,13 @@ func (c *chrome) composeExtensions(sta *client.State, keyShare []byte) []byte {
// extension length is always 401, and server name length is variable // extension length is always 401, and server name length is variable
var ext [17][]byte var ext [17][]byte
ext[0] = addExtRec(makeGREASE(), nil) // First GREASE ext[0] = addExtRec(makeGREASE(), nil) // First GREASE
ext[1] = addExtRec([]byte{0x00, 0x00}, makeServerName(sta.ServerName)) // server name indication ext[1] = addExtRec([]byte{0x00, 0x00}, makeServerName(serverName)) // server name indication
ext[2] = addExtRec([]byte{0x00, 0x17}, nil) // extended_master_secret ext[2] = addExtRec([]byte{0x00, 0x17}, nil) // extended_master_secret
ext[3] = addExtRec([]byte{0xff, 0x01}, []byte{0x00}) // renegotiation_info ext[3] = addExtRec([]byte{0xff, 0x01}, []byte{0x00}) // renegotiation_info
ext[4] = addExtRec([]byte{0x00, 0x0a}, makeSupportedGroups()) // supported groups ext[4] = addExtRec([]byte{0x00, 0x0a}, makeSupportedGroups()) // supported groups
ext[5] = addExtRec([]byte{0x00, 0x0b}, []byte{0x01, 0x00}) // ec point formats ext[5] = addExtRec([]byte{0x00, 0x0b}, []byte{0x01, 0x00}) // ec point formats
ext[6] = addExtRec([]byte{0x00, 0x23}, nil) // Session tickets ext[6] = addExtRec([]byte{0x00, 0x23}, nil) // Session tickets
APLN, _ := hex.DecodeString("000c02683208687474702f312e31") APLN, _ := hex.DecodeString("000c02683208687474702f312e31")
ext[7] = addExtRec([]byte{0x00, 0x10}, APLN) // app layer proto negotiation ext[7] = addExtRec([]byte{0x00, 0x10}, APLN) // app layer proto negotiation
ext[8] = addExtRec([]byte{0x00, 0x05}, []byte{0x01, 0x00, 0x00, 0x00, 0x00}) // status request ext[8] = addExtRec([]byte{0x00, 0x05}, []byte{0x01, 0x00, 0x00, 0x00, 0x00}) // status request
@ -83,8 +79,8 @@ func (c *chrome) composeExtensions(sta *client.State, keyShare []byte) []byte {
return ret return ret
} }
func (c *chrome) composeClientHello(sta *client.State) ([]byte, []byte) { func (c *Chrome) composeClientHello(sta *State) (ch []byte, sharedSecret []byte) {
random, sessionID, keyShare, sharedSecret := client.MakeHiddenData(sta) random, sessionID, keyShare, sharedSecret := MakeHiddenData(sta)
var clientHello [12][]byte var clientHello [12][]byte
clientHello[0] = []byte{0x01} // handshake type clientHello[0] = []byte{0x01} // handshake type
clientHello[1] = []byte{0x00, 0x01, 0xfc} // length 508 clientHello[1] = []byte{0x00, 0x01, 0xfc} // length 508
@ -97,7 +93,7 @@ func (c *chrome) composeClientHello(sta *client.State) ([]byte, []byte) {
clientHello[7] = append(makeGREASE(), cipherSuites...) // cipher suites clientHello[7] = append(makeGREASE(), cipherSuites...) // cipher suites
clientHello[8] = []byte{0x01} // compression methods length 1 clientHello[8] = []byte{0x01} // compression methods length 1
clientHello[9] = []byte{0x00} // compression methods clientHello[9] = []byte{0x00} // compression methods
clientHello[11] = c.composeExtensions(sta, keyShare) clientHello[11] = c.composeExtensions(sta.ServerName, keyShare)
clientHello[10] = []byte{0x00, 0x00} // extensions length 401 clientHello[10] = []byte{0x00, 0x00} // extensions length 401
binary.BigEndian.PutUint16(clientHello[10], uint16(len(clientHello[11]))) binary.BigEndian.PutUint16(clientHello[10], uint16(len(clientHello[11])))
var ret []byte var ret []byte

View File

@ -1,19 +1,15 @@
// Firefox 68 // Firefox 68
package TLS package client
import ( import (
"crypto/rand" "crypto/rand"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"github.com/cbeuw/Cloak/internal/client"
) )
type firefox struct { type Firefox struct{}
browser
}
func (f *firefox) composeExtensions(serverName string, keyShare []byte) []byte { func (f *Firefox) composeExtensions(serverName string, keyShare []byte) []byte {
composeKeyShare := func(hidden []byte) []byte { composeKeyShare := func(hidden []byte) []byte {
ret := make([]byte, 107) ret := make([]byte, 107)
ret[0], ret[1] = 0x00, 0x69 // length 105 ret[0], ret[1] = 0x00, 0x69 // length 105
@ -54,8 +50,8 @@ func (f *firefox) composeExtensions(serverName string, keyShare []byte) []byte {
return ret return ret
} }
func (f *firefox) composeClientHello(sta *client.State) ([]byte, []byte) { func (f *Firefox) composeClientHello(sta *State) (ch []byte, sharedSecret []byte) {
random, sessionID, keyShare, sharedSecret := client.MakeHiddenData(sta) random, sessionID, keyShare, sharedSecret := MakeHiddenData(sta)
var clientHello [12][]byte var clientHello [12][]byte
clientHello[0] = []byte{0x01} // handshake type clientHello[0] = []byte{0x01} // handshake type

View File

@ -35,10 +35,11 @@ type State struct {
staticPub crypto.PublicKey staticPub crypto.PublicKey
IsAdmin bool IsAdmin bool
Browser Browser
ProxyMethod string ProxyMethod string
EncryptionMethod byte EncryptionMethod byte
ServerName string ServerName string
BrowserSig string
NumConn int NumConn int
} }
@ -100,7 +101,7 @@ func (sta *State) ParseConfig(conf string) (err error) {
return err return err
} }
switch preParse.EncryptionMethod { switch strings.ToLower(preParse.EncryptionMethod) {
case "plain": case "plain":
sta.EncryptionMethod = 0x00 sta.EncryptionMethod = 0x00
case "aes-gcm": case "aes-gcm":
@ -111,9 +112,17 @@ func (sta *State) ParseConfig(conf string) (err error) {
return errors.New("Unknown encryption method") return errors.New("Unknown encryption method")
} }
switch strings.ToLower(preParse.BrowserSig) {
case "chrome":
sta.Browser = &Chrome{}
case "firefox":
sta.Browser = &Firefox{}
default:
return errors.New("unsupported browser signature")
}
sta.ProxyMethod = preParse.ProxyMethod sta.ProxyMethod = preParse.ProxyMethod
sta.ServerName = preParse.ServerName sta.ServerName = preParse.ServerName
sta.BrowserSig = preParse.BrowserSig
sta.NumConn = preParse.NumConn sta.NumConn = preParse.NumConn
uid, err := base64.StdEncoding.DecodeString(preParse.UID) uid, err := base64.StdEncoding.DecodeString(preParse.UID)