Skip to content

feat(image): sign a UKI with your own key and upgrade anchor - #382

Merged
Bugs5382 merged 3 commits into
mainfrom
feat/41-image-sign
Oct 16, 2026
Merged

Bugs5382 merged 3 commits into
mainfrom
feat/41-image-sign

Conversation

@Bugs5382

Copy link
Copy Markdown
Contributor

What and why

Release assets are built unsigned and carry no upgrade anchor, so a node installed from one serves the image upgrade calls as unavailable and can never take an in-place upgrade. I want to sign an asset after the fact and have the node trust my key for upgrades from then on.

  • internal/release: Certificate() now prefers CRYPTOS_UPGRADE_ANCHOR (base64 std of the cert DER, which cryptos-switchroot sets from the initramfs) over the build-time CertificateDER ldflag, then ErrNoCertificate. A sign-time anchor wins. A sign-time value that does not parse is an error, never a fallback, and it gets the same RSA check.
  • internal/ukisign (new) and cryptosctl image sign --image <unsigned.uki> --key <key.pem> --cert <cert.pem> [--out <signed.uki>]:
    • appends an uncompressed newc cpio holding upgrade-anchor.der (0100444, root, mtime 0) to .initrd, at a 4-byte boundary;
    • keeps every section before .initrd byte for byte at the same RVA and file offset, grows .initrd in place, moves later sections to the next aligned RVA/offset, and updates SizeOfImage, SizeOfInitializedData and the CheckSum;
    • drops any existing certificate table and Authenticode-signs (SHA-256 image hash, SpcIndirectDataContent with the obsolete file link, PKCS feat(config): implement Phase 1 machine-config parser + validator #7 SignedData, WIN_CERTIFICATE rev 2.0);
    • writes <out>.sig, PKCS#1 v1.5 over SHA-256 of the final bytes;
    • checks its own output before writing anything.
  • It refuses anything that isn't a single-profile UKI with exactly one .linux and one .initrd, and any layout where moving the later sections isn't safe (entry point, data directories or symbol table at or after .initrd, unknown trailing data).
  • Default --out: the input without .unsigned, else .signed.uki.
  • Docs: new docs/image-sign.md, linked from the README.

Refs CryptOS-PKI/cryptos-appliance#41

Verification

  • internal/release: tests for each precedence branch (sign-time wins, fallback to build stamp, neither, broken sign-time anchor, non-RSA sign-time anchor).
  • internal/ukisign: a synthetic UKI (stub sections plus .osrel/.cmdline/.initrd/.linux/.sbat) is signed, and the tests check:
    • the layout invariants, read back with debug/pe;
    • the appended cpio parses and holds the certificate;
    • signing again leaves two archives with the new certificate last and replaces the signature;
    • the Authenticode hash matches an independent computation;
    • the .sig passes imageupgrade.Verify;
    • ukipcr.Predict still accepts the output;
    • the refusals.
  • cmd/cryptosctl: tests for the required flags, and that a non-UKI is refused and nothing is written.

How this was verified

CI is the proof. I built and tested nothing locally for this change, and I did not run the doc's command blocks locally. The appliance suite will run sbverify --cert on a UKI signed by this command and boot it (cryptos-appliance#41).

Certificate now reads CRYPTOS_UPGRADE_ANCHOR (base64 DER, set by
cryptos-switchroot from the anchor appended to the UKI's .initrd at sign
time) before the build-time CertificateDER stamp. A sign-time anchor that
does not parse is an error rather than a fallback, and it gets the same
RSA check.

Refs CryptOS-PKI/cryptos-appliance#41

Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com>
cryptosctl image sign --image --key --cert [--out] appends a newc cpio
holding upgrade-anchor.der to the UKI's .initrd, moves the sections after
it without touching the stub's own sections, Authenticode-signs the
result and writes the detached release signature as <out>.sig. The new
internal/ukisign package checks its own output before anything is
written: the anchor is in place, the Authenticode signature verifies over
a fresh image hash, and the .sig passes imageupgrade.Verify.

Refs CryptOS-PKI/cryptos-appliance#41

Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com>
Refs CryptOS-PKI/cryptos-appliance#41

Signed-off-by: Bugs5382 <12115015+Bugs5382@users.noreply.github.com>
@Bugs5382 Bugs5382 added this to the v0.1.0 milestone Oct 16, 2026
@Bugs5382 Bugs5382 added the enhancement New feature (feat). Minor version bump. label Oct 16, 2026
@Bugs5382 Bugs5382 self-assigned this Oct 16, 2026
@Bugs5382
Bugs5382 merged commit 01cf9e5 into main Oct 16, 2026
15 checks passed
@Bugs5382
Bugs5382 deleted the feat/41-image-sign branch October 16, 2026 12:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature (feat). Minor version bump.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant