Skip to content

Hardware Security Module (TPM) Setup with dm-verity and Encrypted Storage

Introduction

Hardware-based security is critical for production Raspberry Pi deployments, especially in IoT, edge computing, and industrial applications. While Raspberry Pi doesn't have a built-in Trusted Platform Module (TPM), external TPM modules and software-based security measures can provide robust protection for sensitive data and system integrity.

This comprehensive guide covers:

  • External TPM Modules: Integrating SPI/I2C TPM chips (TPM 2.0)
  • dm-verity: Read-only root filesystem with integrity checking
  • LUKS Encryption: Full disk encryption for data partitions
  • Secure Boot: Verifying boot chain integrity
  • Key Management: Hardware-backed key storage
  • Measured Boot: TPM-based boot attestation
  • Practical Deployment: Production-ready security configurations

Essential for:

  • Industrial IoT: Protecting edge devices from tampering
  • Payment Systems: PCI DSS compliance requirements
  • Medical Devices: HIPAA-compliant data protection
  • Smart City Infrastructure: Securing public deployments
  • Government Applications: Meeting security certifications
  • Financial Services: Secure transaction processing
  • Critical Infrastructure: Preventing unauthorized access

Understanding TPM and Security Concepts

What is a TPM?

A Trusted Platform Module (TPM) is a dedicated microcontroller designed to secure hardware through integrated cryptographic keys.

Key Features: - Platform Configuration Registers (PCRs): Store boot measurements - Endorsement Key (EK): Unique, permanent key burned during manufacturing - Storage Root Key (SRK): Master key for encrypting other keys - Attestation Identity Key (AIK): Proves TPM authenticity - Non-Volatile RAM: Secure storage for keys and data - Random Number Generator: True hardware RNG

dm-verity Overview

dm-verity (Device-Mapper Verity) provides transparent integrity checking for read-only block devices.

How it works: 1. Creates a hash tree of the entire filesystem 2. Stores root hash in kernel command line 3. Verifies every block read from disk 4. Panics system if corruption detected (fail-secure)

Benefits: - Detects any unauthorized filesystem modification - Prevents rootkit installation - Ensures system integrity from boot to runtime - Minimal performance overhead (~1-3%)

LUKS Encryption

Linux Unified Key Setup (LUKS) provides full disk encryption with multiple key management options.

Features: - Industry-standard AES-XTS encryption - Multiple key slots (up to 8) - Key derivation function (PBKDF2/Argon2) - Header backup and recovery - Hardware acceleration support

Hardware Requirements

Module Interface Chip Price Compatibility
Infineon SLB9670 SPI TPM 2.0 $15-20 Pi 3/4/5
Infineon OPTIGA I2C TPM 2.0 $10-15 Pi 3/4/5
LetsTrust TPM SPI TPM 2.0 $25-30 Pi 4/5 (official)
Pi-TS TPM Module GPIO TPM 2.0 $20-25 Pi 3/4

Hardware Setup Requirements

Minimum: - Raspberry Pi 4 (4GB) or newer - MicroSD card (32GB+, Class 10) - External TPM module (SPI or I2C)

Recommended: - Raspberry Pi 5 (8GB) - NVMe SSD (for better encryption performance) - External TPM module (LetsTrust or Infineon) - Active cooling (encryption is CPU-intensive)

Optimal: - Raspberry Pi 5 (8GB) - NVMe SSD with hardware encryption - LetsTrust TPM 2.0 module - ICE Tower cooler - UPS or battery backup

Installing TPM Hardware

SPI TPM Module (Infineon SLB9670)

Wiring:

1
2
3
4
5
6
7
TPM Pin    → Raspberry Pi Pin
VCC (3.3V) → Pin 1 (3.3V)
GND        → Pin 6 (GND)
SCK        → Pin 23 (GPIO 11, SPI0_SCLK)
MOSI       → Pin 19 (GPIO 10, SPI0_MOSI)
MISO       → Pin 21 (GPIO 9, SPI0_MISO)
CS         → Pin 24 (GPIO 8, SPI0_CE0)

Enable SPI:

1
2
3
4
5
6
7
8
# Edit config.txt
sudo nano /boot/firmware/config.txt

# Add or uncomment:
dtparam=spi=on

# Reboot
sudo reboot

Verify SPI:

1
2
3
4
5
6
7
# Check SPI is enabled
lsmod | grep spi
# Should show: spi_bcm2835

# Check device
ls /dev/spi*
# Should show: /dev/spidev0.0  /dev/spidev0.1

I2C TPM Module (Infineon OPTIGA)

Wiring:

1
2
3
4
5
TPM Pin    → Raspberry Pi Pin
VCC (3.3V) → Pin 1 (3.3V)
GND        → Pin 9 (GND)
SDA        → Pin 3 (GPIO 2, I2C1_SDA)
SCL        → Pin 5 (GPIO 3, I2C1_SCL)

Enable I2C:

1
2
3
4
5
6
7
8
# Edit config.txt
sudo nano /boot/firmware/config.txt

# Add or uncomment:
dtparam=i2c_arm=on

# Reboot
sudo reboot

Verify I2C:

# Install i2c-tools
sudo apt install i2c-tools

# Scan for devices (TPM usually at 0x2e or 0x2f)
sudo i2cdetect -y 1
#      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
# 00:          -- -- -- -- -- -- -- -- -- -- -- -- --
# 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- 2e --
# 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

Device Tree Overlay

Create custom overlay for TPM:

# For SPI TPM
sudo tee /boot/firmware/overlays/tpm-spi.dts <<'EOF'
/dts-v1/;
/plugin/;

/ {
    compatible = "brcm,bcm2835";

    fragment@0 {
        target = <&spi0>;
        __overlay__ {
            status = "okay";

            tpm@0 {
                compatible = "infineon,slb9670";
                reg = <0>;
                spi-max-frequency = <32000000>;
                status = "okay";
            };
        };
    };
};
EOF

# Compile overlay
sudo dtc -@ -I dts -O dtb -o /boot/firmware/overlays/tpm-spi.dtbo /boot/firmware/overlays/tpm-spi.dts

# Enable in config.txt
echo "dtoverlay=tpm-spi" | sudo tee -a /boot/firmware/config.txt

# Reboot
sudo reboot

TPM Software Setup

Install TPM2 Tools

# Update system
sudo apt update
sudo apt full-upgrade -y

# Install TPM2 software stack
sudo apt install -y \
    tpm2-tools \
    tpm2-abrmd \
    libtpm2-pkcs11-1 \
    libtpm2-pkcs11-tools \
    libtss2-dev \
    libtss2-esys-3.0.2-0 \
    tpm2-tss

# Install optional tools
sudo apt install -y \
    clevis \
    clevis-tpm2 \
    clevis-luks

Enable TPM Resource Manager

# Start TPM2 Access Broker & Resource Manager
sudo systemctl enable tpm2-abrmd
sudo systemctl start tpm2-abrmd

# Verify service
sudo systemctl status tpm2-abrmd

# Check TPM device
ls -l /dev/tpm*
# Should show: /dev/tpm0  /dev/tpmrm0

Test TPM Communication

# Read TPM capabilities
tpm2_getcap properties-fixed

# Sample output:
# TPM2_PT_FAMILY_INDICATOR:
#   raw: 0x322E3000
#   value: "2.0"
# TPM2_PT_MANUFACTURER:
#   raw: 0x49465800
#   value: "IFX"
# ...

# Read PCR values
tpm2_pcrread

# Generate random number
tpm2_getrandom --hex 32

# Test TPM self-test
tpm2_selftest

Initialize TPM

# Clear TPM (WARNING: Deletes all keys!)
tpm2_clear -c p

# Create primary key in owner hierarchy
tpm2_createprimary -C o -g sha256 -G rsa -c primary.ctx

# Create Storage Root Key (SRK)
tpm2_createprimary -C o -g sha256 -G rsa -c srk.ctx

# Make SRK persistent
tpm2_evictcontrol -C o -c srk.ctx 0x81000001

# Verify persistent handle
tpm2_getcap handles-persistent
# Should show: 0x81000001

dm-verity Setup

dm-verity creates a read-only, tamper-proof root filesystem.

Prepare System

# Install required tools
sudo apt install -y \
    cryptsetup \
    cryptsetup-initramfs \
    veritysetup

# Backup current system
sudo dd if=/dev/mmcblk0p2 of=/mnt/backup/rootfs.img bs=4M status=progress

# Create separate data partition for writable data
sudo fdisk /dev/mmcblk0
# Create new partition /dev/mmcblk0p3 for /var, /home, etc.

Create Verity Hash Tree

# Assume /dev/mmcblk0p2 is root partition
ROOT_DEV="/dev/mmcblk0p2"
ROOT_SIZE=$(blockdev --getsz $ROOT_DEV)

# Calculate hash tree size (typically ~1% of data size)
HASH_SIZE=$(echo "$ROOT_SIZE / 100" | bc)

# Shrink root partition to make room for hash
sudo resize2fs $ROOT_DEV $(echo "$ROOT_SIZE - $HASH_SIZE" | bc)s

# Create verity device
sudo veritysetup format \
    $ROOT_DEV \
    /dev/mmcblk0p4 \
    | tee verity-output.txt

# Sample output:
# VERITY header information for /dev/mmcblk0p4
# UUID:            1234-5678-9abc-def0
# Hash type:       1
# Data blocks:     524288
# Data block size: 4096
# Hash block size: 4096
# Hash algorithm:  sha256
# Salt:            abcdef1234567890...
# Root hash:       a1b2c3d4e5f6...

Extract Root Hash

1
2
3
4
5
6
7
# Extract root hash from output
ROOT_HASH=$(grep "Root hash:" verity-output.txt | awk '{print $3}')

echo "Root Hash: $ROOT_HASH"

# Save for later use
echo "$ROOT_HASH" | sudo tee /boot/firmware/verity-root-hash.txt

Update Boot Configuration

1
2
3
4
5
6
7
8
9
# Edit cmdline.txt
sudo nano /boot/firmware/cmdline.txt

# Add dm-verity parameters (single line):
# Original:
# console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait

# Modified (replace ROOT_HASH with actual hash):
# console=serial0,115200 console=tty1 root=/dev/dm-0 rootfstype=ext4 rootwait dm-mod.create="vroot,,,ro,0 1048576 verity 1 /dev/mmcblk0p2 /dev/mmcblk0p4 4096 4096 131072 1 sha256 ROOT_HASH abcdef1234567890"

Configure initramfs

# Create initramfs hook for dm-verity
sudo tee /etc/initramfs-tools/hooks/verity <<'EOF'
#!/bin/sh
PREREQ=""
prereqs()
{
    echo "$PREREQ"
}

case $1 in
prereqs)
    prereqs
    exit 0
    ;;
esac

. /usr/share/initramfs-tools/hook-functions

# Copy veritysetup
copy_exec /sbin/veritysetup /sbin

# Copy dm modules
manual_add_modules dm-verity
manual_add_modules dm-mod

exit 0
EOF

sudo chmod +x /etc/initramfs-tools/hooks/verity

# Update initramfs
sudo update-initramfs -u -k all

Test dm-verity

# Reboot with dm-verity
sudo reboot

# After reboot, verify verity is active
sudo dmsetup table vroot
# Should show verity configuration

# Check device mapper
lsblk
# Should show dm-0 mounted as /

# Try to modify root filesystem (should fail)
sudo touch /test-file
# Error: Read-only file system

# Mount data partition for writable files
sudo mkdir -p /data
sudo mount /dev/mmcblk0p3 /data

# Bind mount writable directories
sudo mount --bind /data/var /var
sudo mount --bind /data/home /home

Make Writable Mounts Persistent

1
2
3
4
5
6
7
8
9
# Edit fstab
sudo nano /etc/fstab

# Add data partition and bind mounts:
/dev/mmcblk0p3  /data           ext4    defaults,noatime  0  2
/data/var       /var            none    bind              0  0
/data/home      /home           none    bind              0  0
/data/tmp       /tmp            none    bind              0  0
/data/log       /var/log        none    bind              0  0

LUKS Encryption

Full disk encryption for data partitions.

Create Encrypted Partition

# Assuming /dev/mmcblk0p3 for data
DATA_DEV="/dev/mmcblk0p3"

# Initialize LUKS partition
sudo cryptsetup luksFormat \
    --type luks2 \
    --cipher aes-xts-plain64 \
    --key-size 512 \
    --hash sha256 \
    --iter-time 5000 \
    $DATA_DEV

# Enter passphrase when prompted

# Open encrypted device
sudo cryptsetup open $DATA_DEV cryptdata

# Create filesystem
sudo mkfs.ext4 /dev/mapper/cryptdata

# Mount
sudo mkdir -p /data
sudo mount /dev/mapper/cryptdata /data

TPM-Based LUKS Unlocking

Use TPM to automatically unlock encrypted partition on verified boot.

# Install clevis
sudo apt install -y clevis clevis-tpm2 clevis-luks

# Bind LUKS to TPM PCRs
sudo clevis luks bind -d $DATA_DEV tpm2 '{"pcr_ids":"0,1,2,3,4,5,6,7"}'

# Enter existing LUKS passphrase

# This stores unlock key in TPM, sealed to PCR values
# Partition will only unlock if PCRs match (boot integrity verified)

PCR Meanings: - PCR 0: BIOS/UEFI firmware - PCR 1: BIOS/UEFI configuration - PCR 2: Option ROMs - PCR 3: Option ROM configuration - PCR 4: Boot loader (GRUB/U-Boot) - PCR 5: Boot loader configuration - PCR 6: Resume from S4/S5 - PCR 7: Secure Boot state

Auto-unlock on Boot

# Install dracut for initramfs with clevis support
sudo apt install -y dracut dracut-network

# Configure dracut
sudo tee /etc/dracut.conf.d/clevis.conf <<EOF
add_dracutmodules+=" clevis clevis-pin-tpm2 "
install_items+=" /usr/bin/clevis-luks-unlock /usr/bin/luksmeta "
EOF

# Regenerate initramfs
sudo dracut -f

# Update crypttab for auto-unlock
echo "cryptdata $DATA_DEV none luks,_netdev,x-systemd.device-timeout=0" | sudo tee -a /etc/crypttab

# Reboot and test
sudo reboot

# After reboot, verify encrypted partition is mounted
mount | grep cryptdata
df -h /data

Backup LUKS Header

# Backup header (CRITICAL - allows recovery if header corrupted)
sudo cryptsetup luksHeaderBackup $DATA_DEV \
    --header-backup-file /root/luks-header-backup-$(date +%Y%m%d).img

# Copy backup to secure external location
sudo cp /root/luks-header-backup-*.img /mnt/usb-backup/

# Restore header (if needed)
# sudo cryptsetup luksHeaderRestore $DATA_DEV \
#     --header-backup-file /root/luks-header-backup-20250101.img

Secure Boot Implementation

U-Boot with Verified Boot

# Install U-Boot tools
sudo apt install -y u-boot-tools device-tree-compiler

# Create signing key
openssl genrsa -out keys/dev.key 2048
openssl req -batch -new -x509 -key keys/dev.key -out keys/dev.crt

# Sign kernel and device tree
mkimage -D "-I dts -O dtb -p 2000" -f auto -A arm64 -T kernel \
    -C none -a 0x00080000 -e 0x00080000 -n "Kernel" \
    -k keys -r kernel.img kernel.fit

# Update config.txt to use FIT image
echo "kernel=kernel.fit" | sudo tee -a /boot/firmware/config.txt

Measured Boot with TPM

Extend TPM PCRs during boot process:

# Create boot measurement script
sudo tee /usr/local/bin/measure-boot.sh <<'EOF'
#!/bin/bash

# Measure bootloader
sha256sum /boot/firmware/start4.elf | awk '{print $1}' | \
    xxd -r -p | tpm2_pcrextend 4:sha256=-

# Measure kernel
sha256sum /boot/firmware/kernel8.img | awk '{print $1}' | \
    xxd -r -p | tpm2_pcrextend 5:sha256=-

# Measure cmdline
sha256sum /boot/firmware/cmdline.txt | awk '{print $1}' | \
    xxd -r -p | tpm2_pcrextend 6:sha256=-

# Measure config
sha256sum /boot/firmware/config.txt | awk '{print $1}' | \
    xxd -r -p | tpm2_pcrextend 7:sha256=-

echo "Boot measurements extended to TPM PCRs"
EOF

sudo chmod +x /usr/local/bin/measure-boot.sh

# Run early in boot process
sudo tee /etc/systemd/system/measure-boot.service <<EOF
[Unit]
Description=Measure Boot Components to TPM
DefaultDependencies=no
Before=basic.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/measure-boot.sh
RemainAfterExit=yes

[Install]
WantedBy=basic.target
EOF

sudo systemctl enable measure-boot

Key Management with TPM

Store Application Keys in TPM

# Create a seal key (protected by TPM)
tpm2_createprimary -C o -c primary.ctx
tpm2_create -C primary.ctx -g sha256 -G aes -r seal.priv -u seal.pub

# Seal a secret
echo "MySecretData" | \
    tpm2_unseal -c seal.ctx

# Make persistent
tpm2_evictcontrol -C o -c seal.ctx 0x81000002

# Load and unseal
tpm2_unseal -c 0x81000002

Generate SSH Keys in TPM

# Create TPM-backed RSA key
tpm2_createprimary -C o -c primary.ctx
tpm2_create -C primary.ctx -G rsa2048 -u ssh.pub -r ssh.priv -a "sign"

# Load key
tpm2_load -C primary.ctx -u ssh.pub -r ssh.priv -c ssh.ctx

# Make persistent
tpm2_evictcontrol -C o -c ssh.ctx 0x81000003

# Extract public key for SSH
tpm2_readpublic -c 0x81000003 -f pem -o ssh_tpm.pem

# Convert to SSH format
ssh-keygen -i -m PKCS8 -f ssh_tpm.pem > ~/.ssh/id_rsa_tpm.pub

Certificate Storage

# Store TLS certificate private key in TPM
openssl genrsa -out temp.key 2048

# Import to TPM
tpm2_import -C 0x81000001 -G rsa -i temp.key -u cert.pub -r cert.priv

# Shred temporary key
shred -u temp.key

# Use with applications (e.g., nginx)
# Configure application to use TPM PKCS#11 interface

Remote Attestation

Verify system integrity remotely using TPM.

Create Attestation Identity

# Create AIK (Attestation Identity Key)
tpm2_createprimary -C e -c ek.ctx
tpm2_createprimary -C o -c srk.ctx

tpm2_create -C srk.ctx -G rsa -u aik.pub -r aik.priv -a "sign|fixedtpm|fixedparent|sensitivedataorigin"

tpm2_load -C srk.ctx -u aik.pub -r aik.priv -c aik.ctx

# Make persistent
tpm2_evictcontrol -C o -c aik.ctx 0x81000004

Quote PCR Values

1
2
3
4
5
6
7
# Generate attestation quote
tpm2_quote -c 0x81000004 -l sha256:0,1,2,3,4,5,6,7 -q test_nonce -m quote.msg -s quote.sig -o quote.pcrs

# Send quote.msg, quote.sig, quote.pcrs to verifier

# Verify quote on remote system
tpm2_checkquote -c aik.pub -m quote.msg -s quote.sig -f quote.pcrs -q test_nonce

Automated Attestation Service

#!/usr/bin/env python3
# attestation_server.py

import subprocess
import json
from flask import Flask, request, jsonify

app = Flask(__name__)

# Expected PCR values (golden measurements)
EXPECTED_PCRS = {
    "sha256": {
        "0": "a1b2c3d4...",  # BIOS measurement
        "4": "e5f6a7b8...",  # Bootloader
        "5": "c9d0e1f2...",  # Kernel
        "7": "a3b4c5d6..."   # Config
    }
}

@app.route('/attest', methods=['POST'])
def attest():
    """Verify device attestation"""
    data = request.json

    # Verify quote signature
    result = subprocess.run([
        'tpm2_checkquote',
        '-c', data['aik_pub'],
        '-m', data['quote_msg'],
        '-s', data['quote_sig'],
        '-f', data['quote_pcrs'],
        '-q', data['nonce']
    ], capture_output=True, text=True)

    if result.returncode != 0:
        return jsonify({"status": "failed", "reason": "Invalid quote signature"}), 403

    # Parse PCR values
    pcrs = json.loads(data['quote_pcrs'])

    # Compare against expected values
    for pcr_num, expected_hash in EXPECTED_PCRS["sha256"].items():
        actual_hash = pcrs["sha256"][pcr_num]
        if actual_hash != expected_hash:
            return jsonify({
                "status": "failed",
                "reason": f"PCR {pcr_num} mismatch",
                "expected": expected_hash,
                "actual": actual_hash
            }), 403

    # All checks passed
    return jsonify({
        "status": "success",
        "message": "Device attestation verified",
        "timestamp": data['timestamp']
    }), 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, ssl_context='adhoc')

Production Deployment

Complete Security Setup Script

#!/bin/bash
# secure-pi-setup.sh - Complete production security setup

set -e

echo "=== Raspberry Pi Hardware Security Setup ==="

# 1. Install TPM tools
echo "[1/8] Installing TPM software..."
apt update
apt install -y tpm2-tools tpm2-abrmd clevis clevis-tpm2 clevis-luks cryptsetup veritysetup

# 2. Initialize TPM
echo "[2/8] Initializing TPM..."
systemctl enable tpm2-abrmd
systemctl start tpm2-abrmd
tpm2_clear -c p
tpm2_createprimary -C o -g sha256 -G rsa -c /root/srk.ctx
tpm2_evictcontrol -C o -c /root/srk.ctx 0x81000001

# 3. Create encrypted data partition
echo "[3/8] Setting up encrypted storage..."
DATA_DEV="/dev/mmcblk0p3"
cryptsetup luksFormat --type luks2 --cipher aes-xts-plain64 --key-size 512 $DATA_DEV
cryptsetup open $DATA_DEV cryptdata
mkfs.ext4 /dev/mapper/cryptdata

# 4. Bind LUKS to TPM
echo "[4/8] Binding encryption to TPM..."
clevis luks bind -d $DATA_DEV tpm2 '{"pcr_ids":"0,1,2,3,4,5,6,7"}'

# 5. Setup dm-verity
echo "[5/8] Configuring dm-verity..."
ROOT_DEV="/dev/mmcblk0p2"
veritysetup format $ROOT_DEV /dev/mmcblk0p4 > /root/verity-output.txt
ROOT_HASH=$(grep "Root hash:" /root/verity-output.txt | awk '{print $3}')
echo "$ROOT_HASH" > /boot/firmware/verity-root-hash.txt

# 6. Update boot config
echo "[6/8] Updating boot configuration..."
# (Add dm-verity parameters to cmdline.txt)

# 7. Configure measured boot
echo "[7/8] Setting up measured boot..."
cp measure-boot.sh /usr/local/bin/
chmod +x /usr/local/bin/measure-boot.sh
systemctl enable measure-boot.service

# 8. Setup monitoring
echo "[8/8] Configuring security monitoring..."
cp tpm-monitor.sh /usr/local/bin/
systemctl enable tpm-monitor.timer

echo "=== Setup Complete ==="
echo "Root Hash: $ROOT_HASH"
echo "Please reboot to activate dm-verity"

Security Monitoring

#!/bin/bash
# tpm-monitor.sh - Monitor TPM and security status

LOG_FILE="/var/log/tpm-security.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

# Check TPM health
if ! tpm2_selftest; then
    log "ERROR: TPM self-test failed!"
    systemd-notify --ready --status="TPM health check failed"
    exit 1
fi

# Read current PCR values
tpm2_pcrread > /tmp/current-pcrs.txt

# Compare with baseline (if exists)
if [ -f /etc/tpm/baseline-pcrs.txt ]; then
    if ! diff -q /etc/tpm/baseline-pcrs.txt /tmp/current-pcrs.txt > /dev/null; then
        log "WARNING: PCR values changed! Possible boot tampering detected"

        # Send alert
        mail -s "TPM Security Alert" admin@example.com < /tmp/current-pcrs.txt

        # Log differences
        diff /etc/tpm/baseline-pcrs.txt /tmp/current-pcrs.txt >> "$LOG_FILE"
    else
        log "INFO: PCR values match baseline"
    fi
else
    # Create baseline
    cp /tmp/current-pcrs.txt /etc/tpm/baseline-pcrs.txt
    log "INFO: Created PCR baseline"
fi

# Check dm-verity status
if ! dmsetup status vroot | grep -q "verity"; then
    log "ERROR: dm-verity not active!"
    exit 1
fi

# Check encrypted partition
if ! cryptsetup status cryptdata | grep -q "is active"; then
    log "ERROR: Encrypted partition not mounted!"
    exit 1
fi

log "INFO: All security checks passed"

Systemd Timer for Monitoring

# /etc/systemd/system/tpm-monitor.timer
[Unit]
Description=TPM Security Monitoring Timer

[Timer]
OnBootSec=5min
OnUnitActiveSec=1h

[Install]
WantedBy=timers.target

# /etc/systemd/system/tpm-monitor.service
[Unit]
Description=TPM Security Monitoring

[Service]
Type=oneshot
ExecStart=/usr/local/bin/tpm-monitor.sh

Enable monitoring:

sudo systemctl enable tpm-monitor.timer
sudo systemctl start tpm-monitor.timer

Troubleshooting

TPM Not Detected

# Check kernel modules
lsmod | grep tpm
# Should show: tpm_tis_spi, tpm_tis_core, tpm

# Load modules manually
sudo modprobe tpm_tis_spi
sudo modprobe tpm_tpm2

# Check dmesg for errors
dmesg | grep -i tpm

# Verify device tree
dtc -I fs /sys/firmware/devicetree/base | grep tpm

# Check SPI/I2C communication
# For SPI:
sudo cat /sys/kernel/debug/spi/spi0.0/stats

# For I2C:
sudo i2cdetect -y 1

dm-verity Boot Failure

# Boot to recovery mode
# Add "break=premount" to cmdline.txt

# In initramfs shell:
# Check verity parameters
cat /proc/cmdline

# Manually setup verity device
veritysetup open /dev/mmcblk0p2 vroot \
    /dev/mmcblk0p4 $(cat /boot/firmware/verity-root-hash.txt)

# Mount and check
mount /dev/dm-0 /root
ls /root

# If successful, check cmdline.txt syntax
# Ensure dm-mod.create parameters are correct

LUKS Unlock Failure

# Check clevis binding
sudo clevis luks list -d /dev/mmcblk0p3

# Manually unlock with passphrase
sudo cryptsetup open /dev/mmcblk0p3 cryptdata

# Re-bind to TPM
sudo clevis luks unbind -d /dev/mmcblk0p3 -s 1
sudo clevis luks bind -d /dev/mmcblk0p3 tpm2 '{"pcr_ids":"0,1,2,3,4,5,6,7"}'

# Check PCR values
tpm2_pcrread

# Regenerate initramfs
sudo dracut -f

PCR Values Changed Unexpectedly

# Identify which PCR changed
diff /etc/tpm/baseline-pcrs.txt <(tpm2_pcrread)

# Common causes:
# PCR 0-3: Firmware update
# PCR 4: Bootloader update
# PCR 5: Kernel update
# PCR 6: Boot configuration change
# PCR 7: Config.txt modification

# Update baseline after legitimate changes
tpm2_pcrread > /etc/tpm/baseline-pcrs.txt

# Re-seal LUKS keys
sudo clevis luks regen -d /dev/mmcblk0p3 -s 1

Performance Impact

Benchmarks (Raspberry Pi 5)

Without Security: - Boot time: 15 seconds - Sequential read: 450 MB/s (NVMe) - Sequential write: 400 MB/s (NVMe) - Random 4K read: 45 MB/s - Random 4K write: 40 MB/s

With dm-verity Only: - Boot time: 17 seconds (+13%) - Sequential read: 435 MB/s (-3%) - Sequential write: N/A (read-only root) - Random 4K read: 43 MB/s (-4%)

With LUKS Encryption (AES-XTS-256): - Boot time: 19 seconds (+27%) - Sequential read: 380 MB/s (-16%) - Sequential write: 340 MB/s (-15%) - Random 4K read: 38 MB/s (-16%) - Random 4K write: 34 MB/s (-15%)

With dm-verity + LUKS: - Boot time: 21 seconds (+40%) - Sequential read: 370 MB/s (-18%) - Sequential write: 335 MB/s (-16%)

CPU Usage (Encryption): - Idle: 2-5% (clevis monitoring) - Active encryption: 15-25% per core - AES hardware acceleration available on Pi 4/5

Optimization Tips

# 1. Use hardware crypto acceleration
# Already enabled by default on Pi 4/5

# 2. Optimize cryptsetup
sudo cryptsetup --perf-submit_from_crypt_cpus benchmark

# 3. Use faster hash for dm-verity (SHA256 vs SHA512)
# SHA256 recommended for better performance

# 4. Reduce verity block size (default 4096)
# Smaller blocks = more overhead but faster detection

# 5. Use NVMe instead of SD card
# 3-5× faster than SD cards

# 6. Enable CPU performance mode
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

Best Practices

1. Defense in Depth

1
2
3
4
5
6
7
# Layer multiple security measures:
# - dm-verity (integrity)
# - LUKS (confidentiality)
# - TPM (key protection)
# - Secure Boot (boot integrity)
# - Firewall (network protection)
# - SELinux/AppArmor (mandatory access control)

2. Key Management

1
2
3
4
5
6
7
8
9
# Use different keys for different purposes
# - Root of Trust (TPM SRK)
# - Disk encryption (LUKS master key)
# - Application keys (TPM-sealed)
# - SSH/TLS keys (TPM-backed)

# Rotate keys periodically
# Backup LUKS headers securely
# Use hardware RNG for key generation

3. Monitoring and Alerting

1
2
3
4
5
# Monitor TPM health
# Alert on PCR changes
# Log all security events
# Regular integrity checks
# Automated testing of recovery procedures

4. Update Strategy

1
2
3
4
# Test updates in staging environment
# Backup before updates
# Update baseline PCRs after verified updates
# Use A/B partitioning for rollback capability

5. Physical Security

1
2
3
4
# Tamper-evident enclosures
# Disable unused interfaces (USB, HDMI when possible)
# Secure boot configuration (read-only boot partition)
# Physical access controls

Summary

This guide covered comprehensive hardware security implementation:

✅ TPM Integration

  • External TPM 2.0 module setup (SPI/I2C)
  • TPM software stack installation
  • Key storage and management
  • Hardware-backed cryptography

✅ dm-verity

  • Read-only root filesystem
  • Hash tree generation
  • Integrity verification
  • Boot-time protection

✅ LUKS Encryption

  • Full disk encryption (AES-XTS-256/512)
  • TPM-sealed auto-unlock
  • Multiple key slots
  • Header backup and recovery

✅ Secure Boot

  • Verified boot chain
  • Measured boot with PCR extension
  • Boot component signing
  • FIT image support

✅ Remote Attestation

  • AIK creation
  • PCR quoting
  • Remote verification
  • Attestation server implementation

✅ Production Deployment

  • Complete setup automation
  • Security monitoring
  • Performance optimization
  • Troubleshooting procedures

✅ Real-World Performance

  • ~18% read overhead (dm-verity)
  • ~16% crypto overhead (LUKS)
  • ~40% boot time increase (full stack)
  • Hardware AES acceleration mitigates impact

Next Steps

Advanced Topics:

  1. Secure Element Integration - Add dedicated secure chips (ATECC608A)
  2. Hardware Wallets - Cryptocurrency key storage
  3. PKCS#11 Integration - Use TPM with standard crypto APIs
  4. HSM Clustering - Distributed key management
  5. Compliance Certification - FIPS 140-2/3, Common Criteria

Related Guides:

With proper HSM/TPM integration, dm-verity, and encryption, your Raspberry Pi achieves enterprise-grade security suitable for production deployments in critical infrastructure, financial services, and regulated industries.