Skip to main content

TlsHandshake

Struct TlsHandshake 

Source
#[non_exhaustive]
pub struct TlsHandshake {
Show 15 fields pub sni: Option<String>, pub client_alpn: Vec<String>, pub server_alpn: Option<String>, pub ja3: Option<String>, pub ja4: Option<String>, pub ja4s: Option<String>, pub version: Option<TlsVersion>, pub cipher_suite: Option<u16>, pub resumption_attempted: bool, pub outcome: HandshakeOutcome, pub ech_outcome: EchOutcome, pub ech_config_id: Option<u8>, pub pq_key_share: bool, pub certificate_chain: Vec<Bytes>, pub ja4x: Option<String>,
}
Available on crate feature tls only.
Expand description

Aggregated TLS handshake event.

One emitted per observed handshake. Carries enough fields for the common “log TLS handshake” use case (SNI, ALPN, version, cipher, JA3/JA4 if features on, outcome) without consumers hand-rolling correlation across the per-message stream.

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§sni: Option<String>§client_alpn: Vec<String>§server_alpn: Option<String>§ja3: Option<String>

JA3 fingerprint (MD5 hex). Set when ja3 feature on.

§ja4: Option<String>

JA4 fingerprint (FoxIO format). Set when ja4 feature on.

§ja4s: Option<String>
Available on crate feature ja4plus only.

JA4S server fingerprint (FoxIO format), from the ServerHello. Set when the ja4 config + opt-in ja4plus feature are on. New in 0.15.0; moved behind ja4plus in 0.16.0 (FoxIO License 1.1 — see NOTICE).

§version: Option<TlsVersion>

Negotiated TLS version (from ServerHello supported_versions if present, else legacy_version).

§cipher_suite: Option<u16>

Server’s selected cipher suite.

§resumption_attempted: bool

True iff the client sent PSK / session-ticket extensions (indicates resumption was attempted).

§outcome: HandshakeOutcome

Final outcome.

§ech_outcome: EchOutcome

Aggregated ECH outcome derived from the client’s ech_present flag plus the server’s ech_retry_configs plaintext-fallback signal.

§ech_config_id: Option<u8>

HPKE config_id from the client’s outer ECHClientHello, when ECH was offered.

§pq_key_share: bool

true if the client offered a post-quantum hybrid key-exchange group (X25519MLKEM768 family). Mirrors TlsClientHello::pq_key_share; the dominant reason a modern ClientHello spans multiple segments. Issue #135 (0.22.0).

§certificate_chain: Vec<Bytes>

Server’s certificate chain from a TLS 1.2 Certificate handshake record (leaf first per RFC 5246 §7.4.2). Each entry is an X.509 DER blob. Empty for TLS 1.3 (cert chain is encrypted) and for sessions where no cert record was observed before the parser stopped. New in 0.18.0 (issue #24 prereq).

§ja4x: Option<String>
Available on crate feature ja4plus only.

JA4X server-certificate fingerprint of the leaf (first) cert in Self::certificate_chain. Behind the FoxIO-licensed ja4plus feature. None when no cert chain was observed (TLS 1.3 / truncated / ja4plus off) or the DER failed to parse. Issue #24 (0.18.0).

Implementations§

Source§

impl TlsHandshake

Source

pub fn ech_state(&self) -> EchState

Classify the ECH (Encrypted ClientHello) state from the handshake-level evidence — the client’s ECH offer and the server’s plaintext-observable rejection signal.

Refines crate::tls::TlsClientHello::ech_state with the server side:

Issue #8 (0.18).

Source

pub fn routing_alpn(&self) -> Option<&str>

The ALPN protocol to route on: the server’s selection if the handshake got that far, otherwise the client’s first offer.

The server’s choice is the negotiated outcome; the client’s list is only a wish. A terminating proxy uses this to decide whether to speak HTTP/1 or HTTP/2 on the connection.

use flowscope::tls::TlsHandshake;

let mut hs = TlsHandshake::default();
hs.client_alpn = vec!["h2".into(), "http/1.1".into()];
assert_eq!(hs.routing_alpn(), Some("h2"));

// Once the server picks, that wins over the offer order.
hs.server_alpn = Some("http/1.1".into());
assert_eq!(hs.routing_alpn(), Some("http/1.1"));
Source

pub fn routing_sni(&self) -> Option<(&str, bool)>

The name to route on, and whether it can be trusted as the client’s real target.

Returns (name, is_real_target). With ECH in play the SNI on the wire is the outer cover domain, so is_real_target is false and the caller should expect to fall further down the ladder in docs/tls-routing.md. None means no SNI at all — route by JA4, first-byte class, or pass through.

This never fails on ECH: degrading is the designed behaviour, and refusing connections that offer ECH would refuse a growing share of ordinary traffic.

use flowscope::tls::{EchOutcome, TlsHandshake};

let mut hs = TlsHandshake::default();
hs.sni = Some("api.example.com".into());
assert_eq!(hs.routing_sni(), Some(("api.example.com", true)));

// With ECH offered, the same field is only a cover name.
hs.ech_outcome = EchOutcome::Accepted;
assert_eq!(hs.routing_sni(), Some(("api.example.com", false)));

Trait Implementations§

Source§

impl Clone for TlsHandshake

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for TlsHandshake

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for TlsHandshake

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for TlsHandshake

Available on crate feature serde only.
Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl PartialEq for TlsHandshake

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for TlsHandshake

Available on crate feature serde only.
Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for TlsHandshake

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more