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
|
#!/bin/bash
# Encrypted and trusted keyring test; trusted keys can be emulated by TPM2.
# DO NOT use this in combination with a real TPM data, it can destroy them.
#
# Note that if trusted or tpm kernel module is built-in, emulated TPM2 cannot
# provide trusted keys (only encrypted keys will be tested then).
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
IMG=keyring_trusted_test.img
MAP="trusted_test"
KEYNAME=testxxx
bin_check()
{
command -v $1 >/dev/null || skip "WARNING: test require $1 binary, test skipped."
}
cleanup() {
clear_keys
[ -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
[ -n "$SWTPM_PIDFILE" ] && rm -f $SWTPM_PIDFILE >/dev/null 2>&1
[ -n "$SWTPM_STATE_DIR" ] && rm -rf $SWTPM_STATE_DIR >/dev/null 2>&1
rm -f $IMG >/dev/null 2>&1
cleanup_modules
}
cleanup_modules()
{
[ -n "$SKIP_MODULE_UNLOAD" ] && return
# This is a hack to avoid linking trusted key to another TPM.
# Without clean load tests do not work reliably.
modprobe -r dm-crypt 2>/dev/null
modprobe -r encrypted-keys 2>/dev/null
modprobe -r trusted 2>/dev/null
modprobe -r tpm_vtpm_proxy 2>/dev/null
modprobe -r tpm 2>/dev/null
}
fail()
{
echo "[FAILED]"
[ -n "$1" ] && echo "$1"
echo "FAILED backtrace:"
while caller $frame; do ((frame++)); done
cleanup
exit 2
}
_sigchld() { local c=$?; [ $c -eq 139 ] && fail "Segfault"; [ $c -eq 134 ] && fail "Aborted"; }
trap _sigchld CHLD
skip()
{
[ -n "$1" ] && echo "$1"
cleanup
exit 77
}
prepare_tpm()
{
SWTPM_STATE_DIR=$(mktemp -d /tmp/systemd_swtpm_state.XXXXXX)
SWTPM_SEAL_KEY="$SWTPM_STATE_DIR/sealkey.ctxt"
SWTPM_PERSISTENT_HANDLE=0x81000001
if [ -z "$TPM_PATH" ]; then
bin_check swtpm
bin_check swtpm_ioctl
SWTPM_PIDFILE=$(mktemp /tmp/systemd_swtpm_pid.XXXXXX)
cleanup_modules
modprobe tpm_vtpm_proxy || fail "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" ] && fail "No TPM_PATH set and swtpm failed, test skipped."
echo "Virtual TPM set up at $TPM_PATH"
# Trusted module needs to see TPM above.
sleep 1
modprobe trusted 2>/dev/null || echo "Failed to load trusted keys kernel module."
else
SKIP_MODULE_UNLOAD=1
echo "Preconfigured TPM set up at $TPM_PATH"
fi
# Create persistent store
tpm2_createprimary -Q -T device:$TPM_PATH --hierarchy o -G rsa2048 -c $SWTPM_SEAL_KEY || fail
tpm2_evictcontrol -Q -T device:$TPM_PATH -c $SWTPM_SEAL_KEY $SWTPM_PERSISTENT_HANDLE || fail
}
prepare_vk_keyring()
{
local s_desc=$(keyctl rdescribe @s | cut -d';' -f5)
local us_desc=$(keyctl rdescribe @us | cut -d';' -f5)
if [ "$s_desc" = "$us_desc" -a -n "$s_desc" ]; then
echo "Session keyring is missing, initializing new one."
keyctl new_session > /dev/null || fail
fi
}
clear_keys()
{
keyctl revoke %encrypted:$KEYNAME 2>/dev/null
keyctl revoke %user:$KEYNAME 2>/dev/null
if [ -n "$TRUSTED_SUPPORTED" ]; then
keyctl revoke %trusted:$KEYNAME 2>/dev/null
tpm2_evictcontrol -Q -T device:$TPM_PATH -C o -c $SWTPM_PERSISTENT_HANDLE 2>/dev/null
fi
}
[ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped."
bin_check keyctl
prepare_vk_keyring
# Prevent using TPM by default
if [ -n "$RUN_KEYRING_TRUSTED_TEST" ]; then
prepare_tpm
# Trusted keyring key
keyctl add trusted $KEYNAME "new 32 keyhandle=$SWTPM_PERSISTENT_HANDLE" @s >/dev/null 2>&1 && TRUSTED_SUPPORTED=1
if [ -n "$TRUSTED_SUPPORTED" ]; then
keyctl print %trusted:$KEYNAME >/dev/null || fail "Cannot read trusted key blob."
fi
else
echo "WARNING: Variable RUN_KEYRING_TRUSTED_TEST must be defined, TPM trusted test skipped."
TRUSTED_SUPPORTED=
fi
# Prepare encrypted key
modprobe encrypted-keys 2>/dev/null || skip "Failed to load encrypted keys kernel module."
# Encrypted keyring key (encrypted with user key)
# User key needed for encrypted key
keyctl add -x user $KEYNAME bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a @s >/dev/null 2>&1 || skip "User key load failed, test skipped."
keyctl print %user:$KEYNAME >/dev/null || fail "Cannot read user key."
keyctl add encrypted $KEYNAME "new user:$KEYNAME 32" @s >/dev/null || fail "Encrypted keys are not supported."
keyctl print %encrypted:$KEYNAME >/dev/null || fail "Cannot read encrypted key blob."
dd if=/dev/zero of=$IMG bs=1M count=32 >/dev/null 2>&1
echo -n "Plain with trusted volume key "
if [ -n "$TRUSTED_SUPPORTED" ]; then
$CRYPTSETUP open --type plain $IMG $MAP --key-size=256 --cipher=aes-xts-plain64 --volume-key-keyring=%trusted:$KEYNAME || fail
dmsetup table --showkeys $MAP | grep -q ":32:trusted:$KEYNAME" || fail
$CRYPTSETUP status $MAP | grep -q "key location: keyring" || fail
$CRYPTSETUP close $MAP || fail
echo "[OK]"
else
echo "[N/A]"
fi
echo -n "Plain with encrypted volume key "
$CRYPTSETUP open --type plain $IMG $MAP --key-size=256 --cipher=aes-xts-plain64 --volume-key-keyring=%encrypted:$KEYNAME ||fail
dmsetup table --showkeys $MAP | grep -q ":32:encrypted:$KEYNAME" || fail
$CRYPTSETUP status $MAP | grep -q "key location: keyring" || fail
$CRYPTSETUP resize $MAP --size 100 || fail
$CRYPTSETUP status $MAP | grep "size:" | grep -q "100 \[512-byte units\]" || fail
$CRYPTSETUP resize $MAP || fail
$CRYPTSETUP close $MAP || fail
echo "[OK]"
cleanup
exit 0
|