| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737 |
- // 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"
- "errors"
- "io"
- "math/big"
- "sort"
- "strconv"
- "time"
- )
- func (uconn *UConn) generateClientHelloConfig(id ClientHelloID) error {
- uconn.clientHelloID = id
- switch uconn.clientHelloID {
- case HelloFirefox_56:
- fallthrough
- case HelloFirefox_55:
- return uconn.parrotFirefox_55()
- case HelloAndroid_6_0_Browser:
- return uconn.parrotAndroid_6_0()
- case HelloAndroid_5_1_Browser:
- return uconn.parrotAndroid_5_1()
- case HelloChrome_62:
- fallthrough
- case HelloChrome_58:
- return uconn.parrotChrome_5x(false)
- case HelloChrome_57:
- return uconn.parrotChrome_5x(true)
- case HelloiOSSafari_11_3_1:
- return uconn.parrotiOSSafari_11_3_1()
- case HelloRandomizedALPN:
- return uconn.parrotRandomizedALPN()
- case HelloRandomizedNoALPN:
- return uconn.parrotRandomizedNoALPN()
- case HelloCustom:
- return uconn.parrotCustom()
- // following ClientHello's are aliases, so we call generateClientHelloConfig() again to set the correct id
- case HelloRandomized:
- if tossBiasedCoin(0.5) {
- return uconn.generateClientHelloConfig(HelloRandomizedALPN)
- } else {
- return uconn.generateClientHelloConfig(HelloRandomizedNoALPN)
- }
- case HelloAndroid_Auto:
- return uconn.generateClientHelloConfig(HelloAndroid_6_0_Browser)
- case HelloFirefox_Auto:
- return uconn.generateClientHelloConfig(HelloFirefox_56)
- case HelloChrome_Auto:
- return uconn.generateClientHelloConfig(HelloChrome_62)
- default:
- return errors.New("Unknown ParrotID: " + id.Str())
- }
- }
- // Fills clientHello header(everything but extensions) fields, which are not set explicitly yet, with defaults
- func (uconn *UConn) fillClientHelloHeader() error {
- hello := uconn.HandshakeState.Hello
- if hello.Vers == 0 {
- hello.Vers = VersionTLS12
- }
- 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}
- }
- return nil
- }
- func (uconn *UConn) parrotFirefox_55() error {
- hello := uconn.HandshakeState.Hello
- session := uconn.HandshakeState.Session
- hello.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,
- }
- err := uconn.fillClientHelloHeader()
- if err != nil {
- return err
- }
- sni := SNIExtension{uconn.config.ServerName}
- ems := utlsExtendedMasterSecretExtension{}
- reneg := RenegotiationInfoExtension{renegotiation: RenegotiateOnceAsClient}
- curves := SupportedCurvesExtension{[]CurveID{X25519, CurveP256, CurveP384, CurveP521}}
- points := SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}}
- sessionTicket := SessionTicketExtension{Session: session}
- if session != nil {
- sessionTicket.Session = session
- if len(session.SessionTicket()) > 0 {
- hello.SessionId = make([]byte, 32)
- _, err := io.ReadFull(uconn.config.rand(), hello.SessionId)
- if err != nil {
- return errors.New("tls: short read from Rand: " + err.Error())
- }
- }
- }
- alpn := ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}
- status := StatusRequestExtension{}
- sigAndHash := SignatureAlgorithmsExtension{SignatureAndHashes: []SignatureAndHash{
- {hashSHA256, signatureECDSA},
- {hashSHA384, signatureECDSA},
- {disabledHashSHA512, signatureECDSA},
- fakeRsaPssSha256,
- fakeRsaPssSha384,
- fakeRsaPssSha512,
- {hashSHA256, signatureRSA},
- {hashSHA384, signatureRSA},
- {disabledHashSHA512, signatureRSA},
- {hashSHA1, signatureECDSA},
- {hashSHA1, signatureRSA}},
- }
- padding := utlsPaddingExtension{GetPaddingLen: boringPaddingStyle}
- uconn.Extensions = []TLSExtension{
- &sni,
- &ems,
- &reneg,
- &curves,
- &points,
- &sessionTicket,
- &alpn,
- &status,
- &sigAndHash,
- &padding,
- }
- return nil
- }
- func (uconn *UConn) parrotAndroid_6_0() error {
- hello := uconn.HandshakeState.Hello
- session := uconn.HandshakeState.Session
- hello.CipherSuites = []uint16{
- OLD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
- OLD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
- FAKE_OLD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
- FAKE_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
- 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,
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
- FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
- TLS_RSA_WITH_AES_128_GCM_SHA256,
- TLS_RSA_WITH_AES_256_CBC_SHA,
- TLS_RSA_WITH_AES_128_CBC_SHA,
- TLS_RSA_WITH_3DES_EDE_CBC_SHA,
- FAKE_TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
- }
- err := uconn.fillClientHelloHeader()
- if err != nil {
- return err
- }
- sni := SNIExtension{uconn.config.ServerName}
- ems := utlsExtendedMasterSecretExtension{}
- sessionTicket := SessionTicketExtension{Session: session}
- if session != nil {
- sessionTicket.Session = session
- if len(session.SessionTicket()) > 0 {
- sessionId := sha256.Sum256(session.SessionTicket())
- hello.SessionId = sessionId[:]
- }
- }
- sigAndHash := SignatureAlgorithmsExtension{SignatureAndHashes: []SignatureAndHash{
- {disabledHashSHA512, signatureRSA},
- {disabledHashSHA512, signatureECDSA},
- {hashSHA384, signatureRSA},
- {hashSHA384, signatureECDSA},
- {hashSHA256, signatureRSA},
- {hashSHA256, signatureECDSA},
- {fakeHashSHA224, signatureRSA},
- {fakeHashSHA224, signatureECDSA},
- {hashSHA1, signatureRSA},
- {hashSHA1, signatureECDSA}},
- }
- status := StatusRequestExtension{}
- npn := NPNExtension{}
- sct := SCTExtension{}
- alpn := ALPNExtension{AlpnProtocols: []string{"http/1.1", "spdy/8.1"}}
- points := SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}}
- curves := SupportedCurvesExtension{[]CurveID{CurveP256, CurveP384}}
- padding := utlsPaddingExtension{GetPaddingLen: boringPaddingStyle}
- uconn.Extensions = []TLSExtension{
- &sni,
- &ems,
- &sessionTicket,
- &sigAndHash,
- &status,
- &npn,
- &sct,
- &alpn,
- &points,
- &curves,
- &padding,
- }
- return nil
- }
- func (uconn *UConn) parrotAndroid_5_1() error {
- hello := uconn.HandshakeState.Hello
- session := uconn.HandshakeState.Session
- hello.CipherSuites = []uint16{
- OLD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
- OLD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
- FAKE_OLD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
- FAKE_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
- FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
- TLS_ECDHE_RSA_WITH_RC4_128_SHA,
- TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
- TLS_RSA_WITH_AES_128_GCM_SHA256,
- TLS_RSA_WITH_AES_256_CBC_SHA,
- TLS_RSA_WITH_AES_128_CBC_SHA,
- TLS_RSA_WITH_RC4_128_SHA,
- FAKE_TLS_RSA_WITH_RC4_128_MD5,
- TLS_RSA_WITH_3DES_EDE_CBC_SHA,
- FAKE_TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
- }
- err := uconn.fillClientHelloHeader()
- if err != nil {
- return err
- }
- sni := SNIExtension{uconn.config.ServerName}
- sessionTicket := SessionTicketExtension{Session: session}
- if session != nil {
- sessionTicket.Session = session
- if len(session.SessionTicket()) > 0 {
- sessionId := sha256.Sum256(session.SessionTicket())
- hello.SessionId = sessionId[:]
- }
- }
- sigAndHash := SignatureAlgorithmsExtension{SignatureAndHashes: []SignatureAndHash{
- {disabledHashSHA512, signatureRSA},
- {disabledHashSHA512, signatureECDSA},
- {hashSHA384, signatureRSA},
- {hashSHA384, signatureECDSA},
- {hashSHA256, signatureRSA},
- {hashSHA256, signatureECDSA},
- {fakeHashSHA224, signatureRSA},
- {fakeHashSHA224, signatureECDSA},
- {hashSHA1, signatureRSA},
- {hashSHA1, signatureECDSA}},
- }
- status := StatusRequestExtension{}
- npn := NPNExtension{}
- sct := SCTExtension{}
- alpn := ALPNExtension{AlpnProtocols: []string{"http/1.1", "spdy/3", "spdy/3.1"}}
- points := SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}}
- curves := SupportedCurvesExtension{[]CurveID{CurveP256, CurveP384, CurveP521}}
- padding := utlsPaddingExtension{GetPaddingLen: boringPaddingStyle}
- uconn.Extensions = []TLSExtension{
- &sni,
- &sessionTicket,
- &sigAndHash,
- &status,
- &npn,
- &sct,
- &alpn,
- &points,
- &curves,
- &padding,
- }
- return nil
- }
- func (uconn *UConn) parrotChrome_5x(includeNonStandardChaChaCiphers bool) error {
- hello := uconn.HandshakeState.Hello
- session := uconn.HandshakeState.Session
- err := uconn.fillClientHelloHeader()
- if err != nil {
- return err
- }
- if includeNonStandardChaChaCiphers {
- hello.CipherSuites = []uint16{
- GetBoringGREASEValue(hello.Random, ssl_grease_cipher),
- 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,
- OLD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
- OLD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
- 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,
- }
- } else {
- hello.CipherSuites = []uint16{
- GetBoringGREASEValue(hello.Random, ssl_grease_cipher),
- 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,
- }
- }
- grease_ext1 := GetBoringGREASEValue(hello.Random, ssl_grease_extension1)
- grease_ext2 := GetBoringGREASEValue(hello.Random, ssl_grease_extension2)
- if grease_ext1 == grease_ext2 {
- grease_ext2 ^= 0x1010
- }
- grease1 := FakeGREASEExtension{Value: grease_ext1}
- reneg := RenegotiationInfoExtension{renegotiation: RenegotiateOnceAsClient}
- sni := SNIExtension{uconn.config.ServerName}
- ems := utlsExtendedMasterSecretExtension{}
- sessionTicket := SessionTicketExtension{Session: session}
- if session != nil {
- sessionTicket.Session = session
- if len(session.SessionTicket()) > 0 {
- sessionId := sha256.Sum256(session.SessionTicket())
- hello.SessionId = sessionId[:]
- }
- }
- sigAndHash := SignatureAlgorithmsExtension{SignatureAndHashes: []SignatureAndHash{
- {hashSHA256, signatureECDSA},
- fakeRsaPssSha256,
- {hashSHA256, signatureRSA},
- {hashSHA384, signatureECDSA},
- fakeRsaPssSha384,
- {hashSHA384, signatureRSA},
- fakeRsaPssSha512,
- {disabledHashSHA512, signatureRSA},
- {hashSHA1, signatureRSA}},
- }
- status := StatusRequestExtension{}
- sct := SCTExtension{}
- alpn := ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}
- channelId := FakeChannelIDExtension{}
- points := SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}}
- curves := SupportedCurvesExtension{[]CurveID{CurveID(GetBoringGREASEValue(hello.Random, ssl_grease_group)),
- X25519, CurveP256, CurveP384}}
- grease2 := FakeGREASEExtension{Value: grease_ext2, Body: []byte{0}}
- padding := utlsPaddingExtension{GetPaddingLen: boringPaddingStyle}
- uconn.Extensions = []TLSExtension{
- &grease1,
- &reneg,
- &sni,
- &ems,
- &sessionTicket,
- &sigAndHash,
- &status,
- &sct,
- &alpn,
- &channelId,
- &points,
- &curves,
- &grease2,
- &padding,
- }
- return nil
- }
- func (uconn *UConn) parrotiOSSafari_11_3_1() error {
- hello := uconn.HandshakeState.Hello
- session := uconn.HandshakeState.Session
- hello.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,
- }
- err := uconn.fillClientHelloHeader()
- if err != nil {
- return err
- }
- reneg := RenegotiationInfoExtension{renegotiation: RenegotiateOnceAsClient}
- sni := SNIExtension{uconn.config.ServerName}
- ems := utlsExtendedMasterSecretExtension{}
- sessionTicket := SessionTicketExtension{Session: session}
- if session != nil {
- sessionTicket.Session = session
- if len(session.SessionTicket()) > 0 {
- sessionId := sha256.Sum256(session.SessionTicket())
- hello.SessionId = sessionId[:]
- }
- }
- sigAndHash := SignatureAlgorithmsExtension{SignatureAndHashes: []SignatureAndHash{
- {hashSHA256, signatureECDSA},
- fakeRsaPssSha256,
- {hashSHA256, signatureRSA},
- {hashSHA384, signatureECDSA},
- fakeRsaPssSha384,
- {hashSHA384, signatureRSA},
- fakeRsaPssSha512,
- {disabledHashSHA512, signatureRSA},
- {hashSHA1, signatureRSA},
- },
- }
- status := StatusRequestExtension{}
- npn := NPNExtension{}
- sct := SCTExtension{}
- alpn := ALPNExtension{AlpnProtocols: []string{"h2", "h2-16", "h2-15", "h2-14", "spdy/3.1", "spdy/3", "http/1.1"}}
- points := SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}}
- curves := SupportedCurvesExtension{[]CurveID{X25519, CurveP256, CurveP384, CurveP521}}
- uconn.Extensions = []TLSExtension{
- &reneg,
- &sni,
- &ems,
- &sessionTicket,
- &sigAndHash,
- &status,
- &npn,
- &sct,
- &alpn,
- &points,
- &curves,
- }
- return nil
- }
- func (uconn *UConn) parrotRandomizedALPN() error {
- err := uconn.parrotRandomizedNoALPN()
- if len(uconn.config.NextProtos) == 0 {
- // if user didn't specify alpn, choose something popular
- uconn.config.NextProtos = []string{"h2", "http/1.1"}
- }
- alpn := ALPNExtension{AlpnProtocols: uconn.config.NextProtos}
- uconn.Extensions = append(uconn.Extensions, &alpn)
- return err
- }
- func (uconn *UConn) parrotRandomizedNoALPN() error {
- hello := uconn.HandshakeState.Hello
- session := uconn.HandshakeState.Session
- hello.CipherSuites = make([]uint16, len(defaultCipherSuites()))
- copy(hello.CipherSuites, defaultCipherSuites())
- shuffledSuites, err := shuffledCiphers()
- if err != nil {
- return err
- }
- hello.CipherSuites = removeRandomCiphers(shuffledSuites, 0.4)
- err = uconn.fillClientHelloHeader()
- if err != nil {
- return err
- }
- sni := SNIExtension{uconn.config.ServerName}
- sessionTicket := SessionTicketExtension{Session: session}
- if session != nil {
- sessionTicket.Session = session
- if len(session.SessionTicket()) > 0 {
- sessionId := sha256.Sum256(session.SessionTicket())
- hello.SessionId = sessionId[:]
- }
- }
- sigAndHashAlgos := []SignatureAndHash{
- {hashSHA256, signatureECDSA},
- {hashSHA256, signatureRSA},
- {hashSHA384, signatureECDSA},
- {hashSHA384, signatureRSA},
- {hashSHA1, signatureRSA},
- }
- if tossBiasedCoin(0.5) {
- sigAndHashAlgos = append(sigAndHashAlgos, SignatureAndHash{disabledHashSHA512, signatureECDSA})
- }
- if tossBiasedCoin(0.5) {
- sigAndHashAlgos = append(sigAndHashAlgos, SignatureAndHash{disabledHashSHA512, signatureRSA})
- }
- if tossBiasedCoin(0.5) {
- sigAndHashAlgos = append(sigAndHashAlgos, SignatureAndHash{hashSHA1, signatureECDSA})
- }
- err = shuffleSignatures(sigAndHashAlgos)
- if err != nil {
- return err
- }
- sigAndHash := SignatureAlgorithmsExtension{SignatureAndHashes: sigAndHashAlgos}
- status := StatusRequestExtension{}
- sct := SCTExtension{}
- points := SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}}
- curveIDs := []CurveID{}
- if tossBiasedCoin(0.7) {
- curveIDs = append(curveIDs, X25519)
- }
- curveIDs = append(curveIDs, CurveP256, CurveP384)
- if tossBiasedCoin(0.3) {
- curveIDs = append(curveIDs, CurveP521)
- }
- curves := SupportedCurvesExtension{curveIDs}
- padding := utlsPaddingExtension{GetPaddingLen: boringPaddingStyle}
- reneg := RenegotiationInfoExtension{renegotiation: RenegotiateOnceAsClient}
- uconn.Extensions = []TLSExtension{
- &sni,
- &sessionTicket,
- &sigAndHash,
- &points,
- &curves,
- }
- if tossBiasedCoin(0.66) {
- uconn.Extensions = append(uconn.Extensions, &padding)
- }
- if tossBiasedCoin(0.66) {
- uconn.Extensions = append(uconn.Extensions, &status)
- }
- if tossBiasedCoin(0.55) {
- uconn.Extensions = append(uconn.Extensions, &sct)
- }
- if tossBiasedCoin(0.44) {
- uconn.Extensions = append(uconn.Extensions, &reneg)
- }
- err = shuffleTLSExtensions(uconn.Extensions)
- if err != nil {
- return err
- }
- return nil
- }
- func (uconn *UConn) parrotCustom() error {
- return uconn.fillClientHelloHeader()
- }
- 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
- }
- 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 []SignatureAndHash) 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
- }
|