Skip to content

TLS record layer + ClientHello SNI extraction (RFC 8446/6066) #196

Description

@EONRaider

Target: 2.7.0 (tentative) (Tier 5 — TLS record layer & SNI, stretch)

Context

The record layer itself is trivial. What makes this a whole tier by
itself: a ClientHello's SNI (Server Name Indication) sits behind a
chain of nested, variable-length, length-prefixed structures, and
"no crypto, no full handshake" has to be an enforced boundary, not
an aspiration that erodes as the parsing gets harder.

Deliverable

Add netprotocols.TLS (layer 7, dispatched from tcp.port 443,
best-effort) scoped narrowly to record framing plus SNI extraction:

  • Decode the 5-byte TLS record header (RFC 8446 §5.1): Content Type
    (1 byte — Handshake is 22, the only one this issue cares about),
    Legacy Version (2 bytes), Length (2 bytes).
  • For a Handshake-type record, decode the 4-byte handshake header
    (Handshake Type 1 byte — ClientHello is 1; Length 3 bytes) and, for
    ClientHello only, walk far enough to reach the Extensions block:
    Legacy Version (2), Random (32), Legacy Session ID (length-prefixed,
    1-byte length), Cipher Suites (length-prefixed, 2-byte length — keep
    as raw bytes, not decoded suite-by-suite), Legacy Compression
    Methods (length-prefixed, 1-byte length), Extensions (length-
    prefixed, 2-byte length).
  • Within Extensions, decode only the shape needed to find
    server_name (type 0x0000, RFC 6066 §3): each extension is Type (2
    bytes), Length (2 bytes), Data. For server_name, Data is itself a
    length-prefixed ServerNameList of ServerName entries (Type 1
    byte — 0 is host_name, HostName length-prefixed 2 bytes, then the
    hostname bytes). Every other extension type stays raw bytes,
    correctly bounded by its own Length — this issue is not "decode TLS
    extensions," it's "find SNI."
  • Content types other than Handshake (Alert 21, ApplicationData 23,
    ChangeCipherSpec 20) decode only the 5-byte record header; their
    payload stays raw (it's ciphertext past the handshake anyway).
  • Register tcp.port 443 → TLS, best-effort.

Explicitly out of scope

ServerHello, Certificate, key exchange, any extension besides
server_name, TLS 1.2-and-earlier's different extension set, DTLS.
All are real follow-ups, not this issue.

Acceptance criteria

  • TLS decodes the record header for every content type; for
    Handshake/ClientHello, decodes far enough to extract SNI when
    present. bytes(TLS.decode(x)) == x.
  • SNI extraction verified against real ClientHello captures from
    at least two different browsers/clients (extension ordering and
    padding conventions vary).
  • A ClientHello with no server_name extension, and one with a
    truncated Extensions block, both decode without raising outside
    the library's normal ProtocolError contract.
  • TCP port 443 dispatches to TLS.
  • CHANGELOG entry documenting the "no crypto, no full handshake"
    boundary explicitly; full ladder green.

Documentation/marketing-claims cleanup for the roadmap as a whole is
its own issue now (#197), not an acceptance criterion here.

References

RFC 8446 (TLS 1.3 record layer / handshake), RFC 6066 §3 (SNI) ·
docs cleanup: #197

Part of #175

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions