pki: the StarshipOS CA, made on the CI box; capsules signed in CI
Ruled by Captain Bob, 2026-11-07: "New root CA on the CI box. Valid StarshipOS rather than snake oil intermediate." - ci/pki/make-ca.sh makes the StarshipOS Root CA (its key stays on the CI box) and the StarshipOS Capsule Signing intermediate it issues, and stores the signing key as the secret CAPSULE_SIGN_KEY. - The kernel finds the signing certificate by one name, CAPSULE_SIGNING_CERT_NAME = pki:starshipos-intermediate.der. The certificate itself lands once make-ca.sh has run; until then the snakeoil intermediate is in the tree under its old name and the capsules check as "no root key" (a warning, as "missing" was). - mkcapsule refuses a signing key that is not that certificate's. - SIGN_KEY has no default; acceptance, build, nightly and release set it from the secret. FABRIC-3.md XLVI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
This commit is contained in:
@@ -56,6 +56,8 @@
|
||||
|
||||
#include "pkcs8_ed25519.h"
|
||||
#include "starkernel/ed25519.h"
|
||||
#include "starkernel/x509_ed25519.h"
|
||||
#include "starkernel/capsule_sig.h"
|
||||
|
||||
/*===========================================================================
|
||||
* xxHash64 (embedded for build tool — no external dependency)
|
||||
@@ -1575,6 +1577,34 @@ static int load_sign_key(const char *key_path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The signing key must be the one whose certificate the image carries
|
||||
* (CAPSULE_SIGNING_CERT_NAME): the kernel checks every signature against
|
||||
* that certificate, and refuses a signature that does not verify -- Mama's
|
||||
* own included. A key that is not the certificate's would build an image
|
||||
* that cannot boot, so refuse to build it. Returns 0 if they match. */
|
||||
static int check_sign_key_matches_cert(void) {
|
||||
uint8_t key_pub[32], cert_pub[32];
|
||||
ed25519_keygen(sign_seed, key_pub);
|
||||
for (int i = 0; i < capsule_count; i++) {
|
||||
if (strcmp(capsules[i].name, CAPSULE_SIGNING_CERT_NAME) != 0) continue;
|
||||
if (x509_extract_ed25519_pubkey(capsules[i].data, capsules[i].length, cert_pub) != 0) {
|
||||
fprintf(stderr, "mkcapsule: ERROR: %s is not an Ed25519 certificate\n",
|
||||
CAPSULE_SIGNING_CERT_NAME);
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(key_pub, cert_pub, 32) != 0) {
|
||||
fprintf(stderr, "mkcapsule: ERROR: the signing key is not %s's -- every "
|
||||
"capsule would fail its check at boot\n", CAPSULE_SIGNING_CERT_NAME);
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr, "mkcapsule: signing key matches %s\n", CAPSULE_SIGNING_CERT_NAME);
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, "mkcapsule: ERROR: --sign-key given, but no %s to check it against\n",
|
||||
CAPSULE_SIGNING_CERT_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
/* --manifest mode: generate block ownership markdown. Optional
|
||||
* --sign-key <keyfile> prefix: mkcapsule --manifest [--sign-key
|
||||
@@ -1717,6 +1747,10 @@ int main(int argc, char **argv) {
|
||||
|
||||
fprintf(stderr, "mkcapsule: %d capsule(s) collected\n", capsule_count);
|
||||
|
||||
if (have_sign_seed && check_sign_key_matches_cert() != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE *out = fopen(output_path, "w");
|
||||
if (!out) {
|
||||
fprintf(stderr, "mkcapsule: ERROR: cannot create '%s'\n", output_path);
|
||||
|
||||
Reference in New Issue
Block a user