session

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: May 3, 2026 License: MPL-2.0 Imports: 18 Imported by: 0

Documentation

Index

Constants

View Source
const (
	RekeyBytesThreshold = 1 << 30 // 1 GB
	RekeyMsgsThreshold  = 1 << 20 // ~1M messages
)

Re-keying thresholds for forward secrecy.

View Source
const (
	NoncePrefixOutbound uint32 = 0x4F555442 // "OUTB"
	NoncePrefixInbound  uint32 = 0x494E4244 // "INBD"
)

Nonce prefixes for direction separation (prevents nonce reuse with same key).

Variables

This section is empty.

Functions

func ComputeFingerprintFromBase64Keys

func ComputeFingerprintFromBase64Keys(pubKeys map[string]string) (string, error)

func CreateRekeyRequest

func CreateRekeyRequest(ownKeys *kbc.OwnKeys, peerKeys *kbc.PeerKeys, epoch uint64, suite kbc.CipherSuite) (*bindings.RekeyRequest, []byte, error)

CreateRekeyRequest generates a RekeyRequest with new encapsulated seeds. Returns the request, the derived new key (for outbound), and any error.

func DialWithStableAddr

func DialWithStableAddr(network, addr string, timeout time.Duration, logger *slog.Logger) (net.Conn, error)

dialWithStableAddr dials a remote address using a net.Dialer that binds to the machine's stable (non-temporary) IPv6 address. This prevents connections from breaking when macOS/Linux deprecates temporary privacy addresses (RFC 4941).

func ExchangePublicKeysLocal

func ExchangePublicKeysLocal(session *Session, conn net.Conn, isInitiator bool) error

ExchangePublicKeysLocal performs a plaintext exchange of public keys over conn. In local mode, the relay is skipped, so both peers need each other's keys before the PQC handshake can run. The initiator (joiner) sends first, responder second.

func FinalizeInboundSession

func FinalizeInboundSession(session *Session, conn net.Conn, encSeeds map[string]string) error

FinalizeInboundSession completes the inbound session setup after peer is verified. It decapsulates seeds, derives the SEKInbound, wraps the net.Conn in SecureConn, and finalizes state.

func PerformInboundHandshake

func PerformInboundHandshake(session *Session, conn net.Conn) error

PerformInboundHandshake handles the first plaintext connection from Bob to Alice.

func PerformOutboundHandshake

func PerformOutboundHandshake(session *Session, remoteAddr string) error

PerformOutboundHandshake dials remoteAddr and sends the PQC handshake.

func PerformOutboundHandshakeOnConn

func PerformOutboundHandshakeOnConn(session *Session, conn net.Conn) error

PerformOutboundHandshakeOnConn sends the PQC handshake on an existing connection. Used by bridge mode where the connection is pre-established (with room token already sent).

func ProcessRekeyRequest

func ProcessRekeyRequest(req *bindings.RekeyRequest, ownKeys *kbc.OwnKeys, peerKeys *kbc.PeerKeys, suite kbc.CipherSuite) (*bindings.RekeyResponse, []byte, error)

ProcessRekeyRequest handles an incoming RekeyRequest. Returns a RekeyResponse, the derived new inbound key, and any error.

func ProcessRekeyResponse

func ProcessRekeyResponse(resp *bindings.RekeyResponse, ownKeys *kbc.OwnKeys, peerKeys *kbc.PeerKeys, suite kbc.CipherSuite) ([]byte, error)

ProcessRekeyResponse handles an incoming RekeyResponse. Returns the derived new outbound key (peer's response seeds).

func StartListener

func StartListener(session *Session, port int) error

StartListener starts a TCP listener on the given port and waits for Bob. It will block until Bob connects and sends valid keys that match the expected fingerprint.

Types

type ConnectionHealth

type ConnectionHealth int32

ConnectionHealth represents the health state of the P2P connection.

const (
	HealthUnknown      ConnectionHealth = iota
	HealthHealthy                       // All heartbeats succeeding
	HealthDegraded                      // High latency or some failures
	HealthDisconnected                  // Connection lost, needs reconnection
)

func (ConnectionHealth) String

func (h ConnectionHealth) String() string

String returns a human-readable representation of the health state.

type HealthMonitor

type HealthMonitor struct {

	// Configuration
	Interval    time.Duration // heartbeat interval (default 5s)
	Timeout     time.Duration // per-heartbeat timeout (default 3s)
	DegradedRTT time.Duration // RTT above this = degraded (default 500ms)
	MaxFailures int           // failures before disconnect (default 3)

	// Callbacks
	OnHealthChange func(old, new ConnectionHealth)
	OnDisconnect   func()
	// contains filtered or unexported fields
}

HealthMonitor monitors the health of a P2P connection via periodic heartbeats. When enough consecutive heartbeats fail, it triggers the OnDisconnect callback.

func NewHealthMonitor

func NewHealthMonitor(session *Session, client bindings.KeibiServiceClient, logger *slog.Logger) *HealthMonitor

NewHealthMonitor creates a new health monitor with default settings.

func (*HealthMonitor) AvgRTT

func (m *HealthMonitor) AvgRTT() time.Duration

AvgRTT returns the exponential moving average of RTT.

func (*HealthMonitor) Health

func (m *HealthMonitor) Health() ConnectionHealth

Health returns the current connection health state.

func (*HealthMonitor) LastRTT

func (m *HealthMonitor) LastRTT() time.Duration

LastRTT returns the most recent round-trip time in nanoseconds.

func (*HealthMonitor) Start

func (m *HealthMonitor) Start()

Start begins the heartbeat monitoring loop in a goroutine.

func (*HealthMonitor) Stop

func (m *HealthMonitor) Stop()

Stop halts the health monitoring loop and waits for it to exit.

type PeerHandshakeMessage

type PeerHandshakeMessage struct {
	Fingerprint      string            `json:"fingerprint"`
	PublicKeys       map[string]string `json:"public_keys"` // base64 encoded
	EncSeeds         map[string]string `json:"enc_seeds"`   // optional for key encapsulation
	OutboundPort     int               `json:"port"`
	SupportedCiphers []string          `json:"supported_ciphers"` // cipher negotiation
	Persistent       bool              `json:"persistent,omitempty"`
}

PeerHandshakeMessage defines the JSON payload sent during handshake.

type ReconnectManager

type ReconnectManager struct {

	// Configuration
	Backoff     []time.Duration // Exponential backoff delays
	MaxAttempts int             // Maximum reconnection attempts

	// Connection details (cached from last successful connection)
	CachedPeerIP   string
	CachedPeerPort int

	// Bridge relay (for firewall traversal). If set, reconnect uses bridge instead of direct.
	BridgeAddr string
	DialBridge func() (net.Conn, error) // Dial bridge with room token

	// Callbacks
	OnReconnecting func()                                                    // Called when reconnection starts
	OnReconnected  func()                                                    // Called on successful reconnection
	OnGaveUp       func()                                                    // Called when all attempts exhausted
	RelayRefresh   func() error                                              // Re-register with relay
	RelayLookup    func(fingerprint string) (ip string, port int, err error) // Lookup peer in relay
	AcceptConn     func(timeout time.Duration) (net.Conn, error)             // Accept incoming connection
	// contains filtered or unexported fields
}

ReconnectManager handles automatic reconnection when the P2P connection drops. It coordinates with the health monitor and uses a deterministic initiator selection to avoid race conditions.

func NewReconnectManager

func NewReconnectManager(session *Session, logger *slog.Logger) *ReconnectManager

NewReconnectManager creates a new reconnection manager with default settings.

func (*ReconnectManager) Attempts

func (r *ReconnectManager) Attempts() int

Attempts returns the number of reconnection attempts made.

func (*ReconnectManager) IsReconnectInitiator

func (r *ReconnectManager) IsReconnectInitiator() bool

IsReconnectInitiator determines which peer should initiate reconnection. The peer with the lexicographically lower fingerprint is the initiator. This avoids race conditions where both peers try to connect simultaneously.

func (*ReconnectManager) OnDisconnect

func (r *ReconnectManager) OnDisconnect()

OnDisconnect is called when the health monitor detects a connection loss. It starts the reconnection loop in a goroutine.

func (*ReconnectManager) Reset

func (r *ReconnectManager) Reset()

Reset resets the manager to connected state (call after manual session restart).

func (*ReconnectManager) State

func (r *ReconnectManager) State() ReconnectState

State returns the current reconnection state.

func (*ReconnectManager) Stop

func (r *ReconnectManager) Stop()

Stop halts any ongoing reconnection attempts and prevents new ones.

type ReconnectState

type ReconnectState int32

ReconnectState represents the current state of the reconnection manager.

const (
	ReconnectStateConnected    ReconnectState = iota // Connection is healthy
	ReconnectStateReconnecting                       // Actively trying to reconnect
	ReconnectStateWaitingPeer                        // Waiting for peer to come online
	ReconnectStateGaveUp                             // Exhausted all retry attempts
)

func (ReconnectState) String

func (s ReconnectState) String() string

String returns a human-readable representation of the reconnect state.

type SecureConn

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

SecureConn wraps a net.Conn with separate inbound/outbound encryption.

func NewSecureConn

func NewSecureConn(conn net.Conn, kek []byte, suite kbc.CipherSuite) *SecureConn

func (*SecureConn) Accept

func (s *SecureConn) Accept() (net.Conn, error)

func (*SecureConn) Addr

func (l *SecureConn) Addr() net.Addr

func (*SecureConn) Close

func (s *SecureConn) Close() error

Close closes the underlying connection.

func (*SecureConn) GetEpoch

func (s *SecureConn) GetEpoch() uint64

GetEpoch returns the current key epoch.

func (*SecureConn) GetStats

func (s *SecureConn) GetStats() (bytesSent, bytesRecv, msgsSent, msgsRecv uint64)

GetStats returns current byte/message counts for monitoring.

func (*SecureConn) LocalAddr

func (s *SecureConn) LocalAddr() net.Addr

LocalAddr returns the local network address.

func (*SecureConn) Read

func (s *SecureConn) Read(p []byte) (int, error)

func (*SecureConn) ReadMessage

func (s *SecureConn) ReadMessage() ([]byte, error)

ReadMessage reads and decrypts a full message.

func (*SecureConn) RemoteAddr

func (s *SecureConn) RemoteAddr() net.Addr

RemoteAddr returns the remote network address.

func (*SecureConn) ResetStats

func (s *SecureConn) ResetStats()

ResetStats resets the byte/message counters after a rekey.

func (*SecureConn) SetDeadline

func (s *SecureConn) SetDeadline(t time.Time) error

func (*SecureConn) SetReadDeadline

func (s *SecureConn) SetReadDeadline(t time.Time) error

func (*SecureConn) SetWriteDeadline

func (s *SecureConn) SetWriteDeadline(t time.Time) error

func (*SecureConn) ShouldRekey

func (s *SecureConn) ShouldRekey() bool

ShouldRekey returns true if key rotation is recommended.

func (*SecureConn) UpdateKey

func (s *SecureConn) UpdateKey(newKek []byte)

UpdateKey atomically updates the encryption key (reuses negotiated cipher suite).

func (*SecureConn) Write

func (s *SecureConn) Write(p []byte) (int, error)

func (*SecureConn) WriteMessage

func (s *SecureConn) WriteMessage(msg []byte) error

WriteMessage encrypts and writes a full message.

type SecureReader

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

SecureReader reads encrypted messages and decrypts them. Caches the AEAD cipher and reuses a header buffer.

func NewSecureReader

func NewSecureReader(r io.Reader, kek []byte, suite kbc.CipherSuite) *SecureReader

func (*SecureReader) Read

func (s *SecureReader) Read() ([]byte, error)

type SecureWriter

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

SecureWriter encrypts messages and writes them to an underlying writer. Uses a cached AEAD cipher and single combined write for performance.

func NewSecureWriter

func NewSecureWriter(w io.Writer, kek []byte, suite kbc.CipherSuite) *SecureWriter

func NewSecureWriterWithPrefix

func NewSecureWriterWithPrefix(w io.Writer, kek []byte, suite kbc.CipherSuite, prefix uint32) *SecureWriter

NewSecureWriterWithPrefix creates a writer with a custom nonce prefix.

func (*SecureWriter) Write

func (s *SecureWriter) Write(p []byte) (int, error)

type Session

type Session struct {
	// Known fingerprint of the expected peer, shared out-of-band.
	ExpectedPeerFingerprint string

	OwnKeys        *kbc.OwnKeys
	OwnFingerprint string

	// Populated after receiving peer keys.
	PeerPubKeys *kbc.PeerKeys // "x25519", "mlkem"

	// Symmetric session key.
	SEKInbound  []byte
	SEKOutbound []byte

	// Negotiated cipher suite for this session.
	CipherMu    sync.Mutex
	CipherSuite kbc.CipherSuite

	// Peer-to-peer TCP connections.
	Session  *SessionSockets
	PeerPort int

	DefaultOutboundPort int
	DefaultInboundPort  int

	GRPCListener net.Listener
	GRPCClient   bindings.KeibiServiceClient

	// Session state and lifecycle
	State       SessionState
	Established time.Time

	Err error

	// Persistent identity flags (learned during handshake).
	OwnIsPersistent  bool
	PeerIsPersistent bool

	// Internal timeout deadline
	Deadline time.Time

	// Re-keying state for forward secrecy.
	RekeyMu       sync.Mutex
	LastRekeyAt   time.Time
	CurrentEpoch  uint64
	RekeyPending  bool
	PendingNewKey []byte // awaiting ACK
	// contains filtered or unexported fields
}

Session represents the state of a P2P connection between Alice and Bob.

func InitSession

func InitSession(logger *slog.Logger, defaultOutboundPort int, defaultInboundPort int) (*Session, error)

func InitSessionWithKeys added in v0.2.0

func InitSessionWithKeys(logger *slog.Logger, keys *kbc.OwnKeys, defaultOutboundPort int, defaultInboundPort int) (*Session, error)

InitSessionWithKeys creates a session using pre-existing keys (for persistent identity). Same as InitSession but skips key generation.

func NewSession

func NewSession(logger *slog.Logger, expectedFingerprint string, timeout time.Duration) *Session

NewSession initializes a new session with a timeout deadline.

func (*Session) GetFingerPrint

func (s *Session) GetFingerPrint() string

func (*Session) GetRekeyEpoch

func (s *Session) GetRekeyEpoch() uint64

GetRekeyEpoch returns the current key epoch.

func (*Session) HandleRekeyRequest

func (s *Session) HandleRekeyRequest(req *bindings.RekeyRequest) (*bindings.RekeyResponse, error)

HandleRekeyRequest processes an incoming RekeyRequest from peer. Updates inbound key and returns response for peer.

func (*Session) HandleRekeyResponse

func (s *Session) HandleRekeyResponse(resp *bindings.RekeyResponse) error

HandleRekeyResponse processes an incoming RekeyResponse from peer. Updates outbound key after peer acknowledged our rekey request.

func (*Session) IsExpired

func (s *Session) IsExpired() bool

IsExpired returns true if the session has passed its allowed timeout.

func (*Session) IsVerified

func (s *Session) IsVerified() bool

IsVerified returns true if the fingerprint matched and session is accepted.

func (*Session) MarkError

func (s *Session) MarkError(err error)

MarkError marks the session as errored and closes any open connections.

func (*Session) ReadyForEncryption

func (s *Session) ReadyForEncryption() bool

ReadyForEncryption returns true when both connections and SEKs are set.

func (*Session) ShouldRekey

func (s *Session) ShouldRekey() bool

ShouldRekey returns true if either connection has exceeded the rekey threshold.

func (*Session) Transition

func (s *Session) Transition(next SessionState) error

Transition safely updates the session state, if allowed.

func (*Session) ValidateExpired

func (s *Session) ValidateExpired()

ValidateExpired moves session to 'expired' state if deadline passed.

func (*Session) ValidatePeer

func (s *Session) ValidatePeer() error

ValidatePeer ensures peer handshake and verification are complete.

func (*Session) ValidateReady

func (s *Session) ValidateReady() error

ValidateReady ensures session is fully ready for encryption and data transfer.

type SessionSockets

type SessionSockets struct {
	Inbound  *SecureConn // Bob -> Alice
	Outbound *SecureConn // Alice -> Bob
}

SessionSockets holds a duplex connection for peer communication.

func NewSessionSockets

func NewSessionSockets(connIn, connOut net.Conn, sekIn, sekOut []byte, suite kbc.CipherSuite) *SessionSockets

type SessionState

type SessionState string
const (
	SessionInit           SessionState = "init"
	SessionStatePending   SessionState = "pending"
	SessionStateVerified  SessionState = "verified"
	SessionStateConnected SessionState = "connected"
	SessionStateError     SessionState = "error"
	SessionStateExpired   SessionState = "expired"
)

Jump to

Keyboard shortcuts

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