Punch list item 1: scratch-device MINT-SCRATCH, verified live on all 3 arches
Implements FABRIC-3.md §XXXII.2's scratch-thumbdrive mint mechanism: capsule_mint_identity_scratch() (capsule_mint.c/.h) builds a throwaway RAM-backed blkio_dev via blkio_ram.c's backend and runs capsule_mint_identity() against it completely unmodified -- same live Zuse-signing operation, same rng_get_bytes() draw for drive_uuid a real thumbdrive gets. Reads back only drive_uuid + the cert devblock; the seed devblock is written into the scratch buffer internally but never read out (no seed is ever baked into a capsule, per the ratified no-seed decision). New FORTH word MINT-SCRATCH (mama_forth_words.c), same stack signature as MINT, mints into the scratch device instead of any attached drive and never touches sk_repl_get_attached_blk_dev() or console-pairing state. Prints the drive_uuid as hex so a live boot log itself proves each call drew fresh entropy. Build correction found along the way: blkio_ram.c was excluded from the kernel build (Makefile.starkernel VM_EXCLUDE) alongside blkio_factory.c/blkio_file.c. blkio_factory_open() unconditionally references blkio_file.c's real fopen()/fread() file I/O, which has no freestanding-kernel equivalent, so the factory function couldn't be used as-is. blkio_ram.c itself is pure memcpy over a caller buffer -- pulled it alone into the kernel build and wired it directly in capsule_mint.c, the same way blkio_factory.c's own extern declarations do internally. Verified live on amd64: two MINT-SCRATCH calls produced two genuinely different drive_uuids (b533246d.../ae11b2b2...), confirming fresh entropy per call rather than stale reuse; VM stayed healthy afterward (5 6 + . -> 11). Clean 3-arch qemu boot (amd64/aarch64/riscv64), logs and DoE CSVs committed per standing convention. Remaining punch-list items (hand-transcription into a .4th block, the unattended-birth call site, the ACL cap bit) not started. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BWpNjdwPtFLuVLaAq44L9K
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
60bcdc09a7
commit
63864c4b01
+1
-1
@@ -530,7 +530,7 @@ VM_ALL_SRCS := \
|
|||||||
VM_EXCLUDE := \
|
VM_EXCLUDE := \
|
||||||
src/main.c src/cli.c src/repl.c \
|
src/main.c src/cli.c src/repl.c \
|
||||||
src/platform/% \
|
src/platform/% \
|
||||||
src/blkio_factory.c src/blkio_file.c src/blkio_ram.c \
|
src/blkio_factory.c src/blkio_file.c \
|
||||||
src/log.c src/doe_metrics.c \
|
src/log.c src/doe_metrics.c \
|
||||||
src/vm.c src/vm_core.c src/vm_bootstrap.c src/vm_runtime.c src/vm_time.c \
|
src/vm.c src/vm_core.c src/vm_bootstrap.c src/vm_runtime.c src/vm_time.c \
|
||||||
src/word_source/q48_16_words.c \
|
src/word_source/q48_16_words.c \
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Capsule Block Manifest — Auto-generated
|
# Capsule Block Manifest — Auto-generated
|
||||||
<!-- Generated by mkcapsule --manifest 2026-09-16T00:15:36Z -->
|
<!-- Generated by mkcapsule --manifest 2026-09-16T08:40:33Z -->
|
||||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||||
<!-- Hand-written justifications and immutability notes live -->
|
<!-- Hand-written justifications and immutability notes live -->
|
||||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||||
|
|||||||
Binary file not shown.
@@ -133,6 +133,37 @@ MintResult capsule_mint_identity(struct blkio_dev *dev, VM *issuer_vm,
|
|||||||
MintPersonality personality,
|
MintPersonality personality,
|
||||||
int drive_known_blank);
|
int drive_known_blank);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capsule_mint_identity_scratch - Mint into a throwaway RAM-backed device
|
||||||
|
* instead of a real thumbdrive (FABRIC-3.md §XXXII.2, unattended-identity
|
||||||
|
* punch list item 1). Runs capsule_mint_identity() completely unmodified
|
||||||
|
* against a scratch blkio_dev built from the shared RAM backend
|
||||||
|
* (blkio_ram.c) -- same live Zuse-signing operation, same rng_get_bytes()
|
||||||
|
* draw for drive_uuid a real thumbdrive gets. "Scratch" describes only
|
||||||
|
* where the bytes are written; nothing about verification changes, and
|
||||||
|
* vm_identity_from_cert() needs no changes to consume the result later.
|
||||||
|
*
|
||||||
|
* The seed devblock capsule_mint_identity() writes internally is never
|
||||||
|
* read back here -- out_uuid/out_cert are the only two fields an
|
||||||
|
* unattended identity needs (FABRIC-3.md §XXXII.2 decision, 2026-09-16:
|
||||||
|
* no seed is ever baked into a capsule).
|
||||||
|
*
|
||||||
|
* @param issuer_vm Same meaning as capsule_mint_identity()'s own --
|
||||||
|
* Zuse's cert lives here (in practice Hera).
|
||||||
|
* @param out_uuid 16 bytes, populated with the minted drive_uuid.
|
||||||
|
* @param out_cert 4096 bytes, populated with the raw (zero-padded)
|
||||||
|
* cert devblock -- matches capsule_wirebind_verify_
|
||||||
|
* cert()'s own read shape, so the same DER-length
|
||||||
|
* handling (parsed from the ASN.1 header, trailing
|
||||||
|
* padding ignored) applies at birth time later.
|
||||||
|
* @return Same MintResult capsule_mint_identity() itself returns.
|
||||||
|
*/
|
||||||
|
MintResult capsule_mint_identity_scratch(VM *issuer_vm,
|
||||||
|
const char *full_name, const char *username,
|
||||||
|
const char *email, const char *phone,
|
||||||
|
MintPersonality personality,
|
||||||
|
uint8_t out_uuid[16], uint8_t out_cert[4096]);
|
||||||
|
|
||||||
#endif /* __STARKERNEL__ */
|
#endif /* __STARKERNEL__ */
|
||||||
|
|
||||||
#endif /* STARKERNEL_CAPSULE_MINT_H */
|
#endif /* STARKERNEL_CAPSULE_MINT_H */
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,21 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* blkio_ram.c's own backend entry points -- no header exists for these
|
||||||
|
* (blkio_factory.c, the vendored hosted-only caller, declares them the
|
||||||
|
* same way: plain externs, not a dedicated blkio_ram.h). blkio_factory.c
|
||||||
|
* itself stays out of the kernel build (it unconditionally references
|
||||||
|
* blkio_file.c's real fopen()/fread() file I/O, which has no freestanding
|
||||||
|
* kernel equivalent); blkio_ram.c alone -- pure memcpy over a caller
|
||||||
|
* buffer -- was pulled into Makefile.starkernel's kernel build for this
|
||||||
|
* function specifically (FABRIC-3.md §XXXII.2, 2026-09-16). */
|
||||||
|
extern size_t blkio_ram_state_size(void);
|
||||||
|
extern const blkio_vtable_t *blkio_ram_vtable(void);
|
||||||
|
extern int blkio_ram_init_state(void *state_mem, size_t state_len,
|
||||||
|
uint8_t *base, uint32_t total_blocks,
|
||||||
|
uint32_t fbs, uint8_t read_only,
|
||||||
|
void **out_opaque);
|
||||||
|
|
||||||
/* Fixed layout, devblock offsets from the drive's own start -- see
|
/* Fixed layout, devblock offsets from the drive's own start -- see
|
||||||
* capsule_mint.h's own doc comment. */
|
* capsule_mint.h's own doc comment. */
|
||||||
#define MINT_CERT_DEVBLOCK 2u
|
#define MINT_CERT_DEVBLOCK 2u
|
||||||
@@ -298,3 +313,73 @@ MintResult capsule_mint_identity(struct blkio_dev *dev, VM *issuer_vm,
|
|||||||
|
|
||||||
return MINT_OK;
|
return MINT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MintResult capsule_mint_identity_scratch(VM *issuer_vm,
|
||||||
|
const char *full_name, const char *username,
|
||||||
|
const char *email, const char *phone,
|
||||||
|
MintPersonality personality,
|
||||||
|
uint8_t out_uuid[16], uint8_t out_cert[4096]) {
|
||||||
|
if (!out_uuid || !out_cert) return MINT_ERR_WRITE_FAIL;
|
||||||
|
|
||||||
|
/* MINT_METADATA_DEVBLOCKS 4KiB devblocks, expressed in blkio's own
|
||||||
|
* 1KiB unit -- same conversion write_devblock()/read_devblock() above
|
||||||
|
* already use. Static, not stack: 20480 bytes is fine on either, but
|
||||||
|
* this buffer's whole reason to exist is to be reused call after call
|
||||||
|
* without re-touching any real device, so giving it a fixed home
|
||||||
|
* matches g_wirebind_attached_username's own precedent for one-shot,
|
||||||
|
* non-reentrant kernel-side scratch state. */
|
||||||
|
static uint8_t scratch_data[MINT_METADATA_DEVBLOCKS * 4u * BLKIO_FORTH_BLOCK_SIZE];
|
||||||
|
static uint8_t scratch_state[64]; /* comfortably larger than blkio_ram's
|
||||||
|
* own state struct; blkio_factory_
|
||||||
|
* open() checks the real size itself
|
||||||
|
* and fails BLKIO_ENOSPACE if this
|
||||||
|
* ever stops being enough. */
|
||||||
|
memset(scratch_data, 0, sizeof(scratch_data));
|
||||||
|
|
||||||
|
if (sizeof(scratch_state) < blkio_ram_state_size()) return MINT_ERR_WRITE_FAIL;
|
||||||
|
|
||||||
|
void *opaque = NULL;
|
||||||
|
if (blkio_ram_init_state(scratch_state, sizeof(scratch_state),
|
||||||
|
scratch_data, MINT_METADATA_DEVBLOCKS * 4u,
|
||||||
|
0, 0, &opaque) != BLKIO_OK) {
|
||||||
|
return MINT_ERR_WRITE_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
blkio_dev_t dev;
|
||||||
|
const blkio_params_t p = {
|
||||||
|
.forth_block_size = 0,
|
||||||
|
.total_blocks = MINT_METADATA_DEVBLOCKS * 4u,
|
||||||
|
.opaque = opaque
|
||||||
|
};
|
||||||
|
if (blkio_open(&dev, blkio_ram_vtable(), &p) != BLKIO_OK) {
|
||||||
|
return MINT_ERR_WRITE_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fresh, zeroed buffer every call -- never a stale sig to misread as
|
||||||
|
* "already minted," so the real homeblocks_sig_check() pass inside
|
||||||
|
* capsule_mint_identity() is redundant here, not skipped for speed. */
|
||||||
|
MintResult r = capsule_mint_identity((struct blkio_dev *)&dev, issuer_vm,
|
||||||
|
full_name, username, email, phone,
|
||||||
|
(uint8_t *)0, (uint8_t *)0,
|
||||||
|
personality, 1 /* drive_known_blank */);
|
||||||
|
if (r != MINT_OK) {
|
||||||
|
blkio_close(&dev);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t sig_block[4096];
|
||||||
|
if (read_devblock((struct blkio_dev *)&dev, HOMEBLOCKS_SIG_START_FBLOCK / 4u,
|
||||||
|
sig_block) != 0) {
|
||||||
|
blkio_close(&dev);
|
||||||
|
return MINT_ERR_VERIFY_FAILED;
|
||||||
|
}
|
||||||
|
memcpy(out_uuid, sig_block + offsetof(homeblocks_sig_t, drive_uuid), 16);
|
||||||
|
|
||||||
|
if (read_devblock((struct blkio_dev *)&dev, MINT_CERT_DEVBLOCK, out_cert) != 0) {
|
||||||
|
blkio_close(&dev);
|
||||||
|
return MINT_ERR_VERIFY_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
blkio_close(&dev);
|
||||||
|
return MINT_OK;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1149,6 +1149,88 @@ static void mama_word_mint(VM *vm)
|
|||||||
vm_push(vm, 0);
|
vm_push(vm, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MINT-SCRATCH ( fname-c fname-u uname-c uname-u email-c email-u
|
||||||
|
* phone-c phone-u restrict? -- ok? )
|
||||||
|
* Same arguments and dictionary meaning as MINT, but mints into a
|
||||||
|
* throwaway RAM-backed scratch device instead of the currently attached
|
||||||
|
* drive -- never touches sk_repl_get_attached_blk_dev() or any real
|
||||||
|
* block device at all (FABRIC-3.md §XXXII.2, unattended-identity punch
|
||||||
|
* list item 1, 2026-09-16). The resulting drive_uuid + cert are kept in
|
||||||
|
* g_mint_scratch_uuid/g_mint_scratch_cert for a follow-up word to read
|
||||||
|
* out for hand-transcription into a capsule -- that packaging step is
|
||||||
|
* its own punch-list item, not built here. The uuid is printed as hex
|
||||||
|
* immediately so a live boot log itself proves each mint drew fresh
|
||||||
|
* entropy rather than reusing stale state.
|
||||||
|
*/
|
||||||
|
static uint8_t g_mint_scratch_uuid[16];
|
||||||
|
static uint8_t g_mint_scratch_cert[4096];
|
||||||
|
|
||||||
|
static void mama_word_mint_scratch(VM *vm)
|
||||||
|
{
|
||||||
|
char phone[USER_IDENTITY_PHONE_MAX];
|
||||||
|
char email[USER_IDENTITY_EMAIL_MAX];
|
||||||
|
char username[USER_IDENTITY_USERNAME_MAX];
|
||||||
|
char full_name[USER_IDENTITY_FULL_NAME_MAX];
|
||||||
|
|
||||||
|
if (vm->dsp < 0) {
|
||||||
|
console_println("MINT-SCRATCH: expects a restrict? flag on top of the stack");
|
||||||
|
vm->error = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cell_t restrict_flag = vm_pop(vm);
|
||||||
|
if (mint_pop_string(vm, phone, sizeof(phone), "phone") != 0) return;
|
||||||
|
if (mint_pop_string(vm, email, sizeof(email), "email") != 0) return;
|
||||||
|
if (mint_pop_string(vm, username, sizeof(username), "username") != 0) return;
|
||||||
|
if (mint_pop_string(vm, full_name, sizeof(full_name), "full_name") != 0) return;
|
||||||
|
|
||||||
|
MintPersonality personality = restrict_flag
|
||||||
|
? MINT_PERSONALITY_STD79_LOCKDOWN
|
||||||
|
: MINT_PERSONALITY_DEFAULT;
|
||||||
|
MintResult r = capsule_mint_identity_scratch(vm, full_name, username, email, phone,
|
||||||
|
personality,
|
||||||
|
g_mint_scratch_uuid, g_mint_scratch_cert);
|
||||||
|
switch (r) {
|
||||||
|
case MINT_OK: {
|
||||||
|
static const char hex[] = "0123456789abcdef";
|
||||||
|
char uuid_hex[33];
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
uuid_hex[i * 2] = hex[(g_mint_scratch_uuid[i] >> 4) & 0xF];
|
||||||
|
uuid_hex[i * 2 + 1] = hex[g_mint_scratch_uuid[i] & 0xF];
|
||||||
|
}
|
||||||
|
uuid_hex[32] = '\0';
|
||||||
|
console_puts("MINT-SCRATCH: identity minted (scratch device, no real drive touched) -- drive_uuid ");
|
||||||
|
console_println(uuid_hex);
|
||||||
|
vm_push(vm, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case MINT_ERR_ALREADY_MINTED:
|
||||||
|
console_println("MINT-SCRATCH: refused -- scratch device already reads as minted");
|
||||||
|
break;
|
||||||
|
case MINT_ERR_NO_ZUSE_CERT:
|
||||||
|
console_println("MINT-SCRATCH: refused -- Zuse has no installed cert to sign with");
|
||||||
|
break;
|
||||||
|
case MINT_ERR_NO_ENTROPY:
|
||||||
|
console_println("MINT-SCRATCH: refused -- no entropy source");
|
||||||
|
break;
|
||||||
|
case MINT_ERR_CERT_BUILD:
|
||||||
|
console_println("MINT-SCRATCH: FAILED -- cert construction error");
|
||||||
|
break;
|
||||||
|
case MINT_ERR_WRITE_FAIL:
|
||||||
|
console_println("MINT-SCRATCH: FAILED -- scratch device write error");
|
||||||
|
break;
|
||||||
|
case MINT_ERR_INVALID_PROFILE:
|
||||||
|
console_println("MINT-SCRATCH: refused -- full_name/username missing or a field too long");
|
||||||
|
break;
|
||||||
|
case MINT_ERR_VERIFY_FAILED:
|
||||||
|
console_println("MINT-SCRATCH: FAILED -- minted but post-write verification failed "
|
||||||
|
"(see log for which check)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vm_push(vm, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief ZUSE-ELIGIBILITY-ADD ( c-addr -- ok? )
|
* @brief ZUSE-ELIGIBILITY-ADD ( c-addr -- ok? )
|
||||||
* Add the 32-byte Ed25519 public key at c-addr to Zuse's elevation
|
* Add the 32-byte Ed25519 public key at c-addr to Zuse's elevation
|
||||||
@@ -1802,6 +1884,7 @@ void register_mama_forth_words(VM *vm)
|
|||||||
register_word(vm, "CAPSULE-BIRTH", mama_word_capsule_birth);
|
register_word(vm, "CAPSULE-BIRTH", mama_word_capsule_birth);
|
||||||
register_word(vm, "CAPSULE-RUN", mama_word_capsule_run);
|
register_word(vm, "CAPSULE-RUN", mama_word_capsule_run);
|
||||||
register_word(vm, "MINT", mama_word_mint);
|
register_word(vm, "MINT", mama_word_mint);
|
||||||
|
register_word(vm, "MINT-SCRATCH", mama_word_mint_scratch);
|
||||||
register_word(vm, "ZUSE-ELIGIBILITY-ADD", mama_word_zuse_eligibility_add);
|
register_word(vm, "ZUSE-ELIGIBILITY-ADD", mama_word_zuse_eligibility_add);
|
||||||
register_word(vm, "ZUSE-ELIGIBLE?", mama_word_zuse_eligible_query);
|
register_word(vm, "ZUSE-ELIGIBLE?", mama_word_zuse_eligible_query);
|
||||||
register_word(vm, "NAME>XT", mama_word_name_to_xt);
|
register_word(vm, "NAME>XT", mama_word_name_to_xt);
|
||||||
@@ -1861,6 +1944,7 @@ void register_mama_forth_words(VM *vm)
|
|||||||
register_word(vm, "CAPSULE-BIRTH", mama_word_capsule_birth);
|
register_word(vm, "CAPSULE-BIRTH", mama_word_capsule_birth);
|
||||||
register_word(vm, "CAPSULE-RUN", mama_word_capsule_run);
|
register_word(vm, "CAPSULE-RUN", mama_word_capsule_run);
|
||||||
register_word(vm, "MINT", mama_word_mint);
|
register_word(vm, "MINT", mama_word_mint);
|
||||||
|
register_word(vm, "MINT-SCRATCH", mama_word_mint_scratch);
|
||||||
register_word(vm, "ZUSE-ELIGIBILITY-ADD", mama_word_zuse_eligibility_add);
|
register_word(vm, "ZUSE-ELIGIBILITY-ADD", mama_word_zuse_eligibility_add);
|
||||||
register_word(vm, "ZUSE-ELIGIBLE?", mama_word_zuse_eligible_query);
|
register_word(vm, "ZUSE-ELIGIBLE?", mama_word_zuse_eligible_query);
|
||||||
register_word(vm, "NAME>XT", mama_word_name_to_xt);
|
register_word(vm, "NAME>XT", mama_word_name_to_xt);
|
||||||
|
|||||||
Reference in New Issue
Block a user