Analysis of OP-TEE SFS Secure Storage Implementation (OPTEE 3.18)
The article examines OP‑TEE 3.18’s SFS secure storage, detailing its GP API, kernel file‑system module, REE daemon interactions, file format with header, hash‑tree nodes, key hierarchy (SSK, TSK, FEK), and encryption using AES‑GCM, and highlights the single‑point‑of‑failure risk of the dirf.db directory.
Secure storage is a key feature of TEEOS, used to protect sensitive data such as keys. When a user saves data via the secure storage API, the data is encrypted inside the TEE and then stored in a REE-side storage area. Common secure storage types in TEE are RPMB and SFS. RPMB is a secure partition in eMMC that is invisible to the non‑secure world and prevents replay and rollback attacks, but its capacity is limited. SFS leverages the REE file system; encrypted data is stored as regular files, offering large capacity but lower security because the files are visible to REE.
The article focuses on the SFS secure storage implementation in OP‑TEE version 3.18. The overall framework consists of a GP secure storage API in the user space, a file system module in the OP‑TEE kernel handling encryption/decryption and RPC messaging, and the REE-side daemon tee_supplicant that receives RPC messages and performs file operations.
The main files involved in OP‑TEE secure storage are shown in the directory layout diagram.
The GP API and corresponding system calls are illustrated in the following diagram, where functions prefixed with syscall_ implement the API in the OP‑TEE kernel.
The secure storage file format consists of three parts: a header, node descriptors, and data blocks (4 KB granularity). OP‑TEE manages file data using a hash‑tree (Merkle tree). Each node ( tee_fs_htree_node_image ) protects two child nodes and a data block. The metadata is stored in the root node ( tee_fs_htree_image ). All fields are duplicated in two versions (ver0, ver1) to ensure atomic updates.
The header structure ( tee_fs_htree_image ) contains fields such as iv (initialization vector for header encryption), tag (authentication tag), enc_fek (encrypted file‑encryption key), imeta (encrypted metadata), and counter (version indicator).
The node structure ( tee_fs_htree_node_image ) includes hash (node hash), iv (IV for data block encryption), tag (authentication tag), and flags (version information).
The file descriptor structure ( tee_fs_fd ) stores runtime information such as file descriptor, directory handle, and UUID.
The creation of a secure storage file is the most complex operation. When a TA first saves data, two types of files are created under /data/tee : dirf.db (global directory and node information) and a numerically named file that stores the actual user data. The creation flow involves permission checking ( vm_check_access_rights ), creation of dirf.db via tee_fs_rpc_create_dfh , and creation of the numeric file via ree_fs_open_primitive . Finally, the encrypted header and data blocks are written using ree_fs_write_primitive .
Opening a secure storage file requires locating the numeric file ID in dirf.db , retrieving the encrypted FEK, and building the hash‑tree node structure. After the file is opened, the TA can perform read/write operations.
Read/write operations depend on the file being opened. Reading uses ree_fs_read , while writing uses ree_fs_write . Both operations involve permission checks and session validation.
The key hierarchy in OP‑TEE secure storage consists of three keys: SSK (Secure Storage Key) derived from the chip‑unique hardware key (HUK), TSK (TA Storage Key) derived from SSK and the TA’s UUID, and FEK (File Encryption Key) generated randomly for each file. SSK and TSK never leave the TEE in plaintext; FEK is encrypted with TSK and stored alongside the encrypted data.
Encryption of both metadata and data blocks uses AES‑GCM with the FEK as the key. Each data block has a unique IV, while the metadata (contained in tee_fs_htree_node_image ) is also encrypted with a distinct IV. The encrypted FEK, metadata, and ciphertext are stored together in the REE file system.
In summary, OP‑TEE’s secure storage provides a sophisticated mechanism that combines TEE‑side encryption, hash‑tree integrity protection, and REE‑side file management. While the design isolates encryption keys within the TEE, the reliance on a single directory file ( dirf.db ) creates a single point of failure; corruption of this file can render all secure objects unreadable. Practical deployments may therefore consider backing up dirf.db on separate REE partitions or customizing the storage layout.
OPPO Kernel Craftsman
Sharing Linux kernel-related cutting-edge technology, technical articles, technical news, and curated tutorials
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.