Phase 10
Secure Boot
Sign the kernel's EFI binary so it can boot on real hardware with UEFI Secure Boot enabled, without needing to disable the firmware security check.
Learning goal
Understand how UEFI Secure Boot works and why it exists.
Category
foundations
Components touched
Builds on
Unlocked by this phase
Why this phase matters
Sign the kernel’s EFI binary so it can boot on real hardware with UEFI Secure Boot enabled, without needing to disable the firmware security check.
How it works in m3OS
Phase 10 adds a host-side signing workflow so m³OS can produce Secure Boot-friendly artifacts for real UEFI hardware. The implementation has three pieces:
How it builds on earlier phases
This phase builds on Framebuffer And Shell and turns that foundation into Secure Boot.
Implementation outline
- Generate a 4096-bit RSA key pair and self-signed X.509 certificate with
openssl. - Add
cargo xtask sign <unsigned-efi>for signing any EFI executable with optional--key/--certoverrides. - Extend
cargo xtask imagewith--signso the build produces a signed bootable disk image in addition to the unsigned image. - Document the one-time certificate enrollment. Two paths exist — choose based on the target machine (see above).
- Verify the signed binary boots with
mokutil --sb-stateordmesgreporting Secure Boot enabled.
Task progress snapshot
18 of 21 tracked tasks are complete.
Documentation targets
- Documentation deliverables have not been listed yet.
Deferred follow-on work
- Key rotation and revocation.
- Submitting to the Microsoft UEFI CA for public distribution.
- Measured boot / TPM attestation (verifying the kernel hash against a TPM PCR).
- Signing individual kernel modules (not applicable to a monolithic or microkernel design where all trusted code is in the single EFI binary).
Source materials
Important code
Code spotlight cards
Code spotlight
Add sign subcommand to xtask
Add sign subcommand to xtask. Why it matters: Integrating signing into the build pipeline avoids manual sbsign invocations. Focus on `cmd_sign` and `sign_efi` in `xtask/src/main.rs` while you trace the snippet.
fn cmd_sign(sign_args: &SignArgs) {
let signed_efi = sign_efi(sign_args);
println!("Signed EFI: {}", signed_efi.display());
println!(
"Reminder: enroll {} with MOK before Secure Boot tests.",
sign_args.cert.display()
);
} Key files
How real OSes differ
- Linux distributions use a **shim** first-stage bootloader signed by Microsoft's UEFI CA. The shim maintains its own **MOK (Machine Owner Key)** database and verifies GRUB, which in turn verifies the kernel. This lets distros ship updates without involving Microsoft on every kernel release.
- The shim approach requires applying to the Microsoft UEFI CA program (months, legal entity required), signing the shim binary with Microsoft's key, and then using the shim to trust the distro's own key for subsequent stages.
- For a personal OS there are two practical options:
- **Via shim's MOK** (`mokutil --import`): the easiest path on machines that already boot through shim. The key lives in shim's MOK list, not the UEFI firmware db.
- **Direct UEFI db enrollment** (`efi-updatevar` or firmware setup): adds the key to the firmware's own signature database, works without shim, but requires putting the firmware into Setup Mode and re-enrolling the PK/KEK hierarchy.
- Windows uses a similar hierarchy but its keys are enrolled by the OEM at manufacturing time. End users cannot easily add their own keys on consumer hardware that ships with "Windows Secure Boot" locked down (though most firmware allows it in the UEFI setup).
Success criteria
- `cargo xtask sign <unsigned-efi>` produces a verified `*-signed.efi`.
- `cargo xtask image --sign` produces `boot-uefi-m3os-signed.img` (and `.vhdx`).
- The signed EFI passes `sbverify --cert m3os.crt <signed-efi>`.
- The unsigned EFI fails `sbverify --cert m3os.crt <unsigned-efi>`.
- The kernel boots on real hardware with Secure Boot enabled after enrolling the cert.
- Booting the unsigned or untrusted image with Secure Boot on is rejected by firmware.
Related phases
Keep exploring the roadmap
Phase 09
CompleteFramebuffer And Shell
Make the OS pleasant to interact with by adding on-screen text output and a very small shell for manual exploration.
Phase 11
CompleteProcess Model
Load and execute arbitrary userspace binaries from disk as isolated ring-3 processes, with a proper lifecycle: spawn, run, wait, exit.