This tutorial will guide you to set up the Mender Client on a Raspberry Pi 4/5 to use a TPM based on the Infineon SLB9672 through the PKCS#11 API.
Prerequisites
- A RPi4 or RPi5 with a LetsTrust / Infineon SLB9672 TPM physically attached. See the instructions for installation details
- The the getting started tutorial up to step 7
- SSH to the RPi as root
Enabling the TPM
The Raspberry Pi OS (Debian based reference distribution) ships with both SPI and the TPM disabled.
First, enable SPI as the physical transport connection layer to the TPM:
sed -i 's/^#dtparam=spi=on/dtparam=spi=on/' /boot/firmware/config.txt
Then append the slb9670 device-tree overlay to the boot config:
grep -qE '^dtoverlay=tpm-slb9670' /boot/firmware/config.txt \
|| echo 'dtoverlay=tpm-slb9670' >> /boot/firmware/config.txt
Reboot for the overlay to take effect, then ssh back in. Confirm that the kernel
actually exposed the TPM:
ls -l /dev/tpm0
Install the TPM and PKCS#11 packages
Install the base tpm2 tooling we’ll need:
apt-get update -qq
apt-get install -y \
tpm2-openssl tpm2-tools \
libtpm2-pkcs11-tools libtpm2-pkcs11-1 \
pkcs11-provider \
jq
As a confirmation that communication with the TPM works, read the properties and try generating some random bytes:
tpm2_getcap properties-fixed | head
# Example output:
# TPM2_PT_FAMILY_INDICATOR:
# raw: 0x322E3000
# value: "2.0"
# TPM2_PT_LEVEL:
# raw: 0
# TPM2_PT_REVISION:
# raw: 0x9F
# value: 1.59
# TPM2_PT_DAY_OF_YEAR:
# raw: 0xAC
tpm2_getrandom 4 --hex
# Example output:
# fe82d252
Wipe any stale TPM state
Clean the TPM to a blank slate so that there are no leftovers from eventual prior activities.
Do this to avoid surprises during the tutorial.
rm -rf /var/lib/tpm2-pkcs11 /root/.tpm2_pkcs11
tpm2_clear
Check that there are no handles left:
tpm2_getcap handles-persistent
Write the OpenSSL config
Generate a dedicated OpenSSL configuration file. This will contain the setup related to the Mender Client instead of polluting the global space. We’ll point the Mender services to this in a later step.
cat > /etc/mender-openssl.cnf <<'EOF'
openssl_conf = openssl_init
[openssl_init]
providers = provider_sect
[provider_sect]
default = default_sect
pkcs11 = pkcs11_sect
[default_sect]
activate = 1
[pkcs11_sect]
module = /usr/lib/aarch64-linux-gnu/ossl-modules/pkcs11.so
pkcs11-module-path = /usr/lib/aarch64-linux-gnu/pkcs11/libtpm2_pkcs11.so.1.9.0
activate = 1
EOF
Create the PKCS#11 token and the TPM-backed key
Generate the key in the TPM. We assume the address pins are on the 0000 default for the example. If your setup differs, you need to adjust accordingly.
mkdir -p /var/lib/tpm2-pkcs11
export TPM2_PKCS11_STORE=/var/lib/tpm2-pkcs11
tpm2_ptool init
TPM2_PKCS11_STORE=/var/lib/tpm2-pkcs11 \
tpm2_ptool addtoken --pid=1 --sopin=0000 --userpin=0000 --label=mender
TPM2_PKCS11_STORE=/var/lib/tpm2-pkcs11 \
tpm2_ptool addkey --label=mender --userpin=0000 --algorithm=ecc256 --key-label=device-key
As a test, reread the public key from the newly generated private key in the TPM:
PEM=$(OPENSSL_CONF=/etc/mender-openssl.cnf openssl pkey \
-provider default -provider pkcs11 \
-in 'pkcs11:token=mender;object=device-key;type=public' \
-pubin -pubout) \
&& printf '%s\n\nSHA-256: %s\n' "$PEM" "$(printf '%s\n' "$PEM" | sha256sum | cut -d' ' -f1)"
# Example output
# -----BEGIN PUBLIC KEY-----
# MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEk4J3wX6XF6lphz27WfaMTrQk6ycB
# DNNLmP5l7+6do7FK6+b35HV5/1fDVw7iOwNloDlsxFvkOJGM9IBfpAW1EA==
# -----END PUBLIC KEY-----
#
# SHA-256: 2a8167401d66b29c7177a1319f7f4af4d6cac27fe8b86e230f48594fb636566d
The TPM is now ready and the key is in place. The steps below this point adjust the Mender client to use the key from the TPM.
Stop the Mender Client daemons and remove the auto-generated key
By default the Mender client generates a private key on the rootfs. Stop the
services and delete it.
systemctl stop mender-authd mender-updated
rm -f /var/lib/mender/mender-agent.pem
Decommission the device in hosted Mender
Because of the steps from the getting started the device already attempted to reach Hosted Mender and is listed as accepted or pending. Decommission this device since the authentication was done with the default key. We will repeat this step with the key from the TPM.
Point both Mender daemons at the scoped cnf
Point mender-authd and mender-updated at the OpenSSL config via drop-in environment settings in their systemd units.
mkdir -p /etc/systemd/system/mender-authd.service.d \
/etc/systemd/system/mender-updated.service.d
cat > /tmp/tpm2.conf <<'EOF'
[Service]
Environment="OPENSSL_CONF=/etc/mender-openssl.cnf"
Environment="TPM2_PKCS11_STORE=/var/lib/tpm2-pkcs11"
EOF
cp /tmp/tpm2.conf /etc/systemd/system/mender-authd.service.d/tpm2.conf
cp /tmp/tpm2.conf /etc/systemd/system/mender-updated.service.d/tpm2.conf
systemctl daemon-reload
Point mender.conf at the TPM key
The getting started process populated the majority of fields in mender.conf needed to connect to hosted Mender. The only field we need to change is Security.AuthPrivateKey.
Set it to the PKCS#11 URI of the key just created:
KEY_URI='pkcs11:token=mender;object=device-key;type=private?pin-value=0000'
cp /etc/mender/mender.conf /etc/mender/mender.conf.bak
jq --arg key "$KEY_URI" '.Security.AuthPrivateKey = $key' \
/etc/mender/mender.conf.bak > /etc/mender/mender.conf
Start the Mender daemons again
Bring both daemons back up:
systemctl start mender-authd mender-updated
Accept the device in hosted Mender
At this point the device is trying to authorize with hosted Mender again, this time with the TPM key.
As you look at the authset from the key and what is printed in hosted Mender, you can confirm it’s now using the key from the TPM.
PEM=$(OPENSSL_CONF=/etc/mender-openssl.cnf openssl pkey \
-provider default -provider pkcs11 \
-in 'pkcs11:token=mender;object=device-key;type=public' \
-pubin -pubout) \
&& printf '%s\n\nSHA-256: %s\n' "$PEM" "$(printf '%s\n' "$PEM" | sha256sum | cut -d' ' -f1)"
# Example output
# -----BEGIN PUBLIC KEY-----
# MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEk4J3wX6XF6lphz27WfaMTrQk6ycB
# DNNLmP5l7+6do7FK6+b35HV5/1fDVw7iOwNloDlsxFvkOJGM9IBfpAW1EA==
# -----END PUBLIC KEY-----
#
# SHA-256: 2a8167401d66b29c7177a1319f7f4af4d6cac27fe8b86e230f48594fb636566d
Wrap up
Congratulations, you have successfully set up mender to use the TPM using the PKCS#11 provider!
You can accept the device and work with it in the same way as if using the default autogenerated key on the rootfs - without the risk of losing the device key material.
Are you already using TPMs or even pre-generated keys in your connected device? How did you streamline the provisioning process? Let us know!![]()
