uTLS Documentation

repository·master·Indexed 25 days ago

https://github.com/refraction-networking/utls

uTLS is a fork of Go's 'crypto/tls' designed for ClientHello fingerprinting resistance. It enables developers to mimic popular browser fingerprints (such as Chrome and Firefox), generate randomized fingerprints, and perform low-level handshake manipulations to bypass censorship. The library includes features for custom TLS extensions, a Roller for cycling HelloIDs, and a Fingerprinter to mimic captured ClientHello traffic.

Tokens
18.7K
Snippets
20
Records
133
Agent score
81%

What's inside uTLS

  1. Overview of Dict TLS

    master

    Dict TLS is a vendored version of godicttls. It provides a dictionary for TLS written in Go, offering bidirectional mapping between TLS parameter/extension values and their corresponding names. It also includes enum convenience for working with these values.

    The data used in this dictionary is sourced from IANA assignments for:

    • Transport Layer Security (TLS) Parameters
    • Transport Layer Security (TLS) Extensions
  2. Use UConn to manage handshakes and extensions

    master

    The UConn type extends the standard tls.Conn. It is the primary interface for managing a connection with custom TLS configurations. It maintains a slice of TLSExtension objects and a public ClientHandshakeState.

    When UConn.BuildHandshakeState() is called (either manually or automatically during UConn.Handshake()), the configuration is applied based on the selected ClientHelloID:

    • HelloGolang: Uses the default Go makeClientHello() implementation. uTLS-specific customizations are ignored.
    • Other ClientHelloIDs: Populates UConn.Hello.{Random, CipherSuites, CompressionMethods} and UConn.Extensions based on a 'parrot' setup. These are then applied to standard TLS structs and marshaled into HandshakeState.Hello.
  3. Choose a ClientHello ID for fingerprinting resistance

    master

    The behavior of the TLS handshake is determined by the clientHelloID passed to tls.UClient. Different IDs provide different levels of fingerprinting resistance and customization:

    • utls.HelloRandomized: Randomly adds and reorders extensions and ciphersuites. Note that it may add ALPN randomly; use utls.HelloRandomizedALPN or utls.HelloRandomizedNoALPN for explicit control.
    • utls.HelloGolang: Uses the default Go crypto/tls marshaling. Warning: This will overwrite your manual changes to the ClientHello. If you need to modify the handshake, call BuildHandshakeState() before applying changes. UConn.Extensions are ignored in this mode.
    • utls.HelloCustom: Prepares a ClientHello with empty uconn.Extensions, allowing you to manually populate them with TLSExtension objects.
    • Browser Parrots: Mimics specific browser fingerprints:
      • utls.HelloChrome_Auto: Latest recommended Google Chrome version.
      • utls.HelloChrome_58: Google Chrome 58.
      • utls.HelloFirefox_Auto: Latest recommended Firefox version.
      • utls.HelloFirefox_55: Firefox 55.
  4. How uTLS manages handshake state

    master

    uTLS bypasses the limitations of Go's crypto/tls package (where many handshake structs and fields are private) by using public copies of private structs.

    To manipulate the handshake, you can modify the fields of the public ClientHandshakeState. Before the handshake begins, uTLS performs a shallow copy of your public state into the internal Go clientHandshakeState, executes the handshake, and then copies the resulting state back to your public struct so you can inspect the handshake results.

  5. Parrot popular browser ClientHellos

    master

    uTLS can mimic the ClientHello of popular browsers (like Chrome and Firefox).

    Important Caveats:

    • We must offer ciphersuites and TLS extensions that are not supported by standard crypto/tls. This is safe if you control the server and can disable these unsupported features.
    • Parroting is imperfect and only covers the ClientHello phase.
    • For certain browsers like iOS, you should call utls.EnableWeakCiphers() prior to use to avoid connection breakage.

    Refer to the compatibility table in the documentation for specific fingerprint IDs and unsupported extensions for each browser version.

  6. Customize the TLS handshake with uTLS

    master

    uTLS provides methods to manipulate the handshake state, such as setting custom random values or session states.

    Set Client Random

    Use SetClientRandom to provide a custom byte slice for the client random value:

    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)

    Set Session State

    You can create a fake session ticket using utls.MakeClientSessionState and apply it via SetSessionState:

    masterSecret := make([]byte, 48)
    copy(masterSecret, []byte("masterSecret is NOT sent over the wire"))
    
    // 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)

    Manual Handshake Customization

    For advanced users who need to build the state manually (e.g., using a randomized ClientHello and then adding specific extensions), use the following workflow:

    1. Call BuildHandshakeState() to prepare the state.
    2. Apply your changes to the extensions.
    3. Call MarshalClientHello() to finalize the bytes that will be sent.
    // 1. Build the state
    err := uconn.BuildHandshakeState()
    
    // ... apply changes to uconn.Extensions ...
    
    // 2. Marshal final bytes
    err = uconn.MarshalClientHello()
    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"))
    
    sessionState := utls.MakeClientSessionState(sessionTicket, uint16(tls.VersionTLS12), 
        tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 
        masterSecret, 
        nil, nil)
    tlsConn.SetSessionState(sessionState)
  7. Fingerprint and mimic a captured ClientHello

    master

    You can use raw bytes from a captured ClientHello to generate a ClientHelloSpec that mimics the original client's properties. This is useful for making new connections look like they originate from the same software as the captured traffic.

    Steps:

    1. Create a Fingerprinter and use FingerprintClientHello on the raw bytes (the bytes must include the full TLS record: type, version, and length).
    2. Create a UClient using tls.HelloCustom.
    3. Apply the generated spec using uConn.ApplyPreset(generatedSpec).
    uConn := UClient(&net.TCPConn{}, nil, HelloCustom)
    fingerprinter := &Fingerprinter{}
    generatedSpec, err := fingerprinter.FingerprintClientHello(rawCapturedClientHelloBytes)
    if err != nil {
      panic("fingerprinting failed: %v", err)
    }
    if err := uConn.ApplyPreset(generatedSpec); err != nil {
      panic("applying generated spec failed: %v", err)
    }
  8. Create a custom TLS handshake

    master

    You can construct a custom handshake by following these steps:

    1. Call tls.UClient() with tls.HelloCustom to obtain an empty configuration.
    2. Populate the UConn.Hello fields (e.g., Random, CipherSuites, CompressionMethods) if necessary.
    3. Configure and add TLS Extensions to UConn.Extensions. Extensions are marshaled in the order they are added.
    4. Set Session and SessionCache as required.

    Warning: If you need to manually control all raw bytes on the wire, you can set UConn.HandshakeStateBuilt = true and marshal the clientHello into UConn.HandshakeState.Hello.raw yourself. If you do this, you are responsible for ensuring the Config and ClientHelloMsg match your manual setup to avoid confusing the underlying crypto/tls implementation.

  9. Migrate from crypto/tls to uTLS

    master

    To replace the standard Go crypto/tls with uTLS, follow these steps:

    1. Import the library using an alias to avoid conflicts with the standard library: import tls "github.com/refraction-networking/utls".
    2. Select a clientHelloID (e.g., utls.HelloChrome_Auto).
    3. Replace the standard tls.Client call with tls.UClient.

    Standard crypto/tls usage:

    config := tls.Config{ServerName: "www.google.com"}
    tlsConn := tls.Client(dialConn, &config)

    uTLS usage:

    config := tls.Config{ServerName: "www.google.com"}
    // Use tls.UClient instead of tls.Client
    tlsConn := tls.UClient(dialConn, &config, utls.HelloChrome_Auto)
    import tls "github.com/refraction-networking/utls"
    
    // ...
    
    config := tls.Config{ServerName: "www.google.com"}
    tlsConn := tls.UClient(dialConn, &config, utls.HelloChrome_Auto)
  10. How the sessionController manages TLS sessions

    master

    The sessionController is an internal mechanism responsible for managing the lifecycle of session-related states, specifically the Session Ticket extension and the Pre-Shared Key (PSK) extension. It handles their initialization, removal (if the ClientHello specification does not include them), and the process of setting the prepared state to the ClientHello.

    Key Responsibilities:

    • Lifecycle Management: Manages the transition from NoSession to initialized states (SessionTicketExtInitialized or PskExtInitialized) and finally to a locked state where further modifications are disallowed.
    • Extension Synchronization: Ensures that the session extensions used by the controller are synchronized with the extensions present in the UConn's ClientHello specification.
    • State Protection: Prevents undefined behavior by enforcing strict state transitions and ensuring that session data is not modified after the ClientHello has been built.

    Note for Users: The sessionController is an internal type. Users should never attempt to construct it directly or modify its underlying state. Use the provided public APIs of UConn and its associated extensions to interact with session resumption.

  11. How UConn and ClientHelloID work together

    master

    A UConn is a specialized TLS connection that allows for fingerprinting resistance and custom handshakes. The behavior of the connection is heavily influenced by the ClientHelloID passed during initialization via UClient:

    • HelloGolang: Uses the default Go TLS ClientHello structure.
    • Mimicking IDs: Uses a predefined ClientHello structure to mimic other browsers or clients.
    • HelloCustom: Allows for a completely custom ClientHello by manually configuring the Extensions slice on the UConn object.

    UConn automatically calls BuildHandshakeState before performing the handshake to ensure the ClientHello is correctly marshaled based on your configuration.

  12. Use ClientHelloSpec for fingerprinting resistance

    master

    uTLS provides pre-defined ClientHelloSpec configurations (often referred to as 'parrots') that mimic the TLS handshake characteristics of specific browsers and operating systems (e.g., Firefox, iOS, Edge, Safari). Using these specs helps a client resist fingerprinting by presenting a ClientHello that looks like a legitimate, common browser.

    Each spec defines:

    • TLSVersMin and TLSVersMax: The supported TLS version range.
    • CipherSuites: The list of supported cipher suites.
    • CompressionMethods: Supported compression algorithms.
    • Extensions: A list of TLSExtension objects that define the specific handshake extensions (like SNIExtension, KeyShareExtension, SupportedCurvesExtension, etc.) used by that specific client version.