mirror of
https://github.com/refraction-networking/utls.git
synced 2025-04-01 19:17:36 +03:00
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.
This commit is contained in:
parent
6663294864
commit
45e7f1de14
3 changed files with 429 additions and 67 deletions
14
u_common.go
14
u_common.go
|
@ -582,9 +582,17 @@ var (
|
|||
HelloChrome_102 = ClientHelloID{helloChrome, "102", nil, nil}
|
||||
HelloChrome_106_Shuffle = ClientHelloID{helloChrome, "106", nil, nil} // beta: shuffler enabled starting from 106
|
||||
|
||||
// Chrome with PSK: Chrome start sending this ClientHello after doing TLS 1.3 handshake with the same server.
|
||||
HelloChrome_100_PSK = ClientHelloID{helloChrome, "100_PSK", nil, nil} // beta: PSK extension added. uTLS doesn't fully support PSK. Use at your own risk.
|
||||
HelloChrome_112_PSK_Shuf = ClientHelloID{helloChrome, "112_PSK", nil, nil} // beta: PSK extension added. uTLS doesn't fully support PSK. Use at your own risk.
|
||||
// Chrome w/ PSK: Chrome start sending this ClientHello after doing TLS 1.3 handshake with the same server.
|
||||
// Beta: PSK extension added. However, uTLS doesn't ship with full PSK support.
|
||||
// Use at your own discretion.
|
||||
HelloChrome_100_PSK = ClientHelloID{helloChrome, "100_PSK", nil, nil}
|
||||
HelloChrome_112_PSK_Shuf = ClientHelloID{helloChrome, "112_PSK", nil, nil}
|
||||
HelloChrome_114_Padding_PSK_Shuf = ClientHelloID{helloChrome, "114_PSK", nil, nil}
|
||||
|
||||
// Chrome w/ Post-Quantum Key Agreement
|
||||
// Beta: PQ extension added. However, uTLS doesn't ship with full PQ support. Use at your own discretion.
|
||||
HelloChrome_115_PQ = ClientHelloID{helloChrome, "115_PQ", nil, nil}
|
||||
HelloChrome_115_PQ_PSK = ClientHelloID{helloChrome, "115_PQ_PSK", nil, nil}
|
||||
|
||||
HelloIOS_Auto = HelloIOS_14
|
||||
HelloIOS_11_1 = ClientHelloID{helloIOS, "111", nil, nil} // legacy "111" means 11.1
|
||||
|
|
|
@ -24,6 +24,7 @@ type UConn struct {
|
|||
|
||||
Extensions []TLSExtension
|
||||
ClientHelloID ClientHelloID
|
||||
pskExtension []*FakePreSharedKeyExtension
|
||||
|
||||
ClientHelloBuilt bool
|
||||
HandshakeState PubClientHandshakeState
|
||||
|
@ -43,13 +44,13 @@ type UConn struct {
|
|||
|
||||
// UClient returns a new uTLS client, with behavior depending on clientHelloID.
|
||||
// Config CAN be nil, but make sure to eventually specify ServerName.
|
||||
func UClient(conn net.Conn, config *Config, clientHelloID ClientHelloID) *UConn {
|
||||
func UClient(conn net.Conn, config *Config, clientHelloID ClientHelloID, pskExtension ...*FakePreSharedKeyExtension) *UConn {
|
||||
if config == nil {
|
||||
config = &Config{}
|
||||
}
|
||||
tlsConn := Conn{conn: conn, config: config, isClient: true}
|
||||
handshakeState := PubClientHandshakeState{C: &tlsConn, Hello: &PubClientHelloMsg{}}
|
||||
uconn := UConn{Conn: &tlsConn, ClientHelloID: clientHelloID, HandshakeState: handshakeState}
|
||||
uconn := UConn{Conn: &tlsConn, ClientHelloID: clientHelloID, pskExtension: pskExtension, HandshakeState: handshakeState}
|
||||
uconn.HandshakeState.uconn = &uconn
|
||||
uconn.handshakeFn = uconn.clientHandshake
|
||||
return &uconn
|
||||
|
|
477
u_parrots.go
477
u_parrots.go
|
@ -16,11 +16,24 @@ import (
|
|||
"strconv"
|
||||
)
|
||||
|
||||
var ErrUnknownClientHelloID = errors.New("tls: unknown ClientHelloID")
|
||||
var ErrNotPSKClientHelloID = errors.New("tls: ClientHello does not contain pre_shared_key extension")
|
||||
var ErrPSKExtensionExpected = errors.New("tls: pre_shared_key extension expected when fetching preset ClientHelloSpec")
|
||||
|
||||
// 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, pskExtension ...*FakePreSharedKeyExtension) (ClientHelloSpec, error) {
|
||||
if len(pskExtension) > 1 {
|
||||
return ClientHelloSpec{}, errors.New("tls: at most one FakePreSharedKeyExtensions is allowed")
|
||||
}
|
||||
|
||||
chs, err := utlsIdToSpec(id)
|
||||
if err != nil && errors.Is(err, ErrUnknownClientHelloID) {
|
||||
chs, err = utlsIdToSpecWithPSK(id, pskExtension...)
|
||||
}
|
||||
|
||||
return chs, err
|
||||
}
|
||||
|
||||
func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
|
||||
|
@ -509,7 +522,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
|
|||
&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
|
||||
},
|
||||
}, nil
|
||||
case HelloChrome_100_PSK:
|
||||
case HelloChrome_106_Shuffle:
|
||||
return ClientHelloSpec{
|
||||
CipherSuites: []uint16{
|
||||
GREASE_PLACEHOLDER,
|
||||
|
@ -532,7 +545,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
|
|||
CompressionMethods: []byte{
|
||||
0x00, // compressionNone
|
||||
},
|
||||
Extensions: []TLSExtension{
|
||||
Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
|
||||
&UtlsGREASEExtension{},
|
||||
&SNIExtension{},
|
||||
&ExtendedMasterSecretExtension{},
|
||||
|
@ -577,27 +590,83 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
|
|||
}},
|
||||
&ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
|
||||
&UtlsGREASEExtension{},
|
||||
&FakePreSharedKeyExtension{},
|
||||
},
|
||||
&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 HelloChrome_106_Shuffle:
|
||||
chs, err := utlsIdToSpec(HelloChrome_102)
|
||||
if err != nil {
|
||||
return chs, err
|
||||
}
|
||||
|
||||
// Chrome 107 started shuffling the order of extensions
|
||||
shuffleExtensions(&chs)
|
||||
return chs, err
|
||||
case HelloChrome_112_PSK_Shuf:
|
||||
chs, err := utlsIdToSpec(HelloChrome_100_PSK)
|
||||
if err != nil {
|
||||
return chs, err
|
||||
}
|
||||
|
||||
// Chrome 112 started shuffling the order of extensions
|
||||
shuffleExtensions(&chs)
|
||||
return chs, err
|
||||
case HelloFirefox_55, HelloFirefox_56:
|
||||
return ClientHelloSpec{
|
||||
TLSVersMax: VersionTLS12,
|
||||
|
@ -1931,53 +2000,337 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
|
|||
// Use empty values as they can be filled later by UConn.ApplyPreset or manually.
|
||||
return generateRandomizedSpec(&id, "", nil, nil)
|
||||
}
|
||||
return ClientHelloSpec{}, errors.New("ClientHello ID " + id.Str() + " is unknown")
|
||||
return ClientHelloSpec{}, fmt.Errorf("%w: %s", ErrUnknownClientHelloID, id.Str())
|
||||
}
|
||||
}
|
||||
|
||||
func shuffleExtensions(chs *ClientHelloSpec) error {
|
||||
// Shuffle extensions to avoid fingerprinting -- introduced in Chrome 106
|
||||
var err error = nil
|
||||
|
||||
// unshufCheck checks:
|
||||
// - if the exts[idx] is a GREASE extension, then it should not be shuffled
|
||||
// - if the exts[idx] is a padding/pre_shared_key extension, then it should be the
|
||||
// last extension in the list and should not be shuffled
|
||||
var unshufCheck = func(idx int, exts []TLSExtension) (donotshuf bool, userErr error) {
|
||||
switch exts[idx].(type) {
|
||||
case *UtlsGREASEExtension:
|
||||
donotshuf = true
|
||||
case *UtlsPaddingExtension, *FakePreSharedKeyExtension:
|
||||
donotshuf = true
|
||||
if idx != len(chs.Extensions)-1 {
|
||||
userErr = errors.New("UtlsPaddingExtension or FakePreSharedKeyExtension must be the last extension")
|
||||
}
|
||||
default:
|
||||
donotshuf = false
|
||||
func utlsIdToSpecWithPSK(id ClientHelloID, pskExtension ...*FakePreSharedKeyExtension) (ClientHelloSpec, error) {
|
||||
switch id {
|
||||
case HelloChrome_100_PSK, HelloChrome_112_PSK_Shuf, HelloChrome_114_Padding_PSK_Shuf, HelloChrome_115_PQ_PSK:
|
||||
if len(pskExtension) == 0 || pskExtension[0] == nil {
|
||||
return ClientHelloSpec{}, fmt.Errorf("%w: %s", ErrPSKExtensionExpected, id.Str())
|
||||
}
|
||||
}
|
||||
|
||||
switch id {
|
||||
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{},
|
||||
pskExtension[0],
|
||||
},
|
||||
}, 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{},
|
||||
pskExtension[0],
|
||||
}),
|
||||
}, 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},
|
||||
pskExtension[0],
|
||||
}),
|
||||
}, 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{},
|
||||
pskExtension[0],
|
||||
}),
|
||||
}, 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, *FakePreSharedKeyExtension:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Shuffle other extensions
|
||||
rand.Shuffle(len(chs.Extensions), func(i, j int) {
|
||||
if unshuf, shuferr := unshufCheck(i, chs.Extensions); unshuf {
|
||||
if shuferr != nil {
|
||||
err = shuferr
|
||||
}
|
||||
return
|
||||
rand.Shuffle(len(exts), func(i, j int) {
|
||||
if skipShuf(i, exts) || skipShuf(j, exts) {
|
||||
return // do not shuffle some of the extensions
|
||||
}
|
||||
|
||||
if unshuf, shuferr := unshufCheck(j, chs.Extensions); unshuf {
|
||||
if shuferr != nil {
|
||||
err = shuferr
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
chs.Extensions[i], chs.Extensions[j] = chs.Extensions[j], chs.Extensions[i]
|
||||
exts[i], exts[j] = exts[j], exts[i]
|
||||
})
|
||||
|
||||
return err
|
||||
return exts
|
||||
}
|
||||
|
||||
func (uconn *UConn) applyPresetByID(id ClientHelloID) (err error) {
|
||||
|
@ -1994,7 +2347,7 @@ func (uconn *UConn) applyPresetByID(id ClientHelloID) (err error) {
|
|||
return nil
|
||||
|
||||
default:
|
||||
spec, err = utlsIdToSpec(id)
|
||||
spec, err = UTLSIdToSpec(id, uconn.pskExtension...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue