Loading nixos/modules/module-list.nix +1 −0 Original line number Diff line number Diff line Loading @@ -1441,6 +1441,7 @@ ./system/boot/stratisroot.nix ./system/boot/modprobe.nix ./system/boot/networkd.nix ./system/boot/unl0kr.nix ./system/boot/plymouth.nix ./system/boot/resolved.nix ./system/boot/shutdown.nix Loading nixos/modules/system/boot/unl0kr.nix 0 → 100644 +89 −0 Original line number Diff line number Diff line { config, lib, pkgs, ... }: let cfg = config.boot.initrd.unl0kr; in { options.boot.initrd.unl0kr = { enable = lib.mkEnableOption (lib.mdDoc "unl0kr in initrd") // { description = lib.mdDoc '' Whether to enable the unl0kr on-screen keyboard in initrd to unlock LUKS. ''; }; }; config = lib.mkIf cfg.enable { meta.maintainers = with lib.maintainers; [ tomfitzhenry ]; assertions = [ { assertion = cfg.enable -> config.boot.initrd.systemd.enable; message = "boot.initrd.unl0kr is only supported with boot.initrd.systemd."; } ]; boot.initrd.systemd = { storePaths = with pkgs; [ "${pkgs.gnugrep}/bin/grep" libinput xkeyboard_config "${config.boot.initrd.systemd.package}/lib/systemd/systemd-reply-password" "${pkgs.unl0kr}/bin/unl0kr" ]; services = { unl0kr-ask-password = { description = "Forward Password Requests to unl0kr"; conflicts = [ "emergency.service" "initrd-switch-root.target" "shutdown.target" ]; unitConfig.DefaultDependencies = false; after = [ "systemd-vconsole-setup.service" "udev.service" ]; before = [ "shutdown.target" ]; script = '' # This script acts as a Password Agent: https://systemd.io/PASSWORD_AGENTS/ DIR=/run/systemd/ask-password/ # If a user has multiple encrypted disks, the requests might come in different times, # so make sure to answer as many requests as we can. Once boot succeeds, other # password agents will be responsible for watching for requests. while [ -d $DIR ] && [ "$(ls -A $DIR/ask.*)" ]; do for file in `ls $DIR/ask.*`; do socket="$(cat "$file" | ${pkgs.gnugrep}/bin/grep "Socket=" | cut -d= -f2)" ${pkgs.unl0kr}/bin/unl0kr | ${config.boot.initrd.systemd.package}/lib/systemd/systemd-reply-password 1 "$socket" done done ''; }; }; paths = { unl0kr-ask-password = { description = "Forward Password Requests to unl0kr"; conflicts = [ "emergency.service" "initrd-switch-root.target" "shutdown.target" ]; unitConfig.DefaultDependencies = false; before = [ "shutdown.target" "paths.target" "cryptsetup.target" ]; wantedBy = [ "sysinit.target" ]; pathConfig = { DirectoryNotEmpty = "/run/systemd/ask-password"; MakeDirectory = true; }; }; }; }; }; } nixos/tests/all-tests.nix +1 −0 Original line number Diff line number Diff line Loading @@ -813,6 +813,7 @@ in { systemd-initrd-luks-empty-passphrase = handleTest ./initrd-luks-empty-passphrase.nix { systemdStage1 = true; }; systemd-initrd-luks-password = handleTest ./systemd-initrd-luks-password.nix {}; systemd-initrd-luks-tpm2 = handleTest ./systemd-initrd-luks-tpm2.nix {}; systemd-initrd-luks-unl0kr = handleTest ./systemd-initrd-luks-unl0kr.nix {}; systemd-initrd-modprobe = handleTest ./systemd-initrd-modprobe.nix {}; systemd-initrd-shutdown = handleTest ./systemd-shutdown.nix { systemdStage1 = true; }; systemd-initrd-simple = handleTest ./systemd-initrd-simple.nix {}; Loading nixos/tests/systemd-initrd-luks-unl0kr.nix 0 → 100644 +75 −0 Original line number Diff line number Diff line import ./make-test-python.nix ({ lib, pkgs, ... }: let passphrase = "secret"; in { name = "systemd-initrd-luks-unl0kr"; meta = with pkgs.lib.maintainers; { maintainers = [ tomfitzhenry ]; }; enableOCR = true; nodes.machine = { pkgs, ... }: { virtualisation = { emptyDiskImages = [ 512 512 ]; useBootLoader = true; mountHostNixStore = true; useEFIBoot = true; qemu.options = [ "-vga virtio" ]; }; boot.loader.systemd-boot.enable = true; boot.initrd.availableKernelModules = [ "evdev" # for entering pw "bochs" ]; environment.systemPackages = with pkgs; [ cryptsetup ]; boot.initrd = { systemd = { enable = true; emergencyAccess = true; }; unl0kr.enable = true; }; specialisation.boot-luks.configuration = { boot.initrd.luks.devices = lib.mkVMOverride { # We have two disks and only type one password - key reuse is in place cryptroot.device = "/dev/vdb"; cryptroot2.device = "/dev/vdc"; }; virtualisation.rootDevice = "/dev/mapper/cryptroot"; virtualisation.fileSystems."/".autoFormat = true; # test mounting device unlocked in initrd after switching root virtualisation.fileSystems."/cryptroot2".device = "/dev/mapper/cryptroot2"; }; }; testScript = '' # Create encrypted volume machine.wait_for_unit("multi-user.target") machine.succeed("echo -n ${passphrase} | cryptsetup luksFormat -q --iter-time=1 /dev/vdb -") machine.succeed("echo -n ${passphrase} | cryptsetup luksFormat -q --iter-time=1 /dev/vdc -") machine.succeed("echo -n ${passphrase} | cryptsetup luksOpen -q /dev/vdc cryptroot2") machine.succeed("mkfs.ext4 /dev/mapper/cryptroot2") # Boot from the encrypted disk machine.succeed("bootctl set-default nixos-generation-1-specialisation-boot-luks.conf") machine.succeed("sync") machine.crash() # Boot and decrypt the disk machine.start() machine.wait_for_text("Password required for booting") machine.screenshot("prompt") machine.send_chars("${passphrase}") machine.screenshot("pw") machine.send_chars("\n") machine.wait_for_unit("multi-user.target") assert "/dev/mapper/cryptroot on / type ext4" in machine.succeed("mount"), "/dev/mapper/cryptroot do not appear in mountpoints list" assert "/dev/mapper/cryptroot2 on /cryptroot2 type ext4" in machine.succeed("mount") ''; }) pkgs/by-name/un/unl0kr/package.nix 0 → 100644 +57 −0 Original line number Diff line number Diff line { lib , nixosTests , stdenv , fetchFromGitLab , inih , libdrm , libinput , libxkbcommon , meson , ninja , pkg-config , scdoc }: stdenv.mkDerivation (finalAttrs: { pname = "unl0kr"; version = "2.0.0"; src = fetchFromGitLab { domain = "gitlab.com"; owner = "cherrypicker"; repo = "unl0kr"; rev = finalAttrs.version; fetchSubmodules = true; hash = "sha256-KPP4Ol1GCAWqdQYlNtKQD/jx8A/xuHdvKjcocPMqWa0="; }; nativeBuildInputs = [ meson ninja pkg-config scdoc ]; buildInputs = [ inih libdrm libinput libxkbcommon ]; propagatedBuildInputs = [ libxkbcommon ]; passthru = { tests.unl0kr = nixosTests.systemd-initrd-luks-unl0kr; }; meta = with lib; { description = "Framebuffer-based disk unlocker for the initramfs based on LVGL"; homepage = "https://gitlab.com/cherrypicker/unl0kr"; license = licenses.gpl3Plus; maintainers = with maintainers; [ tomfitzhenry ]; platforms = platforms.linux; }; }) Loading
nixos/modules/module-list.nix +1 −0 Original line number Diff line number Diff line Loading @@ -1441,6 +1441,7 @@ ./system/boot/stratisroot.nix ./system/boot/modprobe.nix ./system/boot/networkd.nix ./system/boot/unl0kr.nix ./system/boot/plymouth.nix ./system/boot/resolved.nix ./system/boot/shutdown.nix Loading
nixos/modules/system/boot/unl0kr.nix 0 → 100644 +89 −0 Original line number Diff line number Diff line { config, lib, pkgs, ... }: let cfg = config.boot.initrd.unl0kr; in { options.boot.initrd.unl0kr = { enable = lib.mkEnableOption (lib.mdDoc "unl0kr in initrd") // { description = lib.mdDoc '' Whether to enable the unl0kr on-screen keyboard in initrd to unlock LUKS. ''; }; }; config = lib.mkIf cfg.enable { meta.maintainers = with lib.maintainers; [ tomfitzhenry ]; assertions = [ { assertion = cfg.enable -> config.boot.initrd.systemd.enable; message = "boot.initrd.unl0kr is only supported with boot.initrd.systemd."; } ]; boot.initrd.systemd = { storePaths = with pkgs; [ "${pkgs.gnugrep}/bin/grep" libinput xkeyboard_config "${config.boot.initrd.systemd.package}/lib/systemd/systemd-reply-password" "${pkgs.unl0kr}/bin/unl0kr" ]; services = { unl0kr-ask-password = { description = "Forward Password Requests to unl0kr"; conflicts = [ "emergency.service" "initrd-switch-root.target" "shutdown.target" ]; unitConfig.DefaultDependencies = false; after = [ "systemd-vconsole-setup.service" "udev.service" ]; before = [ "shutdown.target" ]; script = '' # This script acts as a Password Agent: https://systemd.io/PASSWORD_AGENTS/ DIR=/run/systemd/ask-password/ # If a user has multiple encrypted disks, the requests might come in different times, # so make sure to answer as many requests as we can. Once boot succeeds, other # password agents will be responsible for watching for requests. while [ -d $DIR ] && [ "$(ls -A $DIR/ask.*)" ]; do for file in `ls $DIR/ask.*`; do socket="$(cat "$file" | ${pkgs.gnugrep}/bin/grep "Socket=" | cut -d= -f2)" ${pkgs.unl0kr}/bin/unl0kr | ${config.boot.initrd.systemd.package}/lib/systemd/systemd-reply-password 1 "$socket" done done ''; }; }; paths = { unl0kr-ask-password = { description = "Forward Password Requests to unl0kr"; conflicts = [ "emergency.service" "initrd-switch-root.target" "shutdown.target" ]; unitConfig.DefaultDependencies = false; before = [ "shutdown.target" "paths.target" "cryptsetup.target" ]; wantedBy = [ "sysinit.target" ]; pathConfig = { DirectoryNotEmpty = "/run/systemd/ask-password"; MakeDirectory = true; }; }; }; }; }; }
nixos/tests/all-tests.nix +1 −0 Original line number Diff line number Diff line Loading @@ -813,6 +813,7 @@ in { systemd-initrd-luks-empty-passphrase = handleTest ./initrd-luks-empty-passphrase.nix { systemdStage1 = true; }; systemd-initrd-luks-password = handleTest ./systemd-initrd-luks-password.nix {}; systemd-initrd-luks-tpm2 = handleTest ./systemd-initrd-luks-tpm2.nix {}; systemd-initrd-luks-unl0kr = handleTest ./systemd-initrd-luks-unl0kr.nix {}; systemd-initrd-modprobe = handleTest ./systemd-initrd-modprobe.nix {}; systemd-initrd-shutdown = handleTest ./systemd-shutdown.nix { systemdStage1 = true; }; systemd-initrd-simple = handleTest ./systemd-initrd-simple.nix {}; Loading
nixos/tests/systemd-initrd-luks-unl0kr.nix 0 → 100644 +75 −0 Original line number Diff line number Diff line import ./make-test-python.nix ({ lib, pkgs, ... }: let passphrase = "secret"; in { name = "systemd-initrd-luks-unl0kr"; meta = with pkgs.lib.maintainers; { maintainers = [ tomfitzhenry ]; }; enableOCR = true; nodes.machine = { pkgs, ... }: { virtualisation = { emptyDiskImages = [ 512 512 ]; useBootLoader = true; mountHostNixStore = true; useEFIBoot = true; qemu.options = [ "-vga virtio" ]; }; boot.loader.systemd-boot.enable = true; boot.initrd.availableKernelModules = [ "evdev" # for entering pw "bochs" ]; environment.systemPackages = with pkgs; [ cryptsetup ]; boot.initrd = { systemd = { enable = true; emergencyAccess = true; }; unl0kr.enable = true; }; specialisation.boot-luks.configuration = { boot.initrd.luks.devices = lib.mkVMOverride { # We have two disks and only type one password - key reuse is in place cryptroot.device = "/dev/vdb"; cryptroot2.device = "/dev/vdc"; }; virtualisation.rootDevice = "/dev/mapper/cryptroot"; virtualisation.fileSystems."/".autoFormat = true; # test mounting device unlocked in initrd after switching root virtualisation.fileSystems."/cryptroot2".device = "/dev/mapper/cryptroot2"; }; }; testScript = '' # Create encrypted volume machine.wait_for_unit("multi-user.target") machine.succeed("echo -n ${passphrase} | cryptsetup luksFormat -q --iter-time=1 /dev/vdb -") machine.succeed("echo -n ${passphrase} | cryptsetup luksFormat -q --iter-time=1 /dev/vdc -") machine.succeed("echo -n ${passphrase} | cryptsetup luksOpen -q /dev/vdc cryptroot2") machine.succeed("mkfs.ext4 /dev/mapper/cryptroot2") # Boot from the encrypted disk machine.succeed("bootctl set-default nixos-generation-1-specialisation-boot-luks.conf") machine.succeed("sync") machine.crash() # Boot and decrypt the disk machine.start() machine.wait_for_text("Password required for booting") machine.screenshot("prompt") machine.send_chars("${passphrase}") machine.screenshot("pw") machine.send_chars("\n") machine.wait_for_unit("multi-user.target") assert "/dev/mapper/cryptroot on / type ext4" in machine.succeed("mount"), "/dev/mapper/cryptroot do not appear in mountpoints list" assert "/dev/mapper/cryptroot2 on /cryptroot2 type ext4" in machine.succeed("mount") ''; })
pkgs/by-name/un/unl0kr/package.nix 0 → 100644 +57 −0 Original line number Diff line number Diff line { lib , nixosTests , stdenv , fetchFromGitLab , inih , libdrm , libinput , libxkbcommon , meson , ninja , pkg-config , scdoc }: stdenv.mkDerivation (finalAttrs: { pname = "unl0kr"; version = "2.0.0"; src = fetchFromGitLab { domain = "gitlab.com"; owner = "cherrypicker"; repo = "unl0kr"; rev = finalAttrs.version; fetchSubmodules = true; hash = "sha256-KPP4Ol1GCAWqdQYlNtKQD/jx8A/xuHdvKjcocPMqWa0="; }; nativeBuildInputs = [ meson ninja pkg-config scdoc ]; buildInputs = [ inih libdrm libinput libxkbcommon ]; propagatedBuildInputs = [ libxkbcommon ]; passthru = { tests.unl0kr = nixosTests.systemd-initrd-luks-unl0kr; }; meta = with lib; { description = "Framebuffer-based disk unlocker for the initramfs based on LVGL"; homepage = "https://gitlab.com/cherrypicker/unl0kr"; license = licenses.gpl3Plus; maintainers = with maintainers; [ tomfitzhenry ]; platforms = platforms.linux; }; })