Documentation
¶
Overview ¶
Package tlsdecode decodes the cleartext portion of a TLS handshake — the ClientHello and ServerHello records that every TLS connection emits in the clear before encryption is negotiated. This is the workhorse pcap-and-paste tool for SOC blue-team analysis (JA3 / JA4 fingerprinting, plaintext SNI extraction, ALPN inspection), threat-intel triage (cipher-suite weakness scanning, version downgrade detection), and offensive recon (server preference fingerprinting, client-stack identification).
Wrap-vs-native judgement ¶
Native. The TLS record layer and handshake messages are fully published in RFC 5246 (TLS 1.2), RFC 8446 (TLS 1.3), and the IANA TLS registries. Every field is a fixed-length integer, length-prefixed byte string, or list. Extension dispatch is a switch over a 2-byte type. Pasting a hex blob extracted from a Wireshark TLS frame, a tcpdump-of- 443 capture, or a tshark `tls.handshake` field is enough — no cryptography (the cleartext portion is the entire scope), no key material, no live network attach.
What this package covers ¶
- TLS record layer envelope: ContentType (Handshake / ChangeCipherSpec / Alert / ApplicationData), Version (major + minor, with TLS 1.0..1.3 name lookup), Length. Multiple back-to-back records in one buffer are supported.
- Handshake message dispatch: ClientHello, ServerHello, HelloRetryRequest, NewSessionTicket, EndOfEarlyData, EncryptedExtensions, Certificate, CertificateRequest, CertificateVerify, Finished, KeyUpdate, MessageHash. Bodies for non-ClientHello / non-ServerHello messages are surfaced as raw hex.
- ClientHello body: legacy_version, random (32 bytes), legacy_session_id, cipher_suites (with IANA name lookup for ~80 suites covering all current TLS 1.3 suites + the most-deployed TLS 1.2 suites including ECDHE-RSA-AES, ECDHE-ECDSA-AES, ChaCha20-Poly1305, and the deprecated-but-still-seen RSA / 3DES / CBC legacy suites), compression_methods, extensions.
- ServerHello body: same field layout as ClientHello but with single selected cipher suite + compression method.
- Extension dispatch with type-name lookup for ~30 IANA- registered extensions. Deep decode for the operationally-important ones:
- server_name (type 0): extracts the SNI value (only host_name name_type 0 is in scope).
- supported_groups (type 10): list of named curves / DH groups with name lookup.
- signature_algorithms (type 13): list of SignatureScheme codes with name lookup.
- application_layer_protocol_negotiation (type 16, ALPN): list of protocol strings (h2, http/1.1, etc.).
- supported_versions (type 43): the canonical TLS 1.3 version-negotiation extension.
- key_share (type 51): list of (group, key) pairs with the group name surfaced.
- **JA3 fingerprint** (per the Salesforce / John Althouse spec): the comma-separated string "version,cipher_suites,extensions,curves, ec_point_formats" with hyphens between list members, plus its MD5 hash. The standard JA3 client fingerprint identifies the TLS client stack (browser, library, malware family) across thousands of distinct signatures.
What this package does NOT cover (deliberately out of scope) ¶
- Certificate body decode (X.509 ASN.1 — that's a separate ~600 LoC walker that warrants its own iteration). The Certificate handshake message is labeled but the cert bytes are surfaced as raw hex.
- Encrypted ApplicationData / CCS / Alert bodies: the record envelope is decoded but the post-handshake ciphertext is opaque without key material.
- JA4 / JA4S / JA4H / JA4X fingerprinting: the newer fingerprint family (FoxIO LLC, 2023) uses a different scheme; deferred until operators show real demand.
- TLS 1.3 inner handshake (EncryptedExtensions onward) is encrypted on the wire and requires session-key material that this Spec deliberately does not handle.
- DTLS (Datagram TLS over UDP) — slight envelope differences (record sequence number); deferred.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CipherSuite ¶
type CipherSuite struct {
Value uint16 `json:"value"`
Hex string `json:"hex"`
Name string `json:"name,omitempty"`
}
CipherSuite is one TLS cipher suite reference.
type ClientHello ¶
type ClientHello struct {
VersionMajor int `json:"version_major"`
VersionMinor int `json:"version_minor"`
VersionName string `json:"version_name"`
RandomHex string `json:"random_hex"`
SessionIDHex string `json:"session_id_hex"`
CipherSuites []CipherSuite `json:"cipher_suites"`
CompressionMethods []int `json:"compression_methods"`
Extensions []*Extension `json:"extensions,omitempty"`
ServerName string `json:"server_name,omitempty"`
ALPNProtocols []string `json:"alpn_protocols,omitempty"`
SupportedVersions []string `json:"supported_versions,omitempty"`
SupportedGroups []string `json:"supported_groups,omitempty"`
SignatureAlgorithms []string `json:"signature_algorithms,omitempty"`
JA3 string `json:"ja3,omitempty"`
JA3Hash string `json:"ja3_hash,omitempty"`
}
ClientHello is the decoded TLS ClientHello body.
type Extension ¶
type Extension struct {
Type int `json:"type"`
TypeName string `json:"type_name"`
Length int `json:"length"`
DataHex string `json:"data_hex,omitempty"`
}
Extension is one TLS extension.
type Frame ¶
type Frame struct {
Records []*Record `json:"records"`
}
Frame is a list of decoded TLS records — TCP segments often pack multiple back-to-back records, so the top-level result is always a slice.
func DecodeBytes ¶
DecodeBytes parses raw TLS record bytes — one or more back-to-back records.
type Handshake ¶
type Handshake struct {
MessageType int `json:"message_type"`
MessageName string `json:"message_name"`
Length int `json:"length"`
ClientHello *ClientHello `json:"client_hello,omitempty"`
ServerHello *ServerHello `json:"server_hello,omitempty"`
BodyHex string `json:"body_hex,omitempty"`
}
Handshake is one TLS handshake message inside a record.
type Record ¶
type Record struct {
ContentType int `json:"content_type"`
ContentName string `json:"content_name"`
VersionMajor int `json:"version_major"`
VersionMinor int `json:"version_minor"`
VersionName string `json:"version_name"`
Length int `json:"length"`
Handshakes []*Handshake `json:"handshakes,omitempty"`
BodyHex string `json:"body_hex,omitempty"`
}
Record is one TLS record-layer frame.
type ServerHello ¶
type ServerHello struct {
VersionMajor int `json:"version_major"`
VersionMinor int `json:"version_minor"`
VersionName string `json:"version_name"`
RandomHex string `json:"random_hex"`
SessionIDHex string `json:"session_id_hex"`
CipherSuite CipherSuite `json:"cipher_suite"`
CompressionMethod int `json:"compression_method"`
Extensions []*Extension `json:"extensions,omitempty"`
NegotiatedALPN string `json:"negotiated_alpn,omitempty"`
NegotiatedVersion string `json:"negotiated_version,omitempty"`
}
ServerHello is the decoded TLS ServerHello body. Same shape as ClientHello but with a single selected cipher suite + compression method.