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 - [ ] 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 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 - [ ] 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 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. 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 - 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 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 - 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). self-contained (reinforces D.3 point 2, was implicit, now explicit).
- **The concrete target shape for message-bus migration** (mined 2026-08-27 from - **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"] M6["✅ Milestone 6 — capsule PKI<br/>DONE 2026-08-26"]
PH8["✅ Phase 8 — Zuse identity<br/>+ block-fence, 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)"] 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"] 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)"] BMAPWRITE["❌ Write block-map to drive (M3)"]
@@ -1422,7 +1430,7 @@ graph TD
DETACH["❌ Detach behavior (M5)"] DETACH["❌ Detach behavior (M5)"]
EXPIRE["✅ EXPIRE reframed: session end<br/>= VM detach via COOL (§B + D.2)"] 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)"] MINT["❌ Ongoing MINT word (Phase 8 + D.3)"]
PENTAGON["📍 Pentagon: Hera/Hermes/Artemis/<br/>User-VM/Console, K5 (D.2b)"] PENTAGON["📍 Pentagon: Hera/Hermes/Artemis/<br/>User-VM/Console, K5 (D.2b)"]
MSGSHAPE["✅ Hermes message shape known<br/>(MSG-CELLS, MSG-ALLOC/DELIVER)"] 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 open fill:#666,stroke:#333,color:#fff
classDef partial fill:#883,stroke:#333,color:#fff classDef partial fill:#883,stroke:#333,color:#fff
class M6,PH8,EXPIRE,MSGSHAPE,HOTPLUG done class M6,PH8,EXPIRE,MSGSHAPE,HOTPLUG done
class W10,STALL,FIRSTTOUCH,BMAPWRITE,BMAPREAD,UNCLEAN,WIREBIND,BINDSTEP,DETACH,MINT,BMAPFMT blocked class W10,STALL,FIRSTTOUCH,BMAPWRITE,BMAPREAD,UNCLEAN,WIREBIND,BINDSTEP,DETACH,MINT,BMAPFMT,CERTVERIFY,RUNCAP blocked
class CERTVERIFY unblocked class ACLKEY,MSGMIGRATE,SSDSCOPE,ROUNDTRIP,POLYBLOCK open
class ACLKEY,RUNCAP,MSGMIGRATE,SSDSCOPE,ROUNDTRIP,POLYBLOCK open
class MIGSM partial 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 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 `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. 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 **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 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 and have re-read on next attach; the interaction with `CERTVERIFY` (does verification gate
reading this content, or only gate the resulting birth). 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 ### 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 Surfaced while scoping `ACLKEY`, stated directly: *"the whole object is to deliver a