@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
ProtocolErrorCodeWhy the protocol rejected the input
§message
stringHuman-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
unknownAny 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:ProtocolErrorCodeWhy 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:stringThis endpoint's identity as stamped on packets
§readonly peerId:stringThe peer's identity as stamped on packets
§readonly protocol:stringThe negotiated protocol identifier
§readonly role:SessionRoleWhether 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