client2

package
v0.0.72 Latest Latest
Warning

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

Go to latest
Published: Feb 4, 2026 License: AGPL-3.0 Imports: 48 Imported by: 0

Documentation

Overview

SPDX-FileCopyrightText: © 2023 David Stainton SPDX-License-Identifier: AGPL-3.0-only

Client2 is the new low level client for Katzenpost mix networks.

Introduction

Client2 uses a privilege separated design where many applications use a thin client library to connect to a single client2 daemon which multiplexes their connections to the mixnet Gateway node.

A Katzenpost mixnet client has several responsibilities at minimum:

* compose Sphinx packets * decrypt SURB replies * send and receive PQ Noise protocol messages * keep up to date with the latest PKI document

Overview

Applications will be integrated with Katzenpost using the thin client library which gives them the capability to talk with the client2 daemon and in that way interact with the mix network. The reason we call it a thin client library is because it does not do any mixnet related cryptography since that is already handled by the client2 daemon. In particular, the PKI document is stripped by the daemon before it's passed on to the thin clients. Likewise, thin clients don't decrypt SURB replies or compose Sphinx packets, instead all the PQ Noise, Sphinx and PKI related cryptography are handled by the daemon.

For more details, please see our Thin client design document: https://katzenpost.network/docs/specs/thin_client.html

SPDX-FileCopyrightText: (c) 2024, 2025 David Stainton. SPDX-License-Identifier: AGPL-3.0-only

SPDX-FileCopyrightText: © 2023 David Stainton SPDX-License-Identifier: AGPL-3.0-only

Index

Constants

View Source
const (
	// MessageIDLength is the length of a message ID in bytes.
	MessageIDLength = 16

	// RoundTripTimeSlop is the slop added to the expected packet
	// round trip timeout threshold.
	RoundTripTimeSlop = (3 * time.Minute) + (45 * time.Second)

	MaxRetransmissions = 3
)
View Source
const (
	// ChannelIDField is the CBOR field name for channel ID.
	ChannelIDField = "channel_id"
	// PayloadField is the CBOR field name for payload.
	PayloadField = "payload"
	// MessageIDField is the CBOR field name for message ID.
	MessageIDField = "message_id"
	// ErrField is the CBOR field name for error (omitempty).
	ErrField = "err,omitempty"
)

CBOR field constants

View Source
const (
	// AppIDLength is the length of the application ID in bytes.
	AppIDLength = 16
)
View Source
const (
	// EchoService is the standardized service string for the echo service.
	EchoService = "echo"
)

Service constants

View Source
const (
	// HaltingState indicates the client is halting.
	HaltingState = "halting"
)

State constants

Variables

View Source
var (
	// ErrNotConnected is the error returned when an operation fails due to the
	// client not currently being connected to the Gateway.
	ErrNotConnected = errors.New("client/conn: not connected to the Gateway")

	// ErrShutdown is the error returned when the connection is closed due to
	// a call to Shutdown().
	ErrShutdown = errors.New("shutdown requested")
)
View Source
var (
	PublishDeadline = vServer.PublishConsensusDeadline

	// WarpedEpoch is a build time flag that accelerates the recheckInterval
	WarpedEpoch = "false"
)

Functions

func CreateChannelReadRequest added in v0.0.50

func CreateChannelReadRequest(channelID [thin.ChannelIDLength]byte,
	statefulReader *bacap.StatefulReader,
	doc *cpki.Document) (*pigeonhole.CourierEnvelope, nike.PrivateKey, error)

func CreateChannelReadRequestWithBoxID added in v0.0.50

func CreateChannelReadRequestWithBoxID(channelID [thin.ChannelIDLength]byte,
	boxID *[bacap.BoxIDSize]byte,
	doc *cpki.Document) (*pigeonhole.CourierEnvelope, nike.PrivateKey, error)

func CreateChannelWriteRequest added in v0.0.50

func CreateChannelWriteRequest(
	statefulWriter *bacap.StatefulWriter,
	payload []byte,
	doc *cpki.Document,
	geometry *pigeonholeGeo.Geometry) (*pigeonhole.CourierEnvelope, nike.PrivateKey, error)

func CreateChannelWriteRequestPrepareOnly added in v0.0.50

func CreateChannelWriteRequestPrepareOnly(
	statefulWriter *bacap.StatefulWriter,
	payload []byte,
	doc *cpki.Document,
	geometry *pigeonholeGeo.Geometry) (*pigeonhole.CourierEnvelope, nike.PrivateKey, error)

CreateChannelWriteRequestPrepareOnly prepares a write request WITHOUT advancing StatefulWriter state. This allows for deferred state advancement until courier acknowledgment.

func GetRandomCourier added in v0.0.50

func GetRandomCourier(doc *cpki.Document) (*[hash.HashSize]byte, []byte, error)

func IntoThinResponse

func IntoThinResponse(r *Response) *thin.Response

func NewListener

func NewListener(client *Client, rates *Rates, egressCh chan *Request, logBackend *log.Backend, onAppDisconnectFn func(*[AppIDLength]byte)) (*listener, error)

New creates a new listener.

func NewPigeonholeChannel added in v0.0.50

func NewPigeonholeChannel() (*bacap.StatefulWriter, *bacap.ReadCap, *bacap.WriteCap)

Types

type ARQMessage

type ARQMessage struct {

	// AppID identifies the application sending/receiving the message/reply.
	AppID *[AppIDLength]byte

	// MessageID is the unique message identifier
	MessageID *[MessageIDLength]byte

	// DestinationIdHash is 32 byte hash of the destination Provider's
	// identity public key.
	DestinationIdHash *[32]byte

	// RecipientQueueID is the queue identity which will receive the message.
	RecipientQueueID []byte

	// Payload is the message payload
	Payload []byte

	// SURBID is the SURB identifier.
	SURBID *[sConstants.SURBIDLength]byte

	// SURBDecryptionKeys is the SURB decryption keys
	SURBDecryptionKeys []byte

	// Retransmissions counts the number of times the message has been retransmitted.
	Retransmissions uint32

	// SentAt contains the time the message was sent.
	SentAt time.Time

	// ReplyETA is the expected round trip time to receive a response.
	ReplyETA time.Duration
}

ARQMessage is used by ARQ.

type CachedDoc

type CachedDoc struct {
	Doc  *cpki.Document
	Blob []byte
}

type ChannelDescriptor added in v0.0.50

type ChannelDescriptor struct {
	// AppID tracks which thin client owns this channel for cleanup purposes
	AppID *[AppIDLength]byte

	StatefulWriter     *bacap.StatefulWriter
	StatefulWriterLock sync.Mutex

	StatefulReader     *bacap.StatefulReader
	StatefulReaderLock sync.Mutex

	EnvelopeDescriptors     map[[hash.HashSize]byte]*EnvelopeDescriptor
	EnvelopeDescriptorsLock sync.RWMutex
}

ChannelDescriptor describes a pigeonhole channel and supplies us with everything we need to read or write to the channel.

type Client

type Client struct {
	worker.Worker
	sync.RWMutex

	PKIClient cpki.Client

	// DialContextFn is the optional alternative Dialer.DialContext function
	// to be used when creating outgoing network connections.
	DialContextFn func(ctx context.Context, network, address string) (net.Conn, error)
	// contains filtered or unexported fields
}

Client manages startup, shutdow, creating new connections and reconnecting.

func New

func New(cfg *config.Config, logBackend *log.Backend) (*Client, error)

New creates a new Client with the provided configuration.

func (*Client) ClockSkew

func (c *Client) ClockSkew() time.Duration

ClockSkew returns the current best guess difference between the client's system clock and the network's global clock, rounded to the nearest second, as measured against the provider during the handshake process. Calls to this routine should not be made until the first `ClientConfig.OnConnFn(true)` callback.

func (*Client) ComposeSphinxPacket

func (c *Client) ComposeSphinxPacket(request *Request) (pkt []byte, surbkey []byte, rtt time.Duration, err error)

ComposeSphinxPacket is used to compose Sphinx packets.

func (*Client) ComposeSphinxPacketForQuery added in v0.0.55

func (c *Client) ComposeSphinxPacketForQuery(request *thin.SendChannelQuery, surbID *[sConstants.SURBIDLength]byte) (pkt []byte, surbkey []byte, rtt time.Duration, err error)

ComposeSphinxPacketForQuery is used to compose Sphinx packets for channel queries.

func (*Client) CurrentDocument

func (c *Client) CurrentDocument() ([]byte, *cpki.Document)

CurrentDocument returns the current pki.Document, or nil iff one does not exist. The caller MUST NOT modify the returned object in any way.

func (*Client) ForceFetch

func (c *Client) ForceFetch()

ForceFetch attempts to force an otherwise idle client to attempt to fetch the contents of the user's spool. This call has no effect if a connection is not established or if the connection is already in the middle of a fetch cycle, and should be considered a best effort operation.

func (*Client) ForceFetchPKI

func (c *Client) ForceFetchPKI()

ForceFetchPKI attempts to force client's pkiclient to wake and fetch consensus documents immediately.

func (*Client) GetDocumentByEpoch added in v0.0.50

func (c *Client) GetDocumentByEpoch(epoch uint64) *cpki.Document

func (*Client) GetPollInterval

func (c *Client) GetPollInterval() time.Duration

XXX This will go away once we get rid of polling.

func (*Client) SendChannelQuery added in v0.0.55

func (c *Client) SendChannelQuery(sendQuery *thin.SendChannelQuery, surbID *[sConstants.SURBIDLength]byte) (surbKey []byte, rtt time.Duration, err error)

SendChannelQuery

func (*Client) SendCiphertext

func (c *Client) SendCiphertext(request *Request) ([]byte, time.Duration, error)

SendCiphertext sends the ciphertext b to the recipient/provider, with a SURB identified by surbID, and returns the SURB decryption key and total round trip delay. Blocks until packet is sent on the wire.

func (*Client) SendPacket

func (c *Client) SendPacket(pkt []byte) error

func (*Client) SetPollInterval

func (c *Client) SetPollInterval(interval time.Duration)

XXX This will go away once we get rid of polling.

func (*Client) Shutdown

func (c *Client) Shutdown()

Shutdown cleanly shuts down a given Client instance.

func (*Client) Start

func (c *Client) Start() error

func (*Client) WaitForCurrentDocument

func (c *Client) WaitForCurrentDocument()

type ConnectError

type ConnectError struct {
	// Err is the original error that caused the connect attempt to fail.
	Err error
}

ConnectError is the error used to indicate that a connect attempt has failed.

func (*ConnectError) Error

func (e *ConnectError) Error() string

Error implements the error interface.

type ConsensusGetter

type ConsensusGetter interface {
	GetConsensus(ctx context.Context, epoch uint64) (*commands.Consensus2, error)
}

type Daemon

type Daemon struct {
	worker.Worker
	// contains filtered or unexported fields
}

func NewDaemon

func NewDaemon(cfg *config.Config) (*Daemon, error)

func (*Daemon) Shutdown

func (d *Daemon) Shutdown()

Shutdown cleanly shuts down a given Server instance.

func (*Daemon) Start

func (d *Daemon) Start() error

type EnvelopeDescriptor added in v0.0.50

type EnvelopeDescriptor struct {
	// Epoch is the Katzenpost epoch in which the ReplyIndex is valid.
	Epoch uint64

	// ReplicaNums are the replica numbers used for this envelope.
	ReplicaNums [2]uint8

	// EnvelopeKey is the Private NIKE Key used with our MKEM scheme.
	EnvelopeKey []byte
}

EnvelopeDescriptor supplies us with everthing we need to decrypt an encrypted envelope reply from a storage replica via the courier. The assumption is that we have access to the PKI document for the Epoch in which the envelope was sent.

func EnvelopeDescriptorFromBytes added in v0.0.54

func EnvelopeDescriptorFromBytes(blob []byte) (*EnvelopeDescriptor, error)

EnvelopeDescriptorFromBytes uses CBOR to deserialize the EnvelopeDescriptor.

func (*EnvelopeDescriptor) Bytes added in v0.0.54

func (e *EnvelopeDescriptor) Bytes() ([]byte, error)

Bytes uses CBOR to serialize the EnvelopeDescriptor.

type PKIError

type PKIError struct {
	// Err is the original PKI error.
	Err error
}

PKIError is the error used to indicate PKI related failures.

func (*PKIError) Error

func (e *PKIError) Error() string

Error implements the error interface.

type ProtocolError

type ProtocolError struct {
	// Err is the original error that triggered connection termination.
	Err error
}

ProtocolError is the error used to indicate that the connection was closed due to wire protocol related reasons.

func (*ProtocolError) Error

func (e *ProtocolError) Error() string

Error implements the error interface.

type Rates

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

type ReplyHandlerParams added in v0.0.50

type ReplyHandlerParams struct {
	AppID       *[AppIDLength]byte
	MessageID   *[MessageIDLength]byte
	ChannelID   uint16
	ChannelDesc *ChannelDescriptor
	EnvHash     *[hash.HashSize]byte
	IsReader    bool
	IsWriter    bool
	ReplyIndex  uint8
}

ReplyHandlerParams groups parameters for reply handler functions

type Request

type Request struct {
	// AppID must be a unique identity for the client application
	// that is sending this Request.
	AppID *[AppIDLength]byte

	CreateWriteChannel *thin.CreateWriteChannel

	CreateReadChannel *thin.CreateReadChannel

	WriteChannel *thin.WriteChannel

	ReadChannel *thin.ReadChannel

	ResumeWriteChannel *thin.ResumeWriteChannel

	ResumeReadChannel *thin.ResumeReadChannel

	ResumeWriteChannelQuery *thin.ResumeWriteChannelQuery

	ResumeReadChannelQuery *thin.ResumeReadChannelQuery

	CloseChannel *thin.CloseChannel

	SendChannelQuery *thin.SendChannelQuery

	ThinClose *thin.ThinClose

	SendLoopDecoy *SendLoopDecoy

	SendDropDecoy *SendDropDecoy

	SendMessage *thin.SendMessage

	SendARQMessage *thin.SendARQMessage
}

func FromThinRequest

func FromThinRequest(r *thin.Request, appid *[AppIDLength]byte) *Request

type Response

type Response struct {
	// AppID must be a unique identity for the client application
	// that is receiving this Response.
	AppID *[AppIDLength]byte

	ShutdownEvent *thin.ShutdownEvent

	ConnectionStatusEvent *thin.ConnectionStatusEvent

	NewPKIDocumentEvent *thin.NewPKIDocumentEvent

	MessageSentEvent *thin.MessageSentEvent

	MessageReplyEvent *thin.MessageReplyEvent

	MessageIDGarbageCollected *thin.MessageIDGarbageCollected

	CreateWriteChannelReply *thin.CreateWriteChannelReply

	CreateReadChannelReply *thin.CreateReadChannelReply

	WriteChannelReply *thin.WriteChannelReply

	ReadChannelReply *thin.ReadChannelReply

	ResumeWriteChannelReply *thin.ResumeWriteChannelReply

	ResumeReadChannelReply *thin.ResumeReadChannelReply

	ResumeWriteChannelQueryReply *thin.ResumeWriteChannelQueryReply

	ResumeReadChannelQueryReply *thin.ResumeReadChannelQueryReply

	ChannelQuerySentEvent *thin.ChannelQuerySentEvent

	ChannelQueryReplyEvent *thin.ChannelQueryReplyEvent
}

type SendDropDecoy added in v0.0.55

type SendDropDecoy struct {
}

type SendLoopDecoy added in v0.0.55

type SendLoopDecoy struct {
}

type StoredEnvelopeData added in v0.0.50

type StoredEnvelopeData struct {
	Envelope *pigeonhole.CourierEnvelope
	BoxID    *[bacap.BoxIDSize]byte
}

StoredEnvelopeData contains the envelope and associated box ID for reuse

type TimerQueue

type TimerQueue struct {
	worker.Worker
	// contains filtered or unexported fields
}

func NewTimerQueue

func NewTimerQueue(action func(interface{})) *TimerQueue

func (*TimerQueue) Len

func (t *TimerQueue) Len() int

func (*TimerQueue) Peek

func (t *TimerQueue) Peek() *queue.Entry

func (*TimerQueue) Pop

func (t *TimerQueue) Pop() interface{}

func (*TimerQueue) Push

func (t *TimerQueue) Push(priority uint64, value interface{})

func (*TimerQueue) Start

func (t *TimerQueue) Start()

Directories

Path Synopsis
Package config implements the configuration for the Katzenpost client.
Package config implements the configuration for the Katzenpost client.
Package proxy implements the support for an upstream (outgoing) proxy.
Package proxy implements the support for an upstream (outgoing) proxy.
Package thin provides a lightweight client API for the Katzenpost mixnet.
Package thin provides a lightweight client API for the Katzenpost mixnet.

Jump to

Keyboard shortcuts

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