Skip to content

JA4: Rust client derives q/t marker from TLS extension 57 instead of transport context #307

Description

@elpy1

Summary

technical_details/JA4.md defines the first character of a client JA4
fingerprint as the transport context:

  • q for QUIC
  • t for TLS over TCP

The Rust client JA4 implementation uses extension 57 (QUIC transport params)
to derive this instead of connection context, making it diverge from the
documented algorithm, and Python and Zeek implementations.

Affected code

Rust client JA4 sets the marker from extension 57:

  • rust/ja4/src/tls.rs:318
  • rust/ja4/src/tls.rs:493
let quic = quic_marker(exts.contains(&TLS_EXT_QUIC_TRANSPORT_PARAMETERS));
const TLS_EXT_QUIC_TRANSPORT_PARAMETERS: u16 = 57;

The helper then emits q or t:

rust/ja4/src/tls.rs:481-487:

fn quic_marker(is_quic: bool) -> char {
    if is_quic {
        'q'
    } else {
        't'
    }
}

Other client implementations

Python client JA4 derives q/t from packet connectiong context. TCP packets
set x['quic'] = False, while UDP packets with a QUIC layer set result in
True (python/ja4.py:514-533).

Client JA4 then uses that (python/ja4.py:217-220):

ptype = 'q' if x['quic'] else 't'

Zeek also uses connection context. It emits q only when the connection
protocol is UDP and the service contains QUIC (zeek/ja4/main.zeek:63-72):

if (c?$conn && c$conn$proto == udp && "QUIC" in c$service) {
  proto = "q";
} else {
  proto = "t";
}

Impact

A ClientHello observed over TCP with extension 57 would be:

  • Rust JA4: q...
  • Python JA4: t...
  • Zeek JA4: t...

Resulting in a different fingerprint across implementations.

Suggested resolution

Align implementations with documented algorithm by using packet/protocol
context for determining q/t mmarker.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions