UEFI Secure Boot+Linux, czyli jak sprawić, aby to działało?
Funkcja "Secure Boot" (bezpieczny rozruch) jest często wyłączana w ustawieniach UEFI, aby móc uruchamiać nośniki z niepodpisanym programem rozruchowym (bootloader), lub np. jeżeli chcemy korzystać jakieś dystrybucji Linux.
Włączanie i konfiguracja bezpiecznego rozruchu dla systemów innych niż Windows i Ubuntu może być dosyć problematyczna dla osób, które nie potrafią czytać dokumentacji, ponieważ często jest ona zbyt kompleksowa (opisuje wiele sposobów radzenia sobie z "Secure Boot") i zazwyczaj nie jest przetłumaczona na język polski. Jednocześnie każda implementacja UEFI jest nieco inna i nie istnieje uniwersalny sposób, który zagwarantuje nam działanie tej funkcji poza Windows.
Sam próbowałem kilka razy, dopiero po przeczytaniu dokumentacji do kilku różnych dystrybucji znalazłem optymalny sposób.
Instrukcje są przeznaczone dla dystrybucji Arch Linux z bootloaderem "systemd-boot" (*dawny gummiboot).Na początek pragnę przytoczyć (przetłumaczone) ostrzeżenie:
„Zastąpienie kluczy platformy (PK) własnymi może zakończyć się zablokowaniem sprzętu na niektórych komputerach, w tym laptopach, uniemożliwiając dostęp do ustawień UEFI/BIOS w celu naprawienia sytuacji. Wynika to z faktu, że oprogramowanie układowe niektórych urządzeń (np. GPU) jest podpisane za pomocą klucza Microsoftu”.<a href="https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#Using_your_own_keys" rel="noopener nofollow" target="_blank">ArchWiki</a><br>
Brzmi niepokojąco? W takim przypadku jednak przestawienie zworki resetującej ustawienia CMOS (lub wyciągnięcie baterii podtrzymującej ustawienia) powinno uratować sytuację.
Nie zawsze jednak łatwo "dobrać się" do płyty głównej, aby to zrobić, szczególnie w laptopach.
Biorąc pod uwagę mnogość implementacji UEFI, trzeba się z potencjalnym ryzykiem liczyć, więc robicie wszystko na własną odpowiedzialność.
Czemu Windows i zazwyczaj Ubuntu nie mają problemu z uruchamianiem się w trybie „Secure Boot”?
Odpowiedź jest prosta. Jeżeli sprawdzimy listę kluczy np. z "db" (baza sygnatur), dodanych fabrycznie przez producenta płyty głównej, pojawi się nam lista, na której widnieje m.in. Microsoft i w ogromnej liczbie przypadków Canonical (Ubuntu).
Przykład: efi‑readvar -v db | grep 'CN='
(...) C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Corporation UEFI CA 2011C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Corporation Third Party Marketplace Root C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Windows Production PCA 2011 C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Root Certificate Authority 2010 C=GB, ST=Isle of Man, L=Douglas, O=Canonical Ltd., CN=Canonical Ltd. Master Certificate Authority
Dlatego też sami musimy zadbać o utworzenie własnych kluczy, podpisanie nimi m.in. kernela systemu, bootloadera i dodaniu kluczy do bazy w UEFI. W przeciwnym wypadku nie uruchomimy innego systemu przy włączonym bezpiecznym rozruchu.
Konfiguracja wymagana do uruchamiania Arch Linux w trybie „Secure Boot”
UWAGA! Ten sposób jest właściwy tylko dla bootloadera systemd-boot!! (nie GRUBa) Potrafi on bezpośrednio załadować podpisane pliki EFI w przeciwieństwie do GRUBa. |
Krótkie wyjaśnienie terminów związanych z "Secure Boot":
- Klucz platformy (PK)
Jest to najwyższy poziom klucza. Domyślnie jest nim klucz od Microsoftu.
- Klucze wymiany klucza (KEK)
Klucze używane do podpisywania aktualizacji bazy podpisów i bazy zakazanych podpisów.
- Baza podpisów (db)
Zawiera klucze i/lub hasze dozwolonych plików binarnych EFI.
- Baza zakazanych podpisów (dbx)
Zawiera klucze i/lub hasze zakazanych plików binarnych EFI. (a także klucze unieważnione)
1. Instalujemy pakiet "efitools":
sudo pacman -S efitools
2. Wykonujemy kopię obecnych kluczy, nawet jeżeli UEFI płyty głównej umożliwia nam przywrócenie fabrycznych, poprzez stosowną opcję (najlepiej umieścić je tymczasowo w łatwo dostępnym miejscu na partycji EFI (ESP)):
UWAGA! Przed wykonaniem kopii, należy wybrać "Other OS" w ustawieniach UEFI w
zakładce Boot => Secure Boot, a także załadowane muszą być domyślne klucze, aby nie otrzymać pustych plików
ESL. Dodatkowo możemy użyć opcji zapisu kluczy na pendrive/partycji EFI. (opcja zapisu kluczy jest dostępna w niektórych implementacjach UEFI) |
sudo su - mkdir /boot/OLDKEYS && cd "$_" efi-readvar -v PK -o old_PK.esl efi-readvar -v KEK -o old_KEK.esl efi-readvar -v db -o old_db.esl efi-readvar -v dbx -o old_dbx.esl
Po tym sprawdzamy, czy utworzone kopie kluczy nie mają zerowego rozmiaru:
du -h *.esl
3. Generujemy własne klucze PK, KEK i db (w różnych formatach):
mkdir /etc/efi-keys && chmod -v 700 "$_" && cd "$_"
(tworzymy katalog na nasze klucze z odpowiednimi prawami dostępu)
uuidgen --random > GUID.txt
(generowanie losowego ID właściciela klucza)
Generowanie - klucz PK:
openssl req -newkey rsa:4096 -nodes -keyout PK.key -new -x509 -sha256 -days 3650 -subj "/CN=my Platform Key/" -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-efi-sig-list -g "$(< GUID.txt)" -c PK.crt -k PK.key PK /dev/null rm_PK.auth
Generowanie - klucz KEK:
openssl req -newkey rsa:4096 -nodes -keyout KEK.key -new -x509 -sha256 -days 3650 -subj "/CN=my Key Exchange Key/" -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
Generowanie - klucz db:
openssl req -newkey rsa:4096 -nodes -keyout db.key -new -x509 -sha256 -days 3650 -subj "/CN=my Signature Database key/" -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
Na koniec kopiujemy je do tymczasowej lokalizacji:
mkdir /boot/DO_DODANIA && cp -v * "$_"
Z tej lokalizacji będziemy później dodawać klucze w ustawieniach UEFI, po tym będzie można katalog "DO_DODANIA" usunąć.
4. Instalujemy pakiet obcy (AUR) "sbupdate-git" i go konfigurujemy:
Wykona nam on konwersję kernela i obrazu initramfs do podpisanego pliku "linux-signed.efi". (i opcjonalnie "linux-fallback-signed.efi") Będzie także dbać o automatyczne podpisywanie przy aktualizacjach systemu. Jest to skrypt napisany w Bashu, specjalnie pod Arch Linuxa. (https://github.com/andreyv/sbupdate)
exit pamac build sbupdate-git
(można użyć innego menadżera do instalacji z AUR)
Otwieramy plik "sbupdate.conf" w swoim preferowanym edytorze tekstu np. kate:
kate /etc/sbupdate.conf
Dodajemy:
EXTRA_SIGN=('/boot/EFI/BOOT/BOOTX64.EFI' '/boot/EFI/systemd/systemd-bootx64.efi')
(należy sprawdzić, czy pliki istnieją w tych lokalizacjach!!)
Następnie wymagany jest CMD_LINE_DEFAULT z parametrami, które wcześniej przekazywaliśmy do kernela w pliku konfiguracyjnym bootloadera.
Przykładowo:
CMDLINE_DEFAULT="root=PARTUUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx rw quiet"
PARTUUID dotyczy naszej partycji ROOT. Możemy go sprawdzić przy pomocy polecenia:
lsblk -o name,mountpoint,partuuid | grep "/ "
UWAGA!! Podstawiamy nasz identyfikator partycji root zamiast x’ów. |
Jeżeli chcemy mieć również opcję "linux-fallback" w bootloaderze to wstawiamy też dodatkowo:
CONFIGS["linux"]="linux linux-fallback"
Mikrokody Intel i AMD (intel-ucode/amd-ucode) są automatycznie wykrywane i nie trzeba ich dołączać jako INITRD.
Sprawdzamy i zapisujemy zmiany w pliku. 5. Zmieniamy konfigurację bootloadera "systemd-boot":
W pliku "/boot/loader/loader.conf" ustawiamy domyślny wpis listy wyboru systemu:
default arch-signed.conf
W katalogu "/boot/loader/entries/" tworzymy plik "arch-signed.conf" i jeżeli wcześniej ustawiliśmy w "sbupdate.conf", że chcemy mieć opcję "linux-fallback", to tworzymy również plik "arch-fallback-signed.conf"
Edytujemy zawartość
"arch-signed.conf" i wstawiamy:
title Arch Linux efi /EFI/Arch/linux-signed.efi
W opcjonalnym "arch-fallback-signed.conf" wstawiamy:
title Arch Linux (fallback) efi /EFI/Arch/linux-fallback-signed.efi
UWAGA! Poprzednie statyczne pliki konfiguracyjne wpisów bootloadera możemy zostawić w razie niepowodzenia lub pomyłki w konfiguracji. |
6. Uruchamiamy "sbupdate":
sudo sbupdate
Ostrzeżenia tego typu możemy zignorować:
warning: data remaining[17952768 vs 17962771]: gaps between PE/COFF sections?
(powinien zostać utworzony plik "linux-signed.efi" i ewentualnie "linux-fallback-signed.efi" w katalogu: "/boot/EFI/Arch")
7. Przechodzimy do ustawień w UEFI, zakładka "Boot" => "Secure Boot". Zmieniamy z "Other OS" na "Windows UEFI". Przechodzimy do "Key Management".
Tutaj ważna jest kolejność, dodajemy klucze najczęściej w kolejności DB → KEK → PK.
Klikamy w "DB Management" => "Append Key" => komunikat "Load the default db" klikamy na "NO".
Klikamy w naszą partycję EFI (ESP), następnie wybieramy katalog "DO_DODANIA".
Na tym etapie wszystko zależy od implementacji UEFI, jednym zadziała plik "db.esl", innym "db.auth" lub "db.cer". Polecam zacząć od "db.esl".
Po wybraniu pliku może być zapytanie o "Input File Format", należy wybrać "Authenticated Variable". Zapyta, czy uaktualnić "db" z wybranego pliku - potwierdzamy. Po tym powinien pokazać się komunikat "Success".
Na starszej płycie Asusa miałem w tym miejscu inny komunikat – "Select Key file type", w takim przypadku należy wybrać "Key Certificate blob".
Dla "KEK Management" wykonujemy dokładnie te same kroki i taki sam typ pliku wybieramy, lecz z przedrostkiem "KEK".
Dla "PK Management" również robimy tak samo, jest to klucz główny (może być tylko 1) i brak opcji "Append Key", musimy wybrać "Set New Key". Wybieramy plik PK z takim samym rozszerzeniem jak w przypadku poprzednich kluczy "db" i "KEK".
Przechodzimy do zakładki "Exit" i zapisujemy zmiany. System powinien się uruchomić.
Jeżeli tak się nie stało i otrzymujemy od UEFI komunikat o niepodpisanym komponencie. To próbujemy dodać klucze tak samo, tylko z plików z innym rozszerzeniem np. ".auth" albo ".cer".
Jeżeli system się nam uruchomi, to konsoli wpisujemy:
bootctl status
Jeśli widzimy napis "Secure Boot: Enabled" - GRATULACJE!
W tym momencie możemy usunąć katalogi "/boot/OLDKEYS" i "/boot/DO_DODANIA". |
W przypadku niepowodzenia i wyczerpania wszystkich możliwości czyścimy wszystkie klucze w ustawieniach UEFI, zmieniamy na "Other OS" i wczytujemy domyślne klucze, z wcześniej utworzonej kopii lub przy pomocy dostępnej opcji w UEFI. (np. "Install default Secure Boot keys" – zwykle widoczne po wyczyszczeniu wszystkich kluczy)
Podsumowanie
Trzeba przyznać, że "Secure Boot" jest dla systemów innych niż Windows/Ubuntu wciąż bardzo toporny w użyciu i traktowany "po macoszemu".
Mechanizm ten był od początku istnienia źle przemyślany, zakładając jako główny "urząd certyfikacyjny" firmę Microsoft lub po prostu użytkownika, który może nie wiedzieć, na jakiej zasadzie to wszystko działa.
Czemu bezpieczny rozruch mimo upływu czasu rzadko jest implementowany w dystrybucjach Linux?
Głównie przez politykę podpisywania obcego kodu stosowaną przez Microsoft:
https://techcommunity.microsoft.com/t5/hardware-dev-center/updated-uefi-signing-requirements/ba-p/1062916
„4. Kod przekazany do podpisania UEFI nie może podlegać GPLv3, ani żadnej licencji, która rzekomo daje komuś prawo do żądania kluczy autoryzacyjnych, aby móc zainstalować zmodyfikowane formy kodu na urządzeniu. Kod objęty taką licencją, który został już podpisany, może mieć unieważniony podpis. Na przykład GRUB 2 jest objęty licencją GPLv3 i nie będzie podpisany”.
Jeżeli czegoś nie zrozumieliście to śmiało pytajcie na forum Dobreprogramy, postaram się pomóc.