From e656c889a82c8e25c50b5d01687276cac77645b5 Mon Sep 17 00:00:00 2001 From: Gaukas Wang Date: Fri, 28 Oct 2022 22:23:16 -0600 Subject: [PATCH 1/2] feat: Chrome 107 fp with shuffler - added `HelloChrome_107` (not used by `HelloChrome_Auto`) - added `shuffleExtensions()` to shuffle the order of extensions in a `ClientHelloSpec` --- u_common.go | 1 + u_parrots.go | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/u_common.go b/u_common.go index a80bce3f..9c388fb9 100644 --- a/u_common.go +++ b/u_common.go @@ -183,6 +183,7 @@ var ( HelloChrome_96 = ClientHelloID{helloChrome, "96", nil} HelloChrome_100 = ClientHelloID{helloChrome, "100", nil} HelloChrome_102 = ClientHelloID{helloChrome, "102", nil} + HelloChrome_107 = ClientHelloID{helloChrome, "107", nil} // beta: shuffler enabled HelloIOS_Auto = HelloIOS_14 HelloIOS_11_1 = ClientHelloID{helloIOS, "111", nil} // legacy "111" means 11.1 diff --git a/u_parrots.go b/u_parrots.go index cfd78c4f..35495d8f 100644 --- a/u_parrots.go +++ b/u_parrots.go @@ -10,6 +10,7 @@ import ( "errors" "fmt" "io" + "math/rand" "sort" "strconv" ) @@ -500,6 +501,14 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) { &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle}, }, }, nil + case HelloChrome_107: + chs, err := utlsIdToSpec(HelloChrome_102) + if err != nil { + return chs, err + } + + // Chrome 107 started shuffling the order of extensions + return shuffleExtensions(chs) case HelloFirefox_55, HelloFirefox_56: return ClientHelloSpec{ TLSVersMax: VersionTLS12, @@ -1833,6 +1842,61 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) { } } +func shuffleExtensions(chs ClientHelloSpec) (ClientHelloSpec, error) { + // Shuffle extensions to avoid fingerprinting -- introduced in Chrome 107 + // GREASE, padding will remain in place (if present) + + // Find indexes of GREASE and padding extensions + var greaseIdx []int + var paddingIdx []int + var otherExtensions []TLSExtension + + for i, ext := range chs.Extensions { + switch ext.(type) { + case *UtlsGREASEExtension: + greaseIdx = append(greaseIdx, i) + case *UtlsPaddingExtension: + paddingIdx = append(paddingIdx, i) + default: + otherExtensions = append(otherExtensions, ext) + } + } + + // Shuffle other extensions + rand.Shuffle(len(otherExtensions), func(i, j int) { + otherExtensions[i], otherExtensions[j] = otherExtensions[j], otherExtensions[i] + }) + + // Rebuild extensions slice + otherExtIdx := 0 +SHUF_EXTENSIONS: + for i := 0; i < len(chs.Extensions); i++ { + // if current index is in greaseIdx or paddingIdx, add GREASE or padding extension + for _, idx := range greaseIdx { + if i == idx { + chs.Extensions[i] = &UtlsGREASEExtension{} + continue SHUF_EXTENSIONS + } + } + for _, idx := range paddingIdx { + if i == idx { + chs.Extensions[i] = &UtlsPaddingExtension{ + GetPaddingLen: BoringPaddingStyle, + } + break SHUF_EXTENSIONS + } + } + + // otherwise add other extension + chs.Extensions[i] = otherExtensions[otherExtIdx] + otherExtIdx++ + } + if otherExtIdx != len(otherExtensions) { + return ClientHelloSpec{}, errors.New("shuffleExtensions: otherExtIdx != len(otherExtensions)") + } + return chs, nil +} + func (uconn *UConn) applyPresetByID(id ClientHelloID) (err error) { var spec ClientHelloSpec uconn.ClientHelloID = id @@ -1973,7 +2037,7 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error { ecdheParams, err := generateECDHEParameters(uconn.config.rand(), curveID) if err != nil { return fmt.Errorf("unsupported Curve in KeyShareExtension: %v."+ - "To mimic it, fill the Data(key) field manually.", curveID) + "To mimic it, fill the Data(key) field manually", curveID) } ext.KeyShares[i].Data = ecdheParams.PublicKey() if !preferredCurveIsSet { From 20a2483e6cd2a1a12f1343da6a3d5bf6f892f722 Mon Sep 17 00:00:00 2001 From: Gaukas Wang Date: Fri, 11 Nov 2022 19:19:13 -0700 Subject: [PATCH 2/2] fix: rename for chronologically accuracy - Renamed `HelloChrome_107` to `HelloChrome_106_Shuffle` to match the versioning info from https://groups.google.com/a/chromium.org/g/blink-dev/c/zdmNs2rTyVI/m/MAiQwQkwCAAJ --- u_common.go | 22 +++++++++++----------- u_parrots.go | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/u_common.go b/u_common.go index 9c388fb9..6cfc3f60 100644 --- a/u_common.go +++ b/u_common.go @@ -173,17 +173,17 @@ var ( HelloFirefox_102 = ClientHelloID{helloFirefox, "102", nil} HelloFirefox_105 = ClientHelloID{helloFirefox, "105", nil} - HelloChrome_Auto = HelloChrome_102 - HelloChrome_58 = ClientHelloID{helloChrome, "58", nil} - HelloChrome_62 = ClientHelloID{helloChrome, "62", nil} - HelloChrome_70 = ClientHelloID{helloChrome, "70", nil} - HelloChrome_72 = ClientHelloID{helloChrome, "72", nil} - HelloChrome_83 = ClientHelloID{helloChrome, "83", nil} - HelloChrome_87 = ClientHelloID{helloChrome, "87", nil} - HelloChrome_96 = ClientHelloID{helloChrome, "96", nil} - HelloChrome_100 = ClientHelloID{helloChrome, "100", nil} - HelloChrome_102 = ClientHelloID{helloChrome, "102", nil} - HelloChrome_107 = ClientHelloID{helloChrome, "107", nil} // beta: shuffler enabled + HelloChrome_Auto = HelloChrome_102 + HelloChrome_58 = ClientHelloID{helloChrome, "58", nil} + HelloChrome_62 = ClientHelloID{helloChrome, "62", nil} + HelloChrome_70 = ClientHelloID{helloChrome, "70", nil} + HelloChrome_72 = ClientHelloID{helloChrome, "72", nil} + HelloChrome_83 = ClientHelloID{helloChrome, "83", nil} + HelloChrome_87 = ClientHelloID{helloChrome, "87", nil} + HelloChrome_96 = ClientHelloID{helloChrome, "96", nil} + HelloChrome_100 = ClientHelloID{helloChrome, "100", nil} + HelloChrome_102 = ClientHelloID{helloChrome, "102", nil} + HelloChrome_106_Shuffle = ClientHelloID{helloChrome, "106", nil} // beta: shuffler enabled starting from 106 HelloIOS_Auto = HelloIOS_14 HelloIOS_11_1 = ClientHelloID{helloIOS, "111", nil} // legacy "111" means 11.1 diff --git a/u_parrots.go b/u_parrots.go index 35495d8f..b4209a0e 100644 --- a/u_parrots.go +++ b/u_parrots.go @@ -501,7 +501,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) { &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle}, }, }, nil - case HelloChrome_107: + case HelloChrome_106_Shuffle: chs, err := utlsIdToSpec(HelloChrome_102) if err != nil { return chs, err @@ -1843,7 +1843,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) { } func shuffleExtensions(chs ClientHelloSpec) (ClientHelloSpec, error) { - // Shuffle extensions to avoid fingerprinting -- introduced in Chrome 107 + // Shuffle extensions to avoid fingerprinting -- introduced in Chrome 106 // GREASE, padding will remain in place (if present) // Find indexes of GREASE and padding extensions