System: Manjaro/Windows dual-boot, NVMe drive, ASUS motherboard, GRUB bootloader Boot chain: UEFI firmware → shim (Microsoft-signed) → GRUB (MOK-signed) → kernel (MOK-signed) Last verified: February 2026, GRUB 2:2.14, shim-signed 15.8
Based on https://gist.github.com/Jai-JAP/5d5d9f67f19e5e5eaf6825b371a17d5d from Jai-JAP.
Manjaro's GRUB has a built-in shim_lock_verifier that requires the shim protocol when Secure Boot is enabled. You cannot bypass shim — GRUB will refuse to load kernels with "shim protocols not found" if launched directly. The boot chain must be: firmware → shim → GRUB → kernel.
Additionally, modern kernels (especially 6.18+) have gaps between PE/COFF sections. Signing them in-place with sbsign --output $file $file corrupts the signature. You must sign to a temp file first, then move it.
sudo pacman -S sbsigntools efibootmgr openssl
# shim-signed from AUR (provides shimx64.efi, mmx64.efi)
sudo pacman -S shim-signedsudo -i
mkdir -p /usr/share/secureboot/keys
cd /usr/share/secureboot/keys
# Generate 4096-bit RSA key pair, 10-year validity
openssl req -newkey rsa:4096 -nodes \
-keyout MOK.key -new -x509 -sha256 -days 3650 \
-subj "/CN=Manjaro MOK/" -out MOK.crt
# Create DER format for firmware enrollment
openssl x509 -outform DER -in MOK.crt -out MOK.cer
# Copy cert to ESP for firmware and shim enrollment
mkdir -p /boot/efi/keys
cp MOK.cer /boot/efi/keys/openssl x509 -in /usr/share/secureboot/keys/MOK.crt -noout -fingerprint -sha1 -dates
ls -la /usr/share/secureboot/keys/
# Should show: MOK.key (private), MOK.crt (PEM cert), MOK.cer (DER cert)Under Secure Boot, GRUB enters lockdown mode and cannot insmod external modules from disk. Every module referenced by grub.cfg must be built into the EFI binary.
# Check which modules grub.cfg actually references
grep -oP "insmod \K\S+" /boot/grub/grub.cfg | sort -u
# Check which of those exist for EFI (some are BIOS-only)
for mod in $(grep -oP "insmod \K\S+" /boot/grub/grub.cfg | sort -u); do
[ ! -f "/usr/lib/grub/x86_64-efi/${mod}.mod" ] && echo "MISSING (skip): $mod"
doneBuild GRUB with all available modules. Omit any that don't exist (vbe, vga, ieee1275_fb are BIOS/OpenFirmware-only):
MODULES="all_video boot btrfs cat chain configfile cpuid cryptodisk echo \
efifwsetup efinet ext2 fat font gcry_arcfour gcry_blowfish gcry_camellia \
gcry_cast5 gcry_crc gcry_des gcry_dsa gcry_idea gcry_md4 gcry_md5 \
gcry_rfc2268 gcry_rijndael gcry_rmd160 gcry_rsa gcry_seed gcry_serpent \
gcry_sha1 gcry_sha256 gcry_sha512 gcry_tiger gcry_twofish gcry_whirlpool \
gettext gfxmenu gfxterm gfxterm_background gzio halt help hfsplus iso9660 \
jpeg keystatus linux loadenv loopback ls lsefi lsefimmap lsefisystab lssal \
luks luks2 lvm mdraid09 mdraid1x memdisk minicmd normal ntfs part_apple \
part_gpt part_msdos password_pbkdf2 play png probe raid5rec raid6rec reboot \
regexp search search_fs_file search_fs_uuid search_label serial sleep smbios \
squash4 test tpm true video xfs zfs zfscrypt zfsinfo efi_gop efi_uga \
video_bochs video_cirrus bli"
grub-install --target=x86_64-efi --efi-directory=/boot/efi \
--modules="${MODULES}" --sbat /usr/share/grub/sbat.csv
grub-mkconfig -o /boot/grub/grub.cfgls -lh /boot/efi/EFI/Manjaro/grubx64.efi
# Should be ~2MB (indicates modules are embedded)
# A tiny ~160KB binary means modules were NOT embedded
objdump -h /boot/efi/EFI/Manjaro/grubx64.efi | grep sbat
# Should show an .sbat sectionsbsign --key /usr/share/secureboot/keys/MOK.key \
--cert /usr/share/secureboot/keys/MOK.crt \
--output /boot/efi/EFI/Manjaro/grubx64.efi \
/boot/efi/EFI/Manjaro/grubx64.efisbverify --list /boot/efi/EFI/Manjaro/grubx64.efi
# Should show: subject: /CN=Manjaro MOK
sbverify --cert /usr/share/secureboot/keys/MOK.crt /boot/efi/EFI/Manjaro/grubx64.efi
# Should show: Signature verification OKCritical: Modern kernels have PE/COFF gaps. In-place signing corrupts the signature. Always sign to a temp file, then replace.
for kernel in /boot/vmlinuz-*; do
echo "=== Signing $kernel ==="
# Remove any existing (potentially bad) signature
sbattach --remove "$kernel" 2>/dev/null
# Sign to temp file, then move (avoids in-place corruption)
sbsign --key /usr/share/secureboot/keys/MOK.key \
--cert /usr/share/secureboot/keys/MOK.crt \
--output "${kernel}.signed" \
"$kernel"
mv "${kernel}.signed" "$kernel"
donefor k in /boot/vmlinuz-*; do
echo "=== $k ==="
sbverify --cert /usr/share/secureboot/keys/MOK.crt "$k" 2>&1
done
# ALL must show: Signature verification OK
# The "data remaining / gaps between PE/COFF sections" warning on newer kernels is normalShim and GRUB must be in the same directory. Shim automatically loads grubx64.efi from its own directory.
# Copy shim and MokManager next to GRUB
cp /usr/share/shim-signed/shimx64.efi /boot/efi/EFI/Manjaro/shimx64.efi
cp /usr/share/shim-signed/mmx64.efi /boot/efi/EFI/Manjaro/mmx64.efi
# Also set up the UEFI fallback boot path
cp /usr/share/shim-signed/shimx64.efi /boot/efi/EFI/boot/bootx64.efi
cp /boot/efi/EFI/Manjaro/grubx64.efi /boot/efi/EFI/boot/grubx64.efi
cp /usr/share/shim-signed/mmx64.efi /boot/efi/EFI/boot/mmx64.efifind /boot/efi/EFI/Manjaro/ /boot/efi/EFI/boot/ -type f -name "*.efi" | sort
# Expected:
# /boot/efi/EFI/Manjaro/grubx64.efi (~2MB, your signed GRUB)
# /boot/efi/EFI/Manjaro/mmx64.efi (MokManager)
# /boot/efi/EFI/Manjaro/shimx64.efi (shim)
# /boot/efi/EFI/boot/bootx64.efi (copy of shim, UEFI fallback)
# /boot/efi/EFI/boot/grubx64.efi (copy of signed GRUB)
# /boot/efi/EFI/boot/mmx64.efi (copy of MokManager)
sbverify --list /boot/efi/EFI/Manjaro/shimx64.efi 2>&1 | head -5
# Should show: Microsoft Corporation UEFI CA
sbverify --list /boot/efi/EFI/Manjaro/grubx64.efi 2>&1 | head -5
# Should show: /CN=Manjaro MOKThe existing Manjaro entry must point to shim, not directly to GRUB. Do NOT create a separate "Shim" entry — just update the Manjaro one.
# Check current entry
efibootmgr -v | grep -i manjaro
# Note the boot number (e.g., Boot0000)
# Delete and recreate pointing to shim
efibootmgr --delete-bootnum --bootnum 0000
efibootmgr --unicode --disk /dev/nvme0n1 --part 1 \
--create --label "Manjaro" --loader /EFI/Manjaro/shimx64.efiefibootmgr -v
# Manjaro entry should point to \EFI\Manjaro\shimx64.efi
# Windows entry should still point to \EFI\Microsoft\Boot\bootmgfw.efiShim has its own key database separate from the UEFI firmware. Even if the key is in the firmware's db, shim needs it enrolled in its MOK list too.
mokutil --import /usr/share/secureboot/keys/MOK.cer
# Enter a one-time password (you'll need it at next boot)On reboot, shim will present the MokManager screen:
- Select "Enroll MOK"
- Select "Continue"
- Select "Yes"
- Enter the password you just set
- Select "Reboot"
mokutil --list-enrolled | grep "CN=Manjaro MOK"
# Should show your key
mokutil --test-key /usr/share/secureboot/keys/MOK.cer
# Should show: /usr/share/secureboot/keys/MOK.cer is already in dbThis is required in addition to shim's MOK enrollment. The firmware needs to trust shim, and shim needs to trust your GRUB and kernels.
- Reboot into BIOS (press Del or F2 at POST)
- Go to Advanced tab → Secure Boot (or Boot tab, varies by model)
- Set Secure Boot Mode to Custom
- Enter Key Management
- Select Authorized Signatures (db)
- Select Append (
⚠️ NOT "Replace" — that would delete Microsoft's keys and break Windows!) - Navigate to your EFI partition and select
keys/MOK.cer - When asked "Input File Format", select "Public Key Certificate"
- Confirm the enrollment
- Set Secure Boot to Enabled
- Save & Exit (F10)
Boot into Manjaro with Secure Boot enabled, then verify:
# Secure Boot should be enabled
mokutil --sb-state
# Expected: SecureBoot enabled
# Key should be in firmware db
mokutil --test-key /usr/share/secureboot/keys/MOK.cer
# Expected: already in db
# Boot chain verification
dmesg | grep -i "secure boot"
# Should indicate Secure Boot is activeBoot into Windows to verify it still works (it should — we appended to db, didn't replace).
Create /etc/pacman.d/hooks/999-signKernel.hook:
[Trigger]
Type = Package
Operation = Install
Operation = Upgrade
Operation = Remove
Target = linux*
[Action]
Description = Signing kernel with MOK for Secure Boot
When = PostTransaction
Exec = /bin/bash -c 'for k in /boot/vmlinuz-*; do sbattach --remove "$k" 2>/dev/null; sbsign --key /usr/share/secureboot/keys/MOK.key --cert /usr/share/secureboot/keys/MOK.crt --output "${k}.signed" "$k" && mv "${k}.signed" "$k"; done'
Depends = sbsigntoolsNote: This hook uses the temp-file signing method to avoid in-place corruption on kernels with PE/COFF gaps.
Create /etc/pacman.d/hooks/1000-signGrub.hook:
[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Path
Target = /boot/efi/EFI/Manjaro/grubx64.efi
[Action]
Description = Signing GRUB with MOK for Secure Boot
When = PostTransaction
Exec = /usr/share/secureboot/signGrub.sh
Depends = sbsigntools
Depends = findutils
Depends = grep
Depends = grubCreate /usr/share/secureboot/signGrub.sh:
#!/bin/bash
MODULES="all_video boot btrfs cat chain configfile cpuid cryptodisk echo \
efifwsetup efinet ext2 fat font gcry_arcfour gcry_blowfish gcry_camellia \
gcry_cast5 gcry_crc gcry_des gcry_dsa gcry_idea gcry_md4 gcry_md5 \
gcry_rfc2268 gcry_rijndael gcry_rmd160 gcry_rsa gcry_seed gcry_serpent \
gcry_sha1 gcry_sha256 gcry_sha512 gcry_tiger gcry_twofish gcry_whirlpool \
gettext gfxmenu gfxterm gfxterm_background gzio halt help hfsplus iso9660 \
jpeg keystatus linux loadenv loopback ls lsefi lsefimmap lsefisystab lssal \
luks luks2 lvm mdraid09 mdraid1x memdisk minicmd normal ntfs part_apple \
part_gpt part_msdos password_pbkdf2 play png probe raid5rec raid6rec reboot \
regexp search search_fs_file search_fs_uuid search_label serial sleep smbios \
squash4 test tpm true video xfs zfs zfscrypt zfsinfo efi_gop efi_uga \
video_bochs video_cirrus bli"
if ! /usr/bin/sbverify --list /boot/efi/EFI/Manjaro/grubx64.efi 2>/dev/null | /usr/bin/grep -q "signature certificates"; then
/usr/bin/grub-install --target=x86_64-efi --efi-directory=/boot/efi/ \
--modules="${MODULES}" --sbat /usr/share/grub/sbat.csv
/usr/bin/sbsign --key /usr/share/secureboot/keys/MOK.key \
--cert /usr/share/secureboot/keys/MOK.crt \
--output /boot/efi/EFI/Manjaro/grubx64.efi \
/boot/efi/EFI/Manjaro/grubx64.efi
/usr/bin/cp /boot/efi/EFI/Manjaro/grubx64.efi /boot/efi/EFI/boot/grubx64.efi
fichmod +x /usr/share/secureboot/signGrub.shRun this anytime to check the health of your Secure Boot setup:
sudo bash -c '
echo "========================================="
echo " Secure Boot Diagnostic"
echo "========================================="
echo ""
echo "=== Secure Boot State ==="
mokutil --sb-state 2>/dev/null
echo ""
echo "=== Boot Entries ==="
efibootmgr -v | grep "^Boot"
echo ""
echo "=== EFI Layout ==="
find /boot/efi/EFI/Manjaro/ /boot/efi/EFI/boot/ -type f -name "*.efi" 2>/dev/null | sort
echo ""
echo "=== GRUB Size & Signature ==="
ls -lh /boot/efi/EFI/Manjaro/grubx64.efi
sbverify --list /boot/efi/EFI/Manjaro/grubx64.efi 2>&1 | grep -A2 "subject"
echo ""
echo "=== Shim Signature ==="
sbverify --list /boot/efi/EFI/Manjaro/shimx64.efi 2>&1 | grep -A2 "issuer" | head -3
echo ""
echo "=== Kernel Signatures ==="
for k in /boot/vmlinuz-*; do
echo "--- $(basename $k) ---"
sbverify --cert /usr/share/secureboot/keys/MOK.crt "$k" 2>&1
done
echo ""
echo "=== MOK Key Fingerprint ==="
openssl x509 -in /usr/share/secureboot/keys/MOK.crt -noout -fingerprint -sha1
echo ""
echo "=== MOK Enrolled in Shim? ==="
mokutil --list-enrolled 2>/dev/null | grep "SHA1 Fingerprint"
echo ""
echo "=== MOK in Firmware DB? ==="
mokutil --test-key /usr/share/secureboot/keys/MOK.cer 2>/dev/null
echo ""
echo "=== GRUB Modules Check ==="
echo "Modules in grub.cfg that are BIOS-only (expected to be missing):"
for mod in $(grep -oP "insmod \K\S+" /boot/grub/grub.cfg | sort -u); do
[ ! -f "/usr/lib/grub/x86_64-efi/${mod}.mod" ] && echo " $mod (BIOS-only, harmless)"
done
echo ""
echo "========================================="
echo " Done"
echo "========================================="
'| Error | Cause | Fix |
|---|---|---|
| "shim protocols not found" | GRUB launched directly, not through shim | Boot entry must point to shimx64.efi, not grubx64.efi |
| "bad shim lock signature" | Kernel signature is invalid or signed with wrong key | Re-sign kernels using temp-file method (Step 4) |
| Silent loop back to GRUB menu | GRUB can't load external modules in lockdown mode | Rebuild GRUB with all modules embedded (Step 2) |
| "alloc magic is broken" | GRUB binary too large / memory corruption | Reduce module count; remove modules not in /usr/lib/grub/x86_64-efi/ |
| Signature verification failed (sbverify) | In-place signing corrupted the signature | Strip signature with sbattach --remove, re-sign to temp file |
| Windows won't boot | Microsoft keys removed from firmware db | Re-enter BIOS → Secure Boot → Restore Factory Keys, then re-append your MOK.cer |
| File | Location | Purpose |
|---|---|---|
| MOK private key | /usr/share/secureboot/keys/MOK.key |
Signs GRUB and kernels |
| MOK cert (PEM) | /usr/share/secureboot/keys/MOK.crt |
Used by sbsign |
| MOK cert (DER) | /usr/share/secureboot/keys/MOK.cer |
Enrolled in firmware db and shim |
| MOK cert on ESP | /boot/efi/keys/MOK.cer |
Accessible from BIOS for enrollment |
| Shim | /boot/efi/EFI/Manjaro/shimx64.efi |
Microsoft-signed first-stage loader |
| MokManager | /boot/efi/EFI/Manjaro/mmx64.efi |
Key enrollment tool |
| GRUB | /boot/efi/EFI/Manjaro/grubx64.efi |
MOK-signed bootloader |
| GRUB config | /boot/grub/grub.cfg |
Generated by grub-mkconfig |
| GRUB defaults | /etc/default/grub |
Input for grub-mkconfig |
| Kernel signing hook | /etc/pacman.d/hooks/999-signKernel.hook |
Auto-signs on kernel update |
| GRUB signing hook | /etc/pacman.d/hooks/1000-signGrub.hook |
Auto-signs on GRUB update |