Mkinitcpio tpm2 encrypt

Napsal uživatel Stopka dne St, 28. 10. 2020 - 10:11

Všechny mé osobní i firemní počítače běží na Arch Linuxu a úložiště na těchto počítačích mám šifrovaná. To s sebou přináší tu nepříjemnost, že při spuštění počítače se musí zadat dvě hesla. Jedno heslo při spouštění systému odemyká disk, druhé mě pak přihlašuje k uživatelskému účtu. Nešlo by hlavní systémový disk odemknout automaticky? Vždyť mobily dneska taky šifrují úložiště a nemusí se při spouštění zařízení zadávat heslo.

Naštěstí jsou dnes již novější laptopy k tomuto účelu vybaveny tak zvaným trusted platform modulem, neboli TPM. Rozšířené jsou dvě navzájem nekompatibilní verze, starší TPM1.2 a nové TPM2. Jak nastavit starší verzi 1.2 je popsáno na oficiální Arch Wiki, k verzi 2 je na internetu několik neoficiálních návodů u kterých mi vždy chybí některé detaily, nebo obsahují zastaralý, již nefunkční způsob použití některých nástrojů.

TPM2

Pro zmíněné využití je potřeba vědět, že TPM je zařízení na základní desce počítače, které, zjednodušeně řečeno, sleduje průběh startování počítače. V každé fázi startu počítače si z různých hodnot vytvoří hash a ten si uloží do jednoho z Platform Configuration Register (PCR). Hashe kterých údajů se ukládají do kterého registru je popsáno v následující tabulce. Někam se ukládá hash programu který se systém chystá spustit, někam se zas ukládá hash všech konfiguračních hodnot.

Číslo Využití
0 BIOS
1 BIOS configuration
2 Option ROMs
3 Option ROM configuration
4 MBR (master boot record)
5 MBR configuration
6 State transitions and wake events
7 Platform manufacturer specific measurements
8–15 Static operating system
16 Debug
23 Application support

Kdybych sledoval registry 0,2,4 a 7, mám vyzkoušeno, že hashe v nich se změní při jakékoliv změně konfigurace biosu, flashnutí jiné verze biosu, nebo i při aktualizaci jádra. 

Na Arch Linuxu je k práci s tpm2 zařízením k dispozici v oficiálním repozitáři balíček tpm2-tools. Ten obsahuje i prográmek tpm2_pcrread, který vypíše aktuální stav PCR registrů.

Registry pak TPM umí použít k zapečetění tajemství, třeba právě hesla k hlavnímu systémovému disku. Při zapečetění si navolím, jaké registry se mají použít a tpm2 mi vygeneruje privátní a veřejný klíč. Když pak tpm2 předložím znovu privátní i veřejný klíč, zkusí z PCR registrů sestavit původní zapečetěný klíč. Vtip je v tom, že klíč vydá  pouze pokud souhlasí zvolené hashe stavu při zapečetění. To znamená, že je vydá jen pokud nikdo nijak nemanipuloval s firmwarem, konfigurací nebo jinou částí kterou zvolené PCR registry sledují.

Zapečetění klíče

Úplně první krok je, vyčistit tpm2 od našich předchozích pokusů a převzít kontrolu nad zařízením. Je možné že na námi používané adrese je již z předchozích pokusů uložený nějaký objekt, je potřeba jej kdyžtak také odebrat.

tpm2_clear
tpm2_startup -c

#odebrat uložený objekt
tpm2_evictcontrol -C o -c 0x81000001

V tuto chvíli bychom měli mít tpm připravené pro zapečetění našeho klíče. Vytvoříme objekt, uložíme jej a  vytvoříme politiku, tj. seznam registrů a hash funkce které se mají použít pro zapečetění. S pomocí objektu a politiky pak zapečetíme klíč v souboru ssd-crypt.key

#vytvořit object
tpm2_createprimary -c primary.ctx

#uložit nový objekt
tpm2_evictcontrol -c primary.ctx 0x81000001

#vytvořit politiku
tpm2_createpolicy --policy-pcr -l "sha256:0,2,7" -L "pcr.policy"

#zapečetit klíč
tpm2_create -C "0x81000001" \
  -a 'fixedtpm|fixedparent|adminwithpolicy|noda' \
  -i ./ssd-crypt.key -L ./pcr.policy \
  -r ssd-crypt.priv.key -u ssd-crypt.pub.key

V tuhle chvíli máme zapečetěno. V adresáři nám vznikly zmiňované klíče, ze kterých lze získat originální klíč pouze pomocí tpm a jeho správně nastavených registrů.

Získání klíče zpět lze vyzkoušet následovně. Po vykonání by ve složce měl přibýt soubor ssd-crypt.unseal.key obsahující původní zapečetěný klíč.

#načíst uložený objekt
tpm2_load -C "0x81000001" \
  -r ssd-crypt.priv.key -u ssd-crypt.pub.key
  -c primary.unseal.ctx

#odpečetit klíč
tpm2_unseal -c primary.unseal.ctx \
  -o ssd-crypt.unseal.key -p "pcr:sha256:0,2,7"

Odemknutí disku při spuštění

Odemknout hlavní systémový disk je potřeba ve fázi initramfs. Initramfs je soubor obsahující init systém,  jaderné moduly, aplikace a konfigurace, které jsou potřeba pro připojení hlavního systémového disku. Jádro si soubor rozbalí do paměti a pomocí nástrojů uvnitř je schopno najít a připojit hlavní disk.

Soubor initramfs je v Arch Linuxu generován pomocí nástroje mkinitcpio a řídí se konfigurací v /etc/mkinitcpio.conf. Tam je popsáno které moduly se mají přidat, které hooky, tj balíčky knihoven a nástrojů se mají přidat a v jakém pořadí se mají volat.

Z AUR repozitáře lze nainstalovat balíček mkinitcpio-tpm2-encrypt, který do systému nainstaluje tpm2 hook pro odemykání disku. Arch Linux nabízí výběr mezi dvěma init systémy. Tradičnější Busybox init a modernější Systemd init. Od výběru init systému se odvíjí konfigurace souboru /etc/mkinitcpio.conf. V případě Busybox initu stačí přidat tpm2 hook před encrypt hook.

HOOKS="... block tpm2 encrypt filesystems ..."

Nedávno, a teď se dostávám k mému přínosu, jsem balíček rozšířil i o podporu systemd, proto je nově možné odemknout disk přidáním systemd hooku sd-tpm2 před sd-encrypt.

HOOKS="... block sd-tpm2 sd-encrypt filesystems ..."

Do initramfs můžeme přibalit i vygenerovaný veřejný a soukromý klíč pro tpm2.

FILES="/etc/tpm2-encrypt/key.pub /etc/tpm2-encrypt/key.priv"

Hook odpečetí klíč pomotcí tpm2 do souboru /crypto_keyfile.bin, a umožní tak bez zadání hesla spustit celý systém. Informace potřebné k odpečetění hook dostane skrze parametry jádra. Takhle mu například předáme informace pro odpečetění klíče z příkladu výše.

tpmkey=rootfs:/etc/tpm2-encrypt/key:0x81000001 tpmpcr=sha256:0,2,7

Pak už jen nastavíme aby se pro odemčení systémového disku použil náš odpečetěný klíč. Pokud náhodou odpečetění selže, bude uživatel dotázán na heslo jako dříve.

Aktualizace jádra

Pokud nastavíme PCR politiku moc přísně, bude se muset klíč pečetit znovu při každé aktualizaci jádra. Změna jádra totiž znamená změnu hashů některých PCR registrů. Tím asi nikdo nechce procházet tak často a tak se nabízí možnost rozvolnit PCR politiku: Zvolit ty klíče, které se nemění aktualizací jádra. Jenže pak je teoreticky možné, že se někdo může povrtat v jádře, protože to je na nešifrovaném oddíle a jeho podoba se kvůli rozvoněné politice nehlídá a tak získat z tpm2 klíč. Kdyby tak byl způsob jak zajistit aby se spustilo jen námi prověřené jádro.

K tomu můžeme použít secure boot. Když do efi zavedeme naše vlastní secure boot klíče a jádro těmito klíči podepíšeme, systém dovolí spustit jen jádro, které jsme sami svým podpisem schválili. Díky tomu nemusíme kontrolovat PCR registry nastavované podle jádra.

Pokud se někdo pokusí změnit klíče v efi, změní se konfigurace efi a tím i hashe v PCR. Pokud někdo vypne secure boot, opět se změní hashe. Pokud někdo nahraje modifikovaný bios, změní se hashe. To znamená klíč k disku se v takových případech nevydá a data jsou v bezpečí. Když se někdo povrtá v jádrře, nebude odpovídat podpis jádra klíčům a efi jej odmítne spustit a k datům se taky nedostane. Když aktualizuju jádro, vždy jej znovu podepíšu (to lze snadno automatizovat), a automatické odemykání se nám tak nerozbije.

Výsledek

Na disku mám dva oddíly. První je malý, nešifrovaný, ve formátu FAT32. Obsahuje jen secure boot klíči podepsaný soubor linux.efi, což je linuxové jádro a initramfs zabalený společně do jedné efi binárky (efi stub).

Bios umí rovnou binárku spustit načíst z ní jádro, připojit initarmfs a odtud se pak odpečetí klíč k disku, připojí se disk a já jsem chvíli po spuštění počítače vítán přihlašovací obrazovkou gdm.