sniffer: use the wire session id length in both hello parsers - #11390
sniffer: use the wire session id length in both hello parsers#11390yosuke-wolfssl wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
haveSessionId/sessionIDSz are not cleared when a hello carries a zero-length Session ID, which can allow stale state to affect resumption/ticket logic if additional hellos are processed on the same sniffer session.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR fixes the TLS sniffer (src/sniffer.c) to honor the on-the-wire Session ID length (0–32) rather than forcing ID_LEN (32), preventing incorrect cache keys/truncation and making resumption detection respect the actual negotiated Session ID size. It also adds an API test that synthesizes minimal IPv4/TCP/TLS records to exercise these edge cases without pcap input.
Changes:
- Update ClientHello/ServerHello parsing to reject
session_id_len > ID_LEN, copy exactlysession_id_lenbytes, and recordsessionIDSzaccordingly. - Update resumption detection to compare both Session ID sizes and only compare the number of bytes actually present.
- Add a new sniffer-focused test that validates rejection/acceptance/resumption behavior for varying Session ID lengths and malformed lengths.
File summaries
| File | Description |
|---|---|
src/sniffer.c |
Fixes sniffer hello parsing to respect the wire Session ID length and updates resumption comparison accordingly. |
tests/api.c |
Adds a targeted regression test that builds minimal packets to validate Session ID length handling in the sniffer. |
Review details
Suppressed comments (1)
src/sniffer.c:4344
haveSessionId/sessionIDSzare only set whenbLenis non-zero; if another ClientHello is processed on the same sniffer session withsession_idlength 0, the previous session-id state can persist and affect later resumption decisions. Clear the session-id state before conditionally copying the new value.
/* store session in case trying to resume */
bLen = *input++;
*sslBytes -= ENUM_LEN;
if (bLen > ID_LEN) {
SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #11390
Scan targets checked: wolfssl-bugs, wolfssl-src
Findings: 1
1 finding(s) posted as inline comments (see file-level comments below)
This review was generated automatically by Fenrir. Reported findings require changes before merge.
9eaefb3 to
800c3d8
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #11390
Scan targets checked: wolfssl-bugs, wolfssl-src
Findings: 1
1 finding(s) posted as inline comments (see file-level comments below)
This review was generated automatically by Fenrir. Reported findings require changes before merge.
- ProcessServerHello() and ProcessClientHello() reject a declared session id length above ID_LEN, copy exactly that many bytes into arrays->sessionID and, under WOLFSSL_TLS13, session->sessionID, and record it as sessionIDSz. - ProcessClientHello() checks the declared length against the bytes remaining in the record before copying. - ProcessServerHello() carries a note that its resumption comparison takes a full length id because that is all the session cache matches. - tests/api.c adds test_sniffer_hello_session_id_len, driving ssl_DecodePacket() with hand-built IPv4/TCP packets: ClientHello and ServerHello lengths above ID_LEN, a ClientHello length running past the record, a zero length id, short ids that differ and that match, and matching full length ids. - SnifferTestPacket(), SnifferTestTcp() and SnifferTestHello() build the packets; the hello packet is allocated at its exact size, and the builder returns BAD_FUNC_ARG when the record exceeds its buffer. - The test and its TEST_DECL are guarded on WOLFSSL_SNIFFER, a non-watch build, PEM support, RSA, the filesystem and TLS 1.2. - The sniffer headers are included for any WOLFSSL_SNIFFER build, with sys/uio.h left under WOLFSSL_SNIFFER_CHAIN_INPUT. Issue: F-13334
800c3d8 to
c51d9cf
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #11390
Scan targets checked: wolfssl-bugs, wolfssl-src
Fenrir result: Approved ✅
No new issues found in the changed files.
Advisory only — this automated result does not count as a GitHub approval.
Fenrir's latest completed scan found no issues; clearing the prior automated change request.
Problem
src/sniffer.cwas the only TLS parser in the tree that ignored the wire session-ID length: both hello parsers validated, copied and recorded a hardcodedID_LEN(32). RFC 5246 §7.4.1.2 permits 0–32.ID_LEN > *sslBytes), so a compact hello — 16-byte ID, one cipher suite, one compression method, 22 bytes remaining — is torn down with a fatal error.ProcessFinished()feeds that value toAddSession()as a session cache key.sessionIDSz == ID_LENtests on the resumption comparison are tautologies, since both sides are forced toID_LEN.Closes f-13334.
Fix (
src/sniffer.c)ProcessServerHello()andProcessClientHello()reject a declared length aboveID_LEN, copy exactly that many bytes, and record it assessionIDSz.ProcessClientHello()gains a read-through check against the declared length, which it never had. This matchesDoServerHello()andDoClientHello()insrc/internal.cand both TLS 1.3 parsers.The resumption comparison is unchanged from master; its two
== ID_LENtests only become meaningful now thatsessionIDSzholds the wire length. A comment records why the full length is required: the session cache matches only full-length IDs (src/ssl_sess.c:1173), as do the client and server resumption decisions (src/internal.c:34543,src/internal.c:41480).Not in scope: short-ID resumption. wolfSSL treats resumption as 32-only throughout, so supporting shorter IDs means changing the cache and both peers' resumption decisions — a separate change. Short IDs are now parsed and recorded correctly; they simply do not resume.
Tests (
tests/api.c)test_sniffer_hello_session_id_lendrivesssl_DecodePacket()with hand-built IPv4/TCP packets — no pcap needed, as the sniffer verifies no checksums.ID_LEN + 1ID_LEN + 1, after a zero-ID ClientHelloVerification
Every guard was confirmed load-bearing by reverting it individually and checking the test fails — including a control that restores the length-based comparison, pinning the
ID_LENrequirement. ThebLen > *sslBytesbound is ASan-only: whenever it fires, the next check rejects the same packet, so the over-read is the sole observable, and the hello packet is allocated at its exact size to expose it.Clean under
-Werrorwith and without TLS 1.3.make check6 passed, 0 failed, 5 skipped.scripts/sniffer-testsuite.testpasses all 10 pcaps with all 9 resume decrypts intact. ASan + UBSan clean on both the unit test and the pcap suite.