utls/u_parrots.go
Gaukas Wang 8094658e76
new: Support TLS-PSK (TLS 1.3) (#231)
* uTLS: X25519Kyber768Draft00 hybrid post-quantum key agreement by cloudflare/go (#222)

* crypto/tls: Add hybrid post-quantum key agreement  (#13)

* import: client-side KEM from cloudflare/go

* import: server-side KEM from cloudflare/go

* fix: modify test to get rid of CFEvents.

Note: uTLS does not promise any server-side functionality, and this change is made to be able to conduct unit tests which requires both side to be able to handle KEM Curves.

Co-authored-by: Christopher Wood <caw@heapingbits.net>
Co-Authored-By: Bas Westerbaan <bas@westerbaan.name>

----

Based on:

* crypto/tls: Add hybrid post-quantum key agreement 

Adds X25519Kyber512Draft00, X25519Kyber768Draft00, and
P256Kyber768Draft00 hybrid post-quantum key agreements with temporary
group identifiers.

The hybrid post-quantum key exchanges uses plain X{25519,448} instead
of HPKE, which we assume will be more likely to be adopted. The order
is chosen to match CECPQ2.

Not enabled by default.

Adds CFEvents to detect `HelloRetryRequest`s and to signal which
key agreement was used.

Co-authored-by: Christopher Wood <caw@heapingbits.net>

 [bas, 1.20.1: also adds P256Kyber768Draft00]
 [pwu, 1.20.4: updated circl to v1.3.3, moved code to cfevent.go]

* crypto: add support for CIRCL signature schemes

* only partially port the commit from cloudflare/go. We would stick to the official x509 at the cost of incompatibility.

Co-Authored-By: Bas Westerbaan <bas@westerbaan.name>
Co-Authored-By: Christopher Patton <3453007+cjpatton@users.noreply.github.com>
Co-Authored-By: Peter Wu <peter@lekensteyn.nl>

* crypto/tls: add new X25519Kyber768Draft00 code point

Ported from cloudflare/go to support the upcoming new post-quantum keyshare.

----

* Point tls.X25519Kyber768Draft00 to the new 0x6399 identifier while the
  old 0xfe31 identifier is available as tls.X25519Kyber768Draft00Old.
* Make sure that the kem.PrivateKey can always be mapped to the CurveID
  that was linked to it. This is needed since we now have two ID
  aliasing to the same scheme, and clients need to be able to detect
  whether the key share presented by the server actually matches the key
  share that the client originally sent.
* Update tests, add the new identifier and remove unnecessary code.

Link: https://mailarchive.ietf.org/arch/msg/tls/HAWpNpgptl--UZNSYuvsjB-Pc2k/
Link: https://datatracker.ietf.org/doc/draft-tls-westerbaan-xyber768d00/02/
Co-Authored-By: Peter Wu <peter@lekensteyn.nl>
Co-Authored-By: Bas Westerbaan <bas@westerbaan.name>

---------

Co-authored-by: Bas Westerbaan <bas@westerbaan.name>
Co-authored-by: Christopher Patton <3453007+cjpatton@users.noreply.github.com>
Co-authored-by: Peter Wu <peter@lekensteyn.nl>

* new: enable PQ parrots (#225)

* Redesign KeySharesEcdheParameters into KeySharesParameters which supports multiple types of keys.

* Optimize program logic to prevent using unwanted keys

* new: more parrots and safety update (#227)

* new: PQ and other parrots

Add new preset parrots:
- HelloChrome_114_Padding_PSK_Shuf
- HelloChrome_115_PQ
- HelloChrome_115_PQ_PSK

* new: ShuffleChromeTLSExtensions

Implement a new function `ShuffleChromeTLSExtensions(exts []TLSExtension) []TLSExtension`.

* update: include psk parameter for parrot-related functions

Update following functions' prototype to accept an optional pskExtension (of type *FakePreSharedKeyExtension):
- `UClient(conn net.Conn, config *Config, clientHelloID ClientHelloID)` => `UClient(conn net.Conn, config *Config, clientHelloID ClientHelloID, pskExtension ...*FakePreSharedKeyExtension)`
- `UTLSIdToSpec(id ClientHelloID)` => `UTLSIdToSpec(id ClientHelloID, pskExtension ...*FakePreSharedKeyExtension)`

* new: pre-defined error from UTLSIdToSpec

Update UTLSIdToSpec to return more comprehensive errors by pre-defining them, allowing easier error comparing/unwrapping.

* new: UtlsPreSharedKeyExtension

In `u_pre_shared_key.go`, create `PreSharedKeyExtension` as an interface, with 3 implementations:
- `UtlsPreSharedKeyExtension` implements full support for `pre_shared_key` less resuming after seeing HRR.
- `FakePreSharedKeyExtension` uses CipherSuiteID, SessionSecret and Identities to calculate the corresponding binders and send them, without setting the internal states. Therefore if the server accepts the PSK and tries to resume, the connection fails.
- `HardcodedPreSharedKeyExtension` allows user to hardcode Identities and Binders to be sent in the extension without setting the internal states. Therefore if the server accepts the PSK and tries to resume, the connection fails.

TODO: Only one of FakePreSharedKeyExtension and HardcodedPreSharedKeyExtension should be kept, the other one should be just removed. We still need to learn more of the safety of hardcoding both Identities and Binders without recalculating the latter.

* update: PSK minor changes and example

* Updates PSK implementations for more comprehensible interfaces when applying preset/json/raw fingerprints.
* Revert FakePreSharedKeyExtension to the old implementation. Add binder size checking.
* Implement TLS-PSK example

New bug: setting `tls.Config.ClientSessionCache` will cause PSK to fail. Currently users must set only `tls.UtlsPreSharedKeyExtension.ClientSessionCacheOverride`.

* fix: PSK failing if config session cache set

* Fix a bug causing PSK to fail if Config.ClientSessionCache is set.
* Removed `ClientSessionCacheOverride` from `UtlsPreSharedKeyExtension`. Set the `ClientSessionCache` in `Config`!

Co-Authored-By: zeeker999 <13848632+zeeker999@users.noreply.github.com>

* Optimize tls resumption (#235)

* feat: bug fix and refactor

* feat: improve example docs: add detailed explanation about the design feat: add assertion on uApplyPatch

* fix: address comments
feat: add option `OmitEmptyPsk` and throw error on empty psk by default
feat: revert changes to public interfaces

* fix: weird residue caused by merging conflict

* fix: remove merge conflict residue code

---------

Co-authored-by: Bas Westerbaan <bas@westerbaan.name>
Co-authored-by: Christopher Patton <3453007+cjpatton@users.noreply.github.com>
Co-authored-by: Peter Wu <peter@lekensteyn.nl>
Co-authored-by: zeeker999 <13848632+zeeker999@users.noreply.github.com>
Co-authored-by: 3andne <52860475+3andne@users.noreply.github.com>
2023-08-27 12:48:31 -06:00

2788 lines
80 KiB
Go

// 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/ecdh"
"crypto/sha256"
"encoding/binary"
"errors"
"fmt"
"io"
"math/rand"
"sort"
"strconv"
)
var ErrUnknownClientHelloID = errors.New("tls: unknown ClientHelloID")
// UTLSIdToSpec converts a ClientHelloID to a corresponding ClientHelloSpec.
//
// Exported internal function utlsIdToSpec per request.
func UTLSIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
return utlsIdToSpec(id)
}
func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
switch id {
case HelloChrome_58, HelloChrome_62:
return ClientHelloSpec{
TLSVersMax: VersionTLS12,
TLSVersMin: VersionTLS10,
CipherSuites: []uint16{
GREASE_PLACEHOLDER,
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: []byte{compressionNone},
Extensions: []TLSExtension{
&UtlsGREASEExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&SessionTicketExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
PKCS1WithSHA1},
},
&StatusRequestExtension{},
&SCTExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&FakeChannelIDExtension{},
&SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}},
&SupportedCurvesExtension{[]CurveID{CurveID(GREASE_PLACEHOLDER),
X25519, CurveP256, CurveP384}},
&UtlsGREASEExtension{},
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
},
GetSessionID: sha256.Sum256,
}, nil
case HelloChrome_70:
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: []byte{
compressionNone,
},
Extensions: []TLSExtension{
&UtlsGREASEExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&SessionTicketExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
PKCS1WithSHA1,
}},
&StatusRequestExtension{},
&SCTExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&FakeChannelIDExtension{},
&SupportedPointsExtension{SupportedPoints: []byte{
pointFormatUncompressed,
}},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{pskModeDHE}},
&SupportedVersionsExtension{[]uint16{
GREASE_PLACEHOLDER,
VersionTLS13,
VersionTLS12,
VersionTLS11,
VersionTLS10}},
&SupportedCurvesExtension{[]CurveID{
CurveID(GREASE_PLACEHOLDER),
X25519,
CurveP256,
CurveP384,
}},
&UtlsCompressCertExtension{[]CertCompressionAlgo{CertCompressionBrotli}},
&UtlsGREASEExtension{},
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
},
}, nil
case HelloChrome_72:
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,
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
},
CompressionMethods: []byte{
0x00, // compressionNone
},
Extensions: []TLSExtension{
&UtlsGREASEExtension{},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
CurveID(GREASE_PLACEHOLDER),
X25519,
CurveP256,
CurveP384,
}},
&SupportedPointsExtension{SupportedPoints: []byte{
0x00, // pointFormatUncompressed
}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&StatusRequestExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
PKCS1WithSHA1,
}},
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
PskModeDHE,
}},
&SupportedVersionsExtension{[]uint16{
GREASE_PLACEHOLDER,
VersionTLS13,
VersionTLS12,
VersionTLS11,
VersionTLS10,
}},
&UtlsCompressCertExtension{[]CertCompressionAlgo{
CertCompressionBrotli,
}},
&UtlsGREASEExtension{},
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
},
}, nil
case HelloChrome_83:
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: []byte{
0x00, // compressionNone
},
Extensions: []TLSExtension{
&UtlsGREASEExtension{},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
CurveID(GREASE_PLACEHOLDER),
X25519,
CurveP256,
CurveP384,
}},
&SupportedPointsExtension{SupportedPoints: []byte{
0x00, // pointFormatUncompressed
}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&StatusRequestExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
}},
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
PskModeDHE,
}},
&SupportedVersionsExtension{[]uint16{
GREASE_PLACEHOLDER,
VersionTLS13,
VersionTLS12,
VersionTLS11,
VersionTLS10,
}},
&UtlsCompressCertExtension{[]CertCompressionAlgo{
CertCompressionBrotli,
}},
&UtlsGREASEExtension{},
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
},
}, nil
case HelloChrome_87:
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: []byte{
0x00, // compressionNone
},
Extensions: []TLSExtension{
&UtlsGREASEExtension{},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
CurveID(GREASE_PLACEHOLDER),
X25519,
CurveP256,
CurveP384,
}},
&SupportedPointsExtension{SupportedPoints: []byte{
0x00, // pointFormatUncompressed
}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&StatusRequestExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
}},
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
PskModeDHE,
}},
&SupportedVersionsExtension{[]uint16{
GREASE_PLACEHOLDER,
VersionTLS13,
VersionTLS12,
VersionTLS11,
VersionTLS10,
}},
&UtlsCompressCertExtension{[]CertCompressionAlgo{
CertCompressionBrotli,
}},
&UtlsGREASEExtension{},
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
},
}, nil
case HelloChrome_96:
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: []byte{
0x00, // compressionNone
},
Extensions: []TLSExtension{
&UtlsGREASEExtension{},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
CurveID(GREASE_PLACEHOLDER),
X25519,
CurveP256,
CurveP384,
}},
&SupportedPointsExtension{SupportedPoints: []byte{
0x00, // pointFormatUncompressed
}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&StatusRequestExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
}},
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
PskModeDHE,
}},
&SupportedVersionsExtension{[]uint16{
GREASE_PLACEHOLDER,
VersionTLS13,
VersionTLS12,
VersionTLS11,
VersionTLS10,
}},
&UtlsCompressCertExtension{[]CertCompressionAlgo{
CertCompressionBrotli,
}},
&ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
&UtlsGREASEExtension{},
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
},
}, nil
case HelloChrome_100, HelloChrome_102:
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: []byte{
0x00, // compressionNone
},
Extensions: []TLSExtension{
&UtlsGREASEExtension{},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
GREASE_PLACEHOLDER,
X25519,
CurveP256,
CurveP384,
}},
&SupportedPointsExtension{SupportedPoints: []byte{
0x00, // pointFormatUncompressed
}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&StatusRequestExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
}},
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
PskModeDHE,
}},
&SupportedVersionsExtension{[]uint16{
GREASE_PLACEHOLDER,
VersionTLS13,
VersionTLS12,
}},
&UtlsCompressCertExtension{[]CertCompressionAlgo{
CertCompressionBrotli,
}},
&ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
&UtlsGREASEExtension{},
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
},
}, nil
case HelloChrome_106_Shuffle:
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: []byte{
0x00, // compressionNone
},
Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
&UtlsGREASEExtension{},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
GREASE_PLACEHOLDER,
X25519,
CurveP256,
CurveP384,
}},
&SupportedPointsExtension{SupportedPoints: []byte{
0x00, // pointFormatUncompressed
}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&StatusRequestExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
}},
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
PskModeDHE,
}},
&SupportedVersionsExtension{[]uint16{
GREASE_PLACEHOLDER,
VersionTLS13,
VersionTLS12,
}},
&UtlsCompressCertExtension{[]CertCompressionAlgo{
CertCompressionBrotli,
}},
&ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
&UtlsGREASEExtension{},
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
}),
}, nil
// Chrome w/ Post-Quantum Key Agreement
case HelloChrome_115_PQ:
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: []byte{
0x00, // compressionNone
},
Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
&UtlsGREASEExtension{},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
GREASE_PLACEHOLDER,
X25519Kyber768Draft00,
X25519,
CurveP256,
CurveP384,
}},
&SupportedPointsExtension{SupportedPoints: []byte{
0x00, // pointFormatUncompressed
}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&StatusRequestExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
}},
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519Kyber768Draft00},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
PskModeDHE,
}},
&SupportedVersionsExtension{[]uint16{
GREASE_PLACEHOLDER,
VersionTLS13,
VersionTLS12,
}},
&UtlsCompressCertExtension{[]CertCompressionAlgo{
CertCompressionBrotli,
}},
&ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
&UtlsGREASEExtension{},
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
}),
}, nil
case HelloFirefox_55, HelloFirefox_56:
return ClientHelloSpec{
TLSVersMax: VersionTLS12,
TLSVersMin: VersionTLS10,
CipherSuites: []uint16{
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,
FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
},
CompressionMethods: []byte{compressionNone},
Extensions: []TLSExtension{
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{X25519, CurveP256, CurveP384, CurveP521}},
&SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&StatusRequestExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
ECDSAWithP384AndSHA384,
ECDSAWithP521AndSHA512,
PSSWithSHA256,
PSSWithSHA384,
PSSWithSHA512,
PKCS1WithSHA256,
PKCS1WithSHA384,
PKCS1WithSHA512,
ECDSAWithSHA1,
PKCS1WithSHA1},
},
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
},
GetSessionID: nil,
}, nil
case HelloFirefox_63, HelloFirefox_65:
return ClientHelloSpec{
TLSVersMin: VersionTLS10,
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,
FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
},
CompressionMethods: []byte{
compressionNone,
},
Extensions: []TLSExtension{
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
X25519,
CurveP256,
CurveP384,
CurveP521,
CurveID(FakeFFDHE2048),
CurveID(FakeFFDHE3072),
}},
&SupportedPointsExtension{SupportedPoints: []byte{
pointFormatUncompressed,
}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&StatusRequestExtension{},
&KeyShareExtension{[]KeyShare{
{Group: X25519},
{Group: CurveP256},
}},
&SupportedVersionsExtension{[]uint16{
VersionTLS13,
VersionTLS12,
VersionTLS11,
VersionTLS10}},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
ECDSAWithP384AndSHA384,
ECDSAWithP521AndSHA512,
PSSWithSHA256,
PSSWithSHA384,
PSSWithSHA512,
PKCS1WithSHA256,
PKCS1WithSHA384,
PKCS1WithSHA512,
ECDSAWithSHA1,
PKCS1WithSHA1,
}},
&PSKKeyExchangeModesExtension{[]uint8{pskModeDHE}},
&FakeRecordSizeLimitExtension{0x4001},
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
}}, nil
case HelloFirefox_99:
return ClientHelloSpec{
TLSVersMin: VersionTLS10,
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,
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
},
CompressionMethods: []byte{
compressionNone,
},
Extensions: []TLSExtension{
&SNIExtension{}, //server_name
&ExtendedMasterSecretExtension{}, //extended_master_secret
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient}, //extensionRenegotiationInfo
&SupportedCurvesExtension{[]CurveID{ //supported_groups
X25519,
CurveP256,
CurveP384,
CurveP521,
CurveID(FakeFFDHE2048),
CurveID(FakeFFDHE3072),
}},
&SupportedPointsExtension{SupportedPoints: []byte{ //ec_point_formats
pointFormatUncompressed,
}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}, //application_layer_protocol_negotiation
&StatusRequestExtension{},
&FakeDelegatedCredentialsExtension{
SupportedSignatureAlgorithms: []SignatureScheme{ //signature_algorithms
ECDSAWithP256AndSHA256,
ECDSAWithP384AndSHA384,
ECDSAWithP521AndSHA512,
ECDSAWithSHA1,
},
},
&KeyShareExtension{[]KeyShare{
{Group: X25519},
{Group: CurveP256}, //key_share
}},
&SupportedVersionsExtension{[]uint16{
VersionTLS13, //supported_versions
VersionTLS12,
VersionTLS11,
VersionTLS10,
}},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{ //signature_algorithms
ECDSAWithP256AndSHA256,
ECDSAWithP384AndSHA384,
ECDSAWithP521AndSHA512,
PSSWithSHA256,
PSSWithSHA384,
PSSWithSHA512,
PKCS1WithSHA256,
PKCS1WithSHA384,
PKCS1WithSHA512,
ECDSAWithSHA1,
PKCS1WithSHA1,
}},
&PSKKeyExchangeModesExtension{[]uint8{ //psk_key_exchange_modes
PskModeDHE,
}},
&FakeRecordSizeLimitExtension{Limit: 0x4001}, //record_size_limit
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle}, //padding
}}, nil
case HelloFirefox_102:
return ClientHelloSpec{
TLSVersMin: VersionTLS10,
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: []byte{
compressionNone,
},
Extensions: []TLSExtension{
&SNIExtension{}, //server_name
&ExtendedMasterSecretExtension{}, //extended_master_secret
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient}, //extensionRenegotiationInfo
&SupportedCurvesExtension{[]CurveID{ //supported_groups
X25519,
CurveP256,
CurveP384,
CurveP521,
CurveID(FakeFFDHE2048),
CurveID(FakeFFDHE3072),
}},
&SupportedPointsExtension{SupportedPoints: []byte{ //ec_point_formats
pointFormatUncompressed,
}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2"}}, //application_layer_protocol_negotiation
&StatusRequestExtension{},
&FakeDelegatedCredentialsExtension{
SupportedSignatureAlgorithms: []SignatureScheme{ //signature_algorithms
ECDSAWithP256AndSHA256,
ECDSAWithP384AndSHA384,
ECDSAWithP521AndSHA512,
ECDSAWithSHA1,
},
},
&KeyShareExtension{[]KeyShare{
{Group: X25519},
{Group: CurveP256}, //key_share
}},
&SupportedVersionsExtension{[]uint16{
VersionTLS13, //supported_versions
VersionTLS12,
}},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{ //signature_algorithms
ECDSAWithP256AndSHA256,
ECDSAWithP384AndSHA384,
ECDSAWithP521AndSHA512,
PSSWithSHA256,
PSSWithSHA384,
PSSWithSHA512,
PKCS1WithSHA256,
PKCS1WithSHA384,
PKCS1WithSHA512,
ECDSAWithSHA1,
PKCS1WithSHA1,
}},
&PSKKeyExchangeModesExtension{[]uint8{ //psk_key_exchange_modes
PskModeDHE,
}},
&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{},
&ExtendedMasterSecretExtension{},
&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,
TLSVersMin: VersionTLS10,
CipherSuites: []uint16{
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
DISABLED_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
DISABLED_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
TLS_RSA_WITH_AES_256_GCM_SHA384,
TLS_RSA_WITH_AES_128_GCM_SHA256,
DISABLED_TLS_RSA_WITH_AES_256_CBC_SHA256,
TLS_RSA_WITH_AES_128_CBC_SHA256,
TLS_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_AES_128_CBC_SHA,
},
CompressionMethods: []byte{
compressionNone,
},
Extensions: []TLSExtension{
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
PKCS1WithSHA1,
}},
&StatusRequestExtension{},
&NPNExtension{},
&SCTExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "h2-16", "h2-15", "h2-14", "spdy/3.1", "spdy/3", "http/1.1"}},
&SupportedPointsExtension{SupportedPoints: []byte{
pointFormatUncompressed,
}},
&SupportedCurvesExtension{Curves: []CurveID{
X25519,
CurveP256,
CurveP384,
CurveP521,
}},
},
}, nil
case HelloIOS_12_1:
return ClientHelloSpec{
CipherSuites: []uint16{
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
DISABLED_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
DISABLED_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
TLS_RSA_WITH_AES_256_GCM_SHA384,
TLS_RSA_WITH_AES_128_GCM_SHA256,
DISABLED_TLS_RSA_WITH_AES_256_CBC_SHA256,
TLS_RSA_WITH_AES_128_CBC_SHA256,
TLS_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_AES_128_CBC_SHA,
0xc008,
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
},
CompressionMethods: []byte{
compressionNone,
},
Extensions: []TLSExtension{
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
ECDSAWithSHA1,
PSSWithSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
PKCS1WithSHA1,
}},
&StatusRequestExtension{},
&NPNExtension{},
&SCTExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "h2-16", "h2-15", "h2-14", "spdy/3.1", "spdy/3", "http/1.1"}},
&SupportedPointsExtension{SupportedPoints: []byte{
pointFormatUncompressed,
}},
&SupportedCurvesExtension{[]CurveID{
X25519,
CurveP256,
CurveP384,
CurveP521,
}},
},
}, nil
case HelloIOS_13:
return ClientHelloSpec{
CipherSuites: []uint16{
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,
DISABLED_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
DISABLED_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
TLS_RSA_WITH_AES_256_GCM_SHA384,
TLS_RSA_WITH_AES_128_GCM_SHA256,
DISABLED_TLS_RSA_WITH_AES_256_CBC_SHA256,
TLS_RSA_WITH_AES_128_CBC_SHA256,
TLS_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_AES_128_CBC_SHA,
0xc008,
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
},
CompressionMethods: []byte{
0x00, // compressionNone
},
Extensions: []TLSExtension{
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
ECDSAWithSHA1,
PSSWithSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
PKCS1WithSHA1,
}},
&StatusRequestExtension{},
&SCTExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&SupportedPointsExtension{SupportedPoints: []byte{
0x00, // pointFormatUncompressed
}},
&KeyShareExtension{[]KeyShare{
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
PskModeDHE,
}},
&SupportedVersionsExtension{[]uint16{
VersionTLS13,
VersionTLS12,
VersionTLS11,
VersionTLS10,
}},
&SupportedCurvesExtension{[]CurveID{
X25519,
CurveP256,
CurveP384,
CurveP521,
}},
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
},
}, nil
case HelloIOS_14:
return ClientHelloSpec{
// TLSVersMax: VersionTLS12,
// TLSVersMin: VersionTLS10,
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,
DISABLED_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
DISABLED_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
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,
DISABLED_TLS_RSA_WITH_AES_256_CBC_SHA256,
TLS_RSA_WITH_AES_128_CBC_SHA256,
TLS_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_AES_128_CBC_SHA,
0xc008,
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
},
CompressionMethods: []byte{
0x00, // compressionNone
},
Extensions: []TLSExtension{
&UtlsGREASEExtension{},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
CurveID(GREASE_PLACEHOLDER),
X25519,
CurveP256,
CurveP384,
CurveP521,
}},
&SupportedPointsExtension{SupportedPoints: []byte{
0x00, // pointFormatUncompressed
}},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&StatusRequestExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
ECDSAWithSHA1,
PSSWithSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
PKCS1WithSHA1,
}},
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
PskModeDHE,
}},
&SupportedVersionsExtension{[]uint16{
GREASE_PLACEHOLDER,
VersionTLS13,
VersionTLS12,
VersionTLS11,
VersionTLS10,
}},
&UtlsGREASEExtension{},
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
},
}, nil
case HelloAndroid_11_OkHttp:
return ClientHelloSpec{
CipherSuites: []uint16{
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
0xcca9, // Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
0xcca8, // Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)
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: []byte{
0x00, // compressionNone
},
Extensions: []TLSExtension{
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{},
// supported_groups
&SupportedCurvesExtension{[]CurveID{
X25519,
CurveP256,
CurveP384,
}},
&SupportedPointsExtension{SupportedPoints: []byte{
0x00, // pointFormatUncompressed
}},
&StatusRequestExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
PKCS1WithSHA1,
}},
},
}, 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{},
&ExtendedMasterSecretExtension{},
&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{},
&ExtendedMasterSecretExtension{},
&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{},
&ExtendedMasterSecretExtension{},
&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{},
&ExtendedMasterSecretExtension{},
&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{},
&ExtendedMasterSecretExtension{},
&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
case HelloChrome_100_PSK:
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: []byte{
0x00, // compressionNone
},
Extensions: []TLSExtension{
&UtlsGREASEExtension{},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
GREASE_PLACEHOLDER,
X25519,
CurveP256,
CurveP384,
}},
&SupportedPointsExtension{SupportedPoints: []byte{
0x00, // pointFormatUncompressed
}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&StatusRequestExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
}},
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
PskModeDHE,
}},
&SupportedVersionsExtension{[]uint16{
GREASE_PLACEHOLDER,
VersionTLS13,
VersionTLS12,
}},
&UtlsCompressCertExtension{[]CertCompressionAlgo{
CertCompressionBrotli,
}},
&ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
&UtlsGREASEExtension{},
&UtlsPreSharedKeyExtension{},
},
}, nil
case HelloChrome_112_PSK_Shuf:
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: []byte{
0x00, // compressionNone
},
Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
&UtlsGREASEExtension{},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
GREASE_PLACEHOLDER,
X25519,
CurveP256,
CurveP384,
}},
&SupportedPointsExtension{SupportedPoints: []byte{
0x00, // pointFormatUncompressed
}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&StatusRequestExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
}},
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
PskModeDHE,
}},
&SupportedVersionsExtension{[]uint16{
GREASE_PLACEHOLDER,
VersionTLS13,
VersionTLS12,
}},
&UtlsCompressCertExtension{[]CertCompressionAlgo{
CertCompressionBrotli,
}},
&ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
&UtlsGREASEExtension{},
&UtlsPreSharedKeyExtension{},
}),
}, nil
case HelloChrome_114_Padding_PSK_Shuf:
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: []byte{
0x00, // compressionNone
},
Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
&UtlsGREASEExtension{},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
GREASE_PLACEHOLDER,
X25519,
CurveP256,
CurveP384,
}},
&SupportedPointsExtension{SupportedPoints: []byte{
0x00, // pointFormatUncompressed
}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&StatusRequestExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
}},
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
PskModeDHE,
}},
&SupportedVersionsExtension{[]uint16{
GREASE_PLACEHOLDER,
VersionTLS13,
VersionTLS12,
}},
&UtlsCompressCertExtension{[]CertCompressionAlgo{
CertCompressionBrotli,
}},
&ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
&UtlsGREASEExtension{},
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
&UtlsPreSharedKeyExtension{},
}),
}, nil
// Chrome w/ Post-Quantum Key Agreement
case HelloChrome_115_PQ_PSK:
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: []byte{
0x00, // compressionNone
},
Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
&UtlsGREASEExtension{},
&SNIExtension{},
&ExtendedMasterSecretExtension{},
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
GREASE_PLACEHOLDER,
X25519Kyber768Draft00,
X25519,
CurveP256,
CurveP384,
}},
&SupportedPointsExtension{SupportedPoints: []byte{
0x00, // pointFormatUncompressed
}},
&SessionTicketExtension{},
&ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
&StatusRequestExtension{},
&SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
ECDSAWithP256AndSHA256,
PSSWithSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PSSWithSHA384,
PKCS1WithSHA384,
PSSWithSHA512,
PKCS1WithSHA512,
}},
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519Kyber768Draft00},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
PskModeDHE,
}},
&SupportedVersionsExtension{[]uint16{
GREASE_PLACEHOLDER,
VersionTLS13,
VersionTLS12,
}},
&UtlsCompressCertExtension{[]CertCompressionAlgo{
CertCompressionBrotli,
}},
&ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
&UtlsGREASEExtension{},
&UtlsPreSharedKeyExtension{},
}),
}, nil
default:
if id.Client == helloRandomized || id.Client == helloRandomizedALPN || id.Client == helloRandomizedNoALPN {
// Use empty values as they can be filled later by UConn.ApplyPreset or manually.
return generateRandomizedSpec(&id, "", nil)
}
return ClientHelloSpec{}, fmt.Errorf("%w: %s", ErrUnknownClientHelloID, id.Str())
}
}
// ShuffleChromeTLSExtensions shuffles the extensions in the ClientHelloSpec to avoid ossification.
// It shuffles every extension except GREASE, padding and pre_shared_key extensions.
//
// This feature was first introduced by Chrome 106.
func ShuffleChromeTLSExtensions(exts []TLSExtension) []TLSExtension {
// unshufCheck checks if the exts[idx] is a GREASE/padding/pre_shared_key extension,
// and returns true on success. For these extensions are considered positionally invariant.
var skipShuf = func(idx int, exts []TLSExtension) bool {
switch exts[idx].(type) {
case *UtlsGREASEExtension, *UtlsPaddingExtension, PreSharedKeyExtension:
return true
default:
return false
}
}
// Shuffle other extensions
rand.Shuffle(len(exts), func(i, j int) {
if skipShuf(i, exts) || skipShuf(j, exts) {
return // do not shuffle some of the extensions
}
exts[i], exts[j] = exts[j], exts[i]
})
return exts
}
func (uconn *UConn) applyPresetByID(id ClientHelloID) (err error) {
var spec ClientHelloSpec
uconn.ClientHelloID = id
// choose/generate the spec
switch id.Client {
case helloRandomized, helloRandomizedNoALPN, helloRandomizedALPN:
spec, err = uconn.generateRandomizedSpec()
if err != nil {
return err
}
case helloCustom:
return nil
default:
spec, err = UTLSIdToSpec(id)
if err != nil {
return err
}
}
return uconn.ApplyPreset(&spec)
}
// ApplyPreset should only be used in conjunction with HelloCustom to apply custom specs.
// Fields of TLSExtensions that are slices/pointers are shared across different connections with
// same ClientHelloSpec. It is advised to use different specs and avoid any shared state.
func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error {
var err error
err = uconn.SetTLSVers(p.TLSVersMin, p.TLSVersMax, p.Extensions)
if err != nil {
return err
}
privateHello, clientKeySharePrivate, err := uconn.makeClientHelloForApplyPreset()
if err != nil {
return err
}
uconn.HandshakeState.Hello = privateHello.getPublicPtr()
if ecdheKey, ok := clientKeySharePrivate.(*ecdh.PrivateKey); ok {
uconn.HandshakeState.State13.EcdheKey = ecdheKey
} else if kemKey, ok := clientKeySharePrivate.(*kemPrivateKey); ok {
uconn.HandshakeState.State13.KEMKey = kemKey.ToPublic()
}
uconn.HandshakeState.State13.KeySharesParams = NewKeySharesParameters()
hello := uconn.HandshakeState.Hello
switch len(hello.Random) {
case 0:
hello.Random = make([]byte, 32)
_, err := io.ReadFull(uconn.config.rand(), hello.Random)
if err != nil {
return errors.New("tls: short read from Rand: " + err.Error())
}
case 32:
// carry on
default:
return errors.New("ClientHello expected length: 32 bytes. Got: " +
strconv.Itoa(len(hello.Random)) + " bytes")
}
if len(hello.CompressionMethods) == 0 {
hello.CompressionMethods = []uint8{compressionNone}
}
// Currently, GREASE is assumed to come from BoringSSL
grease_bytes := make([]byte, 2*ssl_grease_last_index)
grease_extensions_seen := 0
_, err = io.ReadFull(uconn.config.rand(), grease_bytes)
if err != nil {
return errors.New("tls: short read from Rand: " + err.Error())
}
for i := range uconn.greaseSeed {
uconn.greaseSeed[i] = binary.LittleEndian.Uint16(grease_bytes[2*i : 2*i+2])
}
if GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_extension1) == GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_extension2) {
uconn.greaseSeed[ssl_grease_extension2] ^= 0x1010
}
hello.CipherSuites = make([]uint16, len(p.CipherSuites))
copy(hello.CipherSuites, p.CipherSuites)
for i := range hello.CipherSuites {
if isGREASEUint16(hello.CipherSuites[i]) { // just in case the user set a GREASE value instead of unGREASEd
hello.CipherSuites[i] = GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_cipher)
}
}
var sessionID [32]byte
_, err = io.ReadFull(uconn.config.rand(), sessionID[:])
if err != nil {
return err
}
uconn.HandshakeState.Hello.SessionId = sessionID[:]
uconn.Extensions = make([]TLSExtension, len(p.Extensions))
copy(uconn.Extensions, p.Extensions)
// Check whether NPN extension actually exists
var haveNPN bool
// reGrease, and point things to each other
for _, e := range uconn.Extensions {
switch ext := e.(type) {
case *SNIExtension:
if ext.ServerName == "" {
ext.ServerName = uconn.config.ServerName
}
case *UtlsGREASEExtension:
switch grease_extensions_seen {
case 0:
ext.Value = GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_extension1)
case 1:
ext.Value = GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_extension2)
ext.Body = []byte{0}
default:
return errors.New("at most 2 grease extensions are supported")
}
grease_extensions_seen += 1
case *SupportedCurvesExtension:
for i := range ext.Curves {
if isGREASEUint16(uint16(ext.Curves[i])) {
ext.Curves[i] = CurveID(GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_group))
}
}
case *KeyShareExtension:
preferredCurveIsSet := false
for i := range ext.KeyShares {
curveID := ext.KeyShares[i].Group
if isGREASEUint16(uint16(curveID)) { // just in case the user set a GREASE value instead of unGREASEd
ext.KeyShares[i].Group = CurveID(GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_group))
continue
}
if len(ext.KeyShares[i].Data) > 1 {
continue
}
if scheme := curveIdToCirclScheme(curveID); scheme != nil {
pk, sk, err := generateKemKeyPair(scheme, curveID, uconn.config.rand())
if err != nil {
return fmt.Errorf("HRR generateKemKeyPair %s: %w",
scheme.Name(), err)
}
packedPk, err := pk.MarshalBinary()
if err != nil {
return fmt.Errorf("HRR pack circl public key %s: %w",
scheme.Name(), err)
}
uconn.HandshakeState.State13.KeySharesParams.AddKemKeypair(curveID, sk.secretKey, pk)
ext.KeyShares[i].Data = packedPk
if !preferredCurveIsSet {
// only do this once for the first non-grease curve
uconn.HandshakeState.State13.KEMKey = sk.ToPublic()
preferredCurveIsSet = true
}
} else {
ecdheKey, err := generateECDHEKey(uconn.config.rand(), curveID)
if err != nil {
return fmt.Errorf("unsupported Curve in KeyShareExtension: %v."+
"To mimic it, fill the Data(key) field manually", curveID)
}
uconn.HandshakeState.State13.KeySharesParams.AddEcdheKeypair(curveID, ecdheKey, ecdheKey.PublicKey())
ext.KeyShares[i].Data = ecdheKey.PublicKey().Bytes()
if !preferredCurveIsSet {
// only do this once for the first non-grease curve
uconn.HandshakeState.State13.EcdheKey = ecdheKey
preferredCurveIsSet = true
}
}
}
case *SupportedVersionsExtension:
for i := range ext.Versions {
if isGREASEUint16(ext.Versions[i]) { // just in case the user set a GREASE value instead of unGREASEd
ext.Versions[i] = GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_version)
}
}
case *NPNExtension:
haveNPN = true
}
}
// The default golang behavior in makeClientHello always sets NextProtoNeg if NextProtos is set,
// but NextProtos is also used by ALPN and our spec nmay not actually have a NPN extension
hello.NextProtoNeg = haveNPN
err = uconn.sessionController.syncSessionExts()
if err != nil {
return err
}
return nil
}
func (uconn *UConn) generateRandomizedSpec() (ClientHelloSpec, error) {
return generateRandomizedSpec(&uconn.ClientHelloID, uconn.serverName, uconn.config.NextProtos)
}
func generateRandomizedSpec(
id *ClientHelloID,
serverName string,
nextProtos []string,
) (ClientHelloSpec, error) {
p := ClientHelloSpec{}
if id.Seed == nil {
seed, err := NewPRNGSeed()
if err != nil {
return p, err
}
id.Seed = seed
}
r, err := newPRNGWithSeed(id.Seed)
if err != nil {
return p, err
}
if id.Weights == nil {
id.Weights = &DefaultWeights
}
var WithALPN bool
switch id.Client {
case helloRandomizedALPN:
WithALPN = true
case helloRandomizedNoALPN:
WithALPN = false
case helloRandomized:
if r.FlipWeightedCoin(id.Weights.Extensions_Append_ALPN) {
WithALPN = true
} else {
WithALPN = false
}
default:
return p, fmt.Errorf("using non-randomized ClientHelloID %v to generate randomized spec", id.Client)
}
p.CipherSuites = make([]uint16, len(defaultCipherSuites))
copy(p.CipherSuites, defaultCipherSuites)
shuffledSuites, err := shuffledCiphers(r)
if err != nil {
return p, err
}
if r.FlipWeightedCoin(id.Weights.TLSVersMax_Set_VersionTLS13) {
p.TLSVersMin = VersionTLS10
p.TLSVersMax = VersionTLS13
tls13ciphers := make([]uint16, len(defaultCipherSuitesTLS13))
copy(tls13ciphers, defaultCipherSuitesTLS13)
r.rand.Shuffle(len(tls13ciphers), func(i, j int) {
tls13ciphers[i], tls13ciphers[j] = tls13ciphers[j], tls13ciphers[i]
})
// appending TLS 1.3 ciphers before TLS 1.2, since that's what popular implementations do
shuffledSuites = append(tls13ciphers, shuffledSuites...)
// TLS 1.3 forbids RC4 in any configurations
shuffledSuites = removeRC4Ciphers(shuffledSuites)
} else {
p.TLSVersMin = VersionTLS10
p.TLSVersMax = VersionTLS12
}
p.CipherSuites = removeRandomCiphers(r, shuffledSuites, id.Weights.CipherSuites_Remove_RandomCiphers)
sni := SNIExtension{serverName}
sessionTicket := SessionTicketExtension{}
sigAndHashAlgos := []SignatureScheme{
ECDSAWithP256AndSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PKCS1WithSHA384,
PKCS1WithSHA1,
PKCS1WithSHA512,
}
if r.FlipWeightedCoin(id.Weights.SigAndHashAlgos_Append_ECDSAWithSHA1) {
sigAndHashAlgos = append(sigAndHashAlgos, ECDSAWithSHA1)
}
if r.FlipWeightedCoin(id.Weights.SigAndHashAlgos_Append_ECDSAWithP521AndSHA512) {
sigAndHashAlgos = append(sigAndHashAlgos, ECDSAWithP521AndSHA512)
}
if r.FlipWeightedCoin(id.Weights.SigAndHashAlgos_Append_PSSWithSHA256) || p.TLSVersMax == VersionTLS13 {
// https://tools.ietf.org/html/rfc8446 says "...RSASSA-PSS (which is mandatory in TLS 1.3)..."
sigAndHashAlgos = append(sigAndHashAlgos, PSSWithSHA256)
if r.FlipWeightedCoin(id.Weights.SigAndHashAlgos_Append_PSSWithSHA384_PSSWithSHA512) {
// these usually go together
sigAndHashAlgos = append(sigAndHashAlgos, PSSWithSHA384)
sigAndHashAlgos = append(sigAndHashAlgos, PSSWithSHA512)
}
}
r.rand.Shuffle(len(sigAndHashAlgos), func(i, j int) {
sigAndHashAlgos[i], sigAndHashAlgos[j] = sigAndHashAlgos[j], sigAndHashAlgos[i]
})
sigAndHash := SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: sigAndHashAlgos}
status := StatusRequestExtension{}
sct := SCTExtension{}
ems := ExtendedMasterSecretExtension{}
points := SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}}
curveIDs := []CurveID{}
if r.FlipWeightedCoin(id.Weights.CurveIDs_Append_X25519) || p.TLSVersMax == VersionTLS13 {
curveIDs = append(curveIDs, X25519)
}
curveIDs = append(curveIDs, CurveP256, CurveP384)
if r.FlipWeightedCoin(id.Weights.CurveIDs_Append_CurveP521) {
curveIDs = append(curveIDs, CurveP521)
}
curves := SupportedCurvesExtension{curveIDs}
padding := UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle}
reneg := RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient}
p.Extensions = []TLSExtension{
&sni,
&sessionTicket,
&sigAndHash,
&points,
&curves,
}
if WithALPN {
if len(nextProtos) == 0 {
// if user didn't specify alpn yet, choose something popular
nextProtos = []string{"h2", "http/1.1"}
}
alpn := ALPNExtension{AlpnProtocols: nextProtos}
p.Extensions = append(p.Extensions, &alpn)
}
if r.FlipWeightedCoin(id.Weights.Extensions_Append_Padding) || p.TLSVersMax == VersionTLS13 {
// always include for TLS 1.3, since TLS 1.3 ClientHellos are often over 256 bytes
// and that's when padding is required to work around buggy middleboxes
p.Extensions = append(p.Extensions, &padding)
}
if r.FlipWeightedCoin(id.Weights.Extensions_Append_Status) {
p.Extensions = append(p.Extensions, &status)
}
if r.FlipWeightedCoin(id.Weights.Extensions_Append_SCT) {
p.Extensions = append(p.Extensions, &sct)
}
if r.FlipWeightedCoin(id.Weights.Extensions_Append_Reneg) {
p.Extensions = append(p.Extensions, &reneg)
}
if r.FlipWeightedCoin(id.Weights.Extensions_Append_EMS) {
p.Extensions = append(p.Extensions, &ems)
}
if p.TLSVersMax == VersionTLS13 {
ks := KeyShareExtension{[]KeyShare{
{Group: X25519}, // the key for the group will be generated later
}}
if r.FlipWeightedCoin(id.Weights.FirstKeyShare_Set_CurveP256) {
// do not ADD second keyShare because crypto/tls does not support multiple ecdheParams
// TODO: add it back when they implement multiple keyShares, or implement it oursevles
// ks.KeyShares = append(ks.KeyShares, KeyShare{Group: CurveP256})
ks.KeyShares[0].Group = CurveP256
}
pskExchangeModes := PSKKeyExchangeModesExtension{[]uint8{pskModeDHE}}
supportedVersionsExt := SupportedVersionsExtension{
Versions: makeSupportedVersions(p.TLSVersMin, p.TLSVersMax),
}
p.Extensions = append(p.Extensions, &ks, &pskExchangeModes, &supportedVersionsExt)
// Randomly add an ALPS extension. ALPS is TLS 1.3-only and may only
// appear when an ALPN extension is present
// (https://datatracker.ietf.org/doc/html/draft-vvv-tls-alps-01#section-3).
// ALPS is a draft specification at this time, but appears in
// Chrome/BoringSSL.
if WithALPN {
// ALPS is a new addition to generateRandomizedSpec. Use a salted
// seed to create a new, independent PRNG, so that a seed used
// with the previous version of generateRandomizedSpec will
// produce the exact same spec as long as ALPS isn't selected.
r, err := newPRNGWithSaltedSeed(id.Seed, "ALPS")
if err != nil {
return p, err
}
if r.FlipWeightedCoin(id.Weights.Extensions_Append_ALPS) {
// As with the ALPN case above, default to something popular
// (unlike ALPN, ALPS can't yet be specified in uconn.config).
alps := &ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}}
p.Extensions = append(p.Extensions, alps)
}
}
// TODO: randomly add DelegatedCredentialsExtension, once it is
// sufficiently popular.
}
r.rand.Shuffle(len(p.Extensions), func(i, j int) {
p.Extensions[i], p.Extensions[j] = p.Extensions[j], p.Extensions[i]
})
return p, nil
}
func removeRandomCiphers(r *prng, s []uint16, maxRemovalProbability float64) []uint16 {
// removes elements in place
// probability to remove increases for further elements
// never remove first cipher
if len(s) <= 1 {
return s
}
// remove random elements
floatLen := float64(len(s))
sliceLen := len(s)
for i := 1; i < sliceLen; i++ {
if r.FlipWeightedCoin(maxRemovalProbability * float64(i) / floatLen) {
s = append(s[:i], s[i+1:]...)
sliceLen--
i--
}
}
return s[:sliceLen]
}
func shuffledCiphers(r *prng) ([]uint16, error) {
ciphers := make(sortableCiphers, len(cipherSuites))
perm := r.Perm(len(cipherSuites))
for i, suite := range cipherSuites {
ciphers[i] = sortableCipher{suite: suite.id,
isObsolete: ((suite.flags & suiteTLS12) == 0),
randomTag: perm[i]}
}
sort.Sort(ciphers)
return ciphers.GetCiphers(), nil
}
type sortableCipher struct {
isObsolete bool
randomTag int
suite uint16
}
type sortableCiphers []sortableCipher
func (ciphers sortableCiphers) Len() int {
return len(ciphers)
}
func (ciphers sortableCiphers) Less(i, j int) bool {
if ciphers[i].isObsolete && !ciphers[j].isObsolete {
return false
}
if ciphers[j].isObsolete && !ciphers[i].isObsolete {
return true
}
return ciphers[i].randomTag < ciphers[j].randomTag
}
func (ciphers sortableCiphers) Swap(i, j int) {
ciphers[i], ciphers[j] = ciphers[j], ciphers[i]
}
func (ciphers sortableCiphers) GetCiphers() []uint16 {
cipherIDs := make([]uint16, len(ciphers))
for i := range ciphers {
cipherIDs[i] = ciphers[i].suite
}
return cipherIDs
}
func removeRC4Ciphers(s []uint16) []uint16 {
// removes elements in place
sliceLen := len(s)
for i := 0; i < sliceLen; i++ {
cipher := s[i]
if cipher == TLS_ECDHE_ECDSA_WITH_RC4_128_SHA ||
cipher == TLS_ECDHE_RSA_WITH_RC4_128_SHA ||
cipher == TLS_RSA_WITH_RC4_128_SHA {
s = append(s[:i], s[i+1:]...)
sliceLen--
i--
}
}
return s[:sliceLen]
}