@hyperfrontend/network-protocol/security

Security

Purpose

The Security module defines what a security protocol implements: the per-session seal and open operations, the session a protocol is bound to, the outcome of accepting a hello frame, and the machine-readable error a protocol raises when it rejects a frame or a session.


Key Interfaces

SecuritySuite<T>

The two per-session packet operations.

interface SecuritySuite<T = any> {
  readonly seal: PacketSealer<T> // (packet: UnencryptedPacket<T>) => Promise<WirePacket>
  readonly open: PacketOpener<T> // (frame: WirePacket) => Promise<UnencryptedPacket<T>>
}

PacketSealer and PacketOpener are re-exported from packet/.

ProtocolSession and SessionRole

What a protocol needs to key one session. The key material itself is minted by the protocol and exchanged through hello frames once the session exists.

type SessionRole = 'initiator' | 'responder'

interface ProtocolSession {
  readonly protocol: string // The negotiated protocol identifier, e.g. 'v3'
  readonly role: SessionRole // Which side of the handshake this endpoint played
  readonly localId: string // This endpoint's identity as stamped on packets
  readonly peerId: string // The peer's identity as stamped on packets
}

HelloOutcome

type HelloOutcome = 'accepted' | 'duplicate' | 'rejected'
OutcomeMeaning
acceptedThe peer's material is now known and the session can be keyed
duplicateThe same material was already accepted; a retry, ignored
rejectedThe frame is not a hello this session can use

ProtocolError

interface ProtocolError extends Error {
  readonly code: ProtocolErrorCode // Why the protocol rejected the input
}

The error's name is 'ProtocolError'.


Error Codes

const ProtocolErrorCode = {
  UnsupportedVersion: 'unsupported-version',
  Replayed: 'replayed',
  AuthenticationFailed: 'authentication-failed',
  Malformed: 'malformed',
  CounterExhausted: 'counter-exhausted',
  InvalidSession: 'invalid-session',
} as const

type ProtocolErrorCode = (typeof ProtocolErrorCode)[keyof typeof ProtocolErrorCode]
CodeMeaning
unsupported-versionThe frame's version byte is not this protocol's
replayedThe frame's counter is not above the last accepted one
authentication-failedThe frame's tag does not verify under the session's keys
malformedThe frame is too short, or authenticated but does not carry a packet
counter-exhaustedThe session has sealed every counter value it can represent
invalid-sessionThe session cannot be keyed from the material it holds

Functions

createProtocolError

function createProtocolError(code: ProtocolErrorCode, message: string): ProtocolError
import { createProtocolError, ProtocolErrorCode } from '@hyperfrontend/network-protocol/security'

throw createProtocolError(ProtocolErrorCode.Replayed, 'Frame counter 7 is not above the last accepted counter 9')

getProtocolErrorCode

Reads the code off any thrown value, or returns null when the value is not a protocol error.

function getProtocolErrorCode(error: unknown): ProtocolErrorCode | null
import { getProtocolErrorCode } from '@hyperfrontend/network-protocol/security'

const channel = createChannel('comms', {
  ...options,
  onDrop: (drop) => {
    const code = getProtocolErrorCode(drop.cause)
    if (code === 'authentication-failed' || code === 'replayed') {
      alarm(drop)
    }
  },
})

Where the Pieces Meet

A protocol (see protocol/) implements the suite for one session; a channel (see channel/) runs it; every rejection reaches the owner as the cause of a PacketDrop.


Relationship to Other Modules


See Also

Related Modules

ModuleRelationship
protocol/Implements the suite and raises the errors
channel/Binds a session and surfaces drops
packet/The packet shapes the operations convert

API Reference§

ƒ Functions

§function

createProtocolError(code: ProtocolErrorCode, message: string): ProtocolError

Creates a protocol error with a machine-readable code.

Parameters

NameTypeDescription
§code
ProtocolErrorCode
Why the protocol rejected the input
§message
string
Human-readable detail

Returns

ProtocolError
An error whose code survives the pipeline's drop report

Example

Rejecting a replayed frame

throw createProtocolError('replayed', 'Frame counter 7 is not above the last accepted counter 9')
§function

getProtocolErrorCode(error: unknown): ProtocolErrorCode

Reads the protocol error code off an error, when it carries one.

Parameters

NameTypeDescription
§error
unknown
Any thrown value

Returns

ProtocolErrorCode
The code, or null when the value is not a protocol error

Example

Mapping a drop to its cause

getProtocolErrorCode(drop.cause)
// => 'authentication-failed'

Interfaces

§interface

ProtocolError

An error a protocol raises, carrying a machine-readable code beside its message

Properties

§cause?:unknown
§readonly code:ProtocolErrorCode
Why the protocol rejected the input
§message:string
§name:string
§stack?:string
§interface

SecuritySuite

Suite of the two per-session packet operations

Properties

§readonly open:PacketOpener<T>
Opens incoming frames
§readonly seal:PacketSealer<T>
Seals outgoing packets
§interface

ProtocolSession

What a protocol needs to key one session: the negotiated protocol, this side's role, and both identities. The key material itself is minted by the protocol and exchanged through hello frames once the session exists.

Properties

§readonly localId:string
This endpoint's identity as stamped on packets
§readonly peerId:string
The peer's identity as stamped on packets
§readonly protocol:string
The negotiated protocol identifier
§readonly role:SessionRole
Whether this endpoint initiated or answered the handshake

Types

§type

PacketOpener

Opens wire bytes into a plaintext packet under the session's receiving key
type PacketOpener = (packet: WirePacket) => Promise<UnencryptedPacket<T>>
§type

PacketSealer

Seals a plaintext packet into wire bytes under the session's sending key
type PacketSealer = (packet: UnencryptedPacket<T>) => Promise<WirePacket>
§type

ProtocolErrorCode

One of the protocol rejection codes
type ProtocolErrorCode = indexedAccess
§type

HelloOutcome

What accepting a hello frame did.
  • accepted: the peer's material is now known and the session can be keyed
  • duplicate: the same material was already accepted; a retry, ignored
  • rejected: the frame is not a hello this session can use
type HelloOutcome = "accepted" | "duplicate" | "rejected"
§type

SessionRole

Which side of the handshake this endpoint played
type SessionRole = "initiator" | "responder"

Variables

§type

ProtocolErrorCode

Why a protocol rejected a frame or a session.
  • unsupported-version: the frame's version byte is not this protocol's
  • replayed: the frame's counter is not above the last accepted one
  • authentication-failed: the frame's tag does not verify under the session's keys
  • malformed: the frame authenticated but does not carry a packet
  • counter-exhausted: the session has sealed every counter value it can represent
  • invalid-session: the session cannot be keyed from the material it holds