Skip to content

Security

The model

hypernova's trust model matches the deployment model: inside a technical network, frames are trusted like every other protocol on that network (DIP's position for two decades); anything that crosses a boundary is signed. Three places can sign or verify:

  • a Publisher signs at the source (sign_key=, --sign-key-file),
  • the relay signs at the boundary ("sign_key_file" on a route) — the recommended default: publishers inside stay untouched (including C++ supernova servers), and exactly the frames that leave the network carry a signature,
  • a Subscriber verifies (verify_key=, --verify-key-file) — and once it has a key it requires signatures, so an attacker cannot bypass verification by simply omitting the SecurityHeader.
python -c "import secrets; print(secrets.token_hex(32))" > stream.key
# boundary relay route:  "sign_key_file": "/etc/hypernova/stream.key"
hypernova sub site/area1/pump7/env --network officenet --verify-key-file stream.key

The wire format (hypernova signing profile v1)

Signed frames are standard OPC UA Part 14 UADP: the ExtendedFlags1 security bit, a SecurityHeader (signed flag, securityTokenId, 8-byte random nonce), and a signature appended to the NetworkMessage. The signature is HMAC-SHA256 over the entire frame (all headers and payload), 32 bytes, with a pre-shared key per stream or per boundary.

Honesty note: OPC UA Part 14 defines its own SecurityPolicies (AES-CTR-based) keyed through Security Key Services. hypernova v1 carries its signature in the standard frame structure but uses HMAC-SHA256 with pre-shared key files — simpler to deploy, verifiable in four lines of any language, but not interoperable with other stacks' Part 14 security until a full SecurityPolicy lands (roadmap). Unsigned interop is unaffected.

Properties

Threat Coverage
Forged values (spoofed publisher ids) ✅ rejected — every bit of a signed frame is authenticated (a test flips every single bit and asserts rejection)
Tampering in flight ✅ rejected
Replay 🟡 no cryptographic replay protection: a captured signed frame replays verbatim and verifies. Sequence numbers let consumers notice duplicates/reordering, but nothing rejects a replay. Acceptable for periodic telemetry (the next sample supersedes it); do not use the sign-only profile where a replayed value is itself dangerous
Eavesdropping ❌ frames are not encrypted — telemetry is treated as readable on any network it reaches
Key distribution operational: key files on publisher/relay/subscriber hosts. Keys never pass through the registry — it can browse signed streams (shown "signed, unverified") but never holds secrets

Registry and relay hardening

The registry parses attacker-reachable input on both faces (HTTP and UDP). Adversarially reviewed twice; the control plane guarantees are regression-locked:

  • malformed or hostile registrations cannot corrupt or brick it (validation before persistence, quarantine of corrupt store files, per-endpoint bind isolation),
  • hostile datagrams cannot crash it or its browser (700k-datagram fuzz, clamped timestamps, NaN-safe JSON),
  • publication names are escaped everywhere they render.

A signing relay route additionally validates every frame it forwards (it must decode to re-encode) and drops undecodable input, counting drops in its health stats.