Software TPM Emulator For QEMU
Introduction
Trusted Platform Module (TPM) is a component to provide several security functions, e.g. encryption, random number generation, measurement, etc., and now widely deployed among the new machines due to the requirement of Windows 10 certification. For the developers who want to use TPM to develop the security features, a software TPM emulator is usually a good choice. Before 2.11, QEMU can only do TPM passthrough to access the TPM hardware on the host, and this limits the number of guests to access TPM. Besides, the developers are also limited by the hardware capabilities. It's impossible to develop the TPM 2.0 features with a TPM 1.2 chip. Fortunately, since 2.11, QEMU starts to support the TPM emulator. With TPM emulator, the guest can switch between TPM 1.2 and TPM 2.0 easily, and this makes the developer's life much easier.
Install the Software TPM Emulator
The software TPM emulator swtpm is curently included in openSUSE Tumbleweed. For other products and versions the packages are available in the "security" repo:
https://software.opensuse.org//download.html?project=security&package=swtpm
Just download libtpms0 and swtpm and install them.
Setup a TPM Emulator
swtpm provides 3 types of interface: socket, chardev, and cuse. Here we choose "socket" since it's the only type that doesn't need to create a node in /dev. First, create a directory to store the TPM states right inside the VM directory:
$ mkdir ${path_to_vm}/mytpm0
And then, start the emulator to create a socket file, swtpm-sock, for QEMU.
$ swtpm socket --tpmstate dir=${path_to_vm}/mytpm0 \ --ctrl type=unixio,path=${path_to_vm}/mytpm0/swtpm-sock \ --log level=20
By default, swtpm starts a TPM 1.2 emulator and stores the states in "tpm-00.permall" in the directory. It's also possible to create a TPM 2.0 instance:
$ swtpm socket --tpm2 --tpmstate dir=${path_to_vm}/mytpm0 \ --ctrl type=unixio,path=${path_to_vm}/mytpm0/swtpm-sock \ --log level=20
The TPM 2.0 states will be stored in "tpm2-00.permall". If you want swtpm to run in the background, just add "-d" to daemonize it.
Start QEMU along with swtpm
Once you start swtpm, add the following QEMU parameters to create the TPM device:
- For x86_64:
-chardev socket,id=chrtpm,path=${path_to_vm}/mytpm0/swtpm-sock \ -tpmdev emulator,id=tpm0,chardev=chrtpm \ -device tpm-tis,tpmdev=tpm0
- For aarch64:
-chardev socket,id=chrtpm,path=${path_to_vm}/mytpm0/swtpm-sock \ -tpmdev emulator,id=tpm0,chardev=chrtpm \ -device tpm-tis-device,tpmdev=tpm0
The difference is the device name: tpm-tis vs tpm-tis-device
Then, a TPM device will be available in the guest, and "tpm_version" would show you:
TPM 1.2 Version Info: Chip Version: 1.2.18.158 Spec Level: 2 Errata Revision: 3 TPM Vendor ID: IBM TPM Version: 01010000 Manufacturer Info: 49424d00
Start swtpm with libvirt
If you use libvirt, add the following TPM emulator device to template:
<devices> <tpm model='tpm-tis'> <backend type='emulator' version='2.0'/> </tpm> </devices>
libvirt will start swtpm as the TPM emulator for the guest VM. You don't need to launch swtpm daemon by yourself.
The tpm-crb TPM model can also be used, but it's only for TPM 2.0.
The corresponding permall file will be created automatically in /var/lib/libvirt/swtpm/[VM_UUID]
e.g.
# ls /var/lib/libvirt/swtpm/00c1ee41-3150-4d24-80b4-ab032732653c/tpm2/ .lock tpm2-00.permall
The above UUID follows the number in libvirt template.
TPM measurement in OVMF
If you use OVMF firmware for the guest, then the firmware will measure components with TPM.
After booting, kernel exposes the event log by securityfs:
/sys/kernel/security/tpm0/binary_bios_measurements