Skip to content

Commit

Permalink
Add vTPM basic tests
Browse files Browse the repository at this point in the history
This change adds tests for vtpm functionalities. The tests require
XCP-ng 8.3 and a Debian UEFI VM.

The first test creates and destroys a vtpm device. A second test does
basic TPM tests (like message signing) using tpm2-tools.

The second test uses a locally defined fixture called unix_vm_with_vtpm
requiring an halted UEFI Unix VM. The fixture creates a vtpm device
associated to the vm. The vtpm device is destroyed once the tests are
done. The fixture also does a snapshot of the VM and revert it
afterward. This is because the script needs the package tpm2-tools to be
installed.

Signed-off-by: Thierry Escande <[email protected]>
  • Loading branch information
tescande committed Sep 5, 2023
1 parent 0d8f371 commit 41d158c
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 0 deletions.
Empty file added tests/vtpm/__init__.py
Empty file.
28 changes: 28 additions & 0 deletions tests/vtpm/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import pytest

@pytest.fixture(scope='module')
def uefi_unix_halted_vm(uefi_vm, unix_vm, halted_vm):
yield uefi_vm

@pytest.fixture(scope='module')
def unix_vm_with_vtpm(uefi_unix_halted_vm):
vm = uefi_unix_halted_vm
vtpm_uuid = None

if vm.get_vtpm() is None:
vtpm_uuid = vm.create_vtpm()

snapshot = vm.snapshot()

vm.start()

yield vm

# Tear down
if not vm.is_halted():
vm.shutdown(verify=True)

snapshot.destroy()

if vtpm_uuid is not None:
vm.destroy_vtpm()
107 changes: 107 additions & 0 deletions tests/vtpm/test_vtpm_basic_operations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import logging
import pytest
import lib.commands as commands

# These test are basic tests for vTPM devices.
# - Create / Destroy a vTPM device against a VM
# - Do some basic encryption tests using tpm2-tools package
#
# Requirements:
# - an XCP-ng host >= 8.3
# - a Debian based VM

from lib.common import PackageManagerEnum

vtpm_signing_test_script = """#!/bin/env bash
set -ex
apt-get install -y tpm2-tools > /dev/null
tpm2_selftest --fulltest
tpm2_getrandom 32 > /dev/null
TMPDIR=`mktemp -d`
# Create an Endorsement primary key
tpm2_createprimary --hierarchy e --key-context ${TMPDIR}/primary.ctx > /dev/null
# Create key objects
tpm2_create --key-algorithm rsa --public ${TMPDIR}/rsa.pub --private ${TMPDIR}/rsa.priv --parent-context \
${TMPDIR}/primary.ctx > /dev/null
# Load keys into the TPM
tpm2_load --parent-context ${TMPDIR}/primary.ctx --public ${TMPDIR}/rsa.pub --private ${TMPDIR}/rsa.priv \
--key-context ${TMPDIR}/rsa.ctx > /dev/null
# Delete loaded key files
rm -f ${TMPDIR}/rsa.pub ${TMPDIR}/rsa.priv
# Message to sign
echo 'XCP-ng Rulez' > ${TMPDIR}/message.dat
# Sign the message
tpm2_sign --key-context ${TMPDIR}/rsa.ctx --hash-algorithm sha256 --signature ${TMPDIR}/sig.rssa \
${TMPDIR}/message.dat > /dev/null
# Verify signature
tpm2_verifysignature --key-context ${TMPDIR}/rsa.ctx --hash-algorithm sha256 --message ${TMPDIR}/message.dat \
--signature ${TMPDIR}/sig.rssa > /dev/null
# Verify with another message
echo "XCP-ng Still Rulez" > ${TMPDIR}/message.dat
# Verify signature !!!!! THIS MUST FAIL !!!!!
if tpm2_verifysignature --key-context ${TMPDIR}/rsa.ctx --hash-algorithm sha256 --message ${TMPDIR}/message.dat \
--signature ${TMPDIR}/sig.rssa > /dev/null 2>&1; then
echo "Should not succeed"
exit 1
fi
rm -rf ${TMPDIR}
"""

@pytest.mark.small_vm
@pytest.mark.usefixtures("host_at_least_8_3")
def test_create_and_destroy_vtpm(host, uefi_unix_halted_vm):
vm = uefi_unix_halted_vm

vtpm_uuid = vm.get_vtpm()
if vtpm_uuid is not None:
logging.warning("This vm is already associated with a vtpm. Destroying it first")
vm.destroy_vtpm()

vtpm_uuid = vm.create_vtpm()

assert(vtpm_uuid is not None)

logging.info("vtpm created with uuid: %s" % vtpm_uuid)

vm.destroy_vtpm()

@pytest.mark.small_vm
@pytest.mark.usefixtures("host_at_least_8_3")
def test_vtpm(host, unix_vm_with_vtpm):
global vtpm_signing_test_script
vm = unix_vm_with_vtpm

# unix_vm_with_vtpm fixture starts the VM and stops it at teardown
# No need to call vm.start() here

# Also used to retreive the VM IP address
vm.wait_for_os_booted()

pkg_mgr = vm.detect_package_manager()
if pkg_mgr != PackageManagerEnum.APT_GET:
logging.error("This test requires a Debian based VM")
assert False

# Basic TPM2 tests with tpm2-tools
try:
logging.info("Running TPM2 test script on the VM")
out = vm.execute_script(vtpm_signing_test_script)
logging.info("*****\n%s\n*****" % out)
except commands.SSHCommandFailed as e:
logging.error("%s" % str(e))
assert False

0 comments on commit 41d158c

Please sign in to comment.