diff options
Diffstat (limited to 'test/units/TEST-70-TPM2.cryptsetup.sh')
-rwxr-xr-x | test/units/TEST-70-TPM2.cryptsetup.sh | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/test/units/TEST-70-TPM2.cryptsetup.sh b/test/units/TEST-70-TPM2.cryptsetup.sh new file mode 100755 index 0000000..cb7c8b1 --- /dev/null +++ b/test/units/TEST-70-TPM2.cryptsetup.sh @@ -0,0 +1,227 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -ex +set -o pipefail + +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +export SYSTEMD_LOG_LEVEL=debug + +cryptsetup_has_token_plugin_support() { + local plugin_path + + plugin_path="$(cryptsetup --help | sed -nr 's/.*LUKS2 external token plugin path: (.*)\./\1/p')/libcryptsetup-token-systemd-tpm2.so)" + cryptsetup --help | grep -q 'LUKS2 external token plugin support is compiled-in' && [[ -f "$plugin_path" ]] +} + +tpm_check_failure_with_wrong_pin() { + local testIMAGE="${1:?}" + local badpin="${2:?}" + local goodpin="${3:?}" + + # We need to be careful not to trigger DA lockout; allow 2 failures + tpm2_dictionarylockout -s -n 2 + (! PIN=$badpin systemd-cryptsetup attach test-volume "$testIMAGE" - tpm2-device=auto,headless=1) + # Verify the correct PIN works, to be sure the failure wasn't a DA lockout + PIN=$goodpin systemd-cryptsetup attach test-volume "$testIMAGE" - tpm2-device=auto,headless=1 + systemd-cryptsetup detach test-volume + # Clear/reset the DA lockout counter + tpm2_dictionarylockout -c +} + +at_exit() { + # Evict the TPM primary key that we persisted + if [[ -n "${PERSISTENT_HANDLE:-}" ]]; then + tpm2_evictcontrol -c "$PERSISTENT_HANDLE" + fi +} + +trap at_exit EXIT + +# Prepare a fresh disk image +IMAGE="$(mktemp /tmp/systemd-cryptsetup-XXX.IMAGE)" + +truncate -s 20M "$IMAGE" +echo -n passphrase >/tmp/passphrase +# Change file mode to avoid "/tmp/passphrase has 0644 mode that is too permissive" messages +chmod 0600 /tmp/passphrase +cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-urandom "$IMAGE" /tmp/passphrase + +# Unlocking via keyfile +systemd-cryptenroll --unlock-key-file=/tmp/passphrase --tpm2-device=auto "$IMAGE" + +# Enroll unlock with default PCR policy +PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto "$IMAGE" +systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 +systemd-cryptsetup detach test-volume + +# Check with wrong PCR +tpm2_pcrextend 7:sha256=0000000000000000000000000000000000000000000000000000000000000000 +(! systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1) + +# Enroll unlock with PCR+PIN policy +systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" +PASSWORD=passphrase NEWPIN=123456 systemd-cryptenroll --tpm2-device=auto --tpm2-with-pin=true "$IMAGE" +PIN=123456 systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 +systemd-cryptsetup detach test-volume + +# Check failure with wrong PIN; try a few times to make sure we avoid DA lockout +for _ in {0..3}; do + tpm_check_failure_with_wrong_pin "$IMAGE" 123457 123456 +done + +# Check LUKS2 token plugin unlock (i.e. without specifying tpm2-device=auto) +if cryptsetup_has_token_plugin_support; then + PIN=123456 systemd-cryptsetup attach test-volume "$IMAGE" - headless=1 + systemd-cryptsetup detach test-volume + + # Check failure with wrong PIN + for _ in {0..3}; do + tpm_check_failure_with_wrong_pin "$IMAGE" 123457 123456 + done +else + echo 'cryptsetup has no LUKS2 token plugin support, skipping' +fi + +# Check failure with wrong PCR (and correct PIN) +tpm2_pcrextend 7:sha256=0000000000000000000000000000000000000000000000000000000000000000 +(! PIN=123456 systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1) + +# Enroll unlock with PCR 0+7 +systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" +PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 "$IMAGE" +systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 +systemd-cryptsetup detach test-volume + +# Check with wrong PCR 0 +tpm2_pcrextend 0:sha256=0000000000000000000000000000000000000000000000000000000000000000 +(! systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1) + +if tpm_has_pcr sha256 12; then + # Enroll using an explicit PCR value (that does match current PCR value) + systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" + EXPECTED_PCR_VALUE=$(cat /sys/class/tpm/tpm0/pcr-sha256/12) + PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs="12:sha256=$EXPECTED_PCR_VALUE" "$IMAGE" + systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 + systemd-cryptsetup detach test-volume + + # Same as above plus more PCRs without the value or alg specified + systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" + EXPECTED_PCR_VALUE=$(cat /sys/class/tpm/tpm0/pcr-sha256/12) + PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs="1,12:sha256=$EXPECTED_PCR_VALUE,3" "$IMAGE" + systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 + systemd-cryptsetup detach test-volume + + # Same as above plus more PCRs with hash alg specified but hash value not specified + systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" + EXPECTED_PCR_VALUE=$(cat /sys/class/tpm/tpm0/pcr-sha256/12) + PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs="1:sha256,12:sha256=$EXPECTED_PCR_VALUE,3" "$IMAGE" + systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 + systemd-cryptsetup detach test-volume + + # Now the interesting part, enrolling using a hash value that doesn't match the current PCR value + systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" + tpm2_pcrread -Q -o /tmp/pcr.dat sha256:12 + CURRENT_PCR_VALUE=$(cat /sys/class/tpm/tpm0/pcr-sha256/12) + EXPECTED_PCR_VALUE=$(cat /tmp/pcr.dat /tmp/pcr.dat | openssl dgst -sha256 -r | cut -d ' ' -f 1) + PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs="12:sha256=$EXPECTED_PCR_VALUE" "$IMAGE" + (! systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1) + tpm2_pcrextend "12:sha256=$CURRENT_PCR_VALUE" + systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 + systemd-cryptsetup detach test-volume + + # enroll TPM using device key instead of direct access, then verify unlock using TPM + tpm2_pcrread -Q -o /tmp/pcr.dat sha256:12 + CURRENT_PCR_VALUE=$(cat /sys/class/tpm/tpm0/pcr-sha256/12) + tpm2_readpublic -c 0x81000001 -o /tmp/srk.pub + systemd-analyze srk > /tmp/srk2.pub + cmp /tmp/srk.pub /tmp/srk2.pub + if [ -f /run/systemd/tpm2-srk-public-key.tpm2b_public ] ; then + cmp /tmp/srk.pub /run/systemd/tpm2-srk-public-key.tpm2b_public + fi + + # --tpm2-device-key= requires OpenSSL >= 3 with KDF-SS + if openssl_supports_kdf SSKDF; then + PASSWORD=passphrase systemd-cryptenroll --tpm2-device-key=/tmp/srk.pub --tpm2-pcrs="12:sha256=$CURRENT_PCR_VALUE" "$IMAGE" + systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 + systemd-cryptsetup detach test-volume + fi + + rm -f /tmp/pcr.dat /tmp/srk.pub +fi + +# Use default (0) seal key handle +systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" +PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0 "$IMAGE" +systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 +systemd-cryptsetup detach test-volume + +systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" +PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0x0 "$IMAGE" +systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 +systemd-cryptsetup detach test-volume + +# Use SRK seal key handle +systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" +PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=81000001 "$IMAGE" +systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 +systemd-cryptsetup detach test-volume + +systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" +PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0x81000001 "$IMAGE" +systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 +systemd-cryptsetup detach test-volume + +# Test invalid ranges: pcr, nv, session, permanent +systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" +(! PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=7 "$IMAGE") # PCR +(! PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0x01000001 "$IMAGE") # NV index +(! PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0x02000001 "$IMAGE") # HMAC/loaded session +(! PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0x03000001 "$IMAGE") # Policy/saved session +(! PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0x40000001 "$IMAGE") # Permanent + +# Use non-SRK persistent seal key handle (by creating/persisting new key) +PRIMARY=/tmp/primary.ctx +tpm2_createprimary -c "$PRIMARY" +PERSISTENT_LINE=$(tpm2_evictcontrol -c "$PRIMARY" | grep persistent-handle) +PERSISTENT_HANDLE="0x${PERSISTENT_LINE##*0x}" +tpm2_flushcontext -t + +systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" +PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle="${PERSISTENT_HANDLE#0x}" "$IMAGE" +systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 +systemd-cryptsetup detach test-volume + +systemd-cryptenroll --wipe-slot=tpm2 "$IMAGE" +PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle="$PERSISTENT_HANDLE" "$IMAGE" +systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1 +systemd-cryptsetup detach test-volume + +# --tpm2-device-key= requires OpenSSL >= 3 with KDF-SS +if openssl_supports_kdf SSKDF; then + # Make sure that --tpm2-device-key= also works with systemd-repart + tpm2_readpublic -c 0x81000001 -o /tmp/srk.pub + mkdir /tmp/dditest + cat > /tmp/dditest/50-root.conf <<EOF +[Partition] +Type=root +Format=ext4 +CopyFiles=/tmp/dditest:/ +Encrypt=tpm2 +EOF + PASSWORD=passphrase systemd-repart --tpm2-device-key=/tmp/srk.pub --definitions=/tmp/dditest --empty=create --size=50M /tmp/dditest.raw --tpm2-pcrs= + DEVICE="$(systemd-dissect --attach /tmp/dditest.raw)" + udevadm wait --settle --timeout=10 "$DEVICE"p1 + systemd-cryptsetup attach dditest "$DEVICE"p1 - tpm2-device=auto,headless=yes + mkdir /tmp/dditest.mnt + mount -t ext4 /dev/mapper/dditest /tmp/dditest.mnt + cmp /tmp/dditest.mnt/50-root.conf /tmp/dditest/50-root.conf + umount /tmp/dditest.mnt + rmdir /tmp/dditest.mnt + rm /tmp/dditest.raw + rm /tmp/dditest/50-root.conf + rmdir /tmp/dditest +fi + +rm -f "$IMAGE" "$PRIMARY" |