Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Sign systemd boot EFI images for secure booting. #53901

Closed
wants to merge 11 commits into from

Conversation

grahamc
Copy link
Member

@grahamc grahamc commented Jan 13, 2019

with efitools (nix-shell -p efitools)

and running with openssl in the shell environment:

$ cd /home/grahamc/projects/grahamc/secure-boot
$ uuidgen --random > GUID.txt
$ openssl req -newkey rsa:4096 -nodes -keyout PK.key -new -x509 -sha256 -days 3650 -subj "/CN=my Platform Key/" -out PK.crt
$ openssl x509 -outform DER -in PK.crt -out PK.cer
$ cert-to-efi-sig-list -g "$(< GUID.txt)" PK.crt PK.esl
$ sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt PK PK.esl PK.auth
$ sign-efi-sig-list -g "$(< GUID.txt)" -c PK.crt -k PK.key PK /dev/null rm_PK.auth

$ openssl req -newkey rsa:4096 -nodes -keyout KEK.key -new -x509 -sha256 -days 3650 -subj "/CN=my Key Exchange Key/" -out KEK.crt
$ openssl x509 -outform DER -in KEK.crt -out KEK.cer
$ cert-to-efi-sig-list -g "$(< GUID.txt)" KEK.crt KEK.esl
$ sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt KEK KEK.esl KEK.auth

$ openssl req -newkey rsa:4096 -nodes -keyout db.key -new -x509 -sha256 -days 3650 -subj "/CN=my Signature Database key/" -out db.crt
$ openssl x509 -outform DER -in db.crt -out db.cer
$ cert-to-efi-sig-list -g "$(< GUID.txt)" db.crt db.esl
$ sign-efi-sig-list -g "$(< GUID.txt)" -k KEK.key -c KEK.crt db db.esl db.auth

and then loading the .auth files in my UEFI firmware, then setting in
my configuration.nix:

boot = {
  loader = {
    systemd-boot = {
      enable = true;
      signed = true;
      signing-key = "/home/grahamc/projects/grahamc/secure-boot/db.key";
      signing-certificate = "/home/grahamc/projects/grahamc/secure-boot/db.crt";
    };
  };
};

and running nixos-rebuild boot I was able to secure-boot my laptop.

Note: this code signs EVERY boot entry for NixOS, and the BOOT files
from systemd (even if they're already tampered with! since this code
doesn't replace it.) AND does not allow a graceful key phase out. If
the key is replaced in gen2, gen1's boot EFI is deleted and replaced
with a new version.

Also note this only works on x86-64 due to the assumptions in the
builder.py.

Finally, you can have much fewer generations: each generation on my
laptop takes 20MB in /boot.

Info taken from:

@grahamc
Copy link
Member Author

grahamc commented Jan 13, 2019

This whole PR was made sort of on a lark, I didn't exactly plan to set out and do this ... but here we are =)

grahamc added a commit to grahamc/nixos-config that referenced this pull request Jan 14, 2019
Replace the systemd bootloader module with my custom one, which was
PR'd in NixOS/nixpkgs#53901.
grahamc added a commit to grahamc/nixos-config that referenced this pull request Jan 14, 2019
Replace the systemd bootloader module with my custom one, which was
PR'd in NixOS/nixpkgs#53901.
@grahamc
Copy link
Member Author

grahamc commented Jan 15, 2019

@GrahamcOfBorg test boot.uefiUsb

@ghost
Copy link

ghost commented Jan 22, 2019

Very cool concept.

PS: in the nix script you put in the description, is this line correct?

sed -i -e 's#DESTDIR#out#g' Make.rules

instead of:

sed -i -e 's#DESTDIR#$out#g' Make.rules

@grahamc
Copy link
Member Author

grahamc commented Jan 22, 2019

That line was actually correct, but resulted in the output in $out/usr/... I've now fixed that, and PR'd efitools separately: #54471

with efitools (`nix-shell -p efitools`)

and running with openssl in the shell environment:

    $ cd /home/grahamc/projects/grahamc/secure-boot
    $ uuidgen --random > GUID.txt
    $ openssl req -newkey rsa:4096 -nodes -keyout PK.key -new -x509 -sha256 -days 3650 -subj "/CN=my Platform Key/" -out PK.crt
    $ openssl x509 -outform DER -in PK.crt -out PK.cer
    $ cert-to-efi-sig-list -g "$(< GUID.txt)" PK.crt PK.esl
    $ sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt PK PK.esl PK.auth
    $ sign-efi-sig-list -g "$(< GUID.txt)" -c PK.crt -k PK.key PK /dev/null rm_PK.auth

    $ openssl req -newkey rsa:4096 -nodes -keyout KEK.key -new -x509 -sha256 -days 3650 -subj "/CN=my Key Exchange Key/" -out KEK.crt
    $ openssl x509 -outform DER -in KEK.crt -out KEK.cer
    $ cert-to-efi-sig-list -g "$(< GUID.txt)" KEK.crt KEK.esl
    $ sign-efi-sig-list -g "$(< GUID.txt)" -k PK.key -c PK.crt KEK KEK.esl KEK.auth

    $ openssl req -newkey rsa:4096 -nodes -keyout db.key -new -x509 -sha256 -days 3650 -subj "/CN=my Signature Database key/" -out db.crt
    $ openssl x509 -outform DER -in db.crt -out db.cer
    $ cert-to-efi-sig-list -g "$(< GUID.txt)" db.crt db.esl
    $ sign-efi-sig-list -g "$(< GUID.txt)" -k KEK.key -c KEK.crt db db.esl db.auth

and then loading the .auth files in my UEFI firmware, then setting in
my configuration.nix:

    boot = {
      loader = {
        systemd-boot = {
          enable = true;
          signed = true;
          signing-key = "/home/grahamc/projects/grahamc/secure-boot/db.key";
          signing-certificate = "/home/grahamc/projects/grahamc/secure-boot/db.crt";
        };
      };
    };

and running `nixos-rebuild boot` I was able to secure-boot my laptop.

Note: this code signs EVERY boot entry for NixOS, and the BOOT files
from systemd (even if they're already tampered with! since this code
doesn't replace it.) AND does not allow a graceful key phase out. If
the key is replaced in gen2, gen1's boot EFI is deleted and replaced
with a new version.

Also note this only works on x86-64 due to the assumptions in the
builder.py.

Finally, you can have much fewer generations: each generation on my
laptop takes 20MB in /boot.

Info taken from:

 - https://wiki.archlinux.org/index.php/Secure_Boot#Using_your_own_keys
 - https://systemd.io/BOOT_LOADER_SPECIFICATION#type-2-efi-unified-kernel-images
 - https://www.freedesktop.org/software/systemd/man/os-release.html
@Mic92
Copy link
Member

Mic92 commented Jan 22, 2019

If you merge this feature could you drop your notes for setting up in the manual or the wiki?

Only copy if we need to append initrd secrets, and even then
don't copy to the EFI partition.
@grahamc
Copy link
Member Author

grahamc commented Jan 23, 2019

Note the whitespace-free diff is a bit easier to see the smaller changes: 68f7139?w=1

Yes definitely: docs is a blocker for this PR. But, so is having a few people try it out for a while.

@grahamc
Copy link
Member Author

grahamc commented Jan 23, 2019

PS extending this Python code has not been a lot of fun :(

@Mic92
Copy link
Member

Mic92 commented Jan 23, 2019

It gets more fun, once it has type annotations and one has type checks running in its editor because the feedback cycle gets shorter.

@jsimonetti
Copy link
Contributor

I can add the code from this PR still works fine on 20.09 when used as a module.

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/nixos-on-secure-boot-debian-based-laptop/10976/2

@hmenke
Copy link
Member

hmenke commented Jan 16, 2021

@danielfullmer Do you feel like taking this forward? It seems that @grahamc doesn't have time to push this anymore. I'm actually using this code for almost a year already and it would be really great if it made into 21.05.

@06kellyjac
Copy link
Member

As an observer, what extra work is required to make this ready? (Excluding resolving merge conflicts)

@GrahamcOfBorg
Copy link

GrahamcOfBorg commented Jan 16, 2021 via email

@danielfullmer
Copy link
Contributor

@hmenke I unfortunately can't commit to having time to finish up this PR. I should be available to answer any questions about the tests if anyone else would like to finish this up. I'd also like to add that we'd also need some documentation for this feature.

However, I do have a slightly more recent version of the secure boot tests at: https://github.com/danielfullmer/nixpkgs/tree/secure-boot-wip2
The biggest change is that the logic for adding secure boot certs was moved into qemu-vm.nix. IIRC, nixos-rebuild build-vm-with-bootloader should now also be able to pre-enroll the certificate specified under boot.loader.systemd-boot.signing-certificate, so you could interactively test secure boot functionality.

I might not be the best to finish up this PR since I personally wasn't planning to use this feature on my machine until we also had working kernel module signing (#87426) and had chained integrity checking to the actual generation NixOS boots via dm-verity / fs-verity / IMA, or something similar, for which I don't have any great ideas.

@vikanezrimaya
Copy link
Member

WOW! I kinda wanted to have this and now it exists.

I don't think the security would suffer too much from the fact that files are re-signed on every nixos-rebuild boot, if the files are re-installed from the /nix/store every time. Then, if the system booted successfully with Secure Boot from the beginning, and the /nix/store wasn't tampered with, I don't think there's a chance someone untrusted could swap the bootloader. Quite the contrary, every rebuild will ensure the system is in bootable state and all the files are trusted.

@cwyc
Copy link
Contributor

cwyc commented Jun 10, 2021

Thanks a lot for this module.
I've managed to update it to nixos 21.05:
https://github.com/cwyc/nixpkgs/tree/secure-boot-rebased-21.05/nixos/modules/system/boot/loader/systemd-boot
And I've adapted it as an importable module, with the options renamed to boot.loader.systemd-boot-secure:
https://gist.github.com/cwyc/9de83566c92bdabd000256ed49312a53

@bbigras
Copy link
Contributor

bbigras commented Jun 10, 2021

@cwyc Are you going to open a PR? 🙏

@cwyc
Copy link
Contributor

cwyc commented Jun 10, 2021

I've also tried out @danielfullmer 's tests. They work on my end, what is it that has to be changed?

@bbigras
Copy link
Contributor

bbigras commented Jun 19, 2021

Maybe open a new PR and ask for reviews again.

@mweinelt
Copy link
Member

mweinelt commented Jul 15, 2021

Please, please, if someone has the time and knowledge to take this over the finish line, please do. We will apparently not get very many testers without this having landed in nixpkgs, and the value of having this built-in and easily set up is so huge.

@benpye
Copy link
Contributor

benpye commented Jul 17, 2021

@mweinelt I'm definitely interested in seeing this land - what's still missing from the changes that @cwyc posted above? Whilst as mentioned earlier without having chained verification of kernel modules etc we don't get full trust, this is definitely a significant stepping stone to get there.

@TLATER
Copy link
Contributor

TLATER commented Jul 17, 2021

@benpye I think a start would be addressing the review comments - there are plenty right there, some really low hanging fruit!

@Baughn
Copy link
Contributor

Baughn commented Jul 25, 2021

Please, please, if someone has the time and knowledge to take this over the finish line, please do. We will apparently not get very many testers without this having landed in nixpkgs, and the value of having this built-in and easily set up is so huge.

It's something that really ought to be merged and functional by the time of the next release, because a lot of people are about to lose the option of running their systems with secure boot disabled.

Given Windows 11 has it as a requirement, any operating system which doesn't support it at all can't boot. Not without reconfiguring your BIOS at every reboot, at any rate, which I don't think many people are going to do. Personally I've been running an indev version of 11, and...

Well, it's a good upgrade. With the exception of the usual development snapshot bugs, most everything works better than on 10.

I don't expect anyone who's already using NixOS to be stopped by this, so it might not seem that important, but losing the ability to dual-boot will make it far harder to make new converts.

@grahamc
Copy link
Member Author

grahamc commented Jul 25, 2021

lose the option of running their systems with secure boot disabled.

not without reconfiguring your BIOS at every reboot

This sounds like FUD to me. I don't see why Windows11 making it a requirement makes the hardware or firmware behave differently than it has for years. I'd be interested in primary sources if you can provide some.

I have a different approach to this PR in progress, but I don't think this particular implementation is good or worth merging: the lifecycle around signing is unfit for purpose. To that end, I'm closing this because I would be -1 on an implementation similar to this merging.

@grahamc grahamc closed this Jul 25, 2021
@cwyc
Copy link
Contributor

cwyc commented Jul 25, 2021

@Baughn
Looks like it's only an issue if you want to dual-boot with Windows 11. But if you are dual-booting, surely you can't replace Microsoft's keys with the self-signing keys used here, a secure boot solution would have to use shim/preloader?

@matshch
Copy link
Contributor

matshch commented Jul 25, 2021

surely you can't replace Microsoft's keys with the self-signing keys used here

You can import several signing keys in UEFI. This way, I have my own Platform Key, two Key Exchange Keys (my own and Microsoft's, so Windows can autoupdate dbx), two keys in db (again, my own and Microsoft's), and dbx is full of Microsoft's revoked signs. This way, I have Secure dual-boot with Windows 10 and Ubuntu (autosigned by https://github.com/julian-klode/sicherboot).

Installing NixOS requires disabling Secure Boot, which will somewhat lower my security, and this is one of the few reasons that stops me from daily driving NixOS.

@zeratax
Copy link
Contributor

zeratax commented Jul 25, 2021

Given Windows 11 has it as a requirement

that only seems to be true for installation. I installed win 11 then turned off secure boot and am now back to dual booting win 11 and nixos

@TLATER
Copy link
Contributor

TLATER commented Jul 25, 2021

@grahamc do please link your solution here once it's in a state worth looking at so we get a notification :)

@eadwu
Copy link
Member

eadwu commented Jul 25, 2021

I don't know if Windows 11 has it as a requirement but I have been using it since release to Dev and the like past 3 updates and have not gotten anything needing Secure Boot to be re-enabled (whether during upgrade process or daily driving).

@Baughn
Copy link
Contributor

Baughn commented Jul 25, 2021

The source would be https://blogs.windows.com/windows-insider/2021/06/28/update-on-windows-11-minimum-system-requirements/

It's true that at the moment you can disable secure boot after installation, and it'll keep running, but I don't think it's especially safe to assume that will still be the case with the final release. I've never seen any statement from MS saying it will be, and I don't think it'd be safe to assume even if I had.

@grahamc
Copy link
Member Author

grahamc commented Jul 26, 2021

Okay. Good to confirm there is no imminent risk here.

@frogamic
Copy link
Contributor

frogamic commented Aug 8, 2021

I have been meaning to implement an alternative to this myself for a while but I finally got round to it. This completely replaces the configuration file approach with unified kernel images.

https://github.com/frogamic/nix-machines/tree/main/modules/systemd-secure-boot

Some caveats:

  • signing is not optional in this script, though sign_if_not_signed could easily be replaced with different behavior if signing is not enabled, sticking with unified images by default for systemd-boot
  • doesn't sign memtest
  • doesn't sign fwupd bootloader as used for platform firmware updates
  • Leaves behind all the old initrd/bzimage files in EFI/Nixos, should the eventual script nuke these every time on the off-chance they exist?

Some thoughts I had while doing it:

  • Could the unified image be built as a nix derivation instead? Probably in the extraSystemBuildCmds since not all boot methods need it?
    • What happens in that case if a generation doesn't have the unified image? is it just skipped?
  • Should secureboot be a configuration option on the same level as systemd-boot rather than inside it so all boot methods could share it as an option, and any other efi binaries (eg fwupdx64.efi) would use it too?
    • can you even sign your own grub efi like you can with systemd-boot? I never looked into it at all

@pnmadelaine
Copy link
Member

pnmadelaine commented Sep 29, 2021

I've used @frogamic approach on my laptop and I'd really like to see this in NixOS.
Is anyone working on a new PR at the moment?
If not, I'd be happy to work on the caveats mentioned by frogamic and open one.

A few comments I have:

  • I'd say defaulting to unified images is not a great idea, since it takes a lot more space
  • maybe splitting this in two options would be better, the secure boot option requiring to enable the unified images option?
  • a nice to have would be an option to build efitools' LockDown.efi with the user's certificates and add it to the boot menu

@grahamc
Copy link
Member Author

grahamc commented Sep 29, 2021

Is anyone working on a new PR at the moment?

Yes, my company determinate.systems has been investing considerable time and money in to a suitable implementation over the past two months. We're about ready to publish some WIP code. Typically we do all our work in public, however I wanted to have lots of room to experiment and try different approaches. We're also in the process of applying for funding to implement a few workflows.

@K900
Copy link
Contributor

K900 commented Oct 7, 2021

Any updates on this?

@TLATER
Copy link
Contributor

TLATER commented Oct 8, 2021

@K900 the conversation basically continues in #42127 now, but nothing yet today. I'd guess it will take a little while.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet