docs(wiki): ATECC608 is upcoming — retag ledger signing to the on-host reality
No secure element is on-site: event signing runs on the software HMAC (EVENT_SIGNING_KEY, an env var on the host disk), so the ledger is tamper-EVIDENT but forgeable by anyone who owns the host. Several pages overstated it as present-tense "ATECC608-signed / unforgeable"; correct them. - NEW concepts/hardware-signer-options.md: four options for a non-extractable signing key (USB HSM / YubiKey / reuse the TPM / plain-dongle trap) + the recommendation (TPM interim → USB-HSM target; ATECC608 stays for the embedded ESP32, wrong part for a PC host). - entities/atecc608.md: UPCOMING-not-present status banner + PC-vs-embedded. - disk-os-hardening.md: fix the live-USB row (BIOS boot-order password is load-bearing, not Secure Boot — a signed live USB runs); add a physical-tamper chain (Dell 7070 CMOS-reset → live-USB → PCR-7 same-signer unseal) + accepted risks (that unseal, unsigned-initramfs evil-maid, operator-USB read TODO). - open-questions #6 reframed; standing-decisions / overview / threat-model / index de-overstated; log query entry. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
---
|
||||
type: concept
|
||||
tags: [parking, security, integrity, crypto, hardware, threat-model]
|
||||
sources: []
|
||||
updated: 2026-07-02
|
||||
---
|
||||
|
||||
# Hardware signer options (non-extractable ledger signing key)
|
||||
|
||||
Where the **[[append-only-event-chain|signed ledger]]'s** private signing key should live so that an
|
||||
adversary who **owns the host** — including one who decrypts the disk via the [[disk-os-hardening]]
|
||||
physical-tamper chain — still cannot **forge** the ledger. This is the still-open
|
||||
[[open-questions|open-question #6]], reframed once it became clear (2026-07-02) that **no secure
|
||||
element is on-site** and the [[atecc608]] isn't even the right part for a PC.
|
||||
|
||||
## The problem in one line
|
||||
|
||||
Today signing uses the software `SoftwareSigner` — **HMAC-SHA256, key in `EVENT_SIGNING_KEY`, an env
|
||||
var on the host disk**. HMAC is symmetric: the same secret signs *and* verifies, and it sits on the
|
||||
box. So the chain is tamper-**evident** (a blind editor without the key breaks it, and `verifyChain()`
|
||||
pinpoints where) but **not unforgeable** — anyone who reads the key re-signs a doctored chain and it
|
||||
verifies clean. The fix is a signer whose **private key is non-extractable**: the host can ask it to
|
||||
sign, but can never read the key. That is a property of an HSM / smartcard / TPM — **not** of anything
|
||||
that merely *stores* a key.
|
||||
|
||||
## The four options
|
||||
|
||||
### 1. USB HSM — Nitrokey HSM 2 / SmartCard-HSM *(recommended target)*
|
||||
A ~€50 USB device with a non-extractable EC key (secp256r1 — same curve family as the ATECC608). The
|
||||
host signs each event over **PKCS#11**; the key never leaves the token. It's essentially "the
|
||||
ATECC608, but on USB instead of soldered", so it drops into the existing `signer.ts` seam (the
|
||||
`keyId` field + the `TODO(atecc608)` public-key-verifier hook).
|
||||
- **License fit:** OpenSC (the PKCS#11 stack) is LGPL/permissive — no vendor lock-in, matches the
|
||||
all-MIT/Apache/BSD [[technology-stack|stack constraint]].
|
||||
- **Downside:** it's *removable* — an operator can pocket it. But that fails **closed** (no token →
|
||||
can't sign → visibly noticed), and it can be epoxied / locked inside the case.
|
||||
|
||||
### 2. YubiKey (PIV or OpenPGP applet)
|
||||
Also a non-extractable EC/RSA key over PKCS#11; very robust, widely deployed; works the same way as
|
||||
the Nitrokey for this purpose. Slightly more oriented to human 2FA than to an always-present signing
|
||||
oracle, and the vendor stack is less fully-open than OpenSC. **~$50–70.** Fine as a substitute for
|
||||
option 1.
|
||||
|
||||
### 3. Reuse the on-board TPM 2.0 *(recommended interim — free)*
|
||||
The booth PC already has a TPM (it's what seals LUKS — [[tpm]]). A TPM can also hold a non-extractable
|
||||
signing key and sign over it. **Zero extra hardware, closes the "key in a plaintext env file" hole
|
||||
immediately.**
|
||||
- **The nuance:** don't reuse the *LUKS* sealing arrangement. That key is PCR-7-sealed, and the
|
||||
battery-pull → live-USB → PCR-7 chain ([[disk-os-hardening]]) defeats PCR-7-only policies. Bind the
|
||||
**signing** key to the TPM **without a PCR policy** (or with a PIN) so it's about non-extractability,
|
||||
not boot-state — then an attacker who decrypts the disk still can't pull it.
|
||||
- **Weaker than a dedicated HSM** against a sophisticated bus-sniffing attacker, but far stronger than
|
||||
today's on-disk HMAC.
|
||||
|
||||
### 4. Plain USB "sentinel" / dongle *(the trap — avoid)*
|
||||
A generic USB flash drive holding a key file, or a license-dongle that only gates "is this USB
|
||||
present". **Useless here:** if the key is *readable* off the stick, the host-owner copies it, exactly
|
||||
like the env var. Presence-gating is not integrity. Only a device that **signs internally** delivers
|
||||
non-extractability. Do not go this route.
|
||||
|
||||
## Recommendation
|
||||
|
||||
1. **Now (free):** move signing to a **TPM-held key** (option 3, no PCR policy) — kills the
|
||||
plaintext-key-on-disk exposure using hardware already present.
|
||||
2. **Target (purchasable):** a **USB HSM (Nitrokey HSM 2)** as the concrete stand-in for the still-
|
||||
planned [[atecc608]] — same non-extractable-EC model, fits `signer.ts`, open tooling; physically
|
||||
lock it in the case.
|
||||
3. **[[atecc608]]** stays reserved for the **deferred** [[esp32-custom-controller]] (embedded), not
|
||||
the PC host.
|
||||
|
||||
Whichever is chosen, the code seam already exists: each event stores its `keyId`, so a swap is a new
|
||||
`Signer` impl and **old events stay verifiable** under their original key — no migration of history.
|
||||
|
||||
## The mental model to keep
|
||||
|
||||
Against the physical adversary who opens the case, **the only real protection for the financial
|
||||
record is a signing key even root can't read.** That is an HSM/smartcard/TPM property, never a
|
||||
USB-storage property — and it's precisely what's missing today. Note the layering: [[disk-os-hardening]]
|
||||
raises the cost of *reaching* the disk; a hardware signer makes the ledger unforgeable *even after*
|
||||
the disk is reached; and [[reconciliation]] against records the box doesn't hold is the backstop that
|
||||
survives a fully-owned host. They are complements, not substitutes.
|
||||
|
||||
## Relates
|
||||
- [[append-only-event-chain]] — the ledger this key signs; why software signing isn't enough.
|
||||
- [[atecc608]] — the originally-specified secure element (upcoming; embedded, not PC).
|
||||
- [[tpm]] — the on-board part; option 3, and the LUKS-sealing analysis.
|
||||
- [[disk-os-hardening]] — the physical-tamper chain that makes a non-extractable key necessary.
|
||||
- [[open-questions]] #6 (secure-element integration), #7 (JWT symmetric→asymmetric — same key-custody
|
||||
argument for auth tokens).
|
||||
- [[threat-model]] / [[reconciliation]] — the adversary and the backstop control.
|
||||
@@ -26,7 +26,10 @@ authorised access *through the app*. Encryption does nothing against the classic
|
||||
The controls that actually address insider/operator fraud are different in kind:
|
||||
|
||||
- **[[append-only-event-chain]]** — events appended, never edited/deleted; a "void" is itself a
|
||||
recorded event, hash-chained, and **[[atecc608]]-signed** (unforgeable).
|
||||
recorded event, hash-chained, and signed. ⚠ Signing is **software today** (key on the host disk) →
|
||||
tamper-*evident* but forgeable by a host owner; a non-extractable **hardware signer**
|
||||
([[hardware-signer-options]]; [[atecc608]] upcoming) is what makes it truly *unforgeable*. Which is
|
||||
why the load-bearing insider control is reconciliation, next.
|
||||
- **[[reconciliation]]** against an authority the operator can't alter — *this is what remote
|
||||
sync really is*: a fraud-control mechanism, not just a backup.
|
||||
- **[[disk-os-hardening]]** still worthwhile (defeats boot-from-USB) but **not the main event**;
|
||||
|
||||
Reference in New Issue
Block a user