Skip to content

feat(application): dissect RFC 9146 connection-ID DTLS records - #2631

Merged
JarryShaw merged 1 commit into
mainfrom
feat/2515-dtls-cid
Nov 2, 2026
Merged

JarryShaw merged 1 commit into
mainfrom
feat/2515-dtls-cid

Conversation

@JarryShaw

Copy link
Copy Markdown
Owner

What is the purpose of your pull request?

  • feat — a new feature

Description of your pull request and other information

  • CID records: tls12_cid records (RFC 9146) parse as DTLS 1.2 layers chained with the other records in their datagram. When the connection ID length is unknown, the record stays Raw quietly.
  • Where the length comes from: a DTLSContext, found through the context channel as ESPContext is. It learns the IDs the capture's own ClientHello/ServerHello negotiated and matches them by value, so mismatched lengths per direction resolve. A caller can also pass IDs or a cid_length.
  • Memory: learned IDs live on the instance only, per the owner's ruling. An extraction without a caller's context gets its own instance in its own registry, and tests fail if a shared store is reintroduced.
  • Extension 54: connection_id decodes to ConnectionId(cid=…) on SSL. TLS hellos decode it too, although RFC 9146 marks it DTLS-only.

Test vectors are a real Mbed TLS exchange, pinned against tshark's dissection. All other DTLS output is unchanged over every sample capture and a 7,047-case mutation differential. UDP.from_data without __context__ keeps the bytes exact, but CID records come back Raw, because the CID length is not on the wire. This is documented. The owner's answers on #2515 are implemented: DTLS 1.3 CID records are a follow-up in #2625, and a reused instance keeps its IDs. A Sonnet cross-review returned GOOD TO GO, and its notes are folded in.

Closes #2515

- tls12_cid records fell back to Raw: their CID sits before the length
  and its length is negotiated. DTLS parses them with a
  DTLSCIDCiphertext schema and data model, keeping the content encrypted.
- DTLSContext resolves the length from CIDs the hellos negotiated, matched
  by value, then from a caller's cid_length; unknown stays Raw, quietly.
  Learned CIDs live on the instance, and each extraction gets its own.
- SSL decodes the connection_id extension; a TLS hello carrying it,
  DTLS-only per RFC 9146 section 10.2, decodes too. make() takes cid.
- Chained records, rebuilds and makes carry the CIDs they need.

Tests: an Mbed TLS 4.2.0 capture cross-checked with tshark 4.6.9, plus
RFC 9146 Figure 3 vectors; both round trips byte-exact.
@JarryShaw JarryShaw added this to the PyPCAPKit v1.6 milestone Nov 2, 2026
@JarryShaw JarryShaw added feat Pull requests that add a new capability (feat: subject prefix) review: good-to-go Cross-review at the current head says ready; CI state is separate labels Nov 2, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

GOOD TO GO at a020c98b6.

A Sonnet cross-review checked the record layout against RFC 9146 (§4 Figure 3, §3, and §10.3 for the DTLS 1.2 limit). tshark's dissection agrees with every CID record in the Mbed TLS capture. A 7,047-case mutation differential found no change outside CID datagrams. Handled refusals stay quiet.

The fix round applied the owner's ruling that memory is per instance. Nothing was shared before; tests now fail if any shared store returns. It also documented two things: extension 54 decoding in TLS hellos, and the prefix-match caveat.

@JarryShaw
JarryShaw merged commit f0ce065 into main Nov 2, 2026
14 checks passed
@JarryShaw
JarryShaw deleted the feat/2515-dtls-cid branch November 2, 2026 05:07
@github-project-automation github-project-automation Bot moved this to Done in PyPCAPKit Nov 2, 2026
@JarryShaw JarryShaw removed the review: good-to-go Cross-review at the current head says ready; CI state is separate label Nov 2, 2026
JarryShaw added a commit that referenced this pull request Nov 2, 2026
…types and the registry split into 1.6.0 (#2449)

- Breaking: Quick-Start values their fields cannot carry raise, reversing
  1.5.0's round-down of a TCP rate under 80 kbps (#2630).
- Folded into unreleased entries: tls12_cid records and DTLSContext
  (#2631), LinkType 105 and 127 in Frame and PCAP-NG (#2632), and
  DTLS.analyze_handshake behind dtls_handshake and packet (#2634).
- Changed: foundation.registry.protocols split into per-layer submodules
  (#2635); 1.6.0's register_* roles and 1.5.0's three register_protocol*
  roles point at their submodules, 1.5.0's text unchanged.
- The conventions entry records the per-layer wrapper placement (#2635)
  and parse ownership (#2634). No entry for #2629, which changes no
  released behaviour.
- CHANGELOG.md regenerated; util/changelog_md.py --check passes.
JarryShaw added a commit that referenced this pull request Nov 2, 2026
#2515)

#2631 added DTLSCIDCiphertext (data and schema) and the TLS ConnectionId
extension data to their submodules' __all__ but not to the packages, so
test_every_package_reexports_every_child_export failed on main.

- data.application: DTLS_CIDCiphertext, TLS_ConnectionId
- schema.application: DTLS_CIDCiphertext
- data and schema aggregators list the same names in __all__

Aliases follow the <protocol>_<name> form the siblings use
(DTLS_Ciphertext, TLS_ExtensionData). The test is not tier-gated; it fails
on 3.14 as well, and passes on 3.14 and 3.15 with this change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat Pull requests that add a new capability (feat: subject prefix)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

feat(application): dissect RFC 9146 connection-ID DTLS records

1 participant