summaryrefslogtreecommitdiffstats
path: root/test/units/TEST-70-TPM2.pcrlock.sh
blob: fd51161a7027009664ab30290ee1f8f4707082f9 (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
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
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail

# shellcheck source=test/units/util.sh
. "$(dirname "$0")"/util.sh

export SYSTEMD_LOG_LEVEL=debug
export PAGER=
SD_PCREXTEND="/usr/lib/systemd/systemd-pcrextend"
SD_PCRLOCK="/usr/lib/systemd/systemd-pcrlock"

if [[ ! -x "${SD_PCREXTEND:?}" ]] || [[ ! -x "${SD_PCRLOCK:?}" ]] ; then
    echo "$SD_PCREXTEND or $SD_PCRLOCK not found, skipping pcrlock tests"
    exit 0
fi

at_exit() {
    if [[ $? -ne 0 ]]; then
        # Dump the event log on fail, to make debugging a bit easier
        [[ -e /run/log/systemd/tpm2-measure.log ]] && jq --seq --slurp </run/log/systemd/tpm2-measure.log
    fi

    return 0
}

trap at_exit EXIT

# Temporarily override sd-pcrextend's sanity checks
export SYSTEMD_FORCE_MEASURE=1

# The PCRs we are going to lock to. We exclude the various PCRs we touched
# above where no event log record was written, because we cannot analyze
# things without event log. We include debug PCR 16, see below.
PCRS="1+2+3+4+5+16"

# Remove the old measurement log, as it contains all kinds of nonsense from the
# previous test, which will fail our consistency checks. Removing the file also
# means we'll fail consistency check, but at least we'll fail them consistently
# (as the PCR values simply won't match the log).
rm -f /run/log/systemd/tpm2-measure.log

# Ensure a truncated log doesn't crash pcrlock
echo -n -e \\x1e >/tmp/borked
set +e
SYSTEMD_MEASURE_LOG_USERSPACE=/tmp/borked "$SD_PCRLOCK" cel --no-pager --json=pretty
ret=$?
set -e
# If it crashes the exit code will be 149
test $ret -eq 1

SYSTEMD_COLORS=256 "$SD_PCRLOCK"
"$SD_PCRLOCK" cel --no-pager --json=pretty
"$SD_PCRLOCK" log --pcr="$PCRS"
"$SD_PCRLOCK" log --json=pretty --pcr="$PCRS"
"$SD_PCRLOCK" list-components
"$SD_PCRLOCK" list-components --location=250-
"$SD_PCRLOCK" list-components --location=250-:350-
"$SD_PCRLOCK" lock-firmware-config
"$SD_PCRLOCK" lock-gpt
"$SD_PCRLOCK" lock-machine-id
"$SD_PCRLOCK" lock-file-system
"$SD_PCRLOCK" lock-file-system /
"$SD_PCRLOCK" predict --pcr="$PCRS"
"$SD_PCRLOCK" predict --pcr="0x1+0x3+4"
"$SD_PCRLOCK" predict --json=pretty --pcr="$PCRS"

SD_STUB="$(find /usr/lib/systemd/boot/efi/ -name "systemd-boot*.efi" | head -n1)"
if [[ -n "$SD_STUB" ]]; then
    "$SD_PCRLOCK" lock-pe "$SD_STUB"
    "$SD_PCRLOCK" lock-pe <"$SD_STUB"
    "$SD_PCRLOCK" lock-uki "$SD_STUB"
    "$SD_PCRLOCK" lock-uki <"$SD_STUB"
fi

PIN=huhu "$SD_PCRLOCK" make-policy --pcr="$PCRS" --recovery-pin=query
# Repeat immediately (this call will have to reuse the nvindex, rather than create it)
"$SD_PCRLOCK" make-policy --pcr="$PCRS"
"$SD_PCRLOCK" make-policy --pcr="$PCRS" --force

img="/tmp/pcrlock.img"
truncate -s 20M "$img"
echo -n hoho >/tmp/pcrlockpwd
chmod 0600 /tmp/pcrlockpwd
cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-urandom "$img" /tmp/pcrlockpwd

systemd-cryptenroll --unlock-key-file=/tmp/pcrlockpwd --tpm2-device=auto --tpm2-pcrlock=/var/lib/systemd/pcrlock.json --wipe-slot=tpm2 "$img"
systemd-cryptsetup attach pcrlock "$img" - tpm2-device=auto,tpm2-pcrlock=/var/lib/systemd/pcrlock.json,headless
systemd-cryptsetup detach pcrlock

# Measure something into PCR 16 (the "debug" PCR), which should make the activation fail
"$SD_PCREXTEND" --pcr=16 test70

"$SD_PCRLOCK" cel --json=pretty

(! systemd-cryptsetup attach pcrlock "$img" - tpm2-device=auto,tpm2-pcrlock=/var/lib/systemd/pcrlock.json,headless )

# Now add a component for it, rebuild policy and it should work (we'll rebuild
# once like that, but don't provide the recovery pin. This should fail, since
# the PCR is hosed after all. But then we'll use recovery pin, and it should
# work.
echo -n test70 | "$SD_PCRLOCK" lock-raw --pcrlock=/var/lib/pcrlock.d/910-test70.pcrlock --pcr=16
(! "$SD_PCRLOCK" make-policy --pcr="$PCRS")
PIN=huhu "$SD_PCRLOCK" make-policy --pcr="$PCRS" --recovery-pin=query

systemd-cryptsetup attach pcrlock "$img" - tpm2-device=auto,tpm2-pcrlock=/var/lib/systemd/pcrlock.json,headless
systemd-cryptsetup detach pcrlock

# And now let's do it the clean way, and generate the right policy ahead of time.
echo -n test70-take-two | "$SD_PCRLOCK" lock-raw --pcrlock=/var/lib/pcrlock.d/920-test70.pcrlock --pcr=16
"$SD_PCRLOCK" make-policy --pcr="$PCRS"
# the next one should be skipped because redundant
"$SD_PCRLOCK" make-policy --pcr="$PCRS"
# but this one should not be skipped, even if redundant, because we force it
"$SD_PCRLOCK" make-policy --pcr="$PCRS" --force --recovery-pin=show

"$SD_PCREXTEND" --pcr=16 test70-take-two

"$SD_PCRLOCK" cel --json=pretty

systemd-cryptsetup attach pcrlock "$img" - tpm2-device=auto,tpm2-pcrlock=/var/lib/systemd/pcrlock.json,headless
systemd-cryptsetup detach pcrlock

# Now use the root fs support, i.e. make the tool write a copy of the pcrlock
# file as service credential to some temporary dir and remove the local copy, so that
# it has to use the credential version.
mkdir /tmp/fakexbootldr
SYSTEMD_XBOOTLDR_PATH=/tmp/fakexbootldr SYSTEMD_RELAX_XBOOTLDR_CHECKS=1 "$SD_PCRLOCK" make-policy --pcr="$PCRS" --force
mv /var/lib/systemd/pcrlock.json /var/lib/systemd/pcrlock.json.gone

systemd-creds decrypt /tmp/fakexbootldr/loader/credentials/pcrlock.*.cred

SYSTEMD_ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY=/tmp/fakexbootldr/loader/credentials systemd-cryptsetup attach pcrlock "$img" - tpm2-device=auto,headless
systemd-cryptsetup detach pcrlock

mv /var/lib/systemd/pcrlock.json.gone /var/lib/systemd/pcrlock.json
SYSTEMD_XBOOTLDR_PATH=/tmp/fakexbootldr SYSTEMD_RELAX_XBOOTLDR_CHECKS=1 "$SD_PCRLOCK" remove-policy

"$SD_PCRLOCK" unlock-firmware-config
"$SD_PCRLOCK" unlock-gpt
"$SD_PCRLOCK" unlock-machine-id
"$SD_PCRLOCK" unlock-file-system
"$SD_PCRLOCK" unlock-raw --pcrlock=/var/lib/pcrlock.d/910-test70.pcrlock
"$SD_PCRLOCK" unlock-raw --pcrlock=/var/lib/pcrlock.d/920-test70.pcrlock

(! "$SD_PCRLOCK" "")
(! "$SD_PCRLOCK" predict --pcr=-1)
(! "$SD_PCRLOCK" predict --pcr=foo)
(! "$SD_PCRLOCK" predict --pcr=1+1)
(! "$SD_PCRLOCK" predict --pcr=1+++++1)
(! "$SD_PCRLOCK" make-policy --nv-index=0)
(! "$SD_PCRLOCK" make-policy --nv-index=foo)
(! "$SD_PCRLOCK" list-components --location=:)
(! "$SD_PCRLOCK" lock-gpt "")
(! "$SD_PCRLOCK" lock-gpt /dev/sr0)
(! "$SD_PCRLOCK" lock-pe /dev/full)
(! "$SD_PCRLOCK" lock-pe /bin/true)
(! "$SD_PCRLOCK" lock-uki /dev/full)
(! "$SD_PCRLOCK" lock-uki /bin/true)
(! "$SD_PCRLOCK" lock-file-system "")

# Exercise Varlink API a bit (but first turn off condition)

mkdir -p /run/systemd/system/systemd-pcrlock.socket.d
cat > /run/systemd/system/systemd-pcrlock.socket.d/50-no-condition.conf <<EOF
[Unit]
# Turn off all conditions
ConditionSecurity=
EOF

systemctl daemon-reload
systemctl restart systemd-pcrlock.socket

varlinkctl call /run/systemd/io.systemd.PCRLock io.systemd.PCRLock.RemovePolicy '{}'
varlinkctl call /run/systemd/io.systemd.PCRLock io.systemd.PCRLock.MakePolicy '{}'
varlinkctl call --collect --json=pretty /run/systemd/io.systemd.PCRLock io.systemd.PCRLock.ReadEventLog '{}'

rm "$img" /tmp/pcrlockpwd