On 4/19/24 04:31, Gary Lin via Grub-devel wrote:
For the tpm2 module, the TCG2 command submission function is the only
difference between the a QEMU instance and grub-emu. To test TPM key
unsealing with a QEMU instance, it requires an extra OS image to invoke
grub-protect to seal the LUKS key, rather than a simple grub-shell rescue
CD image. On the other hand, grub-emu can share the emulated TPM device
with the host, so that we can seal the LUKS key on host and test key
unsealing with grub-emu.
This test script firstly creates a simple LUKS image to be loaded as a
loopback device in grub-emu. Then an emulated TPM device is created by
swtpm_cuse and PCR 0 and 1 are extended.
There are several test cases in the script to test various settings. Each
test case uses grub-protect or tpm2-tools to seal the LUKS password
against PCR 0 and PCR 1. Then grub-emu is launched to load the LUKS image,
try to mount the image with tpm2_key_protector_init and cryptomount, and
verify the result.
Based on the idea from Michael Chang.
Cc: Michael Chang <mch...@suse.com>
Cc: Stefan Berger <stef...@linux.ibm.com>
Signed-off-by: Gary Lin <g...@suse.com>
---
Makefile.util.def | 6 +
tests/tpm2_test.in | 311 +++++++++++++++++++++++++++++++++++++++
tests/util/grub-shell.in | 6 +-
3 files changed, 322 insertions(+), 1 deletion(-)
create mode 100644 tests/tpm2_test.in
diff --git a/Makefile.util.def b/Makefile.util.def
index 40bfe713d..8d4c53a03 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -1281,6 +1281,12 @@ script = {
common = tests/asn1_test.in;
};
+script = {
+ testcase = native;
+ name = tpm2_test;
+ common = tests/tpm2_test.in;
+};
+
program = {
testcase = native;
name = example_unit_test;
diff --git a/tests/tpm2_test.in b/tests/tpm2_test.in
new file mode 100644
index 000000000..697319c75
--- /dev/null
+++ b/tests/tpm2_test.in
@@ -0,0 +1,311 @@
+#! @BUILD_SHEBANG@ -e
+
+# Test GRUBs ability to unseal a LUKS key with TPM 2.0
+# Copyright (C) 2024 Free Software Foundation, Inc.
+#
+# GRUB is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# GRUB is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+
+grubshell=@builddir@/grub-shell
+
+. "@builddir@/grub-core/modinfo.sh"
+
+if [ x$grub_modinfo_platform != xemu ]; then
+ exit 77
+fi
+
+builddir="@builddir@"
+
+# Force build directory components
+PATH="${builddir}:$PATH"
+export PATH
+
+if [ "x$EUID" = "x" ] ; then
+ EUID=`id -u`
+fi
+
+if [ "$EUID" != 0 ] ; then
+ echo "not root; cannot test tpm2."
+ exit 99
+fi
+
+if ! which cryptsetup >/dev/null 2>&1; then
+ echo "cryptsetup not installed; cannot test tpm2."
+ exit 99
+fi
+
+if ! grep -q tpm_vtpm_proxy /proc/modules && ! modprobe tpm_vtpm_proxy; then
+ echo "no tpm_vtpm_proxy support; cannot test tpm2."
+ exit 99
+fi
+
+if ! which swtpm >/dev/null 2>&1; then
+ echo "swtpm not installed; cannot test tpm2."
+ exit 99
+fi
+
+if ! which tpm2_startup >/dev/null 2>&1; then
+ echo "tpm2-tools not installed; cannot test tpm2."
+ exit 99
+fi
+
+tpm2testdir="`mktemp -d "${TMPDIR:-/tmp}/$(basename "$0").XXXXXXXXXX"`" ||
exit 20
+
+disksize=20M
+
+luksfile=$tpm2testdir/luks.disk
+lukskeyfile=${tpm2testdir}/password.txt
+
+# Choose a low iteration number to reduce the time to decrypt the disk
+csopt="--type luks2 --pbkdf pbkdf2 --iter-time 1000"
+
+tpm2statedir=${tpm2testdir}/tpm
+tpm2ctrl=${tpm2statedir}/ctrl
+tpm2log=${tpm2statedir}/logfile
+
+sealedkey=${tpm2testdir}/sealed.tpm
+
+timeout=20
+
+testoutput=$tpm2testdir/testoutput
+
+vtext="TEST VERIFIED"
+
+# Create the password file
+echo -n "top secret" > ${lukskeyfile}
+
+# Setup LUKS2 image
+truncate -s ${disksize} ${luksfile} || exit 21
+cryptsetup luksFormat -q ${csopt} ${luksfile} ${lukskeyfile} || exit 22
+
+# Shutdown the swtpm instance on exit
+cleanup() {
+ RET=$?
+ if [ -e "$tpm2ctrl" ]; then
+ swtpm_ioctl -s --unix ${tpm2ctrl}
+ fi
+ if [ "${RET}" -eq 0 ]; then
+ rm -rf "$tpm2testdir" || :
+ fi
+}
+trap cleanup EXIT INT TERM KILL QUIT
+
+mkdir -p ${tpm2statedir}
+
+# Create the swtpm chardev instannce
instance
+swtpm chardev --vtpm-proxy --tpmstate dir=${tpm2statedir} \
+ --tpm2 --ctrl type=unixio,path=${tpm2ctrl} \
+ --flags startup-clear --daemon > ${tpm2log}
+ret=$?
+if [ "$ret" -ne 0 ]; then
+ exit $ret
+fi
+
+tpm2dev=$(grep "New TPM device" ${tpm2log} | cut -d' ' -f 4)
I would add this into the loop below because timing-wise swtpm would
have to be fast to have shown this output.
+if [ -z "${tpm2dev}" ]; then
+ exit QUIT
+fi
+
+# Wait for tpm2 chardev
+wait=3
+while [ "${wait}" -gt 0 ]; do
+ if [ -c "${tpm2dev}" ]; then
+ break;
+ fi
+ sleep 1
+ ((wait--))
+done
+if [ "$wait" -le 0 ]; then
echo "TPM device did not appear"
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel