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
rpc_read(struct tee_fs_htree * ht,enum tee_fs_htree_type type,size_t idx,size_t vers,void * data,size_t dlen)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
rpc_read_head(struct tee_fs_htree * ht,size_t vers,struct tee_fs_htree_image * head)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
rpc_read_node(struct tee_fs_htree * ht,size_t node_id,size_t vers,struct tee_fs_htree_node_image * node)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
rpc_write(struct tee_fs_htree * ht,enum tee_fs_htree_type type,size_t idx,size_t vers,const void * data,size_t dlen)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
rpc_write_head(struct tee_fs_htree * ht,size_t vers,const struct tee_fs_htree_image * head)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
rpc_write_node(struct tee_fs_htree * ht,size_t node_id,size_t vers,const struct tee_fs_htree_node_image * node)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
traverse_post_order(struct traverse_arg * targ,struct htree_node * node)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
htree_traverse_post_order(struct tee_fs_htree * ht,traverse_cb_t cb,void * arg)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
node_id_to_level(size_t node_id)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
find_closest_node(struct tee_fs_htree * ht,size_t node_id)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
find_node(struct tee_fs_htree * ht,size_t node_id)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
get_node(struct tee_fs_htree * ht,bool create,size_t node_id,struct htree_node ** node_ret)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
get_idx_from_counter(uint32_t counter0,uint32_t counter1)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
init_head_from_data(struct tee_fs_htree * ht,const uint8_t * hash,uint32_t min_counter)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
init_tree_from_data(struct tee_fs_htree * ht)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
calc_node_hash(struct htree_node * node,struct tee_fs_htree_meta * meta,void * ctx,uint8_t * digest)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
authenc_init(void ** ctx_ret,TEE_OperationMode mode,struct tee_fs_htree * ht,struct tee_fs_htree_node_image * ni,size_t payload_len)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
authenc_decrypt_final(void * ctx,const uint8_t * tag,const void * crypt,size_t len,void * plain)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
authenc_encrypt_final(void * ctx,uint8_t * tag,const void * plain,size_t len,void * crypt)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
verify_root(struct tee_fs_htree * ht)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
verify_node(struct traverse_arg * targ,struct htree_node * node)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
verify_tree(struct tee_fs_htree * ht)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
init_root_node(struct tee_fs_htree * ht)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
create_and_sync(struct tee_fs_htree ** ht_arg,uint8_t * hash,uint32_t min_counter)633*6e1990d7SOx Yeh static TEE_Result create_and_sync(struct tee_fs_htree **ht_arg,
6345a9d570aSOx Yeh uint8_t *hash,
6355a9d570aSOx Yeh uint32_t min_counter)
6365a9d570aSOx Yeh {
6375a9d570aSOx Yeh TEE_Result res = TEE_ERROR_GENERIC;
638*6e1990d7SOx Yeh struct tee_fs_htree *ht = *ht_arg;
6395a9d570aSOx Yeh const struct tee_fs_htree_image dummy_head = {
6405a9d570aSOx Yeh .counter = min_counter,
6415a9d570aSOx Yeh };
6425a9d570aSOx Yeh
6435a9d570aSOx Yeh if (!ht)
6445a9d570aSOx Yeh return TEE_ERROR_GENERIC;
6455a9d570aSOx Yeh
6465a9d570aSOx Yeh res = crypto_rng_read(ht->fek, sizeof(ht->fek));
6475a9d570aSOx Yeh if (res != TEE_SUCCESS)
6485a9d570aSOx Yeh return res;
6495a9d570aSOx Yeh
6505a9d570aSOx Yeh res = tee_fs_fek_crypt(ht->uuid, TEE_MODE_ENCRYPT, ht->fek,
6515a9d570aSOx Yeh sizeof(ht->fek), ht->head.enc_fek);
6525a9d570aSOx Yeh if (res != TEE_SUCCESS)
6535a9d570aSOx Yeh return res;
6545a9d570aSOx Yeh
6555a9d570aSOx Yeh res = init_root_node(ht);
6565a9d570aSOx Yeh if (res != TEE_SUCCESS)
6575a9d570aSOx Yeh return res;
6585a9d570aSOx Yeh
6595a9d570aSOx Yeh ht->dirty = true;
660*6e1990d7SOx Yeh res = tee_fs_htree_sync_to_storage(ht_arg, hash, NULL);
6615a9d570aSOx Yeh if (res != TEE_SUCCESS)
6625a9d570aSOx Yeh return res;
6635a9d570aSOx Yeh
664*6e1990d7SOx Yeh return rpc_write_head(*ht_arg, 0, &dummy_head);
6655a9d570aSOx Yeh }
6665a9d570aSOx Yeh
ht_head_is_partially_done(const struct tee_fs_htree_image * head)6675a9d570aSOx Yeh static bool ht_head_is_partially_done(const struct tee_fs_htree_image *head)
6685a9d570aSOx Yeh {
6695a9d570aSOx Yeh uint8_t zero_tag[TEE_FS_HTREE_TAG_SIZE] = {0};
6705a9d570aSOx Yeh
6715a9d570aSOx Yeh return head->counter == 0 &&
6725a9d570aSOx Yeh !memcmp(head->tag, zero_tag, sizeof(head->tag));
6735a9d570aSOx Yeh }
6745a9d570aSOx Yeh
tee_fs_htree_open(bool create,uint8_t * hash,uint32_t min_counter,const TEE_UUID * uuid,const struct tee_fs_htree_storage * stor,void * stor_aux,struct tee_fs_htree ** ht_ret)675623b9bd4SJens Wiklander TEE_Result tee_fs_htree_open(bool create, uint8_t *hash, uint32_t min_counter,
676623b9bd4SJens Wiklander const TEE_UUID *uuid,
67750a81498SJens Wiklander const struct tee_fs_htree_storage *stor,
67850a81498SJens Wiklander void *stor_aux, struct tee_fs_htree **ht_ret)
67950a81498SJens Wiklander {
68050a81498SJens Wiklander TEE_Result res;
68150a81498SJens Wiklander struct tee_fs_htree *ht = calloc(1, sizeof(*ht));
68250a81498SJens Wiklander
68350a81498SJens Wiklander if (!ht)
68450a81498SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY;
68550a81498SJens Wiklander
6860c4e1284SJens Wiklander ht->uuid = uuid;
68750a81498SJens Wiklander ht->stor = stor;
68850a81498SJens Wiklander ht->stor_aux = stor_aux;
68950a81498SJens Wiklander
69050a81498SJens Wiklander if (create) {
691*6e1990d7SOx Yeh res = create_and_sync(&ht, hash, min_counter);
69250a81498SJens Wiklander } else {
693623b9bd4SJens Wiklander res = init_head_from_data(ht, hash, min_counter);
69450a81498SJens Wiklander if (res != TEE_SUCCESS)
69550a81498SJens Wiklander goto out;
69650a81498SJens Wiklander
6975a9d570aSOx Yeh /*
6985a9d570aSOx Yeh * If a power loss occurred during hash tree creation, the
6995a9d570aSOx Yeh * head may not have been written and counter is still 0.
7005a9d570aSOx Yeh * Re-initialze the hash tree.
7015a9d570aSOx Yeh */
7025a9d570aSOx Yeh if (ht_head_is_partially_done(&ht->head)) {
703*6e1990d7SOx Yeh res = create_and_sync(&ht, hash, min_counter);
7045a9d570aSOx Yeh if (res != TEE_SUCCESS)
7055a9d570aSOx Yeh goto out;
7065a9d570aSOx Yeh }
7075a9d570aSOx Yeh
70850a81498SJens Wiklander res = verify_root(ht);
70950a81498SJens Wiklander if (res != TEE_SUCCESS)
71050a81498SJens Wiklander goto out;
71150a81498SJens Wiklander
71250a81498SJens Wiklander res = init_tree_from_data(ht);
71350a81498SJens Wiklander if (res != TEE_SUCCESS)
71450a81498SJens Wiklander goto out;
71550a81498SJens Wiklander
71650a81498SJens Wiklander res = verify_tree(ht);
71750a81498SJens Wiklander }
71850a81498SJens Wiklander out:
71950a81498SJens Wiklander if (res == TEE_SUCCESS)
72050a81498SJens Wiklander *ht_ret = ht;
72150a81498SJens Wiklander else
72250a81498SJens Wiklander tee_fs_htree_close(&ht);
72350a81498SJens Wiklander return res;
72450a81498SJens Wiklander }
72550a81498SJens Wiklander
tee_fs_htree_get_meta(struct tee_fs_htree * ht)72650a81498SJens Wiklander struct tee_fs_htree_meta *tee_fs_htree_get_meta(struct tee_fs_htree *ht)
72750a81498SJens Wiklander {
72850a81498SJens Wiklander return &ht->imeta.meta;
72950a81498SJens Wiklander }
73050a81498SJens Wiklander
tee_fs_htree_meta_set_dirty(struct tee_fs_htree * ht)73133e4def6SJerome Forissier void tee_fs_htree_meta_set_dirty(struct tee_fs_htree *ht)
73233e4def6SJerome Forissier {
73333e4def6SJerome Forissier ht->dirty = true;
73494a72998SJens Wiklander ht->root.dirty = true;
73533e4def6SJerome Forissier }
73633e4def6SJerome Forissier
free_node(struct traverse_arg * targ __unused,struct htree_node * node)73750a81498SJens Wiklander static TEE_Result free_node(struct traverse_arg *targ __unused,
73850a81498SJens Wiklander struct htree_node *node)
73950a81498SJens Wiklander {
74050a81498SJens Wiklander if (node->parent)
74150a81498SJens Wiklander free(node);
74250a81498SJens Wiklander return TEE_SUCCESS;
74350a81498SJens Wiklander }
74450a81498SJens Wiklander
tee_fs_htree_close(struct tee_fs_htree ** ht)74550a81498SJens Wiklander void tee_fs_htree_close(struct tee_fs_htree **ht)
74650a81498SJens Wiklander {
74750a81498SJens Wiklander if (!*ht)
74850a81498SJens Wiklander return;
74950a81498SJens Wiklander htree_traverse_post_order(*ht, free_node, NULL);
75050a81498SJens Wiklander free(*ht);
75150a81498SJens Wiklander *ht = NULL;
75250a81498SJens Wiklander }
75350a81498SJens Wiklander
htree_sync_node_to_storage(struct traverse_arg * targ,struct htree_node * node)75450a81498SJens Wiklander static TEE_Result htree_sync_node_to_storage(struct traverse_arg *targ,
75550a81498SJens Wiklander struct htree_node *node)
75650a81498SJens Wiklander {
75750a81498SJens Wiklander TEE_Result res;
75850a81498SJens Wiklander uint8_t vers;
75994a72998SJens Wiklander struct tee_fs_htree_meta *meta = NULL;
76050a81498SJens Wiklander
761e2adafecSJens Wiklander /*
762e2adafecSJens Wiklander * The node can be dirty while the block isn't updated due to
763e2adafecSJens Wiklander * updated children, but if block is updated the node has to be
764e2adafecSJens Wiklander * dirty.
765e2adafecSJens Wiklander */
766e2adafecSJens Wiklander assert(node->dirty >= node->block_updated);
767e2adafecSJens Wiklander
76850a81498SJens Wiklander if (!node->dirty)
76950a81498SJens Wiklander return TEE_SUCCESS;
77050a81498SJens Wiklander
77150a81498SJens Wiklander if (node->parent) {
77250a81498SJens Wiklander uint32_t f = HTREE_NODE_COMMITTED_CHILD(node->id & 1);
77350a81498SJens Wiklander
77450a81498SJens Wiklander node->parent->dirty = true;
77550a81498SJens Wiklander node->parent->node.flags ^= f;
77650a81498SJens Wiklander vers = !!(node->parent->node.flags & f);
77750a81498SJens Wiklander } else {
77850a81498SJens Wiklander /*
77950a81498SJens Wiklander * Counter isn't updated yet, it's increased just before
78050a81498SJens Wiklander * writing the header.
78150a81498SJens Wiklander */
78250a81498SJens Wiklander vers = !(targ->ht->head.counter & 1);
78394a72998SJens Wiklander meta = &targ->ht->imeta.meta;
78450a81498SJens Wiklander }
78550a81498SJens Wiklander
78694a72998SJens Wiklander res = calc_node_hash(node, meta, targ->arg, node->node.hash);
78750a81498SJens Wiklander if (res != TEE_SUCCESS)
78850a81498SJens Wiklander return res;
78950a81498SJens Wiklander
79050a81498SJens Wiklander node->dirty = false;
791e2adafecSJens Wiklander node->block_updated = false;
79250a81498SJens Wiklander
79350a81498SJens Wiklander return rpc_write_node(targ->ht, node->id, vers, &node->node);
79450a81498SJens Wiklander }
79550a81498SJens Wiklander
update_root(struct tee_fs_htree * ht)79650a81498SJens Wiklander static TEE_Result update_root(struct tee_fs_htree *ht)
79750a81498SJens Wiklander {
79850a81498SJens Wiklander TEE_Result res;
79950a81498SJens Wiklander void *ctx;
80050a81498SJens Wiklander
80150a81498SJens Wiklander ht->head.counter++;
80250a81498SJens Wiklander
80350a81498SJens Wiklander res = authenc_init(&ctx, TEE_MODE_ENCRYPT, ht, NULL, sizeof(ht->imeta));
80450a81498SJens Wiklander if (res != TEE_SUCCESS)
80550a81498SJens Wiklander return res;
80650a81498SJens Wiklander
80750a81498SJens Wiklander return authenc_encrypt_final(ctx, ht->head.tag, &ht->imeta,
80850a81498SJens Wiklander sizeof(ht->imeta), &ht->head.imeta);
80950a81498SJens Wiklander }
81050a81498SJens Wiklander
tee_fs_htree_sync_to_storage(struct tee_fs_htree ** ht_arg,uint8_t * hash,uint32_t * counter)811f28e5060SJens Wiklander TEE_Result tee_fs_htree_sync_to_storage(struct tee_fs_htree **ht_arg,
812623b9bd4SJens Wiklander uint8_t *hash, uint32_t *counter)
81350a81498SJens Wiklander {
81450a81498SJens Wiklander TEE_Result res;
81550a81498SJens Wiklander struct tee_fs_htree *ht = *ht_arg;
81650a81498SJens Wiklander void *ctx;
81750a81498SJens Wiklander
81850a81498SJens Wiklander if (!ht)
81950a81498SJens Wiklander return TEE_ERROR_CORRUPT_OBJECT;
82050a81498SJens Wiklander
821a48d0254SJens Wiklander if (!ht->dirty)
822a48d0254SJens Wiklander return TEE_SUCCESS;
823a48d0254SJens Wiklander
824ecf2e014SJens Wiklander res = crypto_hash_alloc_ctx(&ctx, TEE_FS_HTREE_HASH_ALG);
82550a81498SJens Wiklander if (res != TEE_SUCCESS)
82650a81498SJens Wiklander return res;
82750a81498SJens Wiklander
82850a81498SJens Wiklander res = htree_traverse_post_order(ht, htree_sync_node_to_storage, ctx);
82950a81498SJens Wiklander if (res != TEE_SUCCESS)
83050a81498SJens Wiklander goto out;
83150a81498SJens Wiklander
83250a81498SJens Wiklander /* All the nodes are written to storage now. Time to update root. */
83350a81498SJens Wiklander res = update_root(ht);
83450a81498SJens Wiklander if (res != TEE_SUCCESS)
83550a81498SJens Wiklander goto out;
83650a81498SJens Wiklander
83750a81498SJens Wiklander res = rpc_write_head(ht, ht->head.counter & 1, &ht->head);
83850a81498SJens Wiklander if (res != TEE_SUCCESS)
83950a81498SJens Wiklander goto out;
84050a81498SJens Wiklander
84150a81498SJens Wiklander ht->dirty = false;
842f28e5060SJens Wiklander if (hash)
843f28e5060SJens Wiklander memcpy(hash, ht->root.node.hash, sizeof(ht->root.node.hash));
844623b9bd4SJens Wiklander if (counter)
845623b9bd4SJens Wiklander *counter = ht->head.counter;
84650a81498SJens Wiklander out:
8476b3a371cSJens Wiklander crypto_hash_free_ctx(ctx);
84850a81498SJens Wiklander if (res != TEE_SUCCESS)
84950a81498SJens Wiklander tee_fs_htree_close(ht_arg);
85050a81498SJens Wiklander return res;
85150a81498SJens Wiklander }
85250a81498SJens Wiklander
get_block_node(struct tee_fs_htree * ht,bool create,size_t block_num,struct htree_node ** node)85350a81498SJens Wiklander static TEE_Result get_block_node(struct tee_fs_htree *ht, bool create,
854e2adafecSJens Wiklander size_t block_num, struct htree_node **node)
85550a81498SJens Wiklander {
85650a81498SJens Wiklander TEE_Result res;
85750a81498SJens Wiklander struct htree_node *nd;
85850a81498SJens Wiklander
85950a81498SJens Wiklander res = get_node(ht, create, BLOCK_NUM_TO_NODE_ID(block_num), &nd);
860e2adafecSJens Wiklander if (res == TEE_SUCCESS)
86150a81498SJens Wiklander *node = nd;
86250a81498SJens Wiklander
86350a81498SJens Wiklander return res;
86450a81498SJens Wiklander }
86550a81498SJens Wiklander
tee_fs_htree_write_block(struct tee_fs_htree ** ht_arg,size_t block_num,const void * block)86650a81498SJens Wiklander TEE_Result tee_fs_htree_write_block(struct tee_fs_htree **ht_arg,
86750a81498SJens Wiklander size_t block_num, const void *block)
86850a81498SJens Wiklander {
86950a81498SJens Wiklander struct tee_fs_htree *ht = *ht_arg;
87050a81498SJens Wiklander TEE_Result res;
87150a81498SJens Wiklander struct tee_fs_rpc_operation op;
87250a81498SJens Wiklander struct htree_node *node = NULL;
87350a81498SJens Wiklander uint8_t block_vers;
87450a81498SJens Wiklander void *ctx;
87550a81498SJens Wiklander void *enc_block;
87650a81498SJens Wiklander
87750a81498SJens Wiklander if (!ht)
87850a81498SJens Wiklander return TEE_ERROR_CORRUPT_OBJECT;
87950a81498SJens Wiklander
880e2adafecSJens Wiklander res = get_block_node(ht, true, block_num, &node);
88150a81498SJens Wiklander if (res != TEE_SUCCESS)
88250a81498SJens Wiklander goto out;
88350a81498SJens Wiklander
884e2adafecSJens Wiklander if (!node->block_updated)
885e2adafecSJens Wiklander node->node.flags ^= HTREE_NODE_COMMITTED_BLOCK;
886e2adafecSJens Wiklander
887e2adafecSJens Wiklander block_vers = !!(node->node.flags & HTREE_NODE_COMMITTED_BLOCK);
88850a81498SJens Wiklander res = ht->stor->rpc_write_init(ht->stor_aux, &op,
88950a81498SJens Wiklander TEE_FS_HTREE_TYPE_BLOCK, block_num,
89050a81498SJens Wiklander block_vers, &enc_block);
89150a81498SJens Wiklander if (res != TEE_SUCCESS)
89250a81498SJens Wiklander goto out;
89350a81498SJens Wiklander
89450a81498SJens Wiklander res = authenc_init(&ctx, TEE_MODE_ENCRYPT, ht, &node->node,
89550a81498SJens Wiklander ht->stor->block_size);
89650a81498SJens Wiklander if (res != TEE_SUCCESS)
89750a81498SJens Wiklander goto out;
89850a81498SJens Wiklander res = authenc_encrypt_final(ctx, node->node.tag, block,
89950a81498SJens Wiklander ht->stor->block_size, enc_block);
90050a81498SJens Wiklander if (res != TEE_SUCCESS)
90150a81498SJens Wiklander goto out;
90250a81498SJens Wiklander
90364fa6c0aSJens Wiklander res = ht->stor->rpc_write_final(&op);
90450a81498SJens Wiklander if (res != TEE_SUCCESS)
90550a81498SJens Wiklander goto out;
90650a81498SJens Wiklander
907e2adafecSJens Wiklander node->block_updated = true;
90850a81498SJens Wiklander node->dirty = true;
90950a81498SJens Wiklander ht->dirty = true;
91050a81498SJens Wiklander out:
91150a81498SJens Wiklander if (res != TEE_SUCCESS)
91250a81498SJens Wiklander tee_fs_htree_close(ht_arg);
91350a81498SJens Wiklander return res;
91450a81498SJens Wiklander }
91550a81498SJens Wiklander
tee_fs_htree_read_block(struct tee_fs_htree ** ht_arg,size_t block_num,void * block)91650a81498SJens Wiklander TEE_Result tee_fs_htree_read_block(struct tee_fs_htree **ht_arg,
91750a81498SJens Wiklander size_t block_num, void *block)
91850a81498SJens Wiklander {
91950a81498SJens Wiklander struct tee_fs_htree *ht = *ht_arg;
92050a81498SJens Wiklander TEE_Result res;
92150a81498SJens Wiklander struct tee_fs_rpc_operation op;
92250a81498SJens Wiklander struct htree_node *node;
92350a81498SJens Wiklander uint8_t block_vers;
92450a81498SJens Wiklander size_t len;
92550a81498SJens Wiklander void *ctx;
92650a81498SJens Wiklander void *enc_block;
92750a81498SJens Wiklander
92850a81498SJens Wiklander if (!ht)
92950a81498SJens Wiklander return TEE_ERROR_CORRUPT_OBJECT;
93050a81498SJens Wiklander
931e2adafecSJens Wiklander res = get_block_node(ht, false, block_num, &node);
93250a81498SJens Wiklander if (res != TEE_SUCCESS)
93350a81498SJens Wiklander goto out;
93450a81498SJens Wiklander
935e2adafecSJens Wiklander block_vers = !!(node->node.flags & HTREE_NODE_COMMITTED_BLOCK);
93650a81498SJens Wiklander res = ht->stor->rpc_read_init(ht->stor_aux, &op,
93750a81498SJens Wiklander TEE_FS_HTREE_TYPE_BLOCK, block_num,
93850a81498SJens Wiklander block_vers, &enc_block);
93950a81498SJens Wiklander if (res != TEE_SUCCESS)
94050a81498SJens Wiklander goto out;
94150a81498SJens Wiklander
94264fa6c0aSJens Wiklander res = ht->stor->rpc_read_final(&op, &len);
94350a81498SJens Wiklander if (res != TEE_SUCCESS)
94450a81498SJens Wiklander goto out;
94550a81498SJens Wiklander if (len != ht->stor->block_size) {
94650a81498SJens Wiklander res = TEE_ERROR_CORRUPT_OBJECT;
94750a81498SJens Wiklander goto out;
94850a81498SJens Wiklander }
94950a81498SJens Wiklander
95050a81498SJens Wiklander res = authenc_init(&ctx, TEE_MODE_DECRYPT, ht, &node->node,
95150a81498SJens Wiklander ht->stor->block_size);
95250a81498SJens Wiklander if (res != TEE_SUCCESS)
95350a81498SJens Wiklander goto out;
95450a81498SJens Wiklander
95550a81498SJens Wiklander res = authenc_decrypt_final(ctx, node->node.tag, enc_block,
95650a81498SJens Wiklander ht->stor->block_size, block);
95750a81498SJens Wiklander out:
95850a81498SJens Wiklander if (res != TEE_SUCCESS)
95950a81498SJens Wiklander tee_fs_htree_close(ht_arg);
96050a81498SJens Wiklander return res;
96150a81498SJens Wiklander }
96250a81498SJens Wiklander
tee_fs_htree_truncate(struct tee_fs_htree ** ht_arg,size_t block_num)96350a81498SJens Wiklander TEE_Result tee_fs_htree_truncate(struct tee_fs_htree **ht_arg, size_t block_num)
96450a81498SJens Wiklander {
96550a81498SJens Wiklander struct tee_fs_htree *ht = *ht_arg;
96650a81498SJens Wiklander size_t node_id = BLOCK_NUM_TO_NODE_ID(block_num);
96750a81498SJens Wiklander struct htree_node *node;
96850a81498SJens Wiklander
96950a81498SJens Wiklander if (!ht)
97050a81498SJens Wiklander return TEE_ERROR_CORRUPT_OBJECT;
97150a81498SJens Wiklander
97250a81498SJens Wiklander while (node_id < ht->imeta.max_node_id) {
97350a81498SJens Wiklander node = find_closest_node(ht, ht->imeta.max_node_id);
97450a81498SJens Wiklander assert(node && node->id == ht->imeta.max_node_id);
97550a81498SJens Wiklander assert(!node->child[0] && !node->child[1]);
97650a81498SJens Wiklander assert(node->parent);
97750a81498SJens Wiklander assert(node->parent->child[node->id & 1] == node);
97850a81498SJens Wiklander node->parent->child[node->id & 1] = NULL;
97950a81498SJens Wiklander free(node);
98050a81498SJens Wiklander ht->imeta.max_node_id--;
98150a81498SJens Wiklander ht->dirty = true;
98250a81498SJens Wiklander }
98350a81498SJens Wiklander
98450a81498SJens Wiklander return TEE_SUCCESS;
98550a81498SJens Wiklander }
986