summaryrefslogtreecommitdiff
path: root/sys/boot/detached-luks.nix
blob: 78ae35c652b099d84a81b11e136c2de7ba37ef00 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
{
  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 = {
    enable = mkEnableOption "detached LUKS header in initrd";

    headerFromBoot = mkOption {
      type = types.str;
    };

    tpmStorageFromBoot = mkOption {
      type = types.str;
      default = "tpm-boot";
    };

    crypt = mkOption {
      type = types.str;
    };

    target = mkOption {
      type = types.str;
    };
  };

  config = mkIf cfg.enable {
    boot.initrd = let
      headerPath = "/initrd-boot/${cfg.headerFromBoot}";
      headerPathEscaped = escapeShellArg headerPath;

      tpmPath = escapeShellArg "/initrd-boot/${cfg.tpmStorageFromBoot}";
      hardwareKeyPath = "/tpm/unsealed.luks-key";
    in {
      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
        # bug in qemu-kvm > 1.5.2 (where the VM clock is initialised
        # to the *boot time* of the host).
        hwclock -s
      '';

      #FIXME: Demasiado vulgar
      preLVMCommands = optionalString (config.local.boot.efi.enable && config.local.boot.efi.removable) ''
        sleep 2
      '';

      luks.devices.${cfg.target} = {
        device = cfg.crypt;
        header = headerPath;
        preLVM = false;

        keyFile = mkIf tpmInitrd hardwareKeyPath;
        fallbackToPassword = tpmInitrd;

        preOpenCommands =
          ''
            mount -o ro -t ${bootFs.fsType} ${bootFs.device} /initrd-boot
          ''
          + optionalString tpmInitrd ''
            mkdir /tpm
            touch ${escapeShellArg hardwareKeyPath}

            unseal_tpm_key() {
              tpm2 createprimary -Q -C owner -g sha256 -G ecc -c /tpm/prim.ctx || return

              tpm2 loadexternal -Q -C owner -G rsa -u ${tpmPath}/signing-key.pub -c /tpm/signing-key.ctx -n /tpm/signing-key.name || return
              tpm2 verifysignature -Q -c /tpm/signing-key.ctx -g sha256 -m ${tpmPath}/auth.policy -s ${tpmPath}/auth.sig -t /tpm/verified.ticket -f rsassa || return

              tpm2 startauthsession -Q -S /tpm/session.ctx --policy-session || return

              tpm_resets=`tpm2 readclock | grep reset_count | sed 's/.*: //g'`
              tpm2 policycountertimer -Q -S /tpm/session.ctx resets="$tpm_resets" || return
              tpm2 policypcr -Q -S /tpm/session.ctx -l sha256:${pcrList} || return
              tpm2 policyauthorize -Q -S /tpm/session.ctx -i ${tpmPath}/auth.policy -n /tpm/signing-key.name -t /tpm/verified.ticket || return

              tpm2 load -Q -C /tpm/prim.ctx -u ${tpmPath}/key.pub -r ${tpmPath}/key.priv -c /tpm/key.ctx || return
              tpm2 unseal -Q -c /tpm/key.ctx -p session:/tpm/session.ctx -o ${escapeShellArg hardwareKeyPath} || return

              tpm2 flushcontext /tpm/session.ctx
            }

            unseal_tpm_key
          '';

        postOpenCommands = mkBefore (''
            umount /initrd-boot
          ''
          + optionalString tpmInitrd ''
            rm -r /tpm
          '');
      };
    };

    local.boot = {
      stack = {
        btrfsToplevelMultidrive.toplevel.device = "/dev/mapper/${cfg.target}";
        luksExt4FscryptImpermanence = {inherit (cfg) target;};
      };

      tpm.initrd.enable = mkDefault config.local.boot.tpm.enable;
    };
  };
}