diff --git a/cffi_dist/build.sh b/cffi_dist/build.sh index 83f6dab..517182f 100755 --- a/cffi_dist/build.sh +++ b/cffi_dist/build.sh @@ -9,10 +9,10 @@ GOOS=darwin CGO_ENABLED=1 GOARCH=amd64 go build -buildmode=c-shared -o ./dist/tl echo 'Build Linux ARM64' # CC is needed when you cross compile from OSX to Linux # On Macos: -# GOOS=linux CGO_ENABLED=1 GOARCH=arm64 CC="aarch64-unknown-linux-gnu-gcc" go build -buildmode=c-shared -o ./dist/tls-client-linux-arm64-$1.so +GOOS=linux CGO_ENABLED=1 GOARCH=arm64 CC="aarch64-unknown-linux-gnu-gcc" go build -buildmode=c-shared -o ./dist/tls-client-linux-arm64-$1.so # On Linux: -GOOS=linux CGO_ENABLED=1 GOARCH=arm64 CC="aarch64-linux-gnu-gcc" go build -buildmode=c-shared -o ./dist/tls-client-linux-arm64-$1.so +#GOOS=linux CGO_ENABLED=1 GOARCH=arm64 CC="aarch64-linux-gnu-gcc" go build -buildmode=c-shared -o ./dist/tls-client-linux-arm64-$1.so echo 'Build Linux ARMv7' # CC is needed when you cross compile from OSX to Linux diff --git a/cffi_src/factory.go b/cffi_src/factory.go index d3ec18f..565f3f4 100644 --- a/cffi_src/factory.go +++ b/cffi_src/factory.go @@ -5,12 +5,13 @@ import ( "bytes" "encoding/base64" "fmt" - "github.com/bogdanfinn/tls-client/profiles" "io" "net" "os" "sync" + "github.com/bogdanfinn/tls-client/profiles" + http "github.com/bogdanfinn/fhttp" "github.com/bogdanfinn/fhttp/cookiejar" "github.com/bogdanfinn/fhttp/http2" @@ -30,7 +31,7 @@ func RemoveSession(sessionId string) { defer clientsLock.Unlock() client, ok := clients[sessionId] if !ok { - return + return } client.CloseIdleConnections() @@ -390,7 +391,7 @@ func getTlsClient(requestInput RequestInput, sessionId string, withSession bool) } func getCustomTlsClientProfile(customClientDefinition *CustomTlsClient) (tls.ClientHelloID, map[http2.SettingID]uint32, []http2.SettingID, []string, uint32, []http2.Priority, *http2.PriorityParam, error) { - specFactory, err := tls_client.GetSpecFactoryFromJa3String(customClientDefinition.Ja3String, customClientDefinition.SupportedSignatureAlgorithms, customClientDefinition.SupportedDelegatedCredentialsAlgorithms, customClientDefinition.SupportedVersions, customClientDefinition.KeyShareCurves, customClientDefinition.CertCompressionAlgo) + specFactory, err := tls_client.GetSpecFactoryFromJa3String(customClientDefinition.Ja3String, customClientDefinition.SupportedSignatureAlgorithms, customClientDefinition.SupportedDelegatedCredentialsAlgorithms, customClientDefinition.SupportedVersions, customClientDefinition.KeyShareCurves, customClientDefinition.ECHCandidateCipherSuites.Translate(), customClientDefinition.ECHCandidatePayloads, customClientDefinition.CertCompressionAlgo) if err != nil { return tls.ClientHelloID{}, nil, nil, nil, 0, nil, nil, err } diff --git a/cffi_src/types.go b/cffi_src/types.go index 32f1ad5..f1c0ca7 100644 --- a/cffi_src/types.go +++ b/cffi_src/types.go @@ -4,6 +4,8 @@ import ( "encoding/json" "fmt" "time" + + tls_client "github.com/bogdanfinn/tls-client" ) type TLSClientError struct { @@ -83,18 +85,39 @@ type RequestInput struct { // CustomTlsClient contains custom TLS specifications to construct a client from. type CustomTlsClient struct { - CertCompressionAlgo string `json:"certCompressionAlgo"` - ConnectionFlow uint32 `json:"connectionFlow"` - H2Settings map[string]uint32 `json:"h2Settings"` - H2SettingsOrder []string `json:"h2SettingsOrder"` - HeaderPriority *PriorityParam `json:"headerPriority"` - Ja3String string `json:"ja3String"` - KeyShareCurves []string `json:"keyShareCurves"` - PriorityFrames []PriorityFrames `json:"priorityFrames"` - PseudoHeaderOrder []string `json:"pseudoHeaderOrder"` - SupportedDelegatedCredentialsAlgorithms []string `json:"supportedDelegatedCredentialsAlgorithms"` - SupportedSignatureAlgorithms []string `json:"supportedSignatureAlgorithms"` - SupportedVersions []string `json:"supportedVersions"` + CertCompressionAlgo string `json:"certCompressionAlgo"` + ConnectionFlow uint32 `json:"connectionFlow"` + H2Settings map[string]uint32 `json:"h2Settings"` + H2SettingsOrder []string `json:"h2SettingsOrder"` + HeaderPriority *PriorityParam `json:"headerPriority"` + Ja3String string `json:"ja3String"` + KeyShareCurves []string `json:"keyShareCurves"` + ECHCandidatePayloads []uint16 `json:"ECHCandidatePayloads"` + ECHCandidateCipherSuites CandidateCipherSuites `json:"ECHCandidateCipherSuites"` + PriorityFrames []PriorityFrames `json:"priorityFrames"` + PseudoHeaderOrder []string `json:"pseudoHeaderOrder"` + SupportedDelegatedCredentialsAlgorithms []string `json:"supportedDelegatedCredentialsAlgorithms"` + SupportedSignatureAlgorithms []string `json:"supportedSignatureAlgorithms"` + SupportedVersions []string `json:"supportedVersions"` +} + +type CandidateCipherSuites []CandidateCipherSuite + +func (c CandidateCipherSuites) Translate() []tls_client.CandidateCipherSuites { + suites := make([]tls_client.CandidateCipherSuites, len(c)) + for i, suite := range c { + suites[i] = tls_client.CandidateCipherSuites{ + KdfId: suite.KdfId, + AeadId: suite.AeadId, + } + } + + return suites +} + +type CandidateCipherSuite struct { + KdfId string `json:"kdfId"` + AeadId string `json:"aeadId"` } // TransportOptions contains settings for the underlying http transport of the tls client diff --git a/client_options.go b/client_options.go index 2c4d05c..4eda6f6 100644 --- a/client_options.go +++ b/client_options.go @@ -49,6 +49,7 @@ type httpClientConfig struct { forceHttp1 bool timeout time.Duration localAddr *net.TCPAddr + // Establish a connection to origin server via ipv4 only disableIPV6 bool dialer net.Dialer diff --git a/example/main.go b/example/main.go index 6be9038..46e25eb 100644 --- a/example/main.go +++ b/example/main.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/bogdanfinn/tls-client/profiles" "io" "log" "net/url" @@ -12,10 +11,11 @@ import ( "path/filepath" "strings" + "github.com/bogdanfinn/tls-client/profiles" + http "github.com/bogdanfinn/fhttp" "github.com/bogdanfinn/fhttp/http2" tls_client "github.com/bogdanfinn/tls-client" - "github.com/bogdanfinn/tls-client/shared" tls "github.com/bogdanfinn/utls" ) @@ -27,6 +27,65 @@ func main() { requestWithCustomClient() rotateProxiesOnClient() downloadImageWithTlsClient() + testPskExtension() +} + +type TlsApiResponse struct { + IP string `json:"ip"` + HTTPVersion string `json:"http_version"` + Method string `json:"method"` + TLS struct { + Ciphers []string `json:"ciphers"` + Extensions []struct { + Name string `json:"name"` + ServerName string `json:"server_name,omitempty"` + Data string `json:"data,omitempty"` + SupportedGroups []string `json:"supported_groups,omitempty"` + EllipticCurvesPointFormats interface{} `json:"elliptic_curves_point_formats,omitempty"` + Protocols []string `json:"protocols,omitempty"` + StatusRequest struct { + CertificateStatusType string `json:"certificate_status_type"` + ResponderIDListLength int `json:"responder_id_list_length"` + RequestExtensionsLength int `json:"request_extensions_length"` + } `json:"status_request,omitempty"` + SignatureAlgorithms []string `json:"signature_algorithms,omitempty"` + SharedKeys []struct { + TLSGrease0X7A7A string `json:"TLS_GREASE (0x7a7a),omitempty"` + X2551929 string `json:"X25519 (29),omitempty"` + } `json:"shared_keys,omitempty"` + PskKeyExchangeMode string `json:"PSK_Key_Exchange_Mode,omitempty"` + Versions []string `json:"versions,omitempty"` + Algorithms []string `json:"algorithms,omitempty"` + PaddingDataLength int `json:"padding_data_length,omitempty"` + } `json:"extensions"` + TLSVersionRecord string `json:"tls_version_record"` + TLSVersionNegotiated string `json:"tls_version_negotiated"` + Ja3 string `json:"ja3"` + Ja3Hash string `json:"ja3_hash"` + ClientRandom string `json:"client_random"` + SessionID string `json:"session_id"` + } `json:"tls"` + HTTP2 struct { + AkamaiFingerprint string `json:"akamai_fingerprint"` + AkamaiFingerprintHash string `json:"akamai_fingerprint_hash"` + SentFrames []struct { + FrameType string `json:"frame_type"` + Length int `json:"length"` + Settings []string `json:"settings,omitempty"` + Increment int `json:"increment,omitempty"` + StreamID int `json:"stream_id,omitempty"` + Headers []string `json:"headers,omitempty"` + Flags []string `json:"flags,omitempty"` + Priority struct { + Weight int `json:"weight"` + DependsOn int `json:"depends_on"` + Exclusive int `json:"exclusive"` + } `json:"priority,omitempty"` + } `json:"sent_frames"` + } `json:"http2"` + HTTP1 struct { + Headers []string `json:"headers"` + } `json:"http1"` } func sslPinning() { @@ -427,7 +486,7 @@ func rotateProxiesOnClient() { return } - tlsApiResponse := shared.TlsApiResponse{} + tlsApiResponse := TlsApiResponse{} if err := json.Unmarshal(readBytes, &tlsApiResponse); err != nil { log.Println(err) return @@ -456,7 +515,7 @@ func rotateProxiesOnClient() { return } - tlsApiResponse = shared.TlsApiResponse{} + tlsApiResponse = TlsApiResponse{} if err := json.Unmarshal(readBytes, &tlsApiResponse); err != nil { log.Println(err) return @@ -514,7 +573,7 @@ func requestWithCustomClient() { Extensions: []tls.TLSExtension{ &tls.UtlsGREASEExtension{}, &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, + &tls.ExtendedMasterSecretExtension{}, &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ tls.CurveID(tls.GREASE_PLACEHOLDER), @@ -629,3 +688,204 @@ func requestWithCustomClient() { log.Printf("requesting topps as customClient1 => status code: %d\n", resp.StatusCode) } + +func testPskExtension() { + settings := map[http2.SettingID]uint32{ + http2.SettingHeaderTableSize: 65536, + http2.SettingEnablePush: 0, + http2.SettingMaxConcurrentStreams: 1000, + http2.SettingInitialWindowSize: 6291456, + http2.SettingMaxHeaderListSize: 262144, + } + settingsOrder := []http2.SettingID{ + http2.SettingHeaderTableSize, + http2.SettingEnablePush, + http2.SettingMaxConcurrentStreams, + http2.SettingInitialWindowSize, + http2.SettingMaxHeaderListSize, + } + + pseudoHeaderOrder := []string{ + ":method", + ":authority", + ":scheme", + ":path", + } + + connectionFlow := uint32(15663105) + + specFactory := func() (tls.ClientHelloSpec, error) { + return tls.ClientHelloSpec{ + CipherSuites: []uint16{ + tls.GREASE_PLACEHOLDER, + tls.TLS_AES_128_GCM_SHA256, + tls.TLS_AES_256_GCM_SHA384, + tls.TLS_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + tls.TLS_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_RSA_WITH_AES_128_CBC_SHA, + tls.TLS_RSA_WITH_AES_256_CBC_SHA, + }, + CompressionMethods: []uint8{ + tls.CompressionNone, + }, + Extensions: []tls.TLSExtension{ + &tls.UtlsGREASEExtension{}, + &tls.PSKKeyExchangeModesExtension{[]uint8{ + tls.PskModeDHE, + }}, + &tls.KeyShareExtension{[]tls.KeyShare{ + {Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}}, + {Group: tls.X25519}, + }}, + &tls.ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}}, + &tls.SupportedVersionsExtension{[]uint16{ + tls.GREASE_PLACEHOLDER, + tls.VersionTLS13, + tls.VersionTLS12, + }}, + &tls.SNIExtension{}, + &tls.SupportedPointsExtension{SupportedPoints: []byte{ + tls.PointFormatUncompressed, + }}, + &tls.StatusRequestExtension{}, + &tls.ExtendedMasterSecretExtension{}, + &tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}, + &tls.SupportedCurvesExtension{[]tls.CurveID{ + tls.CurveID(tls.GREASE_PLACEHOLDER), + tls.X25519, + tls.CurveP256, + tls.CurveP384, + }}, + &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, + &tls.UtlsCompressCertExtension{[]tls.CertCompressionAlgo{ + tls.CertCompressionBrotli, + }}, + &tls.SCTExtension{}, + &tls.SessionTicketExtension{}, + &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ + tls.ECDSAWithP256AndSHA256, + tls.PSSWithSHA256, + tls.PKCS1WithSHA256, + tls.ECDSAWithP384AndSHA384, + tls.PSSWithSHA384, + tls.PKCS1WithSHA384, + tls.PSSWithSHA512, + tls.PKCS1WithSHA512, + }}, + &tls.UtlsGREASEExtension{}, + &tls.UtlsPaddingExtension{GetPaddingLen: tls.BoringPaddingStyle}, + &tls.UtlsPreSharedKeyExtension{OmitEmptyPsk: true}, + }, + }, nil + } + + customClientProfile := profiles.NewClientProfile(tls.ClientHelloID{ + Client: "MyCustomProfileWithPSK", + Version: "1", + Seed: nil, + SpecFactory: specFactory, + }, settings, settingsOrder, pseudoHeaderOrder, connectionFlow, nil, nil) + + options := []tls_client.HttpClientOption{ + tls_client.WithTimeoutSeconds(60), + tls_client.WithClientProfile(customClientProfile), + } + + client, err := tls_client.NewHttpClient(tls_client.NewNoopLogger(), options...) + if err != nil { + log.Println(err) + return + } + + req, err := http.NewRequest(http.MethodGet, "https://tls.peet.ws/api/all", nil) + if err != nil { + log.Println(err) + return + } + + req.Header = http.Header{ + "accept": {"*/*"}, + "user-agent": {"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"}, + http.HeaderOrderKey: { + "accept", + "user-agent", + }, + } + + resp, err := client.Do(req) + if err != nil { + log.Println(err) + return + } + + defer resp.Body.Close() + + readBytes, err := io.ReadAll(resp.Body) + if err != nil { + log.Println(err) + return + } + + tlsApiResponse := TlsApiResponse{} + if err := json.Unmarshal(readBytes, &tlsApiResponse); err != nil { + log.Println(err) + return + } + + if strings.Contains(tlsApiResponse.TLS.Ja3, "-41,") { + log.Println("profile includes PSK extension (41)") + } else { + log.Println("profile does not include PSK extension (41)") + } + + // Now we are doing the second request that the session resumption kicks in + req, err = http.NewRequest(http.MethodGet, "https://tls.peet.ws/api/all", nil) + if err != nil { + log.Println(err) + return + } + + req.Header = http.Header{ + "accept": {"*/*"}, + "user-agent": {"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"}, + http.HeaderOrderKey: { + "accept", + "user-agent", + }, + } + + secondResp, err := client.Do(req) + if err != nil { + log.Println(err) + return + } + + defer secondResp.Body.Close() + + secondRespReadBytes, err := io.ReadAll(secondResp.Body) + if err != nil { + log.Println(err) + return + } + + secondTlsApiResponse := TlsApiResponse{} + if err := json.Unmarshal(secondRespReadBytes, &secondTlsApiResponse); err != nil { + log.Println(err) + return + } + + if strings.Contains(secondTlsApiResponse.TLS.Ja3, "-41,") { + log.Println("profile includes PSK extension (41)") + } else { + log.Println("profile does not include PSK extension (41)") + } +} diff --git a/go.mod b/go.mod index b2ee97b..14b1495 100644 --- a/go.mod +++ b/go.mod @@ -3,22 +3,25 @@ module github.com/bogdanfinn/tls-client go 1.20 require ( - github.com/bogdanfinn/fhttp v0.5.24 - github.com/bogdanfinn/utls v1.5.16 + github.com/bogdanfinn/fhttp v0.5.27 + github.com/bogdanfinn/utls v1.6.1 github.com/google/uuid v1.3.0 github.com/stretchr/testify v1.8.0 github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 - golang.org/x/net v0.5.0 + golang.org/x/net v0.17.0 ) require ( - github.com/andybalholm/brotli v1.0.4 // indirect + github.com/andybalholm/brotli v1.0.5 // indirect + github.com/cloudflare/circl v1.3.6 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/klauspost/compress v1.15.12 // indirect + github.com/klauspost/compress v1.16.7 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/crypto v0.1.0 // indirect - golang.org/x/sys v0.4.0 // indirect - golang.org/x/text v0.6.0 // indirect + github.com/quic-go/quic-go v0.37.4 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index c03d42d..9e60d1b 100644 --- a/go.sum +++ b/go.sum @@ -1,18 +1,36 @@ -github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/bogdanfinn/fhttp v0.5.24 h1:OlyBKjvJp6a3TotN3wuj4mQHHRbfK7QUMrzCPOZGhRc= -github.com/bogdanfinn/fhttp v0.5.24/go.mod h1:brqi5woc5eSCVHdKYBV8aZLbO7HGqpwyDLeXW+fT18I= -github.com/bogdanfinn/utls v1.5.16 h1:NhhWkegEcYETBMj9nvgO4lwvc6NcLH+znrXzO3gnw4M= -github.com/bogdanfinn/utls v1.5.16/go.mod h1:mHeRCi69cUiEyVBkKONB1cAbLjRcZnlJbGzttmiuK4o= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/bogdanfinn/fhttp v0.5.27 h1:+glR3k8v5nxfUSk7+J3M246zEQ2yadhS0vLq1utK71A= +github.com/bogdanfinn/fhttp v0.5.27/go.mod h1:oJiYPG3jQTKzk/VFmogH8jxjH5yiv2rrOH48Xso2lrE= +github.com/bogdanfinn/utls v1.6.1 h1:dKDYAcXEyFFJ3GaWaN89DEyjyRraD1qb4osdEK89ass= +github.com/bogdanfinn/utls v1.6.1/go.mod h1:VXIbRZaiY/wHZc6Hu+DZ4O2CgTzjhjCg/Ou3V4r/39Y= +github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg= +github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM= -github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 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/quic-go/quic-go v0.37.4 h1:ke8B73yMCWGq9MfrCCAw0Uzdm7GaViC3i39dsIdDlH4= +github.com/quic-go/quic-go v0.37.4/go.mod h1:YsbH1r4mSHPJcLF4k4zruUkLBqctEMBDR6VPvcYjIsU= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -20,16 +38,17 @@ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PK github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 h1:YqAladjX7xpA6BM04leXMWAEjS0mTZ5kUU9KRBriQJc= github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5/go.mod h1:2JjD2zLQYH5HO74y5+aE3remJQvl6q4Sn6aWA2wD1Ng= -golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= -golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= 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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/ja3.go b/ja3.go index 5e1b34c..e7c1b04 100644 --- a/ja3.go +++ b/ja3.go @@ -9,7 +9,12 @@ import ( tls "github.com/bogdanfinn/utls" ) -func GetSpecFactoryFromJa3String(ja3String string, supportedSignatureAlgorithms, supportedDelegatedCredentialsAlgorithms, supportedVersions, keyShareCurves []string, certCompressionAlgo string) (func() (tls.ClientHelloSpec, error), error) { +type CandidateCipherSuites struct { + KdfId string + AeadId string +} + +func GetSpecFactoryFromJa3String(ja3String string, supportedSignatureAlgorithms, supportedDelegatedCredentialsAlgorithms, supportedVersions, keyShareCurves []string, echCandidateCipherSuites []CandidateCipherSuites, candidatePayloads []uint16, certCompressionAlgo string) (func() (tls.ClientHelloSpec, error), error) { return func() (tls.ClientHelloSpec, error) { var mappedSignatureAlgorithms []tls.SignatureScheme @@ -45,6 +50,35 @@ func GetSpecFactoryFromJa3String(ja3String string, supportedSignatureAlgorithms, } } + var mappedHpkeSymmetricCipherSuites []tls.HPKESymmetricCipherSuite + + for _, echCandidateCipherSuites := range echCandidateCipherSuites { + kdfId, ok1 := kdfIds[echCandidateCipherSuites.KdfId] + + aeadId, ok2 := aeadIds[echCandidateCipherSuites.AeadId] + if ok1 && ok2 { + mappedHpkeSymmetricCipherSuites = append(mappedHpkeSymmetricCipherSuites, tls.HPKESymmetricCipherSuite{ + KdfId: kdfId, + AeadId: aeadId, + }) + } else { + kdfId, err := strconv.ParseUint(echCandidateCipherSuites.KdfId, 16, 16) + if err != nil { + return tls.ClientHelloSpec{}, fmt.Errorf("%s is not a valid KdfId", echCandidateCipherSuites.KdfId) + } + + aeadId, err := strconv.ParseUint(echCandidateCipherSuites.AeadId, 16, 16) + if err != nil { + return tls.ClientHelloSpec{}, fmt.Errorf("%s is not a valid aeadId", echCandidateCipherSuites.AeadId) + } + + mappedHpkeSymmetricCipherSuites = append(mappedHpkeSymmetricCipherSuites, tls.HPKESymmetricCipherSuite{ + KdfId: uint16(kdfId), + AeadId: uint16(aeadId), + }) + } + } + var mappedTlsVersions []uint16 for _, version := range supportedVersions { @@ -75,14 +109,14 @@ func GetSpecFactoryFromJa3String(ja3String string, supportedSignatureAlgorithms, compressionAlgo, ok := certCompression[certCompressionAlgo] if !ok { - return stringToSpec(ja3String, mappedSignatureAlgorithms, mappedDelegatedCredentialsAlgorithms, mappedTlsVersions, mappedKeyShares, nil) + return stringToSpec(ja3String, mappedSignatureAlgorithms, mappedDelegatedCredentialsAlgorithms, mappedTlsVersions, mappedKeyShares, mappedHpkeSymmetricCipherSuites, candidatePayloads, nil) } - return stringToSpec(ja3String, mappedSignatureAlgorithms, mappedDelegatedCredentialsAlgorithms, mappedTlsVersions, mappedKeyShares, &compressionAlgo) + return stringToSpec(ja3String, mappedSignatureAlgorithms, mappedDelegatedCredentialsAlgorithms, mappedTlsVersions, mappedKeyShares, mappedHpkeSymmetricCipherSuites, candidatePayloads, &compressionAlgo) }, nil } -func stringToSpec(ja3 string, signatureAlgorithms []tls.SignatureScheme, delegatedCredentialsAlgorithms []tls.SignatureScheme, tlsVersions []uint16, keyShares []tls.KeyShare, certCompression *tls.CertCompressionAlgo) (tls.ClientHelloSpec, error) { +func stringToSpec(ja3 string, signatureAlgorithms []tls.SignatureScheme, delegatedCredentialsAlgorithms []tls.SignatureScheme, tlsVersions []uint16, keyShares []tls.KeyShare, hpkeSymmetricCipherSuites []tls.HPKESymmetricCipherSuite, candidatePayloads []uint16, certCompression *tls.CertCompressionAlgo) (tls.ClientHelloSpec, error) { extMap := getExtensionBaseMap() ja3StringParts := strings.Split(ja3, ",") @@ -130,13 +164,17 @@ func stringToSpec(ja3 string, signatureAlgorithms []tls.SignatureScheme, delegat extMap[tls.ExtensionKeyShare] = &tls.KeyShareExtension{KeyShares: keyShares} extMap[tls.ExtensionSupportedPoints] = &tls.SupportedPointsExtension{SupportedPoints: targetPointFormats} + extMap[tls.ExtensionECH] = &tls.GREASEEncryptedClientHelloExtension{ + CandidateCipherSuites: hpkeSymmetricCipherSuites, + CandidatePayloadLens: candidatePayloads, + } extMap[tls.ExtensionSupportedVersions] = &tls.SupportedVersionsExtension{Versions: tlsVersions} extMap[tls.ExtensionSignatureAlgorithms] = &tls.SignatureAlgorithmsExtension{ SupportedSignatureAlgorithms: signatureAlgorithms, } extMap[tls.ExtensionDelegatedCredentials] = &tls.DelegatedCredentialsExtension{ - AlgorithmsSignature: delegatedCredentialsAlgorithms, + SupportedSignatureAlgorithms: delegatedCredentialsAlgorithms, } var exts []tls.TLSExtension @@ -191,10 +229,10 @@ func getExtensionBaseMap() map[uint16]tls.TLSExtension { }, tls.ExtensionSCT: &tls.SCTExtension{}, tls.ExtensionPadding: &tls.UtlsPaddingExtension{GetPaddingLen: tls.BoringPaddingStyle}, - tls.ExtensionExtendedMasterSecret: &tls.UtlsExtendedMasterSecretExtension{}, + tls.ExtensionExtendedMasterSecret: &tls.ExtendedMasterSecretExtension{}, tls.ExtensionRecordSizeLimit: &tls.FakeRecordSizeLimitExtension{}, tls.ExtensionSessionTicket: &tls.SessionTicketExtension{}, - tls.ExtensionPreSharedKey: &tls.PreSharedKeyExtension{}, + tls.ExtensionPreSharedKey: &tls.UtlsPreSharedKeyExtension{}, tls.ExtensionEarlyData: &tls.GenericExtension{Id: tls.ExtensionEarlyData}, tls.ExtensionCookie: &tls.CookieExtension{}, tls.ExtensionPSKModes: &tls.PSKKeyExchangeModesExtension{ diff --git a/mapper.go b/mapper.go index bc69aae..15f534c 100644 --- a/mapper.go +++ b/mapper.go @@ -3,6 +3,7 @@ package tls_client import ( "github.com/bogdanfinn/fhttp/http2" tls "github.com/bogdanfinn/utls" + "github.com/bogdanfinn/utls/dicttls" ) var H2SettingsMap = map[string]http2.SettingID{ @@ -35,6 +36,8 @@ var signatureAlgorithms = map[string]tls.SignatureScheme{ "PKCS1WithSHA1": tls.PKCS1WithSHA1, "ECDSAWithSHA1": tls.ECDSAWithSHA1, "Ed25519": tls.Ed25519, + "SHA224_RSA": tls.SHA224_RSA, + "SHA224_ECDSA": tls.SHA224_ECDSA, } var delegatedCredentialsAlgorithms = map[string]tls.SignatureScheme{ @@ -52,6 +55,18 @@ var delegatedCredentialsAlgorithms = map[string]tls.SignatureScheme{ "Ed25519": tls.Ed25519, } +var kdfIds = map[string]uint16{ + "HKDF_SHA256": dicttls.HKDF_SHA256, + "HKDF_SHA384": dicttls.HKDF_SHA384, + "HKDF_SHA512": dicttls.HKDF_SHA512, +} + +var aeadIds = map[string]uint16{ + "AEAD_AES_128_GCM": dicttls.AEAD_AES_128_GCM, + "AEAD_AES_256_GCM": dicttls.AEAD_AES_256_GCM, + "AEAD_CHACHA20_POLY1305": dicttls.AEAD_CHACHA20_POLY1305, +} + var curves = map[string]tls.CurveID{ "GREASE": tls.CurveID(tls.GREASE_PLACEHOLDER), "P256": tls.CurveP256, diff --git a/profiles/contributed_custom_profiles.go b/profiles/contributed_custom_profiles.go index b639a79..b0dc313 100644 --- a/profiles/contributed_custom_profiles.go +++ b/profiles/contributed_custom_profiles.go @@ -35,7 +35,7 @@ var ZalandoAndroidMobile = ClientProfile{ }, Extensions: []tls.TLSExtension{ &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, + &tls.ExtendedMasterSecretExtension{}, &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ tls.X25519, @@ -98,6 +98,208 @@ var ZalandoAndroidMobile = ClientProfile{ connectionFlow: 15663105, } +var ZalandoIosMobile = ClientProfile{ + clientHelloId: tls.ClientHelloID{ + Client: "ZalandoIosCustom", + Version: "1", + Seed: nil, + SpecFactory: func() (tls.ClientHelloSpec, error) { + return tls.ClientHelloSpec{ + CipherSuites: []uint16{ + tls.GREASE_PLACEHOLDER, + tls.TLS_AES_128_GCM_SHA256, + tls.TLS_AES_256_GCM_SHA384, + tls.TLS_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + }, + CompressionMethods: []byte{ + tls.CompressionNone, + }, + Extensions: []tls.TLSExtension{ + &tls.UtlsGREASEExtension{}, + &tls.SNIExtension{}, + &tls.ExtendedMasterSecretExtension{}, + &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, + &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ + tls.CurveID(tls.GREASE_PLACEHOLDER), + tls.X25519, + tls.CurveP256, + tls.CurveP384, + tls.CurveP521, + }}, + &tls.SupportedPointsExtension{SupportedPoints: []byte{ + tls.PointFormatUncompressed, + }}, + &tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}, + &tls.StatusRequestExtension{}, + &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ + tls.ECDSAWithP256AndSHA256, + tls.PSSWithSHA256, + tls.PKCS1WithSHA256, + tls.ECDSAWithP384AndSHA384, + tls.ECDSAWithSHA1, + tls.PSSWithSHA384, + tls.PSSWithSHA384, + tls.PKCS1WithSHA384, + tls.PSSWithSHA512, + tls.PKCS1WithSHA512, + tls.PKCS1WithSHA1, + }}, + &tls.SCTExtension{}, + &tls.KeyShareExtension{KeyShares: []tls.KeyShare{ + {Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}}, + {Group: tls.X25519}, + }}, + &tls.PSKKeyExchangeModesExtension{Modes: []uint8{ + tls.PskModeDHE, + }}, + &tls.SupportedVersionsExtension{Versions: []uint16{ + tls.GREASE_PLACEHOLDER, + tls.VersionTLS13, + tls.VersionTLS12, + }}, + &tls.UtlsCompressCertExtension{Algorithms: []tls.CertCompressionAlgo{ + tls.CertCompressionZlib, + }}, + &tls.UtlsGREASEExtension{}, + &tls.UtlsPaddingExtension{GetPaddingLen: tls.BoringPaddingStyle}, + }, + }, nil + }, + }, + settings: map[http2.SettingID]uint32{ + http2.SettingHeaderTableSize: 4096, + http2.SettingMaxConcurrentStreams: 100, + http2.SettingInitialWindowSize: 2097152, + http2.SettingMaxFrameSize: 16384, + http2.SettingMaxHeaderListSize: math.MaxUint32, + }, + settingsOrder: []http2.SettingID{ + http2.SettingHeaderTableSize, + http2.SettingMaxConcurrentStreams, + http2.SettingInitialWindowSize, + http2.SettingMaxFrameSize, + http2.SettingMaxHeaderListSize, + }, + pseudoHeaderOrder: []string{ + ":method", + ":path", + ":authority", + ":scheme", + }, + connectionFlow: 15663105, +} + +var NikeIosMobile = ClientProfile{ + clientHelloId: tls.ClientHelloID{ + Client: "NikeIosCustom", + Version: "1", + Seed: nil, + SpecFactory: func() (tls.ClientHelloSpec, error) { + return tls.ClientHelloSpec{ + CipherSuites: []uint16{ + tls.GREASE_PLACEHOLDER, + tls.TLS_AES_128_GCM_SHA256, + tls.TLS_AES_256_GCM_SHA384, + tls.TLS_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + }, + CompressionMethods: []uint8{ + tls.CompressionNone, + }, + Extensions: []tls.TLSExtension{ + &tls.UtlsGREASEExtension{}, + &tls.SNIExtension{}, + &tls.ExtendedMasterSecretExtension{}, + &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, + &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ + tls.CurveID(tls.GREASE_PLACEHOLDER), + tls.X25519, + tls.CurveP256, + tls.CurveP384, + tls.CurveP521, + }}, + &tls.SupportedPointsExtension{SupportedPoints: []byte{ + tls.PointFormatUncompressed, + }}, + &tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}, + &tls.StatusRequestExtension{}, + &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ + tls.ECDSAWithP256AndSHA256, + tls.PSSWithSHA256, + tls.PKCS1WithSHA256, + tls.ECDSAWithP384AndSHA384, + tls.ECDSAWithSHA1, + tls.PSSWithSHA384, + tls.PSSWithSHA384, + tls.PKCS1WithSHA384, + tls.PSSWithSHA512, + tls.PKCS1WithSHA512, + tls.PKCS1WithSHA1, + }}, + &tls.SCTExtension{}, + &tls.KeyShareExtension{KeyShares: []tls.KeyShare{ + {Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}}, + {Group: tls.X25519}, + }}, + &tls.PSKKeyExchangeModesExtension{Modes: []uint8{ + tls.PskModeDHE, + }}, + &tls.SupportedVersionsExtension{Versions: []uint16{ + tls.GREASE_PLACEHOLDER, + tls.VersionTLS13, + tls.VersionTLS12, + }}, + &tls.UtlsCompressCertExtension{Algorithms: []tls.CertCompressionAlgo{ + tls.CertCompressionZlib, + }}, + &tls.UtlsGREASEExtension{}, + &tls.UtlsPaddingExtension{GetPaddingLen: tls.BoringPaddingStyle}, + }, + }, nil + }, + }, + settings: map[http2.SettingID]uint32{ + http2.SettingHeaderTableSize: 4096, + http2.SettingMaxConcurrentStreams: 100, + http2.SettingInitialWindowSize: 2097152, + http2.SettingMaxFrameSize: 16384, + http2.SettingMaxHeaderListSize: math.MaxUint32, + }, + settingsOrder: []http2.SettingID{ + http2.SettingHeaderTableSize, + http2.SettingMaxConcurrentStreams, + http2.SettingInitialWindowSize, + http2.SettingMaxFrameSize, + http2.SettingMaxHeaderListSize, + }, + pseudoHeaderOrder: []string{ + ":method", + ":scheme", + ":path", + ":authority", + }, + connectionFlow: 15663105, +} + var NikeAndroidMobile = ClientProfile{ clientHelloId: tls.ClientHelloID{ Client: "NikeAndroidCustom", @@ -127,7 +329,7 @@ var NikeAndroidMobile = ClientProfile{ }, Extensions: []tls.TLSExtension{ &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, + &tls.ExtendedMasterSecretExtension{}, &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ tls.X25519, @@ -190,6 +392,288 @@ var NikeAndroidMobile = ClientProfile{ connectionFlow: 15663105, } +var CloudflareCustom = ClientProfile{ + clientHelloId: tls.ClientHelloID{ + Client: "CloudflareCustom", + Version: "1", + Seed: nil, + SpecFactory: func() (tls.ClientHelloSpec, error) { + return tls.ClientHelloSpec{ + CipherSuites: []uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + tls.FAKE_TLS_EMPTY_RENEGOTIATION_INFO_SCSV, + }, + CompressionMethods: []uint8{ + tls.CompressionNone, + }, + Extensions: []tls.TLSExtension{ + &tls.SNIExtension{}, + &tls.SupportedPointsExtension{SupportedPoints: []uint8{ + tls.PointFormatUncompressed, + 1, // ansiX962_compressed_prime + 2, // ansiX962_compressed_char2 + }}, + &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ + tls.CurveID(0x0017), + }}, + &tls.SessionTicketExtension{}, + // due to that we do not care about http2 frame settings + &tls.ALPNExtension{AlpnProtocols: []string{"http/1.1"}}, + &tls.GenericExtension{Id: 22}, // encrypt_then_mac + &tls.ExtendedMasterSecretExtension{}, + &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ + tls.ECDSAWithP256AndSHA256, + tls.ECDSAWithP384AndSHA384, + tls.ECDSAWithP521AndSHA512, + 0x0807, + 0x0808, + 0x0809, + 0x080a, + 0x080b, + tls.PSSWithSHA256, + tls.PSSWithSHA384, + tls.PSSWithSHA512, + tls.PKCS1WithSHA256, + tls.PKCS1WithSHA384, + tls.PKCS1WithSHA512, + 0x0303, + 0x0203, + 0x0301, + 0x0201, + 0x0302, + 0x0202, + 0x0402, + 0x0502, + 0x0602, + }}, + }, + }, nil + }, + }, + + //actually the h2 settings are not relevant, because this client does only support http1 + settings: map[http2.SettingID]uint32{ + http2.SettingHeaderTableSize: 4096, + http2.SettingMaxConcurrentStreams: math.MaxUint32, + http2.SettingInitialWindowSize: 16777216, + http2.SettingMaxFrameSize: 16384, + http2.SettingMaxHeaderListSize: math.MaxUint32, + }, + settingsOrder: []http2.SettingID{ + http2.SettingHeaderTableSize, + http2.SettingMaxConcurrentStreams, + http2.SettingInitialWindowSize, + http2.SettingMaxFrameSize, + http2.SettingMaxHeaderListSize, + }, + pseudoHeaderOrder: []string{ + ":method", + ":path", + ":authority", + ":scheme", + }, + connectionFlow: 15663105, +} + +var MMSIos = ClientProfile{ + clientHelloId: tls.ClientHelloID{ + Client: "MMSIos", + Version: "1", + Seed: nil, + SpecFactory: func() (tls.ClientHelloSpec, error) { + return tls.ClientHelloSpec{ + CipherSuites: []uint16{ + 0x1303, + 0x1301, + 0x1302, + 0xcca9, + 0xcca8, + 0xc02b, + 0xc02f, + 0xc02c, + 0xc030, + 0xc009, + 0xc013, + 0xc00a, + 0xc014, + 0x009c, + 0x009d, + 0x002f, + 0x0035, + 0x000a, + }, + CompressionMethods: []uint8{ + tls.CompressionNone, + }, + Extensions: []tls.TLSExtension{ + &tls.SNIExtension{}, + &tls.ExtendedMasterSecretExtension{}, + &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, + &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ + tls.CurveID(0x001d), + tls.CurveID(0x0017), + tls.CurveID(0x0018), + }}, + &tls.SupportedPointsExtension{SupportedPoints: []uint8{ + tls.PointFormatUncompressed, + }}, + &tls.SessionTicketExtension{}, + &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ + 0x0403, + 0x0804, + 0x0401, + 0x0503, + 0x0805, + 0x0501, + 0x0806, + 0x0601, + 0x0201, + }}, + &tls.KeyShareExtension{KeyShares: []tls.KeyShare{ + {Group: tls.X25519}, + }}, + &tls.PSKKeyExchangeModesExtension{Modes: []uint8{ + tls.PskModeDHE, + }}, + &tls.SupportedVersionsExtension{Versions: []uint16{ + tls.VersionTLS13, + tls.VersionTLS12, + }}, + }, + }, nil + }, + }, + settings: map[http2.SettingID]uint32{ + http2.SettingHeaderTableSize: 4096, + http2.SettingEnablePush: 1, + http2.SettingMaxConcurrentStreams: 100, + http2.SettingInitialWindowSize: 2097152, + http2.SettingMaxFrameSize: 16384, + http2.SettingMaxHeaderListSize: math.MaxUint32, + }, + settingsOrder: []http2.SettingID{ + http2.SettingHeaderTableSize, + http2.SettingEnablePush, + http2.SettingMaxConcurrentStreams, + http2.SettingInitialWindowSize, + http2.SettingMaxFrameSize, + http2.SettingMaxHeaderListSize, + }, + pseudoHeaderOrder: []string{ + ":method", + ":scheme", + ":path", + ":authority", + }, + connectionFlow: 15663105, +} + +var MeshIos = ClientProfile{ + clientHelloId: tls.ClientHelloID{ + Client: "MeshIos", + Version: "1", + Seed: nil, + SpecFactory: func() (tls.ClientHelloSpec, error) { + return tls.ClientHelloSpec{ + CipherSuites: []uint16{ + tls.GREASE_PLACEHOLDER, + 0x1301, + 0x1302, + 0x1303, + 0xc02c, + 0xc02b, + 0xcca9, + 0xc030, + 0xc02f, + 0xcca8, + 0xc00a, + 0xc009, + 0xc014, + 0xc013, + }, + CompressionMethods: []uint8{ + tls.CompressionNone, + }, + Extensions: []tls.TLSExtension{ + &tls.UtlsGREASEExtension{}, + &tls.SNIExtension{}, + &tls.ExtendedMasterSecretExtension{}, + &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, + &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ + tls.CurveID(tls.GREASE_PLACEHOLDER), + tls.CurveID(0x001d), + tls.CurveID(0x0017), + tls.CurveID(0x0018), + tls.CurveID(0x0019), + }}, + &tls.SupportedPointsExtension{SupportedPoints: []uint8{ + tls.PointFormatUncompressed, + }}, + &tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}, + &tls.StatusRequestExtension{}, + &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ + 0x0403, + 0x0804, + 0x0401, + 0x0503, + 0x0203, + 0x0805, + 0x0805, + 0x0501, + 0x0806, + 0x0601, + 0x0201, + }}, + &tls.SCTExtension{}, + &tls.KeyShareExtension{KeyShares: []tls.KeyShare{ + {Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}}, + {Group: tls.X25519}, + }}, + &tls.PSKKeyExchangeModesExtension{Modes: []uint8{ + tls.PskModeDHE, + }}, + &tls.SupportedVersionsExtension{Versions: []uint16{ + tls.GREASE_PLACEHOLDER, + tls.VersionTLS13, + tls.VersionTLS12, + }}, + &tls.UtlsCompressCertExtension{Algorithms: []tls.CertCompressionAlgo{ + tls.CertCompressionZlib, + }}, + &tls.UtlsGREASEExtension{}, + &tls.UtlsPaddingExtension{GetPaddingLen: tls.BoringPaddingStyle}, + }, + }, nil + }, + }, + settings: map[http2.SettingID]uint32{ + http2.SettingHeaderTableSize: 4096, + http2.SettingEnablePush: 1, + http2.SettingMaxConcurrentStreams: 100, + http2.SettingInitialWindowSize: 2097152, + http2.SettingMaxFrameSize: 16384, + http2.SettingMaxHeaderListSize: math.MaxUint32, + }, + settingsOrder: []http2.SettingID{ + http2.SettingHeaderTableSize, + http2.SettingEnablePush, + http2.SettingMaxConcurrentStreams, + http2.SettingInitialWindowSize, + http2.SettingMaxFrameSize, + http2.SettingMaxHeaderListSize, + }, + pseudoHeaderOrder: []string{ + ":method", + ":scheme", + ":path", + ":authority", + }, + connectionFlow: 15663105, +} + var MeshAndroid = ClientProfile{ clientHelloId: tls.ClientHelloID{ Client: "MeshAndroid", @@ -221,7 +705,7 @@ var MeshAndroid = ClientProfile{ Extensions: []tls.TLSExtension{ &tls.UtlsGREASEExtension{}, &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, + &tls.ExtendedMasterSecretExtension{}, &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ tls.CurveID(tls.GREASE_PLACEHOLDER), @@ -261,7 +745,7 @@ var MeshAndroid = ClientProfile{ &tls.UtlsCompressCertExtension{Algorithms: []tls.CertCompressionAlgo{ tls.CertCompressionBrotli, }}, - &tls.ALPSExtension{SupportedProtocols: []string{}}, + &tls.ApplicationSettingsExtension{SupportedProtocols: []string{}}, &tls.UtlsGREASEExtension{}, &tls.UtlsPaddingExtension{GetPaddingLen: tls.BoringPaddingStyle}, }, @@ -322,7 +806,7 @@ var MeshIos2 = ClientProfile{ Extensions: []tls.TLSExtension{ &tls.UtlsGREASEExtension{}, &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, + &tls.ExtendedMasterSecretExtension{}, &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ tls.CurveID(tls.GREASE_PLACEHOLDER), @@ -419,7 +903,7 @@ var MeshAndroid2 = ClientProfile{ Extensions: []tls.TLSExtension{ &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, + &tls.ExtendedMasterSecretExtension{}, &tls.SessionTicketExtension{}, &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ tls.ECDSAWithP256AndSHA256, @@ -468,6 +952,109 @@ var MeshAndroid2 = ClientProfile{ connectionFlow: 15663105, } +var ConfirmedIos = ClientProfile{ + clientHelloId: tls.ClientHelloID{ + Client: "ConfirmedIos", + Version: "1", + Seed: nil, + SpecFactory: func() (tls.ClientHelloSpec, error) { + return tls.ClientHelloSpec{ + CipherSuites: []uint16{ + tls.GREASE_PLACEHOLDER, + tls.TLS_AES_128_GCM_SHA256, + tls.TLS_AES_256_GCM_SHA384, + tls.TLS_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + }, + CompressionMethods: []uint8{ + tls.CompressionNone, + }, + Extensions: []tls.TLSExtension{ + &tls.UtlsGREASEExtension{}, + &tls.SNIExtension{}, + &tls.ExtendedMasterSecretExtension{}, + &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, + &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ + tls.CurveID(tls.GREASE_PLACEHOLDER), + tls.X25519, + tls.CurveP256, + tls.CurveP384, + tls.CurveP521, + }}, + &tls.SupportedPointsExtension{SupportedPoints: []uint8{ + tls.PointFormatUncompressed, + }}, + &tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}, + &tls.StatusRequestExtension{}, + &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ + tls.ECDSAWithP256AndSHA256, + tls.PSSWithSHA256, + tls.PKCS1WithSHA256, + tls.ECDSAWithP384AndSHA384, + tls.ECDSAWithSHA1, + tls.PSSWithSHA384, + tls.PSSWithSHA384, + tls.PKCS1WithSHA384, + tls.PSSWithSHA512, + tls.PKCS1WithSHA512, + tls.PKCS1WithSHA1, + }}, + &tls.SCTExtension{}, + &tls.KeyShareExtension{KeyShares: []tls.KeyShare{ + {Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}}, + {Group: tls.X25519}, + }}, + &tls.PSKKeyExchangeModesExtension{Modes: []uint8{ + tls.PskModeDHE, + }}, + &tls.SupportedVersionsExtension{Versions: []uint16{ + tls.GREASE_PLACEHOLDER, + tls.VersionTLS13, + tls.VersionTLS12, + }}, + &tls.UtlsCompressCertExtension{Algorithms: []tls.CertCompressionAlgo{ + tls.CertCompressionZlib, + }}, + &tls.UtlsGREASEExtension{}, + &tls.UtlsPaddingExtension{GetPaddingLen: tls.BoringPaddingStyle}, + }, + }, nil + }, + }, + settings: map[http2.SettingID]uint32{ + http2.SettingHeaderTableSize: 4096, + http2.SettingEnablePush: 1, + http2.SettingMaxConcurrentStreams: 100, + http2.SettingInitialWindowSize: 2097152, + http2.SettingMaxFrameSize: 16384, + http2.SettingMaxHeaderListSize: math.MaxUint32, + }, + settingsOrder: []http2.SettingID{ + http2.SettingHeaderTableSize, + http2.SettingEnablePush, + http2.SettingMaxConcurrentStreams, + http2.SettingInitialWindowSize, + http2.SettingMaxFrameSize, + http2.SettingMaxHeaderListSize, + }, + pseudoHeaderOrder: []string{ + ":method", + ":scheme", + ":path", + ":authority", + }, + connectionFlow: 15663105, +} + var ConfirmedAndroid = ClientProfile{ clientHelloId: tls.ClientHelloID{ Client: "ConfirmedAndroid", @@ -495,7 +1082,7 @@ var ConfirmedAndroid = ClientProfile{ Extensions: []tls.TLSExtension{ &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateNever}, &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, + &tls.ExtendedMasterSecretExtension{}, &tls.SessionTicketExtension{}, &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ tls.ECDSAWithP256AndSHA256, @@ -565,7 +1152,7 @@ var ConfirmedAndroid2 = ClientProfile{ Extensions: []tls.TLSExtension{ &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateNever}, &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, + &tls.ExtendedMasterSecretExtension{}, &tls.SessionTicketExtension{}, &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ tls.ECDSAWithP256AndSHA256, @@ -711,7 +1298,7 @@ var Okhttp4Android10 = ClientProfile{ }, Extensions: []tls.TLSExtension{ &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, + &tls.ExtendedMasterSecretExtension{}, &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateNever}, &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ tls.X25519, @@ -793,7 +1380,7 @@ var Okhttp4Android9 = ClientProfile{ Extensions: []tls.TLSExtension{ &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateNever}, &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, + &tls.ExtendedMasterSecretExtension{}, &tls.SessionTicketExtension{}, &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ tls.ECDSAWithP256AndSHA256, @@ -864,7 +1451,7 @@ var Okhttp4Android8 = ClientProfile{ Extensions: []tls.TLSExtension{ &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateNever}, &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, + &tls.ExtendedMasterSecretExtension{}, &tls.SessionTicketExtension{}, &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ tls.ECDSAWithP256AndSHA256, @@ -933,7 +1520,7 @@ var Okhttp4Android7 = ClientProfile{ Extensions: []tls.TLSExtension{ &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateNever}, &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, + &tls.ExtendedMasterSecretExtension{}, &tls.SessionTicketExtension{}, &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ tls.PKCS1WithSHA512, diff --git a/profiles/internal_browser_profiles.go b/profiles/internal_browser_profiles.go index d9b7b82..2f1a27e 100644 --- a/profiles/internal_browser_profiles.go +++ b/profiles/internal_browser_profiles.go @@ -56,15 +56,14 @@ var Chrome_117 = ClientProfile{ tls.VersionTLS13, tls.VersionTLS12, }}, - &tls.ALPSExtension{SupportedProtocols: []string{"h2"}}, + &tls.ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}}, &tls.SupportedCurvesExtension{[]tls.CurveID{ tls.CurveID(tls.GREASE_PLACEHOLDER), tls.X25519, tls.CurveP256, tls.CurveP384, }}, - &tls.UtlsExtendedMasterSecretExtension{}, - + &tls.ExtendedMasterSecretExtension{}, &tls.SessionTicketExtension{}, &tls.UtlsCompressCertExtension{[]tls.CertCompressionAlgo{ tls.CertCompressionBrotli, @@ -106,6 +105,107 @@ var Chrome_117 = ClientProfile{ connectionFlow: 15663105, } +var Chrome_120 = ClientProfile{ + clientHelloId: tls.ClientHelloID{ + Client: "Chrome", + RandomExtensionOrder: false, + Version: "120", + Seed: nil, + SpecFactory: func() (tls.ClientHelloSpec, error) { + return tls.ClientHelloSpec{ + CipherSuites: []uint16{ + tls.GREASE_PLACEHOLDER, + tls.TLS_AES_128_GCM_SHA256, + tls.TLS_AES_256_GCM_SHA384, + tls.TLS_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + tls.TLS_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_RSA_WITH_AES_128_CBC_SHA, + tls.TLS_RSA_WITH_AES_256_CBC_SHA, + }, + CompressionMethods: []uint8{ + tls.CompressionNone, + }, + Extensions: []tls.TLSExtension{ + &tls.UtlsGREASEExtension{}, + &tls.SNIExtension{}, + &tls.PSKKeyExchangeModesExtension{[]uint8{ + tls.PskModeDHE, + }}, + &tls.SupportedVersionsExtension{[]uint16{ + tls.GREASE_PLACEHOLDER, + tls.VersionTLS13, + tls.VersionTLS12, + }}, + &tls.StatusRequestExtension{}, + &tls.ExtendedMasterSecretExtension{}, + &tls.SessionTicketExtension{}, + &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ + tls.ECDSAWithP256AndSHA256, + tls.PSSWithSHA256, + tls.PKCS1WithSHA256, + tls.ECDSAWithP384AndSHA384, + tls.PSSWithSHA384, + tls.PKCS1WithSHA384, + tls.PSSWithSHA512, + tls.PKCS1WithSHA512, + }}, + &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, + &tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}, + tls.BoringGREASEECH(), + &tls.SCTExtension{}, + &tls.KeyShareExtension{[]tls.KeyShare{ + {Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}}, + {Group: tls.X25519}, + }}, + &tls.SupportedCurvesExtension{[]tls.CurveID{ + tls.GREASE_PLACEHOLDER, + tls.X25519, + tls.CurveP256, + tls.CurveP384, + }}, + &tls.SupportedPointsExtension{SupportedPoints: []byte{ + tls.PointFormatUncompressed, + }}, + &tls.ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}}, + &tls.UtlsCompressCertExtension{[]tls.CertCompressionAlgo{ + tls.CertCompressionBrotli, + }}, + &tls.UtlsGREASEExtension{}, + //&tls.UtlsPaddingExtension{GetPaddingLen: tls.BoringPaddingStyle}, + }, + }, nil + }, + }, + settings: map[http2.SettingID]uint32{ + http2.SettingHeaderTableSize: 65536, + http2.SettingEnablePush: 0, + http2.SettingInitialWindowSize: 6291456, + http2.SettingMaxHeaderListSize: 262144, + }, + settingsOrder: []http2.SettingID{ + http2.SettingHeaderTableSize, + http2.SettingEnablePush, + http2.SettingInitialWindowSize, + http2.SettingMaxHeaderListSize, + }, + pseudoHeaderOrder: []string{ + ":method", + ":authority", + ":scheme", + ":path", + }, + connectionFlow: 15663105, +} + var Chrome_112 = ClientProfile{ clientHelloId: tls.HelloChrome_112, settings: map[http2.SettingID]uint32{ @@ -131,6 +231,56 @@ var Chrome_112 = ClientProfile{ connectionFlow: 15663105, } +var Chrome_116_PSK = ClientProfile{ + clientHelloId: tls.HelloChrome_112_PSK, + settings: map[http2.SettingID]uint32{ + http2.SettingHeaderTableSize: 65536, + http2.SettingEnablePush: 0, + http2.SettingMaxConcurrentStreams: 1000, + http2.SettingInitialWindowSize: 6291456, + http2.SettingMaxHeaderListSize: 262144, + }, + settingsOrder: []http2.SettingID{ + http2.SettingHeaderTableSize, + http2.SettingEnablePush, + http2.SettingMaxConcurrentStreams, + http2.SettingInitialWindowSize, + http2.SettingMaxHeaderListSize, + }, + pseudoHeaderOrder: []string{ + ":method", + ":authority", + ":scheme", + ":path", + }, + connectionFlow: 15663105, +} + +var Chrome_116_PSK_PQ = ClientProfile{ + clientHelloId: tls.HelloChrome_115_PQ_PSK, + settings: map[http2.SettingID]uint32{ + http2.SettingHeaderTableSize: 65536, + http2.SettingEnablePush: 0, + http2.SettingMaxConcurrentStreams: 1000, + http2.SettingInitialWindowSize: 6291456, + http2.SettingMaxHeaderListSize: 262144, + }, + settingsOrder: []http2.SettingID{ + http2.SettingHeaderTableSize, + http2.SettingEnablePush, + http2.SettingMaxConcurrentStreams, + http2.SettingInitialWindowSize, + http2.SettingMaxHeaderListSize, + }, + pseudoHeaderOrder: []string{ + ":method", + ":authority", + ":scheme", + ":path", + }, + connectionFlow: 15663105, +} + var Chrome_111 = ClientProfile{ clientHelloId: tls.HelloChrome_111, settings: map[http2.SettingID]uint32{ @@ -496,7 +646,7 @@ var Firefox_117 = ClientProfile{ }, Extensions: []tls.TLSExtension{ &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, + &tls.ExtendedMasterSecretExtension{}, &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, &tls.SupportedCurvesExtension{[]tls.CurveID{ tls.X25519, @@ -514,7 +664,7 @@ var Firefox_117 = ClientProfile{ &tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}, &tls.StatusRequestExtension{}, &tls.DelegatedCredentialsExtension{ - AlgorithmsSignature: []tls.SignatureScheme{ + SupportedSignatureAlgorithms: []tls.SignatureScheme{ tls.ECDSAWithP256AndSHA256, tls.ECDSAWithP384AndSHA384, tls.ECDSAWithP521AndSHA512, diff --git a/profiles/internal_custom_profiles.go b/profiles/internal_custom_profiles.go index b261005..30fa8dd 100644 --- a/profiles/internal_custom_profiles.go +++ b/profiles/internal_custom_profiles.go @@ -1,594 +1 @@ package profiles - -import ( - "github.com/bogdanfinn/fhttp/http2" - tls "github.com/bogdanfinn/utls" - "math" -) - -var ZalandoIosMobile = ClientProfile{ - clientHelloId: tls.ClientHelloID{ - Client: "ZalandoIosCustom", - Version: "1", - Seed: nil, - SpecFactory: func() (tls.ClientHelloSpec, error) { - return tls.ClientHelloSpec{ - CipherSuites: []uint16{ - tls.GREASE_PLACEHOLDER, - tls.TLS_AES_128_GCM_SHA256, - tls.TLS_AES_256_GCM_SHA384, - tls.TLS_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - }, - CompressionMethods: []byte{ - tls.CompressionNone, - }, - Extensions: []tls.TLSExtension{ - &tls.UtlsGREASEExtension{}, - &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, - &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, - &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ - tls.CurveID(tls.GREASE_PLACEHOLDER), - tls.X25519, - tls.CurveP256, - tls.CurveP384, - tls.CurveP521, - }}, - &tls.SupportedPointsExtension{SupportedPoints: []byte{ - tls.PointFormatUncompressed, - }}, - &tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}, - &tls.StatusRequestExtension{}, - &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ - tls.ECDSAWithP256AndSHA256, - tls.PSSWithSHA256, - tls.PKCS1WithSHA256, - tls.ECDSAWithP384AndSHA384, - tls.ECDSAWithSHA1, - tls.PSSWithSHA384, - tls.PSSWithSHA384, - tls.PKCS1WithSHA384, - tls.PSSWithSHA512, - tls.PKCS1WithSHA512, - tls.PKCS1WithSHA1, - }}, - &tls.SCTExtension{}, - &tls.KeyShareExtension{KeyShares: []tls.KeyShare{ - {Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}}, - {Group: tls.X25519}, - }}, - &tls.PSKKeyExchangeModesExtension{Modes: []uint8{ - tls.PskModeDHE, - }}, - &tls.SupportedVersionsExtension{Versions: []uint16{ - tls.GREASE_PLACEHOLDER, - tls.VersionTLS13, - tls.VersionTLS12, - }}, - &tls.UtlsCompressCertExtension{Algorithms: []tls.CertCompressionAlgo{ - tls.CertCompressionZlib, - }}, - &tls.UtlsGREASEExtension{}, - &tls.UtlsPaddingExtension{GetPaddingLen: tls.BoringPaddingStyle}, - }, - }, nil - }, - }, - settings: map[http2.SettingID]uint32{ - http2.SettingHeaderTableSize: 4096, - http2.SettingMaxConcurrentStreams: 100, - http2.SettingInitialWindowSize: 2097152, - http2.SettingMaxFrameSize: 16384, - http2.SettingMaxHeaderListSize: math.MaxUint32, - }, - settingsOrder: []http2.SettingID{ - http2.SettingHeaderTableSize, - http2.SettingMaxConcurrentStreams, - http2.SettingInitialWindowSize, - http2.SettingMaxFrameSize, - http2.SettingMaxHeaderListSize, - }, - pseudoHeaderOrder: []string{ - ":method", - ":path", - ":authority", - ":scheme", - }, - connectionFlow: 15663105, -} - -var NikeIosMobile = ClientProfile{ - clientHelloId: tls.ClientHelloID{ - Client: "NikeIosCustom", - Version: "1", - Seed: nil, - SpecFactory: func() (tls.ClientHelloSpec, error) { - return tls.ClientHelloSpec{ - CipherSuites: []uint16{ - tls.GREASE_PLACEHOLDER, - tls.TLS_AES_128_GCM_SHA256, - tls.TLS_AES_256_GCM_SHA384, - tls.TLS_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - }, - CompressionMethods: []uint8{ - tls.CompressionNone, - }, - Extensions: []tls.TLSExtension{ - &tls.UtlsGREASEExtension{}, - &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, - &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, - &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ - tls.CurveID(tls.GREASE_PLACEHOLDER), - tls.X25519, - tls.CurveP256, - tls.CurveP384, - tls.CurveP521, - }}, - &tls.SupportedPointsExtension{SupportedPoints: []byte{ - tls.PointFormatUncompressed, - }}, - &tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}, - &tls.StatusRequestExtension{}, - &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ - tls.ECDSAWithP256AndSHA256, - tls.PSSWithSHA256, - tls.PKCS1WithSHA256, - tls.ECDSAWithP384AndSHA384, - tls.ECDSAWithSHA1, - tls.PSSWithSHA384, - tls.PSSWithSHA384, - tls.PKCS1WithSHA384, - tls.PSSWithSHA512, - tls.PKCS1WithSHA512, - tls.PKCS1WithSHA1, - }}, - &tls.SCTExtension{}, - &tls.KeyShareExtension{KeyShares: []tls.KeyShare{ - {Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}}, - {Group: tls.X25519}, - }}, - &tls.PSKKeyExchangeModesExtension{Modes: []uint8{ - tls.PskModeDHE, - }}, - &tls.SupportedVersionsExtension{Versions: []uint16{ - tls.GREASE_PLACEHOLDER, - tls.VersionTLS13, - tls.VersionTLS12, - }}, - &tls.UtlsCompressCertExtension{Algorithms: []tls.CertCompressionAlgo{ - tls.CertCompressionZlib, - }}, - &tls.UtlsGREASEExtension{}, - &tls.UtlsPaddingExtension{GetPaddingLen: tls.BoringPaddingStyle}, - }, - }, nil - }, - }, - settings: map[http2.SettingID]uint32{ - http2.SettingHeaderTableSize: 4096, - http2.SettingMaxConcurrentStreams: 100, - http2.SettingInitialWindowSize: 2097152, - http2.SettingMaxFrameSize: 16384, - http2.SettingMaxHeaderListSize: math.MaxUint32, - }, - settingsOrder: []http2.SettingID{ - http2.SettingHeaderTableSize, - http2.SettingMaxConcurrentStreams, - http2.SettingInitialWindowSize, - http2.SettingMaxFrameSize, - http2.SettingMaxHeaderListSize, - }, - pseudoHeaderOrder: []string{ - ":method", - ":scheme", - ":path", - ":authority", - }, - connectionFlow: 15663105, -} - -var CloudflareCustom = ClientProfile{ - clientHelloId: tls.ClientHelloID{ - Client: "CloudflareCustom", - Version: "1", - Seed: nil, - SpecFactory: func() (tls.ClientHelloSpec, error) { - return tls.ClientHelloSpec{ - CipherSuites: []uint16{ - tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - tls.FAKE_TLS_EMPTY_RENEGOTIATION_INFO_SCSV, - }, - CompressionMethods: []uint8{ - tls.CompressionNone, - }, - Extensions: []tls.TLSExtension{ - &tls.SNIExtension{}, - &tls.SupportedPointsExtension{SupportedPoints: []uint8{ - tls.PointFormatUncompressed, - 1, // ansiX962_compressed_prime - 2, // ansiX962_compressed_char2 - }}, - &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ - tls.CurveID(0x0017), - }}, - &tls.SessionTicketExtension{}, - // due to that we do not care about http2 frame settings - &tls.ALPNExtension{AlpnProtocols: []string{"http/1.1"}}, - &tls.GenericExtension{Id: 22}, // encrypt_then_mac - &tls.UtlsExtendedMasterSecretExtension{}, - &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ - tls.ECDSAWithP256AndSHA256, - tls.ECDSAWithP384AndSHA384, - tls.ECDSAWithP521AndSHA512, - 0x0807, - 0x0808, - 0x0809, - 0x080a, - 0x080b, - tls.PSSWithSHA256, - tls.PSSWithSHA384, - tls.PSSWithSHA512, - tls.PKCS1WithSHA256, - tls.PKCS1WithSHA384, - tls.PKCS1WithSHA512, - 0x0303, - 0x0203, - 0x0301, - 0x0201, - 0x0302, - 0x0202, - 0x0402, - 0x0502, - 0x0602, - }}, - }, - }, nil - }, - }, - - //actually the h2 settings are not relevant, because this client does only support http1 - settings: map[http2.SettingID]uint32{ - http2.SettingHeaderTableSize: 4096, - http2.SettingMaxConcurrentStreams: math.MaxUint32, - http2.SettingInitialWindowSize: 16777216, - http2.SettingMaxFrameSize: 16384, - http2.SettingMaxHeaderListSize: math.MaxUint32, - }, - settingsOrder: []http2.SettingID{ - http2.SettingHeaderTableSize, - http2.SettingMaxConcurrentStreams, - http2.SettingInitialWindowSize, - http2.SettingMaxFrameSize, - http2.SettingMaxHeaderListSize, - }, - pseudoHeaderOrder: []string{ - ":method", - ":path", - ":authority", - ":scheme", - }, - connectionFlow: 15663105, -} - -var MMSIos = ClientProfile{ - clientHelloId: tls.ClientHelloID{ - Client: "MMSIos", - Version: "1", - Seed: nil, - SpecFactory: func() (tls.ClientHelloSpec, error) { - return tls.ClientHelloSpec{ - CipherSuites: []uint16{ - 0x1303, - 0x1301, - 0x1302, - 0xcca9, - 0xcca8, - 0xc02b, - 0xc02f, - 0xc02c, - 0xc030, - 0xc009, - 0xc013, - 0xc00a, - 0xc014, - 0x009c, - 0x009d, - 0x002f, - 0x0035, - 0x000a, - }, - CompressionMethods: []uint8{ - tls.CompressionNone, - }, - Extensions: []tls.TLSExtension{ - &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, - &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, - &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ - tls.CurveID(0x001d), - tls.CurveID(0x0017), - tls.CurveID(0x0018), - }}, - &tls.SupportedPointsExtension{SupportedPoints: []uint8{ - tls.PointFormatUncompressed, - }}, - &tls.SessionTicketExtension{}, - &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ - 0x0403, - 0x0804, - 0x0401, - 0x0503, - 0x0805, - 0x0501, - 0x0806, - 0x0601, - 0x0201, - }}, - &tls.KeyShareExtension{KeyShares: []tls.KeyShare{ - {Group: tls.X25519}, - }}, - &tls.PSKKeyExchangeModesExtension{Modes: []uint8{ - tls.PskModeDHE, - }}, - &tls.SupportedVersionsExtension{Versions: []uint16{ - tls.VersionTLS13, - tls.VersionTLS12, - }}, - }, - }, nil - }, - }, - settings: map[http2.SettingID]uint32{ - http2.SettingHeaderTableSize: 4096, - http2.SettingEnablePush: 1, - http2.SettingMaxConcurrentStreams: 100, - http2.SettingInitialWindowSize: 2097152, - http2.SettingMaxFrameSize: 16384, - http2.SettingMaxHeaderListSize: math.MaxUint32, - }, - settingsOrder: []http2.SettingID{ - http2.SettingHeaderTableSize, - http2.SettingEnablePush, - http2.SettingMaxConcurrentStreams, - http2.SettingInitialWindowSize, - http2.SettingMaxFrameSize, - http2.SettingMaxHeaderListSize, - }, - pseudoHeaderOrder: []string{ - ":method", - ":scheme", - ":path", - ":authority", - }, - connectionFlow: 15663105, -} - -var MeshIos = ClientProfile{ - clientHelloId: tls.ClientHelloID{ - Client: "MeshIos", - Version: "1", - Seed: nil, - SpecFactory: func() (tls.ClientHelloSpec, error) { - return tls.ClientHelloSpec{ - CipherSuites: []uint16{ - tls.GREASE_PLACEHOLDER, - 0x1301, - 0x1302, - 0x1303, - 0xc02c, - 0xc02b, - 0xcca9, - 0xc030, - 0xc02f, - 0xcca8, - 0xc00a, - 0xc009, - 0xc014, - 0xc013, - }, - CompressionMethods: []uint8{ - tls.CompressionNone, - }, - Extensions: []tls.TLSExtension{ - &tls.UtlsGREASEExtension{}, - &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, - &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, - &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ - tls.CurveID(tls.GREASE_PLACEHOLDER), - tls.CurveID(0x001d), - tls.CurveID(0x0017), - tls.CurveID(0x0018), - tls.CurveID(0x0019), - }}, - &tls.SupportedPointsExtension{SupportedPoints: []uint8{ - tls.PointFormatUncompressed, - }}, - &tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}, - &tls.StatusRequestExtension{}, - &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ - 0x0403, - 0x0804, - 0x0401, - 0x0503, - 0x0203, - 0x0805, - 0x0805, - 0x0501, - 0x0806, - 0x0601, - 0x0201, - }}, - &tls.SCTExtension{}, - &tls.KeyShareExtension{KeyShares: []tls.KeyShare{ - {Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}}, - {Group: tls.X25519}, - }}, - &tls.PSKKeyExchangeModesExtension{Modes: []uint8{ - tls.PskModeDHE, - }}, - &tls.SupportedVersionsExtension{Versions: []uint16{ - tls.GREASE_PLACEHOLDER, - tls.VersionTLS13, - tls.VersionTLS12, - }}, - &tls.UtlsCompressCertExtension{Algorithms: []tls.CertCompressionAlgo{ - tls.CertCompressionZlib, - }}, - &tls.UtlsGREASEExtension{}, - &tls.UtlsPaddingExtension{GetPaddingLen: tls.BoringPaddingStyle}, - }, - }, nil - }, - }, - settings: map[http2.SettingID]uint32{ - http2.SettingHeaderTableSize: 4096, - http2.SettingEnablePush: 1, - http2.SettingMaxConcurrentStreams: 100, - http2.SettingInitialWindowSize: 2097152, - http2.SettingMaxFrameSize: 16384, - http2.SettingMaxHeaderListSize: math.MaxUint32, - }, - settingsOrder: []http2.SettingID{ - http2.SettingHeaderTableSize, - http2.SettingEnablePush, - http2.SettingMaxConcurrentStreams, - http2.SettingInitialWindowSize, - http2.SettingMaxFrameSize, - http2.SettingMaxHeaderListSize, - }, - pseudoHeaderOrder: []string{ - ":method", - ":scheme", - ":path", - ":authority", - }, - connectionFlow: 15663105, -} - -var ConfirmedIos = ClientProfile{ - clientHelloId: tls.ClientHelloID{ - Client: "ConfirmedIos", - Version: "1", - Seed: nil, - SpecFactory: func() (tls.ClientHelloSpec, error) { - return tls.ClientHelloSpec{ - CipherSuites: []uint16{ - tls.GREASE_PLACEHOLDER, - tls.TLS_AES_128_GCM_SHA256, - tls.TLS_AES_256_GCM_SHA384, - tls.TLS_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - }, - CompressionMethods: []uint8{ - tls.CompressionNone, - }, - Extensions: []tls.TLSExtension{ - &tls.UtlsGREASEExtension{}, - &tls.SNIExtension{}, - &tls.UtlsExtendedMasterSecretExtension{}, - &tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateOnceAsClient}, - &tls.SupportedCurvesExtension{Curves: []tls.CurveID{ - tls.CurveID(tls.GREASE_PLACEHOLDER), - tls.X25519, - tls.CurveP256, - tls.CurveP384, - tls.CurveP521, - }}, - &tls.SupportedPointsExtension{SupportedPoints: []uint8{ - tls.PointFormatUncompressed, - }}, - &tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}, - &tls.StatusRequestExtension{}, - &tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{ - tls.ECDSAWithP256AndSHA256, - tls.PSSWithSHA256, - tls.PKCS1WithSHA256, - tls.ECDSAWithP384AndSHA384, - tls.ECDSAWithSHA1, - tls.PSSWithSHA384, - tls.PSSWithSHA384, - tls.PKCS1WithSHA384, - tls.PSSWithSHA512, - tls.PKCS1WithSHA512, - tls.PKCS1WithSHA1, - }}, - &tls.SCTExtension{}, - &tls.KeyShareExtension{KeyShares: []tls.KeyShare{ - {Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}}, - {Group: tls.X25519}, - }}, - &tls.PSKKeyExchangeModesExtension{Modes: []uint8{ - tls.PskModeDHE, - }}, - &tls.SupportedVersionsExtension{Versions: []uint16{ - tls.GREASE_PLACEHOLDER, - tls.VersionTLS13, - tls.VersionTLS12, - }}, - &tls.UtlsCompressCertExtension{Algorithms: []tls.CertCompressionAlgo{ - tls.CertCompressionZlib, - }}, - &tls.UtlsGREASEExtension{}, - &tls.UtlsPaddingExtension{GetPaddingLen: tls.BoringPaddingStyle}, - }, - }, nil - }, - }, - settings: map[http2.SettingID]uint32{ - http2.SettingHeaderTableSize: 4096, - http2.SettingEnablePush: 1, - http2.SettingMaxConcurrentStreams: 100, - http2.SettingInitialWindowSize: 2097152, - http2.SettingMaxFrameSize: 16384, - http2.SettingMaxHeaderListSize: math.MaxUint32, - }, - settingsOrder: []http2.SettingID{ - http2.SettingHeaderTableSize, - http2.SettingEnablePush, - http2.SettingMaxConcurrentStreams, - http2.SettingInitialWindowSize, - http2.SettingMaxFrameSize, - http2.SettingMaxHeaderListSize, - }, - pseudoHeaderOrder: []string{ - ":method", - ":scheme", - ":path", - ":authority", - }, - connectionFlow: 15663105, -} diff --git a/profiles/profiles.go b/profiles/profiles.go index 3ff66f6..c437495 100644 --- a/profiles/profiles.go +++ b/profiles/profiles.go @@ -18,6 +18,8 @@ var MappedTLSClients = map[string]ClientProfile{ "chrome_110": Chrome_110, "chrome_111": Chrome_111, "chrome_112": Chrome_112, + "chrome_116_PSK": Chrome_116_PSK, + "chrome_116_PSK_PQ": Chrome_116_PSK_PQ, "chrome_117": Chrome_117, "safari_15_6_1": Safari_15_6_1, "safari_16_0": Safari_16_0, diff --git a/roundtripper.go b/roundtripper.go index 1934d5b..036f879 100644 --- a/roundtripper.go +++ b/roundtripper.go @@ -4,12 +4,13 @@ import ( "context" "errors" "fmt" - "github.com/bogdanfinn/tls-client/profiles" "net" "strings" "sync" "time" + "github.com/bogdanfinn/tls-client/profiles" + http "github.com/bogdanfinn/fhttp" "github.com/bogdanfinn/fhttp/http2" tls "github.com/bogdanfinn/utls" @@ -35,7 +36,8 @@ type roundTripper struct { forceHttp1 bool - headerPriority *http2.PriorityParam + headerPriority *http2.PriorityParam + clientSessionCache tls.ClientSessionCache insecureSkipVerify bool priorities []http2.Priority @@ -139,7 +141,7 @@ func (rt *roundTripper) dialTLS(ctx context.Context, network, addr string) (net. host = rt.serverNameOverwrite } - tlsConfig := &tls.Config{ServerName: host, InsecureSkipVerify: rt.insecureSkipVerify} + tlsConfig := &tls.Config{ClientSessionCache: rt.clientSessionCache, ServerName: host, InsecureSkipVerify: rt.insecureSkipVerify, OmitEmptyPsk: true} if rt.transportOptions != nil { tlsConfig.RootCAs = rt.transportOptions.RootCAs } @@ -166,7 +168,7 @@ func (rt *roundTripper) dialTLS(ctx context.Context, network, addr string) (net. switch conn.ConnectionState().NegotiatedProtocol { case http2.NextProtoTLS: - utlsConfig := &tls.Config{InsecureSkipVerify: rt.insecureSkipVerify} + utlsConfig := &tls.Config{ClientSessionCache: rt.clientSessionCache, InsecureSkipVerify: rt.insecureSkipVerify, OmitEmptyPsk: true} if rt.transportOptions != nil { utlsConfig.RootCAs = rt.transportOptions.RootCAs } @@ -260,7 +262,7 @@ func (rt *roundTripper) dial(ctx context.Context, network, addr string) (net.Con } func (rt *roundTripper) buildHttp1Transport() *http.Transport { - utlsConfig := &tls.Config{InsecureSkipVerify: rt.insecureSkipVerify} + utlsConfig := &tls.Config{ClientSessionCache: rt.clientSessionCache, InsecureSkipVerify: rt.insecureSkipVerify, OmitEmptyPsk: true} if rt.transportOptions != nil { utlsConfig.RootCAs = rt.transportOptions.RootCAs } @@ -310,11 +312,20 @@ func newRoundTripper(clientProfile profiles.ClientProfile, transportOptions *Tra return nil, fmt.Errorf("can not instantiate certificate pinner: %w", err) } + var clientSessionCache tls.ClientSessionCache + + withSessionResumption := supportsSessionResumption(clientProfile.GetClientHelloId()) + + if withSessionResumption { + clientSessionCache = tls.NewLRUClientSessionCache(32) + } + rt := &roundTripper{ dialer: dialer[0], certificatePinner: pinner, badPinHandlerFunc: badPinHandlerFunc, transportOptions: transportOptions, + clientSessionCache: clientSessionCache, serverNameOverwrite: serverNameOverwrite, settings: clientProfile.GetSettings(), settingsOrder: clientProfile.GetSettingsOrder(), @@ -339,3 +350,23 @@ func newRoundTripper(clientProfile profiles.ClientProfile, transportOptions *Tra return rt, nil } + +func supportsSessionResumption(id tls.ClientHelloID) bool { + spec, err := tls.UTLSIdToSpec(id) + + if err != nil { + spec, err = id.ToSpec() + + if err != nil { + return false + } + } + + for _, ext := range spec.Extensions { + if _, ok := ext.(*tls.UtlsPreSharedKeyExtension); ok { + return true + } + } + + return false +} diff --git a/shared/types.go b/shared/types.go deleted file mode 100644 index 9cb21d1..0000000 --- a/shared/types.go +++ /dev/null @@ -1,59 +0,0 @@ -package shared - -type TlsApiResponse struct { - IP string `json:"ip"` - HTTPVersion string `json:"http_version"` - Method string `json:"method"` - TLS struct { - Ciphers []string `json:"ciphers"` - Extensions []struct { - Name string `json:"name"` - ServerName string `json:"server_name,omitempty"` - Data string `json:"data,omitempty"` - SupportedGroups []string `json:"supported_groups,omitempty"` - EllipticCurvesPointFormats interface{} `json:"elliptic_curves_point_formats,omitempty"` - Protocols []string `json:"protocols,omitempty"` - StatusRequest struct { - CertificateStatusType string `json:"certificate_status_type"` - ResponderIDListLength int `json:"responder_id_list_length"` - RequestExtensionsLength int `json:"request_extensions_length"` - } `json:"status_request,omitempty"` - SignatureAlgorithms []string `json:"signature_algorithms,omitempty"` - SharedKeys []struct { - TLSGrease0X7A7A string `json:"TLS_GREASE (0x7a7a),omitempty"` - X2551929 string `json:"X25519 (29),omitempty"` - } `json:"shared_keys,omitempty"` - PskKeyExchangeMode string `json:"PSK_Key_Exchange_Mode,omitempty"` - Versions []string `json:"versions,omitempty"` - Algorithms []string `json:"algorithms,omitempty"` - PaddingDataLength int `json:"padding_data_length,omitempty"` - } `json:"extensions"` - TLSVersionRecord string `json:"tls_version_record"` - TLSVersionNegotiated string `json:"tls_version_negotiated"` - Ja3 string `json:"ja3"` - Ja3Hash string `json:"ja3_hash"` - ClientRandom string `json:"client_random"` - SessionID string `json:"session_id"` - } `json:"tls"` - HTTP2 struct { - AkamaiFingerprint string `json:"akamai_fingerprint"` - AkamaiFingerprintHash string `json:"akamai_fingerprint_hash"` - SentFrames []struct { - FrameType string `json:"frame_type"` - Length int `json:"length"` - Settings []string `json:"settings,omitempty"` - Increment int `json:"increment,omitempty"` - StreamID int `json:"stream_id,omitempty"` - Headers []string `json:"headers,omitempty"` - Flags []string `json:"flags,omitempty"` - Priority struct { - Weight int `json:"weight"` - DependsOn int `json:"depends_on"` - Exclusive int `json:"exclusive"` - } `json:"priority,omitempty"` - } `json:"sent_frames"` - } `json:"http2"` - HTTP1 struct { - Headers []string `json:"headers"` - } `json:"http1"` -} diff --git a/tests/client_test.go b/tests/client_test.go index 7ffa77e..adf7ad5 100644 --- a/tests/client_test.go +++ b/tests/client_test.go @@ -10,17 +10,21 @@ import ( http "github.com/bogdanfinn/fhttp" tls_client "github.com/bogdanfinn/tls-client" - "github.com/bogdanfinn/tls-client/shared" tls "github.com/bogdanfinn/utls" ) func TestClients(t *testing.T) { + t.Log("testing chrome 120") + chrome_120(t) + time.Sleep(2 * time.Second) t.Log("testing chrome 117") chrome_117(t) time.Sleep(2 * time.Second) t.Log("testing firefox 117") firefox_117(t) time.Sleep(2 * time.Second) + t.Log("testing chrome 116 with psk") + chrome116WithPsk(t) t.Log("testing chrome 112") chrome112(t) time.Sleep(2 * time.Second) @@ -115,6 +119,46 @@ var defaultOkHttp4Header = http.Header{ }, } +func chrome116WithPsk(t *testing.T) { + options := []tls_client.HttpClientOption{ + tls_client.WithClientProfile(profiles.Chrome_116_PSK), + tls_client.WithTimeoutSeconds(120), + } + + client, err := tls_client.NewHttpClient(nil, options...) + if err != nil { + t.Fatal(err) + } + + req, err := http.NewRequest(http.MethodGet, peetApiEndpoint, nil) + if err != nil { + t.Fatal(err) + } + + req.Header = defaultHeader + + resp, err := client.Do(req) + if err != nil { + t.Fatal(err) + } + + compareResponse(t, "chrome", clientFingerprints[chrome][tls.HelloChrome_112.Str()], resp) + + req, err = http.NewRequest(http.MethodGet, peetApiEndpoint, nil) + if err != nil { + t.Fatal(err) + } + + req.Header = defaultHeader + + resp, err = client.Do(req) + if err != nil { + t.Fatal(err) + } + + compareResponse(t, "chrome", clientFingerprints[chrome][tls.HelloChrome_112_PSK.Str()], resp) +} + func chrome112(t *testing.T) { options := []tls_client.HttpClientOption{ tls_client.WithClientProfile(profiles.Chrome_112), @@ -465,6 +509,31 @@ func firefox_108(t *testing.T) { compareResponse(t, "firefox", clientFingerprints[firefox][tls.HelloFirefox_108.Str()], resp) } +func chrome_120(t *testing.T) { + options := []tls_client.HttpClientOption{ + tls_client.WithClientProfile(profiles.Chrome_120), + } + + client, err := tls_client.NewHttpClient(nil, options...) + if err != nil { + t.Fatal(err) + } + + req, err := http.NewRequest(http.MethodGet, peetApiEndpoint, nil) + if err != nil { + t.Fatal(err) + } + + req.Header = defaultHeader + + resp, err := client.Do(req) + if err != nil { + t.Fatal(err) + } + + compareResponse(t, "chrome", clientFingerprints[chrome][profiles.Chrome_120.GetClientHelloStr()], resp) +} + func chrome_117(t *testing.T) { options := []tls_client.HttpClientOption{ tls_client.WithClientProfile(profiles.Chrome_117), @@ -573,7 +642,7 @@ func compareResponse(t *testing.T, clientName string, expectedValues map[string] t.Fatal(err) } - tlsApiResponse := shared.TlsApiResponse{} + tlsApiResponse := TlsApiResponse{} if err := json.Unmarshal(readBytes, &tlsApiResponse); err != nil { t.Fatal(err) } diff --git a/tests/client_test_utils.go b/tests/client_test_utils.go index bb4577e..05ae8a3 100644 --- a/tests/client_test_utils.go +++ b/tests/client_test_utils.go @@ -5,6 +5,64 @@ import ( tls "github.com/bogdanfinn/utls" ) +type TlsApiResponse struct { + IP string `json:"ip"` + HTTPVersion string `json:"http_version"` + Method string `json:"method"` + TLS struct { + Ciphers []string `json:"ciphers"` + Extensions []struct { + Name string `json:"name"` + ServerName string `json:"server_name,omitempty"` + Data string `json:"data,omitempty"` + SupportedGroups []string `json:"supported_groups,omitempty"` + EllipticCurvesPointFormats interface{} `json:"elliptic_curves_point_formats,omitempty"` + Protocols []string `json:"protocols,omitempty"` + StatusRequest struct { + CertificateStatusType string `json:"certificate_status_type"` + ResponderIDListLength int `json:"responder_id_list_length"` + RequestExtensionsLength int `json:"request_extensions_length"` + } `json:"status_request,omitempty"` + SignatureAlgorithms []string `json:"signature_algorithms,omitempty"` + SharedKeys []struct { + TLSGrease0X7A7A string `json:"TLS_GREASE (0x7a7a),omitempty"` + X2551929 string `json:"X25519 (29),omitempty"` + } `json:"shared_keys,omitempty"` + PskKeyExchangeMode string `json:"PSK_Key_Exchange_Mode,omitempty"` + Versions []string `json:"versions,omitempty"` + Algorithms []string `json:"algorithms,omitempty"` + PaddingDataLength int `json:"padding_data_length,omitempty"` + } `json:"extensions"` + TLSVersionRecord string `json:"tls_version_record"` + TLSVersionNegotiated string `json:"tls_version_negotiated"` + Ja3 string `json:"ja3"` + Ja3Hash string `json:"ja3_hash"` + ClientRandom string `json:"client_random"` + SessionID string `json:"session_id"` + } `json:"tls"` + HTTP2 struct { + AkamaiFingerprint string `json:"akamai_fingerprint"` + AkamaiFingerprintHash string `json:"akamai_fingerprint_hash"` + SentFrames []struct { + FrameType string `json:"frame_type"` + Length int `json:"length"` + Settings []string `json:"settings,omitempty"` + Increment int `json:"increment,omitempty"` + StreamID int `json:"stream_id,omitempty"` + Headers []string `json:"headers,omitempty"` + Flags []string `json:"flags,omitempty"` + Priority struct { + Weight int `json:"weight"` + DependsOn int `json:"depends_on"` + Exclusive int `json:"exclusive"` + } `json:"priority,omitempty"` + } `json:"sent_frames"` + } `json:"http2"` + HTTP1 struct { + Headers []string `json:"headers"` + } `json:"http1"` +} + const ( chrome = "chrome" firefox = "firefox" @@ -24,12 +82,24 @@ const ( var clientFingerprints = map[string]map[string]map[string]string{ chrome: { + profiles.Chrome_120.GetClientHelloStr(): map[string]string{ + ja3String: "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-45-43-5-23-35-13-65281-16-65037-18-51-10-11-17513-27,29-23-24,0", + ja3Hash: "1d9a054bac1eef41f30d370f9bbb2ad2", + akamaiFingerprint: "1:65536,2:0,4:6291456,6:262144|15663105|0|m,a,s,p", + akamaiFingerprintHash: "90224459f8bf70b7d0a8797eb916dbc9", + }, profiles.Chrome_117.GetClientHelloStr(): map[string]string{ ja3String: "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,45-0-16-13-43-17513-10-23-35-27-18-5-51-65281-11-21,29-23-24,0", ja3Hash: "1ddf8a0ebd957d10c1ab320b10450028", akamaiFingerprint: "1:65536,2:0,4:6291456,6:262144|15663105|0|m,a,s,p", akamaiFingerprintHash: "90224459f8bf70b7d0a8797eb916dbc9", }, + tls.HelloChrome_112_PSK.Str(): map[string]string{ + ja3String: "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,45-51-17513-43-0-11-5-23-16-10-65281-27-18-35-13-21-41,29-23-24,0", + ja3Hash: "11d372983aac706304b678a44351c8dd", + akamaiFingerprint: "1:65536,2:0,3:1000,4:6291456,6:262144|15663105|0|m,a,s,p", + akamaiFingerprintHash: "46cedabdca2073198a42fa10ca4494d0", + }, tls.HelloChrome_112.Str(): map[string]string{ ja3String: "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,45-51-17513-43-0-11-5-23-16-10-65281-27-18-35-13-21,29-23-24,0", ja3Hash: "7f052aeccc9b50e9b3a43a02780539b2", diff --git a/tests/cookie_jar_test.go b/tests/cookie_jar_test.go index 60b89fe..0fc194c 100644 --- a/tests/cookie_jar_test.go +++ b/tests/cookie_jar_test.go @@ -1,11 +1,12 @@ package tests import ( - "github.com/bogdanfinn/tls-client/profiles" "io" "net/url" "testing" + "github.com/bogdanfinn/tls-client/profiles" + http "github.com/bogdanfinn/fhttp" tls_client "github.com/bogdanfinn/tls-client" "github.com/stretchr/testify/assert" @@ -124,17 +125,17 @@ func TestClient_SkipExistingCookiesOnSetCookiesResponse(t *testing.T) { cookiesAfterFirstRequest := client.GetCookies(u) - assert.Equal(t, 1, len(cookiesAfterFirstRequest)) + assert.Equal(t, 2, len(cookiesAfterFirstRequest)) - cookie2 := &http.Cookie{ + cookie3 := &http.Cookie{ Name: cookiesAfterFirstRequest[0].Name, Value: cookiesAfterFirstRequest[0].Value, Domain: cookiesAfterFirstRequest[0].Domain, MaxAge: cookiesAfterFirstRequest[0].MaxAge, } - client.SetCookies(u, []*http.Cookie{cookie2}) + client.SetCookies(u, []*http.Cookie{cookie3}) - assert.Equal(t, 1, len(client.GetCookies(u))) + assert.Equal(t, 2, len(client.GetCookies(u))) req, err = http.NewRequest(http.MethodGet, "https://de.topps.com/", nil) if err != nil { @@ -168,7 +169,7 @@ func TestClient_SkipExistingCookiesOnSetCookiesResponse(t *testing.T) { cookiesAfterSecondRequest := client.GetCookies(u) - assert.Equal(t, 1, len(cookiesAfterSecondRequest)) + assert.Equal(t, 2, len(cookiesAfterSecondRequest)) } func TestClient_ExcludeExpiredCookiesFromRequest(t *testing.T) { diff --git a/tests/firefox_unsupported_group_test.go b/tests/firefox_unsupported_group_test.go new file mode 100644 index 0000000..1d20df5 --- /dev/null +++ b/tests/firefox_unsupported_group_test.go @@ -0,0 +1,32 @@ +package tests + +import ( + "strings" + "testing" + + http "github.com/bogdanfinn/fhttp" + tls_client "github.com/bogdanfinn/tls-client" + "github.com/bogdanfinn/tls-client/profiles" + "github.com/stretchr/testify/assert" +) + +func TestWeb(t *testing.T) { + options := []tls_client.HttpClientOption{ + tls_client.WithClientProfile(profiles.Firefox_110), + } + + client, err := tls_client.NewHttpClient(nil, options...) + if err != nil { + t.Fatal(err) + } + + req, err := http.NewRequest(http.MethodPost, "https://registrierung.web.de/account/email-registration", strings.NewReader("")) + if err != nil { + t.Fatal(err) + } + + req.Header = defaultHeader + + _, err = client.Do(req) + assert.NoError(t, err) +} diff --git a/tests/header_order_test.go b/tests/header_order_test.go index fb31f1f..d48de50 100644 --- a/tests/header_order_test.go +++ b/tests/header_order_test.go @@ -8,7 +8,6 @@ import ( http "github.com/bogdanfinn/fhttp" tls_client "github.com/bogdanfinn/tls-client" - "github.com/bogdanfinn/tls-client/shared" "github.com/stretchr/testify/assert" ) @@ -52,7 +51,7 @@ func TestClient_HeaderOrder(t *testing.T) { t.Fatal(err) } - tlsApiResponse := shared.TlsApiResponse{} + tlsApiResponse := TlsApiResponse{} if err := json.Unmarshal(readBytes, &tlsApiResponse); err != nil { t.Fatal(err) } @@ -87,7 +86,7 @@ func TestClient_HeaderOrder(t *testing.T) { t.Fatal(err) } - tlsApiResponse = shared.TlsApiResponse{} + tlsApiResponse = TlsApiResponse{} if err := json.Unmarshal(readBytes, &tlsApiResponse); err != nil { t.Fatal(err) } @@ -140,7 +139,7 @@ func TestClient_HeaderOrderHttp1(t *testing.T) { t.Fatal(err) } - tlsApiResponse := shared.TlsApiResponse{} + tlsApiResponse := TlsApiResponse{} if err := json.Unmarshal(readBytes, &tlsApiResponse); err != nil { t.Fatal(err) } @@ -175,7 +174,7 @@ func TestClient_HeaderOrderHttp1(t *testing.T) { t.Fatal(err) } - tlsApiResponse = shared.TlsApiResponse{} + tlsApiResponse = TlsApiResponse{} if err := json.Unmarshal(readBytes, &tlsApiResponse); err != nil { t.Fatal(err) } diff --git a/tests/ja3_test.go b/tests/ja3_test.go index 905e6b1..bf4fdfa 100644 --- a/tests/ja3_test.go +++ b/tests/ja3_test.go @@ -3,6 +3,7 @@ package tests import ( "testing" + "github.com/bogdanfinn/tls-client/profiles" utls "github.com/bogdanfinn/utls" "github.com/stretchr/testify/assert" @@ -10,6 +11,10 @@ import ( ) func TestJA3(t *testing.T) { + t.Log("testing ja3 chrome 120") + ja3_chrome_120(t) + t.Log("testing ja3 chrome 116 with psk") + ja3_chrome_112_with_psk(t) t.Log("testing ja3 chrome 105") ja3_chrome_105(t) t.Log("testing ja3 chrome 107") @@ -20,6 +25,63 @@ func TestJA3(t *testing.T) { ja3_opera_91(t) } +func ja3_chrome_120(t *testing.T) { + input := clientFingerprints[chrome][profiles.Chrome_120.GetClientHelloStr()][ja3String] + + ssa := []string{"PKCS1WithSHA256", "PKCS1WithSHA384", "PKCS1WithSHA512"} + dca := []string{"PKCS1WithSHA256", "PKCS1WithSHA384", "PKCS1WithSHA512"} + sv := []string{"1.3", "1.2"} + sc := []string{"GREASE", "X25519"} + ccs := []tls_client.CandidateCipherSuites{ + { + KdfId: "HKDF_SHA256", + AeadId: "AEAD_AES_128_GCM", + }, + { + KdfId: "HKDF_SHA256", + AeadId: "AEAD_CHACHA20_POLY1305", + }, + } + cp := []uint16{128, 160, 192, 224} + + specFunc, err := tls_client.GetSpecFactoryFromJa3String(input, ssa, dca, sv, sc, ccs, cp, "zlib") + + if err != nil { + t.Fatal(err) + } + + spec, err := specFunc() + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, len(spec.CipherSuites), 15, "Client should have 15 CipherSuites") + assert.Equal(t, len(spec.Extensions), 16, "Client should have 16 extensions") +} + +func ja3_chrome_112_with_psk(t *testing.T) { + input := clientFingerprints[chrome][utls.HelloChrome_112_PSK.Str()][ja3String] + + ssa := []string{"PKCS1WithSHA256", "PKCS1WithSHA384", "PKCS1WithSHA512"} + dca := []string{"PKCS1WithSHA256", "PKCS1WithSHA384", "PKCS1WithSHA512"} + sv := []string{"1.3", "1.2"} + sc := []string{"GREASE", "X25519"} + + specFunc, err := tls_client.GetSpecFactoryFromJa3String(input, ssa, dca, sv, sc, nil, nil, "brotli") + + if err != nil { + t.Fatal(err) + } + + spec, err := specFunc() + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, 15, len(spec.CipherSuites), "Client should have 15 CipherSuites") + assert.Equal(t, 17, len(spec.Extensions), "Client should have 17 extensions") +} + func ja3_chrome_105(t *testing.T) { input := clientFingerprints[chrome][utls.HelloChrome_105.Str()][ja3String] @@ -28,7 +90,7 @@ func ja3_chrome_105(t *testing.T) { sv := []string{"1.3", "1.2"} sc := []string{"GREASE", "X25519"} - specFunc, err := tls_client.GetSpecFactoryFromJa3String(input, ssa, dca, sv, sc, "zlib") + specFunc, err := tls_client.GetSpecFactoryFromJa3String(input, ssa, dca, sv, sc, nil, nil, "zlib") if err != nil { t.Fatal(err) @@ -51,7 +113,7 @@ func ja3_chrome_107(t *testing.T) { sv := []string{"1.3", "1.2"} sc := []string{"GREASE", "X25519"} - specFunc, err := tls_client.GetSpecFactoryFromJa3String(input, ssa, dca, sv, sc, "zlib") + specFunc, err := tls_client.GetSpecFactoryFromJa3String(input, ssa, dca, sv, sc, nil, nil, "zlib") if err != nil { t.Fatal(err) @@ -74,7 +136,7 @@ func ja3_firefox_105(t *testing.T) { sv := []string{"1.3", "1.2"} sc := []string{"GREASE", "X25519"} - specFunc, err := tls_client.GetSpecFactoryFromJa3String(input, ssa, dca, sv, sc, "zlib") + specFunc, err := tls_client.GetSpecFactoryFromJa3String(input, ssa, dca, sv, sc, nil, nil, "zlib") if err != nil { t.Fatal(err) @@ -97,7 +159,7 @@ func ja3_opera_91(t *testing.T) { sv := []string{"1.3", "1.2"} sc := []string{"GREASE", "X25519"} - specFunc, err := tls_client.GetSpecFactoryFromJa3String(input, ssa, dca, sv, sc, "zlib") + specFunc, err := tls_client.GetSpecFactoryFromJa3String(input, ssa, dca, sv, sc, nil, nil, "zlib") if err != nil { t.Fatal(err) diff --git a/tests/random_extension_order_test.go b/tests/random_extension_order_test.go index 39b92ad..7d044ad 100644 --- a/tests/random_extension_order_test.go +++ b/tests/random_extension_order_test.go @@ -10,7 +10,6 @@ import ( http "github.com/bogdanfinn/fhttp" tls_client "github.com/bogdanfinn/tls-client" - "github.com/bogdanfinn/tls-client/shared" "github.com/stretchr/testify/assert" ) @@ -42,7 +41,7 @@ func TestClient_RandomExtensionOrderChrome(t *testing.T) { t.Fatal(err) } - tlsApiResponse := shared.TlsApiResponse{} + tlsApiResponse := TlsApiResponse{} if err := json.Unmarshal(readBytes, &tlsApiResponse); err != nil { t.Fatal(err) } @@ -92,7 +91,7 @@ func TestClient_RandomExtensionOrderCustom(t *testing.T) { t.Fatal(err) } - tlsApiResponse := shared.TlsApiResponse{} + tlsApiResponse := TlsApiResponse{} if err := json.Unmarshal(readBytes, &tlsApiResponse); err != nil { t.Fatal(err) }