Linaro Logo

How to emulate Trusted Platform module in QEMU with U-Boot

Ilias Apalodimas

Ilias Apalodimas

Thursday, January 6, 202215 min read

Submit

Do I need a Trusted Platform Module (TPM)?

The short answer is “yes you do”.

TPMs are microcontrollers designed for cryptographic tasks. Don’t think of them as crypto accelerators though, since carrying out cryptographic operations on your CPU will always be faster. However they can encrypt and decrypt information and have a significant advantage over your CPU doing so, since the keys are tied to the TPM. When the TPM is initially configured, it generates a Storage Root Key or SRK. You can then ask the TPM to generate a new keypair for you, which the TPM will encrypt using the SRK, and hand it over to the caller. When the OS needs to encrypt or decrypt something, it loads the key into the TPM. The TPM then decrypts the key and performs the requested operation.

Another interesting functionality of the TPM is the ability to measure the system state using Platform Configuration Registers or PCRs, combined with the key ‘sealing and unsealing’.

PCRs start zeroed out and can only be reseted if on a system reboot. Those can be extended by writing a SHA hash (typically SHA-1/256/384/512 for TPMv2) into the PCR. The TPM concatenates the new hash to the existing PCR value and another SHA is calculated. This new value is now stored in the PCR.

TPMs also have the ability to seal and unseal keys. They can create and secure keys bound to specific platform states (and thus measurements). In order to unseal the key, the PCRs have to contain the exact same values that they had when the key was sealed. So for example you can create an encrypted filesystem with the encryption key sealed safely into your TPM. The filesystem will only be decrypted if the TPM ends up in the expected state.

On typical measured boot scenarios the firmware (or even BL1 is some devices) hashes itself to specific PCRs. So you can have for example BL2 measure itself and then measure BL31, BL32, BL33 and even GRUB config files, commands, Linux initrd etc. This effectively creates a chain of trust, which guarantees system components that we choose to measure have not been modified. Changing any of these would result in a different set of hash values.

U-Boot Support

There is a specification defining a standard interface to the TPM on an UEFI platform. Its purpose is to define APIs and provide information, for things like, is a TPM present, which PCR banks are active, change active PCR banks, obtain the TCG boot log, extend hashes to PCRs, append events to the TCG boot log etc. U-Boot recently got support for this, as well as support for the TCG PC Client Platform Firmware Profile. Patches for U-Boot were contributed by Linaro and can be found here, here and here. It can be tricky to find an Arm device with a TPMv2. If you have a board with an RPMB and OP-TEE support, we recommend trying Microsoft’s fTPM. However testing that in QEMU won’t work since it lacks RPMB emulation. Luckily there is another solution.

Using SWTPM

SWTPM is a TPM emulator that works under QEMU. It provides a memory mapped device which adheres to the TCG TPM Interface Specification. U-Boot lacked an MMIO TPMv2 driver up until this patchset.

Building U-Boot

git clone https://github.com/u-boot/u-boot.git
pushd u-boot
make qemu_arm64_defconfig
make menuconfig

The qemu defconfig includes the needed CONFIG_TPM, CONFIG_TPM2_MMIO and CONFIG_EFI_TCG2_PROTOCOL options. Make sure you enable CONFIG_CMD_EFIDEBUG as well, since we will need it to boot our kernel.

make -j $(nproc)
popd

Running QEMU

Make sure swtpm is installed and running on your system. For Debian and friends there’s a swtpm package, so just do

sudo apt install swtpm
mkdir /tmp/mytpm1
swtpm socket --tpmstate dir=/tmp/mytpm1 \
    --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \
    --log level=40 --tpm2 -t -d

and launch QEMU with swtpm support

qemu-system-aarch64 -nographic -no-acpi \
-bios u-boot.bin -machine virt \
-cpu cortex-a57 -m 2G \
-drive if=virtio,file=<your qcow2> \
-chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \  	-tpmdev emulator,id=tpm0,chardev=chrtpm \
-device tpm-tis-device,tpmdev=tpm0

Booting linux

From U-Boot’s command line do something along the lines of

virtio scan
efidebug boot add -b 0 'Linux' virtio 0 boot/Image -s 'root=/dev/vda'
efidebug boot order 0
bootefi bootmgr

If everything is compiled and launched correctly, you should see the kernel reporting the location of some related EventLog pointers.

efi: EFI v2.80 by Das U-Boot
efi: TPMFinalLog=0x13ddcc040 RTPROP=0x13ddcb040 SMBIOS=0xffffe000
TPMEventLog=0x13ddc4040 MEMRESERVE=0x13ddc3040

Reading the EventLog

I am using a debian qcow2 image, where I have installed the latest tpm2 tools. If you don’t have them install them with

sudo apt install tpm2-tools

The kernel exposes the eventlog in /sys. So you can read it with:

tpm2_eventlog /sys/kernel/security/tpm0/binary_bios_measurements
---
events:
  - EventNum: 0
    PCRIndex: 0
    EventType: EV_NO_ACTION
    Digest: "0000000000000000000000000000000000000000"
    EventSize: 37
    SpecID:
      - Signature: Spec ID Event03
        platformClass: 0
        specVersionMinor: 0
        specVersionMajor: 2
        specErrata: 2
        uintnSize: 2
        numberOfAlgorithms: 2
        Algorithms:
          - Algorithm[0]:
            algorithmId: sha1
            digestSize: 20
          - Algorithm[1]:
            algorithmId: sha256
            digestSize: 32
        vendorInfoSize: 0
  - EventNum: 1
    PCRIndex: 0
    EventType: EV_S_CRTM_VERSION
    DigestCount: 2
  Digests:
      - AlgorithmId: sha1
        Digest: "0772fd675fbebcdd4401008ee8d609760c1675df"
      - AlgorithmId: sha256
        Digest: "69f66450f9a8780cf2fbab358d46b8fabd4b7e9ae886b3d80083646c30e91b4c"
    EventSize: 74
    Event: "552d426f6f7420323032312e31302d7263322d30303031302d67643536666231666138352d646972747920284175672032342032303231202d2030363a33343a3335202b303830302900"
  - EventNum: 2
    PCRIndex: 7
    EventType: EV_EFI_VARIABLE_DRIVER_CONFIG
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "57cd4dc19442475aa82743484f3b1caa88e142b8"
      - AlgorithmId: sha256
        Digest: "115aa827dbccfb44d216ad9ecfda56bdea620b860a94bed5b7a27bba1c4d02d8"
    EventSize: 53
    Event:
      VariableName: 61dfe48b-ca93-d211-aa0d-00e098032b8c
      UnicodeNameLength: 10
      VariableDataLength: 1
      UnicodeName: SecureBoot
      VariableData: "00"
  - EventNum: 3
    PCRIndex: 7
    EventType: EV_EFI_VARIABLE_DRIVER_CONFIG
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "9b1387306ebb7ff8e795e7be77563666bbf4516e"
      - AlgorithmId: sha256
        Digest: "dea7b80ab53a3daaa24d5cc46c64e1fa9ffd03739f90aadbd8c0867c4a5b4890"
    EventSize: 36
    Event:
      VariableName: 61dfe48b-ca93-d211-aa0d-00e098032b8c
      UnicodeNameLength: 2
      VariableDataLength: 0
      UnicodeName: PK
  - EventNum: 4
    PCRIndex: 7
    EventType: EV_EFI_VARIABLE_DRIVER_CONFIG
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "9afa86c507419b8570c62167cb9486d9fc809758"
      - AlgorithmId: sha256
        Digest: "e670e121fcebd473b8bc41bb801301fc1d9afa33904f06f7149b74f12c47a68f"
    EventSize: 38
    Event:
      VariableName: 61dfe48b-ca93-d211-aa0d-00e098032b8c
      UnicodeNameLength: 3
      VariableDataLength: 0
      UnicodeName: KEK
  - EventNum: 5
    PCRIndex: 7
    EventType: EV_EFI_VARIABLE_DRIVER_CONFIG
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "5bf8faa078d40ffbd03317c93398b01229a0e1e0"
      - AlgorithmId: sha256
        Digest: "baf89a3ccace52750c5f0128351e0422a41597a1adfd50822aa363b9d124ea7c"
    EventSize: 36
    Event:
      VariableName: cbb219d7-3a3d-9645-a3bc-dad00e67656f
      UnicodeNameLength: 2
      VariableDataLength: 0
      UnicodeName: db
  - EventNum: 6
    PCRIndex: 7
    EventType: EV_EFI_VARIABLE_DRIVER_CONFIG
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "734424c9fe8fc71716c42096f4b74c88733b175e"
      - AlgorithmId: sha256
        Digest: "9f75b6823bff6af1024a4e2036719cdd548d3cbc2bf1de8e7ef4d0ed01f94bf9"
    EventSize: 38
    Event:
      VariableName: cbb219d7-3a3d-9645-a3bc-dad00e67656f
      UnicodeNameLength: 3
      VariableDataLength: 0
      UnicodeName: dbx
  - EventNum: 7
    PCRIndex: 4
    EventType: EV_EFI_BOOT_SERVICES_APPLICATION
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "d2702383b2e042ebefbb318f9382fd094c1c2d6b"
      - AlgorithmId: sha256
        Digest: "8fb6a4c7a0c7e7f22b944906eb07786cd3860394c7929e7c0768b2c99a2a3d87"
    EventSize: 162
    Event:
      ImageLocationInMemory: 0x7adb3000
      ImageLengthInMemory: 893720
      ImageLinkTimeAddress: 0x0
      LengthOfDevicePath: 130
      DevicePath: "01041400b9731de684a3cc4aaeab82e828f3628b031d050002031d05000104012a0001000000009800000000000000f805000000000050641c65888b6b418f2257061a9dc3c50202040436005c004500460049005c00640065006200690061006e005c007300680069006d0061006100360034002e0065006600690000007fff0400"
  - EventNum: 8
    PCRIndex: 1
    EventType: Unknown event type
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "50eb6bd100c48e81644d666a437725f49c6aed3c"
      - AlgorithmId: sha256
        Digest: "eb881b78feeb95756141a8d5358b891b297fad61b296f667de1f59b66bc92f4f"
    EventSize: 52
    Event: "61dfe48bca93d211aa0d00e098032b8c0900000000000000020000000000000042006f006f0074004f0072006400650072000000"
  - EventNum: 9
    PCRIndex: 1
    EventType: Unknown event type
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "74e29a0674816dfdfc2c2e9cbbcec357132da4e8"
      - AlgorithmId: sha256
        Digest: "5d123811f51e2e46c437c7e88e07053c81f4e63da3f11de8a8a2afb5334db137"
    EventSize: 198
    Event: "61dfe48bca93d211aa0d00e098032b8c0800000000000000960000000000000042006f006f0074003000300030003000010000008200640065006200690061006e00000001041400b9731de684a3cc4aaeab82e828f3628b031d050002031d05000104012a0001000000009800000000000000f805000000000050641c65888b6b418f2257061a9dc3c50202040436005c004500460049005c00640065006200690061006e005c007300680069006d0061006100360034002e0065006600690000007fff0400"
  - EventNum: 10
    PCRIndex: 4
    EventType: EV_EFI_ACTION
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "cd0fdb4531a6ec41be2753ba042637d6e5f7f256"
      - AlgorithmId: sha256
        Digest: "3d6772b4f84ed47595d72a2c4c5ffd15f5bb72c7507fe26f2aaee2c69d5633ba"
    EventSize: 40
    Event: 'Calling EFI Application from Boot Option'
  - EventNum: 11
    PCRIndex: 0
    EventType: EV_SEPARATOR
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "9069ca78e7450a285173431b3e52c5c25299e473"
      - AlgorithmId: sha256
        Digest: "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"
    EventSize: 4
    Event: "00000000"
  - EventNum: 12
    PCRIndex: 1
    EventType: EV_SEPARATOR
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "9069ca78e7450a285173431b3e52c5c25299e473"
      - AlgorithmId: sha256
        Digest: "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"
    EventSize: 4
    Event: "00000000"
  - EventNum: 13
    PCRIndex: 2
    EventType: EV_SEPARATOR
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "9069ca78e7450a285173431b3e52c5c25299e473"
      - AlgorithmId: sha256
        Digest: "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"
    EventSize: 4
    Event: "00000000"
  - EventNum: 14
    PCRIndex: 3
    EventType: EV_SEPARATOR
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "9069ca78e7450a285173431b3e52c5c25299e473"
      - AlgorithmId: sha256
        Digest:
"df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"
    EventSize: 4
    Event: "00000000"
  - EventNum: 15
    PCRIndex: 4
    EventType: EV_SEPARATOR
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "9069ca78e7450a285173431b3e52c5c25299e473"
      - AlgorithmId: sha256
        Digest: "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"
    EventSize: 4
    Event: "00000000"
  - EventNum: 16
    PCRIndex: 5
    EventType: EV_SEPARATOR
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "9069ca78e7450a285173431b3e52c5c25299e473"
      - AlgorithmId: sha256
        Digest: "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"
    EventSize: 4
    Event: "00000000"
  - EventNum: 17
    PCRIndex: 6
    EventType: EV_SEPARATOR
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "9069ca78e7450a285173431b3e52c5c25299e473"
      - AlgorithmId: sha256
        Digest: "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"
    EventSize: 4
    Event: "00000000"
  - EventNum: 18
    PCRIndex: 7
    EventType: EV_SEPARATOR
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "9069ca78e7450a285173431b3e52c5c25299e473"
      - AlgorithmId: sha256
        Digest: "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"
    EventSize: 4
    Event: "00000000"
  - EventNum: 19
    PCRIndex: 5
    EventType: EV_EFI_ACTION
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "443a6b7b82b7af564f2e393cd9d5a388b7fa4a98"
      - AlgorithmId: sha256
        Digest: "d8043d6b7b85ad358eb3b6ae6a873ab7ef23a26352c5dc4faa5aeedacf5eb41b"
    EventSize: 29
    Event: 'Exit Boot Services Invocation'
  - EventNum: 20
    PCRIndex: 5
    EventType: EV_EFI_ACTION
    DigestCount: 2
    Digests:
      - AlgorithmId: sha1
        Digest: "475545ddc978d7bfd036facc7e2e987f48189f0d"
      - AlgorithmId: sha256
        Digest: "b54f7542cbd872a81a9d9dea839b2b8d747c7ebd5ea6615c40f42f44a6dbeba0"
    EventSize: 40
    Event: 'Exit Boot Services Returned with Success'
pcrs:
  sha1:
    0  : 0x3e26be54f5f15140afbe509cc4580538d979598d
    1  : 0x5b4c188c39baa249f688460a63b68df6d3d3ec94
    2  : 0xb2a83b0ebf2f8374299a5b2bdfc31ea955ad7236
    3  : 0xb2a83b0ebf2f8374299a5b2bdfc31ea955ad7236
    4  : 0x260ae65533f38ab643f157bd176c72f9fdece410
    5  : 0xd16d7e629fd8d08ca256f9ad3a3a1587c9e6cc1b
    6  : 0xb2a83b0ebf2f8374299a5b2bdfc31ea955ad7236
    7  : 0x518bd167271fbb64589c61e43d8c0165861431d8
  sha256:
    0  :
0x7f35c1ef1bb7b9d2aee58ec4c36cf384d70524c2ce2b6801772d7fdb1d2b5f5a
    1  : 0xf35b74319598e48a6a69a6a04e903a872558b891563b0af23c877c8472c277a6
    2  : 0x3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969
    3  : 0x3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969
    4  : 0xbe4d7464e3a3c0a04040355368006a5fbe02c0ef232c8c18926df9b718374f36
    5  : 0xa5ceb755d043f32431d63e39f5161464620a3437280494b5850dc1b47cc074e0
    6  : 0x3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969
    7  : 0x65caf8dd1e0ea7a6347b635d2b379c93b9a1351edc2afc3ecda700e534eb3068

For more information on the work Linaro does in securing edge devices, go to our Trusted Substrate project page. Trusted Substrate is an integrated firmware solution made of all necessary components to implement Arm SystemReady standards with more security options turned on.