#!/usr/bin/env bash # gen-mok-key.sh — Generate a Machine Owner Key (MOK) pair for Secure Boot # # Purpose: # Produces an RSA-4096 key pair used to sign EFI binaries (BOOTX64.EFI, # shim, grub) and out-of-tree kernel modules so they pass UEFI Secure Boot # verification once the public cert is enrolled in the firmware. # # Output (gitignored): # build/keys/MOK.priv — PEM private key (sbsign / sign-file input) # build/keys/MOK.der — DER public certificate (mokutil enrollment input) # build/keys/MOK.pem — PEM public certificate (sbsign --cert input) # # Idempotent: if MOK.priv already exists, exits 0 without regenerating. # Re-running with existing keys is safe — won't clobber a key already used # to sign released ISOs. # # ─── User enrollment workflow (post-install) ───────────────────────────── # 1. Copy build/keys/MOK.der to the installed system (USB / scp / etc.) # 2. On the booted veilor-os system, as root: # mokutil --import /path/to/MOK.der # Set a one-time password when prompted. # 3. Reboot. The shim's MokManager will appear on next boot — choose # "Enroll MOK", confirm with the password from step 2, then continue # boot. The cert is now in the kernel's .platform keyring. # 4. Verify enrollment: # mokutil --list-enrolled | grep -A2 'veilor' # # ─── Uploading to GitHub Actions secrets ───────────────────────────────── # After running this script, populate the CI signing secrets with: # gh secret set MOK_PRIVATE_KEY < build/keys/MOK.priv # gh secret set MOK_CERT < build/keys/MOK.der # # Keep build/keys/ off-disk-backup-medium-of-record offline. Anyone with # MOK.priv can sign code that boots on enrolled machines. # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" KEY_DIR="$REPO_ROOT/build/keys" PRIV_KEY="$KEY_DIR/MOK.priv" DER_CERT="$KEY_DIR/MOK.der" PEM_CERT="$KEY_DIR/MOK.pem" # Subject for the X.509 cert. Tweak CN if you fork the project. SUBJ="/CN=veilor-os Machine Owner Key/O=veilor-org/OU=secure-boot/" # Cert validity — 10 years. Long enough that we don't churn re-enrollment; # short enough that a leaked key has a hard expiry. DAYS=3650 if [[ -f "$PRIV_KEY" ]]; then echo "[INFO] $PRIV_KEY already exists — skipping (idempotent)." echo "[INFO] To regenerate, delete $KEY_DIR/ first." exit 0 fi mkdir -p "$KEY_DIR" chmod 700 "$KEY_DIR" echo "[*] Generating RSA-4096 MOK keypair → $KEY_DIR/" # Single openssl invocation produces PEM private key + DER public cert. # -nodes = no passphrase on the key (CI must use it non-interactively). # Protect the resulting MOK.priv with filesystem perms only. openssl req \ -new \ -x509 \ -newkey rsa:4096 \ -nodes \ -sha256 \ -days "$DAYS" \ -subj "$SUBJ" \ -keyout "$PRIV_KEY" \ -outform DER \ -out "$DER_CERT" # Also emit a PEM-encoded copy of the cert — sbsign accepts PEM more # reliably than DER in some distros' build of the tool. openssl x509 -inform DER -in "$DER_CERT" -outform PEM -out "$PEM_CERT" chmod 600 "$PRIV_KEY" chmod 644 "$DER_CERT" "$PEM_CERT" echo "[OK] MOK keypair written:" echo " private : $PRIV_KEY (mode 600)" echo " cert DER: $DER_CERT (enroll via mokutil --import)" echo " cert PEM: $PEM_CERT (sbsign --cert input)" echo "" echo "[next] Upload to CI:" echo " gh secret set MOK_PRIVATE_KEY < $PRIV_KEY" echo " gh secret set MOK_CERT < $DER_CERT"