Fork of the Go standard TLS library, providing low-level access to the ClientHello for mimicry purposes.
Find a file
2017-08-07 18:33:38 -04:00
cipherhw uTLS: initial commit 2017-07-07 11:02:48 -04:00
examples uTLS: initial commit 2017-07-07 11:02:48 -04:00
testdata uTLS: initial commit 2017-07-07 11:02:48 -04:00
testenv uTLS: initial commit 2017-07-07 11:02:48 -04:00
alert.go Initial commit: clone of crypto/tls 2017-06-22 18:00:11 -04:00
cipher_suites.go uTLS: initial commit 2017-07-07 11:02:48 -04:00
common.go uTLS: initial commit 2017-07-07 11:02:48 -04:00
conn.go Initial commit: clone of crypto/tls 2017-06-22 18:00:11 -04:00
conn_test.go Initial commit: clone of crypto/tls 2017-06-22 18:00:11 -04:00
CONTRIBUTING.md Add CONTRIBUTING.md 2017-08-07 18:33:38 -04:00
CONTRIBUTORS_GUIDE.md uTLS: initial commit 2017-07-07 11:02:48 -04:00
example_test.go Initial commit: clone of crypto/tls 2017-06-22 18:00:11 -04:00
generate_cert.go Initial commit: clone of crypto/tls 2017-06-22 18:00:11 -04:00
handshake_client.go Initial commit: clone of crypto/tls 2017-06-22 18:00:11 -04:00
handshake_client_test.go Initial commit: clone of crypto/tls 2017-06-22 18:00:11 -04:00
handshake_messages.go Initial commit: clone of crypto/tls 2017-06-22 18:00:11 -04:00
handshake_messages_test.go Initial commit: clone of crypto/tls 2017-06-22 18:00:11 -04:00
handshake_server.go Initial commit: clone of crypto/tls 2017-06-22 18:00:11 -04:00
handshake_server_test.go Initial commit: clone of crypto/tls 2017-06-22 18:00:11 -04:00
handshake_test.go Initial commit: clone of crypto/tls 2017-06-22 18:00:11 -04:00
key_agreement.go uTLS: initial commit 2017-07-07 11:02:48 -04:00
LICENSE Add LICENSE 2017-07-07 11:35:15 -04:00
prf.go uTLS: initial commit 2017-07-07 11:02:48 -04:00
prf_test.go Initial commit: clone of crypto/tls 2017-06-22 18:00:11 -04:00
README.md README: add note about Handshake() being mandatory 2017-07-31 18:20:09 -04:00
ticket.go Initial commit: clone of crypto/tls 2017-06-22 18:00:11 -04:00
tls.go Initial commit: clone of crypto/tls 2017-06-22 18:00:11 -04:00
tls_test.go uTLS: initial commit 2017-07-07 11:02:48 -04:00
u_common.go uTLS: initial commit 2017-07-07 11:02:48 -04:00
u_conn.go uTLS: initial commit 2017-07-07 11:02:48 -04:00
u_conn_test.go uTLS: initial commit 2017-07-07 11:02:48 -04:00
u_parrots.go uTLS: initial commit 2017-07-07 11:02:48 -04:00
u_public.go uTLS: initial commit 2017-07-07 11:02:48 -04:00
u_tls_extensions.go uTLS: initial commit 2017-07-07 11:02:48 -04:00

uTLS

Low-level access to handshake

  • Read/write access to all bits of client hello message.
  • Read access to fields of ClientHandshakeState, which, among other things, includes ServerHello and MasterSecret.

ClientHello fingerprinting resistance

Golang's ClientHello has a very unique fingerprint, which especially sticks out on mobile clients, where Golang is not too popular yet. Some members of anti-censorship community are concerned that their tools could be trivially blocked based on ClientHello with relatively small collateral damage. There are multiple solutions to this issue.

Randomized handshake

This package can be used to generate randomized ClientHello. Provides a moving target without any compatibility or parrot-is-dead attack risks.
Feedback about implementation details of randomized handshake is extremely appreciated.

Parroting

This package can be used to parrot ClientHello of popular browsers. There are some caveats to this parroting:

  • We are forced to offer ciphersuites and tls extensions that are not supported by crypto/tls. This is not a problem, if you fully control the server and turn unsupported things off on server side.
  • Parroting could be imperfect, and there is no parroting beyond ClientHello.
  • We are forced to offer ciphersuites and tls extensions setups that are not supported by crypto/tls. This is not a problem, if you fully control the server.
  • Parroting could be imperfect, and there is no parroting beyond ClientHello.\
Parrot Ciphers* Signature* Unsupported extensions
Android 5.1 low very low None
Android 6.0 low very low Extended Master Secret**
Chrome 58 no low Extended Master Secret**, ChannelID

* Denotes very rough guesstimate of likelihood that unsupported things will get echoed back by the server in the wild, visibly breaking the connection.
** New extensions such as EMS become popular quickly, so it's not recommended to use with servers you don't own.
As seen in table, many good parrots will become available once EMS is implemented in crypto/tls.

Work-in-progress parrots

Not finished yet!

Parrot Ciphers* Signature* Unsupported extensions
Firefox 53 low low Extended Master Secret**
Parrots FAQ

Does it really look like, say, Google Chrome with all the GREASE and stuff?

It LGTM, but please open up Wireshark and check. If you see something — say something.

Aren't there side channels? Everybody knows that the bird is a wordparrot is dead

There sure are. If you found one that approaches practicality at line speed — please tell us.

Things to implement in Golang to make parrots better
  • Extended Master Secret and ChannelID extensions
  • Enable sha512 and sha224 hashes by default
  • Implement RSA PSS signature algorithms
  • In general, any modern crypto is likely to be useful going forward.

Custom Handshake

It is possible to create custom handshake by

  1. Use HelloCustom as an argument for UClient() to get empty config
  2. Fill tls header fields: UConn.Hello.{Random, CipherSuites, CompressionMethods}, if needed, or stick to defaults.
  3. Configure and add various TLS Extensions to UConn.Extensions: they will be marshaled in order.
  4. Set Session and SessionCache, as needed.

If you need to manually control all the bytes on the wire(certainly not recommended!), you can set UConn.HandshakeStateBuilt = true, and marshal clientHello into UConn.HandshakeState.Hello.raw yourself. In this case you will be responsible for modifying other parts of Config and ClientHelloMsg to reflect your setup.

Fake Session Tickets

Set of provided functions is likely to change, as use-cases aren't fully worked out yet. Currently, there is a simple function to set session ticket to any desired state:

func (c *ExtendedConfig) SetSessionState(session *ClientSessionState)

Note that session tickets (fake ones or otherwise) are not reused.
To reuse tickets, create a shared cache and set it on current and further configs:

func (c *ExtendedConfig) SetSessionCache(cache ClientSessionCache)

Usage

Find other examples here.

For a reference, here's how default "crypto/tls" is used:

    config := tls.Config{ServerName: "www.google.com"}
    dialConn, err := net.Dial("tcp", "172.217.11.46:443")
    if err != nil {
        fmt.Printf("net.Dial() failed: %+v\n", err)
        return
    }
    tlsConn := tls.Client(dialConn, &config)
    err = tlsConn.Handshake()
    if err != nil {
    fmt.Printf("tlsConn.Handshake() error: %+v", err)
        return
    }

Now, if you want to use uTLS, simply substitute tlsConn := tls.Client(dialConn, &config) with tlsConn := utls.UClient(dialConn, &config, clientHelloID) where clientHelloID is one of the following:

  1. utls.HelloRandomized adds/reorders extensions, ciphersuites, etc. randomly.
    HelloRandomized adds ALPN in 50% of cases, you may want to use HelloRandomizedALPN or HelloRandomizedNoALPN to choose specific behavior explicitly, as ALPN might affect application layer.
  2. utls.HelloGolang HelloGolang will use default "crypto/tls" handshake marshaling codepath, which WILL overwrite your changes to Hello(Config, Session are fine). You might want to call BuildHandshakeState() before applying any changes. UConn.Extensions will be completely ignored.
  3. utls.HelloCustom will prepare ClientHello with empty uconn.Extensions so you can fill it with TLSExtension's manually.
  4. The rest will will parrot given browser.
    • utls.HelloChrome_Auto- parrots recommended(latest) Google Chrome version
    • utls.HelloChrome_58 - parrots Google Chrome 58
    • utls.HelloFirefox_Auto - parrots recommended(latest) Firefox version
    • utls.HelloFirefox_53_WIP - parrots Firefox 53 (Work in progress!)
    • utls.HelloAndroid_Auto
    • utls.HelloAndroid_6_0_Browser
    • utls.HelloAndroid_5_1_Browser

Note: it is mandatory to manually call tlsConn.Handshake() afterwards. Otherwise, eventual tls.Write() is going to call non-overridden version of handshake.

Customizing handshake

Before doing Handshake() you can also set fake session ticket, set clientHello or change uconn in other ways:

    cRandom := []byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
        110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
        120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
        130, 131}
    tlsConn.SetClientRandom(cRandom)
    masterSecret := make([]byte, 48)
    copy(masterSecret, []byte("masterSecret is NOT sent over the wire")) // you may use it for real security

    // Create a session ticket that wasn't actually issued by the server.
    sessionState := utls.MakeClientSessionState(sessionTicket, uint16(tls.VersionTLS12),
        tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
        masterSecret,
        nil, nil)
    tlsConn.SetSessionState(sessionState)