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).