Files
parking_solution/wiki/concepts/challenge-response-auth.md
julian bfe64032d8 Initial scaffold: Turborepo monorepo + design wiki
Turborepo (pnpm workspaces) with all dependencies pinned to latest
mutually-compatible versions: turbo 2.9, TypeScript 6, Fastify 5,
React 19, Vite 8, better-sqlite3 12 + Drizzle ORM 0.45.

Layout:
- apps/server   Fastify backend (local JWT auth + role guard, /health)
- apps/web      React 19 + Vite 8 operator SPA
- packages/db   Drizzle schema on SQLite/WAL; append-only events + users
- packages/devices  reader/printer/relay adapter interfaces (intent-only relay)
- packages/shared   shared domain types

Architecture constraints from the design wiki are encoded in the scaffold:
append-only hash-chained + signed event log, device-agnostic adapters,
"a barrier is not a door" (relay expresses intent only), fully-local
offline-first auth.

wiki/ is an LLM-maintained Obsidian knowledge base (28 pages) ingested
from the architecture & design notes, with its own maintenance schema.

Verified: pnpm install, full turbo build (5/5), server boots and serves
/health, drizzle-kit generates the initial migration.
2026-06-14 00:34:11 +02:00

30 lines
1.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
type: concept
tags: [parking, security, crypto, access-control]
sources: [parking-system-architecture]
updated: 2026-06-14
---
# Challenge–Response Auth (asymmetric signatures)
The authentication scheme for the [[esp32-custom-controller]]. Closes the actual hole in the
[[uhppote-udp-protocol]]: **forged or replayed commands**. The requirement is **authenticity +
freshness (anti-replay)**; encryption is optional. (See [[parking-system-architecture]] §7.)
```
Host (private key) ESP32 (host's PUBLIC key only)
│── "open lane 2" ──────────────────▶│ generates fresh random nonce
│◀──────────── nonce ─────────────────│
│ sign(nonce ‖ command ‖ ts) ────────▶│ verify vs stored public key
│ │ check nonce fresh + unused → pulse relay
```
## The elegant property
The controller stores **only a public key**. Physically compromising the ESP32 (popping the
cabinet, dumping flash via the [[atecc608]]) yields **nothing usable for forging commands**. The
fresh per-command **nonce** defeats replay without counter-persistence headaches.
A shared-secret / encrypted channel would **not** have this property — the secret would sit on
both ends. That's why authentication (not encryption) is the right build here.