blob: d3e7c29c5dacd7c976b0d3215de02ab030acbd3e (
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
{
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() {
[ -e ${tpmPath}/auth.sig ] || return
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;
};
systemd.services = {
clear-tpm2-boot-auth = let
inherit (config.local.boot.efi.esp) mountpoint;
mountUnit = concatStringsSep "-" (splitString "/" (removePrefix "/" mountpoint)) + ".mount";
tpmBootPath = "${mountpoint}/${cfg.tpmStorageFromBoot}";
in {
after = ["tpm2.target" mountUnit];
wantedBy = ["tpm2.target"];
serviceConfig = {
Type = "oneshot";
};
script = ''
for file in auth.policy auth.sig; do
path="${tpmBootPath}/$file"
[ -f "$path" ] && shred -fu -- "$path"
done
sync -f "${mountpoint}"
'';
};
};
};
}
|