On 3/26/26 03:25, Ryan Eatmon wrote:
> 
> 
> On 3/19/2026 11:58 AM, Shiva Tripathi wrote:
>> Add initramfs module to dynamic-layers/tpm-layer providing LUKS2 full
>> disk encryption with TPM-sealed keys for TI K3 platforms. Keys are
>> sealed by firmware TPM (fTPM) running in OP-TEE and stored in eMMC
>> RPMB.
>>
>> Features:
>> - First-boot in-place encryption with tpm2_getrandom key generation
>> - TPM-sealed key storage via persistent handle 0x81080001
>> - Automatic unlock on subsequent boots
>> - Space verification ensuring 32MB available for LUKS header
>>
>> The module is built only when meta-tpm layer is present and gets
>> included in initramfs only when DISTRO_FEATURES='luks' and
>> MACHINE_FEATURES='optee-ftpm'
>>
>> Signed-off-by: Shiva Tripathi <[email protected]>
>> ---
>>   .../initramfs-module-luks-ftpm/luksftpm       | 341 ++++++++++++++++++
>>   .../initramfs-module-luks-ftpm_1.0.bb         |  43 +++
>>   .../packagegroup-ti-core-initramfs.bbappend   |   3 +
>>   3 files changed, 387 insertions(+)
>>   create mode 100644 meta-ti-bsp/dynamic-layers/tpm-layer/recipes-ti/
>> initramfs/initramfs-module-luks-ftpm/luksftpm
>>   create mode 100644 meta-ti-bsp/dynamic-layers/tpm-layer/recipes-ti/
>> initramfs/initramfs-module-luks-ftpm_1.0.bb
>>   create mode 100644 meta-ti-bsp/dynamic-layers/tpm-layer/recipes-ti/
>> initramfs/packagegroup-ti-core-initramfs.bbappend
>>
>> diff --git a/meta-ti-bsp/dynamic-layers/tpm-layer/recipes-ti/
>> initramfs/initramfs-module-luks-ftpm/luksftpm b/meta-ti-bsp/dynamic-
>> layers/tpm-layer/recipes-ti/initramfs/initramfs-module-luks-ftpm/luksftpm
>> new file mode 100644
>> index 00000000..5e3aedc4
>> --- /dev/null
>> +++ b/meta-ti-bsp/dynamic-layers/tpm-layer/recipes-ti/initramfs/
>> initramfs-module-luks-ftpm/luksftpm
>> @@ -0,0 +1,341 @@
>> +#!/bin/sh
>> +# initramfs-framework module for LUKS encryption with fTPM support
>> +
>> +# 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
>> +wait_for_device() {
>> +    local device="$1"
>> +    local timeout="${2:-10}"
>> +
>> +    msg "Waiting for storage device ${device}..."
>> +    for i in $(seq 1 ${timeout}); do
>> +        if [ -b "${device}" ]; then
>> +            return 0
>> +        fi
>> +        sleep 1
>> +    done
>> +    return 1
>> +}
>> +
>> +# Initialize fTPM and check availability
>> +init_ftpm() {
>> +    msg "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=$!
>> +        sleep 5
>> +    else
>> +        info "Warning: Trusted execution environment not available"
>> +        return 1
>> +    fi
>> +
>> +    # Load fTPM kernel module
>> +    if ! /sbin/modprobe tpm_ftpm_tee; then
>> +        info "Warning: TPM module failed to load"
>> +        return 1
>> +    fi
>> +
>> +    # Wait for TPM device
>> +    for i in $(seq 1 10); do
>> +        if [ -c /dev/tpmrm0 ]; then
>> +            export TPM2TOOLS_TCTI="device:/dev/tpmrm0"
>> +            return 0
>> +        fi
>> +        sleep 1
>> +    done
>> +
>> +    info "Warning: fTPM not available - encryption will be skipped"
>> +    return 1
>> +}
>> +
>> +# Generate 32-byte random key using TPM RNG
>> +generate_random_key() {
>> +    /usr/bin/tpm2_getrandom --hex 32
>> +}
>> +
>> +# Seal data with TPM and store in persistent handle
>> +tpm_seal_key() {
>> +    local KEY_DATA="$1"
>> +
>> +    # Create primary key in owner hierarchy
>> +    /usr/bin/tpm2_createprimary -C o -c "${TPM_PRIMARY_CTX}" -Q ||
>> return 1
>> +
>> +    # Create sealed object
>> +    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
>> +}
>> +
>> +# Unseal data from TPM persistent handle
>> +tpm_unseal_key() {
>> +    # Check if persistent handle exists
>> +    if ! /usr/bin/tpm2_getcap handles-persistent | grep -q
>> "${TPM2_HANDLE}"; then
>> +        debug "ERROR: TPM persistent handle not found"
>> +        return 1
>> +    fi
>> +
>> +    # Unseal key directly from persistent handle
>> +    /usr/bin/tpm2_unseal -c "${TPM2_HANDLE}" || return 1
>> +
>> +    return 0
>> +}
>> +
>> +# Perform in-place LUKS encryption (first boot)
>> +encrypt_root_filesystem() {
>> +    msg "=========================================="
>> +    msg "First boot: Encrypting root filesystem"
>> +    msg "=========================================="
>> +
>> +    # Set marker to track encryption progress
>> +    touch "${ENCRYPTION_MARKER}"
>> +    sync
>> +
>> +    # Generate random encryption key using TPM RNG
>> +    msg "Generating encryption key..."
>> +    LUKS_KEY=$(generate_random_key)
>> +
>> +    if [ -z "${LUKS_KEY}" ]; then
>> +        msg "ERROR: Failed to generate encryption key"
>> +        rm -f "${ENCRYPTION_MARKER}"
>> +        return 1
>> +    fi
>> +
>> +    # Seal key with TPM before encryption starts
>> +    msg "Securing key with TPM..."
>> +    if ! tpm_seal_key "${LUKS_KEY}"; then
>> +        msg "ERROR: Failed to secure key"
>> +        rm -f "${ENCRYPTION_MARKER}"
>> +        return 1
>> +    fi
>> +
>> +    # Filesystem check before encryption
>> +    msg "Checking filesystem integrity..."
>> +    /usr/sbin/e2fsck -f -y "${ROOT_DEV}"
>> +    E2FSCK_RET=$?
>> +    if [ ${E2FSCK_RET} -ge 4 ]; then
>> +        msg "ERROR: Filesystem check failed"
>> +        rm -f "${ENCRYPTION_MARKER}"
>> +        return 1
>> +    fi
>> +
>> +    # Shrink filesystem before encryption to leave room for LUKS header
>> +    msg "Preparing filesystem for encryption..."
>> +    /usr/sbin/resize2fs -M "${ROOT_DEV}" || {
>> +        msg "ERROR: Failed to prepare filesystem"
>> +        rm -f "${ENCRYPTION_MARKER}"
>> +        return 1
>> +    }
>> +
>> +    # Verify partition has sufficient space for LUKS header
>> +    msg "Verifying space for encryption..."
>> +    MIN_BLOCKS=$(/usr/sbin/resize2fs -P "${ROOT_DEV}" 2>&1 | awk '/
>> [Mm]inimum.*:/ {print $NF}')
>> +
>> +    # Get filesystem block size and device size
>> +    BLOCK_SIZE=$(/usr/sbin/tune2fs -l "${ROOT_DEV}" 2>/dev/null | awk
>> '/^Block size:/ {print $NF}')
>> +    DEV_NAME=$(basename "${ROOT_DEV}")
>> +    PART_SECTORS=$(cat /sys/class/block/"${DEV_NAME}"/size 2>/dev/null)
>> +
>> +    if [ -z "${MIN_BLOCKS}" ] || [ -z "${BLOCK_SIZE}" ] || [ -z
>> "${PART_SECTORS}" ]; then
>> +        msg "ERROR: Unable to determine partition geometry"
>> +        rm -f "${ENCRYPTION_MARKER}"
>> +        return 1
>> +    fi
>> +
>> +    # Convert filesystem blocks to 512-byte sectors
>> +    MIN_SECTORS=$((MIN_BLOCKS * BLOCK_SIZE / 512))
>> +    LUKS_SECTORS=65536  # 32MB in 512-byte sectors
>> +
>> +    if [ $((PART_SECTORS - MIN_SECTORS)) -lt ${LUKS_SECTORS} ]; then
>> +        msg "ERROR: Insufficient space for LUKS header (need 32MB free)"
>> +        rm -f "${ENCRYPTION_MARKER}"
>> +        return 1
>> +    fi
>> +
>> +    # Perform in-place encryption
>> +    msg "=========================================="
>> +    msg "Encrypting filesystem..."
>> +    msg "This will take several minutes."
>> +    msg "DO NOT POWER OFF THE DEVICE!"
>> +    msg "=========================================="
>> +
>> +    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}" || {
>> +        msg "ERROR: Encryption failed"
>> +        rm -f "${ENCRYPTION_MARKER}"
>> +        return 1
>> +    }
>> +
>> +    msg "=========================================="
>> +    msg "Encryption completed successfully!"
>> +    msg "=========================================="
>> +
>> +    # Remove encryption marker
>> +    rm -f "${ENCRYPTION_MARKER}"
>> +    sync
>> +
>> +    # Unlock the newly encrypted device
>> +    msg "Activating encrypted filesystem..."
>> +    echo -n "${LUKS_KEY}" | \
>> +        /usr/sbin/cryptsetup luksOpen "${ROOT_DEV}" "${CRYPT_NAME}"
>> --key-file - || {
>> +        msg "ERROR: Failed to activate encrypted filesystem"
>> +        return 1
>> +    }
>> +
>> +    # Resize filesystem to fit the encrypted device
>> +    msg "Optimizing filesystem..."
>> +    /usr/sbin/resize2fs -f "${CRYPT_DEV}" || {
>> +        msg "ERROR: Failed to optimize filesystem"
>> +        return 1
>> +    }
>> +
>> +    # Verify filesystem after resize
>> +    /usr/sbin/e2fsck -f -y "${CRYPT_DEV}" || {
>> +        info "WARNING: Filesystem verification had issues, but
>> continuing"
>> +    }
>> +
>> +    return 0
>> +}
>> +
>> +# Unlock encrypted root filesystem (subsequent boots)
>> +unlock_encrypted_root() {
>> +    msg "Unlocking encrypted filesystem..."
>> +
>> +    # Unseal key from TPM persistent handle
>> +    LUKS_KEY=$(tpm_unseal_key)
>> +
>> +    if [ -z "${LUKS_KEY}" ]; then
>> +        msg "ERROR: Failed to retrieve encryption key from TPM"
>> +        msg "Attempting passphrase fallback..."
>> +
>> +        # Try to unlock with passphrase (interactive)
>> +        /usr/sbin/cryptsetup luksOpen "${ROOT_DEV}" "${CRYPT_NAME}" || {
>> +            fatal "ERROR: Failed to unlock encrypted filesystem"
>> +        }
>> +    else
>> +        # Unlock with unsealed key
>> +        echo -n "${LUKS_KEY}" | \
>> +            /usr/sbin/cryptsetup luksOpen "${ROOT_DEV}"
>> "${CRYPT_NAME}" --key-file - || {
>> +            fatal "ERROR: Failed to unlock with TPM key"
>> +        }
>> +    fi
>> +
>> +    msg "Encrypted filesystem unlocked"
>> +}
>> +
>> +# Module enabled check
>> +luksftpm_enabled() {
>> +    # Always run this module - it handles both encrypted and
>> unencrypted cases
>> +    return 0
>> +}
>> +
>> +# Module main function
>> +luksftpm_run() {
>> +    # Wait for storage device
>> +    if ! wait_for_device "${ROOT_DEV}" 10; then
>> +        info "Storage device not found, skipping encryption module"
>> +        return 0
>> +    fi
>> +
>> +    # Mount boot partition
>> +    msg "Mounting boot partition..."
>> +    mkdir -p "${BOOT_MNT}"
>> +    if ! mount "${BOOT_DEV}" "${BOOT_MNT}"; then
>> +        info "ERROR: Failed to mount boot partition, attempting
>> standard boot..."
>> +        mkdir -p ${ROOTFS_DIR}
>> +        mount "${ROOT_DEV}" ${ROOTFS_DIR}
>> +        return 0
>> +    fi
>> +
>> +    # Initialize fTPM
>> +    TPM_AVAILABLE=0
>> +    if init_ftpm; then
>> +        TPM_AVAILABLE=1
>> +    fi
>> +
>> +    # Check filesystem encryption status
>> +    msg "Checking filesystem encryption status..."
>> +
>> +    MOUNT_DEV="${ROOT_DEV}"
>> +
>> +    if /usr/sbin/cryptsetup isLuks "${ROOT_DEV}"; then
>> +        msg "Filesystem is encrypted"
>> +        unlock_encrypted_root
>> +        MOUNT_DEV="${CRYPT_DEV}"
>> +    else
>> +        msg "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
>> +                msg "Resuming interrupted encryption..."
>> +                if ! encrypt_root_filesystem; then
>> +                    msg "ERROR: Failed to resume encryption"
>> +                    msg "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
>> +                    msg "ERROR: Encryption failed - booting without
>> encryption"
>> +                    MOUNT_DEV="${ROOT_DEV}"
>> +                fi
>> +            fi
>> +        else
>> +            msg "TPM not available - skipping encryption"
>> +            MOUNT_DEV="${ROOT_DEV}"
>> +        fi
>> +    fi
>> +
>> +    # Unmount boot partition before switching root
>> +    umount "${BOOT_MNT}"
>> +
>> +    # Mount root filesystem to $ROOTFS_DIR (framework expects this)
>> +    msg "Mounting root filesystem..."
>> +    mkdir -p ${ROOTFS_DIR}
>> +    mount "${MOUNT_DEV}" ${ROOTFS_DIR} || {
>> +        fatal "ERROR: Failed to mount root filesystem!"
>> +    }
>> +
>> +    # Clean up tmpfs and sensitive variables
>> +    rm -f "${TPM_PRIMARY_CTX}" "${TPM_KEY_PUB}" "${TPM_KEY_PRIV}"
>> "${TPM_KEY_CTX}"
>> +    unset LUKS_KEY TPM_AVAILABLE MOUNT_DEV TEE_SUPPLICANT_PID
>> +
>> +    msg "Boot complete"
>> +}
>> diff --git a/meta-ti-bsp/dynamic-layers/tpm-layer/recipes-ti/
>> initramfs/initramfs-module-luks-ftpm_1.0.bb b/meta-ti-bsp/dynamic-
>> layers/tpm-layer/recipes-ti/initramfs/initramfs-module-luks-ftpm_1.0.bb
>> new file mode 100644
>> index 00000000..b2a41d08
>> --- /dev/null
>> +++ b/meta-ti-bsp/dynamic-layers/tpm-layer/recipes-ti/initramfs/
>> initramfs-module-luks-ftpm_1.0.bb
>> @@ -0,0 +1,43 @@
>> +SUMMARY = "initramfs support for LUKS encryption with fTPM"
>> +DESCRIPTION = "Provides LUKS2 full disk encryption using firmware TPM
>> (fTPM) for key management on TI K3 platforms"
>> +
>> +LICENSE = "MIT"
>> +LIC_FILES_CHKSUM = "file://${COREBASE}/meta/
>> COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420"
>> +
>> +# Only build for platforms with optee-ftpm support
>> +COMPATIBLE_MACHINE = "null"
>> +COMPATIBLE_MACHINE:k3 = "${@bb.utils.contains('MACHINE_FEATURES',
>> 'optee-ftpm', '.*', 'null', d)}"
>> +
>> +FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
>> +
>> +SRC_URI = "file://luksftpm"
>> +
>> +S = "${UNPACKDIR}"
>> +
>> +do_install() {
>> +    install -d ${D}/init.d
>> +    # Install as 85-luksftpm (runs after udev at 01, before rootfs at
>> 90)
>> +    install -m 0755 ${UNPACKDIR}/luksftpm ${D}/init.d/85-luksftpm
>> +}
>> +
>> +FILES:${PN} = "/init.d/85-luksftpm"
>> +
>> +# Runtime dependencies
>> +RDEPENDS:${PN} = "\
>> +    initramfs-framework-base \
>> +    busybox \
>> +    kmod \
>> +    cryptsetup \
>> +    tpm2-tools \
>> +    tpm2-tss \
>> +    libtss2-tcti-device \
>> +    optee-client \
>> +    optee-ftpm \
>> +    e2fsprogs-e2fsck \
>> +    e2fsprogs-resize2fs \
>> +    e2fsprogs-tune2fs \
>> +    util-linux-blkid \
>> +    kernel-module-tpm-ftpm-tee \
>> +"
>> +
>> +PACKAGE_ARCH = "${MACHINE_ARCH}"
>> diff --git a/meta-ti-bsp/dynamic-layers/tpm-layer/recipes-ti/
>> initramfs/packagegroup-ti-core-initramfs.bbappend b/meta-ti-bsp/
>> dynamic-layers/tpm-layer/recipes-ti/initramfs/packagegroup-ti-core-
>> initramfs.bbappend
>> new file mode 100644
>> index 00000000..52c82389
>> --- /dev/null
>> +++ b/meta-ti-bsp/dynamic-layers/tpm-layer/recipes-ti/initramfs/
>> packagegroup-ti-core-initramfs.bbappend
>> @@ -0,0 +1,3 @@
>> +LUKS_ENCRYPTION ?= "${@bb.utils.contains('MACHINE_FEATURES', 'optee-
>> ftpm', 'initramfs-module-luks-ftpm', '', d)}"
>> +
>> +RDEPENDS:${PN}:append = " ${@bb.utils.contains('DISTRO_FEATURES',
>> 'luks', '${LUKS_ENCRYPTION}', '', d)}"
> 
> We are missing another setting that should be in the dynamic layer. With
> the above we are adding a bunch of new packages into the initramfs and
> we are now running into the INITRAMFS_MAXSIZE check.
> 
> I created:
> meta-ti-bsp/dynamic-layers/tpm-layer/recipes-ti/initramfs/ti-core-
> initramfs.bbappend
> 
> With:
> INITRAMFS_MAXSIZE = "200000"
> 
> And that finished the build successfully.  So I think we need a V9 to
> include this change as well.
> 

Thanks for testing.
As part of my testing I had some busybox optimizations (using busybox as
init manager) that might have helped keep the initramfs size smaller.
But using the default settings (systemd as init manager) the initramfs
size crosses the current limit.

Will address the change in V9 as suggested.

Thanks,
Shiva

> 
> 

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

Reply via email to