On Mon Mar 2, 2026 at 8:46 AM CST, Shiva Tripathi via lists.yoctoproject.org 
wrote:
> Add ti-encrypted-boot-initramfs for LUKS encryption with TPM-sealed
> keys. This provides full disk encryption using dm-crypt with keys
> sealed by firmware TPM (fTPM) running in OP-TEE and stored in eMMC RPMB.
>
> The initramfs includes:
> - Custom init script for in-place LUKS encryption on first boot
> - TPM key sealing/unsealing using persistent handle 0x81080001
> - Support for cryptsetup, tpm2-tools, and OP-TEE client
> - Automatic filesystem resize after encryption
>
> ti-encrypted-boot-initramfs builds when MACHINE_FEATURES contains
> 'luks-encryption'.
>
> Signed-off-by: Shiva Tripathi <[email protected]>
> ---
>  .../initramfs-ti-encrypted-init/files/init    | 324 ++++++++++++++++++
>  .../initramfs-ti-encrypted-init_1.0.bb        |  30 ++
>  .../initramfs/ti-encrypted-boot-initramfs.bb  |  50 +++
>  3 files changed, 404 insertions(+)
>  create mode 100644 
> meta-ti-bsp/recipes-ti/initramfs/initramfs-ti-encrypted-init/files/init
>  create mode 100644 
> meta-ti-bsp/recipes-ti/initramfs/initramfs-ti-encrypted-init_1.0.bb
>  create mode 100644 
> meta-ti-bsp/recipes-ti/initramfs/ti-encrypted-boot-initramfs.bb
>
> diff --git 
> a/meta-ti-bsp/recipes-ti/initramfs/initramfs-ti-encrypted-init/files/init 
> b/meta-ti-bsp/recipes-ti/initramfs/initramfs-ti-encrypted-init/files/init
> new file mode 100644
> index 00000000..6675b6ed
> --- /dev/null
> +++ b/meta-ti-bsp/recipes-ti/initramfs/initramfs-ti-encrypted-init/files/init
> @@ -0,0 +1,324 @@
> +#!/usr/bin/busybox sh
> +# TI SDK initramfs init script with LUKS2 + fTPM encryption support
> +
> +# Mount essential filesystems
> +/usr/bin/busybox echo "Initializing system..."
> +/usr/bin/busybox mount -t proc proc /proc
> +/usr/bin/busybox mount -t sysfs sysfs /sys
> +/usr/bin/busybox mount -t devtmpfs devtmpfs /dev
> +
> +# Configuration
> +BOOT_DEV="/dev/mmcblk1p1"           # Boot partition (FAT, unencrypted)
> +ROOT_DEV="/dev/mmcblk1p2"           # Root partition (will be encrypted)
> +CRYPT_NAME="root_crypt"
> +CRYPT_DEV="/dev/mapper/${CRYPT_NAME}"
> +BOOT_MNT="/boot_part"
> +TPM_PRIMARY_CTX="/tmp/tpm_primary.ctx"
> +TPM_KEY_PRIV="/tmp/tpm_key.priv"
> +TPM_KEY_PUB="/tmp/tpm_key.pub"
> +TPM_KEY_CTX="/tmp/tpm_key.ctx"
> +TPM2_HANDLE="0x81080001"            # TPM persistent handle for LUKS key
> +ENCRYPTION_MARKER="${BOOT_MNT}/.encryption_in_progress"
> +
> +# Wait for MMC device to appear (up to 10 seconds)
> +/usr/bin/busybox echo "Waiting for storage device..."
> +for i in 1 2 3 4 5 6 7 8 9 10; do
> +    if [ -b "${ROOT_DEV}" ]; then
> +        break
> +    fi
> +    /usr/bin/busybox sleep 1
> +done
> +
> +# Check if root device exists
> +if [ ! -b "${ROOT_DEV}" ]; then
> +    /usr/bin/busybox echo "ERROR: Storage device not found!"
> +    /usr/bin/busybox sh
> +fi
> +
> +# Mount boot partition
> +/usr/bin/busybox echo "Mounting boot partition..."
> +/usr/bin/busybox mkdir -p "${BOOT_MNT}"
> +if ! /usr/bin/busybox mount "${BOOT_DEV}" "${BOOT_MNT}"; then
> +    /usr/bin/busybox echo "ERROR: Failed to mount boot partition!"
> +    /usr/bin/busybox echo "Attempting standard boot..."
> +    /usr/bin/busybox mkdir -p /newroot
> +    /usr/bin/busybox mount "${ROOT_DEV}" /newroot
> +    exec /usr/sbin/switch_root /newroot /sbin/init
> +fi

The main boot path should be the error path here, not an arbitrary duplication
of logic.

> +
> +# Initialize fTPM in OP-TEE
> +/usr/bin/busybox echo "Initializing secure hardware(fTPM)..."
> +
> +# Start TEE supplicant (required for fTPM TA to work)
> +if [ -x /usr/sbin/tee-supplicant ]; then
> +    /usr/sbin/tee-supplicant -d &
> +    TEE_SUPPLICANT_PID=$!
> +    /usr/bin/busybox sleep 5
> +else
> +    /usr/bin/busybox echo "Warning: Trusted execution environment not 
> available"
> +fi
> +
> +# Load fTPM kernel module
> +if ! /sbin/modprobe tpm_ftpm_tee; then
> +    /usr/bin/busybox echo "Warning: TPM module failed to load"
> +fi
> +
> +# Wait for TPM device (up to 10 seconds)
> +for i in 1 2 3 4 5 6 7 8 9 10; do
> +    if [ -c /dev/tpmrm0 ]; then
> +        break
> +    fi
> +    /usr/bin/busybox sleep 1
> +done

This should be a function who's exit code is use in the below script directly
instead of rechecking if the device is present.

> +
> +# Check if TPM is available
> +TPM_AVAILABLE=0
> +if [ -c /dev/tpmrm0 ]; then
> +    TPM_AVAILABLE=1
> +    export TPM2TOOLS_TCTI="device:/dev/tpmrm0"
> +else
> +    /usr/bin/busybox echo "Warning: fTPM not available - encryption will be 
> skipped"
> +    if [ -n "${TEE_SUPPLICANT_PID}" ]; then
> +        /usr/bin/busybox kill "${TEE_SUPPLICANT_PID}" 2>/dev/null
> +    fi
> +fi
> +
> +# Function: Generate 32-byte random key using TPM RNG
> +generate_random_key() {
> +    if [ $TPM_AVAILABLE -eq 1 ]; then
> +        /usr/bin/tpm2_getrandom --hex 32
> +    else
> +        /usr/bin/busybox echo "ERROR: TPM not available for key generation"
> +        return 1
> +    fi
> +}

This should probably be reported to the user, or at least they should be told
how to access it during runtime.

> +
> +# Function: Seal data with TPM and store in persistent handle
> +tpm_seal_key() {
> +    local KEY_DATA="$1"
> +
> +    if [ $TPM_AVAILABLE -eq 0 ]; then
> +        /usr/bin/busybox echo "ERROR: TPM not available for sealing"
> +        return 1
> +    fi
> +
> +    # Create primary key in owner hierarchy
> +    /usr/bin/tpm2_createprimary -C o -c "${TPM_PRIMARY_CTX}" -Q || return 1
> +
> +    # Create sealed object
> +    /usr/bin/busybox echo -n "${KEY_DATA}" | \
> +        /usr/bin/tpm2_create -C "${TPM_PRIMARY_CTX}" \
> +        -u "${TPM_KEY_PUB}" -r "${TPM_KEY_PRIV}" \
> +        -i- -Q || return 1
> +
> +    # Load sealed object into TPM
> +    /usr/bin/tpm2_load -C "${TPM_PRIMARY_CTX}" \
> +        -u "${TPM_KEY_PUB}" -r "${TPM_KEY_PRIV}" \
> +        -c "${TPM_KEY_CTX}" -Q || return 1
> +
> +    # Make key persistent at handle (stored in TPM NV RAM - RPMB)
> +    /usr/bin/tpm2_evictcontrol -C o -c "${TPM_KEY_CTX}" "${TPM2_HANDLE}" || 
> return 1
> +
> +    return 0
> +}
> +
> +# Function: Unseal data from TPM persistent handle
> +tpm_unseal_key() {
> +    if [ $TPM_AVAILABLE -eq 0 ]; then
> +        /usr/bin/busybox echo "ERROR: TPM not available for unsealing" >&2
> +        return 1
> +    fi
> +
> +    # Check if persistent handle exists
> +    if ! /usr/bin/tpm2_getcap handles-persistent | grep -q "${TPM2_HANDLE}"; 
> then
> +        /usr/bin/busybox echo "ERROR: TPM persistent handle not found" >&2
> +        return 1
> +    fi
> +
> +    # Unseal key directly from persistent handle
> +    /usr/bin/tpm2_unseal -c "${TPM2_HANDLE}" || return 1
> +
> +    return 0
> +}
> +
> +# Function: Perform in-place LUKS encryption (first boot)
> +encrypt_root_filesystem() {
> +    /usr/bin/busybox echo "=========================================="
> +    /usr/bin/busybox echo "First boot: Encrypting root filesystem"
> +    /usr/bin/busybox echo "=========================================="
> +
> +    # Set marker to track encryption progress
> +    /usr/bin/busybox touch "${ENCRYPTION_MARKER}"
> +    /usr/bin/busybox sync
> +
> +    # Generate random encryption key using TPM RNG
> +    /usr/bin/busybox echo "Generating encryption key..."
> +    LUKS_KEY=$(generate_random_key)
> +
> +    if [ -z "${LUKS_KEY}" ]; then
> +        /usr/bin/busybox echo "ERROR: Failed to generate encryption key"
> +        /usr/bin/busybox rm -f "${ENCRYPTION_MARKER}"
> +        return 1
> +    fi
> +
> +    # Seal key with TPM before encryption starts
> +    /usr/bin/busybox echo "Securing key with TPM..."
> +    if ! tpm_seal_key "${LUKS_KEY}"; then
> +        /usr/bin/busybox echo "ERROR: Failed to secure key"
> +        /usr/bin/busybox rm -f "${ENCRYPTION_MARKER}"
> +        return 1
> +    fi
> +
> +    # Filesystem check before encryption
> +    /usr/bin/busybox echo "Checking filesystem integrity..."
> +    /usr/sbin/e2fsck -f -y "${ROOT_DEV}"
> +    E2FSCK_RET=$?
> +    if [ ${E2FSCK_RET} -ge 4 ]; then
> +        /usr/bin/busybox echo "ERROR: Filesystem check failed"
> +        /usr/bin/busybox rm -f "${ENCRYPTION_MARKER}"
> +        return 1
> +    fi
> +
> +    # Shrink filesystem before encryption to leave room for LUKS header
> +    /usr/bin/busybox echo "Preparing filesystem for encryption..."
> +    /usr/sbin/resize2fs "${ROOT_DEV}" 368M || {

Arbitrary size here, prone to failure in the future. Look into the "-M" option
instead.

> +        /usr/bin/busybox echo "ERROR: Failed to prepare filesystem"
> +        /usr/bin/busybox rm -f "${ENCRYPTION_MARKER}"
> +        return 1
> +    }
> +
> +    # Perform in-place encryption
> +    /usr/bin/busybox echo "=========================================="
> +    /usr/bin/busybox echo "Encrypting filesystem..."
> +    /usr/bin/busybox echo "This will take several minutes."
> +    /usr/bin/busybox echo "DO NOT POWER OFF THE DEVICE!"
> +    /usr/bin/busybox echo "=========================================="
> +
> +    /usr/bin/busybox echo -n "${LUKS_KEY}" | \
> +        /usr/sbin/cryptsetup reencrypt --encrypt \
> +        --type luks2 \
> +        --cipher aes-xts-plain64 \
> +        --key-size 256 \
> +        --hash sha256 \
> +        --reduce-device-size 32M \
> +        --key-file - \
> +        "${ROOT_DEV}" || {
> +        /usr/bin/busybox echo "ERROR: Encryption failed"
> +        /usr/bin/busybox rm -f "${ENCRYPTION_MARKER}"
> +        return 1
> +    }

This should only work on partitions that already contain a LUKS header. The LUKS
header is placed in sector 0 of the block device. resize2fs doesn't support
changing the starting position of the filesystem so you will always corrupt the
existing filesystem. It may still be recoverable, but that's not the point. This
is a bad idea.

Additionally, the partition should be overwritten with randomized data before
use to make sure unused blocks look indistinguishable from later encrypted data.
This is not something that can be done using an initramfs without external
storage.

> +
> +    /usr/bin/busybox echo "=========================================="
> +    /usr/bin/busybox echo "Encryption completed successfully!"
> +    /usr/bin/busybox echo "=========================================="
> +
> +    # Remove encryption marker
> +    /usr/bin/busybox rm -f "${ENCRYPTION_MARKER}"
> +    /usr/bin/busybox sync
> +
> +    # Unlock the newly encrypted device
> +    /usr/bin/busybox echo "Activating encrypted filesystem..."
> +    /usr/bin/busybox echo -n "${LUKS_KEY}" | \
> +        /usr/sbin/cryptsetup luksOpen "${ROOT_DEV}" "${CRYPT_NAME}" 
> --key-file - || {
> +        /usr/bin/busybox echo "ERROR: Failed to activate encrypted 
> filesystem"
> +        return 1
> +    }
> +
> +    # Resize filesystem to fit the encrypted device
> +    /usr/bin/busybox echo "Optimizing filesystem..."
> +    /usr/sbin/resize2fs -f "${CRYPT_DEV}" || {
> +        /usr/bin/busybox echo "ERROR: Failed to optimize filesystem"
> +        return 1
> +    }
> +
> +    # Verify filesystem after resize
> +    /usr/sbin/e2fsck -f -y "${CRYPT_DEV}" || {
> +        /usr/bin/busybox echo "WARNING: Filesystem verification had issues, 
> but continuing"
> +    }
> +    return 0
> +}
> +
> +# Function: Unlock encrypted root filesystem (subsequent boots)
> +unlock_encrypted_root() {
> +    /usr/bin/busybox echo "Unlocking encrypted filesystem..."
> +
> +    # Unseal key from TPM persistent handle
> +    LUKS_KEY=$(tpm_unseal_key)
> +
> +    if [ -z "${LUKS_KEY}" ]; then
> +        /usr/bin/busybox echo "ERROR: Failed to retrieve encryption key from 
> TPM"
> +        /usr/bin/busybox echo "Attempting passphrase fallback..."
> +
> +        # Try to unlock with passphrase (interactive)
> +        /usr/sbin/cryptsetup luksOpen "${ROOT_DEV}" "${CRYPT_NAME}" || {
> +            /usr/bin/busybox echo "ERROR: Failed to unlock encrypted 
> filesystem"
> +            /usr/bin/busybox sh
> +        }
> +    else
> +        # Unlock with unsealed key
> +        /usr/bin/busybox echo -n "${LUKS_KEY}" | \
> +            /usr/sbin/cryptsetup luksOpen "${ROOT_DEV}" "${CRYPT_NAME}" 
> --key-file - || {
> +            /usr/bin/busybox echo "ERROR: Failed to unlock with TPM key"
> +            /usr/bin/busybox sh
> +        }
> +    fi
> +
> +    /usr/bin/busybox echo "Encrypted filesystem unlocked"
> +}
> +
> +# Main boot logic
> +/usr/bin/busybox echo "Checking filesystem encryption status..."
> +
> +# Check if device is LUKS encrypted
> +if /usr/sbin/cryptsetup isLuks "${ROOT_DEV}"; then
> +    /usr/bin/busybox echo "Filesystem is encrypted"
> +    unlock_encrypted_root
> +    MOUNT_DEV="${CRYPT_DEV}"
> +else
> +    /usr/bin/busybox echo "Filesystem is not encrypted"
> +
> +    # Check if encryption is enabled and TPM is available
> +    if [ $TPM_AVAILABLE -eq 1 ]; then
> +        # Check for encryption marker (resume interrupted encryption)
> +        if [ -f "${ENCRYPTION_MARKER}" ]; then
> +            /usr/bin/busybox echo "Resuming interrupted encryption..."
> +            if ! encrypt_root_filesystem; then
> +                /usr/bin/busybox echo "ERROR: Failed to resume encryption"
> +                /usr/bin/busybox echo "Booting without encryption..."
> +                MOUNT_DEV="${ROOT_DEV}"
> +            else
> +                MOUNT_DEV="${CRYPT_DEV}"
> +            fi
> +        else
> +            # First boot - perform encryption
> +            if encrypt_root_filesystem; then
> +                MOUNT_DEV="${CRYPT_DEV}"
> +            else
> +                /usr/bin/busybox echo "ERROR: Encryption failed - booting 
> without encryption"
> +                MOUNT_DEV="${ROOT_DEV}"
> +            fi
> +        fi
> +    else
> +        /usr/bin/busybox echo "TPM not available - skipping encryption"
> +        MOUNT_DEV="${ROOT_DEV}"
> +    fi
> +fi
> +
> +# Unmount boot partition before switching root
> +/usr/bin/busybox umount "${BOOT_MNT}"
> +
> +# Mount root filesystem (encrypted or unencrypted)
> +/usr/bin/busybox echo "Mounting root filesystem..."
> +/usr/bin/busybox mkdir -p /newroot
> +/usr/bin/busybox mount "${MOUNT_DEV}" /newroot || {
> +    /usr/bin/busybox echo "ERROR: Failed to mount root filesystem!"
> +    /usr/bin/busybox sh
> +}
> +
> +/usr/bin/busybox echo "Boot complete"
> +
> +# Clean up tmpfs
> +/usr/bin/busybox rm -f "${TPM_PRIMARY_CTX}" "${TPM_KEY_PUB}" 
> "${TPM_KEY_PRIV}" "${TPM_KEY_CTX}"
> +
> +# Switch to real root
> +exec /usr/sbin/switch_root /newroot /sbin/init

In general I think this effort is misguided. An initrd is not a replacement for
live image install. We should not be dramatically changing the running system as
part of the first boot.

> diff --git 
> a/meta-ti-bsp/recipes-ti/initramfs/initramfs-ti-encrypted-init_1.0.bb 
> b/meta-ti-bsp/recipes-ti/initramfs/initramfs-ti-encrypted-init_1.0.bb
> new file mode 100644
> index 00000000..7da878f7
> --- /dev/null
> +++ b/meta-ti-bsp/recipes-ti/initramfs/initramfs-ti-encrypted-init_1.0.bb
> @@ -0,0 +1,30 @@
> +SUMMARY = "TI encrypted boot initramfs init script"
> +DESCRIPTION = "Custom /init script for encrypted boot with fTPM + LUKS 
> support"
> +
> +LICENSE = "MIT"
> +LIC_FILES_CHKSUM = 
> "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420"
> +
> +FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}/files:"
> +FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
> +
> +SRC_URI = "file://init"
> +
> +S = "${WORKDIR}/sources"
> +UNPACKDIR = "${WORKDIR}"
> +
> +# This recipe must run in the initramfs context
> +inherit allarch
> +
> +do_install() {
> +    # Install /init script to root of initramfs
> +    install -m 0755 ${UNPACKDIR}/init ${D}/init
> +}
> +
> +# Package the /init file
> +FILES:${PN} = "/init"
> +
> +# Runtime dependencies
> +RDEPENDS:${PN} = "busybox cryptsetup tpm2-tools tpm2-tss optee-client 
> e2fsprogs-e2fsck e2fsprogs-resize2fs util-linux-blkid"
> +
> +# This package must be included in initramfs
> +PACKAGE_ARCH = "${MACHINE_ARCH}"
> diff --git a/meta-ti-bsp/recipes-ti/initramfs/ti-encrypted-boot-initramfs.bb 
> b/meta-ti-bsp/recipes-ti/initramfs/ti-encrypted-boot-initramfs.bb
> new file mode 100644
> index 00000000..314499db
> --- /dev/null
> +++ b/meta-ti-bsp/recipes-ti/initramfs/ti-encrypted-boot-initramfs.bb
> @@ -0,0 +1,50 @@
> +SUMMARY = "TI encrypted boot initramfs image"
> +
> +DESCRIPTION = "Minimal initramfs image with dm-crypt/fTPM support for 
> encrypted root filesystem. \
> +This initramfs provides LUKS encryption with TPM-sealed keys stored in RPMB."
> +
> +LICENSE = "MIT"
> +
> +# Only build this when luks-encryption feature is enabled
> +COMPATIBLE_MACHINE = "null"
> +COMPATIBLE_MACHINE:k3 = "${@bb.utils.contains('MACHINE_FEATURES', 
> 'luks-encryption', '.*', 'null', d)}"
> +
> +INITRAMFS_FSTYPES = "cpio.gz"
> +
> +IMAGE_NAME = "ti-encrypted-boot-initramfs"
> +
> +export IMAGE_BASENAME = "${IMAGE_NAME}"
> +
> +# Install our custom init script and dependencies
> +PACKAGE_INSTALL = "\
> +    initramfs-ti-encrypted-init \
> +    busybox \
> +    base-passwd \
> +    kmod \
> +    cryptsetup \
> +    tpm2-tools \
> +    tpm2-tss \
> +    libtss2-tcti-device \
> +    optee-client \
> +    util-linux-blkid \
> +    e2fsprogs-e2fsck \
> +    e2fsprogs-resize2fs \
> +    kernel-module-tpm-ftpm-tee \
> +    ${ROOTFS_BOOTSTRAP_INSTALL} \
> +"
> +
> +# Ensure the initramfs only contains the bare minimum
> +IMAGE_FEATURES = ""
> +IMAGE_LINGUAS = ""
> +
> +# Exclude kernel image from initramfs
> +PACKAGE_EXCLUDE = "kernel-image-*"
> +
> +IMAGE_FSTYPES = "${INITRAMFS_FSTYPES}"
> +IMAGE_NAME_SUFFIX ?= ""
> +IMAGE_ROOTFS_SIZE = "16384"
> +IMAGE_ROOTFS_EXTRA_SPACE = "0"
> +
> +BAD_RECOMMENDATIONS += "busybox-syslog"
> +
> +inherit image

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#19632): 
https://lists.yoctoproject.org/g/meta-ti/message/19632
Mute This Topic: https://lists.yoctoproject.org/mt/118097473/21656
Group Owner: [email protected]
Unsubscribe: https://lists.yoctoproject.org/g/meta-ti/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to