eap

package
v0.0.0-...-35f84e0 Latest Latest
Warning

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

Go to latest
Published: Sep 1, 2026 License: AGPL-3.0 Imports: 18 Imported by: 0

Documentation

Overview

Package eap implements the EAP authentication framework and its MSCHAPv2 and TLS methods for IKEv2.

Index

Constants

View Source
const (
	TypeIdentity    uint8 = 1
	TypeNAK         uint8 = 3
	TypeTLS         uint8 = 13
	TypeMSCHAPv2    uint8 = 26
	TypeExpandedEAP uint8 = 254
)

EAP type codes.

View Source
const (
	CodeRequest  uint8 = 1
	CodeResponse uint8 = 2
	CodeSuccess  uint8 = 3
	CodeFailure  uint8 = 4
)

EAP codes.

Variables

View Source
var (
	ErrUnsupportedMethod = errors.New("eap: unsupported method")
	ErrIdentityRequired  = errors.New("eap: identity response required first")
	ErrMethodFailed      = errors.New("eap: method authentication failed")
)
View Source
var (
	ErrTooManyRounds = errors.New("eap: exceeded maximum exchange rounds")
	ErrEAPFailure    = errors.New("eap: authenticator sent Failure")
)
View Source
var (
	ErrPoolExhausted = errors.New("pool: all addresses allocated")
	ErrNotAllocated  = errors.New("pool: address not allocated")
)

Functions

func DeriveMSK

func DeriveMSK(password string, ntResponse [24]byte) [64]byte

DeriveMSK constructs the 64-octet EAP MSK from MS-CHAPv2 credentials. RFC 3079 Section 3 + RFC 3748 Section 7.10. MSK = MasterReceiveKey(16) || MasterSendKey(16) || zeroPadding(32). strongSwan and Windows use zero-padded MSK per draft-kamath-pppext-eap-mschapv2-02.

func GenerateAuthenticatorResponse

func GenerateAuthenticatorResponse(password string, ntResponse [24]byte, peerChallenge, authChallenge [16]byte, userName string) [20]byte

GenerateAuthenticatorResponse computes the mutual authentication proof (S= value). RFC 2759 Section 8: GenerateAuthenticatorResponse. Returns 20 raw bytes.

func GenerateNTResponse

func GenerateNTResponse(authChallenge, peerChallenge [16]byte, userName, password string) [24]byte

GenerateNTResponse computes the full NT-Response for an MS-CHAPv2 exchange. RFC 2759 Section 8: GenerateNTResponse.

func GetAsymmetricStartKey

func GetAsymmetricStartKey(masterKey [16]byte, keyLen int, isSend, isServer bool) []byte

GetAsymmetricStartKey derives a session key of the requested length. RFC 3079 Section 3: GetAsymmetricStartKey.

func GetMasterKey

func GetMasterKey(password string, ntResponse [24]byte) [16]byte

GetMasterKey derives the 16-byte MPPE master key from MS-CHAPv2 credentials. RFC 3079 Section 3: GetMasterKey.

Types

type AllocateResult

type AllocateResult struct {
	IPv4   net.IP
	IPv6   net.IP
	DNS4   []net.IP
	DNS6   []net.IP
	Domain string
}

AllocateResult holds the addresses allocated to a client.

type Method

type Method interface {
	// Type returns the EAP type code for this method.
	Type() uint8

	// Start generates the first EAP-Request for this method.
	Start(identifier uint8) *Packet

	// Process handles an EAP-Response from the peer and returns the next action.
	Process(response *Packet) MethodResult

	// Close releases every resource the method holds. The caller MUST call it
	// once the exchange has ended, for ANY reason: success, failure, refusal or
	// abandonment. A method that starts a goroutine leaks it otherwise.
	//
	// Close is idempotent and safe on a method that was never started.
	Close()
}

Method is the interface for an EAP authentication method (server/authenticator side).

type MethodConfig

type MethodConfig struct {
	// For EAP-MSCHAPv2.
	Password string `json:"-"` //nolint:gosec // EAP credential, never serialized

	// For EAP-TLS.
	CACertPEM     []byte
	ServerCertPEM []byte
	ServerKeyPEM  []byte
}

MethodConfig holds configuration needed by EAP methods.

type MethodResult

type MethodResult struct {
	Response     *Packet
	FinalRequest *Packet
	MSK          [64]byte
	Done         bool
	Err          error
}

MethodResult is the outcome of processing one EAP exchange round.

Session.handleMethod reads the fields in this order, and the four outcomes they name are mutually exclusive:

FinalRequest  send it as the method's last word, then fail with Err
Done          the exchange succeeded and MSK carries the key
Err           the exchange failed, and an EAP-Failure answers the peer
Response      the exchange continues with this EAP-Request

FinalRequest is the method's last word: a packet the method owes the peer on a refusal, sent by an exchange that has already failed. The EAP-Failure that RFC 3748 Section 4.2 obliges follows it on the next round, and nothing else can. A method that sets FinalRequest MUST set Err too, because the packet carries the protocol's reason and Err carries the operator's.

Setting Response BESIDE Err puts the packet nowhere: the Err branch answers with an EAP-Failure and the Response is discarded. That is why the last word has a field of its own rather than a flag over Response, and it is a defect this package has already paid for once (see the EAP-TLS alert in tlsMethod.Process, eap_tls.go).

type Packet

type Packet struct {
	Code       uint8
	Identifier uint8
	Type       uint8
	TypeData   []byte
}

Packet is a parsed EAP packet (Code, Identifier, Type, TypeData). RFC 3748 Section 4: Success/Failure packets have no Type field.

func DecodePacket

func DecodePacket(data []byte) (*Packet, error)

DecodePacket parses raw EAP bytes into a Packet.

func (*Packet) Encode

func (p *Packet) Encode() []byte

Encode serializes an EAP packet to wire format.

type PeerResult

type PeerResult struct {
	Response  *Packet
	MSK       [64]byte
	Done      bool
	Discarded bool
	Err       error
}

PeerResult is the outcome of processing one EAP-Request from the authenticator.

Four outcomes, and the caller reads them in this order (handleEAPResponse, internal/component/ike/engine/fsm.go):

Err        the exchange failed, and the IKE SA is put in StateDead
Done       the exchange succeeded and MSK carries the key
Response   the exchange continues with this EAP-Response
Discarded  the packet was dropped and the exchange waits for the next one

Discarded is a field rather than the absence of the other three. RFC 3748 Section 4.2 makes a peer drop several packets in silence, and the wire behavior of dropping one is indistinguishable from a result that fell out of a branch nobody wrote: both send nothing and both end no exchange. A zero value that reads as a valid answer is what ai/rules/principles.md forbids, so the drop says so, and the caller logs it because a forged EAP-Success is a thing an operator wants named.

type PeerSession

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

PeerSession manages the EAP peer (client/initiator) side of an exchange.

func NewPeerSession

func NewPeerSession(method uint8, identity, password string) *PeerSession

NewPeerSession creates an EAP peer session for the given method.

func NewPeerSessionTLS

func NewPeerSessionTLS(identity string, cfg *PeerTLSConfig) *PeerSession

NewPeerSessionTLS creates an EAP-TLS peer session with certificate material.

func (*PeerSession) Close

func (ps *PeerSession) Close()

Close releases every resource the peer session holds.

The caller MUST call it once the exchange has ended, for ANY reason: an EAP-Success, an EAP-Failure, a refused method, or an authenticator that stopped answering. The EAP-TLS client runs its TLS engine on a goroutine parked in eapTLSTransport.Read, and only closing the transport releases it, so an exchange that ends without this call strands that goroutine together with the tls.Conn and the handshake secrets it holds.

The guard reads tlsStarted rather than the pointer, because startTLSClient runs on the engine's dispatch goroutine while this runs on the session's owner goroutine. startTLSClient assigns tlsTransport BEFORE it stores that flag, so a load that sees true also sees the assignment.

Idempotent, and safe on an MS-CHAPv2 session or on one whose TLS client never started.

func (*PeerSession) Process

func (ps *PeerSession) Process(request *Packet) PeerResult

Process handles an incoming EAP packet (Request or Success/Failure) from the authenticator and returns the peer's response. On EAP-Success, Done is true and MSK is set.

func (*PeerSession) Succeeded

func (ps *PeerSession) Succeeded() bool

Succeeded reports whether the exchange completed successfully.

type PeerTLSConfig

type PeerTLSConfig struct {
	CertPEM   []byte
	KeyPEM    []byte
	CACertPEM []byte
}

PeerTLSConfig holds certificate material for the EAP-TLS peer (client).

type Pool

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

Pool manages virtual IP address allocation for road warrior clients.

func NewPool

func NewPool(ipv4CIDR, ipv6CIDR string, dns []string, domain string) (*Pool, error)

NewPool creates a pool from IPv4 CIDR, optional IPv6 CIDR, DNS servers, and search domain.

func (*Pool) Allocate

func (p *Pool) Allocate() (*AllocateResult, error)

Allocate assigns the next available address(es) from the pool.

func (*Pool) Available

func (p *Pool) Available() int

Available returns the number of unallocated IPv4 addresses.

func (*Pool) Release

func (p *Pool) Release(ip net.IP) error

Release returns an address to the pool.

type Session

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

Session manages a single EAP exchange (authenticator side).

func NewSession

func NewSession(methodType uint8, config MethodConfig) (*Session, error)

NewSession creates an EAP session for the given method type.

func (*Session) Begin

func (s *Session) Begin() *Packet

Begin returns the initial EAP-Request/Identity packet. RFC 3748 Section 5.1: authenticator starts with Identity request.

func (*Session) Close

func (s *Session) Close()

Close releases every resource the exchange holds.

The caller MUST call it once the exchange has ended, for ANY reason: an EAP-Success, an EAP-Failure, a refused method, or a peer that stopped answering. EAP-TLS runs its TLS engine on a goroutine parked in a read that only this call can release, so an exchange that ends without it leaks that goroutine and the TLS keys it holds. The peer decides how many exchanges start and how many of them it abandons, and it is unauthenticated while it does so, which is what makes the omission reachable from the network.

Close is idempotent and safe on a session whose method never started.

func (*Session) Err

func (s *Session) Err() error

Err returns why the method refused the peer, or nil when the exchange failed for a reason the method never saw: a peer that answered the Identity request with something else, or a NAK of the offered method. The caller MUST log it beside its own failure line, because RFC 3748 Section 4.2 leaves an EAP-Failure packet no field to carry a reason in and this is the only place one exists.

func (*Session) Identity

func (s *Session) Identity() string

Identity returns the peer identity extracted from the EAP-Response/Identity.

func (*Session) MSK

func (s *Session) MSK() [64]byte

MSK returns the Master Session Key after successful authentication.

func (*Session) Process

func (s *Session) Process(response *Packet) *Packet

Process handles an incoming EAP-Response and returns the next EAP-Request (or Success/Failure). Returns nil when the exchange is complete and the final packet has already been returned.

func (*Session) Succeeded

func (s *Session) Succeeded() bool

State returns whether the session completed successfully.

Jump to

Keyboard shortcuts

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