diff --git a/common.go b/common.go index 822ae449..0763722c 100644 --- a/common.go +++ b/common.go @@ -96,7 +96,6 @@ const ( extensionSignatureAlgorithmsCert uint16 = 50 extensionKeyShare uint16 = 51 extensionNextProtoNeg uint16 = 13172 // not IANA assigned - extensionALPS uint16 = 17513 extensionRenegotiationInfo uint16 = 0xff01 ) diff --git a/u_common.go b/u_common.go index febc4d12..7ee2f355 100644 --- a/u_common.go +++ b/u_common.go @@ -23,7 +23,11 @@ const ( utlsExtensionCompressCertificate uint16 = 27 // extensions with 'fake' prefix break connection, if server echoes them back - fakeExtensionChannelID uint16 = 30032 // not IANA assigned + fakeExtensionTokenBinding uint16 = 24 + fakeExtensionChannelIDOld uint16 = 30031 // not IANA assigned + fakeExtensionChannelID uint16 = 30032 // not IANA assigned + fakeExtensionALPS uint16 = 17513 // not IANA assigned + fakeExtensionDelegatedCredentials uint16 = 34 fakeRecordSizeLimit uint16 = 0x001c @@ -44,9 +48,15 @@ const ( FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA = uint16(0x0033) FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA = uint16(0x0039) - FAKE_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = uint16(0x009f) 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) ) // newest signatures @@ -54,6 +64,9 @@ var ( FakePKCS1WithSHA224 SignatureScheme = 0x0301 FakeECDSAWithSHA224 SignatureScheme = 0x0303 + FakeSHA1WithDSA SignatureScheme = 0x0202 + FakeSHA256WithDSA SignatureScheme = 0x0402 + // fakeEd25519 = SignatureAndHash{0x08, 0x07} // fakeEd448 = SignatureAndHash{0x08, 0x08} ) @@ -109,6 +122,10 @@ const ( helloChrome = "Chrome" helloIOS = "iOS" helloAndroid = "Android" + helloEdge = "Edge" + helloSafari = "Safari" + hello360 = "360Browser" + helloQQ = "QQBrowser" // versions helloAutoVers = "0" @@ -146,13 +163,14 @@ var ( HelloRandomizedNoALPN = ClientHelloID{helloRandomizedNoALPN, helloAutoVers, nil} // The rest will will parrot given browser. - HelloFirefox_Auto = HelloFirefox_102 + HelloFirefox_Auto = HelloFirefox_105 HelloFirefox_55 = ClientHelloID{helloFirefox, "55", nil} HelloFirefox_56 = ClientHelloID{helloFirefox, "56", nil} HelloFirefox_63 = ClientHelloID{helloFirefox, "63", nil} HelloFirefox_65 = ClientHelloID{helloFirefox, "65", nil} HelloFirefox_99 = ClientHelloID{helloFirefox, "99", nil} HelloFirefox_102 = ClientHelloID{helloFirefox, "102", nil} + HelloFirefox_105 = ClientHelloID{helloFirefox, "105", nil} HelloChrome_Auto = HelloChrome_102 HelloChrome_58 = ClientHelloID{helloChrome, "58", nil} @@ -172,6 +190,20 @@ var ( HelloIOS_14 = ClientHelloID{helloIOS, "14", nil} HelloAndroid_11_OkHttp = ClientHelloID{helloAndroid, "11", nil} + + HelloEdge_Auto = HelloEdge_85 // HelloEdge_106 seems to be incompatible with this library + HelloEdge_85 = ClientHelloID{helloEdge, "85", nil} + HelloEdge_106 = ClientHelloID{helloEdge, "106", nil} + + HelloSafari_Auto = HelloSafari_16_0 + HelloSafari_16_0 = ClientHelloID{helloSafari, "16.0", nil} + + Hello360_Auto = Hello360_7_5 // Hello360_11_0 seems to be incompatible with this library + Hello360_7_5 = ClientHelloID{hello360, "7.5", nil} + Hello360_11_0 = ClientHelloID{hello360, "11.0", nil} + + HelloQQ_Auto = HelloQQ_11_1 + HelloQQ_11_1 = ClientHelloID{helloQQ, "11.1", nil} ) // based on spec's GreaseStyle, GREASE_PLACEHOLDER may be replaced by another GREASE value diff --git a/u_fingerprinter.go b/u_fingerprinter.go index 88b87cf2..d0c1bcc8 100644 --- a/u_fingerprinter.go +++ b/u_fingerprinter.go @@ -318,8 +318,63 @@ func (f *Fingerprinter) FingerprintClientHello(data []byte) (*ClientHelloSpec, e } clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &UtlsCompressCertExtension{methods}) - case fakeExtensionChannelID, fakeRecordSizeLimit: - clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &GenericExtension{extension, extData}) + case fakeExtensionChannelID: + clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &FakeChannelIDExtension{}) + + case fakeExtensionChannelIDOld: + clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &FakeChannelIDExtension{true}) + + case fakeExtensionTokenBinding: + var tokenBindingExt FakeTokenBindingExtension + var keyParameters cryptobyte.String + if !extData.ReadUint8(&tokenBindingExt.MajorVersion) || + !extData.ReadUint8(&tokenBindingExt.MinorVersion) || + !extData.ReadUint8LengthPrefixed(&keyParameters) { + return nil, errors.New("unable to read token binding extension data") + } + tokenBindingExt.KeyParameters = keyParameters + clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &tokenBindingExt) + + case fakeExtensionALPS: + // Similar to ALPN (RFC 7301, Section 3.1): + // https://datatracker.ietf.org/doc/html/draft-vvv-tls-alps#section-3 + var protoList cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() { + return nil, errors.New("unable to read ALPS extension data") + } + supportedProtocols := []string{} + for !protoList.Empty() { + var proto cryptobyte.String + if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() { + return nil, errors.New("unable to read ALPS extension data") + } + supportedProtocols = append(supportedProtocols, string(proto)) + } + clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &ApplicationSettingsExtension{supportedProtocols}) + + case fakeRecordSizeLimit: + recordSizeExt := new(FakeRecordSizeLimitExtension) + if !extData.ReadUint16(&recordSizeExt.Limit) { + return nil, errors.New("unable to read record size limit extension data") + } + clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, recordSizeExt) + + case fakeExtensionDelegatedCredentials: + //https://datatracker.ietf.org/doc/html/draft-ietf-tls-subcerts-15#section-4.1.1 + var supportedAlgs cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&supportedAlgs) || supportedAlgs.Empty() { + return nil, errors.New("unable to read signature algorithms extension data") + } + supportedSignatureAlgorithms := []SignatureScheme{} + for !supportedAlgs.Empty() { + var sigAndAlg uint16 + if !supportedAlgs.ReadUint16(&sigAndAlg) { + return nil, errors.New("unable to read signature algorithms extension data") + } + supportedSignatureAlgorithms = append( + supportedSignatureAlgorithms, SignatureScheme(sigAndAlg)) + } + clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &FakeDelegatedCredentialsExtension{supportedSignatureAlgorithms}) case extensionPreSharedKey: // RFC 8446, Section 4.2.11 @@ -351,7 +406,7 @@ func (f *Fingerprinter) FingerprintClientHello(data []byte) (*ClientHelloSpec, e } else if f.AllowBluntMimicry { clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &GenericExtension{extension, extData}) } else { - return nil, fmt.Errorf("unsupported extension %#x", extension) + return nil, fmt.Errorf("unsupported extension %d", extension) } continue diff --git a/u_parrots.go b/u_parrots.go index 43568638..aa64d150 100644 --- a/u_parrots.go +++ b/u_parrots.go @@ -703,7 +703,6 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) { &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle}, }, }, nil - case HelloFirefox_99: return ClientHelloSpec{ TLSVersMin: VersionTLS10, @@ -865,6 +864,113 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) { &FakeRecordSizeLimitExtension{Limit: 0x4001}, //record_size_limit &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle}, //padding }}, nil + case HelloFirefox_105: + return ClientHelloSpec{ + TLSVersMin: VersionTLS12, + TLSVersMax: VersionTLS13, + CipherSuites: []uint16{ + TLS_AES_128_GCM_SHA256, + TLS_CHACHA20_POLY1305_SHA256, + TLS_AES_256_GCM_SHA384, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + TLS_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_256_GCM_SHA384, + TLS_RSA_WITH_AES_128_CBC_SHA, + TLS_RSA_WITH_AES_256_CBC_SHA, + }, + CompressionMethods: []uint8{ + 0x0, // no compression + }, + Extensions: []TLSExtension{ + &SNIExtension{}, + &UtlsExtendedMasterSecretExtension{}, + &RenegotiationInfoExtension{ + Renegotiation: RenegotiateOnceAsClient, + }, + &SupportedCurvesExtension{ + Curves: []CurveID{ + X25519, + CurveP256, + CurveP384, + CurveP521, + 256, + 257, + }, + }, + &SupportedPointsExtension{ + SupportedPoints: []uint8{ + 0x0, // uncompressed + }, + }, + &SessionTicketExtension{}, + &ALPNExtension{ + AlpnProtocols: []string{ + "h2", + "http/1.1", + }, + }, + &StatusRequestExtension{}, + &FakeDelegatedCredentialsExtension{ + SupportedSignatureAlgorithms: []SignatureScheme{ + ECDSAWithP256AndSHA256, + ECDSAWithP384AndSHA384, + ECDSAWithP521AndSHA512, + ECDSAWithSHA1, + }, + }, + &KeyShareExtension{ + KeyShares: []KeyShare{ + { + Group: X25519, + }, + { + Group: CurveP256, + }, + }, + }, + &SupportedVersionsExtension{ + Versions: []uint16{ + VersionTLS13, + VersionTLS12, + }, + }, + &SignatureAlgorithmsExtension{ + SupportedSignatureAlgorithms: []SignatureScheme{ + ECDSAWithP256AndSHA256, + ECDSAWithP384AndSHA384, + ECDSAWithP521AndSHA512, + PSSWithSHA256, + PSSWithSHA384, + PSSWithSHA512, + PKCS1WithSHA256, + PKCS1WithSHA384, + PKCS1WithSHA512, + ECDSAWithSHA1, + PKCS1WithSHA1, + }, + }, + &PSKKeyExchangeModesExtension{ + Modes: []uint8{ + PskModeDHE, + }, + }, + &FakeRecordSizeLimitExtension{ + Limit: 0x4001, + }, + &UtlsPaddingExtension{ + GetPaddingLen: BoringPaddingStyle, + }, + }, + }, nil case HelloIOS_11_1: return ClientHelloSpec{ TLSVersMax: VersionTLS12, @@ -1194,6 +1300,618 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) { }}, }, }, nil + case HelloEdge_85: + return ClientHelloSpec{ + CipherSuites: []uint16{ + GREASE_PLACEHOLDER, + TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, + TLS_CHACHA20_POLY1305_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + TLS_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_256_GCM_SHA384, + TLS_RSA_WITH_AES_128_CBC_SHA, + TLS_RSA_WITH_AES_256_CBC_SHA, + }, + CompressionMethods: []uint8{ + 0x0, // no compression + }, + Extensions: []TLSExtension{ + &UtlsGREASEExtension{}, + &SNIExtension{}, + &UtlsExtendedMasterSecretExtension{}, + &RenegotiationInfoExtension{ + Renegotiation: RenegotiateOnceAsClient, + }, + &SupportedCurvesExtension{ + Curves: []CurveID{ + GREASE_PLACEHOLDER, + X25519, + CurveP256, + CurveP384, + }, + }, + &SupportedPointsExtension{ + SupportedPoints: []uint8{ + 0x0, // pointFormatUncompressed + }, + }, + &SessionTicketExtension{}, + &ALPNExtension{ + AlpnProtocols: []string{ + "h2", + "http/1.1", + }, + }, + &StatusRequestExtension{}, + &SignatureAlgorithmsExtension{ + SupportedSignatureAlgorithms: []SignatureScheme{ + ECDSAWithP256AndSHA256, + PSSWithSHA256, + PKCS1WithSHA256, + ECDSAWithP384AndSHA384, + PSSWithSHA384, + PKCS1WithSHA384, + PSSWithSHA512, + PKCS1WithSHA512, + }, + }, + &SCTExtension{}, + &KeyShareExtension{ + KeyShares: []KeyShare{ + { + Group: GREASE_PLACEHOLDER, + Data: []byte{ + 0, + }, + }, + { + Group: X25519, + }, + }, + }, + &PSKKeyExchangeModesExtension{ + Modes: []uint8{ + PskModeDHE, + }, + }, + &SupportedVersionsExtension{ + Versions: []uint16{ + GREASE_PLACEHOLDER, + VersionTLS13, + VersionTLS12, + VersionTLS11, + VersionTLS10, + }, + }, + &UtlsCompressCertExtension{ + Algorithms: []CertCompressionAlgo{ + CertCompressionBrotli, + }, + }, + &UtlsGREASEExtension{}, + &UtlsPaddingExtension{ + GetPaddingLen: BoringPaddingStyle, + }, + }, + }, nil + case HelloEdge_106: + return ClientHelloSpec{ + TLSVersMin: VersionTLS12, + TLSVersMax: VersionTLS13, + CipherSuites: []uint16{ + GREASE_PLACEHOLDER, + TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, + TLS_AES_256_GCM_SHA384, + TLS_CHACHA20_POLY1305_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + TLS_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_256_GCM_SHA384, + TLS_RSA_WITH_AES_128_CBC_SHA, + TLS_RSA_WITH_AES_256_CBC_SHA, + }, + CompressionMethods: []uint8{ + 0x0, // no compression + }, + Extensions: []TLSExtension{ + &UtlsGREASEExtension{}, + &SNIExtension{}, + &UtlsExtendedMasterSecretExtension{}, + &RenegotiationInfoExtension{ + Renegotiation: RenegotiateOnceAsClient, + }, + &SupportedCurvesExtension{ + Curves: []CurveID{ + GREASE_PLACEHOLDER, + X25519, + CurveP256, + CurveP384, + }, + }, + &SupportedPointsExtension{ + SupportedPoints: []uint8{ + 0x0, // uncompressed + }, + }, + &SessionTicketExtension{}, + &ALPNExtension{ + AlpnProtocols: []string{ + "h2", + "http/1.1", + }, + }, + &StatusRequestExtension{}, + &SignatureAlgorithmsExtension{ + SupportedSignatureAlgorithms: []SignatureScheme{ + ECDSAWithP256AndSHA256, + PSSWithSHA256, + PKCS1WithSHA256, + ECDSAWithP384AndSHA384, + PSSWithSHA384, + PKCS1WithSHA384, + PSSWithSHA512, + PKCS1WithSHA512, + }, + }, + &SCTExtension{}, + &KeyShareExtension{ + KeyShares: []KeyShare{ + { + Group: GREASE_PLACEHOLDER, + Data: []byte{ + 0, + }, + }, + { + Group: X25519, + }, + }, + }, + &PSKKeyExchangeModesExtension{ + Modes: []uint8{ + PskModeDHE, + }, + }, + &SupportedVersionsExtension{ + Versions: []uint16{ + GREASE_PLACEHOLDER, + VersionTLS13, + VersionTLS12, + }, + }, + &UtlsCompressCertExtension{ + Algorithms: []CertCompressionAlgo{ + CertCompressionBrotli, + }, + }, + &ApplicationSettingsExtension{ + SupportedProtocols: []string{ + "h2", + }, + }, + &UtlsGREASEExtension{}, + &UtlsPaddingExtension{ + GetPaddingLen: BoringPaddingStyle, + }, + }, + }, nil + case HelloSafari_16_0: + return ClientHelloSpec{ + TLSVersMin: VersionTLS10, + TLSVersMax: VersionTLS13, + CipherSuites: []uint16{ + GREASE_PLACEHOLDER, + TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, + TLS_CHACHA20_POLY1305_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS_RSA_WITH_AES_256_GCM_SHA384, + TLS_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_256_CBC_SHA, + TLS_RSA_WITH_AES_128_CBC_SHA, + FAKE_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + TLS_RSA_WITH_3DES_EDE_CBC_SHA, + }, + CompressionMethods: []uint8{ + 0x0, // no compression + }, + Extensions: []TLSExtension{ + &UtlsGREASEExtension{}, + &SNIExtension{}, + &UtlsExtendedMasterSecretExtension{}, + &RenegotiationInfoExtension{ + Renegotiation: RenegotiateOnceAsClient, + }, + &SupportedCurvesExtension{ + Curves: []CurveID{ + GREASE_PLACEHOLDER, + X25519, + CurveP256, + CurveP384, + CurveP521, + }, + }, + &SupportedPointsExtension{ + SupportedPoints: []uint8{ + 0x0, // uncompressed + }, + }, + &ALPNExtension{ + AlpnProtocols: []string{ + "h2", + "http/1.1", + }, + }, + &StatusRequestExtension{}, + &SignatureAlgorithmsExtension{ + SupportedSignatureAlgorithms: []SignatureScheme{ + ECDSAWithP256AndSHA256, + PSSWithSHA256, + PKCS1WithSHA256, + ECDSAWithP384AndSHA384, + ECDSAWithSHA1, + PSSWithSHA384, + PSSWithSHA384, + PKCS1WithSHA384, + PSSWithSHA512, + PKCS1WithSHA512, + PKCS1WithSHA1, + }, + }, + &SCTExtension{}, + &KeyShareExtension{ + KeyShares: []KeyShare{ + { + Group: GREASE_PLACEHOLDER, + Data: []byte{ + 0, + }, + }, + { + Group: X25519, + }, + }, + }, + &PSKKeyExchangeModesExtension{ + Modes: []uint8{ + PskModeDHE, + }, + }, + &SupportedVersionsExtension{ + Versions: []uint16{ + GREASE_PLACEHOLDER, + VersionTLS13, + VersionTLS12, + VersionTLS11, + VersionTLS10, + }, + }, + &UtlsCompressCertExtension{ + Algorithms: []CertCompressionAlgo{ + CertCompressionZlib, + }, + }, + &UtlsGREASEExtension{}, + &UtlsPaddingExtension{ + GetPaddingLen: BoringPaddingStyle, + }, + }, + }, nil + case Hello360_7_5: + return ClientHelloSpec{ + CipherSuites: []uint16{ + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + TLS_RSA_WITH_AES_256_CBC_SHA, + DISABLED_TLS_RSA_WITH_AES_256_CBC_SHA256, + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + TLS_ECDHE_RSA_WITH_RC4_128_SHA, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + FAKE_TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + TLS_RSA_WITH_RC4_128_SHA, + FAKE_TLS_RSA_WITH_RC4_128_MD5, + TLS_RSA_WITH_AES_128_CBC_SHA, + TLS_RSA_WITH_AES_128_CBC_SHA256, + TLS_RSA_WITH_3DES_EDE_CBC_SHA, + }, + CompressionMethods: []uint8{ + 0x0, // no compression + }, + Extensions: []TLSExtension{ + &SNIExtension{}, + &RenegotiationInfoExtension{ + Renegotiation: RenegotiateOnceAsClient, + }, + &SupportedCurvesExtension{ + Curves: []CurveID{ + CurveP256, + CurveP384, + CurveP521, + }, + }, + &SupportedPointsExtension{ + SupportedPoints: []uint8{ + 0x0, // pointFormatUncompressed + }, + }, + &SessionTicketExtension{}, + &NPNExtension{}, + &ALPNExtension{ + AlpnProtocols: []string{ + "spdy/2", + "spdy/3", + "spdy/3.1", + "http/1.1", + }, + }, + &FakeChannelIDExtension{ + OldExtensionID: true, + }, + &StatusRequestExtension{}, + &SignatureAlgorithmsExtension{ + SupportedSignatureAlgorithms: []SignatureScheme{ + PKCS1WithSHA256, + PKCS1WithSHA384, + PKCS1WithSHA1, + ECDSAWithP256AndSHA256, + ECDSAWithP384AndSHA384, + ECDSAWithSHA1, + FakeSHA256WithDSA, + FakeSHA1WithDSA, + }, + }, + }, + }, nil + case Hello360_11_0: + return ClientHelloSpec{ + TLSVersMin: VersionTLS10, + TLSVersMax: VersionTLS13, + CipherSuites: []uint16{ + GREASE_PLACEHOLDER, + TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, + TLS_CHACHA20_POLY1305_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + TLS_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_256_GCM_SHA384, + TLS_RSA_WITH_AES_128_CBC_SHA, + TLS_RSA_WITH_AES_256_CBC_SHA, + TLS_RSA_WITH_3DES_EDE_CBC_SHA, + }, + CompressionMethods: []uint8{ + 0x0, // no compression + }, + Extensions: []TLSExtension{ + &UtlsGREASEExtension{}, + &SNIExtension{}, + &UtlsExtendedMasterSecretExtension{}, + &RenegotiationInfoExtension{ + Renegotiation: RenegotiateOnceAsClient, + }, + &SupportedCurvesExtension{ + Curves: []CurveID{ + GREASE_PLACEHOLDER, + X25519, + CurveP256, + CurveP384, + }, + }, + &SupportedPointsExtension{ + SupportedPoints: []uint8{ + 0x0, // uncompressed + }, + }, + &SessionTicketExtension{}, + &ALPNExtension{ + AlpnProtocols: []string{ + "h2", + "http/1.1", + }, + }, + &StatusRequestExtension{}, + &SignatureAlgorithmsExtension{ + SupportedSignatureAlgorithms: []SignatureScheme{ + ECDSAWithP256AndSHA256, + PSSWithSHA256, + PKCS1WithSHA256, + ECDSAWithP384AndSHA384, + PSSWithSHA384, + PKCS1WithSHA384, + PSSWithSHA512, + PKCS1WithSHA512, + PKCS1WithSHA1, + }, + }, + &SCTExtension{}, + &FakeChannelIDExtension{ + OldExtensionID: false, + }, + &KeyShareExtension{ + KeyShares: []KeyShare{ + { + Group: GREASE_PLACEHOLDER, + Data: []byte{ + 0, + }, + }, + { + Group: X25519, + }, + }, + }, + &PSKKeyExchangeModesExtension{ + Modes: []uint8{ + PskModeDHE, + }, + }, + &SupportedVersionsExtension{ + Versions: []uint16{ + GREASE_PLACEHOLDER, + VersionTLS13, + VersionTLS12, + VersionTLS11, + VersionTLS10, + }, + }, + &UtlsCompressCertExtension{ + Algorithms: []CertCompressionAlgo{ + CertCompressionBrotli, + }, + }, + &UtlsGREASEExtension{}, + &UtlsPaddingExtension{ + GetPaddingLen: BoringPaddingStyle, + }, + }, + }, nil + case HelloQQ_11_1: + return ClientHelloSpec{ + TLSVersMin: VersionTLS10, + TLSVersMax: VersionTLS13, + CipherSuites: []uint16{ + GREASE_PLACEHOLDER, + TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, + TLS_CHACHA20_POLY1305_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + TLS_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_256_GCM_SHA384, + TLS_RSA_WITH_AES_128_CBC_SHA, + TLS_RSA_WITH_AES_256_CBC_SHA, + }, + CompressionMethods: []uint8{ + 0x0, // no compression + }, + Extensions: []TLSExtension{ + &UtlsGREASEExtension{}, + &SNIExtension{}, + &UtlsExtendedMasterSecretExtension{}, + &RenegotiationInfoExtension{ + Renegotiation: RenegotiateOnceAsClient, + }, + &SupportedCurvesExtension{ + Curves: []CurveID{ + GREASE_PLACEHOLDER, + X25519, + CurveP256, + CurveP384, + }, + }, + &SupportedPointsExtension{ + SupportedPoints: []uint8{ + 0x0, // uncompressed + }, + }, + &SessionTicketExtension{}, + &ALPNExtension{ + AlpnProtocols: []string{ + "h2", + "http/1.1", + }, + }, + &StatusRequestExtension{}, + &SignatureAlgorithmsExtension{ + SupportedSignatureAlgorithms: []SignatureScheme{ + ECDSAWithP256AndSHA256, + PSSWithSHA256, + PKCS1WithSHA256, + ECDSAWithP384AndSHA384, + PSSWithSHA384, + PKCS1WithSHA384, + PSSWithSHA512, + PKCS1WithSHA512, + }, + }, + &SCTExtension{}, + &KeyShareExtension{ + KeyShares: []KeyShare{ + { + Group: GREASE_PLACEHOLDER, + Data: []byte{ + 0, + }, + }, + { + Group: X25519, + }, + }, + }, + &PSKKeyExchangeModesExtension{ + Modes: []uint8{ + PskModeDHE, + }, + }, + &SupportedVersionsExtension{ + Versions: []uint16{ + GREASE_PLACEHOLDER, + VersionTLS13, + VersionTLS12, + VersionTLS11, + VersionTLS10, + }, + }, + &UtlsCompressCertExtension{ + Algorithms: []CertCompressionAlgo{ + CertCompressionBrotli, + }, + }, + &ApplicationSettingsExtension{ + SupportedProtocols: []string{ + "h2", + }, + }, + &UtlsGREASEExtension{}, + &UtlsPaddingExtension{ + GetPaddingLen: BoringPaddingStyle, + }, + }, + }, nil default: return ClientHelloSpec{}, errors.New("ClientHello ID " + id.Str() + " is unknown") } diff --git a/u_tls_extensions.go b/u_tls_extensions.go index 3e878753..c4816d3d 100644 --- a/u_tls_extensions.go +++ b/u_tls_extensions.go @@ -356,6 +356,17 @@ func (e *ALPNExtension) Read(b []byte) (int, error) { return e.Len(), io.EOF } +// ApplicationSettingsExtension represents the TLS ALPS extension. At the time +// of this writing, this extension is currently a draft: +// https://datatracker.ietf.org/doc/html/draft-vvv-tls-alps-01 +// +// This library does not offer actual support for ALPS. This extension is +// "faked" - it is advertised by the client, but not respected if the server +// responds with support. +// +// In the normal convention of this library, this type name would be prefixed +// with 'Fake'. The existing name is retained for backwards compatibility +// reasons. type ApplicationSettingsExtension struct { SupportedProtocols []string } @@ -378,8 +389,8 @@ func (e *ApplicationSettingsExtension) Read(b []byte) (int, error) { } // Read Type. - b[0] = byte(extensionALPS >> 8) // hex: 44 dec: 68 - b[1] = byte(extensionALPS & 0xff) // hex: 69 dec: 105 + b[0] = byte(fakeExtensionALPS >> 8) // hex: 44 dec: 68 + b[1] = byte(fakeExtensionALPS & 0xff) // hex: 69 dec: 105 lengths := b[2:] // get the remaining buffer without Type b = b[6:] // set the buffer to the buffer without Type, Length and ALPS Extension Length (so only the Supported ALPN list remains) @@ -834,6 +845,8 @@ FAKE EXTENSIONS */ type FakeChannelIDExtension struct { + // The extension ID changed from 30031 to 30032. Set to true to use the old extension ID. + OldExtensionID bool } func (e *FakeChannelIDExtension) writeToUConn(uc *UConn) error { @@ -848,9 +861,13 @@ func (e *FakeChannelIDExtension) Read(b []byte) (int, error) { if len(b) < e.Len() { return 0, io.ErrShortBuffer } + extensionID := fakeExtensionChannelID + if e.OldExtensionID { + extensionID = fakeExtensionChannelIDOld + } // https://tools.ietf.org/html/draft-balfanz-tls-channelid-00 - b[0] = byte(fakeExtensionChannelID >> 8) - b[1] = byte(fakeExtensionChannelID & 0xff) + b[0] = byte(extensionID >> 8) + b[1] = byte(extensionID & 0xff) // The length is 0 return e.Len(), io.EOF } @@ -911,3 +928,69 @@ func (e *DelegatedCredentialsExtension) Read(b []byte) (int, error) { } return e.Len(), io.EOF } + +// https://tools.ietf.org/html/rfc8472#section-2 + +type FakeTokenBindingExtension struct { + MajorVersion, MinorVersion uint8 + KeyParameters []uint8 +} + +func (e *FakeTokenBindingExtension) writeToUConn(uc *UConn) error { + return nil +} + +func (e *FakeTokenBindingExtension) Len() int { + // extension ID + data length + versions + key parameters length + key parameters + return 2 + 2 + 2 + 1 + len(e.KeyParameters) +} + +func (e *FakeTokenBindingExtension) Read(b []byte) (int, error) { + if len(b) < e.Len() { + return 0, io.ErrShortBuffer + } + dataLen := e.Len() - 4 + b[0] = byte(fakeExtensionTokenBinding >> 8) + b[1] = byte(fakeExtensionTokenBinding & 0xff) + b[2] = byte(dataLen >> 8) + b[3] = byte(dataLen & 0xff) + b[4] = e.MajorVersion + b[5] = e.MinorVersion + b[6] = byte(len(e.KeyParameters)) + if len(e.KeyParameters) > 0 { + copy(b[7:], e.KeyParameters) + } + return e.Len(), io.EOF +} + +// https://datatracker.ietf.org/doc/html/draft-ietf-tls-subcerts-15#section-4.1.1 + +type FakeDelegatedCredentialsExtension struct { + SupportedSignatureAlgorithms []SignatureScheme +} + +func (e *FakeDelegatedCredentialsExtension) writeToUConn(uc *UConn) error { + return nil +} + +func (e *FakeDelegatedCredentialsExtension) Len() int { + return 6 + 2*len(e.SupportedSignatureAlgorithms) +} + +func (e *FakeDelegatedCredentialsExtension) Read(b []byte) (int, error) { + if len(b) < e.Len() { + return 0, io.ErrShortBuffer + } + // https://datatracker.ietf.org/doc/html/draft-ietf-tls-subcerts-15#section-4.1.1 + b[0] = byte(fakeExtensionDelegatedCredentials >> 8) + b[1] = byte(fakeExtensionDelegatedCredentials) + b[2] = byte((2 + 2*len(e.SupportedSignatureAlgorithms)) >> 8) + b[3] = byte((2 + 2*len(e.SupportedSignatureAlgorithms))) + b[4] = byte((2 * len(e.SupportedSignatureAlgorithms)) >> 8) + b[5] = byte((2 * len(e.SupportedSignatureAlgorithms))) + for i, sigAndHash := range e.SupportedSignatureAlgorithms { + b[6+2*i] = byte(sigAndHash >> 8) + b[7+2*i] = byte(sigAndHash) + } + return e.Len(), io.EOF +}