[arch-releng] Secure Boot support (FS#53864)
Hi all, following up on FS#53864, I tried to summarise possible ways to implement Secure Boot in Arch Linux. I apologise in advance for the very long email... I structured the text into two possible approaches (technically three, but the first one is not very feasible) and would love to hear your opinion on them. If there is an interest in implementing Secure Boot, I am happy to help out wherever I can. You will see however that most required changes are more on the "administrative" side rather than the "coding" side, e.g. officially adopting packages from the AUR, creating certificates, submitting binaries to Microsoft for review, ... I have successfully tested the approach "Using a signed shimx64.efi built by a third party" on different machines, with Secure Boot enabled and disabled. Current situation ----------------- On UEFI systems, Archiso uses PreLoader.efi from efitools [1] to chainload the systemd-boot boot loader. As the efitools EFI binaries used in Arch Linux are built from source and not signed by Microsoft, this procedure fails when Secure Boot is enabled because the unsigned PreLoader.efi cannot be executed. (This makes the preloader a bit useless, see FS#59487: systemd-boot could be directly installed as bootx64.efi instead, as the only purpose of the preloader is to make Secure Boot possible.) Previously, Archiso used an old version of efitools signed by Microsoft, which is provided by Linux kernel maintainer James Bottomley [2]: it was formerly packaged as "prebootloader", but this package has been removed in favour of efitools [3]. Possible solutions ------------------ Using a signed PreLoader.efi built by Arch Linux ------------------------------------------------ It is possible to build UEFI binaries yourself and get them signed by Microsoft by submitting them to [4], see [5] for the requirements that need to be fulfilled. However, judging by [4], it seems that Microsoft focuses on the "shim" boot loader instead of efitools, therefore I don't know how likely it is for such a request to succeed. I therefore concentrated on switching from efitools to shim in the next two sections. Using a signed shimx64.efi built by a third party ------------------------------------------------- The efforts regarding Secure Boot on Linux now seem to concentrate around the shim boot loader [6], available in the AUR as shim-efi. It is developed by Red Hat and works as a drop-in replacement for efitools: the only difference are some name changes, i.e. "PreLoader.efi" is called "shimx64.efi", "HashTool.efi" is "mmx64.efi", and the second-stage boot loader needs to be called "grubx64.efi" instead of "loader.efi" (even if it is not GRUB, but systemd-boot in case of Archiso). This would allow to use Secure Boot by the following process, which is also documented in the corresponding section of the Wiki [7]: 1. Boot the Arch Linux ISO with Secure Boot enabled. 2. The signed shimx64.efi tries to load grubx64.efi, which is the systemd-boot boot loader. As systemd-boot is unsigned, this will fail, so shimx64.efi launches mmx64.efi instead. mmx64.efi gives you the opportunity to enroll the hashes of the boot loader (grubx64.efi) and kernel (vmlinuz.efi). This saves their hashes in the EFI variable "MokList", which allows them to be executed with Secure Boot enabled. 3. After a restart, shimx64.efi is now able to execute the thus approved boot loader and kernel without further user action. 4. When the boot loader or kernel are updated, the user needs to enroll the new binaries using the same process as in 2. There are two possibilities to obtain a pre-built signed shimx64.efi: there is a "generic" version built by former Red Hat employee Matthew Garrett [8], but it is very old and might not be suitable any more. As an alternative, we can use any newer Microsoft-signed shim built by a distribution like Fedora [9], which is what the AUR package shim-signed does. Advantages of this approach: + Most distributions supporting Secure Boot seem to use shim, so this might be more well-tried than the efitools approach. + It should be easy to verify the authenticity of the prebuilt binaries because the review process for shims signed by Microsoft is public [10] and includes information about the build configuration. Detaching the signature from the binary [11] makes it possible to verify that the unsigned binary is reproducible from source. Disadvantages: - We don't have control over the build of the unsigned binary and depend on another distribution for updates. - Other distributions include their own signing key in the shim binary. This allows them to sign their boot loader and kernel themselves, avoiding the need to enroll the hashes every time (see the next section). We cannot make use of this key ourselves, so we have a shim that includes a superfluous (but harmless) additional public key. Using a signed shimx64.efi built by Arch Linux ---------------------------------------------- It is possible to build shim yourself and get it signed by Microsoft. To do this, you need to submit it to Microsoft [4] and open an issue in [10] providing all the necessary information. If the request is approved, you receive back the signed files you can then distribute. The easiest approach is to only get shimx64.efi signed and let users enrol the hashes of the boot loader and kernel manually [7]. However, with our own shim, we can do much better: it is possible to embed the public key of a certificate into the shim binary [12]. This certificate can be used to sign the boot loader and kernel so that Secure Boot works completely automated out of the box, without having to enrol hashes. This process is documented in the Wiki as well [13] (except that you don't have to enroll "MOK.cer" manually, since it is already embedded in the shim binary). This approach would not only be beneficial to Archiso, it can also be used on installed systems for Secure Boot to work out of the box! To follow this approach, the following things need to be done: 1. Create a certificate conforming to the policy [5]. 2. Build shim [6], embedding the public part of the certificate generated in 1. [12] 3. Submit the binary "shimx64.efi" to Microsoft [4] and the shim-review repository [10]. 4. Once the signed binary is returned, verify that it matches the submitted build [11] and distribute it as a package. 5. In Archiso, replace "PreLoader.efi" and "HashTool.efi" by "shimx64.efi" and "mmx64.efi", rename "loader.efi" to "grubx64.efi". 6. (Optional) Sign the kernel "vmlinuz-linux" and all relevant boot loaders (systemd-boot, GRUB, REFInd) with sbsign from the sbsigntools package using the key generated in 1. This needs to be incorporated into the PKGBUILD of the respective packages. Advantages: + Full control over the distributed binaries. + Transparent for users, no manual enrollment is necessary. + Works for installed systems as well as Archiso. Disadvantages: - This is much more elaborate than using a pre-built signed binary, as we need to go through the shim review process ourselves. - Signing the kernel and boot loaders requires access to the private key of the certificate. Depending on how the certificate is stored, this might pose logistic problems for developers/TUs wanting to update one of the affected packages. Note however that this part is completely optional, users will still be able to enrol unsigned binaries using a hash [7]. Therefore this will also still allow users running a custom kernel or boot loader to use Secure Boot. Suggested action ---------------- If shipping binaries built by a third party is acceptable in this context, I would start with the approach described in "Using a signed shimx64.efi built by a third party". This requires the least effort to get Secure Boot working (just adopt shim-signed as an official package and follow "Using a signed shimx64.efi built by Arch Linux", step 4.), but will still require manual enrolment of the boot loader and kernel hashes by the user. If you want full control over the distributed binaries, I suggest the approach described in "Using a signed shimx64.efi built by Arch Linux", possibly in the following stages: 1. Adopt the AUR package shim-efi as an official package in order to build shim from source. 2. Move Archiso from efitools to shim as described in "Using a signed shimx64.efi built by Arch Linux", step 4. 3. Wait a couple of months to gain experience with the new preloader. 4. If all goes well, submit shim for signing as described in "Using a signed shimx64.efi built by Arch Linux", step 3. 5. Distribute the signed shim as a package and use it in Archiso. 6. When this is up and running, gauge interest for signing the boot loader and kernel with the key embedded in shim to remove the need to manually enrol the hashes on every boot loader/kernel update. If there is an interest in pursuing any of these approaches, I am happy to submit the necessary (but fairly trivial) patch to move Archiso from efitools to shim or to assist in the process of submitting the shim binary for review as far as I can. Unfortunately, the main workload will still rest on a developer/TU. If there are any questions, don't hesitate to ask! I have successfully tested the approach described in "Using a signed shimx64.efi built by a third party" on multiple machines with Secure Boot enabled and disabled and I am happy to share the necessary steps to locally build an Arch Linux ISO which works with Secure Boot enabled. Cheers, Jonas [1] https://git.kernel.org/pub/scm/linux/kernel/git/jejb/efitools.git [2] https://blog.hansenpartnership.com/linux-foundation-secure-boot-system-relea... [3] https://git.archlinux.org/svntogit/packages.git/commit/?h=packages/prebootloader&id=88bac02c2d44724a4684b06aa38e0add11161cd7 [4] https://docs.microsoft.com/en-us/windows-hardware/drivers/dashboard/lsa-and-... [5] https://blogs.msdn.microsoft.com/windows_hardware_certification/2013/12/03/m... [6] https://github.com/rhboot/shim [7] https://wiki.archlinux.org/index.php/Secure_Boot#shim_with_hash [8] https://mjg59.dreamwidth.org/20303.html [9] https://apps.fedoraproject.org/packages/shim/ [10] https://github.com/rhboot/shim-review [11] https://wiki.debian.org/SecureBoot#line-160 [12] https://github.com/rhboot/shim/blob/b3e4d1f7555aabbf5d54de5ea7cd7e839e7bd83d... [13] https://wiki.archlinux.org/index.php/Secure_Boot#shim_with_key
Using a signed shimx64.efi built by Arch Linux ---------------------------------------------- It is possible to build shim yourself and get it signed by Microsoft. [...] [I]t is possible to embed the public key of a certificate into the shim binary [...].> This certificate can be used to sign the boot loader and kernel so
completely automated out of the box, without having to enrol hashes. I think the best solution here is to use detached signatures and a separate package for the signed binaries, which builds the unsigned binary as usual, then attaches the signature (which can be distributed
On the bug tracker there was a question regarding the access to the secret key and the reproducibility of packages containing signed binaries. This concerns the second approach I suggested, i.e. that Secure Boot works publicly, unlike the secret key) and checks whether this results in a valid signed binary. Example ------- Consider the systemd-boot boot loader: the systemd package would stay unmodified and is used to build the unsigned EFI binary "systemd-bootx64.efi". To distribute a signed binary "systemd-bootx64.efi.signed", a person holding the secret key to the signing certificate would extract the binary and sign it by using a script along the following lines: tar -s '|.*/||' -xf systemd-*-x86_64.pkg.tar.xz \ usr/lib/systemd/boot/efi/systemd-bootx64.efi sbsign --cert pub.crt --key priv.key --detached systemd-bootx64.efi This creates a signature file "systemd-bootx64.efi.pk7", which isn't very useful on its own, but can be used to build a package "systemd-boot-signed" that contains a complete signed binary: The PKGBUILD of this new package is mostly the same as the existing systemd package, except for the following modifications: the public part of the signing certificate "pub.crt" and the signature "systemd-bootx64.efi.pk7" are added to the sources array (and to the public repository), and the build functions are adjusted as follows: build(){ # [...] usual build function here # sign the binary with the provided signature sbattach --attach "$srcdir/systemd-bootx64.efi.pk7" \ build/src/boot/efi/systemd-bootx64.efi } check() { # [...] usual check function here # verify that the signature is valid sbverify --cert pub.crt build/src/boot/efi/systemd-bootx64.efi } package() { # distribute only the signed binary install -Dm755 build/src/boot/efi/systemd-bootx64.efi \ "$pkgdir/usr/lib/boot/efi/systemd-bootx64.efi.signed" } Evaluation ---------- This has the following advantages: + Since the original package is not modified, users wanting to use the unsigned binaries (e.g. because they rebuild the package with local modifications) aren't affected at all. + Building the main and the signed package can be split between different developers/TUs, i.e. the maintainer of the original package does not necessarily need to have access to the signing key. + The amount of purely binary content (i.e. the signature) is kept to the absolutely necessary minimum. + It is possible for anybody to independently build and verify the signed package, check() will fail if the signature does not match the built binary. Disadvantage: - The PKGBUILD code is duplicated between the two packages. (Obviously, it would be easy to script the necessary changes to the signed package to minimise human error.) Alternatives ------------ Alternatives to this approach are: - Directly generating a signed binary by removing the "--detached" option from sbsign and distributing it as a binary package "systemd-boot-signed-bin". Avoids the PKGBUILD duplication, but makes it harder to verify that the signed binary is indeed the one built from source (but still doable by removing the signature with "sbattach --remove" and comparing the unsigned binaries). - Incorporating the assembly of the signature into the original PKGBUILD, e.g. by adding a makepkg option "--no-efi-sign" that skips all the signature stuff. You would then first build the unsigned binaries using this option, then you create the detached signature, add it to the sources and rerun with a normal "makepkg". This avoids the code duplication, but would probably require changes to makepkg because the currently available options don't seem to be a good match for this scenario.
participants (1)
-
Jonas Witschel