diff options
| author | Alejandro Soto <alejandro@34project.org> | 2025-07-24 01:33:49 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2025-07-25 20:32:52 -0600 |
| commit | 81020f92b9312679bbec34272839db4494f369b6 (patch) | |
| tree | c780925a3c9b68ab2efe7711092e19da7c918ff4 | |
| parent | 2ad37812978e83578ce6c7cf5fcd3e7d783b99a4 (diff) | |
sys/boot: implement TPM2 crypt device unlock
| -rw-r--r-- | sys/boot/detached-luks.nix | 78 | ||||
| -rw-r--r-- | sys/boot/tpm.nix | 69 |
2 files changed, 125 insertions, 22 deletions
diff --git a/sys/boot/detached-luks.nix b/sys/boot/detached-luks.nix index a7b1bc9..1e7cc2b 100644 --- a/sys/boot/detached-luks.nix +++ b/sys/boot/detached-luks.nix @@ -1,6 +1,11 @@ { config, lib, pkgs, ... }: with lib; let cfg = config.local.boot.detachedLuks; + + bootFs = config.fileSystems."/boot"; + tpmInitrd = config.local.boot.tpm.initrd.enable; + + pcrList = concatStringsSep "," (map toString config.local.boot.tpm.initrd.pcrs); in { options.local.boot.detachedLuks = { @@ -10,6 +15,11 @@ in type = types.str; }; + tpmStorageFromBoot = mkOption { + type = types.str; + default = "tpm-boot"; + }; + crypt = mkOption { type = types.str; }; @@ -23,16 +33,16 @@ in boot.initrd = let headerPath = "/initrd-boot/${cfg.headerFromBoot}"; + headerPathEscaped = escapeShellArg headerPath; + + tpmPath = escapeShellArg "/initrd-boot/${cfg.tpmStorageFromBoot}"; + hardwareKeyPath = "/tpm/unsealed.luks-key"; in { - preDeviceCommands = - let - headerPathEscaped = escapeShellArg headerPath; - in - '' - mkdir -p `dirname ${headerPathEscaped}` - touch ${headerPathEscaped} - ''; + preDeviceCommands = '' + mkdir -p `dirname ${headerPathEscaped}` + touch ${headerPathEscaped} + ''; postDeviceCommands = mkIf (!config.boot.initrd.systemd.enable) '' # Set the system time from the hardware clock to work around a @@ -51,23 +61,51 @@ in header = headerPath; preLVM = false; - preOpenCommands = - let - boot = config.fileSystems."/boot"; - in - '' - mount -o ro -t ${boot.fsType} ${boot.device} /initrd-boot - ''; + keyFile = mkIf tpmInitrd hardwareKeyPath; + fallbackToPassword = tpmInitrd; - postOpenCommands = mkBefore '' - umount /initrd-boot + preOpenCommands = '' + mount -o ro -t ${bootFs.fsType} ${bootFs.device} /initrd-boot + '' + optionalString tpmInitrd '' + mkdir /tpm + + tpm2 createprimary -Q -C owner -g sha256 -G ecc -c /tpm/prim.ctx + + tpm2 loadexternal -Q -C owner -G rsa -u ${tpmPath}/signing-key.pub -c /tpm/signing-key.ctx -n /tpm/signing-key.name + tpm2 verifysignature -Q -c /tpm/signing-key.ctx -g sha256 -m ${tpmPath}/auth.policy -s ${tpmPath}/auth.sig -t /tpm/verified.ticket -f rsassa + + tpm2 startauthsession -Q -S /tpm/session.ctx --policy-session + + tpm_resets=`tpm2 readclock | grep reset_count | sed 's/.*: //g'` + tpm2 policycountertimer -Q -S /tpm/session.ctx resets="$tpm_resets" + tpm2 policypcr -Q -S /tpm/session.ctx -l sha256:${pcrList} + tpm2 policyauthorize -Q -S /tpm/session.ctx -i ${tpmPath}/auth.policy -n /tpm/signing-key.name -t /tpm/verified.ticket + + tpm2 load -Q -C /tpm/prim.ctx -u ${tpmPath}/key.pub -r ${tpmPath}/key.priv -c /tpm/key.ctx + tpm2 unseal -Q -c /tpm/key.ctx -p session:/tpm/session.ctx -o /tpm/unsealed.luks-key + + echo "Unsealed!" + cat /tpm/unsealed.luks-key + echo "Unsealed! END" + + tpm2 flushcontext /tpm/session.ctx ''; + + postOpenCommands = mkBefore ('' + umount /initrd-boot + '' + optionalString tpmInitrd '' + rm -r /tpm + ''); }; }; - local.boot.stack = { - btrfsToplevelMultidrive.toplevel.device = "/dev/mapper/${cfg.target}"; - luksExt4FscryptImpermanence = { inherit (cfg) target; }; + local.boot = { + stack = { + btrfsToplevelMultidrive.toplevel.device = "/dev/mapper/${cfg.target}"; + luksExt4FscryptImpermanence = { inherit (cfg) target; }; + }; + + tpm.initrd.enable = mkDefault config.local.boot.tpm.enable; }; }; } diff --git a/sys/boot/tpm.nix b/sys/boot/tpm.nix index 4932b7c..1e446ab 100644 --- a/sys/boot/tpm.nix +++ b/sys/boot/tpm.nix @@ -1,10 +1,57 @@ { config, lib, pkgs, ... }: with lib; let cfg = config.local.boot.tpm; + + pcrList = concatStringsSep "," (map toString cfg.initrd.pcrs); + + # Crear signing-key con: + # $ openssl genrsa -out ~/vtmp/signing-key.priv 2048 + # $ openssl rsa -in ~/vtmp/signing-key.priv -out ~/vtmp/signing-key.pub -pubout + # Y copiar signing-key.pub a /boot/tpm-boot. Guardar signing-key.priv en lugar seguro. + # + # Crear llave con: + # $ tpm2_loadexternal -G rsa -C owner -u signing-key.pub -c signing-key.ctx -n signing-key.name + # $ tpm2_startauthsession -S session.ctx + # $ tpm2_policyauthorize -S session.ctx -L require-signed.policy -n signing-key.name + # $ tpm2_flushcontext session.ctx + # $ tpm2_createprimary -C owner -g sha256 -G ecc -c prim.ctx + # $ head -c128 /dev/urandom | tpm2_create -C prim.ctx -u key.pub -r key.priv -c key.ctx -L require-signed.policy -i- + # Y mover key.priv/key.pub a /boot/tpm-boot + # + # Usage: tpm2-grant-next-boot < signing-key.priv + # Genera auth.policy y auth.sig + tpm2-grant-next-boot = pkgs.writeShellApplication { + name = "tpm2-grant-next-boot"; + runtimeInputs = [ pkgs.openssl pkgs.tpm2-tools ]; + + text = '' + ctx_dir="$(mktemp -d)" + trap 'rm -rf -- "$ctx_dir"' EXIT + + tpm2_createprimary -Q -C owner -g sha256 -G ecc -c "$ctx_dir/prim.ctx" + + tpm2_startauthsession -Q -S "$ctx_dir/session.ctx" + tpm_resets=$(tpm2_readclock | grep reset_count | sed 's/.*: //') + tpm2_policycountertimer -Q -S "$ctx_dir/session.ctx" resets="$((tpm_resets+1))" + tpm2_policypcr -Q -S "$ctx_dir/session.ctx" -L auth.policy -l sha256:${pcrList} + tpm2_flushcontext -Q "$ctx_dir/session.ctx" + + openssl dgst -sha256 -sign /dev/stdin -out auth.sig auth.policy + ''; + }; in { options.local.boot.tpm = { enable = mkEnableOption "Trusted Platform Module 2.0"; + + initrd = { + enable = mkEnableOption "TPM2 in initrd"; + + pcrs = mkOption { + type = with types; listOf (ints.between 0 23); + default = [ 0 2 7 8 11 ]; + }; + }; }; config = mkIf cfg.enable { @@ -13,6 +60,26 @@ in assertion = config.local.boot.efi.enable; message = "TPM2 requires EFI"; } + { + assertion = cfg.initrd.enable -> cfg.enable; + message = "TPM2 in initrd requires TPM2"; + } + ]; + + boot.initrd = mkIf cfg.initrd.enable { + extraUtilsCommands = '' + copy_bin_and_libs ${pkgs.tpm2-tools}/bin/.tpm2-wrapped + mv $out/bin/{.tpm2-wrapped,tpm2} + cp {${pkgs.tpm2-tss},$out}/lib/libtss2-tcti-device.so.0 + ''; + + kernelModules = [ + "tpm_tis" + ]; + }; + + environment.systemPackages = optionals cfg.initrd.enable [ + tpm2-grant-next-boot ]; security.tpm2 = { @@ -21,7 +88,5 @@ in pkcs11.enable = true; tctiEnvironment.enable = true; }; - - environment.systemPackages = [ pkgs.tpm2-tools ]; }; } |
