12 KiB
FIPS ESP32 Internet Tunnel Proxy — Architecture Plan (Option 2)
Goal
Enable an ESP32 device on any WiFi network to reach FIPS mesh destinations by npub without running the full FIPS mesh stack locally.
This option introduces a public Tunnel Proxy service:
- ESP32 connects to proxy over an internet-safe authenticated tunnel transport.
- Proxy joins/runs on FIPS mesh as a full node.
- ESP32 keeps end-to-end session cryptography (Noise XK to remote FIPS destination).
- Proxy handles mesh routing, peer management, tree/bloom/discovery internals.
Why This Exists
The full embedded FIPS port is powerful but heavy (link layer, mesh routing, discovery, bloom filters, tree state, wire framing, etc.).
A plain internet gateway is simpler, but it degrades the core FIPS property (routing/addressing by npub identity at the endpoint layer).
This tunnel-proxy design targets a middle path:
- Keep ESP32 lightweight enough for constrained firmware.
- Preserve destination addressing by npub.
- Keep session-layer crypto endpoint-bound (ESP32 ↔ remote destination).
Non-Goals
- Replacing native full-node FIPS implementations.
- Guaranteeing relay-free NAT traversal between two arbitrary private endpoints.
- Eliminating all trust in proxy operators (proxy still affects availability/metadata).
High-Level Architecture
graph TD
subgraph "ESP32 Device (Any WiFi)"
APP["Nostr App / Publisher"]
XK["Noise XK Session Engine\n(init/responder)"]
TP["Tunnel Transport Client\n(TLS/Noise-IK stream)"]
TPC["Tunnel Proxy Client Protocol\n(frame mux)"]
end
subgraph "Public Internet"
NET["Internet"]
end
subgraph "Proxy Host (Public)"
TPS["Tunnel Proxy Server\n(auth + session map)"]
BR["Leaf Session Broker\nXK frame relay"]
FIPSD["fipsd full node\n(tree+bloom+routing)"]
CTL["Control API to fipsd"]
TUN["fips0 TUN / session ingress-egress"]
end
subgraph "FIPS Mesh"
REMOTE["Remote FIPS Destination\n(e.g., Nostr relay node)"]
end
APP <--> XK
XK <--> TPC
TPC <--> TP
TP <--> NET
NET <--> TPS
TPS <--> BR
BR <--> CTL
BR <--> TUN
TUN <--> FIPSD
FIPSD <--> REMOTE
Core Design Choice
Split responsibilities
ESP32 keeps:
- Device identity key material (nsec/npub).
- Noise XK session handshake + transport encryption/decryption.
- Application framing (Nostr over WS-like stream abstraction).
Proxy keeps:
- FIPS mesh connectivity (peer transport, IK links, routing, tree/bloom/discovery).
- Mapping device identity to routable leaf representation.
- Reliable relay of opaque session datagrams between mesh and device tunnel.
Trust Model
Proxy is trusted for
- Availability (may drop, delay, or reorder packets).
- Correct registration and routing relay behavior.
- Access control enforcement for admitted devices.
Proxy is NOT trusted for
- Device private key custody.
- Session key custody.
- Decrypting application payload that is Noise XK-protected end-to-end.
Metadata exposure
Proxy can observe timing, volume, target identity metadata, and liveness.
Identity and Addressing Model
Each ESP32 has its own FIPS identity (npub/node_addr). The proxy maintains a device registry:
device_npub -> node_addr -> active_tunnel_connectiondevice_npub -> auth policy- optional aliases/tags for operations
The proxy registers device identities as managed dependents in the local FIPS node state so mesh traffic can be routed to those addresses.
Tunnel Transport Options
Option A (recommended first): TLS + mutual device authentication
- ESP32 opens outbound TCP/TLS to public proxy endpoint.
- Device authenticates with challenge signed by device nsec (or static client cert mapped to npub).
- Easy NAT/firewall compatibility.
Option B (future): Noise IK tunnel
- Lower overhead and cryptographic consistency with FIPS stack.
- More custom implementation and operational tooling required.
Requirement regardless of option
Tunnel transport itself must provide anti-injection and replay-resilient framing for control messages.
Tunnel Control Protocol (TCP over TLS/Noise)
Length-prefixed binary messages, multiplexed per logical FIPS session.
Frame header proposal:
+---------+-----------+------------+-------------+
| type(1) | flags(1) | stream_id | len (4 BE) |
| | | (4 bytes) | |
+---------+-----------+------------+-------------+
| payload (len bytes)
+---------------------------------------------------+
Message types
0x01 AUTH_HELLO(device -> proxy)0x02 AUTH_CHALLENGE(proxy -> device)0x03 AUTH_PROOF(device -> proxy)0x04 AUTH_OK/0x05 AUTH_FAIL0x10 OPEN_SESSION(device requests remote npub + service/port)0x11 SESSION_OPENED/0x12 SESSION_OPEN_FAIL0x20 XK_MSG1(initiator msg1 payload)0x21 XK_MSG20x22 XK_MSG30x30 DATA_CIPHERTEXT0x40 CLOSE_SESSION0x50 HEARTBEAT0xFF ERROR
stream_id is tunnel-local multiplexing key for concurrent destination sessions.
Session/Data Path
Outbound (ESP32 initiates to remote npub)
- ESP32 authenticates tunnel.
- ESP32 sends
OPEN_SESSION(remote_npub, service_port). - Proxy resolves/registers route context in fipsd.
- ESP32 sends XK msg1 via
XK_MSG1(stream_id). - Proxy wraps as FIPS SessionSetup toward remote node_addr.
- Mesh delivers to remote destination.
- Remote returns msg2/msg3 path via mesh; proxy forwards raw handshake bytes.
- ESP32 and remote complete XK and derive session keys.
- ESP32 sends encrypted application ciphertext frames; proxy relays opaquely.
Inbound (remote initiates to ESP32)
- Remote sends SessionSetup to device node_addr.
- fipsd local-delivers to proxy-managed dependent handler.
- Proxy forwards raw msg1 to active ESP32 tunnel.
- ESP32 generates msg2; proxy relays back through mesh.
- msg3 relayed to ESP32; session established.
- Ongoing ciphertext data relay in both directions.
Required fipsd/Proxy Integration Surface
Two viable server-side integration styles:
Style 1: TUN interception (lower daemon changes)
- Proxy reads/writes on
fips0for managed dependent addresses. - Performs IPv6 adapter translation where needed.
- Faster prototype but more packet-shim complexity.
Style 2: SessionDatagram control API (preferred long-term)
Expose explicit APIs/events from fipsd:
register_managed_leaf(npub)/unregister_managed_leaf(npub)send_session_datagram(src,dst,payload)subscribe_managed_leaf_datagrams()
This avoids tunnel-proxy dependence on TUN packet plumbing and keeps relay at protocol-native layer.
Security Requirements
- Device authentication bound to npub identity.
- Per-device ACLs (allowed destinations, rate limits, max sessions).
- Replay protection for tunnel control plane (nonce/window or strict monotonic sequence per connection).
- Idle/session timeout and forced re-auth.
- Structured audit logs (auth, open/close, errors, throttles).
Failure Handling
Device disconnect
- Mark device offline.
- Keep managed leaf registration with short grace period (configurable).
- Reject inbound session opens until re-authenticated.
Proxy restart
- Rebuild device registry from persisted config/state.
- Re-register managed leaves in fipsd.
- Active sessions re-established lazily.
Mesh path failures
- Surface CoordsRequired/PathBroken/MtuExceeded upstream as control events.
- ESP32 may retry setup using same stream_id or a new stream_id.
Performance Targets (initial)
- Tunnel auth handshake: < 1.5 s on typical WiFi.
- Session open (XK) median: < 2.5 s internet-to-mesh.
- Added proxy relay overhead: < 15 ms median per direction (excluding mesh path latency).
- Concurrent sessions per device: 2 initially (expand later).
Implementation Phases
Phase 0 — Protocol/spec freeze
- Finalize tunnel frame format and auth method.
- Decide Style 1 (TUN) vs Style 2 (SessionDatagram API) for first implementation.
- Define compatibility/version negotiation field in
AUTH_HELLO.
Deliverables:
docs/design/fips-esp32-tunnel-proxy-spec.md(wire-level spec)- test vectors for auth and framing
Phase 1 — Proxy MVP (single device, outbound only)
- Public listener with TLS auth challenge.
- Static registry for one device npub.
OPEN_SESSION+ outbound XK relay only.- Relay encrypted data frames.
Validation:
- ESP32 publishes kind1 to FIPS-hosted relay by remote npub.
Phase 2 — Inbound initiation and multi-device
- Inbound SessionSetup forwarding to correct device tunnel.
- Multi-device concurrent tunnels.
- Session map eviction and collision handling.
Validation:
- Remote node initiates to ESP32 identity successfully.
Phase 3 — Robustness and controls
- ACL, rate-limits, heartbeat, reconnect backoff.
- Observability metrics and trace IDs.
- Integration tests under packet loss/reorder.
Validation:
- 24h soak test with intermittent WiFi loss.
Phase 4 — Hardening and rollout
- Key rotation procedures.
- Proxy HA strategy (active/passive or sticky shard by device npub).
- Operational docs and incident runbooks.
ESP32 Firmware Delta vs Current Projects
Relative to existing internet nostr client:
- Add tunnel client transport module.
- Add auth challenge signer using existing nsec.
- Keep/use Noise XK session module from bridge plan.
- Keep Nostr message construction/signing path unchanged.
Relative to current full leaf port effort:
- Remove need for on-device tree/bloom/discovery/link IK stack.
- Keep only session crypto + app protocol + tunnel mux.
Suggested Repository Layout (new components)
proxy/
fips-tunnel-proxy/
src/
auth.rs
frame.rs
session_broker.rs
fips_integration.rs
main.rs
esp32/
tunnel_client/
tunnel_transport.c
tunnel_transport.h
tunnel_proto.c
tunnel_proto.h
tunnel_auth.c
tunnel_auth.h
Test Plan
Unit
- Frame parser fuzz tests.
- Auth challenge/response verification tests.
- Session map state machine tests.
Integration
- ESP32 simulator/client -> proxy -> test fipsd node -> relay service.
- Inbound and outbound XK handshake relay.
- Packet loss/reorder simulation on tunnel and mesh links.
End-to-end
- Real ESP32 from multiple WiFi networks (home, hotspot, enterprise guest).
- Publish + readback nostr events over FIPS path by destination npub.
Migration Strategy
- Keep current full-leaf client as reference implementation.
- Implement tunnel-proxy MVP and switch one test device.
- Compare reliability/latency and code size.
- Decide whether to deprecate full on-device mesh stack for production devices.
Risks and Mitigations
- Proxy centralization risk -> support multiple proxies and device failover list.
- Tunnel protocol complexity creep -> strict scope; avoid embedding mesh semantics in tunnel layer.
- Auth/key misuse -> use explicit key separation labels and domain-separated signatures.
- Operational single point of failure -> health checks, watchdog restart, persistent registry snapshots.
Success Criteria
- ESP32 can publish to FIPS-hosted nostr relay from arbitrary internet WiFi.
- Destination addressed by npub at session setup interface.
- ESP32 firmware complexity materially reduced versus full mesh port.
- Proxy never requires device private keys and cannot decrypt end-to-end session payload.