feat: add TLS ClientHello/ServerHello analyzer with JA3/JA3S fingerprinting (#2)#30
feat: add TLS ClientHello/ServerHello analyzer with JA3/JA3S fingerprinting (#2)#30
Conversation
Establishes the routing pattern for multiple stream analyzers (HTTP, TLS, future SSH/SMB). Content-based detection is primary (TLS record header, HTTP method keywords), port hints as fallback. Validated against Zeek DPD, Suricata, and Wireshark approaches.
Covers: StreamDispatcher (ADR 0001), TlsAnalyzer with JA3/JA3S fingerprinting, weak cipher detection, SNI extraction, TLS record buffering. Validated via Perplexity: tls-parser API, JA3 format, GREASE filtering, TLS 1.3 version handling, detection scope.
Codifies the two-trait model (ProtocolAnalyzer for packet-level, StreamAnalyzer for stream-level), internal structure pattern (per-flow state, aggregate counters, findings, error tracking), and the steps to add a new analyzer. Documents existing DNS/HTTP analyzers and planned TLS analyzer.
6 tasks: scaffolding, dispatcher tests, TLS record parsing + JA3, ServerHello + JA3S + weak cipher tests, summarize(), CLI integration. 14 total tests across 2 test files.
Extension parsing failures were silently producing empty extension lists via .ok().unwrap_or_default(), computing JA3 with missing data without any indication to the user. Now increments parse_errors so users know fingerprints may be incomplete. Also counts unexpected Incomplete errors from record parsing. Partial JA3 with empty extension fields is still computed (matches Zeek behavior).
SSLv3 is prohibited by RFC 7568 (POODLE vulnerability). SSLv2 is even worse (DROWN attack). Generate Anomaly/Likely/High findings for both ClientHello and ServerHello using these versions. Verified against tests/fixtures/tls.pcap (SSL 3.0 traffic).
There was a problem hiding this comment.
Pull request overview
Adds TLS stream analysis (ClientHello/ServerHello parsing) to wirerust, including JA3/JA3S fingerprinting and weak/deprecated TLS signal detection, and introduces a stream dispatcher to route reassembled TCP flows to the appropriate analyzer.
Changes:
- Added
TlsAnalyzer(StreamAnalyzer) to parse TLS handshakes, extract SNI, compute JA3/JA3S, and emit findings for weak ciphers / deprecated SSL versions. - Added
StreamDispatcherto classify reassembled TCP streams via content-first detection with port fallback and forward data to HTTP/TLS analyzers. - Wired
--tlsinto the CLI analyze path and added unit tests + ADR/spec documentation.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/analyzer/tls.rs |
New TLS stream analyzer with per-flow buffering, handshake parsing, JA3/JA3S, counters, and findings. |
src/dispatcher.rs |
New dispatcher to route reassembled flow bytes to HTTP vs TLS analyzers. |
src/main.rs |
Integrates dispatcher and --tls flag into analyze workflow; updates reassembly requirements and reporting. |
src/lib.rs |
Exposes the new dispatcher module. |
src/analyzer/mod.rs |
Exposes the new tls analyzer module. |
tests/tls_analyzer_tests.rs |
Adds TLS analyzer unit tests (ClientHello/ServerHello parsing, JA3/JA3S, findings, summarize). |
tests/dispatcher_tests.rs |
Adds dispatcher routing unit tests. |
docs/adr/0001-content-first-stream-dispatch.md |
ADR documenting dispatcher approach and rationale. |
docs/adr/0002-modular-protocol-analyzers.md |
ADR documenting analyzer modularity/traits pattern. |
docs/superpowers/specs/2026-04-07-tls-clienthello-design.md |
Design spec for TLS analyzer + dispatcher. |
docs/superpowers/plans/2026-04-07-tls-analyzer.md |
Implementation plan for TLS analyzer + dispatcher. |
Cargo.toml |
Adds tls-parser and md-5 dependencies. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // TLS record header on port 80 — content detection should override port | ||
| let tls_data = [0x16, 0x03, 0x03, 0x00, 0x05, 0x01, 0x00, 0x00, 0x01, 0x00]; | ||
| dispatcher.on_data(&fk, Direction::ClientToServer, &tls_data, 0); | ||
|
|
||
| // HTTP analyzer should NOT have received this data | ||
| let http = dispatcher.http.as_ref().unwrap(); | ||
| assert_eq!(http.method_counts().len(), 0); | ||
| } |
There was a problem hiding this comment.
The dispatcher routing assertions here don’t actually detect misrouting: if TLS bytes are incorrectly forwarded to HttpAnalyzer, method_counts() can still remain empty while parse_errors increments. To make these tests validate routing, also assert that dispatcher.http.as_ref().unwrap().parse_error_count() remains 0 for TLS payloads (and/or assert TLS analyzer state changed, e.g., handshake_count()/parse_error_count()), so a wrong route would fail the test.
There was a problem hiding this comment.
Fixed in 343a101. Added parse_error_count() == 0 assertions to the content detection and port fallback tests to verify HTTP analyzer didn't attempt to parse misrouted TLS bytes.
Add TLS 1.2 (aes256gcm, with SNI) and TLS 1.3 (rfc8446) pcap fixtures from the Wireshark test suite. 4 integration tests verify: - TLS 1.2: SNI extraction, JA3/JA3S computation, version tracking - TLS 1.3: legacy_version (771) in JA3, 2 handshakes parsed - SSL 3.0: deprecated protocol + weak cipher findings generated - summarize() output has all required fields
…gth check 1. Don't cache DispatchTarget::None — allow reclassification on subsequent on_data when more bytes arrive (Copilot #1) 2. Add MAX_RECORD_PAYLOAD (18,432) sanity check to reject impossibly large TLS records that would pin buffer memory (Copilot #2) 3. Stronger dispatcher test assertions — verify HTTP parse_error_count stays 0 when TLS is routed correctly (Copilot #3) 4. Early return in dispatcher when no analyzers enabled (Copilot #4)
Adds TLS to protocol analysis, features, architecture diagram, and component table. Updates --tls flag description (no longer "coming soon"). Removes TLS from roadmap (implemented in #30). Adds max_receive_window to reassembly feature description.
Summary
TlsAnalyzerimplementingStreamAnalyzer— parses ClientHello and ServerHello from reassembled TCP streams, extracts SNI, computes JA3/JA3S fingerprints, detects weak cipher suites (NULL/anonymous/export/RC4) and deprecated SSL 2.0/3.0 versionsStreamDispatcher(ADR 0001) — content-first routing of reassembled TCP streams to HTTP or TLS analyzers based on first-byte inspection (0x16 0x03for TLS, HTTP method keywords for HTTP), with port-based fallback--tlsCLI flag to the new analyzer via the dispatcherTest plan
tests/fixtures/tls.pcap— detected SSL 3.0, export ciphers, computed correct JA3/JA3S hashestests/fixtures/http-full.cap— 2 GET requests parsed, TLS sees 0 packetscargo clippy --testsclean