7.6 KiB
ADR-305: Authenticated sensor identity — RF chain of custody
- Status: Accepted — initial implementation planned (ADR-300 phase 1)
- Date: 2026-08-11
- Deciders: ruv
- Tags: security, identity, provenance, sensor-ingest, attestation, phase-1
Context
This ADR is a child of ADR-300 (perception substrate program) and owns primitive #5, authenticated sensor identity. In the ADR-300 dependency DAG it is a spine root that, together with ADR-306 (canonical spatial ontology), feeds ADR-301 (calibration certificate) and ADR-319 (witness chain).
RuView's inference outputs are only as trustworthy as the measurements that
produced them, yet today a measurement's origin is essentially assertional. The
UDP data plane accepts frames from any reachable host: ADR-296 shipped step
one — a loopback-default bind (--udp-bind) and an optional source
IP/CIDR allowlist — and explicitly deferred to a follow-up ADR "per-device
provisioned keys, MAC/AEAD, device identifiers, monotonic sequence numbers,
freshness window, and replay rejection." This ADR is that step two. ADR-296
correctly documented that an IP allowlist does not stop LAN spoofing; a
cryptographic device identity is what closes that gap.
Foundations already exist in the tree and must be reused rather than rebuilt:
wifi-densepose-rufieldprovidesDeviceId,Signature,SignatureBlock,FrameProvenance,ProvenanceClass, andSignatureVerifyError— the type vocabulary for a signed frame.wifi-densepose-bfldprovidesCapabilityAttestationandPrivacyAttestationProof(BFLD attestation, ADR-141) — the device-side attestation surface.- ADR-295 defines the source-provenance state machine and freshness
(
SpatialStateFreshness); a monotonic sequence and freshness window slot into that machine rather than duplicating it.
The gap is not new primitives but an end-to-end chain of custody: a frame
must be traceable as device → signed measurement → sequence → timestamp → calibration → inference → signed event, with every link verified at the
ingest boundary per CLAUDE.md ("validate untrusted input at every network,
hardware, and FFI boundary; default to least authority").
Options considered
- Stop at ADR-296 (bind + IP allowlist). Rejected: ADR-296 itself names this insufficient on a trusted LAN; any on-subnet host can still spoof a device.
- TLS/DTLS transport authentication only. Rejected: authenticates the channel, not the measurement. It does not survive store-and-forward, does not bind a sequence number into the signed object, and gives the downstream evidence/witness layers nothing to re-verify offline.
- Per-device signing keys with a signed measurement envelope, monotonic sequence, and freshness window, reusing the RuField/BFLD types. Chosen.
Decision
Introduce an authenticated frame envelope carried through the sensing server, built from existing RuField/BFLD types.
1. Per-device provisioned identity
- Each radio (ESP32-S3/C6 node or adapter) is provisioned with a keypair; the
device holds the private key, the server holds the enrolled public key bound
to a
DeviceId. Provisioning is an explicit, authorized enrollment step — a device is untrusted until an operator enrolls its public key. Private keys are never logged or committed (CLAUDE.md credential rule); the ESP32 side followsfirmware/esp32-csi-nodekey-handling notes. - The enrollment record binds
DeviceId → public key → capabilities(viaCapabilityAttestation, ADR-141), so a device can only assert measurements for phenomena it is attested to sense. This is what ADR-318 (capability certificate) later consumes.
2. Signed measurement envelope
- A frame on the wire becomes a
SignatureBlockover the canonical serialization of{DeviceId, sequence, timestamp, measurement-hash}. The measurement itself (CSI/CIR payload) is covered by the hash so tampering is detectable without embedding the whole payload twice. - Verification uses
Signature/SignatureVerifyErrorfromwifi-densepose-rufield. A frame that fails signature verification is dropped and counted, exactly as ADR-296 drops disallowed sources — anErrat the boundary, never a warning that proceeds.
3. Monotonic sequence + freshness (replay defense)
- Each device maintains a strictly monotonic per-device sequence number. The
server tracks the last accepted sequence per
DeviceId; a non-increasing sequence is rejected as a replay. - A freshness window bounds
timestampagainst the server clock skew budget; stale frames are rejected. This reuses ADR-295'sSpatialStateFreshnessrather than inventing a parallel notion of staleness, and composes with ADR-297's stale-node handling.
4. Chain of custody into the event
- On successful verification the frame's
FrameProvenancerecords the verifiedDeviceId, sequence, and timestamp. Calibration (ADR-301) and inference annotate their transforms, and the emitted spatial event (ADR-306 ontology) carries a signed provenance lineage.ProvenanceClassstill enforces the synthetic/measured invariant from ADR-282/ADR-279 (invariant 6): a measured chain of custody can never be aliased to synthetic and vice-versa. - This end-to-end signed lineage is the substrate the ADR-319 witness chain serializes and the ADR-318 capability certificate points at as evidence.
Compatibility
- The envelope is opt-in per deployment and negotiated at enrollment. An un-enrolled single-node desktop deployment keeps working unauthenticated behind ADR-296's loopback default; a routable, multi-node, or fleet deployment (ADR-316) requires enrolled identities. The startup security log (ADR-296) is extended to state whether frame authentication is active.
Consequences
- LAN spoofing and replay — the residual risks ADR-296 named plainly — are closed for enrolled deployments. The measurement, not merely the channel, is authenticated, so the guarantee survives store-and-forward into the witness chain.
- Enrollment/key-management is now an operational responsibility (provisioning, rotation, revocation). This is documented as a deployment step; key rotation and revocation lists are specified here but their fleet distribution is owned by ADR-316.
- Signature verification adds per-frame CPU cost at ingest; bounded and measured in validation below. It is a deliberate cost for a verifiable chain of custody.
- A schema addition to the frame contract; un-enrolled deployments are unaffected, and the migration accessor mirrors ADR-297's approach.
- No spoof-resistance claim is MEASURED until validated on real silicon (CLAUDE.md hardware rule): a passing unit/integration suite demonstrates the logic, not the fielded device path.
Validation
- Unit tests (
cargo test -p wifi-densepose-sensing-server,-p wifi-densepose-rufield): valid envelope accepted; bad signature rejected and counted; non-monotonic sequence rejected as replay; out-of- window timestamp rejected; un-enrolledDeviceIdrejected; measured/synthetic provenance aliasing rejected (ADR-279 invariant 6). - Integration test: a captured/synthesized multi-frame stream produces a
verifiable
device → … → signed eventlineage that ADR-319 can serialize and re-verify offline. - Benchmark (
cargo bench): per-frame verification cost, to bound ingest overhead. - Real-silicon evidence required before any deployment-grade authentication claim: a captured boot/runtime log from an enrolled ESP32 node signing frames end-to-end. A successful build or simulator run is not hardware evidence.