Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
vendor.github.com.refraction-networking.utls.u_parrots.go Maven / Gradle / Ivy
// 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/sha256"
"encoding/binary"
"errors"
"fmt"
"io"
"sort"
"strconv"
)
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{},
&UtlsExtendedMasterSecretExtension{},
&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{},
&UtlsExtendedMasterSecretExtension{},
&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,
}},
&FakeCertCompressionAlgsExtension{[]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{},
&UtlsExtendedMasterSecretExtension{},
&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,
}},
&FakeCertCompressionAlgsExtension{[]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{},
&UtlsExtendedMasterSecretExtension{},
&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,
}},
&FakeCertCompressionAlgsExtension{[]CertCompressionAlgo{
CertCompressionBrotli,
}},
&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{},
&UtlsExtendedMasterSecretExtension{},
&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{},
&UtlsExtendedMasterSecretExtension{},
&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 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{},
&UtlsExtendedMasterSecretExtension{},
&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{},
&UtlsExtendedMasterSecretExtension{},
&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
default:
return ClientHelloSpec{}, errors.New("ClientHello ID " + id.Str() + " is unknown")
}
}
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, ecdheParams, err := uconn.makeClientHello()
if err != nil {
return err
}
uconn.HandshakeState.Hello = privateHello.getPublicPtr()
uconn.HandshakeState.State13.EcdheParams = ecdheParams
hello := uconn.HandshakeState.Hello
session := uconn.HandshakeState.Session
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.CipherSuites) == 0 {
hello.CipherSuites = defaultCipherSuites()
}
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 hello.CipherSuites[i] == GREASE_PLACEHOLDER {
hello.CipherSuites[i] = GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_cipher)
}
}
uconn.GetSessionID = p.GetSessionID
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 *SessionTicketExtension:
if session == nil && uconn.config.ClientSessionCache != nil {
cacheKey := clientSessionCacheKey(uconn.RemoteAddr(), uconn.config)
session, _ = uconn.config.ClientSessionCache.Get(cacheKey)
// TODO: use uconn.loadSession(hello.getPrivateObj()) to support TLS 1.3 PSK-style resumption
}
err := uconn.SetSessionState(session)
if err != nil {
return err
}
case *SupportedCurvesExtension:
for i := range ext.Curves {
if ext.Curves[i] == GREASE_PLACEHOLDER {
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 curveID == GREASE_PLACEHOLDER {
ext.KeyShares[i].Group = CurveID(GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_group))
continue
}
if len(ext.KeyShares[i].Data) > 1 {
continue
}
ecdheParams, err := generateECDHEParameters(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)
}
ext.KeyShares[i].Data = ecdheParams.PublicKey()
if !preferredCurveIsSet {
// only do this once for the first non-grease curve
uconn.HandshakeState.State13.EcdheParams = ecdheParams
preferredCurveIsSet = true
}
}
case *SupportedVersionsExtension:
for i := range ext.Versions {
if ext.Versions[i] == GREASE_PLACEHOLDER {
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
return nil
}
func (uconn *UConn) generateRandomizedSpec() (ClientHelloSpec, error) {
p := ClientHelloSpec{}
if uconn.ClientHelloID.Seed == nil {
seed, err := NewPRNGSeed()
if err != nil {
return p, err
}
uconn.ClientHelloID.Seed = seed
}
r, err := newPRNGWithSeed(uconn.ClientHelloID.Seed)
if err != nil {
return p, err
}
id := uconn.ClientHelloID
var WithALPN bool
switch id.Client {
case helloRandomizedALPN:
WithALPN = true
case helloRandomizedNoALPN:
WithALPN = false
case helloRandomized:
if r.FlipWeightedCoin(0.7) {
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(0.4) {
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, 0.4)
sni := SNIExtension{uconn.config.ServerName}
sessionTicket := SessionTicketExtension{Session: uconn.HandshakeState.Session}
sigAndHashAlgos := []SignatureScheme{
ECDSAWithP256AndSHA256,
PKCS1WithSHA256,
ECDSAWithP384AndSHA384,
PKCS1WithSHA384,
PKCS1WithSHA1,
PKCS1WithSHA512,
}
if r.FlipWeightedCoin(0.63) {
sigAndHashAlgos = append(sigAndHashAlgos, ECDSAWithSHA1)
}
if r.FlipWeightedCoin(0.59) {
sigAndHashAlgos = append(sigAndHashAlgos, ECDSAWithP521AndSHA512)
}
if r.FlipWeightedCoin(0.51) || 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(0.9) {
// 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 := UtlsExtendedMasterSecretExtension{}
points := SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}}
curveIDs := []CurveID{}
if r.FlipWeightedCoin(0.71) || p.TLSVersMax == VersionTLS13 {
curveIDs = append(curveIDs, X25519)
}
curveIDs = append(curveIDs, CurveP256, CurveP384)
if r.FlipWeightedCoin(0.46) {
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(uconn.config.NextProtos) == 0 {
// if user didn't specify alpn yet, choose something popular
uconn.config.NextProtos = []string{"h2", "http/1.1"}
}
alpn := ALPNExtension{AlpnProtocols: uconn.config.NextProtos}
p.Extensions = append(p.Extensions, &alpn)
}
if r.FlipWeightedCoin(0.62) || 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(0.74) {
p.Extensions = append(p.Extensions, &status)
}
if r.FlipWeightedCoin(0.46) {
p.Extensions = append(p.Extensions, &sct)
}
if r.FlipWeightedCoin(0.75) {
p.Extensions = append(p.Extensions, &reneg)
}
if r.FlipWeightedCoin(0.77) {
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(0.25) {
// 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)
}
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]
}