11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 250a81498SJens Wiklander /* 350a81498SJens Wiklander * Copyright (c) 2017, Linaro Limited 450a81498SJens Wiklander */ 550a81498SJens Wiklander 650a81498SJens Wiklander #include <assert.h> 789da7ffeSAnil Kumar Reddy #include <config.h> 8e1770e71SJens Wiklander #include <crypto/crypto.h> 950a81498SJens Wiklander #include <initcall.h> 1050a81498SJens Wiklander #include <kernel/tee_common_otp.h> 1150a81498SJens Wiklander #include <stdlib.h> 1250a81498SJens Wiklander #include <string_ext.h> 1350a81498SJens Wiklander #include <string.h> 1450a81498SJens Wiklander #include <tee/fs_htree.h> 1550a81498SJens Wiklander #include <tee/tee_fs_key_manager.h> 1650a81498SJens Wiklander #include <tee/tee_fs_rpc.h> 1750a81498SJens Wiklander #include <utee_defines.h> 1850a81498SJens Wiklander #include <util.h> 1950a81498SJens Wiklander 2050a81498SJens Wiklander #define TEE_FS_HTREE_CHIP_ID_SIZE 32 2150a81498SJens Wiklander #define TEE_FS_HTREE_HASH_ALG TEE_ALG_SHA256 2250a81498SJens Wiklander #define TEE_FS_HTREE_TSK_SIZE TEE_FS_HTREE_HASH_SIZE 2350a81498SJens Wiklander #define TEE_FS_HTREE_ENC_ALG TEE_ALG_AES_ECB_NOPAD 2450a81498SJens Wiklander #define TEE_FS_HTREE_ENC_SIZE TEE_AES_BLOCK_SIZE 2550a81498SJens Wiklander #define TEE_FS_HTREE_SSK_SIZE TEE_FS_HTREE_HASH_SIZE 2650a81498SJens Wiklander 2750a81498SJens Wiklander #define TEE_FS_HTREE_AUTH_ENC_ALG TEE_ALG_AES_GCM 2850a81498SJens Wiklander #define TEE_FS_HTREE_HMAC_ALG TEE_ALG_HMAC_SHA256 2950a81498SJens Wiklander 3050a81498SJens Wiklander #define BLOCK_NUM_TO_NODE_ID(num) ((num) + 1) 3150a81498SJens Wiklander 3250a81498SJens Wiklander #define NODE_ID_TO_BLOCK_NUM(id) ((id) - 1) 3350a81498SJens Wiklander 3450a81498SJens Wiklander /* 3550a81498SJens Wiklander * The hash tree is implemented as a binary tree with the purpose to ensure 3650a81498SJens Wiklander * integrity of the data in the nodes. The data in the nodes their turn 3750a81498SJens Wiklander * provides both integrity and confidentiality of the data blocks. 3850a81498SJens Wiklander * 3950a81498SJens Wiklander * The hash tree is saved in a file as: 4050a81498SJens Wiklander * +----------------------------+ 4150a81498SJens Wiklander * | htree_image.0 | 4250a81498SJens Wiklander * | htree_image.1 | 4350a81498SJens Wiklander * +----------------------------+ 4450a81498SJens Wiklander * | htree_node_image.1.0 | 4550a81498SJens Wiklander * | htree_node_image.1.1 | 4650a81498SJens Wiklander * +----------------------------+ 4750a81498SJens Wiklander * | htree_node_image.2.0 | 4850a81498SJens Wiklander * | htree_node_image.2.1 | 4950a81498SJens Wiklander * +----------------------------+ 5050a81498SJens Wiklander * | htree_node_image.3.0 | 5150a81498SJens Wiklander * | htree_node_image.3.1 | 5250a81498SJens Wiklander * +----------------------------+ 5350a81498SJens Wiklander * | htree_node_image.4.0 | 5450a81498SJens Wiklander * | htree_node_image.4.1 | 5550a81498SJens Wiklander * +----------------------------+ 5650a81498SJens Wiklander * ... 5750a81498SJens Wiklander * 5850a81498SJens Wiklander * htree_image is the header of the file, there's two instances of it. One 5950a81498SJens Wiklander * which is committed and the other is used when updating the file. Which 6050a81498SJens Wiklander * is committed is indicated by the "counter" field, the one with the 6150a81498SJens Wiklander * largest value is selected. 6250a81498SJens Wiklander * 6350a81498SJens Wiklander * htree_node_image is a node in the hash tree, each node has two instances 6450a81498SJens Wiklander * which is committed is decided by the parent node .flag bit 65e2adafecSJens Wiklander * HTREE_NODE_COMMITTED_CHILD. Which version is the committed version of 6650a81498SJens Wiklander * node 1 is determined by the by the lowest bit of the counter field in 6750a81498SJens Wiklander * the header. 6850a81498SJens Wiklander * 6950a81498SJens Wiklander * Note that nodes start counting at 1 while blocks at 0, this means that 7050a81498SJens Wiklander * block 0 is represented by node 1. 7150a81498SJens Wiklander * 7250a81498SJens Wiklander * Where different elements are stored in the file is managed by the file 73455856d4SJens Wiklander * system. 7450a81498SJens Wiklander */ 7550a81498SJens Wiklander 7650a81498SJens Wiklander #define HTREE_NODE_COMMITTED_BLOCK BIT32(0) 7750a81498SJens Wiklander /* n is 0 or 1 */ 7850a81498SJens Wiklander #define HTREE_NODE_COMMITTED_CHILD(n) BIT32(1 + (n)) 7950a81498SJens Wiklander 8050a81498SJens Wiklander struct htree_node { 8150a81498SJens Wiklander size_t id; 8250a81498SJens Wiklander bool dirty; 83e2adafecSJens Wiklander bool block_updated; 8450a81498SJens Wiklander struct tee_fs_htree_node_image node; 8550a81498SJens Wiklander struct htree_node *parent; 8650a81498SJens Wiklander struct htree_node *child[2]; 8750a81498SJens Wiklander }; 8850a81498SJens Wiklander 8950a81498SJens Wiklander struct tee_fs_htree { 9050a81498SJens Wiklander struct htree_node root; 9150a81498SJens Wiklander struct tee_fs_htree_image head; 9250a81498SJens Wiklander uint8_t fek[TEE_FS_HTREE_FEK_SIZE]; 9350a81498SJens Wiklander struct tee_fs_htree_imeta imeta; 9450a81498SJens Wiklander bool dirty; 950c4e1284SJens Wiklander const TEE_UUID *uuid; 9650a81498SJens Wiklander const struct tee_fs_htree_storage *stor; 9750a81498SJens Wiklander void *stor_aux; 9850a81498SJens Wiklander }; 9950a81498SJens Wiklander 10050a81498SJens Wiklander struct traverse_arg; 10150a81498SJens Wiklander typedef TEE_Result (*traverse_cb_t)(struct traverse_arg *targ, 10250a81498SJens Wiklander struct htree_node *node); 10350a81498SJens Wiklander struct traverse_arg { 10450a81498SJens Wiklander struct tee_fs_htree *ht; 10550a81498SJens Wiklander traverse_cb_t cb; 10650a81498SJens Wiklander void *arg; 10750a81498SJens Wiklander }; 10850a81498SJens Wiklander 10950a81498SJens Wiklander static TEE_Result rpc_read(struct tee_fs_htree *ht, enum tee_fs_htree_type type, 11050a81498SJens Wiklander size_t idx, size_t vers, void *data, size_t dlen) 11150a81498SJens Wiklander { 11250a81498SJens Wiklander TEE_Result res; 11350a81498SJens Wiklander struct tee_fs_rpc_operation op; 11450a81498SJens Wiklander size_t bytes; 11550a81498SJens Wiklander void *p; 11650a81498SJens Wiklander 11750a81498SJens Wiklander res = ht->stor->rpc_read_init(ht->stor_aux, &op, type, idx, vers, &p); 11850a81498SJens Wiklander if (res != TEE_SUCCESS) 11950a81498SJens Wiklander return res; 12050a81498SJens Wiklander 12164fa6c0aSJens Wiklander res = ht->stor->rpc_read_final(&op, &bytes); 12250a81498SJens Wiklander if (res != TEE_SUCCESS) 12350a81498SJens Wiklander return res; 12450a81498SJens Wiklander 12550a81498SJens Wiklander if (bytes != dlen) 12650a81498SJens Wiklander return TEE_ERROR_CORRUPT_OBJECT; 12750a81498SJens Wiklander 12850a81498SJens Wiklander memcpy(data, p, dlen); 12950a81498SJens Wiklander return TEE_SUCCESS; 13050a81498SJens Wiklander } 13150a81498SJens Wiklander 13250a81498SJens Wiklander static TEE_Result rpc_read_head(struct tee_fs_htree *ht, size_t vers, 13350a81498SJens Wiklander struct tee_fs_htree_image *head) 13450a81498SJens Wiklander { 13550a81498SJens Wiklander return rpc_read(ht, TEE_FS_HTREE_TYPE_HEAD, 0, vers, 13650a81498SJens Wiklander head, sizeof(*head)); 13750a81498SJens Wiklander } 13850a81498SJens Wiklander 13950a81498SJens Wiklander static TEE_Result rpc_read_node(struct tee_fs_htree *ht, size_t node_id, 14050a81498SJens Wiklander size_t vers, 14150a81498SJens Wiklander struct tee_fs_htree_node_image *node) 14250a81498SJens Wiklander { 14350a81498SJens Wiklander return rpc_read(ht, TEE_FS_HTREE_TYPE_NODE, node_id - 1, vers, 14450a81498SJens Wiklander node, sizeof(*node)); 14550a81498SJens Wiklander } 14650a81498SJens Wiklander 14750a81498SJens Wiklander static TEE_Result rpc_write(struct tee_fs_htree *ht, 14850a81498SJens Wiklander enum tee_fs_htree_type type, size_t idx, 14950a81498SJens Wiklander size_t vers, const void *data, size_t dlen) 15050a81498SJens Wiklander { 15150a81498SJens Wiklander TEE_Result res; 15250a81498SJens Wiklander struct tee_fs_rpc_operation op; 15350a81498SJens Wiklander void *p; 15450a81498SJens Wiklander 15550a81498SJens Wiklander res = ht->stor->rpc_write_init(ht->stor_aux, &op, type, idx, vers, &p); 15650a81498SJens Wiklander if (res != TEE_SUCCESS) 15750a81498SJens Wiklander return res; 15850a81498SJens Wiklander 15950a81498SJens Wiklander memcpy(p, data, dlen); 16064fa6c0aSJens Wiklander return ht->stor->rpc_write_final(&op); 16150a81498SJens Wiklander } 16250a81498SJens Wiklander 16350a81498SJens Wiklander static TEE_Result rpc_write_head(struct tee_fs_htree *ht, size_t vers, 16450a81498SJens Wiklander const struct tee_fs_htree_image *head) 16550a81498SJens Wiklander { 16650a81498SJens Wiklander return rpc_write(ht, TEE_FS_HTREE_TYPE_HEAD, 0, vers, 16750a81498SJens Wiklander head, sizeof(*head)); 16850a81498SJens Wiklander } 16950a81498SJens Wiklander 17050a81498SJens Wiklander static TEE_Result rpc_write_node(struct tee_fs_htree *ht, size_t node_id, 17150a81498SJens Wiklander size_t vers, 17250a81498SJens Wiklander const struct tee_fs_htree_node_image *node) 17350a81498SJens Wiklander { 17450a81498SJens Wiklander return rpc_write(ht, TEE_FS_HTREE_TYPE_NODE, node_id - 1, vers, 17550a81498SJens Wiklander node, sizeof(*node)); 17650a81498SJens Wiklander } 17750a81498SJens Wiklander 17850a81498SJens Wiklander static TEE_Result traverse_post_order(struct traverse_arg *targ, 17950a81498SJens Wiklander struct htree_node *node) 18050a81498SJens Wiklander { 18150a81498SJens Wiklander TEE_Result res; 18250a81498SJens Wiklander 18350a81498SJens Wiklander /* 18450a81498SJens Wiklander * This function is recursing but not very deep, only with Log(N) 18550a81498SJens Wiklander * maximum depth. 18650a81498SJens Wiklander */ 18750a81498SJens Wiklander 18850a81498SJens Wiklander if (!node) 18950a81498SJens Wiklander return TEE_SUCCESS; 19050a81498SJens Wiklander 19150a81498SJens Wiklander res = traverse_post_order(targ, node->child[0]); 19250a81498SJens Wiklander if (res != TEE_SUCCESS) 19350a81498SJens Wiklander return res; 19450a81498SJens Wiklander 19550a81498SJens Wiklander res = traverse_post_order(targ, node->child[1]); 19650a81498SJens Wiklander if (res != TEE_SUCCESS) 19750a81498SJens Wiklander return res; 19850a81498SJens Wiklander 19950a81498SJens Wiklander return targ->cb(targ, node); 20050a81498SJens Wiklander } 20150a81498SJens Wiklander 20250a81498SJens Wiklander static TEE_Result htree_traverse_post_order(struct tee_fs_htree *ht, 20350a81498SJens Wiklander traverse_cb_t cb, void *arg) 20450a81498SJens Wiklander { 20550a81498SJens Wiklander struct traverse_arg targ = { ht, cb, arg }; 20650a81498SJens Wiklander 20750a81498SJens Wiklander return traverse_post_order(&targ, &ht->root); 20850a81498SJens Wiklander } 20950a81498SJens Wiklander 21050a81498SJens Wiklander static size_t node_id_to_level(size_t node_id) 21150a81498SJens Wiklander { 21250a81498SJens Wiklander assert(node_id && node_id < UINT_MAX); 21350a81498SJens Wiklander /* Calculate level of the node, root node (1) has level 1 */ 21450a81498SJens Wiklander return sizeof(unsigned int) * 8 - __builtin_clz(node_id); 21550a81498SJens Wiklander } 21650a81498SJens Wiklander 21750a81498SJens Wiklander static struct htree_node *find_closest_node(struct tee_fs_htree *ht, 21850a81498SJens Wiklander size_t node_id) 21950a81498SJens Wiklander { 22050a81498SJens Wiklander struct htree_node *node = &ht->root; 22150a81498SJens Wiklander size_t level = node_id_to_level(node_id); 22250a81498SJens Wiklander size_t n; 22350a81498SJens Wiklander 22450a81498SJens Wiklander /* n = 1 because root node is level 1 */ 22550a81498SJens Wiklander for (n = 1; n < level; n++) { 22650a81498SJens Wiklander struct htree_node *child; 22750a81498SJens Wiklander size_t bit_idx; 22850a81498SJens Wiklander 22950a81498SJens Wiklander /* 23050a81498SJens Wiklander * The difference between levels of the current node and 23150a81498SJens Wiklander * the node we're looking for tells which bit decides 23250a81498SJens Wiklander * direction in the tree. 23350a81498SJens Wiklander * 23450a81498SJens Wiklander * As the first bit has index 0 we'll subtract 1 23550a81498SJens Wiklander */ 23650a81498SJens Wiklander bit_idx = level - n - 1; 23750a81498SJens Wiklander child = node->child[((node_id >> bit_idx) & 1)]; 23850a81498SJens Wiklander if (!child) 23950a81498SJens Wiklander return node; 24050a81498SJens Wiklander node = child; 24150a81498SJens Wiklander } 24250a81498SJens Wiklander 24350a81498SJens Wiklander return node; 24450a81498SJens Wiklander } 24550a81498SJens Wiklander 24650a81498SJens Wiklander static struct htree_node *find_node(struct tee_fs_htree *ht, size_t node_id) 24750a81498SJens Wiklander { 24850a81498SJens Wiklander struct htree_node *node = find_closest_node(ht, node_id); 24950a81498SJens Wiklander 25050a81498SJens Wiklander if (node && node->id == node_id) 25150a81498SJens Wiklander return node; 25250a81498SJens Wiklander return NULL; 25350a81498SJens Wiklander } 25450a81498SJens Wiklander 25550a81498SJens Wiklander static TEE_Result get_node(struct tee_fs_htree *ht, bool create, 25650a81498SJens Wiklander size_t node_id, struct htree_node **node_ret) 25750a81498SJens Wiklander { 25850a81498SJens Wiklander struct htree_node *node; 25950a81498SJens Wiklander struct htree_node *nc; 26050a81498SJens Wiklander size_t n; 26150a81498SJens Wiklander 26250a81498SJens Wiklander node = find_closest_node(ht, node_id); 26350a81498SJens Wiklander if (!node) 26450a81498SJens Wiklander return TEE_ERROR_GENERIC; 26550a81498SJens Wiklander if (node->id == node_id) 26650a81498SJens Wiklander goto ret_node; 26750a81498SJens Wiklander 26850a81498SJens Wiklander /* 26950a81498SJens Wiklander * Trying to read beyond end of file should be caught earlier than 27050a81498SJens Wiklander * here. 27150a81498SJens Wiklander */ 27250a81498SJens Wiklander if (!create) 27350a81498SJens Wiklander return TEE_ERROR_GENERIC; 27450a81498SJens Wiklander 27550a81498SJens Wiklander /* 27650a81498SJens Wiklander * Add missing nodes, some nodes may already be there. When we've 27750a81498SJens Wiklander * processed the range all nodes up to node_id will be in the tree. 27850a81498SJens Wiklander */ 27950a81498SJens Wiklander for (n = node->id + 1; n <= node_id; n++) { 28050a81498SJens Wiklander node = find_closest_node(ht, n); 28150a81498SJens Wiklander if (node->id == n) 28250a81498SJens Wiklander continue; 28350a81498SJens Wiklander /* Node id n should be a child of node */ 28450a81498SJens Wiklander assert((n >> 1) == node->id); 28550a81498SJens Wiklander assert(!node->child[n & 1]); 28650a81498SJens Wiklander 28750a81498SJens Wiklander nc = calloc(1, sizeof(*nc)); 28850a81498SJens Wiklander if (!nc) 28950a81498SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 29050a81498SJens Wiklander nc->id = n; 29150a81498SJens Wiklander nc->parent = node; 29250a81498SJens Wiklander node->child[n & 1] = nc; 29350a81498SJens Wiklander node = nc; 29450a81498SJens Wiklander } 29550a81498SJens Wiklander 29650a81498SJens Wiklander if (node->id > ht->imeta.max_node_id) 29750a81498SJens Wiklander ht->imeta.max_node_id = node->id; 29850a81498SJens Wiklander 29950a81498SJens Wiklander ret_node: 30050a81498SJens Wiklander *node_ret = node; 30150a81498SJens Wiklander return TEE_SUCCESS; 30250a81498SJens Wiklander } 30350a81498SJens Wiklander 30450a81498SJens Wiklander static int get_idx_from_counter(uint32_t counter0, uint32_t counter1) 30550a81498SJens Wiklander { 30650a81498SJens Wiklander if (!(counter0 & 1)) { 30750a81498SJens Wiklander if (!(counter1 & 1)) 30850a81498SJens Wiklander return 0; 30950a81498SJens Wiklander if (counter0 > counter1) 31050a81498SJens Wiklander return 0; 31150a81498SJens Wiklander else 31250a81498SJens Wiklander return 1; 31350a81498SJens Wiklander } 31450a81498SJens Wiklander 31550a81498SJens Wiklander if (counter1 & 1) 31650a81498SJens Wiklander return 1; 31750a81498SJens Wiklander else 31850a81498SJens Wiklander return -1; 31950a81498SJens Wiklander } 32050a81498SJens Wiklander 321f28e5060SJens Wiklander static TEE_Result init_head_from_data(struct tee_fs_htree *ht, 322623b9bd4SJens Wiklander const uint8_t *hash, uint32_t min_counter) 32350a81498SJens Wiklander { 32450a81498SJens Wiklander TEE_Result res; 32550a81498SJens Wiklander int idx; 32650a81498SJens Wiklander 327f28e5060SJens Wiklander if (hash) { 328f28e5060SJens Wiklander for (idx = 0;; idx++) { 329f28e5060SJens Wiklander res = rpc_read_node(ht, 1, idx, &ht->root.node); 330f28e5060SJens Wiklander if (res != TEE_SUCCESS) 331f28e5060SJens Wiklander return res; 332f28e5060SJens Wiklander 333f28e5060SJens Wiklander if (!memcmp(ht->root.node.hash, hash, 334f28e5060SJens Wiklander sizeof(ht->root.node.hash))) { 335f28e5060SJens Wiklander res = rpc_read_head(ht, idx, &ht->head); 336f28e5060SJens Wiklander if (res != TEE_SUCCESS) 337f28e5060SJens Wiklander return res; 338f28e5060SJens Wiklander break; 339f28e5060SJens Wiklander } 340f28e5060SJens Wiklander 341f28e5060SJens Wiklander if (idx) 342499f488fSJoakim Nordell return TEE_ERROR_CORRUPT_OBJECT; 343f28e5060SJens Wiklander } 344f28e5060SJens Wiklander } else { 345f28e5060SJens Wiklander struct tee_fs_htree_image head[2]; 346f28e5060SJens Wiklander 34750a81498SJens Wiklander for (idx = 0; idx < 2; idx++) { 34850a81498SJens Wiklander res = rpc_read_head(ht, idx, head + idx); 34950a81498SJens Wiklander if (res != TEE_SUCCESS) 35050a81498SJens Wiklander return res; 35150a81498SJens Wiklander } 35250a81498SJens Wiklander 35350a81498SJens Wiklander idx = get_idx_from_counter(head[0].counter, head[1].counter); 35450a81498SJens Wiklander if (idx < 0) 35550a81498SJens Wiklander return TEE_ERROR_SECURITY; 35650a81498SJens Wiklander 35750a81498SJens Wiklander res = rpc_read_node(ht, 1, idx, &ht->root.node); 35850a81498SJens Wiklander if (res != TEE_SUCCESS) 35950a81498SJens Wiklander return res; 36050a81498SJens Wiklander 36150a81498SJens Wiklander ht->head = head[idx]; 362f28e5060SJens Wiklander } 363f28e5060SJens Wiklander 364623b9bd4SJens Wiklander if (ht->head.counter < min_counter) 365623b9bd4SJens Wiklander return TEE_ERROR_SECURITY; 366623b9bd4SJens Wiklander 36750a81498SJens Wiklander ht->root.id = 1; 36850a81498SJens Wiklander 36950a81498SJens Wiklander return TEE_SUCCESS; 37050a81498SJens Wiklander } 37150a81498SJens Wiklander 37250a81498SJens Wiklander static TEE_Result init_tree_from_data(struct tee_fs_htree *ht) 37350a81498SJens Wiklander { 37450a81498SJens Wiklander TEE_Result res; 37550a81498SJens Wiklander struct tee_fs_htree_node_image node_image; 37650a81498SJens Wiklander struct htree_node *node; 37750a81498SJens Wiklander struct htree_node *nc; 37850a81498SJens Wiklander size_t committed_version; 37950a81498SJens Wiklander size_t node_id = 2; 38050a81498SJens Wiklander 38150a81498SJens Wiklander while (node_id <= ht->imeta.max_node_id) { 38250a81498SJens Wiklander node = find_node(ht, node_id >> 1); 38350a81498SJens Wiklander if (!node) 38450a81498SJens Wiklander return TEE_ERROR_GENERIC; 38550a81498SJens Wiklander committed_version = !!(node->node.flags & 38650a81498SJens Wiklander HTREE_NODE_COMMITTED_CHILD(node_id & 1)); 38750a81498SJens Wiklander 38850a81498SJens Wiklander res = rpc_read_node(ht, node_id, committed_version, 38950a81498SJens Wiklander &node_image); 39050a81498SJens Wiklander if (res != TEE_SUCCESS) 39150a81498SJens Wiklander return res; 39250a81498SJens Wiklander 39350a81498SJens Wiklander res = get_node(ht, true, node_id, &nc); 39450a81498SJens Wiklander if (res != TEE_SUCCESS) 39550a81498SJens Wiklander return res; 39650a81498SJens Wiklander nc->node = node_image; 39750a81498SJens Wiklander node_id++; 39850a81498SJens Wiklander } 39950a81498SJens Wiklander 40050a81498SJens Wiklander return TEE_SUCCESS; 40150a81498SJens Wiklander } 40250a81498SJens Wiklander 40394a72998SJens Wiklander static TEE_Result calc_node_hash(struct htree_node *node, 40494a72998SJens Wiklander struct tee_fs_htree_meta *meta, void *ctx, 40550a81498SJens Wiklander uint8_t *digest) 40650a81498SJens Wiklander { 40750a81498SJens Wiklander TEE_Result res; 40850a81498SJens Wiklander uint8_t *ndata = (uint8_t *)&node->node + sizeof(node->node.hash); 40950a81498SJens Wiklander size_t nsize = sizeof(node->node) - sizeof(node->node.hash); 41050a81498SJens Wiklander 4116b3a371cSJens Wiklander res = crypto_hash_init(ctx); 41250a81498SJens Wiklander if (res != TEE_SUCCESS) 41350a81498SJens Wiklander return res; 41450a81498SJens Wiklander 4156b3a371cSJens Wiklander res = crypto_hash_update(ctx, ndata, nsize); 41650a81498SJens Wiklander if (res != TEE_SUCCESS) 41750a81498SJens Wiklander return res; 41850a81498SJens Wiklander 41994a72998SJens Wiklander if (meta) { 4206b3a371cSJens Wiklander res = crypto_hash_update(ctx, (void *)meta, sizeof(*meta)); 42194a72998SJens Wiklander if (res != TEE_SUCCESS) 42294a72998SJens Wiklander return res; 42394a72998SJens Wiklander } 42494a72998SJens Wiklander 42550a81498SJens Wiklander if (node->child[0]) { 4266b3a371cSJens Wiklander res = crypto_hash_update(ctx, node->child[0]->node.hash, 42750a81498SJens Wiklander sizeof(node->child[0]->node.hash)); 42850a81498SJens Wiklander if (res != TEE_SUCCESS) 42950a81498SJens Wiklander return res; 43050a81498SJens Wiklander } 43150a81498SJens Wiklander 43250a81498SJens Wiklander if (node->child[1]) { 4336b3a371cSJens Wiklander res = crypto_hash_update(ctx, node->child[1]->node.hash, 43450a81498SJens Wiklander sizeof(node->child[1]->node.hash)); 43550a81498SJens Wiklander if (res != TEE_SUCCESS) 43650a81498SJens Wiklander return res; 43750a81498SJens Wiklander } 43850a81498SJens Wiklander 4396b3a371cSJens Wiklander return crypto_hash_final(ctx, digest, TEE_FS_HTREE_HASH_SIZE); 44050a81498SJens Wiklander } 44150a81498SJens Wiklander 44250a81498SJens Wiklander static TEE_Result authenc_init(void **ctx_ret, TEE_OperationMode mode, 44350a81498SJens Wiklander struct tee_fs_htree *ht, 44450a81498SJens Wiklander struct tee_fs_htree_node_image *ni, 44550a81498SJens Wiklander size_t payload_len) 44650a81498SJens Wiklander { 44750a81498SJens Wiklander TEE_Result res = TEE_SUCCESS; 44850a81498SJens Wiklander const uint32_t alg = TEE_FS_HTREE_AUTH_ENC_ALG; 449d7ac7d0fSJens Wiklander void *ctx; 45050a81498SJens Wiklander size_t aad_len = TEE_FS_HTREE_FEK_SIZE + TEE_FS_HTREE_IV_SIZE; 45150a81498SJens Wiklander uint8_t *iv; 45250a81498SJens Wiklander 45350a81498SJens Wiklander if (ni) { 45450a81498SJens Wiklander iv = ni->iv; 45550a81498SJens Wiklander } else { 45650a81498SJens Wiklander iv = ht->head.iv; 457d0ea0f9fSEtienne Carriere aad_len += sizeof(ht->head.counter); 458d0ea0f9fSEtienne Carriere 459d0ea0f9fSEtienne Carriere /* 460d0ea0f9fSEtienne Carriere * With CFG_REE_FS_HTREE_HASH_SIZE_COMPAT, hash data passed 461d0ea0f9fSEtienne Carriere * for AAD is truncated to TEE_FS_HTREE_FEK_SIZE bytes so 462d0ea0f9fSEtienne Carriere * use the correct size aad_len computation. 463d0ea0f9fSEtienne Carriere */ 464d0ea0f9fSEtienne Carriere if (IS_ENABLED(CFG_REE_FS_HTREE_HASH_SIZE_COMPAT)) 465d0ea0f9fSEtienne Carriere aad_len += TEE_FS_HTREE_FEK_SIZE; 466d0ea0f9fSEtienne Carriere else 467d0ea0f9fSEtienne Carriere aad_len += TEE_FS_HTREE_HASH_SIZE; 46850a81498SJens Wiklander } 46950a81498SJens Wiklander 47050a81498SJens Wiklander if (mode == TEE_MODE_ENCRYPT) { 47136a063efSJens Wiklander res = crypto_rng_read(iv, TEE_FS_HTREE_IV_SIZE); 47250a81498SJens Wiklander if (res != TEE_SUCCESS) 47350a81498SJens Wiklander return res; 47450a81498SJens Wiklander } 47550a81498SJens Wiklander 476d7ac7d0fSJens Wiklander res = crypto_authenc_alloc_ctx(&ctx, alg); 47750a81498SJens Wiklander if (res != TEE_SUCCESS) 47850a81498SJens Wiklander return res; 47950a81498SJens Wiklander 48052ee414bSJens Wiklander res = crypto_authenc_init(ctx, mode, ht->fek, TEE_FS_HTREE_FEK_SIZE, iv, 4818875ce46SJens Wiklander TEE_FS_HTREE_IV_SIZE, TEE_FS_HTREE_TAG_SIZE, 4828875ce46SJens Wiklander aad_len, payload_len); 48350a81498SJens Wiklander if (res != TEE_SUCCESS) 484112261f7SJerome Forissier goto err_free; 48550a81498SJens Wiklander 48650a81498SJens Wiklander if (!ni) { 48789da7ffeSAnil Kumar Reddy size_t hash_size = TEE_FS_HTREE_HASH_SIZE; 48889da7ffeSAnil Kumar Reddy 48989da7ffeSAnil Kumar Reddy if (IS_ENABLED(CFG_REE_FS_HTREE_HASH_SIZE_COMPAT)) 49089da7ffeSAnil Kumar Reddy hash_size = TEE_FS_HTREE_FEK_SIZE; 49189da7ffeSAnil Kumar Reddy 49252ee414bSJens Wiklander res = crypto_authenc_update_aad(ctx, mode, ht->root.node.hash, 49389da7ffeSAnil Kumar Reddy hash_size); 49450a81498SJens Wiklander if (res != TEE_SUCCESS) 495112261f7SJerome Forissier goto err; 49650a81498SJens Wiklander 49752ee414bSJens Wiklander res = crypto_authenc_update_aad(ctx, mode, 49850a81498SJens Wiklander (void *)&ht->head.counter, 49950a81498SJens Wiklander sizeof(ht->head.counter)); 50050a81498SJens Wiklander if (res != TEE_SUCCESS) 501112261f7SJerome Forissier goto err; 50250a81498SJens Wiklander } 50350a81498SJens Wiklander 50452ee414bSJens Wiklander res = crypto_authenc_update_aad(ctx, mode, ht->head.enc_fek, 50550a81498SJens Wiklander TEE_FS_HTREE_FEK_SIZE); 50650a81498SJens Wiklander if (res != TEE_SUCCESS) 507112261f7SJerome Forissier goto err; 50850a81498SJens Wiklander 50952ee414bSJens Wiklander res = crypto_authenc_update_aad(ctx, mode, iv, TEE_FS_HTREE_IV_SIZE); 510112261f7SJerome Forissier if (res != TEE_SUCCESS) 511112261f7SJerome Forissier goto err; 51250a81498SJens Wiklander 51350a81498SJens Wiklander *ctx_ret = ctx; 51450a81498SJens Wiklander 515112261f7SJerome Forissier return TEE_SUCCESS; 516112261f7SJerome Forissier err: 51752ee414bSJens Wiklander crypto_authenc_final(ctx); 518112261f7SJerome Forissier err_free: 51952ee414bSJens Wiklander crypto_authenc_free_ctx(ctx); 52050a81498SJens Wiklander return res; 52150a81498SJens Wiklander } 52250a81498SJens Wiklander 52350a81498SJens Wiklander static TEE_Result authenc_decrypt_final(void *ctx, const uint8_t *tag, 52450a81498SJens Wiklander const void *crypt, size_t len, 52550a81498SJens Wiklander void *plain) 52650a81498SJens Wiklander { 52750a81498SJens Wiklander TEE_Result res; 52850a81498SJens Wiklander size_t out_size = len; 52950a81498SJens Wiklander 53052ee414bSJens Wiklander res = crypto_authenc_dec_final(ctx, crypt, len, plain, &out_size, tag, 5318875ce46SJens Wiklander TEE_FS_HTREE_TAG_SIZE); 53252ee414bSJens Wiklander crypto_authenc_final(ctx); 53352ee414bSJens Wiklander crypto_authenc_free_ctx(ctx); 53450a81498SJens Wiklander 53550a81498SJens Wiklander if (res == TEE_SUCCESS && out_size != len) 53650a81498SJens Wiklander return TEE_ERROR_GENERIC; 53750a81498SJens Wiklander if (res == TEE_ERROR_MAC_INVALID) 53850a81498SJens Wiklander return TEE_ERROR_CORRUPT_OBJECT; 53950a81498SJens Wiklander 54050a81498SJens Wiklander return res; 54150a81498SJens Wiklander } 54250a81498SJens Wiklander 54350a81498SJens Wiklander static TEE_Result authenc_encrypt_final(void *ctx, uint8_t *tag, 54450a81498SJens Wiklander const void *plain, size_t len, 54550a81498SJens Wiklander void *crypt) 54650a81498SJens Wiklander { 54750a81498SJens Wiklander TEE_Result res; 54850a81498SJens Wiklander size_t out_size = len; 54950a81498SJens Wiklander size_t out_tag_size = TEE_FS_HTREE_TAG_SIZE; 55050a81498SJens Wiklander 55152ee414bSJens Wiklander res = crypto_authenc_enc_final(ctx, plain, len, crypt, &out_size, tag, 5528875ce46SJens Wiklander &out_tag_size); 55352ee414bSJens Wiklander crypto_authenc_final(ctx); 55452ee414bSJens Wiklander crypto_authenc_free_ctx(ctx); 55550a81498SJens Wiklander 55650a81498SJens Wiklander if (res == TEE_SUCCESS && 55750a81498SJens Wiklander (out_size != len || out_tag_size != TEE_FS_HTREE_TAG_SIZE)) 55850a81498SJens Wiklander return TEE_ERROR_GENERIC; 55950a81498SJens Wiklander 56050a81498SJens Wiklander return res; 56150a81498SJens Wiklander } 56250a81498SJens Wiklander 56350a81498SJens Wiklander static TEE_Result verify_root(struct tee_fs_htree *ht) 56450a81498SJens Wiklander { 56550a81498SJens Wiklander TEE_Result res; 56650a81498SJens Wiklander void *ctx; 56750a81498SJens Wiklander 5680c4e1284SJens Wiklander res = tee_fs_fek_crypt(ht->uuid, TEE_MODE_DECRYPT, ht->head.enc_fek, 56950a81498SJens Wiklander sizeof(ht->fek), ht->fek); 57050a81498SJens Wiklander if (res != TEE_SUCCESS) 57150a81498SJens Wiklander return res; 57250a81498SJens Wiklander 57350a81498SJens Wiklander res = authenc_init(&ctx, TEE_MODE_DECRYPT, ht, NULL, sizeof(ht->imeta)); 57450a81498SJens Wiklander if (res != TEE_SUCCESS) 57550a81498SJens Wiklander return res; 57650a81498SJens Wiklander 57750a81498SJens Wiklander return authenc_decrypt_final(ctx, ht->head.tag, ht->head.imeta, 57850a81498SJens Wiklander sizeof(ht->imeta), &ht->imeta); 57950a81498SJens Wiklander } 58050a81498SJens Wiklander 58150a81498SJens Wiklander static TEE_Result verify_node(struct traverse_arg *targ, 58250a81498SJens Wiklander struct htree_node *node) 58350a81498SJens Wiklander { 58450a81498SJens Wiklander void *ctx = targ->arg; 58550a81498SJens Wiklander TEE_Result res; 58650a81498SJens Wiklander uint8_t digest[TEE_FS_HTREE_HASH_SIZE]; 58750a81498SJens Wiklander 58894a72998SJens Wiklander if (node->parent) 58994a72998SJens Wiklander res = calc_node_hash(node, NULL, ctx, digest); 59094a72998SJens Wiklander else 59194a72998SJens Wiklander res = calc_node_hash(node, &targ->ht->imeta.meta, ctx, digest); 59250a81498SJens Wiklander if (res == TEE_SUCCESS && 59348e10604SJerome Forissier consttime_memcmp(digest, node->node.hash, sizeof(digest))) 59450a81498SJens Wiklander return TEE_ERROR_CORRUPT_OBJECT; 59550a81498SJens Wiklander 59650a81498SJens Wiklander return res; 59750a81498SJens Wiklander } 59850a81498SJens Wiklander 59950a81498SJens Wiklander static TEE_Result verify_tree(struct tee_fs_htree *ht) 60050a81498SJens Wiklander { 60150a81498SJens Wiklander TEE_Result res; 60250a81498SJens Wiklander void *ctx; 60350a81498SJens Wiklander 604ecf2e014SJens Wiklander res = crypto_hash_alloc_ctx(&ctx, TEE_FS_HTREE_HASH_ALG); 60550a81498SJens Wiklander if (res != TEE_SUCCESS) 60650a81498SJens Wiklander return res; 60750a81498SJens Wiklander 60850a81498SJens Wiklander res = htree_traverse_post_order(ht, verify_node, ctx); 6096b3a371cSJens Wiklander crypto_hash_free_ctx(ctx); 61050a81498SJens Wiklander 61150a81498SJens Wiklander return res; 61250a81498SJens Wiklander } 61350a81498SJens Wiklander 61450a81498SJens Wiklander static TEE_Result init_root_node(struct tee_fs_htree *ht) 61550a81498SJens Wiklander { 61650a81498SJens Wiklander TEE_Result res; 61750a81498SJens Wiklander void *ctx; 61850a81498SJens Wiklander 619ecf2e014SJens Wiklander res = crypto_hash_alloc_ctx(&ctx, TEE_FS_HTREE_HASH_ALG); 62050a81498SJens Wiklander if (res != TEE_SUCCESS) 62150a81498SJens Wiklander return res; 62250a81498SJens Wiklander 62350a81498SJens Wiklander ht->root.id = 1; 62409eedd2dSJens Wiklander ht->root.dirty = true; 62550a81498SJens Wiklander 62694a72998SJens Wiklander res = calc_node_hash(&ht->root, &ht->imeta.meta, ctx, 62794a72998SJens Wiklander ht->root.node.hash); 6286b3a371cSJens Wiklander crypto_hash_free_ctx(ctx); 62950a81498SJens Wiklander 63050a81498SJens Wiklander return res; 63150a81498SJens Wiklander } 63250a81498SJens Wiklander 633*5a9d570aSOx Yeh static TEE_Result create_and_sync(struct tee_fs_htree *ht, 634*5a9d570aSOx Yeh uint8_t *hash, 635*5a9d570aSOx Yeh uint32_t min_counter) 636*5a9d570aSOx Yeh { 637*5a9d570aSOx Yeh TEE_Result res = TEE_ERROR_GENERIC; 638*5a9d570aSOx Yeh const struct tee_fs_htree_image dummy_head = { 639*5a9d570aSOx Yeh .counter = min_counter, 640*5a9d570aSOx Yeh }; 641*5a9d570aSOx Yeh 642*5a9d570aSOx Yeh if (!ht) 643*5a9d570aSOx Yeh return TEE_ERROR_GENERIC; 644*5a9d570aSOx Yeh 645*5a9d570aSOx Yeh res = crypto_rng_read(ht->fek, sizeof(ht->fek)); 646*5a9d570aSOx Yeh if (res != TEE_SUCCESS) 647*5a9d570aSOx Yeh return res; 648*5a9d570aSOx Yeh 649*5a9d570aSOx Yeh res = tee_fs_fek_crypt(ht->uuid, TEE_MODE_ENCRYPT, ht->fek, 650*5a9d570aSOx Yeh sizeof(ht->fek), ht->head.enc_fek); 651*5a9d570aSOx Yeh if (res != TEE_SUCCESS) 652*5a9d570aSOx Yeh return res; 653*5a9d570aSOx Yeh 654*5a9d570aSOx Yeh res = init_root_node(ht); 655*5a9d570aSOx Yeh if (res != TEE_SUCCESS) 656*5a9d570aSOx Yeh return res; 657*5a9d570aSOx Yeh 658*5a9d570aSOx Yeh ht->dirty = true; 659*5a9d570aSOx Yeh res = tee_fs_htree_sync_to_storage(&ht, hash, NULL); 660*5a9d570aSOx Yeh if (res != TEE_SUCCESS) 661*5a9d570aSOx Yeh return res; 662*5a9d570aSOx Yeh 663*5a9d570aSOx Yeh return rpc_write_head(ht, 0, &dummy_head); 664*5a9d570aSOx Yeh } 665*5a9d570aSOx Yeh 666*5a9d570aSOx Yeh static bool ht_head_is_partially_done(const struct tee_fs_htree_image *head) 667*5a9d570aSOx Yeh { 668*5a9d570aSOx Yeh uint8_t zero_tag[TEE_FS_HTREE_TAG_SIZE] = {0}; 669*5a9d570aSOx Yeh 670*5a9d570aSOx Yeh return head->counter == 0 && 671*5a9d570aSOx Yeh !memcmp(head->tag, zero_tag, sizeof(head->tag)); 672*5a9d570aSOx Yeh } 673*5a9d570aSOx Yeh 674623b9bd4SJens Wiklander TEE_Result tee_fs_htree_open(bool create, uint8_t *hash, uint32_t min_counter, 675623b9bd4SJens Wiklander const TEE_UUID *uuid, 67650a81498SJens Wiklander const struct tee_fs_htree_storage *stor, 67750a81498SJens Wiklander void *stor_aux, struct tee_fs_htree **ht_ret) 67850a81498SJens Wiklander { 67950a81498SJens Wiklander TEE_Result res; 68050a81498SJens Wiklander struct tee_fs_htree *ht = calloc(1, sizeof(*ht)); 68150a81498SJens Wiklander 68250a81498SJens Wiklander if (!ht) 68350a81498SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 68450a81498SJens Wiklander 6850c4e1284SJens Wiklander ht->uuid = uuid; 68650a81498SJens Wiklander ht->stor = stor; 68750a81498SJens Wiklander ht->stor_aux = stor_aux; 68850a81498SJens Wiklander 68950a81498SJens Wiklander if (create) { 690*5a9d570aSOx Yeh res = create_and_sync(ht, hash, min_counter); 69150a81498SJens Wiklander } else { 692623b9bd4SJens Wiklander res = init_head_from_data(ht, hash, min_counter); 69350a81498SJens Wiklander if (res != TEE_SUCCESS) 69450a81498SJens Wiklander goto out; 69550a81498SJens Wiklander 696*5a9d570aSOx Yeh /* 697*5a9d570aSOx Yeh * If a power loss occurred during hash tree creation, the 698*5a9d570aSOx Yeh * head may not have been written and counter is still 0. 699*5a9d570aSOx Yeh * Re-initialze the hash tree. 700*5a9d570aSOx Yeh */ 701*5a9d570aSOx Yeh if (ht_head_is_partially_done(&ht->head)) { 702*5a9d570aSOx Yeh res = create_and_sync(ht, hash, min_counter); 703*5a9d570aSOx Yeh if (res != TEE_SUCCESS) 704*5a9d570aSOx Yeh goto out; 705*5a9d570aSOx Yeh } 706*5a9d570aSOx Yeh 70750a81498SJens Wiklander res = verify_root(ht); 70850a81498SJens Wiklander if (res != TEE_SUCCESS) 70950a81498SJens Wiklander goto out; 71050a81498SJens Wiklander 71150a81498SJens Wiklander res = init_tree_from_data(ht); 71250a81498SJens Wiklander if (res != TEE_SUCCESS) 71350a81498SJens Wiklander goto out; 71450a81498SJens Wiklander 71550a81498SJens Wiklander res = verify_tree(ht); 71650a81498SJens Wiklander } 71750a81498SJens Wiklander out: 71850a81498SJens Wiklander if (res == TEE_SUCCESS) 71950a81498SJens Wiklander *ht_ret = ht; 72050a81498SJens Wiklander else 72150a81498SJens Wiklander tee_fs_htree_close(&ht); 72250a81498SJens Wiklander return res; 72350a81498SJens Wiklander } 72450a81498SJens Wiklander 72550a81498SJens Wiklander struct tee_fs_htree_meta *tee_fs_htree_get_meta(struct tee_fs_htree *ht) 72650a81498SJens Wiklander { 72750a81498SJens Wiklander return &ht->imeta.meta; 72850a81498SJens Wiklander } 72950a81498SJens Wiklander 73033e4def6SJerome Forissier void tee_fs_htree_meta_set_dirty(struct tee_fs_htree *ht) 73133e4def6SJerome Forissier { 73233e4def6SJerome Forissier ht->dirty = true; 73394a72998SJens Wiklander ht->root.dirty = true; 73433e4def6SJerome Forissier } 73533e4def6SJerome Forissier 73650a81498SJens Wiklander static TEE_Result free_node(struct traverse_arg *targ __unused, 73750a81498SJens Wiklander struct htree_node *node) 73850a81498SJens Wiklander { 73950a81498SJens Wiklander if (node->parent) 74050a81498SJens Wiklander free(node); 74150a81498SJens Wiklander return TEE_SUCCESS; 74250a81498SJens Wiklander } 74350a81498SJens Wiklander 74450a81498SJens Wiklander void tee_fs_htree_close(struct tee_fs_htree **ht) 74550a81498SJens Wiklander { 74650a81498SJens Wiklander if (!*ht) 74750a81498SJens Wiklander return; 74850a81498SJens Wiklander htree_traverse_post_order(*ht, free_node, NULL); 74950a81498SJens Wiklander free(*ht); 75050a81498SJens Wiklander *ht = NULL; 75150a81498SJens Wiklander } 75250a81498SJens Wiklander 75350a81498SJens Wiklander static TEE_Result htree_sync_node_to_storage(struct traverse_arg *targ, 75450a81498SJens Wiklander struct htree_node *node) 75550a81498SJens Wiklander { 75650a81498SJens Wiklander TEE_Result res; 75750a81498SJens Wiklander uint8_t vers; 75894a72998SJens Wiklander struct tee_fs_htree_meta *meta = NULL; 75950a81498SJens Wiklander 760e2adafecSJens Wiklander /* 761e2adafecSJens Wiklander * The node can be dirty while the block isn't updated due to 762e2adafecSJens Wiklander * updated children, but if block is updated the node has to be 763e2adafecSJens Wiklander * dirty. 764e2adafecSJens Wiklander */ 765e2adafecSJens Wiklander assert(node->dirty >= node->block_updated); 766e2adafecSJens Wiklander 76750a81498SJens Wiklander if (!node->dirty) 76850a81498SJens Wiklander return TEE_SUCCESS; 76950a81498SJens Wiklander 77050a81498SJens Wiklander if (node->parent) { 77150a81498SJens Wiklander uint32_t f = HTREE_NODE_COMMITTED_CHILD(node->id & 1); 77250a81498SJens Wiklander 77350a81498SJens Wiklander node->parent->dirty = true; 77450a81498SJens Wiklander node->parent->node.flags ^= f; 77550a81498SJens Wiklander vers = !!(node->parent->node.flags & f); 77650a81498SJens Wiklander } else { 77750a81498SJens Wiklander /* 77850a81498SJens Wiklander * Counter isn't updated yet, it's increased just before 77950a81498SJens Wiklander * writing the header. 78050a81498SJens Wiklander */ 78150a81498SJens Wiklander vers = !(targ->ht->head.counter & 1); 78294a72998SJens Wiklander meta = &targ->ht->imeta.meta; 78350a81498SJens Wiklander } 78450a81498SJens Wiklander 78594a72998SJens Wiklander res = calc_node_hash(node, meta, targ->arg, node->node.hash); 78650a81498SJens Wiklander if (res != TEE_SUCCESS) 78750a81498SJens Wiklander return res; 78850a81498SJens Wiklander 78950a81498SJens Wiklander node->dirty = false; 790e2adafecSJens Wiklander node->block_updated = false; 79150a81498SJens Wiklander 79250a81498SJens Wiklander return rpc_write_node(targ->ht, node->id, vers, &node->node); 79350a81498SJens Wiklander } 79450a81498SJens Wiklander 79550a81498SJens Wiklander static TEE_Result update_root(struct tee_fs_htree *ht) 79650a81498SJens Wiklander { 79750a81498SJens Wiklander TEE_Result res; 79850a81498SJens Wiklander void *ctx; 79950a81498SJens Wiklander 80050a81498SJens Wiklander ht->head.counter++; 80150a81498SJens Wiklander 80250a81498SJens Wiklander res = authenc_init(&ctx, TEE_MODE_ENCRYPT, ht, NULL, sizeof(ht->imeta)); 80350a81498SJens Wiklander if (res != TEE_SUCCESS) 80450a81498SJens Wiklander return res; 80550a81498SJens Wiklander 80650a81498SJens Wiklander return authenc_encrypt_final(ctx, ht->head.tag, &ht->imeta, 80750a81498SJens Wiklander sizeof(ht->imeta), &ht->head.imeta); 80850a81498SJens Wiklander } 80950a81498SJens Wiklander 810f28e5060SJens Wiklander TEE_Result tee_fs_htree_sync_to_storage(struct tee_fs_htree **ht_arg, 811623b9bd4SJens Wiklander uint8_t *hash, uint32_t *counter) 81250a81498SJens Wiklander { 81350a81498SJens Wiklander TEE_Result res; 81450a81498SJens Wiklander struct tee_fs_htree *ht = *ht_arg; 81550a81498SJens Wiklander void *ctx; 81650a81498SJens Wiklander 81750a81498SJens Wiklander if (!ht) 81850a81498SJens Wiklander return TEE_ERROR_CORRUPT_OBJECT; 81950a81498SJens Wiklander 820a48d0254SJens Wiklander if (!ht->dirty) 821a48d0254SJens Wiklander return TEE_SUCCESS; 822a48d0254SJens Wiklander 823ecf2e014SJens Wiklander res = crypto_hash_alloc_ctx(&ctx, TEE_FS_HTREE_HASH_ALG); 82450a81498SJens Wiklander if (res != TEE_SUCCESS) 82550a81498SJens Wiklander return res; 82650a81498SJens Wiklander 82750a81498SJens Wiklander res = htree_traverse_post_order(ht, htree_sync_node_to_storage, ctx); 82850a81498SJens Wiklander if (res != TEE_SUCCESS) 82950a81498SJens Wiklander goto out; 83050a81498SJens Wiklander 83150a81498SJens Wiklander /* All the nodes are written to storage now. Time to update root. */ 83250a81498SJens Wiklander res = update_root(ht); 83350a81498SJens Wiklander if (res != TEE_SUCCESS) 83450a81498SJens Wiklander goto out; 83550a81498SJens Wiklander 83650a81498SJens Wiklander res = rpc_write_head(ht, ht->head.counter & 1, &ht->head); 83750a81498SJens Wiklander if (res != TEE_SUCCESS) 83850a81498SJens Wiklander goto out; 83950a81498SJens Wiklander 84050a81498SJens Wiklander ht->dirty = false; 841f28e5060SJens Wiklander if (hash) 842f28e5060SJens Wiklander memcpy(hash, ht->root.node.hash, sizeof(ht->root.node.hash)); 843623b9bd4SJens Wiklander if (counter) 844623b9bd4SJens Wiklander *counter = ht->head.counter; 84550a81498SJens Wiklander out: 8466b3a371cSJens Wiklander crypto_hash_free_ctx(ctx); 84750a81498SJens Wiklander if (res != TEE_SUCCESS) 84850a81498SJens Wiklander tee_fs_htree_close(ht_arg); 84950a81498SJens Wiklander return res; 85050a81498SJens Wiklander } 85150a81498SJens Wiklander 85250a81498SJens Wiklander static TEE_Result get_block_node(struct tee_fs_htree *ht, bool create, 853e2adafecSJens Wiklander size_t block_num, struct htree_node **node) 85450a81498SJens Wiklander { 85550a81498SJens Wiklander TEE_Result res; 85650a81498SJens Wiklander struct htree_node *nd; 85750a81498SJens Wiklander 85850a81498SJens Wiklander res = get_node(ht, create, BLOCK_NUM_TO_NODE_ID(block_num), &nd); 859e2adafecSJens Wiklander if (res == TEE_SUCCESS) 86050a81498SJens Wiklander *node = nd; 86150a81498SJens Wiklander 86250a81498SJens Wiklander return res; 86350a81498SJens Wiklander } 86450a81498SJens Wiklander 86550a81498SJens Wiklander TEE_Result tee_fs_htree_write_block(struct tee_fs_htree **ht_arg, 86650a81498SJens Wiklander size_t block_num, const void *block) 86750a81498SJens Wiklander { 86850a81498SJens Wiklander struct tee_fs_htree *ht = *ht_arg; 86950a81498SJens Wiklander TEE_Result res; 87050a81498SJens Wiklander struct tee_fs_rpc_operation op; 87150a81498SJens Wiklander struct htree_node *node = NULL; 87250a81498SJens Wiklander uint8_t block_vers; 87350a81498SJens Wiklander void *ctx; 87450a81498SJens Wiklander void *enc_block; 87550a81498SJens Wiklander 87650a81498SJens Wiklander if (!ht) 87750a81498SJens Wiklander return TEE_ERROR_CORRUPT_OBJECT; 87850a81498SJens Wiklander 879e2adafecSJens Wiklander res = get_block_node(ht, true, block_num, &node); 88050a81498SJens Wiklander if (res != TEE_SUCCESS) 88150a81498SJens Wiklander goto out; 88250a81498SJens Wiklander 883e2adafecSJens Wiklander if (!node->block_updated) 884e2adafecSJens Wiklander node->node.flags ^= HTREE_NODE_COMMITTED_BLOCK; 885e2adafecSJens Wiklander 886e2adafecSJens Wiklander block_vers = !!(node->node.flags & HTREE_NODE_COMMITTED_BLOCK); 88750a81498SJens Wiklander res = ht->stor->rpc_write_init(ht->stor_aux, &op, 88850a81498SJens Wiklander TEE_FS_HTREE_TYPE_BLOCK, block_num, 88950a81498SJens Wiklander block_vers, &enc_block); 89050a81498SJens Wiklander if (res != TEE_SUCCESS) 89150a81498SJens Wiklander goto out; 89250a81498SJens Wiklander 89350a81498SJens Wiklander res = authenc_init(&ctx, TEE_MODE_ENCRYPT, ht, &node->node, 89450a81498SJens Wiklander ht->stor->block_size); 89550a81498SJens Wiklander if (res != TEE_SUCCESS) 89650a81498SJens Wiklander goto out; 89750a81498SJens Wiklander res = authenc_encrypt_final(ctx, node->node.tag, block, 89850a81498SJens Wiklander ht->stor->block_size, enc_block); 89950a81498SJens Wiklander if (res != TEE_SUCCESS) 90050a81498SJens Wiklander goto out; 90150a81498SJens Wiklander 90264fa6c0aSJens Wiklander res = ht->stor->rpc_write_final(&op); 90350a81498SJens Wiklander if (res != TEE_SUCCESS) 90450a81498SJens Wiklander goto out; 90550a81498SJens Wiklander 906e2adafecSJens Wiklander node->block_updated = true; 90750a81498SJens Wiklander node->dirty = true; 90850a81498SJens Wiklander ht->dirty = true; 90950a81498SJens Wiklander out: 91050a81498SJens Wiklander if (res != TEE_SUCCESS) 91150a81498SJens Wiklander tee_fs_htree_close(ht_arg); 91250a81498SJens Wiklander return res; 91350a81498SJens Wiklander } 91450a81498SJens Wiklander 91550a81498SJens Wiklander TEE_Result tee_fs_htree_read_block(struct tee_fs_htree **ht_arg, 91650a81498SJens Wiklander size_t block_num, void *block) 91750a81498SJens Wiklander { 91850a81498SJens Wiklander struct tee_fs_htree *ht = *ht_arg; 91950a81498SJens Wiklander TEE_Result res; 92050a81498SJens Wiklander struct tee_fs_rpc_operation op; 92150a81498SJens Wiklander struct htree_node *node; 92250a81498SJens Wiklander uint8_t block_vers; 92350a81498SJens Wiklander size_t len; 92450a81498SJens Wiklander void *ctx; 92550a81498SJens Wiklander void *enc_block; 92650a81498SJens Wiklander 92750a81498SJens Wiklander if (!ht) 92850a81498SJens Wiklander return TEE_ERROR_CORRUPT_OBJECT; 92950a81498SJens Wiklander 930e2adafecSJens Wiklander res = get_block_node(ht, false, block_num, &node); 93150a81498SJens Wiklander if (res != TEE_SUCCESS) 93250a81498SJens Wiklander goto out; 93350a81498SJens Wiklander 934e2adafecSJens Wiklander block_vers = !!(node->node.flags & HTREE_NODE_COMMITTED_BLOCK); 93550a81498SJens Wiklander res = ht->stor->rpc_read_init(ht->stor_aux, &op, 93650a81498SJens Wiklander TEE_FS_HTREE_TYPE_BLOCK, block_num, 93750a81498SJens Wiklander block_vers, &enc_block); 93850a81498SJens Wiklander if (res != TEE_SUCCESS) 93950a81498SJens Wiklander goto out; 94050a81498SJens Wiklander 94164fa6c0aSJens Wiklander res = ht->stor->rpc_read_final(&op, &len); 94250a81498SJens Wiklander if (res != TEE_SUCCESS) 94350a81498SJens Wiklander goto out; 94450a81498SJens Wiklander if (len != ht->stor->block_size) { 94550a81498SJens Wiklander res = TEE_ERROR_CORRUPT_OBJECT; 94650a81498SJens Wiklander goto out; 94750a81498SJens Wiklander } 94850a81498SJens Wiklander 94950a81498SJens Wiklander res = authenc_init(&ctx, TEE_MODE_DECRYPT, ht, &node->node, 95050a81498SJens Wiklander ht->stor->block_size); 95150a81498SJens Wiklander if (res != TEE_SUCCESS) 95250a81498SJens Wiklander goto out; 95350a81498SJens Wiklander 95450a81498SJens Wiklander res = authenc_decrypt_final(ctx, node->node.tag, enc_block, 95550a81498SJens Wiklander ht->stor->block_size, block); 95650a81498SJens Wiklander out: 95750a81498SJens Wiklander if (res != TEE_SUCCESS) 95850a81498SJens Wiklander tee_fs_htree_close(ht_arg); 95950a81498SJens Wiklander return res; 96050a81498SJens Wiklander } 96150a81498SJens Wiklander 96250a81498SJens Wiklander TEE_Result tee_fs_htree_truncate(struct tee_fs_htree **ht_arg, size_t block_num) 96350a81498SJens Wiklander { 96450a81498SJens Wiklander struct tee_fs_htree *ht = *ht_arg; 96550a81498SJens Wiklander size_t node_id = BLOCK_NUM_TO_NODE_ID(block_num); 96650a81498SJens Wiklander struct htree_node *node; 96750a81498SJens Wiklander 96850a81498SJens Wiklander if (!ht) 96950a81498SJens Wiklander return TEE_ERROR_CORRUPT_OBJECT; 97050a81498SJens Wiklander 97150a81498SJens Wiklander while (node_id < ht->imeta.max_node_id) { 97250a81498SJens Wiklander node = find_closest_node(ht, ht->imeta.max_node_id); 97350a81498SJens Wiklander assert(node && node->id == ht->imeta.max_node_id); 97450a81498SJens Wiklander assert(!node->child[0] && !node->child[1]); 97550a81498SJens Wiklander assert(node->parent); 97650a81498SJens Wiklander assert(node->parent->child[node->id & 1] == node); 97750a81498SJens Wiklander node->parent->child[node->id & 1] = NULL; 97850a81498SJens Wiklander free(node); 97950a81498SJens Wiklander ht->imeta.max_node_id--; 98050a81498SJens Wiklander ht->dirty = true; 98150a81498SJens Wiklander } 98250a81498SJens Wiklander 98350a81498SJens Wiklander return TEE_SUCCESS; 98450a81498SJens Wiklander } 985