scanner

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 4, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package scanner enumerates TLS protocol versions, cipher suites and key exchange groups by sending its own ClientHello messages and reading only the server's reply. It does not depend on which algorithms the local TLS library implements, so it can detect SSLv2, export and NULL ciphers that no modern client would negotiate. Probes never complete a handshake and send no application data.

Index

Constants

View Source
const (
	VersionSSL2  uint16 = 0x0002
	VersionSSL3  uint16 = 0x0300
	VersionTLS10 uint16 = 0x0301
	VersionTLS11 uint16 = 0x0302
	VersionTLS12 uint16 = 0x0303
	VersionTLS13 uint16 = 0x0304
)

Protocol version codes.

View Source
const (
	GroupSecp256r1      uint16 = 23
	GroupSecp384r1      uint16 = 24
	GroupSecp521r1      uint16 = 25
	GroupX25519         uint16 = 29
	GroupX448           uint16 = 30
	GroupFFDHE2048      uint16 = 256
	GroupFFDHE3072      uint16 = 257
	GroupFFDHE4096      uint16 = 258
	GroupFFDHE6144      uint16 = 259
	GroupFFDHE8192      uint16 = 260
	GroupX25519MLKEM768 uint16 = 0x11EC
	GroupP256MLKEM768   uint16 = 0x11EB
	GroupP384MLKEM1024  uint16 = 0x11ED
)

Named groups.

Variables

AllVersions is the probe order.

View Source
var ErrNotTLS = errors.New("server response is not TLS")

ErrNotTLS means the peer answered with something that is not TLS.

View Source
var ErrRejected = errors.New("rejected by server")

ErrRejected means the server refused the offered parameters (alert, or closed the connection) — i.e. "not supported".

TLS13Groups are probed individually in TLS 1.3 group enumeration.

Functions

func AlertName

func AlertName(d byte) string

AlertName names an alert description.

func ExtensionName

func ExtensionName(t uint16) string

ExtensionName names a TLS extension type.

func GroupBits

func GroupBits(g uint16) int

GroupBits is the approximate security-relevant size used for grading.

func GroupName

func GroupName(g uint16) string

GroupName names a named group.

func LegacySuites

func LegacySuites() []uint16

LegacySuites returns all TLS 1.0–1.2 suites.

func TLS13Suites

func TLS13Suites() []uint16

TLS13Suites returns the TLS 1.3 suites in registry order.

func VersionName

func VersionName(v uint16) string

VersionName returns "TLS 1.2" style names.

Types

type AcceptedSuite

type AcceptedSuite struct {
	Suite
	KeyExchange *KeyExchange `json:"key_exchange_params,omitempty"`
}

AcceptedSuite is a cipher suite the server negotiated.

type AlertError

type AlertError struct {
	Level       byte
	Description byte
}

AlertError is a TLS alert received instead of a ServerHello.

func (*AlertError) Error

func (e *AlertError) Error() string

type CipherResult

type CipherResult struct {
	Version         string          `json:"version"`
	ID              uint16          `json:"id"`
	Suites          []AcceptedSuite `json:"suites"`
	ServerPreferred *bool           `json:"server_order,omitempty"` // nil when fewer than two suites
	Error           string          `json:"error,omitempty"`
}

CipherResult lists the suites accepted for one version.

type Dialer

type Dialer func(ctx context.Context) (net.Conn, error)

Dialer returns a connection that is ready for a ClientHello: for STARTTLS protocols the plaintext upgrade has already happened.

type Extras

type Extras struct {
	SecureRenegotiation  *bool    `json:"secure_renegotiation,omitempty"` // RFC 5746
	FallbackSCSV         *bool    `json:"fallback_scsv,omitempty"`        // RFC 7507; nil if not testable
	Compression          *bool    `json:"compression,omitempty"`          // TLS compression accepted (CRIME)
	SessionTickets       *bool    `json:"session_tickets,omitempty"`
	ExtendedMasterSecret *bool    `json:"extended_master_secret,omitempty"`
	EncryptThenMAC       *bool    `json:"encrypt_then_mac,omitempty"`
	Extensions           []string `json:"server_extensions,omitempty"` // at the highest TLS ≤1.2 version
}

Extras holds protocol behaviour checks.

type GroupResult

type GroupResult struct {
	TLS13 []string `json:"tls13,omitempty"`
	TLS12 []string `json:"tls12,omitempty"` // ECDHE curves accepted with TLS ≤1.2
}

GroupResult lists supported key exchange groups.

type Hello

type Hello struct {
	Version           uint16   // legacy_version field
	RecordVersion     uint16   // record layer version; 0 = min(Version, TLS 1.0)
	Suites            []uint16 // cipher suites in preference order
	ServerName        string   // SNI; omitted for IP addresses and when empty
	SupportedVersions []uint16 // TLS 1.3 supported_versions; nil omits the extension
	Groups            []uint16 // supported_groups; nil = default for the version
	KeyShares         []uint16 // groups to send key shares for (TLS 1.3); nil = x25519
	NoKeyShares       bool     // send an empty key_share (forces HelloRetryRequest)
	Compression       []byte   // compression methods; nil = null only
	ALPN              []string
	Fallback          bool // append TLS_FALLBACK_SCSV
	NoRenegotiation   bool // omit TLS_EMPTY_RENEGOTIATION_INFO_SCSV
}

Hello describes a ClientHello to send.

func (*Hello) Marshal

func (h *Hello) Marshal() ([]byte, error)

Marshal encodes the ClientHello as a single TLS record.

type KeyExchange

type KeyExchange struct {
	Kind    string `json:"kind"` // ECDH or DH
	Group   string `json:"group,omitempty"`
	GroupID uint16 `json:"group_id,omitempty"`
	Bits    int    `json:"bits"`
}

KeyExchange describes the server's ephemeral parameters (TLS ≤1.2).

func (*KeyExchange) String

func (k *KeyExchange) String() string

String formats e.g. "ECDH x25519" or "DH 2048 bits".

type Prober

type Prober struct {
	Dial        Dialer
	ServerName  string
	Timeout     time.Duration // per probe; default 10s
	Concurrency int           // parallel probes; default 8
}

Prober sends ClientHello probes to one endpoint.

func (*Prober) CheckExtras

func (p *Prober) CheckExtras(ctx context.Context, minLegacy, maxLegacy uint16) Extras

CheckExtras runs behaviour probes. maxLegacy is the highest supported version ≤ TLS 1.2 (0 if none); minLegacy the lowest ≥ TLS 1.0.

func (*Prober) Ciphers

func (p *Prober) Ciphers(ctx context.Context, v uint16) CipherResult

Ciphers enumerates the suites accepted with version v by repeatedly offering every not-yet-accepted suite. When the server enforces its own order the result is in server preference order.

func (*Prober) CiphersAll

func (p *Prober) CiphersAll(ctx context.Context, versions []uint16) []CipherResult

CiphersAll enumerates suites for each supported version concurrently.

func (*Prober) Curves12

func (p *Prober) Curves12(ctx context.Context, v uint16, ecdheSuites []uint16) []string

Curves12 finds ECDHE curves accepted with TLS ≤1.2 using the given ECDHE suites (from cipher enumeration).

func (*Prober) Groups13

func (p *Prober) Groups13(ctx context.Context) []string

Groups13 finds the TLS 1.3 groups the server accepts. Each probe offers a single group with no key share; a supporting server must answer with a HelloRetryRequest naming that group.

func (*Prober) ProbeVersion

func (p *Prober) ProbeVersion(ctx context.Context, v uint16) VersionResult

ProbeVersion tests whether the server accepts version v.

func (*Prober) Send

func (p *Prober) Send(ctx context.Context, h *Hello, wantMore bool) (*ServerHello, error)

Send performs one probe. wantMore also reads Certificate and ServerKeyExchange for TLS ≤1.2.

func (*Prober) Versions

func (p *Prober) Versions(ctx context.Context) []VersionResult

Versions probes every protocol version concurrently.

type ServerHello

type ServerHello struct {
	LegacyVersion uint16
	Version       uint16 // negotiated version (supported_versions if present)
	CipherSuite   uint16
	Compression   byte
	SessionIDLen  int
	Extensions    []uint16 // extension types in order received

	HelloRetry    bool
	KeyShareGroup uint16
	// Filled from later handshake messages for TLS ≤1.2 when requested.
	Certificates [][]byte // DER, as sent
	KeyExchange  *KeyExchange
	// contains filtered or unexported fields
}

ServerHello is the parsed server response to a probe.

func (*ServerHello) ExtensionData

func (s *ServerHello) ExtensionData(t uint16) []byte

ExtensionData returns the raw body of extension t.

func (*ServerHello) HasExtension

func (s *ServerHello) HasExtension(t uint16) bool

HasExtension reports whether the server sent extension t.

type Suite

type Suite struct {
	ID       uint16   `json:"id"`
	Name     string   `json:"name"`
	KeyExch  string   `json:"key_exchange"`   // ECDHE, DHE, RSA, ECDH, DH, PSK, SRP, TLS1.3, NULL
	Auth     string   `json:"authentication"` // RSA, ECDSA, DSS, anon, PSK, SRP, any, NULL
	Cipher   string   `json:"cipher"`         // AES, 3DES, RC4, CHACHA20, ...
	Bits     int      `json:"bits"`
	Mode     string   `json:"mode"` // GCM, CCM, CCM8, CBC, POLY1305, stream, none
	MAC      string   `json:"mac"`  // AEAD, SHA, SHA256, SHA384, MD5
	Export   bool     `json:"export"`
	TLS13    bool     `json:"tls13"`
	Strength string   `json:"strength"` // modern, deprecated, weak, insecure
	Reasons  []string `json:"reasons,omitempty"`
}

Suite describes one cipher suite.

func Lookup

func Lookup(id uint16) Suite

Lookup returns the suite with id, or a placeholder for unknown IDs.

func (Suite) AEAD

func (s Suite) AEAD() bool

AEAD reports whether the suite uses authenticated encryption.

func (Suite) ForwardSecret

func (s Suite) ForwardSecret() bool

ForwardSecret reports whether the key exchange is ephemeral.

type VersionResult

type VersionResult struct {
	Version   string `json:"version"`
	ID        uint16 `json:"id"`
	Supported bool   `json:"supported"`
	Error     string `json:"error,omitempty"` // probe failed (not a rejection)
}

VersionResult is the outcome for one protocol version.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL