I'm trying to understand why secure boot works on my machine. It is enabled in the UEFI config, everything boots just fine, and mokutil --sb-state
says SecureBoot enabled
. But I think it shouldn't. Here is how it's supposed to work AFAIK:
- I turn on the machine, and it starts running its builtin firmware.
- The firmware verifies the shim (signed by Microsoft) and jumps into it.
- The shim verifies GRUB (signed by the distro) and jumps into it.
- GRUB verifies its config, the initrd (signed by me?), the kernel (signed by the distro) and boots the kernel.
- The kernel verifies modules (signed by the distro) before loading them.
When I try to verify this manually, the only thing that has a valid signature is the shim. GRUB and the kernel image contain signatures but they fail verification. The initrd and the grub config are not signed. Yet the system boots which does not inspire confidence.
I used mokutil
, sbverify
, and osslsigncode
. Maybe these are not the right tools? Maybe secure boot is actually disabled? I'll try to give as much information as I can.
Here is what I did
First, I exported all of the trusted public keys using mokutil
and displayed the issuer and subject for reference.
# mokutil --export --pk
# mokutil --export --kek
# mokutil --export --db
# mokutil --export
# for derfile in ./*.der; do
> openssl x509 -inform der -outform pem -in "$derfile" -out "${derfile}.pem"
> done
# rename 's/.der.pem$/.pem/' ./*.der.pem
# for pemfile in ./*.pem; do
> echo "$pemfile"
> openssl x509 -inform pem -in "$pemfile" -text | egrep 'CN ?='
> done
./DB-0001.pem
Issuer: C = US, ST = Washington, L = Redmond, O = Microsoft Corporation, CN = Microsoft Root Certificate Authority 2010
Subject: C = US, ST = Washington, L = Redmond, O = Microsoft Corporation, CN = Microsoft Windows Production PCA 2011
./DB-0002.pem
Issuer: C = US, ST = Washington, L = Redmond, O = Microsoft Corporation, CN = Microsoft Corporation Third Party Marketplace Root
Subject: C = US, ST = Washington, L = Redmond, O = Microsoft Corporation, CN = Microsoft Corporation UEFI CA 2011
./DB-0003.pem
Issuer: C = US, O = HP Inc., CN = HP Inc. DB Key 2016 CA
Subject: CN = HP UEFI Secure Boot DB 2017, OU = CODE-SIGN, C = US, O = HP Inc.
./KEK-0001.pem
Issuer: C = US, ST = Washington, L = Redmond, O = Microsoft Corporation, CN = Microsoft Corporation Third Party Marketplace Root
Subject: C = US, ST = Washington, L = Redmond, O = Microsoft Corporation, CN = Microsoft Corporation KEK CA 2011
./KEK-0002.pem
Issuer: C = US, O = HP Inc., CN = HP Inc. KEK 2016 CA
Subject: CN = HP UEFI Secure Boot KEK 2017, OU = CODE-SIGN, C = US, O = HP Inc.
./MOK-0001.pem
Issuer: CN = strib.tech
Subject: CN = strib.tech
./MOK-0002.pem
Issuer: CN = Debian Secure Boot CA
Subject: CN = Debian Secure Boot CA
./PK-0001.pem
Issuer: C = US, O = HP Inc., CN = HP Inc. PK 2016 CA
Subject: CN = HP UEFI Secure Boot PK 2017, OU = CODE-SIGN, C = US, O = HP Inc.
Then, I tried to verify all the relevant files with all of these public keys using sbverify
.
# for imgfile in /boot/vmlinuz-* /boot/initrd.img-* /boot/efi/EFI/devuan/*; do
> for pemfile in ./*.pem; do
> sbverify --cert "$pemfile" "$imgfile" &> /dev/null && echo "$imgfile is signed with $pemfile"
> done
> done
/boot/efi/EFI/devuan/shimx64.efi is signed with ./DB-0002.pem
Oops. Let's check why. I'll show the GRUB image here, but the situation is the same for the shim helper modules and the kernel image.
# sbverify --list /boot/efi/EFI/devuan/grubx64.efi
signature 1
image signature issuers:
- /CN=Debian Secure Boot CA
image signature certificates:
- subject: /CN=Debian Secure Boot Signer 2020
issuer: /CN=Debian Secure Boot CA
It is claiming to be signed by a key that is signed by MOK-0002.pem
. Maybe I don't have that key? Turns out I do, it's just hidden in the same file along with the signature. So I got it out.
# osslsigncode extract-signature -pem -in /boot/efi/EFI/devuan/grubx64.efi -out signature.pem
Succeeded
# openssl pkcs7 -in signature.pem -print_certs -out intermediate.pem
# openssl x509 -in intermediate.pem -text | grep CN
Issuer: CN = Debian Secure Boot CA
Subject: CN = Debian Secure Boot Signer 2020
Unfortunately, verification still fails. Same thing if I cat intermediate.pem
and MOK-0002.pem
together, in any order, or if I remove the junk before BEGIN CERTIFICATE
.
# sbverify --cert intermediate.pem /boot/efi/EFI/devuan/grubx64.efi
Signature verification failed
osslsigncode also has a verify option, and gives more information than sbverify.
# osslsigncode verify -in /boot/efi/EFI/devuan/grubx64.efi -CAfile both.pem -verbose
Current PE checksum : 00183046
Calculated PE checksum: 00183046
Signature Index: 0 (Primary Signature)
Message digest algorithm : SHA256
Current message digest : A9BDE7F125657CB9E30974274B8B2762B2AA7CB86D8DE9386A645A49077AAF8E
Calculated message digest : A9BDE7F125657CB9E30974274B8B2762B2AA7CB86D8DE9386A645A49077AAF8E
Signer's certificate:
Signer #0:
Subject: /CN=Debian Secure Boot Signer 2020
Issuer : /CN=Debian Secure Boot CA
Serial : B55EB3B9
Certificate expiration date:
notBefore : Jul 21 15:52:54 2020 GMT
notAfter : Jul 21 15:52:54 2030 GMT
Number of certificates: 1
Signer #0:
Subject: /CN=Debian Secure Boot Signer 2020
Issuer : /CN=Debian Secure Boot CA
Serial : B55EB3B9
Certificate expiration date:
notBefore : Jul 21 15:52:54 2020 GMT
notAfter : Jul 21 15:52:54 2030 GMT
CAfile: both.pem
TSA's certificates file: /usr/lib/ssl/certs/ca-bundle.crt
Timestamp is not available
Unsupported Signer's certificate purpose XKU_CODE_SIGN
Signature verification: failed
Number of verified signatures: 1
Failed
Maybe the shim ignores all other superfluous fields like the certificate purpose. I'd be fine with this. But to believe that, I'd need to see a different error with a modified GRUB image. The problem is when I overwrite a few bytes here and there, osslsigncode just segfaults.
Partial solution
I know it is possible to embed the initrd inside the kernel image, and the GRUB config in the GRUB image, which I could then sign with my own key, MOK-0001.pem
. So if I can get those signatures verified, I'd be basically done. Verifying the kernel modules would be great, but since they'd be loaded from a verified initrd or a LUKS partition, it's not a huge deal.
What about the kernel modules
The kernel modules are signed according to modinfo
(sbverify
and osslsigncode
don't recognize the file format).
# modinfo iwlwifi | egrep -A12 '^sig'
sig_id: PKCS#7
signer: Debian Secure Boot CA
sig_key: B5:5E:B3:B9
sig_hashalgo: sha256
signature: A1:B8:D5:51:C0:C2:80:AD:01:7A:6E:E9:E9:96:E8:BB:4F:53:7F:09:
1A:62:04:8F:5A:62:97:0C:37:0D:98:17:C4:30:E3:39:9D:4B:FB:7E:
64:03:69:CA:A6:37:59:8C:F9:05:66:FB:A5:F1:66:88:8B:11:75:05:
0C:52:8B:A4:44:D7:70:BD:02:9F:29:1C:87:F4:37:15:6F:83:C8:D7:
2B:BC:CE:F9:9E:D4:D2:23:5A:26:48:A1:C7:43:A7:74:0C:6A:9C:18:
12:A7:D5:93:F2:D8:0D:9D:28:6F:34:CD:88:79:A1:26:32:D3:9F:BF:
8F:B7:91:CA:AF:1E:36:96:B0:F8:FA:B9:05:80:A5:E3:5B:5C:BB:A8:
5B:EC:5D:B6:97:B8:8F:00:99:62:69:19:C5:58:F4:13:D9:3C:5A:C0:
9F:08:49:43:CF:30:DB:CD:8E:9B:6F:65:21:5E:64:68:5B:33:26:93:
38:F5:DA:40:B1:F4:5F:E9:A0:E3:C3:10:C6:0C:EA:A1:42:BF:A8:DD:
59:88:32:E9:7B:4A:2B:0D:89:9D:6F:E7:CE:0D:A6:E9:28:D8:3F:C8:
B1:4F:FC:DD:35:22:D6:23:C4:86:C3:78:1F:5D:E8:2E:FD:3E:D4:D8:
CC:30:1D:BF:5A:2C:C2:2E:83:E8:63:CB:1F:D3:7D:FD
Does modinfo actually verify this or does it just print whatever signature it finds I don't know. I tried changing random bytes in the .ko file to get a failure, but it is unclear from the error message whether it is because of the signature, or just some ELF checksum.
# modinfo iwlwifi.ko
filename: /root/iwlwifi.ko
modinfo: ERROR: could not get modinfo from 'iwlwifi': Invalid argument
Updates
I modified the osslsigncode
source, and I can now verify signatures. The problem was it explicitly disallowed XKU_CODE_SIGN as a certificate purpose.
--- osslsigncode-2.1.orig/osslsigncode.c
+++ osslsigncode-2.1/osslsigncode.c
@@ -2521,12 +2521,6 @@ static int verify_authenticode(SIGNATURE
goto out;
}
- /* check extended key usage flag XKU_CODE_SIGN */
- if (!(X509_get_extended_key_usage(signer) & XKU_CODE_SIGN)) {
- printf("Unsupported Signer's certificate purpose XKU_CODE_SIGN\n");
- goto out;
- }
-
verok = 1; /* OK */
out:
if (!verok)
With this new version, I can successfully verify the shim helper modules, GRUB, and the kernel. Now I can create a GRUB image using grub-mkstandalone
with an embedded public key, and a minimal config that enables signature checking and loads the main config. This covers all files read by GRUB and uses good old GPG detached signatures. Which means there is no need to use CONFIG_INITRAMFS_SOURCE
(that would have been super annoying).
Artem S. Tashkinov's answer clarifies the situation with the kernel modules. I think that's all. I'll create a bootable signer USB stick and keep the secret keys there, which I'll need for updating GRUB (shouldn't be that often).