On 3/3/26 04:10, Ryan Eatmon wrote: > > > On 3/2/2026 4:36 PM, Randolph Sapp wrote: >> 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. > > 100% agree. This is something that should be done at build time as part > of the image creation. >
Thanks for the review comments. I'll work on the changes. The current implementation focuses on first boot encryption because that way it's possible to seal encryption keys to TPM persistent handle 0x81080001 via tpm2_evictcontrol. The key becomes device-bound through TPM's internal sealing keys (unique per device) and is stored in the device's RPMB (not on the filesystem). Build-time encryption with TPM-sealed keys is not possible because: - TPM hardware is not available during image build - Each target device has a unique TPM with device-specific sealing keys - RPMB authentication is device-specific The key must be sealed on the actual target device where the TPM exists. CIP Core's initramfs-crypt-hook uses the same approach [1]- first-boot in-place encryption with TPM sealing [1] https://gitlab.com/cip-project/cip-core/isar-cip-core/-/blob/master/doc/README.tpm2.encryption.md#encrypted-partitions Regards, Shiva > >>> 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 (#19634): https://lists.yoctoproject.org/g/meta-ti/message/19634 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]] -=-=-=-=-=-=-=-=-=-=-=-
