#!/usr/bin/env bash # SPDX-License-Identifier: LGPL-2.1-or-later set -ex set -o pipefail export SYSTEMD_LOG_LEVEL=debug # Prepare fresh disk image img="/var/tmp/test.img" truncate -s 20M $img echo -n passphrase >/tmp/passphrase cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-urandom $img /tmp/passphrase # Unlocking via keyfile systemd-cryptenroll --unlock-key-file=/tmp/passphrase --tpm2-device=auto $img # Enroll unlock with default PCR policy env PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto $img /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 /usr/lib/systemd/systemd-cryptsetup detach test-volume # Check with wrong PCR tpm2_pcrextend 7:sha256=0000000000000000000000000000000000000000000000000000000000000000 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; } # Enroll unlock with PCR+PIN policy systemd-cryptenroll --wipe-slot=tpm2 $img env PASSWORD=passphrase NEWPIN=123456 systemd-cryptenroll --tpm2-device=auto --tpm2-with-pin=true $img env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 /usr/lib/systemd/systemd-cryptsetup detach test-volume # Check failure with wrong PIN env PIN=123457 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; } # Check LUKS2 token plugin unlock (i.e. without specifying tpm2-device=auto) if cryptsetup --help | grep -q 'LUKS2 external token plugin support is compiled-in' && \ [ -f "$(cryptsetup --help | sed -n -r 's/.*LUKS2 external token plugin path: (.*)\./\1/p')/libcryptsetup-token-systemd-tpm2.so" ]; then env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - headless=1 /usr/lib/systemd/systemd-cryptsetup detach test-volume # Check failure with wrong PIN env PIN=123457 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - headless=1 && { echo 'unexpected success'; exit 1; } else echo 'cryptsetup has no LUKS2 token plugin support, skipping' fi # Check failure with wrong PCR (and correct PIN) tpm2_pcrextend 7:sha256=0000000000000000000000000000000000000000000000000000000000000000 env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; } # Enroll unlock with PCR 0+7 systemd-cryptenroll --wipe-slot=tpm2 $img env PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 $img /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 /usr/lib/systemd/systemd-cryptsetup detach test-volume # Check with wrong PCR 0 tpm2_pcrextend 0:sha256=0000000000000000000000000000000000000000000000000000000000000000 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && exit 1 rm $img if [[ -e /usr/lib/systemd/systemd-measure ]]; then echo HALLO >/tmp/tpmdata1 echo foobar >/tmp/tpmdata2 cat >/tmp/result </tmp/result.json </tmp/result </tmp/result.json </dev/null; then MEASURE_BANKS+=("--bank=sha1") fi # Sign current PCR state with it /usr/lib/systemd/systemd-measure sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: | tee "/tmp/pcrsign.sig" dd if=/dev/urandom of=/tmp/pcrtestdata bs=1024 count=64 systemd-creds encrypt /tmp/pcrtestdata /tmp/pcrtestdata.encrypted --with-key=host+tpm2-with-public-key --tpm2-public-key="/tmp/pcrsign-public.pem" systemd-creds decrypt /tmp/pcrtestdata.encrypted - --tpm2-signature="/tmp/pcrsign.sig" | cmp - /tmp/pcrtestdata # Invalidate PCR, decrypting should fail now tpm2_pcrextend 11:sha256=0000000000000000000000000000000000000000000000000000000000000000 systemd-creds decrypt /tmp/pcrtestdata.encrypted - --tpm2-signature="/tmp/pcrsign.sig" >/dev/null && { echo 'unexpected success'; exit 1; } # Sign new PCR state, decrypting should work now. /usr/lib/systemd/systemd-measure sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: >"/tmp/pcrsign.sig2" systemd-creds decrypt /tmp/pcrtestdata.encrypted - --tpm2-signature="/tmp/pcrsign.sig2" | cmp - /tmp/pcrtestdata # Now, do the same, but with a cryptsetup binding truncate -s 20M $img cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-urandom $img /tmp/passphrase # Ensure that an unrelated signature, when not requested, is not used touch /run/systemd/tpm2-pcr-signature.json systemd-cryptenroll --unlock-key-file=/tmp/passphrase --tpm2-device=auto --tpm2-public-key="/tmp/pcrsign-public.pem" $img # Reset and use the signature now rm -f /run/systemd/tpm2-pcr-signature.json systemd-cryptenroll --wipe-slot=tpm2 $img systemd-cryptenroll --unlock-key-file=/tmp/passphrase --tpm2-device=auto --tpm2-public-key="/tmp/pcrsign-public.pem" --tpm2-signature="/tmp/pcrsign.sig2" $img # Check if we can activate that (without the token module stuff) SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=0 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig2",headless=1 SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=0 /usr/lib/systemd/systemd-cryptsetup detach test-volume2 # Check if we can activate that (and a second time with the token module stuff enabled) SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=1 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig2",headless=1 SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=1 /usr/lib/systemd/systemd-cryptsetup detach test-volume2 # After extending the PCR things should fail tpm2_pcrextend 11:sha256=0000000000000000000000000000000000000000000000000000000000000000 SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=0 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig2",headless=1 && { echo 'unexpected success'; exit 1; } SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=1 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig2",headless=1 && { echo 'unexpected success'; exit 1; } # But once we sign the current PCRs, we should be able to unlock again /usr/lib/systemd/systemd-measure sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: >"/tmp/pcrsign.sig3" SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=0 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig3",headless=1 /usr/lib/systemd/systemd-cryptsetup detach test-volume2 SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=1 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig3",headless=1 /usr/lib/systemd/systemd-cryptsetup detach test-volume2 # Test --append mode and de-duplication. With the same parameters signing should not add a new entry /usr/lib/systemd/systemd-measure sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: --append="/tmp/pcrsign.sig3" >"/tmp/pcrsign.sig4" cmp "/tmp/pcrsign.sig3" "/tmp/pcrsign.sig4" # Sign one more phase, this should /usr/lib/systemd/systemd-measure sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=quux:waldo --append="/tmp/pcrsign.sig4" >"/tmp/pcrsign.sig5" ( ! cmp "/tmp/pcrsign.sig4" "/tmp/pcrsign.sig5" ) # Should still be good to unlock, given the old entry still exists SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=0 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig5",headless=1 /usr/lib/systemd/systemd-cryptsetup detach test-volume2 # Adding both signatures once more should not change anything, due to the deduplication /usr/lib/systemd/systemd-measure sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: --append="/tmp/pcrsign.sig5" >"/tmp/pcrsign.sig6" /usr/lib/systemd/systemd-measure sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=quux:waldo --append="/tmp/pcrsign.sig6" >"/tmp/pcrsign.sig7" cmp "/tmp/pcrsign.sig5" "/tmp/pcrsign.sig7" rm $img else echo "/usr/lib/systemd/systemd-measure or PCR sysfs files not found, skipping signed PCR policy test case" fi if [ -e /usr/lib/systemd/systemd-pcrphase ] && \ [ -f /sys/class/tpm/tpm0/pcr-sha256/11 ]; then # Let's measure the machine ID tpm2_pcrread sha256:15 -Q -o /tmp/oldpcr15 mv /etc/machine-id /etc/machine-id.save echo 994013bf23864ee7992eab39a96dd3bb >/etc/machine-id SYSTEMD_FORCE_MEASURE=1 /usr/lib/systemd/systemd-pcrphase --machine-id mv /etc/machine-id.save /etc/machine-id tpm2_pcrread sha256:15 -Q -o /tmp/newpcr15 # And check it matches expectations ( cat /tmp/oldpcr15 ; echo -n "machine-id:994013bf23864ee7992eab39a96dd3bb" | openssl dgst -binary -sha256 ) | openssl dgst -binary -sha256 | cmp - /tmp/newpcr15 rm /tmp/oldpcr15 /tmp/newpcr15 # And similar for the boot phase measurement into PCR 11 tpm2_pcrread sha256:11 -Q -o /tmp/oldpcr11 SYSTEMD_FORCE_MEASURE=1 /usr/lib/systemd/systemd-pcrphase foobar tpm2_pcrread sha256:11 -Q -o /tmp/newpcr11 ( cat /tmp/oldpcr11 ; echo -n "foobar" | openssl dgst -binary -sha256 ) | openssl dgst -binary -sha256 | cmp - /tmp/newpcr11 rm /tmp/oldpcr11 /tmp/newpcr11 else echo "/usr/lib/systemd/systemd-pcrphase or PCR sysfs files not found, skipping PCR extension test case" fi # Ensure that sandboxing doesn't stop creds from being accessible echo "test" > /tmp/testdata systemd-creds encrypt /tmp/testdata /tmp/testdata.encrypted --with-key=tpm2 # LoadCredentialEncrypted systemd-run -p PrivateDevices=yes -p LoadCredentialEncrypted=testdata.encrypted:/tmp/testdata.encrypted --pipe --wait systemd-creds cat testdata.encrypted | cmp - /tmp/testdata # SetCredentialEncrypted systemd-run -p PrivateDevices=yes -p SetCredentialEncrypted=testdata.encrypted:"$(cat /tmp/testdata.encrypted)" --pipe --wait systemd-creds cat testdata.encrypted | cmp - /tmp/testdata rm /tmp/testdata echo OK >/testok exit 0