summaryrefslogtreecommitdiffstats
path: root/tests/systemd-test-plugin
blob: 7515f762b756aac00dfb6bcfe852865956335647 (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
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/bin/bash

CC="cc"

PASSWD="tpm2_test"
PASSWD2="tpm2_test2"
FAST_PBKDF_OPT="--pbkdf pbkdf2 --pbkdf-force-iterations 1000"
IMG=systemd_token_test.img
MAP="systemd_tpm2_test"

function bin_check()
{
    command -v $1 >/dev/null || skip "WARNING: test require $1 binary, test skipped."
}

function cleanup() {
    [ -S $SWTPM_STATE_DIR/ctrl.sock ] && {
        # shutdown TPM via control socket
        swtpm_ioctl -s --unix $SWTPM_STATE_DIR/ctrl.sock
        sleep 1
    }

    # if graceful shutdown was successful, pidfile should be deleted
    # if it is still present, we forcefully kill the process
    [ -f "$SWTPM_PIDFILE" ] && {
        kill -9 $(cat $SWTPM_PIDFILE) >/dev/null 2>&1
    }

    [ -b /dev/mapper/$MAP ] && dmsetup remove --retry $MAP

    rm -f $SWTPM_PIDFILE >/dev/null 2>&1
    rm -rf $SWTPM_STATE_DIR >/dev/null 2>&1
    rm -f $IMG >/dev/null 2>&1
}

function fail()
{
    echo "[FAILED]"
    [ -n "$1" ] && echo "$1"
    echo "FAILED backtrace:"
    while caller $frame; do ((frame++)); done
    cleanup
    exit 2
}

function skip()
{
    [ -n "$1" ] && echo "$1"
    cleanup
    exit 77
}

# Prevent downloading and compiling systemd by default
[ -z "$RUN_SYSTEMD_PLUGIN_TEST" ] && skip "WARNING: Variable RUN_SYSTEMD_PLUGIN_TEST must be defined, test skipped."

[ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped."
bin_check swtpm
bin_check swtpm_ioctl

CRYPTENROLL_LD_PRELOAD=""

# if CRYPTSETUP_PATH is defined, we run against installed binaries,
# otherwise we compile systemd tokens from source
[ ! -z "$CRYPTSETUP_TESTS_RUN_IN_MESON" ] && {
    bin_check git
    bin_check meson
    bin_check ninja
    bin_check pkgconf

    INSTALL_PATH=$CRYPTSETUP_PATH/../external-tokens/install
    mkdir -p $INSTALL_PATH
    DESTDIR=$INSTALL_PATH meson install -C ..
    PC_FILE="$(find $INSTALL_PATH -name 'libcryptsetup.pc')"
    echo "INSTALL_PATH $INSTALL_PATH"
    echo "PC_FILE $PC_FILE"
    sed -i "s/^prefix=/prefix=${INSTALL_PATH//\//\\\/}/g" "$PC_FILE"
    export PKG_CONFIG_PATH=$(dirname $PC_FILE)

    # systemd build system misses libcryptsetup.h if it is installed in non-default path
    export CFLAGS="${CFLAGS:-} $(pkgconf --cflags libcryptsetup)"

    SYSTEMD_PATH=$CRYPTSETUP_PATH/../external-tokens/systemd
    SYSTEMD_CRYPTENROLL=$SYSTEMD_PATH/build/systemd-cryptenroll

    mkdir -p $SYSTEMD_PATH
    [ -d $SYSTEMD_PATH/.git ] || git clone --depth=1 https://github.com/systemd/systemd.git $SYSTEMD_PATH
    cd $SYSTEMD_PATH
    meson setup build/ -D tpm2=true -D libcryptsetup=true -D libcryptsetup-plugins=true || skip "Failed to configure systemd via meson, some dependencies are probably missing."
    ninja -C build/ systemd-cryptenroll libcryptsetup-token-systemd-tpm2.so || skip "Failed to build systemd."

    CRYPTSETUP_TOKENS_PATH=$CRYPTSETUP_PATH/../tokens/ssh

    cd $CRYPTSETUP_PATH/../tests
    cp $SYSTEMD_PATH/build/libcryptsetup-token-*.so $CRYPTSETUP_TOKENS_PATH
    cp $SYSTEMD_PATH/build/src/shared/*.so $CRYPTSETUP_TOKENS_PATH
    export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$CRYPTSETUP_PATH/../tests"

    CRYPTENROLL_LD_PRELOAD="$CRYPTSETUP_PATH/../lib/libcryptsetup.so"

    echo "CRYPTENROLL_LD_PRELOAD $CRYPTENROLL_LD_PRELOAD"
}

[ -z "$CRYPTSETUP_PATH" ] && {
    bin_check git
    bin_check meson
    bin_check ninja
    bin_check pkgconf

    INSTALL_PATH=$(pwd)/external-tokens/install
    make -C .. install DESTDIR=$INSTALL_PATH
    PC_FILE="$(find $INSTALL_PATH -name 'libcryptsetup.pc')"
    sed -i "s/^prefix=/prefix=${INSTALL_PATH//\//\\\/}/g" "$PC_FILE"
    export PKG_CONFIG_PATH=$(dirname $PC_FILE)

    # systemd build system misses libcryptsetup.h if it is installed in non-default path
    export CFLAGS="${CFLAGS:-} $(pkgconf --cflags libcryptsetup)"

    SYSTEMD_PATH=$(pwd)/external-tokens/systemd
    CRYPTSETUP_PATH=$(pwd)/..
    SYSTEMD_CRYPTENROLL=$SYSTEMD_PATH/build/systemd-cryptenroll

    mkdir -p $SYSTEMD_PATH
    [ -d $SYSTEMD_PATH/.git ] || git clone --depth=1 https://github.com/systemd/systemd.git $SYSTEMD_PATH
    cd $SYSTEMD_PATH
    meson setup build/ -D tpm2=true -D libcryptsetup=true -D libcryptsetup-plugins=true || skip "Failed to configure systemd via meson, some dependencies are probably missing."
    ninja -C build/ systemd-cryptenroll libcryptsetup-token-systemd-tpm2.so || skip "Failed to build systemd."

    CRYPTSETUP_TOKENS_PATH=$CRYPTSETUP_PATH/.libs

    cd $CRYPTSETUP_PATH/tests
    cp $SYSTEMD_PATH/build/libcryptsetup-token-*.so $CRYPTSETUP_TOKENS_PATH
    cp $SYSTEMD_PATH/build/src/shared/*.so $CRYPTSETUP_TOKENS_PATH

    CRYPTENROLL_LD_PRELOAD="$CRYPTSETUP_PATH/.libs/libcryptsetup.so"
}
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
[ ! -x "$CRYPTSETUP" ] && skip "Cannot find $CRYPTSETUP, test skipped."

[ -z "$SYSTEMD_CRYPTENROLL" ] && {
    bin_check systemd-cryptenroll
    SYSTEMD_CRYPTENROLL="systemd-cryptenroll"
}

[ -z "$TPM_PATH" ] && {
    echo "Setting up virtual TPM using swtpm..."
    SWTPM_PIDFILE=$(mktemp /tmp/systemd_swtpm_pid.XXXXXX)
    SWTPM_STATE_DIR=$(mktemp -d /tmp/systemd_swtpm_state.XXXXXX)
    modprobe tpm_vtpm_proxy || skip "Failed to load tpm_vtpm_proxy kernel module, required for emulated TPM."
    SWTPM_LOG=$(swtpm chardev --vtpm-proxy --tpm2 --tpmstate dir=$SWTPM_STATE_DIR -d --pid file=$SWTPM_PIDFILE --ctrl type=unixio,path=$SWTPM_STATE_DIR/ctrl.sock)
    TPM_PATH=$(echo $SWTPM_LOG | grep -Eo '/dev/tpm([0-9])+' | sed 's/tpm/tpmrm/')
    [ -z "$TPM_PATH" ] && skip "No TPM_PATH set and swtpm failed, test skipped."
    sleep 1
    echo "Virtual TPM set up at $TPM_PATH"
}

if [ -n "$SSH_BUILD_DIR" ]; then
	CUSTOM_TOKENS_PATH="--external-tokens-path $SSH_BUILD_DIR"
fi
FAKE_TPM_PATH="$(pwd)/fake_systemd_tpm_path.so"
[ ! -z "$CRYPTSETUP_TESTS_RUN_IN_MESON" ] && FAKE_TPM_PATH="$CRYPTSETUP_PATH/../tests/fake_systemd_tpm_path.so"
[ -f $FAKE_TPM_PATH ] || skip "Please compile $FAKE_TPM_PATH."
export LD_PRELOAD="$LD_PRELOAD:$FAKE_TPM_PATH"

export TPM_PATH=$TPM_PATH
echo "TPM path is $TPM_PATH"

dd if=/dev/zero of=$IMG bs=1M count=32 >/dev/null 2>&1
echo $PASSWD | $CRYPTSETUP luksFormat --type luks2 $FAST_PBKDF_OPT $IMG --force-password -q

echo "Enrolling the device to TPM 2 using systemd-cryptenroll.."
LD_PRELOAD="$LD_PRELOAD:$CRYPTENROLL_LD_PRELOAD" PASSWORD="$PASSWD" $SYSTEMD_CRYPTENROLL $IMG --tpm2-device=$TPM_PATH >/dev/null 2>&1

$CRYPTSETUP luksDump --external-tokens-path $CRYPTSETUP_TOKENS_PATH $IMG | grep -q "tpm2-blob" || fail "Failed to dump $IMG using systemd_tpm2 token (no tpm2-blob in output)."
echo "Activating the device via TPM2 external token.."
$CRYPTSETUP open --external-tokens-path $CRYPTSETUP_TOKENS_PATH --token-only $IMG $MAP >/dev/null 2>&1 || fail "Failed to open $IMG using systemd_tpm2 token."
$CRYPTSETUP close $MAP >/dev/null 2>&1 || fail "Failed to close $MAP."

echo "Adding passphrase via TPM2 token.."
echo $PASSWD2 | $CRYPTSETUP luksAddKey --external-tokens-path $CRYPTSETUP_TOKENS_PATH $FAST_PBKDF_OPT $IMG --force-password -q --token-only >/dev/null 2>&1 || fail "Failed to add passphrase by tpm2 token."
echo $PASSWD2 | $CRYPTSETUP open $IMG --test-passphrase --disable-external-tokens >/dev/null 2>&1 || fail "Failed to test passphrase added by tpm2 token."

echo "Exporting and removing TPM2 token.."
EXPORTED_TOKEN=$($CRYPTSETUP token export $IMG --token-id 0)
$CRYPTSETUP token remove $IMG --token-id 0
$CRYPTSETUP open --external-tokens-path $CRYPTSETUP_TOKENS_PATH $IMG --test-passphrase --token-only >/dev/null 2>&1 && fail "Activating without passphrase should fail after TPM2 token removal."

echo "Re-importing TPM2 token.."
echo $EXPORTED_TOKEN | $CRYPTSETUP token import $IMG --token-id 0 || fail "Failed to re-import deleted token."
$CRYPTSETUP open --external-tokens-path $CRYPTSETUP_TOKENS_PATH $IMG --test-passphrase --token-only >/dev/null 2>&1 || fail "Failed to activate after re-importing deleted token."

cleanup
exit 0