Help us shape the future of Go! Take the 2026 Go Developer Survey

tlsprofiles

package module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 22, 2026 License: MIT Imports: 3 Imported by: 0

README

TLS client profiles that reproduce the handshakes of iOS apps built with Akamai's Bot Manager Premier SDK. Akamai checks the handshake and the HTTP/2 settings before it reads the sensor, so a client that connects with one of these profiles is the other half of a Roolink BMP sensor.

The same seven profiles ship in two forms:

The profiles

iOS apps on Akamai's SDK connect with one of two handshake families, Standard and Secondary. The handshake also changes between iOS releases, so each family has variants keyed on the ios version in the Roolink sensor response.

ios in the response Standard Secondary
27 and later StandardIOS27 SecondaryIOS26_2
26.2 to 26.x StandardIOS26_2 SecondaryIOS26_2
26.0 and 26.1 StandardIOS26 SecondaryIOS26
Older StandardIOS SecondaryIOS

Start with Standard. If the app refuses the session although the sensor is fresh and the cookies are set, switch to Secondary. Note which one an app accepts.

Profile JA4 HTTP/2
StandardIOS27 t13d1313h2_f57a46bbacb6_7f0f34a4126d 2:0;4:2097152;3:100;9:1|10485760|0|m,s,p,a
StandardIOS26_2, StandardIOS26 t13d1313h2_f57a46bbacb6_7f0f34a4126d 2:0;4:2097152;3:100;9:1|10485760|0|m,s,p,a
SecondaryIOS26_2, SecondaryIOS26, SecondaryIOS t13d2013h2_a09f3c656075_7f0f34a4126d Secondary 26.x: as above. SecondaryIOS: 2:0;4:2097152;3:100|10485760|0|m,s,p,a
StandardIOS t13d1314h2_f57a46bbacb6_e42f34c56612 2:0;4:2097152;3:100|10485760|0|m,s,p,a

Standard and Secondary differ in cipher-suite order and count (Secondary adds the legacy TLS 1.2 suites), in the TLS versions offered, and in whether a padding extension is present. StandardIOS27 is StandardIOS26_2 with the TLS 1.3 suites reordered to TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_AES_128_GCM_SHA256, as captured from an iPhone 17 Pro on iOS 27.0, so it shares StandardIOS26_2's JA4 and differs in JA3; no separate iOS 27 Secondary handshake has been captured, so Secondary apps stay on SecondaryIOS26_2. The 26.x and 27 variants add the X25519MLKEM768 key share and the NO_RFC7540_PRIORITIES HTTP/2 setting that older iOS releases do not send.

Go

import (
	tls_client "github.com/bogdanfinn/tls-client"
	"github.com/roolinkio/tlsprofiles"
)

client, err := tls_client.NewHttpClient(tls_client.NewNoopLogger(),
	tls_client.WithClientProfile(tlsprofiles.StandardIOS26_2),
	tls_client.WithCookieJar(tls_client.NewCookieJar()),
	tls_client.WithProxyUrl(proxyURL),
	tls_client.WithDisableHttp3(),
)

Built against tls-client v1.16.0 and utls v1.7.8-barnius. Keep the same profile for the life of a session; switching mid-session ends it.

Python and Node

Each entry of profiles.json is one profile with the keys the shared library's customTlsClient payload takes:

Key What it holds
ja3String Cipher suites, extensions in order, curves and point formats. GREASE placeholders are 2570.
supportedSignatureAlgorithms, supportedVersions, keyShareCurves, certCompressionAlgos, alpnProtocols The extension contents the JA3 string cannot carry.
h2Settings, h2SettingsOrder, pseudoHeaderOrder, connectionFlow The HTTP/2 SETTINGS frame, its order, the pseudo-header order and the connection window. UNKNOWN_SETTING_9 is NO_RFC7540_PRIORITIES.

Node passes an entry straight through as customTlsClient, with withRandomTLSExtensionOrder: false and disableHttp3: true. Python needs a small Session subclass because the wrapper's custom-client payload predates the current shared library; the Roolink docs show it in full.

The JSON profiles mirror the Go module: identical JA3, JA4 and HTTP/2 fingerprints from Go, Node and Python. StandardIOS27 has so far been checked from Go only, against a real iOS 27.0 capture.

Verifying a client

Request https://tls.peet.ws/api/all through the client and compare tls.ja4 and http2.akamai_fingerprint with the table above. A mismatch means the profile did not apply, usually because extension randomization is on or HTTP/3 is enabled.

Documentation: https://docs.roolink.io

Documentation

Overview

Package tlsprofiles holds the TLS client profiles that reproduce the handshakes of iOS apps built with Akamai's Bot Manager Premier SDK, for use with github.com/bogdanfinn/tls-client. Two handshake families exist, Standard and Secondary, in variants keyed on the iOS version reported by the Roolink sensor response. profiles.json carries the same profiles as custom-client definitions for the Python and Node wrappers.

Index

Constants

This section is empty.

Variables

View Source
var (
	// StandardIOS27 is the Standard handshake for iOS 27: StandardIOS26_2 with TLS_AES_128_GCM_SHA256 offered last of the TLS 1.3 suites.
	// JA4 t13d1213h2_d893ac74c21d_7f0f34a4126d.
	StandardIOS27 = profiles.NewClientProfile(
		tls.ClientHelloID{
			Client:               "StandardIOS",
			RandomExtensionOrder: false,
			Version:              "1.0.0",
			Seed:                 nil,
			SpecFactory: func() (tls.ClientHelloSpec, error) {
				clientHello := tls.ClientHelloSpec{
					CipherSuites: []uint16{
						tls.GREASE_PLACEHOLDER,
						0x1302,
						0x1303,
						0x1301,
						0xc02c,
						0xc030,
						0xc02b,
						0xcca9,
						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),
							0x11ec,
							0x001d,
							0x0017,
							0x0018,
							0x0019,
						}},
						&tls.SupportedPointsExtension{SupportedPoints: []byte{
							tls.PointFormatUncompressed,
						}},
						&tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
						&tls.StatusRequestExtension{},
						&tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{
							0x0403,
							0x0804,
							0x0401,
							0x0503,
							0x0805,
							0x0805,
							0x0501,
							0x0806,
							0x0601,
							0x0201,
						}},
						&tls.SCTExtension{},
						&tls.KeyShareExtension{KeyShares: []tls.KeyShare{
							{Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}},
							{Group: tls.X25519MLKEM768},
							{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},
					},
				}
				return clientHello, nil
			},
			Weights: &tls.Weights{},
		},
		map[http2.SettingID]uint32{
			http2.SettingEnablePush:           0,
			http2.SettingMaxConcurrentStreams: 100,
			http2.SettingInitialWindowSize:    2097152,
			9:                                 1,
		},
		[]http2.SettingID{
			http2.SettingEnablePush,
			http2.SettingInitialWindowSize,
			http2.SettingMaxConcurrentStreams,
			9,
		},
		[]string{
			":method",
			":scheme",
			":path",
			":authority",
		},
		uint32(10485760),
		[]http2.Priority{},
		&http2.PriorityParam{},
		0, false, nil, nil, 0, nil, false,
	)
	// StandardIOS26_2 is the Standard handshake for iOS 26.2 and later: the first profile to try.
	// JA4 t13d1313h2_f57a46bbacb6_7f0f34a4126d.
	StandardIOS26_2 = profiles.NewClientProfile(
		tls.ClientHelloID{
			Client:               "StandardIOS",
			RandomExtensionOrder: false,
			Version:              "1.0.0",
			Seed:                 nil,
			SpecFactory: func() (tls.ClientHelloSpec, error) {
				clientHello := tls.ClientHelloSpec{
					CipherSuites: []uint16{
						tls.GREASE_PLACEHOLDER,
						0x1302,
						0x1301,
						0x1303,
						0xc02c,
						0xc030,
						0xc02b,
						0xcca9,
						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),
							0x11ec,
							0x001d,
							0x0017,
							0x0018,
							0x0019,
						}},
						&tls.SupportedPointsExtension{SupportedPoints: []byte{
							tls.PointFormatUncompressed,
						}},
						&tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
						&tls.StatusRequestExtension{},
						&tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{
							0x0403,
							0x0804,
							0x0401,
							0x0503,
							0x0805,
							0x0805,
							0x0501,
							0x0806,
							0x0601,
							0x0201,
						}},
						&tls.SCTExtension{},
						&tls.KeyShareExtension{KeyShares: []tls.KeyShare{
							{Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}},
							{Group: tls.X25519MLKEM768},
							{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},
					},
				}
				return clientHello, nil
			},
			Weights: &tls.Weights{},
		},
		map[http2.SettingID]uint32{
			http2.SettingEnablePush:           0,
			http2.SettingMaxConcurrentStreams: 100,
			http2.SettingInitialWindowSize:    2097152,
			9:                                 1,
		},
		[]http2.SettingID{
			http2.SettingEnablePush,
			http2.SettingInitialWindowSize,
			http2.SettingMaxConcurrentStreams,
			9,
		},
		[]string{
			":method",
			":scheme",
			":path",
			":authority",
		},
		uint32(10485760),
		[]http2.Priority{},
		&http2.PriorityParam{},
		0, false, nil, nil, 0, nil, false,
	)
	// SecondaryIOS26_2 is the Secondary handshake for iOS 26.2 and later: the fallback when Standard is refused.
	// JA4 t13d2013h2_a09f3c656075_7f0f34a4126d.
	SecondaryIOS26_2 = profiles.NewClientProfile(
		tls.ClientHelloID{
			Client:               "SecondaryIOS",
			RandomExtensionOrder: false,
			Version:              "1.0.0",
			Seed:                 nil,
			SpecFactory: func() (tls.ClientHelloSpec, error) {
				return tls.ClientHelloSpec{
					CipherSuites: []uint16{
						tls.GREASE_PLACEHOLDER,
						tls.TLS_AES_256_GCM_SHA384,
						tls.TLS_CHACHA20_POLY1305_SHA256,
						tls.TLS_AES_128_GCM_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,
						tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
						tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
						tls.TLS_RSA_WITH_AES_256_CBC_SHA,
						tls.TLS_RSA_WITH_AES_128_CBC_SHA,
						tls.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
						tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
						tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
					},
					CompressionMethods: []uint8{
						tls.CompressionNone,
					},
					Extensions: []tls.TLSExtension{
						&tls.UtlsGREASEExtension{},
						&tls.SNIExtension{},
						&tls.ExtendedMasterSecretExtension{},
						&tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateNever},
						&tls.SupportedCurvesExtension{Curves: []tls.CurveID{
							tls.CurveID(tls.GREASE_PLACEHOLDER),
							tls.X25519MLKEM768,
							tls.X25519,
							tls.CurveP256,
							tls.CurveP384,
							tls.CurveP521,
						}},
						&tls.SupportedPointsExtension{SupportedPoints: []byte{0x00}},
						&tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
						&tls.StatusRequestExtension{},
						&tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{
							tls.ECDSAWithP256AndSHA256,
							tls.PSSWithSHA256,
							tls.PKCS1WithSHA256,
							tls.ECDSAWithP384AndSHA384,
							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.X25519MLKEM768},
							{Group: tls.X25519},
						}},
						&tls.PSKKeyExchangeModesExtension{Modes: []uint8{
							tls.PskModeDHE,
						}},
						&tls.SupportedVersionsExtension{Versions: []uint16{
							tls.GREASE_PLACEHOLDER,
							tls.VersionTLS13,
							tls.VersionTLS12,
							tls.VersionTLS11,
							tls.VersionTLS10,
						}},
						&tls.UtlsCompressCertExtension{Algorithms: []tls.CertCompressionAlgo{
							tls.CertCompressionZlib,
						}},
						&tls.UtlsGREASEExtension{},
					},
				}, nil
			},
		},
		map[http2.SettingID]uint32{
			http2.SettingEnablePush:           0,
			http2.SettingInitialWindowSize:    2097152,
			http2.SettingMaxConcurrentStreams: 100,
			9:                                 1,
		},
		[]http2.SettingID{
			http2.SettingEnablePush,
			http2.SettingInitialWindowSize,
			http2.SettingMaxConcurrentStreams,
			9,
		},
		[]string{
			":method",
			":scheme",
			":path",
			":authority",
		},
		uint32(10485760),
		[]http2.Priority{},
		&http2.PriorityParam{},
		0, false, nil, nil, 0, nil, false,
	)
	// StandardIOS26 is the Standard handshake for iOS 26.0 and 26.1: the first profile to try.
	// JA4 t13d1313h2_f57a46bbacb6_7f0f34a4126d.
	StandardIOS26 = profiles.NewClientProfile(
		tls.ClientHelloID{
			Client:               "StandardIOS",
			RandomExtensionOrder: false,
			Version:              "1.0.0",
			Seed:                 nil,
			SpecFactory: func() (tls.ClientHelloSpec, error) {
				clientHello := tls.ClientHelloSpec{
					CipherSuites: []uint16{
						tls.GREASE_PLACEHOLDER,
						0x1302,
						0x1303,
						0x1301,
						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),
							0x11ec,
							0x001d,
							0x0017,
							0x0018,
							0x0019,
						}},
						&tls.SupportedPointsExtension{SupportedPoints: []byte{
							tls.PointFormatUncompressed,
						}},
						&tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
						&tls.StatusRequestExtension{},
						&tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{
							0x0403,
							0x0804,
							0x0401,
							0x0503,
							0x0805,
							0x0805,
							0x0501,
							0x0806,
							0x0601,
							0x0201,
						}},
						&tls.SCTExtension{},
						&tls.KeyShareExtension{KeyShares: []tls.KeyShare{
							{Group: tls.CurveID(tls.GREASE_PLACEHOLDER), Data: []byte{0}},
							{Group: tls.X25519MLKEM768},
							{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},
					},
				}
				return clientHello, nil
			},
			Weights: &tls.Weights{},
		},
		map[http2.SettingID]uint32{
			http2.SettingEnablePush:           0,
			http2.SettingMaxConcurrentStreams: 100,
			http2.SettingInitialWindowSize:    2097152,
			9:                                 1,
		},
		[]http2.SettingID{
			http2.SettingEnablePush,
			http2.SettingInitialWindowSize,
			http2.SettingMaxConcurrentStreams,
			9,
		},
		[]string{
			":method",
			":scheme",
			":path",
			":authority",
		},
		uint32(10485760),
		[]http2.Priority{},
		&http2.PriorityParam{},
		0, false, nil, nil, 0, nil, false,
	)
	// SecondaryIOS26 is the Secondary handshake for iOS 26.0 and 26.1: the fallback when Standard is refused.
	// JA4 t13d2013h2_a09f3c656075_7f0f34a4126d.
	SecondaryIOS26 = profiles.NewClientProfile(
		tls.ClientHelloID{
			Client:               "SecondaryIOS",
			RandomExtensionOrder: false,
			Version:              "1.0.0",
			Seed:                 nil,
			SpecFactory: func() (tls.ClientHelloSpec, error) {
				return tls.ClientHelloSpec{
					CipherSuites: []uint16{
						tls.GREASE_PLACEHOLDER,
						tls.TLS_AES_256_GCM_SHA384,
						tls.TLS_CHACHA20_POLY1305_SHA256,
						tls.TLS_AES_128_GCM_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,
						tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
						tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
						tls.TLS_RSA_WITH_AES_256_CBC_SHA,
						tls.TLS_RSA_WITH_AES_128_CBC_SHA,
						tls.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
						tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
						tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
					},
					CompressionMethods: []uint8{
						tls.CompressionNone,
					},
					Extensions: []tls.TLSExtension{
						&tls.UtlsGREASEExtension{},
						&tls.SNIExtension{},
						&tls.ExtendedMasterSecretExtension{},
						&tls.RenegotiationInfoExtension{Renegotiation: tls.RenegotiateNever},
						&tls.SupportedCurvesExtension{Curves: []tls.CurveID{
							tls.CurveID(tls.GREASE_PLACEHOLDER),
							tls.X25519MLKEM768,
							tls.X25519,
							tls.CurveP256,
							tls.CurveP384,
							tls.CurveP521,
						}},
						&tls.SupportedPointsExtension{SupportedPoints: []byte{0x00}},
						&tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
						&tls.StatusRequestExtension{},
						&tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{
							tls.ECDSAWithP256AndSHA256,
							tls.PSSWithSHA256,
							tls.PKCS1WithSHA256,
							tls.ECDSAWithP384AndSHA384,
							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.X25519MLKEM768},
							{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{},
					},
				}, nil
			},
		},
		map[http2.SettingID]uint32{
			http2.SettingEnablePush:           0,
			http2.SettingInitialWindowSize:    2097152,
			http2.SettingMaxConcurrentStreams: 100,
			9:                                 1,
		},
		[]http2.SettingID{
			http2.SettingEnablePush,
			http2.SettingInitialWindowSize,
			http2.SettingMaxConcurrentStreams,
			9,
		},
		[]string{
			":method",
			":scheme",
			":path",
			":authority",
		},
		uint32(10485760),
		[]http2.Priority{},
		&http2.PriorityParam{},
		0, false, nil, nil, 0, nil, false,
	)
	// StandardIOS is the Standard handshake for iOS releases before 26: the first profile to try.
	// JA4 t13d1314h2_f57a46bbacb6_e42f34c56612.
	StandardIOS = profiles.NewClientProfile(
		tls.ClientHelloID{
			Client:               "StandardIOS",
			RandomExtensionOrder: false,
			Version:              "1.0.0",
			Seed:                 nil,
			SpecFactory: func() (tls.ClientHelloSpec, error) {
				clientHello := 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.RenegotiateNever},
						&tls.SupportedCurvesExtension{Curves: []tls.CurveID{
							tls.CurveID(tls.GREASE_PLACEHOLDER),
							tls.X25519,
							tls.CurveP256,
							tls.CurveP384,
							tls.CurveP521,
						}},
						&tls.SupportedPointsExtension{SupportedPoints: []byte{0}},
						&tls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
						&tls.StatusRequestExtension{},
						&tls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []tls.SignatureScheme{
							tls.ECDSAWithP256AndSHA256,
							tls.PSSWithSHA256,
							tls.PKCS1WithSHA256,
							tls.ECDSAWithP384AndSHA384,
							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},
					},
				}
				return clientHello, nil
			},
			Weights: &tls.Weights{},
		},
		map[http2.SettingID]uint32{
			http2.SettingEnablePush:           0,
			http2.SettingInitialWindowSize:    2097152,
			http2.SettingMaxConcurrentStreams: 100,
		},
		[]http2.SettingID{
			http2.SettingEnablePush,
			http2.SettingInitialWindowSize,
			http2.SettingMaxConcurrentStreams,
		},
		[]string{
			":method",
			":scheme",
			":path",
			":authority",
		},
		uint32(10485760),
		[]http2.Priority{},
		&http2.PriorityParam{},
		0, false, nil, nil, 0, nil, false,
	)
	// SecondaryIOS is the Secondary handshake for iOS releases before 26: the fallback when Standard is refused.
	// JA4 t13d2013h2_a09f3c656075_7f0f34a4126d.
	SecondaryIOS = profiles.NewClientProfile(
		tls.ClientHelloID{
			Client:               "SecondaryIOS",
			RandomExtensionOrder: false,
			Version:              "1.0.0",
			Seed:                 nil,
			SpecFactory: func() (tls.ClientHelloSpec, error) {
				clientHello := tls.ClientHelloSpec{
					CipherSuites: []uint16{
						tls.GREASE_PLACEHOLDER,
						0x1301,
						0x1302,
						0x1303,
						0xc02c,
						0xc02b,
						0xcca9,
						0xc030,
						0xc02f,
						0xcca8,
						0xc00a,
						0xc009,
						0xc014,
						0xc013,
						0x9d,
						0x9c,
						0x35,
						0x2f,
						0xc008,
						0xc012,
						0xa,
					},
					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.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.VersionTLS11,
							tls.VersionTLS10,
						}},
						&tls.UtlsCompressCertExtension{Algorithms: []tls.CertCompressionAlgo{
							tls.CertCompressionZlib,
						}},
						&tls.UtlsGREASEExtension{},
					},
				}
				return clientHello, nil
			},
		},
		map[http2.SettingID]uint32{
			http2.SettingEnablePush:           0,
			http2.SettingInitialWindowSize:    2097152,
			http2.SettingMaxConcurrentStreams: 100,
		},
		[]http2.SettingID{
			http2.SettingEnablePush,
			http2.SettingInitialWindowSize,
			http2.SettingMaxConcurrentStreams,
		},
		[]string{
			":method",
			":scheme",
			":path",
			":authority",
		},
		uint32(10485760),
		[]http2.Priority{},
		&http2.PriorityParam{},
		0, false, nil, nil, 0, nil, false,
	)
)

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL