pki: the StarshipOS CA, made on the CI box; capsules signed in CI
Build / Image RASPI (push) Successful in 2m17s
Build / Image PC (push) Successful in 2m31s
Build / Image MILKV (push) Successful in 2m20s
Build / v4 tests (32- and 64-bit cells) (push) Successful in 8m51s

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:
Claude
2026-11-07 04:15:29 +00:00
parent 4ae1f759d5
commit 03027f9769
13 changed files with 246 additions and 19 deletions
+44
View File
@@ -6061,3 +6061,47 @@ four conflicts resolved to the branch's files (`92ca805e`).
- The first scheduled nightly's publish to Nexus (#17).
- The Pi 5 and Mars images booted on their boards (#27, #28); a Pi 4 port (#26).
- Revoke the access token `claude-session-20261106` (Settings, Applications).
## XLVI. The StarshipOS CA: capsules signed in CI, by a root on the CI box (2026-11-07)
### 1. Found
Every image built anywhere but Captain Bob's machine carried unsigned capsules: CI, the
acceptance runs, the nightly bound for Nexus, a release, the demo. The capsule-signing key -- the
snakeoil intermediate of the offline LithosAnanke Root CA (FABRIC-2.md, Milestone 6) -- lived only
there, `kernel/Makefile`'s `SIGN_KEY` named its path, and a missing signature is a warning by
design (2026-08-26), so they booted: `V4: capsule v4:sys:core.f18 signature: missing (unsigned)`
in every accepted log (`logs/20261106-004933`). And `mkcapsule` signed with whatever key it was
given: a key that is not the embedded certificate's makes every signature INVALID, which refuses
Mama.
### 2. Ruled
Captain Bob, 2026-11-07: "New root CA on the CI box. Valid StarshipOS rather than snake oil
intermediate."
### 3. Built
- `ci/pki/make-ca.sh`, run once on the CI box: **StarshipOS Root CA** (Ed25519, 20 years,
self-signed; its key stays on that box, in `/var/lib/starshipos-ca`) and **StarshipOS Capsule
Signing** (Ed25519, 10 years, issued by the root, `CA:TRUE, pathlen:0`). It refuses to
overwrite a CA, prints both certificates, and stores the signing key as the repository secret
`CAPSULE_SIGN_KEY` (or says how).
- The image carries `capsules/pki/starshipos-intermediate.der` in place of the snakeoil
intermediate; the kernel finds it by one name, `CAPSULE_SIGNING_CERT_NAME` (`capsule_sig.h`).
- `mkcapsule` checks the signing key against that certificate before it writes anything, and
refuses a key that is not its, or a key with no certificate to check.
- `SIGN_KEY` has no default (`kernel/Makefile`, `v4/Makefile`): CI sets it from the secret (a step
in `acceptance.yml`, `build.yml`, `nightly.yml`, `release.yml`); unset, the capsules are built
unsigned, as before.
What it is not: the kernel still does not check the intermediate against a root at boot
(`x509_ed25519.h`; `ACL.4th`'s `ACL-CA-KEY` is still 0). A signature proves a capsule matches the
certificate in the same image. That is unchanged by this, and a ruling of its own.
### 4. Verified
With a CA made by `make-ca.sh` in a scratch directory (not the real one): `openssl verify` of the
chain OK; `make-ca.sh` refuses a second run; `mkcapsule` with the signing key -- "signing key
matches"; with the root's key -- refused; with a key and no certificate -- refused; with no key --
unsigned, as before. The acceptance with the real certificate is the PR's.