Tinfoil session 1: Enabling secure boot vector on linux
While being a strong proponent of security and privacy I for long neglected one particular security vector on my laptops - secureboot, relying on compensating controls I put in place. SecureBoot was pushed on me by Microsoft so I naturally reflexly rejected it. Now however is a time to reconsider the stance, especially in view of much higher pressure on privacy and as result much deeper penetration of foreing networked compute elements around us (this is the place we put our tinfoil hat on).
So the goal I have in mind in general is somewhat inspired by Librem laptops with libremkey and heads providing secure and tamper-proof boot vector. For this session the bar is set to merely make sure we can boot securily. Simple enough. Since I'm using Arch Linux the obvious starting point is Arch Wiki's article on SecureBoot. I'll need to create my own keys (stored securily), load them to EFI BIOS, sign the EFI image, enable secure boot and boot into linux. Easy peasy.
First we create crypto-vault to store our keys. They should not be stored on the same laptop of course, you should make a crypto vault from cheap usb thumbdrive. Cheap due to low volume, not poor quality. But for simplicity (and due to the fact the first laptop is mostly sitting on the table (I carry another one) - we'll do it on the local drive. Also I have a Nitrokey so the keyfile will be encryped by its pgp card.
First generate random 512bit key and put it on the ramdrive (so that we don't need to securely remove it later). Then use it as a keyfile to create luks partition:dd if=/dev/random of=/tmp/luks bs=64 count=1 sudo cryptsetup luksFormat /dev/sda8 /tmp/luks
Now encrypt the key, store it lokally and recycle the raw key:
gpg -e -r me@ruff.mobi < /tmp/luks >./key dd if=/dev/random of=/tmp/luks bs=64 count=1 rm /tmp/luks gpg -d -u me@ruff.mobi < ./key | sudo cryptsetup open /dev/sda8 Vault -d-
Format luks partition with fav fs (simple ext4 should be ok) and since we need root (sudo) to operate the vault we can move the key to root's home to avoid exposing it in open.
sudo mkfs.ext4 /dev/mapper/Vault sudo mkdir /mnt/sec sudo mv key /root/.key sudo cryptsetup close Vault
Now let's create simple script to open the vault and run the created script to actually open it. If you plan using the script for a longer term it would be better using part UUID instead part number. Numbers are volatile.
vim sezamy
#!/bin/bash
LUKS=/dev/sda8
sudo cat /root/.key | gpg -d -u me@ruff.mobi | sudo cryptsetup open $LUKS Vault -d-
sudo mount /dev/mapper/Vault /mnt/sec
$ bash -x sezamy
+ sudo cat /root/.key
+ gpg -d -u me@ruff.mobi
+ sudo cryptsetup open /dev/sda8 Vault -d-
gpg: verschlüsselt mit 512-Bit ECDH Schlüssel, ID 7DAE27C8C4A956A3, erzeugt 2021-10-23
"Ruslan Marchenko (ruff) <me@ruff.mobi>"
+ sudo mount /dev/mapper/Vault /mnt/sec
sudo mkdir /mnt/sec/ruff
sudo chown ruff:ruff /mnt/sec/ruff/
chmod 700 /mnt/sec/ruff/
Now let's create a home for EFI keys and generate the keys using ArchLinux wiki as a tutorial:
cd /mnt/sec/ruff/ && mkdir UEFI && cd UEFI && mkdir {db,dbx,KEK,PK}
openssl req -new -x509 -newkey rsa:4096 -nodes -sha256 -days 3650 \
-keyout PK.key -subj '/CN=MyPK/' -out PK.crt
openssl req -new -x509 -newkey rsa:4096 -nodes -sha256 -days 3650 \
-keyout KEK.key -subj '/CN=MyKEK/' -out KEK.crt
openssl req -new -x509 -newkey rsa:4096 -nodes -sha256 -days 3650 \
-keyout SDB.key -subj '/CN=MySDB/' -out SDB.crt
sudo pacman -Syu sbsigntools efitools
uuidgen --random > UEFI.guid
cert-to-efi-sig-list -g `< UEFI.guid` PK.crt PK.esl
sign-efi-sig-list -g `< UEFI.guid` -k PK.key -c PK.crt PK PK.esl PK/PK.auth
cert-to-efi-sig-list -g `< UEFI.guid` KEK.crt KEK.esl
sign-efi-sig-list -g `< UEFI.guid` -k PK.key -c PK.crt KEK KEK.esl KEK/KEK.auth
cert-to-efi-sig-list -g `< UEFI.guid` SDB.crt SDB.esl
sign-efi-sig-list -g `< UEFI.guid` -k KEK.key -c KEK.crt db SDB.esl db/SDB.auth
sbkeysync --keystore . --verbose --dry-run --pk
At this point you should see your 3 new keys being detected by sbkeysync. If you're still using dual-boot you'd need to add Microsoft keys:
curl -L 'https://go.microsoft.com/fwlink/?LinkId=321192' > MSProdCA2011.cer curl -L 'https://go.microsoft.com/fwlink/?linkid=321194' > MSUEFICA2011.cer openssl x509 -in MSProdCA2011.cer -out MSProdCA2011.crt -inform DER openssl x509 -in MSUEFICA2011.cer -out MSUEFICA2011.crt -inform DER
Technically we can pipe it right from curl but we may need DER if we want to load them manually.
cert-to-efi-sig-list -g 77fa9abd-0359-4d32-bd60-28f4e78f784b MSProdCA2011.crt \ MSProdCA2011.esl cert-to-efi-sig-list -g 77fa9abd-0359-4d32-bd60-28f4e78f784b MSUEFICA2011.crt \ MSUEFICA2011.esl cat MSProdCA2011.esl MSUEFICA2011.esl > MS.esl sign-efi-sig-list -a -g 77fa9abd-0359-4d32-bd60-28f4e78f784b -k KEK.key \ -c KEK.crt db MS.esl db/MS.auth
The wiki is saying the efivars are locked by immutable flag, let's confirm this:
lsattr /sys/firmware/efi/efivars/{PK,KEK,db,dbx}*
They are indeed, so let's create a simple script which unsets immutable attr and syncs the keys:
echo 'sbkeysync --keystore . --verbose --pk' >> sync.sh vim sync.sh
and add chattr -i /sys/firmware/efi/efivars/{PK,KEK,db,dbx}* before and +i after
sudo bash -x sync.sh ... Error writing key update: Permission denied Error syncing keystore file ./db/SDB.auth
This operation is kind of finicky. On my two laptops, one refused entirely to load keys until I wiped all keys (which switched it into Setup Mode, hence is expected). Then it imported the keys with above command but I needed to re-run it multiple times, it seems sbkeysync is pushing keys in some arbitrary order, but EFI BIOS allows them to be loaded only in specific order (PK, KEK, db). My other laptop pushed db key (without PK/KEK) and then refused to accept either PK or KEK.
Ok, let's add via UEFI BIOS then. Copy auth files to ESP to be accessible from UEFI.
sudo cp {PK,KEK,db}/*.auth /esp/EFI/Linux/
Also sign the unified kernel image:
sudo mv /esp/EFI/Linux/arch.efi /esp/EFI/Linux/arch.uefi sudo sbsign --key UEFI/SDB.key --cert UEFI/SDB.crt \ --output /esp/EFI/Linux/arch.efi /esp/EFI/Linux/arch.uefi warning: data remaining[17838080 vs 17848308]: gaps between PE/COFF sections? warning: data remaining[17838080 vs 17848312]: gaps between PE/COFF sections? Signing Unsigned original image $ sbverify /esp/EFI/Linux/arch.efi warning: data remaining[17840376 vs 17850608]: gaps between PE/COFF sections? Signature verification failed $ sbverify /esp/EFI/Boot/bootx64.efi Signature verification OK $ sbverify /esp/EFI/Boot/bootx64.efi --list signature 1 image signature issuers: - /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Windows Production PCA 2011 image signature certificates: - subject: /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Windows issuer: /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Windows Production PCA 2011 - subject: /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Windows Production PCA 2011 issuer: /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Root Certificate Authority 2010 $ sbverify /esp/EFI/Linux/arch.efi --cert UEFI/SDB.crt warning: data remaining[17840376 vs 17850608]: gaps between PE/COFF sections? Signature verification OK systemctl reboot --firmware-setup
Setup PK/KEK from auth file, enable secure boot, ensure boot entry points to signed efi file, ensure you have set admin password (otherwise what's a point). Save and reboot. Now - here we have different results on two different laptops. First my attemp to deal with old Asus trio (tx201la).
It failed. Even though db looks ok:
$ efi-readvar
Variable PK, length 1324
PK: List 0, type X509
Signature 0, size 1296, owner 54652821-eb08-4bd2-8108-9cbcebc308f4
Subject:
CN=MyPK
Issuer:
CN=MyPK
Variable KEK, length 1326
KEK: List 0, type X509
Signature 0, size 1298, owner 54652821-eb08-4bd2-8108-9cbcebc308f4
Subject:
CN=MyKEK
Issuer:
CN=MyKEK
Variable db, length 4469
db: List 0, type X509
Signature 0, size 1298, owner 54652821-eb08-4bd2-8108-9cbcebc308f4
Subject:
CN=MySDB
Issuer:
CN=MySDB
db: List 1, type X509
Signature 0, size 1572, owner 26dc4851-195f-4ae1-9a19-fbf883bbb35e
Subject:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, \
CN=Microsoft Corporation UEFI CA 2011
Issuer:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, \
CN=Microsoft Corporation Third Party Marketplace Root
db: List 2, type X509
Signature 0, size 1515, owner 26dc4851-195f-4ae1-9a19-fbf883bbb35e
Subject:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, \
CN=Microsoft Windows Production PCA 2011
Issuer:
C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, \
CN=Microsoft Root Certificate Authority 2010
Variable dbx has no entries
Variable MokList has no entries
It did boot into Windows though, hence MS keys are accepted in our new PK/KEK/DB chain. Let's check signature:
$ sbverify /esp/EFI/Linux/arch.efi warning: data remaining[17840376 vs 17850608]: gaps between PE/COFF sections? Signature verification failed
Hm, ok, so despite having new platform keys UEFI is refusing to accept our signature. Let's compare with built-in shim:
$ sbverify /esp/EFI/Linux/arch.efi -v warning: data remaining[17840376 vs 17850608]: gaps between PE/COFF sections? signature 1 image signature issuers: - /CN=MySDB image signature certificates: - subject: /CN=MySDB issuer: /CN=MySDB PKCS7 verification failed 139878892764160:error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error:crypto/pkcs7/pk7_smime.c:284:Verify error:self signed certificate Signature verification failed [ruff@trx ruff]$ sbverify /esp/EFI/Boot/bootx64.efi -v signature 1 image signature issuers: - /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Windows Production PCA 2011 image signature certificates: - subject: /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Windows issuer: /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Windows Production PCA 2011 - subject: /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Windows Production PCA 2011 issuer: /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Root Certificate Authority 2010 PKCS7 verification passed Signature verification OK
Ok, so at least verification utility refuses to accept self-signed SDB while being ok with chained MS Windows signature. Let's create our own cert-chain then and try to cargo-cult the existing shim:
openssl req -new -newkey rsa:4096 -nodes -keyout Arch.key -sha256 \ -subj '/CN=My Arch/' -out Arch.csr openssl x509 -req -in Arch.csr -out Arch.crt -CA UEFI/SDB.crt \ -CAkey UEFI/SDB.key -CAcreateserial -days 3650 sudo sbsign --key Arch.key --cert Arch.crt --addcert SDB.crt --output \ /esp/EFI/Linux/arch.efi /esp/EFI/Linux/arch.uefi systemctl reboot --firmware-setup
And nothing. Going forward - it is a red herring, sbverify utility still fails to verify because it verifies against system trust anchor (root CAs). Either way the Asus EFI BIOS refuses to accept image signed by custom key.
To prove that I've repeated the whole process on second laptop - Dell Inspirion. And there it worked flawlessly at the first attempt. Eg. as mentioned earlier the EFI BIOS refued to accept PK/KEK keys from sbkeysync command. However after copying them to ESP, rebooting into BIOS, setting them manually from files, enabling secure boot and rebooting - my signed EFI image got loaded without any hiccup. I just rebooted again to set admin password and hence seal the secureboot.
$ bootctl --esp-path /esp --no-variables
systemd-boot not installed in ESP.
System:
Firmware: UEFI 2.40 (American Megatrends 5.11)
Secure Boot: enabled
Setup Mode: user
TPM2 Support: yes
Boot into FW: supported
That's a result I expected, and a proof I did everything right the first time. However there are some gaps.
If you followed my thought train via prism of Arch Wiki, you might have not noticed the first gap - namely Unified Kernel Image (arch.uefi). That is - I didn't explain where did I get one, the process how to make one is explained in the referenced archwiki article.
The second gap is Microsoft key. Depending on how thick is a tinfoil on your hat you may want to skip this as it enables booting any image signed by Microsoft keys. While I do not trust microsoft products in terms of privacy, I still consider them having fair security in mind, merely due to the fact tons of huge businesses are relying on their security, and if that becomes (knowingly) compromised the backlash would destroy the company. But this is just for my peace of mind, I'm not at all trying to convince anyone. The choice is yours. And once I receive my gaming console I'll probably ditch it.
And as a spoiler for next part - do make sure you have your original boot method preserved (eg. unsecured efi grub). SecureBoot we just made is not yet ready for deployment, mere MVP.
Link... Mon Nov 29 23:17:42 2021