Reference Design · HTTP-Free Transport

A data channel to entityOS Cloud with no HTTP.

Point-to-point, mutually authenticated, over a single TCP port. CESR on the wire, ACDCs as payloads, KERI for identity, authentication, and key rotation. When the goal is to get HTTP/HTTPS out of the stack — by design, or because 80/443 is blocked at the firewall — this is how you run your own strictly-framed, cryptographically-attributable channel instead.

One TCP Port CESR Framing ACDC Payloads KERI Direct Mode Default-Deny
Get The Threat Model Right First

What this actually buys you.

It is easy to oversell, and the design decisions depend on it. Blocking HTTP/S and running your own signed channel does not make payloads inspectable by the firewall — an encrypted or signed custom channel is exactly as opaque to deep-packet inspection as TLS is. You are not making threats detectable at the network. You are relocating inspection to your endpoint.

A razor-narrow firewall allow

One port, known peers, default-deny — instead of the permissive HTTP attack surface. The firewall's job shrinks to a single question: is this the one port, from a known peer?

No free-text region on the wire

No headers, no body, no content-type. Header injection, content-type confusion, request smuggling and TLS-tunnelled exfil simply do not exist as constructs — there is nowhere to put them.

Cryptographic attribution

Every frame is attributable to a specific KERI AID. Anything unauthenticated or off-schema is dropped before it reaches application logic — validation moves from generic DPI to your endpoint checking typed, signed frames.

That is a strong posture. It is an endpoint-side posture, not a firewall-side one. Say so.

Architecture Five Layers, Lowest To Highest

One stream. Five layers stacked on plain TCP.

The channel is a single TCP stream on the one allowed port. No TLS record layer is needed — CESR is self-framing. Everything above the socket is comparatively easy bookkeeping; the framing layer is where the anti-stuffing property lives.

Transportplain TCP · one allowed port
Framing — CESRtyped · self-framing · signed groups
Identity / Auth — KERI direct modeKEL exchange + receipts · no CA, no cert chain
Payload — ACDCsvalidated against pinned schema SAIDs
Session Integritymonotonic sequence / nonce replay guard
↑ you add this — KERI does not give it for free
  • Transport is just TCP on the one open port. Optionally wrap it in WireGuard for a silent-drop property at the network edge.
  • Framing is CESR: typed, self-framing, signed. A frame either parses as valid CESR with a valid signature over a known AID, or the parser drops the stream.
  • Identity is KERI direct mode. KEL exchange plus receipts give mutual authentication with no certificate authority and no chain to validate.
  • Payload is ACDCs, validated against schema SAIDs pinned ahead of time. Well-formed-but-wrong is rejected here, after framing rejects garbage.
  • Session integrity is the one layer you own entirely: a monotonic sequence or nonce inside each signed ACDC, enforced after signature verification and before any effect.
Lock the version before you write code

Pick CESR/KERI v1 or v2 and commit — the version-string format and the count-code tables differ. Do not hardcode code assignments from memory; drive your tables directly from the CESR spec tables. This is the one area where recall is not trustworthy.

The Core Problem A Streaming CESR Parser

The parser is the whole game.

Everything else sits on top of this and is easy bookkeeping. Get the parser wrong and you desync the stream; get it right and the rest follows. It must be self-framing and restartable on partial reads — TCP hands you arbitrary byte chunks, so at each frame boundary the parser must be able to say "need more bytes" and consume nothing, or a split read corrupts state.

At each frame boundary, sniff the first byte's high bits — the tritet — to decide what you hold: a serialised KERI event (JSON begins with {; CBOR and MGPK have their own leads), a CESR text primitive, or a CESR binary group. That dispatch is the cold start. Never parse until you can prove you hold a complete unit.

Events — sized by version string

Read the size, then take exactly that many bytes

  • The v field embeds the serialisation kind and the byte length
  • Read just far enough to extract that size
  • Take exactly that many bytes as the event
  • Do not scan for a closing brace — nesting and non-JSON serialisations make that wrong
Conflating these two mechanisms is the classic desync bug.
Attachments — sized by count codes

Parse the code, then consume exactly that span

  • After the event come CESR count-coded groups
  • Indexed signatures, receipt couples, seal triples
  • The count code states how many quadlets or bytes follow
  • Parse the code, then consume exactly that span — no more, no less
Two distinct framing mechanisms. Keep them separate in code.
loop: sniff first byte (tritet) at frame boundary read event: extract size from version string -> take exactly that many bytes read attachment group(s): parse count code -> consume exactly that span assemble (event + attachments) into one unit hand the unit up to the state machine repeat

The connection state machine

The parser surfaces complete units; the state machine gives them meaning. Point-to-point makes the handshake an IK-equivalent — the client bakes in entityOS.cloud's AID and current key state ahead of time and pins it. Pre-rotation is what makes that safe: each rotation commits to the next key, so a pinned AID plus verified KEL history proves the counterparty with no negotiation an attacker can downgrade.

  1. 1

    Cold start / genus

    Optionally consume a leading genus-version count code (v2), then expect the peer's inception and any rotation events establishing its KEL.

  2. 2

    KEL verification

    Verify the peer's establishment history against the pinned AID. Reject on any mismatch before emitting anything.

  3. 3

    Receipts

    Direct mode is receipt-based: issue a receipt (chit) over the peer's events and expect theirs over yours. The parser already surfaces receipt couples as an attachment group — route that unit to the receipt handler.

  4. 4

    Steady state

    ACDC exchange, schema-validated against pinned SAIDs, each carrying a monotonic sequence or nonce. The replay guard lives here — after signature verification, before any application effect.

  5. 5

    Rotation

    A rotation event arrives as an ordinary event unit. Verify against the pre-rotation commitment, update key state, continue on the same socket. This is why long-lived links stay secure without reconnecting through any external PKI.

Where This Differs

HTTP/TLS stack vs. the KERI direct channel.

Same opacity to the network. A very different attack surface, and a different place where trust is anchored.

Property HTTP / TLS Stack KERI Direct Channel
Firewall allowPermissive 80/443One port, known peers, default-deny
Free-text region on the wireHeaders, body, content-typeNone — typed frames only
Header injection / smugglingPossibleNot a construct
Per-message attributionSession-level (TLS)Every frame → a KERI AID
CA / cert-chain dependencyRequiredNone
Key rotationRe-issue / reconnectIn-band, same socket
Payload inspectable at firewallNo (encrypted)No — relocated to endpoint
Replay / ordering guardBuilt into TLS recordsYou add it yourself

The last two rows are the honest ones: opacity is unchanged, and one guarantee TLS gave you for free is now your responsibility.

Security Requirements

What KERI gives you — and what you must add.

KERI direct mode hands you attribution and rotation. It does not give you the rest. These are the pieces you build, and the first two are the ones most commonly skipped.

01
Per-frame attribution
Every signed frame ties to a specific KERI AID. This comes for free.
Given
02
In-band key rotation
Pre-rotation commitments let keys roll on the live socket. This comes for free.
Given
03
Replay + ordering guard
A monotonic sequence or nonce inside each signed ACDC; reject non-advancing values. Without it, a captured valid frame replays. Enforce it after signature verification, before any effect.
Add Yourself
04
Two-stage payload validation
CESR framing rejects garbage; schema validation rejects well-formed-but-wrong. Both stages stay cryptographically attributable to the sender's AID.
Add Yourself

The client now owns TLS-equivalent duties: key management, rotation, replay protection, downgrade resistance. KERI hands you rotation; do not hand-roll the rest casually.

Hand-Rolling The Stream Layer Three Traps, In The Order They Bite

Nearly all the risk lives in three places.

If you are reusing an existing KERI library's transport, the parser section does not apply to you — direct-mode transport is a smaller shim job. If you are writing the stream layer yourself, these are the ones to fuzz, bound, and order correctly.

Partial-read correctness

Fuzz this first. Feed the parser the same valid stream sliced at every byte offset and assert identical output. If a one-byte-at-a-time feed does not match a whole-buffer feed, the "need more bytes" logic is wrong. Highest-value test you will write.

Backpressure

A signed event can be large; a peer can pipeline many before you receipt. Bound the accumulation buffer and stop reading the socket when full, or an authenticated peer can OOM you. Silent-drop at the firewall does not help — these are bytes from a peer you already trust.

Verify-before-act ordering

A structurally valid unit is not an authenticated one. The order is always: parse → verify signature over the AID → replay check → then act. Never let a parsed-but-unverified unit reach application logic.

Optional network envelope — WireGuard

Pure app-layer over plain TCP works. But for a silent-drop property at the network edge, run the TCP channel inside WireGuard: the firewall opens one UDP port, and any packet without valid keys gets no response at all — scanners and stuffing attempts hit a black hole. WireGuard is Noise-based and mutually authenticated, so it composes cleanly under the KERI layer.

Scope & Cautions

Point-to-point only. Endpoint-side by design.

// scope

Point-to-point, no discovery

No witnesses, no mailboxes, no OOBIs over HTTP. If you later need fan-out or store-and-forward, that is a different design — witness/mailbox mode — and out of scope here.

client entityOS.cloud
one TCP port · pinned AIDs
// operations

Scope the firewall block

Blocking 80/443 breaks package repos, OS updates, other APIs and third-party SaaS. Apply the block to the segment or service tier that talks to entityOS.cloud — not the whole network.

block 80/443 at the tier
not the perimeter
// reference

Read, don't reuse

keripy's directing module (Director / Directant over TCP) is the closest existing implementation of this shape. Read it for receipt-handshake sequencing — most other KERI deployments assume witness/mailbox mode over HTTP and will mislead you.

keripy directing
Director · Directant

Blocking HTTP and running your own signed channel does not make threats detectable at the network. It relocates inspection from a generic DPI guessing at arbitrary HTTP to your endpoint validating decrypted, typed, signed frames against a strict schema.

The entityOS.cloud application-level ACDC schemas come from the entityOS side and are pinned by SAID. The wire is yours; the meaning is theirs.