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.
Certificate handshake message ¶
The TLS 1.2 (and earlier) Certificate handshake message is decoded: the certificate_list is walked and each DER certificate is chained through internal/x509decode to surface subject / issuer / validity / SAN / fingerprints / CA flag — so a captured handshake yields the server's cert chain in one decode. In TLS 1.3 the Certificate message is encrypted, so the plaintext form seen in a passive capture is the pre-1.3 layout decoded here; a body that doesn't match it is reported with a note, never mis-parsed.
What this package does NOT cover (deliberately out of scope) ¶
- 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 CertEntry ¶ added in v0.473.0
type CertEntry struct {
Length int `json:"length"`
Certificate *x509decode.Certificate `json:"x509,omitempty"`
DERHex string `json:"der_hex,omitempty"`
DecodeError string `json:"decode_error,omitempty"`
}
CertEntry is one certificate from the chain, decoded via internal/x509decode.
type Certificate ¶ added in v0.473.0
type Certificate struct {
CertificateCount int `json:"certificate_count"`
Certificates []*CertEntry `json:"certificates,omitempty"`
Notes []string `json:"notes,omitempty"`
}
Certificate is a decoded TLS Certificate handshake message (the TLS 1.2 / TLS 1.0-1.1 form: a 3-byte certificate_list length followed by 3-byte-length-prefixed DER certificates). In TLS 1.3 the Certificate message is encrypted (sent after the handshake keys are derived), so the plaintext form visible in a passive capture is the pre-1.3 layout decoded here; a body that does not match it (e.g. a decrypted 1.3 message with its request-context prefix and per-certificate extensions) is reported with a note rather than mis-parsed.
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"`
Certificate *Certificate `json:"certificate,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.