| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794 |
- // 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/rand"
- "crypto/sha256"
- "encoding/binary"
- "errors"
- "fmt"
- "io"
- "math/big"
- "sort"
- "strconv"
- "time"
- )
- 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,
- }},
- &GenericExtension{id: fakeCertCompressionAlgs, data: []byte{02, 00, 02}},
- &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:
- 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}},
- &GenericExtension{id: fakeRecordSizeLimit, data: []byte{0x40, 0x01}},
- &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
- default:
- return ClientHelloSpec{}, errors.New("ClientHello ID " + id.Str() + " is unknown")
- }
- }
- func (uconn *UConn) applyPresetByID(id ClientHelloID) (err error) {
- var spec ClientHelloSpec
- // choose/generate the spec
- switch id {
- case HelloRandomized:
- if tossBiasedCoin(0.5) {
- return uconn.applyPresetByID(HelloRandomizedALPN)
- } else {
- return uconn.applyPresetByID(HelloRandomizedNoALPN)
- }
- case HelloRandomizedALPN:
- spec, err = uconn.generateRandomizedSpec(true)
- if err != nil {
- return err
- }
- case HelloRandomizedNoALPN:
- spec, err = uconn.generateRandomizedSpec(false)
- if err != nil {
- return err
- }
- case HelloCustom:
- return nil
- default:
- spec, err = utlsIdToSpec(id)
- if err != nil {
- return err
- }
- }
- uconn.clientHelloID = id
- 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)
- 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 uconn.greaseSeed[ssl_grease_extension1] == 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)
- // 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:
- 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)
- }
- }
- }
- }
- return nil
- }
- func (uconn *UConn) generateRandomizedSpec(WithALPN bool) (ClientHelloSpec, error) {
- p := ClientHelloSpec{}
- p.CipherSuites = make([]uint16, len(defaultCipherSuites()))
- copy(p.CipherSuites, defaultCipherSuites())
- shuffledSuites, err := shuffledCiphers()
- if err != nil {
- return p, err
- }
- if tossBiasedCoin(0.4) {
- p.TLSVersMin = VersionTLS10
- p.TLSVersMax = VersionTLS13
- tls13ciphers := defaultCipherSuitesTLS13()
- err = shuffleUInts16(tls13ciphers)
- if err != nil {
- return p, err
- }
- // 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(shuffledSuites, 0.4)
- sni := SNIExtension{uconn.config.ServerName}
- sessionTicket := SessionTicketExtension{Session: uconn.HandshakeState.Session}
- sigAndHashAlgos := []SignatureScheme{
- ECDSAWithP256AndSHA256,
- PKCS1WithSHA256,
- ECDSAWithP384AndSHA384,
- PKCS1WithSHA384,
- PKCS1WithSHA1,
- PKCS1WithSHA512,
- }
- if tossBiasedCoin(0.63) {
- sigAndHashAlgos = append(sigAndHashAlgos, ECDSAWithSHA1)
- }
- if tossBiasedCoin(0.59) {
- sigAndHashAlgos = append(sigAndHashAlgos, ECDSAWithP521AndSHA512)
- }
- if tossBiasedCoin(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 tossBiasedCoin(0.9) {
- // these usually go together
- sigAndHashAlgos = append(sigAndHashAlgos, PSSWithSHA384)
- sigAndHashAlgos = append(sigAndHashAlgos, PSSWithSHA512)
- }
- }
- err = shuffleSignatures(sigAndHashAlgos)
- if err != nil {
- return p, err
- }
- sigAndHash := SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: sigAndHashAlgos}
- status := StatusRequestExtension{}
- sct := SCTExtension{}
- ems := UtlsExtendedMasterSecretExtension{}
- points := SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}}
- curveIDs := []CurveID{}
- if tossBiasedCoin(0.71) || p.TLSVersMax == VersionTLS13 {
- curveIDs = append(curveIDs, X25519)
- }
- curveIDs = append(curveIDs, CurveP256, CurveP384)
- if tossBiasedCoin(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 tossBiasedCoin(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 tossBiasedCoin(0.74) {
- p.Extensions = append(p.Extensions, &status)
- }
- if tossBiasedCoin(0.46) {
- p.Extensions = append(p.Extensions, &sct)
- }
- if tossBiasedCoin(0.75) {
- p.Extensions = append(p.Extensions, &reneg)
- }
- if tossBiasedCoin(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 tossBiasedCoin(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)
- }
- err = shuffleTLSExtensions(p.Extensions)
- if err != nil {
- return p, err
- }
- err = uconn.SetTLSVers(p.TLSVersMin, p.TLSVersMax)
- if err != nil {
- return p, err
- }
- return p, nil
- }
- func tossBiasedCoin(probability float32) bool {
- // probability is expected to be in [0,1]
- // this function never returns errors for ease of use
- const precision = 0xffff
- threshold := float32(precision) * probability
- value, err := getRandInt(precision)
- if err != nil {
- // I doubt that this code will ever actually be used, as other functions are expected to complain
- // about used source of entropy. Nonetheless, this is more than enough for given purpose
- return ((time.Now().Unix() & 1) == 0)
- }
- if float32(value) <= threshold {
- return true
- } else {
- return false
- }
- }
- func removeRandomCiphers(s []uint16, maxRemovalProbability float32) []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 := float32(len(s))
- sliceLen := len(s)
- for i := 1; i < sliceLen; i++ {
- if tossBiasedCoin(maxRemovalProbability * float32(i) / floatLen) {
- s = append(s[:i], s[i+1:]...)
- sliceLen--
- i--
- }
- }
- return s[:sliceLen]
- }
- 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]
- }
- func getRandInt(max int) (int, error) {
- bigInt, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
- return int(bigInt.Int64()), err
- }
- func getRandPerm(n int) ([]int, error) {
- permArray := make([]int, n)
- for i := 1; i < n; i++ {
- j, err := getRandInt(i + 1)
- if err != nil {
- return permArray, err
- }
- permArray[i] = permArray[j]
- permArray[j] = i
- }
- return permArray, nil
- }
- func shuffledCiphers() ([]uint16, error) {
- ciphers := make(sortableCiphers, len(cipherSuites))
- perm, err := getRandPerm(len(cipherSuites))
- if err != nil {
- return nil, err
- }
- 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
- }
- // so much for generics
- func shuffleTLSExtensions(s []TLSExtension) error {
- // shuffles array in place
- perm, err := getRandPerm(len(s))
- if err != nil {
- return err
- }
- for i := range s {
- s[i], s[perm[i]] = s[perm[i]], s[i]
- }
- return nil
- }
- // so much for generics
- func shuffleSignatures(s []SignatureScheme) error {
- // shuffles array in place
- perm, err := getRandPerm(len(s))
- if err != nil {
- return err
- }
- for i := range s {
- s[i], s[perm[i]] = s[perm[i]], s[i]
- }
- return nil
- }
- // so much for generics
- func shuffleUInts16(s []uint16) error {
- // shuffles array in place
- perm, err := getRandPerm(len(s))
- if err != nil {
- return err
- }
- for i := range s {
- s[i], s[perm[i]] = s[perm[i]], s[i]
- }
- return nil
- }
|