Secure Boot Demystified — My Step-by-Step Guide to Solving Dual Boot Setup

Secure Boot is one of those features that sounds simple in theory but can be maddening in practice — especially if you’re setting up a dual boot with Windows and Linux. What should have been a straightforward process turned into hours of trial and error for me. This guide is my attempt to break it […]

Secure Boot is one of those features that sounds simple in theory but can be maddening in practice — especially if you’re setting up a dual boot with Windows and Linux. What should have been a straightforward process turned into hours of trial and error for me. This guide is my attempt to break it down step by step, in plain language, so others don’t have to go through the same frustration and makes Secure Boot a little less intimidating.

Aim: To use Secure Boot in a dual boot environment (Linux/Gento and Windows). The bootloader used is Grub.

Important Concepts:

  1. What is Secure Boot?

Secure Boot is a security feature built into modern computer firmware (UEFI) that ensures a device only boots using software trusted by the Original Equipment Manufacturer (OEM). When enabled, it verifies the digital signatures of the bootloader, operating system kernel, and other critical startup components before execution. If any of these files are tampered with or replaced by unauthorized code—such as rootkits or bootkits—Secure Boot will block the system from starting, helping protect against low-level malware and maintaining the integrity of the boot process.

  • What is Grub?

GRUB (GNU GRUB, short for GNU GRand Unified Bootloader) is a widely used open-source bootloader that allows a user to choose and load different operating systems or kernels during system startup. It is commonly used in Unix-like systems, especially Linux, to load the OS into memory after the system firmware (BIOS or UEFI) completes its initialization. GRUB supports a variety of file systems, can chainload other bootloaders, and offers a configurable menu interface, making it flexible for dual-boot or multi-boot setups.

  • What are the UEFI Keys?

UEFI Secure Boot keys are cryptographic keys stored in the system’s firmware (ie. On the motherboard) that control which software is trusted and allowed to run during the boot process. They include four main types:

  1. Platform Key (PK), which establishes the root of trust and authorizes changes to Secure Boot settings. It is installed by the system or motherboard manufacturer and is used to sign and authorize changes to the Secure Boot configuration, including the addition or removal of other keys such as Key Exchange Keys (KEKs). Only the holder of the private half of the Platform Key can modify Secure Boot’s trust structure, making it the ultimate authority that controls which firmware updates, bootloaders, and operating systems are trusted to run on the device.
    1. Key Exchange Keys (KEKs), which authorize updates to the allowed or forbidden signature databases. In other words KEKs are keys in the UEFI Secure Boot framework that act as trusted intermediaries between the Platform Key (PK) and the signature databases (DB and DBX). Installed and maintained by system or OS vendors, KEKs are used to securely update the lists of trusted (DB) and revoked (DBX) digital signatures without requiring direct use of the PK. This design allows authorized vendors—such as Microsoft or a Linux distribution maintainer—to update bootloader trust lists or revoke compromised certificates while keeping the Platform Key safely untouched, maintaining both flexibility and security in the boot process
    1. Database (DB), which contains trusted digital signatures and certificates for approved bootloaders and drivers. In other words, DB keys in UEFI Secure Boot are the collection of trusted digital signatures, certificates, and cryptographic hashes that define which bootloaders, operating system kernels, and UEFI drivers are allowed to run during startup. Stored in the firmware, this whitelist is verified against the software being loaded; if the software’s signature matches an entry in the DB, it is permitted to execute. The DB is typically populated by the system manufacturer or operating system vendors and can be updated through authorized processes using the Key Exchange Keys (KEKs), ensuring that only verified and trusted code is loaded in the boot process.
    1. Forbidden Database (DBX), which lists revoked or blacklisted signatures for software known to be insecure or compromised. (Not to be used much)

Together, these keys ensure that only verified, trusted code can execute at boot, protecting against unauthorized or malicious software.

  • What is an EFI Signature List?

An EFI Signature List (ESL) is a file format used in UEFI Secure Boot to store a list of trusted or revoked digital signatures, certificates, or hashes. Think of it as a “digital guest list” that tells the firmware which programs, bootloaders, or drivers are allowed (or not allowed) to run during startup. These lists are used to update the Secure Boot databases (like DB or DBX) and are always digitally signed so the firmware can be sure they haven’t been tampered with

  • What is the GUID in an ESL?

In UEFI Secure Boot, each EFI Signature List (ESL) includes a GUID (Globally Unique Identifier) that specifies the type or format of the signatures it contains. This GUID tells the firmware how to interpret the entries—for example, whether they are X.509 certificates, SHA-256 hashes, or RSA public keys.

Some common GUIDs used in ESLs are:

  • EFI_CERT_X509_GUID – for X.509 certificate entries.
  • EFI_CERT_SHA256_GUID – for SHA-256 hash entries.
  • EFI_CERT_RSA2048_GUID – for 2048-bit RSA public keys.

Essentially, the GUID is like a “label” inside the list that tells the system what kind of signature data it’s dealing with.

  • Where does one get these Keys?

All motherboards already have the Microsoft keys pre-installed. If they are deleted, the motherboards have ‘Install factory keys’ as an option which installs the KEK and Microsoft keys.

The keys for Gentoo are to be made by the user and this guide describes how to do that.

  • What is UEFI Setup Mode?

Setup Mode in UEFI Secure Boot is the state a system enters when no Platform Key (PK) is installed in the firmware. In this mode, Secure Boot’s signature verification is disabled, allowing unrestricted installation or modification of Secure Boot keys (PK, KEKs, DB, and DBX). It is typically used by system manufacturers or administrators during initial setup or key enrollment. Once a Platform Key is added, the system leaves Setup Mode and enters User Mode, where Secure Boot enforcement begins.

  • What is Shim Lock and why to disable it?

Shim Lock is a security mechanism used in Linux boot processes with UEFI Secure Boot to ensure that only trusted, signed executables are loaded after the initial boot stage. It’s part of the shim bootloader, which is a small, Microsoft-signed piece of code that runs first when Secure Boot is enabled. Shim contains an embedded certificate (usually from the Linux distribution) and uses “shim_lock” to verify that the next-stage bootloader (like GRUB) and the kernel are properly signed with trusted keys. If the signature check fails, the boot process is stopped to prevent unverified or potentially malicious code from running

It will be disabled as we will be signing Grub using gpg keys and hence will not be using the Microsoft signed code.

Software Required:

  1. Sbisigntools: https://git.kernel.org/pub/scm/linux/kernel/git/jejb/sbsigntools.git/
emerge --ask app-crypt/sbsigntools
# emerge --ask app-crypt/efitools
# emerge --ask app-crypt/gnupg
# emerge --ask dev-libs/openssl

Process:

  1. Making the Keys:
    1. Create directories where the keys would be saved:
# mkdir -p /etc/ssl/private/secure_boot
# chmod 700 /etc/ssl/private/secure_boot
  • Create a private key
# cd /etc/ssl/private/secure_boot
# openssl req -x509 -subj "/CN=My PK" -newkey rsa:2048 -noenc -keyout my_pk.pem -days 9999 -sha256 -out my_pk.pem
# openssl req -x509 -subj "/CN=My KEK" -newkey rsa:2048 -noenc -keyout my_kek.pem -days 9999 -sha256 -out my_kek.pem
# openssl req -x509 -subj "/CN=My signing key" -newkey rsa:2048 -noenc -keyout my_db.pem -days 9999 -sha256 -out my_db.pem
  • Create a UUID
# uuidgen > uuid.txt
  • Setting the correct permissions, creating a GUID and ESL:
# for key_name in my_pk my_kek my_db; do
  chmod 400 ${key_name}.pem
  cert-to-efi-sig-list -g $(< uuid.txt) ${key_name}.pem ${key_name}.esl;
done
  • Getting the Factory Keys (ie. Microsoft Keys)

We need to get the Microsoft keys and add our created keys to it so that both windows and linux can be verified by the UEFI. Hence, first we need to get the MS keys which are provided by all motherbopards as factory keys.

# for key_type in KEK db dbx; do
efi-readvar -v "$key_type" -o factory_"${key_type,,}".esl
done
  • Combining our and factory keys:
# for key_type in kek db; do
  cat factory_${key_type}.esl my_${key_type}.esl >combined_${key_type}.esl
done
  • Sign the newly created combined key with the PK (platform key) so that it can be uploaded to the motherboard.
# sign-efi-sig-list -c my_pk.pem -k my_pk.pem PK my_pk.{esl,auth}
# sign-efi-sig-list -c my_pk.pem -k my_pk.pem KEK combined_kek.{esl,auth}
# sign-efi-sig-list -c my_kek.pem -k my_kek.pem db combined_db.{esl,auth}
# sign-efi-sig-list -c my_kek.pem -k my_kek.pem dbx factory_dbx.{esl,auth}
  • Now we need to enter the “Setup Mode”

Generally for entering the setup mode the factory installed keys need to be deleted from the UEFI firmware. The process for MSI and Asrock motherboards is given below:

  1. Reboot the system and enter into UEFI settings mode by pressing DEL.
    1. For Asrock Mother Board
      1. Go into Security>Secure  Boot
  1. Clear Secure Boot Keys to enter Setup Mode
  • For MSI Mother Boards
    • Go to Settings> Security>Secure Boot>Key Management
  1. Delete All Secure Boot Variables
  • Now we have entered the Setup Mode. Reboot into linux and continue further.
  • Check if the system is into Setup Mode:
# efi-readvar

The output will be :

Variable PK has no entries

Variable KEK has no entries

Variable db has no entries

Variable dbx has no entries

Variable MokList has no entries

  • Upload all the PK, KEK, DB and DBX files that we have created to the motherboard:
# cd /etc/ssl/private/secure_boot
# efi-updatevar -f combined_kek.auth KEK
# efi-updatevar -f combined_db.auth db
# efi-updatevar -f factory_dbx.auth dbx
# efi-updatevar -f my_pk.auth PK
  • Recheck if the variables have been uploaded to the motherboard:
# efi-readvar

The output will not be empty.

  • Uptil now we have created the keys, combined them with Microsoft keys amd uploaded them to the motherboard. Now we have to sign the Kernel and Grub files with these keys so that when the UEFI checks with the uploaded keys they are signed.
  1. Kernel Configuration to use Secure Boot and signing the Kernel:
  1. Create Kernel Keys and correcting the permissions:
# mkdir -p /etc/ssl/private/kernel
# chmod 700 /etc/ssl/private/kernel
# openssl req -batch -new -noenc -utf8 -sha3-512 -key <(openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-521) -x509 -outform PEM -out /etc/ssl/private/kernel/my_kernel_key.pem -keyout /etc/ssl/private/kernel/my_kernel_key.pem
# chmod 400 /etc/ssl/private/kernel/my_kernel_key.pem
  • Rebuilding the Kernel:
# cd /usr/src/linux
# make menuconfig
  • To check the below config:

-*- Cryptographic API —>

        Certificates for signature checking —>

            Type of module signing key to be generated (<key type>) —>

Select SHA3-512

[*] Enable loadable module support —>

    -*- Module signature verification

    [*]     Require modules to be validly signed

    [*]     Automatically sign all modules

        Hash algorithm to sign modules (SHA3-512) —>

-*- Cryptographic API —>

    Certificates for signature checking —>

        (/etc/ssl/private/kernel/my_kernel_key.pem) File name or PKCS#11 URI of module signing key

  • Edit the /etc/portage/make.conf

USE=”… modules-sign …”

MODULES_SIGN_KEY=”/etc/ssl/private/kernel/my_kernel_key.pem”

MODULES_SIGN_CERT=”/etc/ssl/private/kernel/my_kernel_key.pem”

MODULES_SIGN_HASH=”sha3-512″

  • Rebuild the Kernel:
# make -j$(nproc) && make -j$(nproc) modules_install && make install
  • Sign the Kernel:
# sbsign --cert /etc/ssl/private/secure_boot/my_db.pem --key /etc/ssl/private/secure_boot/my_db.pem /boot/vmlinuz-<version>-gentoo --output /boot/vmlinuz-<version>-gentoo
  1. The final step is to install Grub and Sign all files used by Grub
    1. Create a file for gpg parameter in /root
# nano /root/my_grub_gpg_parameter

Copy / paste the below in nano:

# See warning!

%no-protection

# As of GRUB 2.12, only DSA and RSA keys are supported.

Key-Type: RSA

Key-Length: 4096

# GRUB only needs to verify signatures.

Key-Usage: sign

# Information to help identify this key.

Name-Real: grub

Name-Comment: This key is used to sign files for GRUB.

# (0) means to never expire.

Expire-Date: 0

%commit

  • Make the gpg key:
# gpg --batch --full-gen-key /root/my_grub_gpg_parameter
  • Export the key for further usage
# gpg -o /tmp/grub_gpg_public_key --export grub
  • Edit /etc/portage/make.conf for Grub

USE=”… secureboot …”

SECUREBOOT_SIGN_KEY=”/etc/ssl/private/secure_boot/my_db.pem”

SECUREBOOT_SIGN_CERT=”/etc/ssl/private/secure_boot/my_db.pem”

  • Install Grub by disabling Shim lock
# grub-install --disable-shim-lock --pubkey=/tmp/grub_gpg_public_key --modules="pgp gcry_sha512 gcry_rsa" --efi-directory=/efi
  • Sign the Grub efi file
# cd /efi/EFI/gentoo
# sbsign --cert /etc/ssl/private/secure_boot/my_db.pem --key /etc/ssl/private/secure_boot/my_db.pem grubx64.efi
# mv grubx64.efi{.signed,}
  • Also need to sign the Microsoft EFI file as under:
# cd /efi/EFI/Microsoft/Boot
# cp bootmgfw.efi bootmgfw.efi.old   #(Create a copy of the MS efi)
# gpg -bu "grub" --digest-algo SHA512 /efi//EFI/Microsoft/Boot/bootmgfw.efi
  • Create a script for signing all files used by grub
# nano /etc/bash/bashrc.d/99_my_install_kernel.bash

Copy paste the below in nano

sign_file_for_grub()

{

            # Sign all files that GRUB will use in the boot chain; The list of files to sign include:

            # – GRUB-related files (configs, environment, modules).

            # – kernel.

            # – initramfs.

            # – CPU microcode.

            local -a File_to_sign=()

            local    current_file=”

            echo “Signing all files required for boot with the GRUB GPG key…”

            # The name of the kernel and initramfs files found in /boot can vary depending on what package and USE flags are used to install the kernel; we need

            # to be less restrictive with our regular expression in the ‘find’ command because of this. Since we don’t know how the kernel and initramfs names

            # end, we simply have to include all file names that contain the words ‘vmlinuz’ or ‘init’; this has the unwanted effect of including files that end

            # with ‘.sig’.

            #

            # To fix this, we use ‘grep’ to filter out the files that end with ‘.sig’. If we didn’t do this, we would eventually get files that end in

            # ‘.sig.sig.sig.sig…’ (a never-ending loop of detached signatures of detached signatures).

            File_to_sign=($(find /boot -regextype posix-extended -regex ‘.*(\.cfg|\.lst|\.mod|vmlinuz.*|init.*|grubenv|-uc\.img)$’ | grep -vE ‘\.sig$’))

            # Delete the old signatures.

            #

            # NOTE:

            # This is not the same as deleting ‘.sig’ files from the ‘File_to_sign’ array; this is deleting the detached signatures of files we know are not

            # signatures themselves.

            rm -f “${File_to_sign[@]/%/.sig}”

            # Now that all the old signatures are deleted, we can make new ones.

            for current_file in “${File_to_sign[@]}”

            do

                        # Make a new detached signature for a file that GRUB will verify on boot.

                        gpg –batch -bu “grub” –digest-algo SHA512 “$current_file” || return 1

            done

}

  1. Run the above script
# source /etc/profile
# sign_file_for_grub
  1. All the files have been signed and now we can reboot
  2. Press DEL and enter UEFI on the Motherboard and enable ‘Secure Boot’
  3. Reboot into Linux and check:
# dmesg | grep -i secure

Output should be Secure Boot Enabled.

  1. In Windows
    1. Click run and msinfo32
    1. Check System Summary Tab – Secure Boot State – ON

Getting Secure Boot to work in a dual boot setup was far from easy, but it reinforced an important lesson: even complex systems can be understood if broken down step by step. With the setup complete, both Windows and Linux now run seamlessly under Secure Boot. What started as a frustrating technical roadblock turned into a rewarding exercise in persistence and problem-solving. Hopefully, this guide gives you not just the steps, but also the confidence that Secure Boot can be tamed — and once it works, it works reliably.

References:

  1. https://wiki.gentoo.org/wiki/Secure_Boot
  2. https://wiki.gentoo.org/wiki/Secure_Boot/GRUB
  3. http://forums.gentoo.org/viewtopic.php?p=8868498#8868498

Leave a Reply

Your email address will not be published. Required fields are marked *