Arch, Secure Boot a falešný pocit bezpečí

19. 10. 2018 19:00 (aktualizováno) vogo

Nedávno jsem s kolegou diskutoval právě o tomhle vynálezu, SecureBoot. Došli jsme k závěru, že nemá smysl mít podepsaný zavaděč a jádro, když se dá podvrhnout initramdisk a díky tomu odposlechnout heslo šifrovaného disku.

Nedalo mi to a pročetl jsem si kus ArchWiki, mimochodem nejlepší dokumentace k linuxovým distribucím obecně. Heureka! Spojením informací z článku o Secure Boot a systemd-boot vypadly dva skripty a hook pro pacman, které dávají pocit sucha a bezpečí. V nadpisu je zmínka o falešném pocitu bezpečí, nechme stranou úvahy o důvodech, které by někoho vedly k pokusu získat šifrovaná data z disku právě vašeho notebooku. Ona falešnost souvisí s absencí jednoduchého způsobu, jak ověřit, že útočník nezměnil klíče i jádro v době, kdy měl fyzický přístup ke stroji a vy jste o tom nevěděli. To, že jsem paranoidní ještě neznamená, že po mě nejdou.

Krok jedna je vygenerovat klíče, ideálně na nějakém bezpečném místě, například adresář:

/root/secure_boot

Skript, který celou činnost automatizuje je vhodné umístit tamtéž.  /root/secure_boot/gen-keys.sh:

#!/bin/bash
echo -n "Enter path where generate the keys [/root/secure_boot/keys]: "
read KEYS_PATH
[ -z "${KEYS_PATH}" ] && KEYS_PATH="/root/secure_boot/keys"

echo -n "Enter a Common Name to embed in the keys [EFI Platform Key]: "
read KEY_COMMON_NAME
[ -z "${KEY_COMMON_NAME}" ] && KEY_COMMON_NAME="EFI Platform Key"

mkdir -p "${KEYS_PATH}" || exit
cd "${KEYS_PATH}" || exit

# Create a GUID for owner identification:
uuidgen --random > GUID.txt

# Platform key:
openssl req -newkey rsa:2048 -nodes -keyout PK.key -new -x509 -sha256 -days 3650 -subj "/CN=$KEY_COMMON_NAME/" -out PK.crt
openssl x509 -outform DER -in PK.crt -out PK.cer
cert-to-efi-sig-list -g "$(< GUID.txt)" PK.crt PK.esl
sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt PK PK.esl PK.auth

# Sign an empty file to allow removing Platform Key when in "User Mode":
sign-efi-sig-list -g "$(< GUID.txt)" -c PK.crt -k PK.key PK /dev/null rm_PK.auth

# Key Exchange Key:
openssl req -newkey rsa:2048 -nodes -keyout KEK.key -new -x509 -sha256 -days 3650 -subj "/CN=$KEY_COMMON_NAME/" -out KEK.crt
openssl x509 -outform DER -in KEK.crt -out KEK.cer
cert-to-efi-sig-list -g "$(< GUID.txt)" KEK.crt KEK.esl
sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt KEK KEK.esl KEK.auth

# Signature Database key:
openssl req -newkey rsa:2048 -nodes -keyout db.key -new -x509 -sha256 -days 3650 -subj "/CN=$KEY_COMMON_NAME/" -out db.crt
openssl x509 -outform DER -in db.crt -out db.cer
cert-to-efi-sig-list -g "$(< GUID.txt)" db.crt db.esl
sign-efi-sig-list -g "$(< GUID.txt)" -k KEK.key -c KEK.crt db db.esl db.auth

chmod 0600 *.key

echo ""
echo ".key"
echo "PEM format private keys for EFI binary and EFI signature list signing."
echo ".crt"
echo "PEM format certificates for sbsign."
echo ".cer:"
echo "DER format certificates for firmware."
echo ".esl"
echo "Certificates in EFI Signature List for KeyTool and/or firmware."
echo ".auth"
echo "Certificates in EFI Signature List with authentication header (i.e. a signed certificate update file) for KeyTool and/or firmware."
echo ""

echo -n "Copy all *.cer, *.els, *.auth files to your EFI System Partition (Y/n)? "
read -n 1
if [ -z "${REPLY}" ] || [ "${REPLY}" == "y" ]; then
    echo -n "Enter destination path [/boot/secure_boot/]: "
    read DEST_PATH
    [ -z "${DEST_PATH}" ] && DEST_PATH="/boot/secure_boot/"
    mkdir -p "${DEST_PATH}"
    cp *.cer *.esl *.auth  "${DEST_PATH}"
fi

echo "Done!"

Vygenerované veřejné klíče je potřeba naládovat do BIOSu, u mě to šlo přímo v něm samém, jinak to lze i z nabootovaného systému, zvídavého čtenáře nasměřuje odkazovaná stránka z ArchWiki.

Krok druhý je vytvoření jediného souboru, který bude obsahovat jádro, initramdisk a ostatní nezbytnosti k nabootování, a který bude podepsaný. Dá se to zvládnout tak, že ve výsledku není potřeba zavaděč, spouští se přímo tento soubor. Celé tohle kouzlo zvládne skript  /root/secure_boot/mk-sign-linux-efi.sh:

#!/bin/bash

EFI_DIR=/boot/EFI
KEY_DIR=/root/secure_boot/keys
CMD_LINE=/root/secure_boot/cmdline.txt
KERNEL=/boot/vmlinuz-linux
INTEL_UCODE=/boot/intel-ucode.img
INITRAMFS=/boot/initramfs-linux.img
EFI_STUB=/usr/lib/systemd/boot/efi/linuxx64.efi.stub
TMP_DIR=$(mktemp -d)
OUT_IMG=/boot/EFI/Arch/linux.efi

cat ${INTEL_UCODE} ${INITRAMFS} > ${TMP_DIR}/initramfs.img

/usr/bin/objcopy \
    --add-section .osrel=/etc/os-release --change-section-vma .osrel=0x20000 \
    --add-section .cmdline=${CMD_LINE} --change-section-vma .cmdline=0x30000 \
    --add-section .linux=${KERNEL} --change-section-vma .linux=0x40000 \
    --add-section .initrd=${TMP_DIR}/initramfs.img --change-section-vma .initrd=0x3000000 \
    ${EFI_STUB} ${TMP_DIR}/out.efi

mkdir -p $(dirname ${OUT_IMG})

/usr/bin/sbsign --key ${KEY_DIR}/db.key --cert ${KEY_DIR}/db.crt --output ${OUT_IMG} ${TMP_DIR}/out.efi

V ramdisku musí být podpora „komprese“ cat (výchozí stav v Archu), pokud chcete při startu nahrát aktualizaci mikrokódu do procesoru. A hlavně na patřičném místě je třeba mít soubor cmdline.txt, pokud jste spokojeni s parametry aktuálně spuštěného systému, stačí příkaz:

cat /proc/cmdline > /root/secure_boot/cmdline.txt

Výsledkem celého procesu je podepsaný soubor linux.efi, který stačí nastavit v BIOSu jako zaváděný systém. Opět jsem to udělal přímo, bez utility systému, pro zvídavé je postup napsán na ArchWiki viz odkaz výše.

No a poslední slibovaná fičura, zautomatizování celého procesu vytvoření podepsaného efi souboru po aktualizaci systému. Hook pro pacman  /etc/pacman.d/hooks/99-secure-boot.hook:

[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = linux

[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = intel-ucode

[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = systemd

[Trigger]
Type = File
Operation = Install
Operation = Upgrade
Target = usr/lib/initcpio/*

[Action]
Description = Creating Linux.efi bundle and signing for SecureBoot
When = PostTransaction
Exec = /root/secure_boot/mk-sign-linux-efi.sh

Co říci na závěr? Zříkám se jakékoli odpovědnosti za váš nefungující počítač, nebo poškozenou instalaci, hodně štěstí při paranoidním zabezpečování :-D.

Máte zabezpečený systém?

Sdílet