Difference between revisions of "Linux: Secure Boot"
(→Installation of required tools) (change visibility) |
(→Prepare signed grub.cfg kernel and initrd on the EFI partition) (change visibility) |
||
Line 118: | Line 118: | ||
KERNEL_VERSION=$(uname -r) | KERNEL_VERSION=$(uname -r) | ||
KERNEL_CMDLINE=$(cat /proc/cmdline | awk '{ $1=""; print $0 }') | KERNEL_CMDLINE=$(cat /proc/cmdline | awk '{ $1=""; print $0 }') | ||
− | + | cat > /boot/efi/grub.cfg << EOF | |
set timeout_style=menu | set timeout_style=menu | ||
set timeout=2 | set timeout=2 | ||
Line 134: | Line 134: | ||
* Copy your existent kernel and initrd to the EFI partition | * Copy your existent kernel and initrd to the EFI partition | ||
− | + | cp /boot/vmlinuz-$KERNEL_VERSION /boot/efi/ | |
− | + | cp /boot/initrd.img-$KERNEL_VERSION /boot/efi/ | |
* Sign grub.cfg, kernel and initrd with your GPG key | * Sign grub.cfg, kernel and initrd with your GPG key |
Revision as of 06:35, 6 June 2018
Contents
Secure Boot and Linux
The idea is to create a signed GRUB EFI binary with required modules built-in. Secure Boot verifies this binary during boot. GRUB then reads the signed grub.cfg which contains the list of available kernels and then loads the signed kernel and initrd. GRUB's verification is based on GPG which is independent of Secure Boot.
The guide was tested on a Debian system with the specs listed below, but should be easily adaptable.
- Device: fitlet2
- OS: Debian GNU/Linux testing (buster)
- Kernel: 4.13.0-1-amd64
- BIOS: 05/14/2018 American Megatrends Inc. FLT2.0.40.01.00
- GRUB: 2.02-2
- efitools: 1.8.1
Installation of required tools
# super-user mode required su - apt update apt install -y openssl gnupg gpg sbsigntool uuid-runtime # Package efitools must to be compiled and installed manually because Debian repository contains old 1.4.2 version: apt build-dep -y efitools wget https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git/snapshot/efitools-1.8.1.tar.gz tar -xvzf efitools-1.8.1.tar.gz cd efitools-1.8.1 make make install cd -
Secure Boot setup
- Generate your own keys for Secure Boot: PK, KEK, db
CN="Your Common Name" O="Your Organisation" openssl req -new -x509 -newkey rsa:2048 -subj "/CN=$CN PK, O=$O/" -keyout PK.key -out PK.crt -days 7300 -nodes -sha256 openssl req -new -x509 -newkey rsa:2048 -subj "/CN=$CN KEK, O=$O/" -keyout KEK.key -out KEK.crt -days 7300 -nodes -sha256 openssl req -new -x509 -newkey rsa:2048 -subj "/CN=$CN db, O=$O/" -keyout db.key -out db.crt -days 7300 -nodes -sha256
- Convert open part of the keys to the ESL format understood for UEFI
UUID=$(uuidgen --random) cert-to-efi-sig-list -g $UUID PK.crt PK.esl cert-to-efi-sig-list -g $UUID KEK.crt KEK.esl cert-to-efi-sig-list -g $UUID db.crt db.esl
- Sign ESL files
sign-efi-sig-list -k PK.key -c PK.crt PK PK.esl PK.auth sign-efi-sig-list -k PK.key -c PK.crt KEK KEK.esl KEK.auth sign-efi-sig-list -k KEK.key -c KEK.crt db db.esl db.auth
- At this stage your are ready to sign GRUB EFI binary and add it to the list of binaries allowed by Secure Boot
GRUB EFI setup
GRUB EFI supports loading of GPG signed files only e.g. config or kernels through the verify module. The grub-mkstandalone command can be used to create a single GRUB binary with built-in modules and initial configuration script. The GRUB password is required to restrict access to the GRUB shell which allows running arbitrary commands. Your grub.cfg, kernel and initrd and their signatures would be placed on the EFI partition.
- Create initial GRUB configuration script grub.init.cfg
EFI_UUID=$(lsblk -f | grep -i efi | grep -E -o "[A-Z0-9]{4}-[A-Z0-9]{4}") GRUB_PASSWORD="Your GRUB password" GRUB_PASSWORD_HASH=$(echo -e "$GRUB_PASSWORD\n$GRUB_PASSWORD" | grub-mkpasswd-pbkdf2 | grep -o "grub.*") cat > grub.init.cfg << EOF set check_signatures=enforce export check_signatures set superusers=root export superusers password_pbkdf2 root $GRUB_PASSWORD_HASH search --no-floppy --fs-uuid --set=root $EFI_UUID configfile /grub.cfg echo /grub.cfg did not boot the system, rebooting the system in 10 seconds.. sleep 10 reboot EOF ### as result grub.init.cfg will be created
- Generate your GPG key
GPG_PASSWORD="Your GPG password" cat > gpg.batch.file << EOF %echo Generating a basic OpenPGP key Key-Type: DSA Key-Length: 1024 Subkey-Type: ELG-E Subkey-Length: 1024 Name-Real: Denis Turischev Name-Comment: Compulab LTD Name-Email: denis.turischev@compulab.co.il Expire-Date: 0 Passphrase: "$GPG_PASSWORD" # Do a commit here, so that we can later print "done" :-) %commit %echo done EOF gpg --batch --gen-key gpg.batch.file 2>&1 | tee gpg.log GPG_KEY=$(cat gpg.log | grep -o "gpg: key [0-9A-Z]* marked as ultimately trusted" | awk '{ print $3 }') echo GPG_KEY=$GPG_KEY gpg --export $GPG_KEY > gpg.key
- Sing grub.init.cfg with your GPG key
export GPG_TTY=$(tty) # https://github.com/keybase/keybase-issues/issues/2798 # gpg: signing failed: Inappropriate ioctl for device #2798 echo -e "$GPG_PASSWORD" | gpg --yes --default-key $GPG_KEY --detach-sign grub.init.cfg ### as result grub.init.cfg.sig will be created
- Creating single GRUB EFI binary with buit-in modules and signed grub.init.cfg
MODULES="all_video archelp boot bufio configfile crypto echo efi_gop efi_uga ext2 extcmd \ fat font fshelp gcry_dsa gcry_rsa gcry_sha1 gcry_sha512 gettext gfxterm linux linuxefi ls \ memdisk minicmd mmap mpi normal part_gpt part_msdos password_pbkdf2 pbkdf2 reboot relocator \ search search_fs_file search_fs_uuid search_label sleep tar terminal verify video_fb" grub-mkstandalone -d /usr/lib/grub/x86_64-efi -O x86_64-efi --modules "$MODULES" --pubkey gpg.key --output grubx64.efi boot/grub/grub.cfg=grub.init.cfg boot/grub/grub.cfg.sig=grub.init.cfg.sig -v ### as result grubx64.efi will be created
- Sign grubx64.efi with your db key
sbsign --key db.key --cert db.crt grubx64.efi ### as result grubx64.efi.signed will be created, it will be your bootloader
Prepare signed grub.cfg kernel and initrd on the EFI partition
- Mount your EFI partition to /boot/efi
mount /dev/disk/by-uuid/$EFI_UUID /boot/efi
- Create grub.cfg on the EFI partition
KERNEL_VERSION=$(uname -r) KERNEL_CMDLINE=$(cat /proc/cmdline | awk '{ $1=""; print $0 }') cat > /boot/efi/grub.cfg << EOF set timeout_style=menu set timeout=2 set gfxmode=auto set gfxpayload=keep terminal_output gfxterm menuentry 'Debian GNU/Linux, with Linux $KERNEL_VERSION' --unrestricted { echo 'Loading Linux $KERNEL_VERSION ...' linux /vmlinuz-$KERNEL_VERSION $KERNEL_CMDLINE echo 'Loading initial ramdisk ...' initrd /initrd.img-$KERNEL_VERSION } EOF ### as result grub.cfg will be created, please review it
- Copy your existent kernel and initrd to the EFI partition
cp /boot/vmlinuz-$KERNEL_VERSION /boot/efi/ cp /boot/initrd.img-$KERNEL_VERSION /boot/efi/
- Sign grub.cfg, kernel and initrd with your GPG key
gpg --default-key "$GPG_KEY" --detach-sign /boot/efi/grub.cfg gpg --default-key "$GPG_KEY" --detach-sign /boot/efi/vmlinuz-$KERNEL_VERSION gpg --default-key "$GPG_KEY" --detach-sign /boot/efi/initrd.img-$KERNEL_VERSION ### as result signatures of these files will be created
Final steps
- Replace your existent bootloader with signed one
# make a copy of your existent bootloader sudo cp /boot/efi/EFI/boot/bootx64.efi /boot/efi/EFI/boot/bootx64.efi.orig # place grubx64.efi.signed you've created before as default bootloader sudo cp grubx64.efi.signed /boot/efi/EFI/boot/bootx64.efi
- Install keys into EFI (PK last as it will enable Custom Mode locking out further unsigned changes):
sudo efi-updatevar -f db.auth db sudo efi-updatevar -f KEK.auth KEK sudo efi-updatevar -f PK.auth PK
- From now on only EFI binaries signed with any db key can be loaded
- Reboot