gen-efi is the tool Shani OS uses to build Unified Kernel Images (UKIs), manage MOK (Machine Owner Key) Secure Boot keys, and enroll LUKS2 decryption keys into the TPM2 chip. It runs automatically as part of every shani-deploy update cycle and is also available for manual use.
Understanding gen-efi is not required for everyday use — shani-deploy calls it automatically. This guide is for users who want to understand the boot security chain, manually re-enroll Secure Boot or TPM2 after firmware changes, or diagnose boot issues.
Full reference: docs.shani.dev — Secure Boot and docs.shani.dev — gen-efi.
---
What is a Unified Kernel Image (UKI)?
A UKI is a single EFI binary that bundles:
- The Linux kernel
- The initramfs
- The kernel command line (including root device, LUKS UUID, LSM list, swap offset)
Because all three are packaged together and the whole file is signed with the MOK key, nothing can be changed at boot time without invalidating the signature. This is stronger than a traditionally signed kernel — even the kernel command line is immutable once the UKI is signed.
Shani OS maintains two UKIs, one per slot:
/boot/efi/EFI/shanios/shanios-blue.efi/boot/efi/EFI/shanios/shanios-green.efi
Both are signed with the same MOK key. gen-efi configure regenerates them during every shani-deploy update and on manual request.
---
The Secure Boot Chain
UEFI Firmware
└─ verifies BOOTX64.EFI (Shim, signed by Microsoft CA)
└─ Shim verifies systemd-boot (grubx64.efi, signed by MOK)
└─ systemd-boot verifies and loads the UKI (shanios-blue.efi, signed by MOK)
└─ UKI contains: kernel + initramfs + cmdline (all signed together)
The MOK (Machine Owner Key) is a keypair generated on your machine during installation:
- Private key:
/etc/secureboot/keys/MOK.key(never leaves the device) - Certificate:
/etc/secureboot/keys/MOK.crt - DER-encoded public key:
/etc/secureboot/keys/MOK.der(also copied to/boot/efi/EFI/BOOT/MOK.derfor MokManager enrollment)
If the MOK keypair is missing when gen-efi runs, it automatically generates a fresh 2048-bit RSA keypair, re-signs all existing EFI binaries on the ESP, and stages MOK enrollment. If MOK.key and MOK.crt exist but are a mismatched keypair, gen-efi detects this before attempting to sign and regenerates the full pair rather than failing with an opaque OpenSSL error deep inside dracut.
---
gen-efi Quick Reference
# Generate UKI for a specific slot (must match the currently booted slot when run directly)
sudo gen-efi configure blue
sudo gen-efi configure green
# Enroll MOK key into UEFI firmware (re-signs EFI binaries, stages mokutil enrollment)
sudo gen-efi enroll-mok
# Clean up stale MOK keys from previous installations
sudo gen-efi cleanup-mok
# Enroll LUKS key into TPM2 (for passwordless disk unlock)
sudo gen-efi enroll-tpm2
# Remove stale TPM2 LUKS keyslots after re-enrollment
sudo gen-efi cleanup-tpm2
Important:
gen-efi configureenforces that the target slot matches the currently booted slot when run directly on the live system. Running it for the inactive slot is only permitted inside a chroot, whichshani-deploydoes automatically. This prevents a common mistake: generating a UKI for@greenwhile booted into@bluewould embed@blue's kernel in@green's boot entry.
---
Generating UKIs
gen-efi configure <slot> rebuilds the UKI for a slot by:
- Validating that
<slot>matches the currently booted subvolume (unless running inside a chroot) - Ensuring the MOK keypair exists — generating a new one if missing, and validating that
MOK.keyandMOK.crtare a matching keypair before attempting to sign anything - Mounting the ESP at
/boot/efitemporarily if not already mounted - Updating shim (
BOOTX64.EFI) and systemd-boot (grubx64.efi) on the ESP if the source binaries in/usrare newer than what's on the ESP - Reading the current kernel version from
/usr/lib/modules/ - Detecting the LUKS UUID from the live mapper device, with a fallback to the existing
/etc/crypttabentry for chroot environments where the device path is not accessible - Updating
/etc/crypttaband the dracut crypt config (/etc/dracut.conf.d/99-crypt-key.conf) to keep them consistent - Generating the complete kernel command line — including
rootflags=subvol=@<slot>,rd.luks.*parameters,rd.vconsole.keymap=from/etc/vconsole.conf, andresume=/resume_offset=from the Btrfs swapfile if present — and writing it atomically to/etc/kernel/install_cmdline_<slot> - Running
dracut --force --uefito build the UKI - Signing the binary with
sbsignand verifying it withsbverify - Staging MOK enrollment automatically if the current key is not yet enrolled in firmware (silent when already enrolled)
# Rebuild the UKI for the currently booted slot
sudo gen-efi configure blue # if booted into @blue
sudo gen-efi configure green # if booted into @green
# Verify signatures
sbverify --cert /etc/secureboot/keys/MOK.crt /boot/efi/EFI/shanios/shanios-blue.efi
sbverify --cert /etc/secureboot/keys/MOK.crt /boot/efi/EFI/shanios/shanios-green.efi
When would you manually run gen-efi configure?
- After enabling or changing full-disk encryption
- When troubleshooting a boot issue caused by a stale or corrupt UKI
- After a LUKS UUID change (e.g. re-encryption)
- When
shani-deploycalls it automatically via chroot during a normal update
---
Secure Boot: MOK Enrollment
After installation, Secure Boot is disabled (you disabled it before installing per the pre-installation checklist). To re-enable it, you need to enroll your MOK key into the UEFI firmware.
Method 1: From the Live USB (Recommended)
On the first boot from the Shani OS USB, MokManager (mmx64.efi) launches automatically and offers to enroll a key from disk:
- Select "Enroll key from disk"
- Navigate to the EFI partition and select
EFI/BOOT/MOK.der - Confirm enrollment
- Reboot and enable Secure Boot in BIOS
Method 2: From the Installed System
If you missed the MokManager prompt:
# Re-signs all EFI binaries, copies MOK.der to ESP, stages enrollment via mokutil
sudo gen-efi enroll-mok
# Reboot — MokManager appears automatically
# Confirm with password: shanios
sudo reboot
enroll-mok must run on the live booted system — it talks to real UEFI firmware via mokutil and cannot run inside a chroot. After MokManager completes, enable Secure Boot in BIOS.
# After confirming the new key is enrolled, remove stale keys from previous installations
sudo gen-efi cleanup-mok
# Verify the key is enrolled
mokutil --list-enrolled | grep -i shani
mokutil --sb-state
cleanup-mok compares the fingerprint of each enrolled key against the current MOK.der. Keys that do not match are staged for deletion via mokutil --delete, confirmed in MokManager on the next reboot. Run it only after confirming the new key is enrolled.
---
TPM2 Auto-Unlock
TPM2 auto-unlock seals your LUKS decryption key into the TPM2 chip. The PCR policy is chosen automatically:
- Secure Boot enabled: PCR 0 + PCR 7 — firmware measurements and Secure Boot state (UEFI db/dbx/pk)
- Secure Boot disabled: PCR 0 only — firmware measurements only (weaker: an attacker with physical access could replace the bootloader)
The disk unlocks silently on boot when PCR values match. Your LUKS passphrase always remains valid as a fallback.
During enrollment, gen-efi enroll-tpm2 also checks the LUKS KDF and warns if it is pbkdf2 instead of argon2id — pbkdf2 is orders of magnitude weaker against GPU brute-force attacks. You can convert with cryptsetup luksConvertKey --pbkdf argon2id <device>.
Setup
# Enroll LUKS key into TPM2 (one-time setup after fresh install)
# You will be prompted for your LUKS passphrase
# You can also opt in to a TPM2 PIN for a second factor
sudo gen-efi enroll-tpm2
# Reboot and confirm silent unlock
sudo reboot
After Firmware Updates
If fwupdmgr update updated your BIOS or platform firmware, PCR 0 changes. The TPM will not release the key with the old binding, so you will be prompted for your LUKS passphrase on the next boot. This is expected.
# After booting with passphrase, clean up the stale TPM2 slot
sudo gen-efi cleanup-tpm2
# Re-enroll with the current PCR values
sudo gen-efi enroll-tpm2
cleanup-tpm2 collects all TPM2-type keyslots from the LUKS header, keeps the highest-numbered (most recently written), and wipes the rest using systemd-cryptenroll --wipe-slot. It prompts for your LUKS passphrase to authorise each removal.
After Secure Boot Changes
When you change Secure Boot settings (enable, disable, or change enrolled keys), PCR 7 changes. Re-enroll:
sudo gen-efi cleanup-tpm2
sudo gen-efi enroll-tpm2
Verifying TPM2 State
# List LUKS keyslots and tokens including TPM2 entries
sudo cryptsetup luksDump /dev/nvme0n1p2 | grep -A 5 "Token"
# Confirm TPM2 enrollment
sudo cryptsetup luksDump /dev/nvme0n1p2 | grep systemd-tpm2
# List available TPM2 devices
sudo systemd-cryptenroll --tpm2-device=list
---
Inspecting the Kernel Command Line
The kernel command line is embedded in the UKI at build time. gen-efi always regenerates it from live system state — it never reuses a cached file. The generated line is stored at /etc/kernel/install_cmdline_<slot> (overwritten on every run). To read the cmdline embedded in an existing UKI:
# Extract and display the command line from a UKI
sudo objcopy -O binary --only-section=.cmdline \
/boot/efi/EFI/shanios/shanios-blue.efi /dev/stdout | strings
# Or use ukify (if available)
sudo ukify inspect /boot/efi/EFI/shanios/shanios-blue.efi
The generated command line looks like:
quiet splash systemd.volatile=state ro lsm=landlock,lockdown,yama,integrity,apparmor,bpf
rootfstype=btrfs rootflags=subvol=@blue,ro,noatime,compress=zstd,space_cache=v2,autodefrag
rd.luks.uuid=<uuid> rd.luks.name=<uuid>=shani_root rd.luks.options=<uuid>=tpm2-device=auto
root=/dev/mapper/shani_root rd.vconsole.keymap=us
resume=UUID=<uuid> resume_offset=<offset>
Parameters are added or omitted based on system state: rd.luks.* only on encrypted systems, rd.vconsole.keymap= only if /etc/vconsole.conf defines a keymap, resume= only if /swap/swapfile exists.
---
Troubleshooting
MOK.key and MOK.crt Do Not Match
gen-efi detects keypair mismatches before attempting to sign anything and regenerates the full pair automatically. After regeneration, run enroll-mok to stage enrollment of the new key, then reboot to confirm in MokManager.
UKI Signature Verification Fails
# Verify the UKI against the local MOK cert
sbverify --cert /etc/secureboot/keys/MOK.crt /boot/efi/EFI/shanios/shanios-blue.efi
# If it fails, rebuild the UKI for the current slot
sudo gen-efi configure blue
# If the MOK key changed, re-enroll it
sudo gen-efi enroll-mok
Secure Boot Rejects the Kernel After Update
# Check signature on the new slot's UKI
sbverify --cert /etc/secureboot/keys/MOK.crt /boot/efi/EFI/shanios/shanios-green.efi
# Regenerate if needed (run from the currently booted slot)
sudo gen-efi configure blue
# Confirm the MOK key is enrolled
mokutil --list-enrolled | grep -i shani
TPM2 Fails After Secure Boot Change
When you change Secure Boot settings, PCR 7 changes. Re-enroll:
sudo gen-efi cleanup-tpm2
sudo gen-efi enroll-tpm2
Full boot and security troubleshooting: docs.shani.dev — Boot Issues and docs.shani.dev — Encryption Issues.
---
Resources
- Shani OS Troubleshooting Guide — when things go wrong
- Shani OS FAQ — common questions answered
- docs.shani.dev — Secure Boot — full Secure Boot reference
- docs.shani.dev — gen-efi Reference — complete gen-efi documentation
- docs.shani.dev — TPM2 Enrollment — TPM2 setup guide
- Security Without Configuration — security model overview
- Telegram community
---
Built in India 🇮🇳 · Immutable · Atomic · Zero Telemetry