From 691c04289b3f96644800ea4820cc1ea8c2331395 Mon Sep 17 00:00:00 2001 From: Robert Allan James Date: Thu, 27 Aug 2026 14:13:00 -0400 Subject: [PATCH] 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. --- FABRIC-3.md | 73 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 7 deletions(-) diff --git a/FABRIC-3.md b/FABRIC-3.md index 1d7f7bf..b4f7c7b 100644 --- a/FABRIC-3.md +++ b/FABRIC-3.md @@ -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
DONE 2026-08-26"] PH8["✅ Phase 8 — Zuse identity
+ block-fence, DONE 2026-08-26"] - CERTVERIFY["🔓 CA-signed-cert verification path (M3)
UNBLOCKED by M6, not yet built"] + CERTVERIFY["❌ Zuse-signed user-cert verification (M3)
SCOPED 2026-08-27 (§F.7) — X.509/DER, own trust root"] FIRSTTOUCH["❌ First-touch identity→block-range
allocation (M3)"] BMAPFMT["❌ On-drive block-map format (M3)
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
= VM detach via COOL (§B + D.2)"] - RUNCAP["❓ Runtime capsule construction
from thumbdrive content (D.4) — new mechanism"] + RUNCAP["❌ Runtime capsule construction
from thumbdrive content — SCOPED 2026-08-27 (§F.6)"] MINT["❌ Ongoing MINT word (Phase 8 + D.3)"] PENTAGON["📍 Pentagon: Hera/Hermes/Artemis/
User-VM/Console, K5 (D.2b)"] MSGSHAPE["✅ Hermes message shape known
(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