| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801 |
- // Copyright 2017 Google Inc. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package tls
- import (
- "crypto/hmac"
- "crypto/sha512"
- "encoding/json"
- "errors"
- "fmt"
- "hash"
- "log"
- "github.com/Psiphon-Labs/utls/internal/helper"
- "golang.org/x/crypto/cryptobyte"
- )
- // Naming convention:
- // Unsupported things are prefixed with "Fake"
- // Things, supported by utls, but not crypto/tls' are prefixed with "utls"
- // Supported things, that have changed their ID are prefixed with "Old"
- // Supported but disabled things are prefixed with "Disabled". We will _enable_ them.
- // TLS handshake message types.
- const (
- utlsTypeEncryptedExtensions uint8 = 8 // implemention incomplete by crypto/tls
- // https://datatracker.ietf.org/doc/html/rfc8879#section-7.2
- utlsTypeCompressedCertificate uint8 = 25
- )
- // TLS
- const (
- extensionNextProtoNeg uint16 = 13172 // not IANA assigned. Removed by crypto/tls since Nov 2019
- utlsExtensionPadding uint16 = 21
- utlsExtensionCompressCertificate uint16 = 27 // https://datatracker.ietf.org/doc/html/rfc8879#section-7.1
- utlsExtensionApplicationSettings uint16 = 17513 // not IANA assigned
- utlsFakeExtensionCustom uint16 = 1234 // not IANA assigned, for ALPS
- utlsExtensionECH uint16 = 0xfe0d // draft-ietf-tls-esni-17
- utlsExtensionECHOuterExtensions uint16 = 0xfd00 // draft-ietf-tls-esni-17
- // extensions with 'fake' prefix break connection, if server echoes them back
- fakeExtensionEncryptThenMAC uint16 = 22
- fakeExtensionTokenBinding uint16 = 24
- fakeExtensionDelegatedCredentials uint16 = 34
- fakeExtensionPreSharedKey uint16 = 41
- fakeOldExtensionChannelID uint16 = 30031 // not IANA assigned
- fakeExtensionChannelID uint16 = 30032 // not IANA assigned
- )
- const (
- OLD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = uint16(0xcc13)
- OLD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = uint16(0xcc14)
- DISABLED_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = uint16(0xc024)
- DISABLED_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = uint16(0xc028)
- DISABLED_TLS_RSA_WITH_AES_256_CBC_SHA256 = uint16(0x003d)
- FAKE_OLD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = uint16(0xcc15) // we can try to craft these ciphersuites
- FAKE_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = uint16(0x009e) // from existing pieces, if needed
- FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA = uint16(0x0033)
- FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA = uint16(0x0039)
- FAKE_TLS_RSA_WITH_RC4_128_MD5 = uint16(0x0004)
- FAKE_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = uint16(0x009f)
- FAKE_TLS_DHE_DSS_WITH_AES_128_CBC_SHA = uint16(0x0032)
- FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = uint16(0x006b)
- FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = uint16(0x0067)
- FAKE_TLS_EMPTY_RENEGOTIATION_INFO_SCSV = uint16(0x00ff)
- // https://docs.microsoft.com/en-us/dotnet/api/system.net.security.tlsciphersuite?view=netcore-3.1
- FAKE_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = uint16(0xc008)
- )
- const (
- CurveSECP256R1 CurveID = 0x0017
- CurveSECP384R1 CurveID = 0x0018
- CurveSECP521R1 CurveID = 0x0019
- CurveX25519 CurveID = 0x001d
- FakeCurveFFDHE2048 CurveID = 0x0100
- FakeCurveFFDHE3072 CurveID = 0x0101
- FakeCurveFFDHE4096 CurveID = 0x0102
- FakeCurveFFDHE6144 CurveID = 0x0103
- FakeCurveFFDHE8192 CurveID = 0x0104
- )
- // Other things
- const (
- fakeRecordSizeLimit uint16 = 0x001c
- )
- // newest signatures
- var (
- FakePKCS1WithSHA224 SignatureScheme = 0x0301
- FakeECDSAWithSHA224 SignatureScheme = 0x0303
- FakeSHA1WithDSA SignatureScheme = 0x0202
- FakeSHA256WithDSA SignatureScheme = 0x0402
- // fakeEd25519 = SignatureAndHash{0x08, 0x07}
- // fakeEd448 = SignatureAndHash{0x08, 0x08}
- )
- // fake curves(groups)
- var (
- FakeFFDHE2048 = uint16(0x0100)
- FakeFFDHE3072 = uint16(0x0101)
- )
- // https://tools.ietf.org/html/draft-ietf-tls-certificate-compression-04
- type CertCompressionAlgo uint16
- const (
- CertCompressionZlib CertCompressionAlgo = 0x0001
- CertCompressionBrotli CertCompressionAlgo = 0x0002
- CertCompressionZstd CertCompressionAlgo = 0x0003
- )
- const (
- PskModePlain uint8 = pskModePlain
- PskModeDHE uint8 = pskModeDHE
- )
- type ClientHelloID struct {
- Client string
- // Version specifies version of a mimicked clients (e.g. browsers).
- // Not used in randomized, custom handshake, and default Go.
- Version string
- // Seed is only used for randomized fingerprints to seed PRNG.
- // Must not be modified once set.
- Seed *PRNGSeed
- // Weights are only used for randomized fingerprints in func
- // generateRandomizedSpec(). Must not be modified once set.
- Weights *Weights
- }
- func (p *ClientHelloID) Str() string {
- return fmt.Sprintf("%s-%s", p.Client, p.Version)
- }
- func (p *ClientHelloID) IsSet() bool {
- return (p.Client == "") && (p.Version == "")
- }
- const (
- // clients
- helloGolang = "Golang"
- helloRandomized = "Randomized"
- helloRandomizedALPN = "Randomized-ALPN"
- helloRandomizedNoALPN = "Randomized-NoALPN"
- helloCustom = "Custom"
- helloFirefox = "Firefox"
- helloChrome = "Chrome"
- helloIOS = "iOS"
- helloAndroid = "Android"
- helloEdge = "Edge"
- helloSafari = "Safari"
- hello360 = "360Browser"
- helloQQ = "QQBrowser"
- // versions
- helloAutoVers = "0"
- )
- type ClientHelloSpec struct {
- CipherSuites []uint16 // nil => default
- CompressionMethods []uint8 // nil => no compression
- Extensions []TLSExtension // nil => no extensions
- TLSVersMin uint16 // [1.0-1.3] default: parse from .Extensions, if SupportedVersions ext is not present => 1.0
- TLSVersMax uint16 // [1.2-1.3] default: parse from .Extensions, if SupportedVersions ext is not present => 1.2
- // GreaseStyle: currently only random
- // sessionID may or may not depend on ticket; nil => random
- GetSessionID func(ticket []byte) [32]byte
- // TLSFingerprintLink string // ?? link to tlsfingerprint.io for informational purposes
- }
- // ReadCipherSuites is a helper function to construct a list of cipher suites from
- // a []byte into []uint16.
- //
- // example: []byte{0x13, 0x01, 0x13, 0x02, 0x13, 0x03} => []uint16{0x1301, 0x1302, 0x1303}
- func (chs *ClientHelloSpec) ReadCipherSuites(b []byte) error {
- cipherSuites := []uint16{}
- s := cryptobyte.String(b)
- for !s.Empty() {
- var suite uint16
- if !s.ReadUint16(&suite) {
- return errors.New("unable to read ciphersuite")
- }
- cipherSuites = append(cipherSuites, unGREASEUint16(suite))
- }
- chs.CipherSuites = cipherSuites
- return nil
- }
- // ReadCompressionMethods is a helper function to construct a list of compression
- // methods from a []byte into []uint8.
- func (chs *ClientHelloSpec) ReadCompressionMethods(compressionMethods []byte) error {
- chs.CompressionMethods = compressionMethods
- return nil
- }
- // ReadTLSExtensions is a helper function to construct a list of TLS extensions from
- // a byte slice into []TLSExtension.
- func (chs *ClientHelloSpec) ReadTLSExtensions(b []byte, allowBluntMimicry bool, realPSK bool) error {
- extensions := cryptobyte.String(b)
- for !extensions.Empty() {
- var extension uint16
- var extData cryptobyte.String
- if !extensions.ReadUint16(&extension) {
- return fmt.Errorf("unable to read extension ID")
- }
- if !extensions.ReadUint16LengthPrefixed(&extData) {
- return fmt.Errorf("unable to read data for extension %x", extension)
- }
- ext := ExtensionFromID(extension)
- extWriter, ok := ext.(TLSExtensionWriter)
- if ext != nil && ok { // known extension and implements TLSExtensionWriter properly
- switch extension {
- case extensionPreSharedKey:
- // PSK extension, need to see if we do real or fake PSK
- if realPSK {
- extWriter = &UtlsPreSharedKeyExtension{}
- } else {
- extWriter = &FakePreSharedKeyExtension{}
- }
- case extensionSupportedVersions:
- chs.TLSVersMin = 0
- chs.TLSVersMax = 0
- }
- if _, err := extWriter.Write(extData); err != nil {
- return err
- }
- chs.Extensions = append(chs.Extensions, extWriter)
- } else {
- if allowBluntMimicry {
- chs.Extensions = append(chs.Extensions, &GenericExtension{extension, extData})
- } else {
- return fmt.Errorf("unsupported extension %d", extension)
- }
- }
- }
- return nil
- }
- func (chs *ClientHelloSpec) AlwaysAddPadding() {
- alreadyHasPadding := false
- for idx, ext := range chs.Extensions {
- if _, ok := ext.(*UtlsPaddingExtension); ok {
- alreadyHasPadding = true
- break
- }
- if _, ok := ext.(PreSharedKeyExtension); ok {
- alreadyHasPadding = true // PSK must be last, so we can't append padding after it
- // instead we will insert padding before PSK
- chs.Extensions = append(chs.Extensions[:idx], append([]TLSExtension{&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle}}, chs.Extensions[idx:]...)...)
- break
- }
- }
- if !alreadyHasPadding {
- chs.Extensions = append(chs.Extensions, &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle})
- }
- }
- // Import TLS ClientHello data from client.tlsfingerprint.io:8443
- //
- // data is a map of []byte with following keys:
- // - cipher_suites: [10, 10, 19, 1, 19, 2, 19, 3, 192, 43, 192, 47, 192, 44, 192, 48, 204, 169, 204, 168, 192, 19, 192, 20, 0, 156, 0, 157, 0, 47, 0, 53]
- // - compression_methods: [0] => null
- // - extensions: [10, 10, 255, 1, 0, 45, 0, 35, 0, 16, 68, 105, 0, 11, 0, 43, 0, 18, 0, 13, 0, 0, 0, 10, 0, 27, 0, 5, 0, 51, 0, 23, 10, 10, 0, 21]
- // - pt_fmts (ec_point_formats): [1, 0] => len: 1, content: 0x00
- // - sig_algs (signature_algorithms): [0, 16, 4, 3, 8, 4, 4, 1, 5, 3, 8, 5, 5, 1, 8, 6, 6, 1] => len: 16, content: 0x0403, 0x0804, 0x0401, 0x0503, 0x0805, 0x0501, 0x0806, 0x0601
- // - supported_versions: [10, 10, 3, 4, 3, 3] => 0x0a0a, 0x0304, 0x0303 (GREASE, TLS 1.3, TLS 1.2)
- // - curves (named_groups, supported_groups): [0, 8, 10, 10, 0, 29, 0, 23, 0, 24] => len: 8, content: GREASE, 0x001d, 0x0017, 0x0018
- // - alpn: [0, 12, 2, 104, 50, 8, 104, 116, 116, 112, 47, 49, 46, 49] => len: 12, content: h2, http/1.1
- // - key_share: [10, 10, 0, 1, 0, 29, 0, 32] => {group: 0x0a0a, len:1}, {group: 0x001d, len:32}
- // - psk_key_exchange_modes: [1] => psk_dhe_ke(0x01)
- // - cert_compression_algs: [2, 0, 2] => brotli (0x0002)
- // - record_size_limit: [0, 255] => 255
- //
- // TLSVersMin/TLSVersMax are set to 0 if supported_versions is present.
- // To prevent conflict, they should be set manually if needed BEFORE calling this function.
- func (chs *ClientHelloSpec) ImportTLSClientHello(data map[string][]byte) error {
- var tlsExtensionTypes []uint16
- var err error
- if data["cipher_suites"] == nil {
- return errors.New("cipher_suites is required")
- }
- chs.CipherSuites, err = helper.Uint8to16(data["cipher_suites"])
- if err != nil {
- return err
- }
- if data["compression_methods"] == nil {
- return errors.New("compression_methods is required")
- }
- chs.CompressionMethods = data["compression_methods"]
- if data["extensions"] == nil {
- return errors.New("extensions is required")
- }
- tlsExtensionTypes, err = helper.Uint8to16(data["extensions"])
- if err != nil {
- return err
- }
- for _, extType := range tlsExtensionTypes {
- extension := ExtensionFromID(extType)
- extWriter, ok := extension.(TLSExtensionWriter)
- if !ok {
- return fmt.Errorf("unsupported extension %d", extType)
- }
- if extension == nil || !ok {
- log.Printf("[Warning] Unsupported extension %d added as a &GenericExtension without Data", extType)
- chs.Extensions = append(chs.Extensions, &GenericExtension{extType, []byte{}})
- } else {
- switch extType {
- case extensionSupportedPoints:
- if data["pt_fmts"] == nil {
- return errors.New("pt_fmts is required")
- }
- _, err = extWriter.Write(data["pt_fmts"])
- if err != nil {
- return err
- }
- case extensionSignatureAlgorithms:
- if data["sig_algs"] == nil {
- return errors.New("sig_algs is required")
- }
- _, err = extWriter.Write(data["sig_algs"])
- if err != nil {
- return err
- }
- case extensionSupportedVersions:
- chs.TLSVersMin = 0
- chs.TLSVersMax = 0
- if data["supported_versions"] == nil {
- return errors.New("supported_versions is required")
- }
- // need to add uint8 length prefix
- fixedData := make([]byte, len(data["supported_versions"])+1)
- fixedData[0] = uint8(len(data["supported_versions"]) & 0xff)
- copy(fixedData[1:], data["supported_versions"])
- _, err = extWriter.Write(fixedData)
- if err != nil {
- return err
- }
- case extensionSupportedCurves:
- if data["curves"] == nil {
- return errors.New("curves is required")
- }
- _, err = extWriter.Write(data["curves"])
- if err != nil {
- return err
- }
- case extensionALPN:
- if data["alpn"] == nil {
- return errors.New("alpn is required")
- }
- _, err = extWriter.Write(data["alpn"])
- if err != nil {
- return err
- }
- case extensionKeyShare:
- if data["key_share"] == nil {
- return errors.New("key_share is required")
- }
- // need to add (zero) data per each key share, [10, 10, 0, 1] => [10, 10, 0, 1, 0]
- fixedData := make([]byte, 0)
- for i := 0; i < len(data["key_share"]); i += 4 {
- fixedData = append(fixedData, data["key_share"][i:i+4]...)
- for j := 0; j < int(data["key_share"][i+3]); j++ {
- fixedData = append(fixedData, 0)
- }
- }
- // add uint16 length prefix
- fixedData = append([]byte{uint8(len(fixedData) >> 8), uint8(len(fixedData) & 0xff)}, fixedData...)
- _, err = extWriter.Write(fixedData)
- if err != nil {
- return err
- }
- case extensionPSKModes:
- if data["psk_key_exchange_modes"] == nil {
- return errors.New("psk_key_exchange_modes is required")
- }
- // need to add uint8 length prefix
- fixedData := make([]byte, len(data["psk_key_exchange_modes"])+1)
- fixedData[0] = uint8(len(data["psk_key_exchange_modes"]) & 0xff)
- copy(fixedData[1:], data["psk_key_exchange_modes"])
- _, err = extWriter.Write(fixedData)
- if err != nil {
- return err
- }
- case utlsExtensionCompressCertificate:
- if data["cert_compression_algs"] == nil {
- return errors.New("cert_compression_algs is required")
- }
- // need to add uint8 length prefix
- fixedData := make([]byte, len(data["cert_compression_algs"])+1)
- fixedData[0] = uint8(len(data["cert_compression_algs"]) & 0xff)
- copy(fixedData[1:], data["cert_compression_algs"])
- _, err = extWriter.Write(fixedData)
- if err != nil {
- return err
- }
- case fakeRecordSizeLimit:
- if data["record_size_limit"] == nil {
- return errors.New("record_size_limit is required")
- }
- _, err = extWriter.Write(data["record_size_limit"]) // uint16 as []byte
- if err != nil {
- return err
- }
- case utlsExtensionApplicationSettings:
- // TODO: tlsfingerprint.io should record/provide application settings data
- extWriter.(*ApplicationSettingsExtension).SupportedProtocols = []string{"h2"}
- case extensionPreSharedKey:
- log.Printf("[Warning] PSK extension added without data")
- default:
- if !isGREASEUint16(extType) {
- log.Printf("[Warning] extension %d added without data", extType)
- } /*else {
- log.Printf("[Warning] GREASE extension added but ID/Data discarded. They will be automatically re-GREASEd on ApplyPreset() call.")
- }*/
- }
- chs.Extensions = append(chs.Extensions, extWriter)
- }
- }
- return nil
- }
- // ImportTLSClientHelloFromJSON imports ClientHelloSpec from JSON data from client.tlsfingerprint.io format
- //
- // It calls ImportTLSClientHello internally after unmarshaling JSON data into map[string][]byte
- func (chs *ClientHelloSpec) ImportTLSClientHelloFromJSON(jsonB []byte) error {
- var data map[string][]byte
- err := json.Unmarshal(jsonB, &data)
- if err != nil {
- return err
- }
- return chs.ImportTLSClientHello(data)
- }
- // FromRaw converts a ClientHello message in the form of raw bytes into a ClientHelloSpec.
- //
- // ctrlFlags: []bool{bluntMimicry, realPSK}
- func (chs *ClientHelloSpec) FromRaw(raw []byte, ctrlFlags ...bool) error {
- if chs == nil {
- return errors.New("cannot unmarshal into nil ClientHelloSpec")
- }
- var bluntMimicry = false
- var realPSK = false
- if len(ctrlFlags) > 0 {
- bluntMimicry = ctrlFlags[0]
- }
- if len(ctrlFlags) > 1 {
- realPSK = ctrlFlags[1]
- }
- *chs = ClientHelloSpec{} // reset
- s := cryptobyte.String(raw)
- var contentType uint8
- var recordVersion uint16
- if !s.ReadUint8(&contentType) || // record type
- !s.ReadUint16(&recordVersion) || !s.Skip(2) { // record version and length
- return errors.New("unable to read record type, version, and length")
- }
- if recordType(contentType) != recordTypeHandshake {
- return errors.New("record is not a handshake")
- }
- var handshakeVersion uint16
- var handshakeType uint8
- if !s.ReadUint8(&handshakeType) || !s.Skip(3) || // message type and 3 byte length
- !s.ReadUint16(&handshakeVersion) || !s.Skip(32) { // 32 byte random
- return errors.New("unable to read handshake message type, length, and random")
- }
- if handshakeType != typeClientHello {
- return errors.New("handshake message is not a ClientHello")
- }
- chs.TLSVersMin = recordVersion
- chs.TLSVersMax = handshakeVersion
- var ignoredSessionID cryptobyte.String
- if !s.ReadUint8LengthPrefixed(&ignoredSessionID) {
- return errors.New("unable to read session id")
- }
- // CipherSuites
- var cipherSuitesBytes cryptobyte.String
- if !s.ReadUint16LengthPrefixed(&cipherSuitesBytes) {
- return errors.New("unable to read ciphersuites")
- }
- if err := chs.ReadCipherSuites(cipherSuitesBytes); err != nil {
- return err
- }
- // CompressionMethods
- var compressionMethods cryptobyte.String
- if !s.ReadUint8LengthPrefixed(&compressionMethods) {
- return errors.New("unable to read compression methods")
- }
- if err := chs.ReadCompressionMethods(compressionMethods); err != nil {
- return err
- }
- if s.Empty() {
- // Extensions are optional
- return nil
- }
- var extensions cryptobyte.String
- if !s.ReadUint16LengthPrefixed(&extensions) {
- return errors.New("unable to read extensions data")
- }
- if err := chs.ReadTLSExtensions(extensions, bluntMimicry, realPSK); err != nil {
- return err
- }
- // if extension list includes padding, we update the padding-to-len according to
- // the raw ClientHello length
- for _, ext := range chs.Extensions {
- if _, ok := ext.(*UtlsPaddingExtension); ok {
- ext.(*UtlsPaddingExtension).GetPaddingLen = AlwaysPadToLen(len(raw) - 5)
- break
- }
- }
- return nil
- }
- // UnmarshalJSON unmarshals a ClientHello message in the form of JSON into a ClientHelloSpec.
- func (chs *ClientHelloSpec) UnmarshalJSON(jsonB []byte) error {
- var chsju ClientHelloSpecJSONUnmarshaler
- if err := json.Unmarshal(jsonB, &chsju); err != nil {
- return err
- }
- *chs = chsju.ClientHelloSpec()
- return nil
- }
- var (
- // HelloGolang will use default "crypto/tls" handshake marshaling codepath, which WILL
- // overwrite your changes to Hello(Config, Session are fine).
- // You might want to call BuildHandshakeState() before applying any changes.
- // UConn.Extensions will be completely ignored.
- HelloGolang = ClientHelloID{helloGolang, helloAutoVers, nil, nil}
- // HelloCustom will prepare ClientHello with empty uconn.Extensions so you can fill it with
- // TLSExtensions manually or use ApplyPreset function
- HelloCustom = ClientHelloID{helloCustom, helloAutoVers, nil, nil}
- // HelloRandomized* randomly adds/reorders extensions, ciphersuites, etc.
- HelloRandomized = ClientHelloID{helloRandomized, helloAutoVers, nil, nil}
- HelloRandomizedALPN = ClientHelloID{helloRandomizedALPN, helloAutoVers, nil, nil}
- HelloRandomizedNoALPN = ClientHelloID{helloRandomizedNoALPN, helloAutoVers, nil, nil}
- // The rest will will parrot given browser.
- HelloFirefox_Auto = HelloFirefox_120
- HelloFirefox_55 = ClientHelloID{helloFirefox, "55", nil, nil}
- HelloFirefox_56 = ClientHelloID{helloFirefox, "56", nil, nil}
- HelloFirefox_63 = ClientHelloID{helloFirefox, "63", nil, nil}
- HelloFirefox_65 = ClientHelloID{helloFirefox, "65", nil, nil}
- HelloFirefox_99 = ClientHelloID{helloFirefox, "99", nil, nil}
- HelloFirefox_102 = ClientHelloID{helloFirefox, "102", nil, nil}
- HelloFirefox_105 = ClientHelloID{helloFirefox, "105", nil, nil}
- HelloFirefox_120 = ClientHelloID{helloFirefox, "120", nil, nil}
- HelloChrome_Auto = HelloChrome_120
- HelloChrome_58 = ClientHelloID{helloChrome, "58", nil, nil}
- HelloChrome_62 = ClientHelloID{helloChrome, "62", nil, nil}
- HelloChrome_70 = ClientHelloID{helloChrome, "70", nil, nil}
- HelloChrome_72 = ClientHelloID{helloChrome, "72", nil, nil}
- HelloChrome_83 = ClientHelloID{helloChrome, "83", nil, nil}
- HelloChrome_87 = ClientHelloID{helloChrome, "87", nil, nil}
- HelloChrome_96 = ClientHelloID{helloChrome, "96", nil, nil}
- HelloChrome_100 = ClientHelloID{helloChrome, "100", nil, nil}
- HelloChrome_102 = ClientHelloID{helloChrome, "102", nil, nil}
- HelloChrome_106_Shuffle = ClientHelloID{helloChrome, "106", nil, nil} // TLS Extension shuffler enabled starting from 106
- // Chrome w/ PSK: Chrome start sending this ClientHello after doing TLS 1.3 handshake with the same server.
- // Beta: PSK extension added. However, uTLS doesn't ship with full PSK support.
- // Use at your own discretion.
- HelloChrome_PSK_Auto = HelloChrome_114_Padding_PSK_Shuf
- HelloChrome_100_PSK = ClientHelloID{helloChrome, "100_PSK", nil, nil}
- HelloChrome_112_PSK_Shuf = ClientHelloID{helloChrome, "112_PSK", nil, nil}
- HelloChrome_114_Padding_PSK_Shuf = ClientHelloID{helloChrome, "114_PSK", nil, nil}
- // Chrome w/ Post-Quantum Key Agreement
- // Beta: PQ extension added. However, uTLS doesn't ship with full PQ support. Use at your own discretion.
- HelloChrome_115_PQ = ClientHelloID{helloChrome, "115_PQ", nil, nil}
- HelloChrome_115_PQ_PSK = ClientHelloID{helloChrome, "115_PQ_PSK", nil, nil}
- // Chrome ECH
- HelloChrome_120 = ClientHelloID{helloChrome, "120", nil, nil}
- // Chrome w/ Post-Quantum Key Agreement and Encrypted ClientHello
- HelloChrome_120_PQ = ClientHelloID{helloChrome, "120_PQ", nil, nil}
- HelloIOS_Auto = HelloIOS_14
- HelloIOS_11_1 = ClientHelloID{helloIOS, "111", nil, nil} // legacy "111" means 11.1
- HelloIOS_12_1 = ClientHelloID{helloIOS, "12.1", nil, nil}
- HelloIOS_13 = ClientHelloID{helloIOS, "13", nil, nil}
- HelloIOS_14 = ClientHelloID{helloIOS, "14", nil, nil}
- HelloAndroid_11_OkHttp = ClientHelloID{helloAndroid, "11", nil, nil}
- HelloEdge_Auto = HelloEdge_85 // HelloEdge_106 seems to be incompatible with this library
- HelloEdge_85 = ClientHelloID{helloEdge, "85", nil, nil}
- HelloEdge_106 = ClientHelloID{helloEdge, "106", nil, nil}
- HelloSafari_Auto = HelloSafari_16_0
- HelloSafari_16_0 = ClientHelloID{helloSafari, "16.0", nil, nil}
- Hello360_Auto = Hello360_7_5 // Hello360_11_0 seems to be incompatible with this library
- Hello360_7_5 = ClientHelloID{hello360, "7.5", nil, nil}
- Hello360_11_0 = ClientHelloID{hello360, "11.0", nil, nil}
- HelloQQ_Auto = HelloQQ_11_1
- HelloQQ_11_1 = ClientHelloID{helloQQ, "11.1", nil, nil}
- )
- type Weights struct {
- Extensions_Append_ALPN float64
- TLSVersMax_Set_VersionTLS13 float64
- CipherSuites_Remove_RandomCiphers float64
- SigAndHashAlgos_Append_ECDSAWithSHA1 float64
- SigAndHashAlgos_Append_ECDSAWithP521AndSHA512 float64
- SigAndHashAlgos_Append_PSSWithSHA256 float64
- SigAndHashAlgos_Append_PSSWithSHA384_PSSWithSHA512 float64
- CurveIDs_Append_X25519 float64
- CurveIDs_Append_CurveP521 float64
- Extensions_Append_Padding float64
- Extensions_Append_Status float64
- Extensions_Append_SCT float64
- Extensions_Append_Reneg float64
- Extensions_Append_EMS float64
- FirstKeyShare_Set_CurveP256 float64
- Extensions_Append_ALPS float64
- }
- // Do not modify them directly as they may being used. If you
- // want to use your custom weights, please make a copy first.
- var DefaultWeights = Weights{
- Extensions_Append_ALPN: 0.7,
- TLSVersMax_Set_VersionTLS13: 0.4,
- CipherSuites_Remove_RandomCiphers: 0.4,
- SigAndHashAlgos_Append_ECDSAWithSHA1: 0.63,
- SigAndHashAlgos_Append_ECDSAWithP521AndSHA512: 0.59,
- SigAndHashAlgos_Append_PSSWithSHA256: 0.51,
- SigAndHashAlgos_Append_PSSWithSHA384_PSSWithSHA512: 0.9,
- CurveIDs_Append_X25519: 0.71,
- CurveIDs_Append_CurveP521: 0.46,
- Extensions_Append_Padding: 0.62,
- Extensions_Append_Status: 0.74,
- Extensions_Append_SCT: 0.46,
- Extensions_Append_Reneg: 0.75,
- Extensions_Append_EMS: 0.77,
- FirstKeyShare_Set_CurveP256: 0.25,
- Extensions_Append_ALPS: 0.33,
- }
- // based on spec's GreaseStyle, GREASE_PLACEHOLDER may be replaced by another GREASE value
- // https://tools.ietf.org/html/draft-ietf-tls-grease-01
- const GREASE_PLACEHOLDER = 0x0a0a
- func isGREASEUint16(v uint16) bool {
- // First byte is same as second byte
- // and lowest nibble is 0xa
- return ((v >> 8) == v&0xff) && v&0xf == 0xa
- }
- func unGREASEUint16(v uint16) uint16 {
- if isGREASEUint16(v) {
- return GREASE_PLACEHOLDER
- } else {
- return v
- }
- }
- // utlsMacSHA384 returns a SHA-384 based MAC. These are only supported in TLS 1.2
- // so the given version is ignored.
- func utlsMacSHA384(key []byte) hash.Hash {
- return hmac.New(sha512.New384, key)
- }
- var utlsSupportedCipherSuites []*cipherSuite
- func init() {
- utlsSupportedCipherSuites = append(cipherSuites, []*cipherSuite{
- {OLD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 12, ecdheRSAKA,
- suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
- {OLD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 12, ecdheECDSAKA,
- suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
- }...)
- }
- // EnableWeakCiphers allows utls connections to continue in some cases, when weak cipher was chosen.
- // This provides better compatibility with servers on the web, but weakens security. Feel free
- // to use this option if you establish additional secure connection inside of utls connection.
- // This option does not change the shape of parrots (i.e. same ciphers will be offered either way).
- // Must be called before establishing any connections.
- func EnableWeakCiphers() {
- utlsSupportedCipherSuites = append(cipherSuites, []*cipherSuite{
- {DISABLED_TLS_RSA_WITH_AES_256_CBC_SHA256, 32, 32, 16, rsaKA,
- suiteTLS12, cipherAES, macSHA256, nil},
- {DISABLED_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, 32, 48, 16, ecdheECDSAKA,
- suiteECDHE | suiteECSign | suiteTLS12 | suiteSHA384, cipherAES, utlsMacSHA384, nil},
- {DISABLED_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, 32, 48, 16, ecdheRSAKA,
- suiteECDHE | suiteTLS12 | suiteSHA384, cipherAES, utlsMacSHA384, nil},
- }...)
- }
- func mapSlice[T any, U any](slice []T, transform func(T) U) []U {
- newSlice := make([]U, 0, len(slice))
- for _, t := range slice {
- newSlice = append(newSlice, transform(t))
- }
- return newSlice
- }
- func panicOnNil(caller string, params ...any) {
- for i, p := range params {
- if p == nil {
- panic(fmt.Sprintf("tls: %s failed: the [%d] parameter is nil", caller, i))
- }
- }
- }
- func anyTrue[T any](slice []T, predicate func(i int, t *T) bool) bool {
- for i := 0; i < len(slice); i++ {
- if predicate(i, &slice[i]) {
- return true
- }
- }
- return false
- }
- func allTrue[T any](slice []T, predicate func(i int, t *T) bool) bool {
- for i := 0; i < len(slice); i++ {
- if !predicate(i, &slice[i]) {
- return false
- }
- }
- return true
- }
- func uAssert(condition bool, msg string) {
- if !condition {
- panic(msg)
- }
- }
- func sliceEq[T comparable](sliceA []T, sliceB []T) bool {
- if len(sliceA) != len(sliceB) {
- return false
- }
- for i := 0; i < len(sliceA); i++ {
- if sliceA[i] != sliceB[i] {
- return false
- }
- }
- return true
- }
- type Initializable interface {
- // IsInitialized returns a boolean indicating whether the extension has been initialized.
- // If false is returned, utls will initialize the extension.
- IsInitialized() bool
- }
|