From 99c4c7730a39b54fd3d9890eeb3a617fadf12d34 Mon Sep 17 00:00:00 2001
From: Andy Wang
Date: Thu, 2 Sep 2021 17:49:07 +0100
Subject: [PATCH 01/10] Update Go version
---
.github/workflows/build.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 03cdf87..99258f6 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -10,7 +10,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
- go-version: '^1.15' # The Go version to download (if necessary) and use.
+ go-version: '^1.17' # The Go version to download (if necessary) and use.
- run: go test -race -coverprofile coverage.txt -coverpkg ./... -covermode atomic ./...
- uses: codecov/codecov-action@v1
with:
From 67dba8c8facdb5b48a6f58d18134ca411ae36683 Mon Sep 17 00:00:00 2001
From: Andy Wang
Date: Wed, 26 Jan 2022 00:57:18 +0000
Subject: [PATCH 02/10] Return empty slices instead of nil for ListAllUsers
---
internal/server/usermanager/localmanager.go | 3 +++
internal/server/usermanager/voidmanager.go | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/internal/server/usermanager/localmanager.go b/internal/server/usermanager/localmanager.go
index d60f62e..4b3096b 100644
--- a/internal/server/usermanager/localmanager.go
+++ b/internal/server/usermanager/localmanager.go
@@ -191,6 +191,9 @@ func (manager *localManager) ListAllUsers() (infos []UserInfo, err error) {
})
return err
})
+ if infos == nil {
+ infos = []UserInfo{}
+ }
return
}
diff --git a/internal/server/usermanager/voidmanager.go b/internal/server/usermanager/voidmanager.go
index a20ab3c..d317353 100644
--- a/internal/server/usermanager/voidmanager.go
+++ b/internal/server/usermanager/voidmanager.go
@@ -15,7 +15,7 @@ func (v *Voidmanager) UploadStatus(updates []StatusUpdate) ([]StatusResponse, er
}
func (v *Voidmanager) ListAllUsers() ([]UserInfo, error) {
- return nil, ErrMangerIsVoid
+ return []UserInfo{}, ErrMangerIsVoid
}
func (v *Voidmanager) GetUserInfo(UID []byte) (UserInfo, error) {
From e157e73adecf4ab7c425327485f4801456f8e9fa Mon Sep 17 00:00:00 2001
From: Andy Wang
Date: Wed, 26 Jan 2022 00:58:33 +0000
Subject: [PATCH 03/10] Check proxy method after checking admin uid to allow
admin to have an invalid but unused proxy method
---
internal/server/auth.go | 4 ----
internal/server/dispatcher.go | 12 ++++++++++++
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/internal/server/auth.go b/internal/server/auth.go
index 1ce79ff..c7e6d1b 100644
--- a/internal/server/auth.go
+++ b/internal/server/auth.go
@@ -83,10 +83,6 @@ func AuthFirstPacket(firstPacket []byte, transport Transport, sta *State) (info
err = fmt.Errorf("%w: %v", ErrBadDecryption, err)
return
}
- if _, ok := sta.ProxyBook[info.ProxyMethod]; !ok {
- err = ErrBadProxyMethod
- return
- }
info.Transport = transport
return
}
diff --git a/internal/server/dispatcher.go b/internal/server/dispatcher.go
index 287e363..20eae5f 100644
--- a/internal/server/dispatcher.go
+++ b/internal/server/dispatcher.go
@@ -213,6 +213,18 @@ func dispatchConnection(conn net.Conn, sta *State) {
return
}
+ if _, ok := sta.ProxyBook[ci.ProxyMethod]; !ok {
+ log.WithFields(log.Fields{
+ "remoteAddr": conn.RemoteAddr(),
+ "UID": b64(ci.UID),
+ "sessionId": ci.SessionId,
+ "proxyMethod": ci.ProxyMethod,
+ "encryptionMethod": ci.EncryptionMethod,
+ }).Error(ErrBadProxyMethod)
+ goWeb()
+ return
+ }
+
var user *ActiveUser
if sta.IsBypass(ci.UID) {
user, err = sta.Panel.GetBypassUser(ci.UID)
From 611bad91fd9bd039165f8ef7d704037a50c33dc7 Mon Sep 17 00:00:00 2001
From: Andy Wang
Date: Wed, 2 Feb 2022 21:50:44 +0000
Subject: [PATCH 04/10] Minor refactors to remove unnecessary function
---
.gitignore | 4 +++-
internal/client/TLS.go | 25 ++++++++++++-------------
internal/client/TLS_test.go | 2 +-
internal/client/chrome.go | 20 ++++++++++----------
internal/client/chrome_test.go | 4 +---
internal/client/firefox.go | 10 +++++-----
internal/client/firefox_test.go | 4 ++--
7 files changed, 34 insertions(+), 35 deletions(-)
diff --git a/.gitignore b/.gitignore
index a82796c..9d8deca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
corpus/
suppressions/
crashers/
-*.zip
\ No newline at end of file
+*.zip
+.idea/
+build/
\ No newline at end of file
diff --git a/internal/client/TLS.go b/internal/client/TLS.go
index 39e8bb3..7e21724 100644
--- a/internal/client/TLS.go
+++ b/internal/client/TLS.go
@@ -13,14 +13,14 @@ type clientHelloFields struct {
random []byte
sessionId []byte
x25519KeyShare []byte
- sni []byte
+ serverName string
}
type browser interface {
composeClientHello(clientHelloFields) []byte
}
-func makeServerName(serverName string) []byte {
+func generateSNI(serverName string) []byte {
serverNameListLength := make([]byte, 2)
binary.BigEndian.PutUint16(serverNameListLength, uint16(len(serverName)+3))
serverNameType := []byte{0x00} // host_name
@@ -45,16 +45,6 @@ func addExtRec(typ []byte, data []byte) []byte {
return ret
}
-func genStegClientHello(ai authenticationPayload, serverName string) (ret clientHelloFields) {
- // random is marshalled ephemeral pub key 32 bytes
- // The authentication ciphertext and its tag are then distributed among SessionId and X25519KeyShare
- ret.random = ai.randPubKey[:]
- ret.sessionId = ai.ciphertextWithTag[0:32]
- ret.x25519KeyShare = ai.ciphertextWithTag[32:64]
- ret.sni = makeServerName(serverName)
- return
-}
-
type DirectTLS struct {
*common.TLSConn
browser browser
@@ -64,7 +54,16 @@ type DirectTLS struct {
// if the server proceed with Cloak authentication
func (tls *DirectTLS) Handshake(rawConn net.Conn, authInfo AuthInfo) (sessionKey [32]byte, err error) {
payload, sharedSecret := makeAuthenticationPayload(authInfo)
- chOnly := tls.browser.composeClientHello(genStegClientHello(payload, authInfo.MockDomain))
+
+ // random is marshalled ephemeral pub key 32 bytes
+ // The authentication ciphertext and its tag are then distributed among SessionId and X25519KeyShare
+ fields := clientHelloFields{
+ random: payload.randPubKey[:],
+ sessionId: payload.ciphertextWithTag[0:32],
+ x25519KeyShare: payload.ciphertextWithTag[32:64],
+ serverName: authInfo.MockDomain,
+ }
+ chOnly := tls.browser.composeClientHello(fields)
chWithRecordLayer := common.AddRecordLayer(chOnly, common.Handshake, common.VersionTLS11)
_, err = rawConn.Write(chWithRecordLayer)
if err != nil {
diff --git a/internal/client/TLS_test.go b/internal/client/TLS_test.go
index b8bdd81..bd3b051 100644
--- a/internal/client/TLS_test.go
+++ b/internal/client/TLS_test.go
@@ -33,6 +33,6 @@ func TestMakeServerName(t *testing.T) {
}
for _, p := range pairs {
- assert.Equal(t, p.target, makeServerName(p.serverName))
+ assert.Equal(t, p.target, generateSNI(p.serverName))
}
}
diff --git a/internal/client/chrome.go b/internal/client/chrome.go
index 34e394f..58c1050 100644
--- a/internal/client/chrome.go
+++ b/internal/client/chrome.go
@@ -21,7 +21,7 @@ func makeGREASE() []byte {
return doubleGREASE
}
-func (c *Chrome) composeExtensions(sni []byte, keyShare []byte) []byte {
+func (c *Chrome) composeExtensions(serverName string, keyShare []byte) []byte {
makeSupportedGroups := func() []byte {
suppGroupListLen := []byte{0x00, 0x08}
@@ -47,13 +47,13 @@ func (c *Chrome) composeExtensions(sni []byte, keyShare []byte) []byte {
// extension length is always 403, and server name length is variable
var ext [17][]byte
- ext[0] = addExtRec(makeGREASE(), nil) // First GREASE
- ext[1] = addExtRec([]byte{0x00, 0x00}, sni) // server name indication
- ext[2] = addExtRec([]byte{0x00, 0x17}, nil) // extended_master_secret
- ext[3] = addExtRec([]byte{0xff, 0x01}, []byte{0x00}) // renegotiation_info
- ext[4] = addExtRec([]byte{0x00, 0x0a}, makeSupportedGroups()) // supported groups
- ext[5] = addExtRec([]byte{0x00, 0x0b}, []byte{0x01, 0x00}) // ec point formats
- ext[6] = addExtRec([]byte{0x00, 0x23}, nil) // Session tickets
+ ext[0] = addExtRec(makeGREASE(), nil) // First GREASE
+ ext[1] = addExtRec([]byte{0x00, 0x00}, generateSNI(serverName)) // server name indication
+ ext[2] = addExtRec([]byte{0x00, 0x17}, nil) // extended_master_secret
+ ext[3] = addExtRec([]byte{0xff, 0x01}, []byte{0x00}) // renegotiation_info
+ ext[4] = addExtRec([]byte{0x00, 0x0a}, makeSupportedGroups()) // supported groups
+ ext[5] = addExtRec([]byte{0x00, 0x0b}, []byte{0x01, 0x00}) // ec point formats
+ ext[6] = addExtRec([]byte{0x00, 0x23}, nil) // Session tickets
ALPN, _ := hex.DecodeString("000c02683208687474702f312e31")
ext[7] = addExtRec([]byte{0x00, 0x10}, ALPN) // app layer proto negotiation
ext[8] = addExtRec([]byte{0x00, 0x05}, []byte{0x01, 0x00, 0x00, 0x00, 0x00}) // status request
@@ -87,12 +87,12 @@ func (c *Chrome) composeClientHello(hd clientHelloFields) (ch []byte) {
clientHello[3] = hd.random // random
clientHello[4] = []byte{0x20} // session id length 32
clientHello[5] = hd.sessionId // session id
- clientHello[6] = []byte{0x00, 0x20} // cipher suites length 34
+ clientHello[6] = []byte{0x00, 0x20} // cipher suites length 32
cipherSuites, _ := hex.DecodeString("130113021303c02bc02fc02cc030cca9cca8c013c014009c009d002f0035")
clientHello[7] = append(makeGREASE(), cipherSuites...) // cipher suites
clientHello[8] = []byte{0x01} // compression methods length 1
clientHello[9] = []byte{0x00} // compression methods
- clientHello[11] = c.composeExtensions(hd.sni, hd.x25519KeyShare)
+ clientHello[11] = c.composeExtensions(hd.serverName, hd.x25519KeyShare)
clientHello[10] = []byte{0x00, 0x00} // extensions length 403
binary.BigEndian.PutUint16(clientHello[10], uint16(len(clientHello[11])))
var ret []byte
diff --git a/internal/client/chrome_test.go b/internal/client/chrome_test.go
index 8ddb6f8..629e23c 100644
--- a/internal/client/chrome_test.go
+++ b/internal/client/chrome_test.go
@@ -30,9 +30,7 @@ func TestComposeExtension(t *testing.T) {
serverName := "github.com"
keyShare, _ := hex.DecodeString("690f074f5c01756982269b66d58c90c47dc0f281d654c7b2c16f63c9033f5604")
- sni := makeServerName(serverName)
-
- result := (&Chrome{}).composeExtensions(sni, keyShare)
+ result := (&Chrome{}).composeExtensions(serverName, keyShare)
target, _ := hex.DecodeString("8a8a00000000000f000d00000a6769746875622e636f6d00170000ff01000100000a000a00088a8a001d00170018000b00020100002300000010000e000c02683208687474702f312e31000500050100000000000d0012001004030804040105030805050108060601001200000033002b00298a8a000100001d0020690f074f5c01756982269b66d58c90c47dc0f281d654c7b2c16f63c9033f5604002d00020101002b000b0a3a3a0304030303020301001b00030200024a4a000100001500d2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
for p := 0; p < len(result); p++ {
if result[p] != target[p] {
diff --git a/internal/client/firefox.go b/internal/client/firefox.go
index 89631ee..6e66955 100644
--- a/internal/client/firefox.go
+++ b/internal/client/firefox.go
@@ -10,7 +10,7 @@ import (
type Firefox struct{}
-func (f *Firefox) composeExtensions(SNI []byte, keyShare []byte) []byte {
+func (f *Firefox) composeExtensions(serverName string, keyShare []byte) []byte {
composeKeyShare := func(hidden []byte) []byte {
ret := make([]byte, 107)
ret[0], ret[1] = 0x00, 0x69 // length 105
@@ -24,9 +24,9 @@ func (f *Firefox) composeExtensions(SNI []byte, keyShare []byte) []byte {
}
// extension length is always 399, and server name length is variable
var ext [12][]byte
- ext[0] = addExtRec([]byte{0x00, 0x00}, SNI) // server name indication
- ext[1] = addExtRec([]byte{0x00, 0x17}, nil) // extended_master_secret
- ext[2] = addExtRec([]byte{0xff, 0x01}, []byte{0x00}) // renegotiation_info
+ ext[0] = addExtRec([]byte{0x00, 0x00}, generateSNI(serverName)) // server name indication
+ ext[1] = addExtRec([]byte{0x00, 0x17}, nil) // extended_master_secret
+ ext[2] = addExtRec([]byte{0xff, 0x01}, []byte{0x00}) // renegotiation_info
suppGroup, _ := hex.DecodeString("000c001d00170018001901000101")
ext[3] = addExtRec([]byte{0x00, 0x0a}, suppGroup) // supported groups
ext[4] = addExtRec([]byte{0x00, 0x0b}, []byte{0x01, 0x00}) // ec point formats
@@ -63,7 +63,7 @@ func (f *Firefox) composeClientHello(hd clientHelloFields) (ch []byte) {
clientHello[8] = []byte{0x01} // compression methods length 1
clientHello[9] = []byte{0x00} // compression methods
- clientHello[11] = f.composeExtensions(hd.sni, hd.x25519KeyShare)
+ clientHello[11] = f.composeExtensions(hd.serverName, hd.x25519KeyShare)
clientHello[10] = []byte{0x00, 0x00} // extensions length
binary.BigEndian.PutUint16(clientHello[10], uint16(len(clientHello[11])))
diff --git a/internal/client/firefox_test.go b/internal/client/firefox_test.go
index fd04fda..6b6a338 100644
--- a/internal/client/firefox_test.go
+++ b/internal/client/firefox_test.go
@@ -11,8 +11,8 @@ func TestComposeExtensions(t *testing.T) {
serverName := "consent.google.com"
keyShare, _ := hex.DecodeString("8d8ea1b80430b7710b65f0d89b0144a5eeb218709ce6613d4fc8bfb117657c15")
- sni := makeServerName(serverName)
- result := (&Firefox{}).composeExtensions(sni, keyShare)
+
+ result := (&Firefox{}).composeExtensions(serverName, keyShare)
// skip random secp256r1
if !bytes.Equal(result[:133], target[:133]) || !bytes.Equal(result[198:], target[198:]) {
t.Errorf("got %x", result)
From 750340126ac7c44d84662e7c8538d0dc08c08c4b Mon Sep 17 00:00:00 2001
From: Andy Wang
Date: Wed, 2 Feb 2022 21:59:42 +0000
Subject: [PATCH 05/10] Update browser fingerprint versions (no actual
fingerprint change)
---
internal/client/chrome.go | 2 +-
internal/client/firefox.go | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/internal/client/chrome.go b/internal/client/chrome.go
index 58c1050..042c6f0 100644
--- a/internal/client/chrome.go
+++ b/internal/client/chrome.go
@@ -1,4 +1,4 @@
-// Fingerprint of Chrome 90
+// Fingerprint of Chrome 97
package client
diff --git a/internal/client/firefox.go b/internal/client/firefox.go
index 6e66955..10c48b6 100644
--- a/internal/client/firefox.go
+++ b/internal/client/firefox.go
@@ -1,4 +1,4 @@
-// Fingerprint of Firefox 88
+// Fingerprint of Firefox 96
package client
From 847b7e24bf406b284dd7f008af26c205f81271d2 Mon Sep 17 00:00:00 2001
From: Andy Wang
Date: Wed, 2 Feb 2022 22:18:34 +0000
Subject: [PATCH 06/10] Update dependencies
---
go.mod | 20 +++++---------
go.sum | 84 ++++++++++++++++------------------------------------------
2 files changed, 30 insertions(+), 74 deletions(-)
diff --git a/go.mod b/go.mod
index 3b69708..04cad73 100644
--- a/go.mod
+++ b/go.mod
@@ -3,22 +3,16 @@ module github.com/cbeuw/Cloak
go 1.14
require (
- github.com/cbeuw/connutil v0.0.0-20200411160121-c5a5c4a9de14
- github.com/dvyukov/go-fuzz v0.0.0-20201003075337-90825f39c90b // indirect
- github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect
- github.com/gorilla/mux v1.7.3
- github.com/gorilla/websocket v1.4.1
+ github.com/cbeuw/connutil v0.0.0-20200411215123-966bfaa51ee3
+ github.com/gorilla/mux v1.8.0
+ github.com/gorilla/websocket v1.4.2
github.com/juju/ratelimit v1.0.1
- github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/kr/pretty v0.1.0 // indirect
- github.com/mitchellh/gox v1.0.1 // indirect
- github.com/sirupsen/logrus v1.5.0
- github.com/stephens2424/writerset v1.0.2 // indirect
+ github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.6.1
gitlab.com/yawning/utls.git v0.0.12-1
- go.etcd.io/bbolt v1.3.4
- golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
- golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect
- golang.org/x/tools v0.0.0-20201015182029-a5d9e455e9c4 // indirect
+ go.etcd.io/bbolt v1.3.6
+ golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838
+ golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
)
diff --git a/go.sum b/go.sum
index 7fc2281..052333a 100644
--- a/go.sum
+++ b/go.sum
@@ -1,96 +1,58 @@
-github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74=
-github.com/cbeuw/connutil v0.0.0-20200411160121-c5a5c4a9de14 h1:bWJKlzTJR7C9DX0l1qhkTaP1lTEBWVDKhg8C/tNJqKg=
-github.com/cbeuw/connutil v0.0.0-20200411160121-c5a5c4a9de14/go.mod h1:6jR2SzckGv8hIIS9zWJ160mzGVVOYp4AXZMDtacL6LE=
+github.com/cbeuw/connutil v0.0.0-20200411215123-966bfaa51ee3 h1:LRxW8pdmWmyhoNh+TxUjxsAinGtCsVGjsl3xg6zoRSs=
+github.com/cbeuw/connutil v0.0.0-20200411215123-966bfaa51ee3/go.mod h1:6jR2SzckGv8hIIS9zWJ160mzGVVOYp4AXZMDtacL6LE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
-github.com/dvyukov/go-fuzz v0.0.0-20201003075337-90825f39c90b h1:CXfDl9Y3NKuhOSxF9kXhiLmuYCdufQDrLY2fO1BzqBU=
-github.com/dvyukov/go-fuzz v0.0.0-20201003075337-90825f39c90b/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
-github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
-github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
-github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
-github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
-github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/hashicorp/go-version v1.0.0 h1:21MVWPKDphxa7ineQQTrCU5brh7OuVVAzGOCnnCPtE8=
-github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
+github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/juju/ratelimit v1.0.1 h1:+7AIFJVQ0EQgq/K9+0Krm7m530Du7tIz0METWzN0RgY=
github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
-github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI=
-github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4=
-github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY=
-github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/refraction-networking/utls v0.0.0-20190909200633-43c36d3c1f57 h1:SL1K0QAuC1b54KoY1pjPWe6kSlsFHwK9/oC960fKrTY=
-github.com/refraction-networking/utls v0.0.0-20190909200633-43c36d3c1f57/go.mod h1:tz9gX959MEFfFN5whTIocCLUG57WiILqtdVxI8c6Wj0=
-github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s=
-github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
-github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
-github.com/stephens2424/writerset v1.0.2 h1:znRLgU6g8RS5euYRcy004XeE4W+Tu44kALzy7ghPif8=
-github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9COBTTl8mzkwADnc=
+github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo=
gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ=
gitlab.com/yawning/utls.git v0.0.12-1 h1:RL6O0MP2YI0KghuEU/uGN6+8b4183eqNWoYgx7CXD0U=
gitlab.com/yawning/utls.git v0.0.12-1/go.mod h1:3ONKiSFR9Im/c3t5RKmMJTVdmZN496FNyk3mjrY1dyo=
-go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
-go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
+go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEBT6lE4eh+jOh886GHrn6V8=
-golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE=
+golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
-golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY=
-golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 h1:XDXtA5hveEEV8JB2l7nhMTp3t3cHp9ZpwcdjqyEWLlo=
+golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20201015182029-a5d9e455e9c4 h1:rQWkJiVIyJ3PgiSHL+RXc8xbrK8duU6jG5eeZ9G7nk8=
-golang.org/x/tools v0.0.0-20201015182029-a5d9e455e9c4/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
From 8e07491e9868dcb73e56cf649ff09f2bc0c27cb7 Mon Sep 17 00:00:00 2001
From: Andy Wang
Date: Thu, 24 Feb 2022 19:38:38 +0000
Subject: [PATCH 07/10] Update README.md
---
README.md | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/README.md b/README.md
index f380dac..d39fdd5 100644
--- a/README.md
+++ b/README.md
@@ -3,25 +3,26 @@
[](https://goreportcard.com/report/github.com/cbeuw/Cloak)
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SAUYKGSREP8GL&source=url)
-
+
+
+
+
-
+Cloak is a [pluggable transport](https://www.ietf.org/proceedings/103/slides/slides-103-pearg-pt-slides-01) that enhances
+traditional proxy tools like OpenVPN to evade [sophisticated censorship](https://en.wikipedia.org/wiki/Deep_packet_inspection) and [data discrimination](https://en.wikipedia.org/wiki/Net_bias).
-Cloak is a [pluggable transport](https://www.ietf.org/proceedings/103/slides/slides-103-pearg-pt-slides-01) that works
-alongside traditional proxy tools like OpenVPN to evade deep-packet-inspection based censorship.
-
-Cloak is not a standalone proxy program. Rather, it works by masquerading proxy tool's traffic as normal web browsing
-traffic. In contrast to traditional tools which have very prominent traffic "fingerprints", it's very difficult to
-precisely target Cloak with little false positives. This increases the collateral damage to censorship actions as
+Cloak is not a standalone proxy program. Rather, it works by masquerading proxied traffic as normal web browsing
+activities. In contrast to traditional tools which have very prominent traffic fingerprints and can be blocked by simple filtering rules,
+it's very difficult to precisely target Cloak with little false positives. This increases the collateral damage to censorship actions as
attempts to block Cloak could also damage services the censor state relies on.
-To a third party observer, a host running Cloak server is indistinguishable from an innocent web server. Both while
+To any third party observer, a host running Cloak server is indistinguishable from an innocent web server. Both while
passively observing traffic flow to and from the server, as well as while actively probing the behaviours of a Cloak
server. This is achieved through the use a series
of [cryptographic stegnatography techniques](https://github.com/cbeuw/Cloak/wiki/Steganography-and-encryption).
-Since Cloak is transparent, it can be used in conjunction with any proxy software that tunnels traffic through TCP or
-UDP, such as Shadowsocks, OpenVPN and Tor. Multiple proxy servers can be running on the same server host machine and
+Cloak can be used in conjunction with any proxy program that tunnels traffic through TCP or
+UDP, such as Shadowsocks, OpenVPN and Tor. Multiple proxy servers can be running on the same server host and
Cloak server will act as a reverse proxy, bridging clients with their desired proxy end.
Cloak multiplexes traffic through multiple underlying TCP connections which reduces head-of-line blocking and eliminates
@@ -31,9 +32,8 @@ Cloak provides multi-user support, allowing multiple clients to connect to the p
default). It also provides traffic management features such as usage credit and bandwidth control. This allows a proxy
server to serve multiple users even if the underlying proxy software wasn't designed for multiple users
-Cloak has two modes of [_Transport_](https://github.com/cbeuw/Cloak/wiki/CDN-mode): `direct` and `CDN`. Clients can
-either connect to the host running Cloak server directly, or it can instead connect to a CDN edge server, which may be
-used by many other websites as well, thus further increases the collateral damage to censorship.
+Cloak also supports tunneling through an intermediary CDN server such as Amazon Cloudfront. Such services are so widely used,
+attempts to disrupt traffic to them can lead to very high collateral damage for the censor.
## Quick Start
From 39306cf93085831b7d2ed710ccb52122a9a77a62 Mon Sep 17 00:00:00 2001
From: Andy Wang
Date: Fri, 25 Feb 2022 00:21:37 +0000
Subject: [PATCH 08/10] Update README.md
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index d39fdd5..8104505 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,10 @@
+
+
+
+
Cloak is a [pluggable transport](https://www.ietf.org/proceedings/103/slides/slides-103-pearg-pt-slides-01) that enhances
traditional proxy tools like OpenVPN to evade [sophisticated censorship](https://en.wikipedia.org/wiki/Deep_packet_inspection) and [data discrimination](https://en.wikipedia.org/wiki/Net_bias).
From 9e2549c117056b8af2701fdab22ca13e7326dfd9 Mon Sep 17 00:00:00 2001
From: moonburnt
Date: Mon, 21 Mar 2022 01:08:08 +0200
Subject: [PATCH 09/10] Fix typo in README
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 8104505..e2dff6a 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ attempts to block Cloak could also damage services the censor state relies on.
To any third party observer, a host running Cloak server is indistinguishable from an innocent web server. Both while
passively observing traffic flow to and from the server, as well as while actively probing the behaviours of a Cloak
server. This is achieved through the use a series
-of [cryptographic stegnatography techniques](https://github.com/cbeuw/Cloak/wiki/Steganography-and-encryption).
+of [cryptographic steganography techniques](https://github.com/cbeuw/Cloak/wiki/Steganography-and-encryption).
Cloak can be used in conjunction with any proxy program that tunnels traffic through TCP or
UDP, such as Shadowsocks, OpenVPN and Tor. Multiple proxy servers can be running on the same server host and
From fda8b2b3c8f202da7461a7a3e7a9bff5d5448cdc Mon Sep 17 00:00:00 2001
From: notsure2
Date: Thu, 24 Mar 2022 20:26:32 +0200
Subject: [PATCH 10/10] Add Steam client signature cab2baf994ded9c9
---
internal/client/state.go | 4 +-
internal/client/steam.go | 91 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 94 insertions(+), 1 deletion(-)
create mode 100644 internal/client/steam.go
diff --git a/internal/client/state.go b/internal/client/state.go
index b9f8125..550f002 100644
--- a/internal/client/state.go
+++ b/internal/client/state.go
@@ -238,7 +238,9 @@ func (raw *RawConfig) ProcessRawConfig(worldState common.WorldState) (local Loca
case "firefox":
browser = &Firefox{}
case "chrome":
- fallthrough
+ browser = &Chrome{}
+ case "steam":
+ browser = &Steam{}
default:
browser = &Chrome{}
}
diff --git a/internal/client/steam.go b/internal/client/steam.go
new file mode 100644
index 0000000..b022f2e
--- /dev/null
+++ b/internal/client/steam.go
@@ -0,0 +1,91 @@
+// Fingerprint of Steam Client
+
+package client
+
+import (
+ "encoding/binary"
+ "encoding/hex"
+)
+
+type Steam struct{}
+
+func (c *Steam) composeExtensions(serverName string, keyShare []byte) []byte {
+
+ makeSupportedGroups := func() []byte {
+ suppGroupListLen := []byte{0x00, 0x08}
+ ret := make([]byte, 2+8)
+ copy(ret[0:2], suppGroupListLen)
+ copy(ret[2:4], makeGREASE())
+ copy(ret[4:], []byte{0x00, 0x1d, 0x00, 0x17, 0x00, 0x18})
+ return ret
+ }
+
+ makeKeyShare := func(hidden []byte) []byte {
+ ret := make([]byte, 43)
+ ret[0], ret[1] = 0x00, 0x29 // length 41
+ copy(ret[2:4], makeGREASE())
+ ret[4], ret[5] = 0x00, 0x01 // length 1
+ ret[6] = 0x00
+ ret[7], ret[8] = 0x00, 0x1d // group x25519
+ ret[9], ret[10] = 0x00, 0x20 // length 32
+ copy(ret[11:43], hidden)
+ return ret
+ }
+
+ // extension length is always 403, and server name length is variable
+
+ var ext [17][]byte
+ ext[0] = addExtRec(makeGREASE(), nil) // First GREASE
+ ext[1] = addExtRec([]byte{0x00, 0x00}, generateSNI(serverName)) // server name indication
+ ext[2] = addExtRec([]byte{0x00, 0x17}, nil) // extended_master_secret
+ ext[3] = addExtRec([]byte{0xff, 0x01}, []byte{0x00}) // renegotiation_info
+ ext[4] = addExtRec([]byte{0x00, 0x0a}, makeSupportedGroups()) // supported groups
+ ext[5] = addExtRec([]byte{0x00, 0x0b}, []byte{0x01, 0x00}) // ec point formats
+ ext[6] = addExtRec([]byte{0x00, 0x23}, nil) // Session tickets
+ ALPN, _ := hex.DecodeString("000c02683208687474702f312e31")
+ ext[7] = addExtRec([]byte{0x00, 0x10}, ALPN) // app layer proto negotiation
+ ext[8] = addExtRec([]byte{0x00, 0x05}, []byte{0x01, 0x00, 0x00, 0x00, 0x00}) // status request
+ sigAlgo, _ := hex.DecodeString("001004030804040105030805050108060601")
+ ext[9] = addExtRec([]byte{0x00, 0x0d}, sigAlgo) // Signature Algorithms
+ ext[10] = addExtRec([]byte{0x00, 0x12}, nil) // signed cert timestamp
+ ext[11] = addExtRec([]byte{0x00, 0x33}, makeKeyShare(keyShare)) // key share
+ ext[12] = addExtRec([]byte{0x00, 0x2d}, []byte{0x01, 0x01}) // psk key exchange modes
+ suppVersions, _ := hex.DecodeString("0a9A9A0304030303020301") // 9A9A needs to be a GREASE
+ copy(suppVersions[1:3], makeGREASE())
+ ext[13] = addExtRec([]byte{0x00, 0x2b}, suppVersions) // supported versions
+ ext[14] = addExtRec([]byte{0x00, 0x1b}, []byte{0x02, 0x00, 0x02}) // compress certificate
+ ext[15] = addExtRec(makeGREASE(), []byte{0x00}) // Last GREASE
+ // len(ext[1]) + 170 + len(ext[16]) = 403
+ // len(ext[16]) = 233 - len(ext[1])
+ // 2+2+len(padding) = 233 - len(ext[1])
+ // len(padding) = 229 - len(ext[1])
+ ext[16] = addExtRec([]byte{0x00, 0x15}, make([]byte, 229-len(ext[1]))) // padding
+ var ret []byte
+ for _, e := range ext {
+ ret = append(ret, e...)
+ }
+ return ret
+}
+
+func (c *Steam) composeClientHello(hd clientHelloFields) (ch []byte) {
+ var clientHello [12][]byte
+ clientHello[0] = []byte{0x01} // handshake type
+ clientHello[1] = []byte{0x00, 0x01, 0xfc} // length 508
+ clientHello[2] = []byte{0x03, 0x03} // client version
+ clientHello[3] = hd.random // random
+ clientHello[4] = []byte{0x20} // session id length 32
+ clientHello[5] = hd.sessionId // session id
+ clientHello[6] = []byte{0x00, 0x20} // cipher suites length 32
+ cipherSuites, _ := hex.DecodeString("130313011302cca9cca8c02bc02fc02cc030c013c014009c009d002f0035")
+ clientHello[7] = append(makeGREASE(), cipherSuites...) // cipher suites
+ clientHello[8] = []byte{0x01} // compression methods length 1
+ clientHello[9] = []byte{0x00} // compression methods
+ clientHello[11] = c.composeExtensions(hd.serverName, hd.x25519KeyShare)
+ clientHello[10] = []byte{0x00, 0x00} // extensions length 403
+ binary.BigEndian.PutUint16(clientHello[10], uint16(len(clientHello[11])))
+ var ret []byte
+ for _, c := range clientHello {
+ ret = append(ret, c...)
+ }
+ return ret
+}