-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathhook_tpm2
executable file
·227 lines (203 loc) · 7.02 KB
/
hook_tpm2
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#!/usr/bin/ash
load_params() {
if [[ ! -f "$1" ]]; then
return;
fi
set -- $(cat $1)
for param in "$@"; do
case "$param" in
tpmkey=*)
tpmkey="${param#tpmkey=}"
;;
tpmpcr=*)
tpmpcr="${param#tpmpcr=}"
;;
tpmextend=*)
tpmextend="${param#tpmextend=}"
;;
tpmextend=*)
tpmextend="${param#tpmextend=}"
;;
tpmprompt=*)
tpmprompt="${param#tpmprompt=}"
;;
tpmdev=*)
tpmdev="${param#tpmdev=}"
;;
ckeyfile=*)
ckeyfile="${param#ckeyfile=}"
;;
esac
done
}
load_defaults(){
# This file will be loaded by the encrypt hook
ckeyfile="/crypto_keyfile.bin"
# Rootfs location for sealed key files
tpmkeypub="/tpm_keyfile.pub"
tpmkeypriv="/tpm_keyfile.priv"
# TPM device
tpmdev="/dev/tpmrm0"
}
process_params(){
load_defaults
# Load params from config file
load_params /etc/tpm2-encrypt/params
# Load kernel params
load_params /proc/cmdline
}
run_hook() {
local ckeyfile tpmkeypub tpmkeypriv tpmkeyparent tpmkeyindex tpmkeyoffset
local tpmkeysize tkdev tkarg1 tkarg2 tkarg3 resolved pcrextendnum
local pcrextendalg tpmload pcrbank unseal unsealout tpmok origifs
origifs="$IFS"
process_params
export TPM2TOOLS_TCTI="device:${tpmdev}"
# Parse tpmkey command line parameter
if [ -n "$tpmkey" ]; then
IFS=: read tkdev tkarg1 tkarg2 tkarg3 <<EOF
$tpmkey
EOF
IFS="$origifs"
case "$tkdev" in
rootfs)
# Key is in initcpio root filesystem. Use files in place
if [ -z "$tkarg3" ]; then
tpmkeypub="${tkarg1}.pub"
tpmkeypriv="${tkarg1}.priv"
tpmkeyparent="$tkarg2"
else
tpmkeypub="$tkarg1"
tpmkeypriv="$tkarg2"
tpmkeyparent="$tkarg3"
fi
;;
nvram)
# Key is in NVRAM. Populate NVRAM variables
tpmkeyindex="$tkarg1"
tpmkeyoffset="$tkarg2"
tpmkeysize="$tkarg3"
;;
*)
# Key is on block device
# Locate, mount, and copy the key files
if resolved=$(resolve_device "${tkdev}" ${rootdelay}); then
mkdir /tpmkey
mount -r -t auto "$resolved" /tpmkey
if [ -z "$tkarg3" ]; then
dd if="/tpmkey/${tkarg1}.pub" of="$tpmkeypub" >/dev/null 2>&1
dd if="/tpmkey/${tkarg1}.priv" of="$tpmkeypriv" >/dev/null 2>&1
tpmkeyparent="$tkarg2"
else
dd if="/tpmkey/${tkarg1}" of="$tpmkeypub" >/dev/null 2>&1
dd if="/tpmkey/${tkarg2}" of="$tpmkeypriv" >/dev/null 2>&1
tpmkeyparent="$tkarg3"
fi
umount /tpmkey
rmdir /tpmkey
fi
;;
esac
# If there is no NVRAM index and no sealed files, print an error
if [ -z "$tpmkeyindex" ] && [ ! -f "$tpmkeypub" -o ! -f "$tpmkeypriv" ]; then
err "TPM keyfiles could not be opened"
fi
fi
# Parse the tpmextend command line parameter
if [ -n "$tpmextend" ]; then
IFS=: read pcrextendalg pcrextendnum <<EOF
$tpmextend
EOF
IFS="$origifs"
fi
# We must have a PCR list to retrieve a key
[ -n "$tpmkey" ] && [ -z "$tpmpcr" ] && err "TPM PCR bank not specified"
# If we have a key and PCR list, decrypt it
if [ -n "$tpmpcr" -a -n "$tpmkeyindex" ] || [ -n "$tpmpcr" -a -f "$tpmkeypub" -a -f "$tpmkeypriv" ]; then
# Load key object if stored on disk
tpmload=0
if [ -z "$tpmkeyindex" ]; then
if [ -n "$tpmprompt" ]; then
echo
tpm2_load -Q -C "$tpmkeyparent" -P file:- -r "$tpmkeypriv" -u "$tpmkeypub" -c /tpmobject.ctx 2>/dev/null
tpmload=$?
echo
else
tpm2_load -Q -C "$tpmkeyparent" -r "$tpmkeypriv" -u "$tpmkeypub" -c /tpmobject.ctx >/dev/null 2>&1
tpmload=$?
fi
fi
# Format nvram arguments
[ -n "$tpmkeyoffset" ] && tpmkeyoffset="--offset=${tpmkeyoffset}"
[ -n "$tpmkeysize" ] && tpmkeysize="--size=${tpmkeysize}"
# Attempt to decrypt key with each PCR bank specified
unseal=1
if [ $tpmload -eq 0 ]; then
IFS="|"
for pcrbank in $tpmpcr; do
if [ -n "$tpmkeyindex" ]; then
unsealout=$(tpm2_nvread -Q $tpmkeyoffset $tpmkeysize -P "pcr:${pcrbank}" -o $ckeyfile "$tpmkeyindex" 2>&1)
unseal=$?
else
unsealout=$(tpm2_unseal -Q -c /tpmobject.ctx -p "pcr:${pcrbank}" -o "$ckeyfile" 2>&1)
unseal=$?
fi
if [ $unseal -eq 0 ]; then break; fi
done
IFS="$origifs"
fi
# Check decryption resuts and report
tpmok=0
if [ $unseal -eq 0 ]; then
tpmok=1
elif echo "$unsealout" | grep -sqiE 'Could not load tcti'; then
err "TPM communication error"
elif echo "$unsealout" | grep -sqiE 'ERROR.*0x99D'; then
echo
echo "!!! TPM WARNING: PCR VALUES HAVE CHANGED !!!"
echo "This is an indication that the boot configuration has been altered since"
echo "the TPM key was generated. This is normal after kernel updates or firmware"
echo "changes, however this could also indicate a malicious change to your system."
echo
elif [ -n "$tpmkeyindex" ]; then
err "Could not read key from TPM NVRAM"
elif [ $tpmload -ne 0 ]; then
err "Could not load TPM keyfile"
else
err "Could not unseal TPM keyfile"
fi
if [ $tpmok -eq 0 ]; then
rm -f "$ckeyfile"
msg ":: TPM Could not decrypt LUKS key"
fi
fi
# Extend specified PCR
if [ -n "$pcrextendnum" ] && [ -n "$pcrextendalg" ]; then
case "$pcrextendalg" in
sha1|sha224|sha256|sha384|sha512)
tpm2_pcrextend ${pcrextendnum}:${pcrextendalg}=$("${pcrextendalg}sum" /proc/cmdline 2>/dev/null | cut -f1 -d' ') >/dev/null 2>&1
if [ $? -ne 0 ]; then
err "Could not extend TPM PCR"
fi
;;
*)
err "Hash algorithm not supported for PCR extend"
;;
esac
fi
# Cleanup
rm -f /tpmobject.ctx "$tpmkeypub" "$tpmkeypriv"
}
run_cleanuphook() {
process_params
# Securely delete key if still present
if [ -f "$ckeyfile" ]; then
dd if=/dev/urandom of="$ckeyfile" bs=$(stat -c "%s" "$ckeyfile") count=1 conv=notrunc >/dev/null 2>&1
rm -f "$ckeyfile"
fi
}
print_key() {
process_params
cat "$ckeyfile"
}
# vim: set ft=sh ts=4 sw=4 et: