Milestone 6: BLOCK_MAP.md signature-status column
--manifest mode's file scan is a completely separate code path from build mode (only ever walks .4th files, never the embedded PKI cert or font capsule) -- extended it to accept the same optional --sign-key <path> prefix build mode already has, factoring the key-loading code into a shared load_sign_key(), so the manifest can report real per-capsule signing status without touching or requiring a rebuild of capsule_generated.c. New "Signed" column on the capsule summary table: yes/no when --sign-key was given, n/a (with an explanatory footnote) when it wasn't -- never a bare blank that could be misread as "unsigned". Makefile.starkernel's manifest-generation call site now passes the same SIGN_KEY_ARGS the real build uses, so capsules/BLOCK_MAP.md reflects this machine's actual signed state by default. Verified: clean compile, BLOCK_MAP.md correctly shows "yes" for all 31 tracked capsules on a real signed build; a quick amd64 boot (no kernel code touched, host tooling only) confirmed no regression. This closes every open Milestone 6 item except magic-number content-type detection (shared with Milestone 4, not started) and the hard-refuse flip (deliberately deferred). Documented in FABRIC-3.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U14ET9CWAtbQMbYqomKgXd
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
2fc55f47e1
commit
c640f99211
+76
-39
@@ -169,6 +169,7 @@ typedef struct {
|
||||
uint64_t hash;
|
||||
int blocks[MAX_BLOCKS_PER_CAPSULE];
|
||||
int block_count;
|
||||
int has_sig; /* 1 if signed this run (--manifest --sign-key <path>) */
|
||||
} ManifestEntry;
|
||||
|
||||
static ManifestEntry manifest_entries[MAX_CAPSULES];
|
||||
@@ -607,6 +608,12 @@ static int manifest_file(const char *fpath, const struct stat *sb,
|
||||
e->block_count = collect_block_numbers(data, (size_t)sz,
|
||||
e->blocks, MAX_BLOCKS_PER_CAPSULE);
|
||||
qsort(e->blocks, (size_t)e->block_count, sizeof(int), cmp_int);
|
||||
e->has_sig = 0;
|
||||
if (have_sign_seed) {
|
||||
uint8_t sig[64];
|
||||
sign_capsule_bytes(data, (size_t)sz, sig);
|
||||
e->has_sig = 1;
|
||||
}
|
||||
|
||||
free(data);
|
||||
return 0;
|
||||
@@ -654,8 +661,8 @@ static void generate_manifest(FILE *out) {
|
||||
|
||||
/* Capsule summary */
|
||||
fprintf(out, "## Capsule Summary\n\n");
|
||||
fprintf(out, "| Capsule | Blocks claimed | xxHash64 |\n");
|
||||
fprintf(out, "|---------|----------------|----------|\n");
|
||||
fprintf(out, "| Capsule | Blocks claimed | xxHash64 | Signed |\n");
|
||||
fprintf(out, "|---------|----------------|----------|--------|\n");
|
||||
for (int i = 0; i < manifest_count; i++) {
|
||||
ManifestEntry *e = &manifest_entries[i];
|
||||
fprintf(out, "| `%s` | ", e->name);
|
||||
@@ -667,9 +674,16 @@ static void generate_manifest(FILE *out) {
|
||||
fprintf(out, "%d", e->blocks[j]);
|
||||
}
|
||||
}
|
||||
fprintf(out, " | `0x%016" PRIx64 "` |\n", e->hash);
|
||||
fprintf(out, " | `0x%016" PRIx64 "` | %s |\n", e->hash,
|
||||
have_sign_seed ? (e->has_sig ? "yes" : "no") : "n/a");
|
||||
}
|
||||
fprintf(out, "\n");
|
||||
if (!have_sign_seed) {
|
||||
fprintf(out,
|
||||
"*Signed column is `n/a`: this manifest run had no `--sign-key`. "
|
||||
"Re-run with `--sign-key <path>` to check signing status "
|
||||
"(does not modify or require rebuilding capsule_generated.c).*\n\n");
|
||||
}
|
||||
|
||||
/* Block map sorted by LBN */
|
||||
fprintf(out, "## Block Map (sorted by LBN)\n\n");
|
||||
@@ -972,10 +986,57 @@ static void generate_output(FILE *out) {
|
||||
* Main
|
||||
*===========================================================================*/
|
||||
|
||||
/* Loads key_path, extracts its Ed25519 seed into sign_seed, sets
|
||||
* have_sign_seed=1 on success. Shared by build mode and --manifest mode
|
||||
* (both accept an optional --sign-key <path>). Returns 0 on success,
|
||||
* writes an ERROR to stderr and returns -1 on failure. */
|
||||
static int load_sign_key(const char *key_path) {
|
||||
FILE *kf = fopen(key_path, "rb");
|
||||
if (!kf) {
|
||||
fprintf(stderr, "mkcapsule: ERROR: cannot open key '%s'\n", key_path);
|
||||
return -1;
|
||||
}
|
||||
fseek(kf, 0, SEEK_END);
|
||||
long klen = ftell(kf);
|
||||
fseek(kf, 0, SEEK_SET);
|
||||
uint8_t *kbuf = malloc((size_t)klen);
|
||||
if (!kbuf || fread(kbuf, 1, (size_t)klen, kf) != (size_t)klen) {
|
||||
fprintf(stderr, "mkcapsule: ERROR: cannot read key '%s'\n", key_path);
|
||||
fclose(kf);
|
||||
free(kbuf);
|
||||
return -1;
|
||||
}
|
||||
fclose(kf);
|
||||
if (pkcs8_extract_ed25519_seed(kbuf, (size_t)klen, sign_seed) != 0) {
|
||||
fprintf(stderr, "mkcapsule: ERROR: '%s' is not a valid PKCS#8 "
|
||||
"Ed25519 private key\n", key_path);
|
||||
free(kbuf);
|
||||
return -1;
|
||||
}
|
||||
free(kbuf);
|
||||
have_sign_seed = 1;
|
||||
fprintf(stderr, "mkcapsule: signing capsules with key '%s'\n", key_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
/* --manifest mode: generate block ownership markdown */
|
||||
/* --manifest mode: generate block ownership markdown. Optional
|
||||
* --sign-key <keyfile> prefix: mkcapsule --manifest [--sign-key
|
||||
* <keyfile>] <capsules_dir> [<out.md>] -- lets the manifest report
|
||||
* real signing status without touching capsule_generated.c. */
|
||||
if (argc >= 3 && strcmp(argv[1], "--manifest") == 0) {
|
||||
base_dir = argv[2];
|
||||
int a = 2;
|
||||
if (argc >= 4 && strcmp(argv[2], "--sign-key") == 0) {
|
||||
if (argc < 5) {
|
||||
fprintf(stderr, "mkcapsule: ERROR: --manifest --sign-key "
|
||||
"requires <keyfile> <capsules_dir>\n");
|
||||
return 1;
|
||||
}
|
||||
if (load_sign_key(argv[3]) != 0) return 1;
|
||||
a = 4;
|
||||
}
|
||||
|
||||
base_dir = argv[a];
|
||||
base_dir_len = strlen(base_dir);
|
||||
while (base_dir_len > 0 && base_dir[base_dir_len - 1] == '/') base_dir_len--;
|
||||
|
||||
@@ -985,18 +1046,19 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
FILE *mout = stdout;
|
||||
if (argc == 4) {
|
||||
mout = fopen(argv[3], "w");
|
||||
int have_out = (argc == a + 2);
|
||||
if (have_out) {
|
||||
mout = fopen(argv[a + 1], "w");
|
||||
if (!mout) {
|
||||
fprintf(stderr, "mkcapsule: ERROR: cannot create '%s'\n", argv[3]);
|
||||
fprintf(stderr, "mkcapsule: ERROR: cannot create '%s'\n", argv[a + 1]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
generate_manifest(mout);
|
||||
if (mout != stdout) {
|
||||
if (have_out) {
|
||||
fclose(mout);
|
||||
fprintf(stderr, "mkcapsule: manifest written to %s (%d capsule(s))\n",
|
||||
argv[3], manifest_count);
|
||||
argv[a + 1], manifest_count);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1026,32 +1088,7 @@ int main(int argc, char **argv) {
|
||||
"<keyfile> <capsules_dir> <output.c>\n");
|
||||
return 1;
|
||||
}
|
||||
const char *key_path = argv[2];
|
||||
FILE *kf = fopen(key_path, "rb");
|
||||
if (!kf) {
|
||||
fprintf(stderr, "mkcapsule: ERROR: cannot open key '%s'\n", key_path);
|
||||
return 1;
|
||||
}
|
||||
fseek(kf, 0, SEEK_END);
|
||||
long klen = ftell(kf);
|
||||
fseek(kf, 0, SEEK_SET);
|
||||
uint8_t *kbuf = malloc((size_t)klen);
|
||||
if (!kbuf || fread(kbuf, 1, (size_t)klen, kf) != (size_t)klen) {
|
||||
fprintf(stderr, "mkcapsule: ERROR: cannot read key '%s'\n", key_path);
|
||||
fclose(kf);
|
||||
free(kbuf);
|
||||
return 1;
|
||||
}
|
||||
fclose(kf);
|
||||
if (pkcs8_extract_ed25519_seed(kbuf, (size_t)klen, sign_seed) != 0) {
|
||||
fprintf(stderr, "mkcapsule: ERROR: '%s' is not a valid PKCS#8 "
|
||||
"Ed25519 private key\n", key_path);
|
||||
free(kbuf);
|
||||
return 1;
|
||||
}
|
||||
free(kbuf);
|
||||
have_sign_seed = 1;
|
||||
fprintf(stderr, "mkcapsule: signing capsules with key '%s'\n", key_path);
|
||||
if (load_sign_key(argv[2]) != 0) return 1;
|
||||
arg0 = 3;
|
||||
}
|
||||
|
||||
@@ -1061,8 +1098,8 @@ int main(int argc, char **argv) {
|
||||
" %s [--sign-key <keyfile>] <capsules_dir> <output.c>\n"
|
||||
" build capsule C source\n"
|
||||
" %s --lint <capsules_dir> lint all .4th files\n"
|
||||
" %s --manifest <capsules_dir> print block manifest (stdout)\n"
|
||||
" %s --manifest <capsules_dir> <out.md> write block manifest to file\n"
|
||||
" %s --manifest [--sign-key <keyfile>] <capsules_dir> [<out.md>]\n"
|
||||
" print/write block manifest\n"
|
||||
"\n"
|
||||
"Lint checks (per .4th file):\n"
|
||||
" - each block opens with 'Block N'\n"
|
||||
@@ -1078,7 +1115,7 @@ int main(int argc, char **argv) {
|
||||
"\n"
|
||||
"Names are colon-separated relative paths (e.g. core:init.4th).\n"
|
||||
"Files whose encoded name exceeds %d bytes are skipped with a warning.\n",
|
||||
argv[0], argv[0], argv[0], argv[0], CAPSULE_NAME_MAX - 1);
|
||||
argv[0], argv[0], argv[0], CAPSULE_NAME_MAX - 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user