tls

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 20, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const TypeTLS protocol.Type = 13

Variables

This section is empty.

Functions

func NewState

func NewState(c protocol.Context) any

func Protocol

func Protocol() protocol.Payload

Types

type BuffConn

type BuffConn struct {
	// contains filtered or unexported fields
}

BuffConn is an in-memory net.Conn that bridges a sequence of short-lived EAP handler invocations with the single long-lived crypto/tls handshake goroutine started in tlsInit.

Threading model:

  • The TLS goroutine is the SOLE caller of Read/Write/Close/deadline setters.
  • Handler goroutines are the SOLE callers of FeedFlight/WaitOutbound/ HarvestFlight and the inspection helpers.

Every field is guarded by mu. State changes are published by replacing the notify channel (broadcastLocked), which both Read and WaitOutbound select on; this gives condition-variable semantics that also compose with context cancellation and deadlines. The previous implementation shared two *bytes.Buffer values and a pair of non-atomic counters across both goroutines and relied on retry/backoff timing for correctness, which is a data race.

func NewBuffConn

func NewBuffConn(ctx context.Context, cctx protocol.Context) *BuffConn

NewBuffConn creates an empty conn. Peer data (including the first ClientHello flight) is delivered exclusively through FeedFlight so there is a single ingestion path.

func (*BuffConn) Close

func (c *BuffConn) Close() error

func (*BuffConn) FeedFlight added in v0.2.0

func (c *BuffConn) FeedFlight(data []byte)

FeedFlight delivers one complete, reassembled peer flight (EAP fragmentation already stripped by the payload layer) and wakes a parked Read. It resets the read-waiting state because it provides exactly the data the TLS goroutine was waiting for, which prevents a later WaitOutbound from observing a stale "waiting" signal from before this flight.

func (*BuffConn) HarvestFlight added in v0.2.0

func (c *BuffConn) HarvestFlight() []byte

HarvestFlight atomically drains and returns the accumulated outbound bytes.

func (*BuffConn) InboundLen added in v0.2.0

func (c *BuffConn) InboundLen() int

InboundLen reports how many inbound bytes are buffered (unconsumed by TLS).

func (*BuffConn) LocalAddr

func (c *BuffConn) LocalAddr() net.Addr

func (*BuffConn) OutboundLen added in v0.2.0

func (c *BuffConn) OutboundLen() int

OutboundLen reports how many outbound bytes are buffered.

func (*BuffConn) PeekInbound added in v0.2.0

func (c *BuffConn) PeekInbound() []byte

PeekInbound returns a copy of the unconsumed inbound bytes.

func (*BuffConn) Read

func (c *BuffConn) Read(p []byte) (int, error)

Read implements net.Conn for the TLS goroutine. It returns buffered inbound bytes immediately (supporting short reads); otherwise it records that it is waiting, wakes any pending WaitOutbound, and parks until more data arrives, the conn is closed, the context is cancelled, or the read deadline fires.

func (*BuffConn) ReadWaiting added in v0.2.0

func (c *BuffConn) ReadWaiting() bool

ReadWaiting reports whether the TLS goroutine is currently parked waiting for more peer data. Intended for tests.

func (*BuffConn) RemoteAddr

func (c *BuffConn) RemoteAddr() net.Addr

func (*BuffConn) ResetInbound added in v0.2.0

func (c *BuffConn) ResetInbound()

ResetInbound discards any unconsumed inbound bytes.

func (*BuffConn) ResetOutbound added in v0.2.0

func (c *BuffConn) ResetOutbound()

ResetOutbound discards any unharvested outbound bytes.

func (*BuffConn) SetDeadline

func (c *BuffConn) SetDeadline(t time.Time) error

func (*BuffConn) SetReadDeadline

func (c *BuffConn) SetReadDeadline(t time.Time) error

func (*BuffConn) SetWriteDeadline

func (c *BuffConn) SetWriteDeadline(t time.Time) error

func (*BuffConn) WaitOutbound added in v0.2.0

func (c *BuffConn) WaitOutbound(done, errc <-chan struct{}) WaitOutcome

WaitOutbound blocks until the TLS goroutine has produced outbound bytes, is parked waiting for the next peer flight, the handshake finished (done), the handshake errored (errc), the context expired, or the conn closed. It never busy-polls. done and errc may be nil (those arms simply never fire).

func (*BuffConn) Write

func (c *BuffConn) Write(p []byte) (int, error)

Write implements net.Conn for the TLS goroutine. It appends to the outbound buffer, wakes any pending WaitOutbound, and never blocks.

type Flag

type Flag byte
const (
	FlagLengthIncluded Flag = 1 << 7
	FlagMoreFragments  Flag = 1 << 6
	FlagTLSStart       Flag = 1 << 5
	FlagNone           Flag = 0
)

type Payload

type Payload struct {
	Flags  Flag
	Length uint32
	Data   []byte

	Inner protocol.Payload
	// contains filtered or unexported fields
}

func (*Payload) Decode

func (p *Payload) Decode(raw []byte) error

func (*Payload) Encode

func (p *Payload) Encode() ([]byte, error)

func (*Payload) Handle

func (p *Payload) Handle(ctx protocol.Context) protocol.Payload

Handle advances the EAP-TLS exchange by one RADIUS round-trip: on first call it starts the TLS handshake (tlsInit), then on each call it feeds the reassembled peer flight to the background handshake goroutine, waits for the goroutine's response without polling, fragments and returns the outbound flight, and on completion resolves the final status — or, when wrapped by PEAP, delegates the protected channel to the inner protocol. See _RFC.md for the concurrency model.

func (*Payload) HasInner

func (p *Payload) HasInner() protocol.Payload

func (*Payload) ModifyRADIUSResponse

func (p *Payload) ModifyRADIUSResponse(r *radius.Packet, q *radius.Packet) error

func (*Payload) Offerable

func (p *Payload) Offerable() bool

func (*Payload) String

func (p *Payload) String() string

func (*Payload) Type

func (p *Payload) Type() protocol.Type

type Settings

type Settings struct {
	Config *tls.Config
	// VerifyPeerCertificate mirrors tls.Config.VerifyPeerCertificate while adding
	// protocol.Context. Note that Go does not invoke this callback on resumed
	// connections.
	VerifyPeerCertificate func(ctx protocol.Context, rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
	// VerifyConnection mirrors tls.Config.VerifyConnection while adding
	// protocol.Context. Prefer this hook for production-critical validation that
	// must also run on resumed connections.
	VerifyConnection func(ctx protocol.Context, cs tls.ConnectionState) error
	// HandshakeSuccessful runs after the TLS handshake has completed and the EAP
	// layer is ready to decide whether the authenticated client should proceed.
	HandshakeSuccessful func(ctx protocol.Context, certs []*x509.Certificate) protocol.Status
	// MaxMessageSize bounds a single reassembled EAP-TLS message (one peer
	// flight). Zero selects the package default (64 KiB). It guards against a
	// malicious peer declaring an enormous fragmented message (RFC 5216 Section 3.1).
	MaxMessageSize int
}

Settings defines the reusable TLS extension points for EAP-TLS/PEAP consumers.

Consumers that only need native Go TLS client-certificate enforcement can keep Config.ClientAuth at tls.RequireAndVerifyClientCert and leave the hooks nil.

Consumers that need identity-aware inspection or application-specific policy decisions during the handshake can instead require certificate presence (typically tls.RequireAnyClientCert) and perform their own validation in VerifyConnection. That hook runs for all connections, including resumptions.

func (Settings) MaxTLSMessageSize added in v0.2.0

func (s Settings) MaxTLSMessageSize() int

MaxTLSMessageSize exposes the configured reassembly bound to the TLS layer.

func (Settings) TLSConfig

func (s Settings) TLSConfig() *tls.Config

type State

type State struct {

	// TLS is the server side of the in-memory TLS connection; Conn is the
	// byte pipe it reads from / writes to. Context (with ContextCancel) bounds
	// the whole handshake to staleConnectionTimeout and is cancelled when the
	// exchange ends. ClientHello captures the peer's hello for inspection.
	TLS           *tls.Conn
	Conn          *BuffConn
	Context       context.Context
	ContextCancel context.CancelFunc
	ClientHello   *tls.ClientHelloInfo

	HandshakeDone bool
	FinalStatus   protocol.Status

	HandshakeDoneCh chan struct{}
	HandshakeErrCh  chan struct{}

	// --- Outbound fragmentation (server -> peer) ---
	//
	// A TLS flight larger than maxChunkSize is split into RemainingChunks and
	// sent across several EAP-TLS fragments. TotalPayloadSize is the original
	// size advertised in the first fragment's Length field, and
	// IncludeLengthInNextFragment marks that first fragment.
	RemainingChunks             [][]byte
	TotalPayloadSize            int
	IncludeLengthInNextFragment bool

	// MPPEKey is the exported keying material (RFC 5216) used to derive the
	// MS-MPPE-Recv/Send keys returned on Access-Accept.
	MPPEKey []byte
	// HandshakeCtx is the protocol.Context handed to the handshake-completion
	// callbacks; Logger is the session logger.
	HandshakeCtx protocol.Context
	Logger       protocol.Logger
	// contains filtered or unexported fields
}

State is the per-session state for the EAP-TLS / PEAP outer layer. One State lives for the whole TLS exchange of a single EAP session and is persisted between RADIUS round-trips by the StateManager.

Concurrency model: the TLS handshake runs on a dedicated background goroutine (started in tlsInit) while each RADIUS packet is processed on a separate handler goroutine. The two communicate through Conn (a race-free BuffConn) and through the synchronization fields below. Every field that both goroutines may touch is accessed only through the helper methods on State, never directly, so the locking stays in one place.

func (*State) FinalStatusValue added in v0.1.4

func (s *State) FinalStatusValue() protocol.Status

func (*State) HandshakeDoneValue added in v0.1.4

func (s *State) HandshakeDoneValue() bool

func (*State) HasMore

func (s *State) HasMore() bool

func (*State) SetFinalStatus added in v0.1.4

func (s *State) SetFinalStatus(status protocol.Status)

func (*State) SetHandshakeDone added in v0.1.4

func (s *State) SetHandshakeDone(done bool)

type TLSConfig

type TLSConfig interface {
	TLSConfig() *tls.Config
}

type WaitOutcome added in v0.2.0

type WaitOutcome int

WaitOutcome reports why WaitOutbound returned.

const (
	// WaitFlightBoundary: the TLS goroutine produced outbound data and/or is
	// parked waiting for the next peer flight. The caller should harvest.
	WaitFlightBoundary WaitOutcome = iota
	// WaitHandshakeDone: the handshake completed successfully.
	WaitHandshakeDone
	// WaitError: the handshake goroutine reported an error.
	WaitError
	// WaitTimeout: the stale-connection context expired.
	WaitTimeout
	// WaitClosed: the conn was closed.
	WaitClosed
)

Jump to

Keyboard shortcuts

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