FABRIC-3.md: scope CERTVERIFY, correct D.4's PKI-reuse assumption

Traced x509_ed25519.h and zuse_cert_devblock.h before scoping: a regular user's cert has a fully separate trust root from the capsule-PKI chain (signed by Zuse's own on-device key, not the offline root CA/snakeoil intermediate), so verification is a single ed25519_verify() call, no chain walk. Corrects D.4's earlier "no new crypto work needed" claim -- x509_extract_ed25519_pubkey() deliberately stops at SubjectPublicKeyInfo, so verifying (not just reading) a cert needs new DER-walking code to capture the TBSCertificate byte range and signature. Decisions: X.509/DER format, drive_uuid bound via the cert's serialNumber field (avoids needing extension parsing), revocation deferred, cert lives in homeblocks_sig_t's already-reserved cert_offset/cert_devblocks.
This commit is contained in:
Robert Allan James
2026-08-27 14:13:00 -04:00
parent 8b3e46fa55
commit 691c04289b
+66 -7
View File
@@ -127,7 +127,9 @@ decisions get added here, not to `FABRIC-2.md`. Follow the same discipline `FABR
- [ ] Implement the CA-signed-cert verification path (Milestone 6 dependency — the cert chain
validator doesn't exist yet either). **Now confirmed a hard prerequisite of `WIREBIND` too
(`FABRIC-3.md` §F.5), not just an M3 item in isolation.**
(`FABRIC-3.md` §F.5), not just an M3 item in isolation. SCOPED 2026-08-27 (§F.7)**: format
and trust root decided (Zuse-signed X.509/DER cert, not the offline capsule-PKI chain); the
actual DER signature-extraction code is new work, not yet built.
- [ ] Implement the first-touch allocation function: given a verified identity pubkey and a
requested block count, either read an existing range from the drive's map or claim a new
@@ -1308,7 +1310,13 @@ independently confirmed — see D.4's gaps):
addendum above) — TTL was never a valid mechanism for a VM patron in the first place.
- Regular-user cert chain-of-trust mechanism — signed by Zuse's own key, verified with
already-built, already-proven Ed25519/X.509 primitives (Milestone 6). No new crypto work
needed, only a new verification *call site* using existing functions.
needed, only a new verification *call site* using existing functions. **Correction,
2026-08-27 (`FABRIC-3.md` §F.7): partially wrong.** `x509_extract_ed25519_pubkey()`
deliberately stops at `SubjectPublicKeyInfo` — no signature extraction, no TBS-byte-range
capture, no chain/issuer check of any kind (`x509_ed25519.h`'s own doc comment). Verifying a
*signed* cert (not just reading a pubkey out of one) is new DER-walking work, not a pure
reuse. Trust root is also confirmed separate from the capsule-PKI chain: Zuse's own
on-device key (`zuse_cert_devblock_t`), never the offline root CA / snakeoil intermediate.
- Whether the system needs a central user directory — no, by design; each thumbdrive is
self-contained (reinforces D.3 point 2, was implicit, now explicit).
- **The concrete target shape for message-bus migration** (mined 2026-08-27 from
@@ -1408,7 +1416,7 @@ graph TD
M6["✅ Milestone 6 — capsule PKI<br/>DONE 2026-08-26"]
PH8["✅ Phase 8 — Zuse identity<br/>+ block-fence, DONE 2026-08-26"]
CERTVERIFY["🔓 CA-signed-cert verification path (M3)<br/>UNBLOCKED by M6, not yet built"]
CERTVERIFY["❌ Zuse-signed user-cert verification (M3)<br/>SCOPED 2026-08-27 (§F.7) — X.509/DER, own trust root"]
FIRSTTOUCH["❌ First-touch identity→block-range<br/>allocation (M3)"]
BMAPFMT["❌ On-drive block-map format (M3)<br/>SCOPED 2026-08-27 (§F.4) — repurpose blk_meta_t"]
BMAPWRITE["❌ Write block-map to drive (M3)"]
@@ -1422,7 +1430,7 @@ graph TD
DETACH["❌ Detach behavior (M5)"]
EXPIRE["✅ EXPIRE reframed: session end<br/>= VM detach via COOL (§B + D.2)"]
RUNCAP[" Runtime capsule construction<br/>from thumbdrive content (D.4) — new mechanism"]
RUNCAP[" Runtime capsule construction<br/>from thumbdrive content — SCOPED 2026-08-27 (§F.6)"]
MINT["❌ Ongoing MINT word (Phase 8 + D.3)"]
PENTAGON["📍 Pentagon: Hera/Hermes/Artemis/<br/>User-VM/Console, K5 (D.2b)"]
MSGSHAPE["✅ Hermes message shape known<br/>(MSG-CELLS, MSG-ALLOC/DELIVER)"]
@@ -1469,9 +1477,8 @@ graph TD
classDef open fill:#666,stroke:#333,color:#fff
classDef partial fill:#883,stroke:#333,color:#fff
class M6,PH8,EXPIRE,MSGSHAPE,HOTPLUG done
class W10,STALL,FIRSTTOUCH,BMAPWRITE,BMAPREAD,UNCLEAN,WIREBIND,BINDSTEP,DETACH,MINT,BMAPFMT blocked
class CERTVERIFY unblocked
class ACLKEY,RUNCAP,MSGMIGRATE,SSDSCOPE,ROUNDTRIP,POLYBLOCK open
class W10,STALL,FIRSTTOUCH,BMAPWRITE,BMAPREAD,UNCLEAN,WIREBIND,BINDSTEP,DETACH,MINT,BMAPFMT,CERTVERIFY,RUNCAP blocked
class ACLKEY,MSGMIGRATE,SSDSCOPE,ROUNDTRIP,POLYBLOCK open
class MIGSM partial
```
@@ -1502,6 +1509,11 @@ finished). Dashed arrows = softer "gates/informs" relationships.
to bind to, and without `RUNCAP` there's no per-identity VM content to birth — today's
`capsule_birth_baby()` only runs fixed, build-time-baked capsules by name, so "spin up that
identity's VM" had no real mechanism behind it at all until this pass traced it.
- **`CERTVERIFY` and the capsule-PKI chain are two separate trust roots, not one** (§F.7) —
easy to conflate since both use Ed25519/X.509, but user certs are signed by Zuse's own
on-device key while capsules are signed by the offline root CA's snakeoil intermediate.
Neither chain validates the other; a future audit pass should keep this distinction explicit
rather than let "PKI" get treated as one undifferentiated mechanism.
**Not yet done:** an ordered plan (which node to attack first, given the graph). Per Captain
Bob's own framing, that's the next pass — "start asking and answering questions iteratively
@@ -1747,6 +1759,53 @@ whether the source is plain FORTH text authored once at mint time or something a
and have re-read on next attach; the interaction with `CERTVERIFY` (does verification gate
reading this content, or only gate the resulting birth).
### F.7 — `CERTVERIFY` (Zuse-signed user-cert verification)
Traced against the actual crypto/cert code before assuming D.4's "no new crypto work needed"
framing was still accurate. Two files settle the trust-root question outright:
`x509_ed25519.h`'s own doc comment ("no signature verification, no chain validation, no
extension parsing — this only answers *what public key does this cert claim to hold*") and
`zuse_cert_devblock_h`'s design (Zuse's own on-device Ed25519 keypair, persisted in the system
block-fence, `FABRIC-3.md` §C). **Confirmed: a regular user's cert has a completely separate
trust root from the capsule-PKI chain** — it's signed by Zuse's own locally-resident key, never
the offline root CA / snakeoil intermediate. No chain walk is needed at verify time; it's one
signature check against a pubkey the kernel already holds.
**Decisions made 2026-08-27 (iterative Q&A pass):**
1. **Format: X.509/DER**, not a simple custom struct (the `zuse_cert_devblock_t` precedent
would have been simpler, but explicitly not chosen). The cert's `SubjectPublicKeyInfo`
holds the owner's Ed25519 pubkey (same field `x509_extract_ed25519_pubkey()` already reads).
2. **Drive binding: the cert's `serialNumber` field holds the 16-byte `drive_uuid`** (matching
`homeblocks_sig_t.drive_uuid`) rather than adding a new X.509v3 extension — `serialNumber`
is an early, shallow `SEQUENCE` member (actually simpler to reach than
`SubjectPublicKeyInfo`, which the existing parser already walks past), so this avoids
needing any extension-parsing support at all. Binding to the drive means a valid cert's
bytes alone, copied onto a different physical drive, will not verify there.
3. **Revocation: explicitly deferred.** Matches this project's incremental-scope precedent
elsewhere (capsules have a `REVOKED` flag; user-cert revocation is separate, unbuilt
surface). `CERTVERIFY` v1 only checks magic/structure, the embedded algorithm OID
(Ed25519, rejecting anything else — same check `x509_extract_ed25519_pubkey()` already
does for the pubkey field), the `serialNumber`-vs-`drive_uuid` match, and the signature
itself.
4. **Real added scope, flagged honestly rather than assumed away:** verifying (not just
reading) this cert requires genuinely new DER-walking code beyond
`x509_extract_ed25519_pubkey()` — that function stops at `SubjectPublicKeyInfo` by design.
`CERTVERIFY` additionally needs: the raw `TBSCertificate` byte range (the exact bytes
Zuse's signature covers), the outer `signatureValue` `BIT STRING` contents, and the
`serialNumber` `INTEGER` bytes. Verification itself is then one call:
`ed25519_verify(zuse_pubkey, tbs_bytes, tbs_len, signature)`, where `zuse_pubkey` comes
from this system's own `zuse_cert_devblock_t`, not from anything read off the user's drive.
5. **Location on drive:** `homeblocks_sig_t.cert_offset`/`cert_devblocks` — already reserved
for exactly this ("the CA-signed cert blob") since that header was first designed. No
header changes needed here, unlike `RUNCAP`'s repurposing of the block-map fields.
**Not yet scoped (deferred within this node):** the actual new DER TBS/signature-extraction
function's design (this pass decided *what* it must extract, not its implementation); whether
`x509_ed25519.c` grows this capability in place or a sibling file holds it; how `MINT` (which
shares this exact cert format on the signing side) constructs the DER bytes in the first place
— DER *encoding* has never been needed in this kernel before, only decoding.
### D.5 — Scope expansion (2026-08-27): identity is common to every VM, not just users
Surfaced while scoping `ACLKEY`, stated directly: *"the whole object is to deliver a