xref: /optee_os/core/tee/fs_htree.c (revision 0c4e1284c44fe5700824a3fb47fff82d76025ff8)
150a81498SJens Wiklander /*
250a81498SJens Wiklander  * Copyright (c) 2017, Linaro Limited
350a81498SJens Wiklander  * All rights reserved.
450a81498SJens Wiklander  *
550a81498SJens Wiklander  * Redistribution and use in source and binary forms, with or without
650a81498SJens Wiklander  * modification, are permitted provided that the following conditions are met:
750a81498SJens Wiklander  *
850a81498SJens Wiklander  * 1. Redistributions of source code must retain the above copyright notice,
950a81498SJens Wiklander  * this list of conditions and the following disclaimer.
1050a81498SJens Wiklander  *
1150a81498SJens Wiklander  * 2. Redistributions in binary form must reproduce the above copyright notice,
1250a81498SJens Wiklander  * this list of conditions and the following disclaimer in the documentation
1350a81498SJens Wiklander  * and/or other materials provided with the distribution.
1450a81498SJens Wiklander  *
1550a81498SJens Wiklander  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1650a81498SJens Wiklander  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1750a81498SJens Wiklander  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1850a81498SJens Wiklander  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
1950a81498SJens Wiklander  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2050a81498SJens Wiklander  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2150a81498SJens Wiklander  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2250a81498SJens Wiklander  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2350a81498SJens Wiklander  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2450a81498SJens Wiklander  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2550a81498SJens Wiklander  * POSSIBILITY OF SUCH DAMAGE.
2650a81498SJens Wiklander  */
2750a81498SJens Wiklander 
2850a81498SJens Wiklander #include <assert.h>
2950a81498SJens Wiklander #include <initcall.h>
3050a81498SJens Wiklander #include <kernel/tee_common_otp.h>
3150a81498SJens Wiklander #include <optee_msg_supplicant.h>
3250a81498SJens Wiklander #include <stdlib.h>
3350a81498SJens Wiklander #include <string_ext.h>
3450a81498SJens Wiklander #include <string.h>
3550a81498SJens Wiklander #include <tee/fs_htree.h>
3650a81498SJens Wiklander #include <tee/tee_cryp_provider.h>
3750a81498SJens Wiklander #include <tee/tee_fs_key_manager.h>
3850a81498SJens Wiklander #include <tee/tee_fs_rpc.h>
3950a81498SJens Wiklander #include <utee_defines.h>
4050a81498SJens Wiklander #include <util.h>
4150a81498SJens Wiklander 
4250a81498SJens Wiklander #define TEE_FS_HTREE_CHIP_ID_SIZE	32
4350a81498SJens Wiklander #define TEE_FS_HTREE_HASH_ALG		TEE_ALG_SHA256
4450a81498SJens Wiklander #define TEE_FS_HTREE_TSK_SIZE		TEE_FS_HTREE_HASH_SIZE
4550a81498SJens Wiklander #define TEE_FS_HTREE_ENC_ALG		TEE_ALG_AES_ECB_NOPAD
4650a81498SJens Wiklander #define TEE_FS_HTREE_ENC_SIZE		TEE_AES_BLOCK_SIZE
4750a81498SJens Wiklander #define TEE_FS_HTREE_SSK_SIZE		TEE_FS_HTREE_HASH_SIZE
4850a81498SJens Wiklander 
4950a81498SJens Wiklander #define TEE_FS_HTREE_AUTH_ENC_ALG	TEE_ALG_AES_GCM
5050a81498SJens Wiklander #define TEE_FS_HTREE_HMAC_ALG		TEE_ALG_HMAC_SHA256
5150a81498SJens Wiklander 
5250a81498SJens Wiklander #define BLOCK_NUM_TO_NODE_ID(num)	((num) + 1)
5350a81498SJens Wiklander 
5450a81498SJens Wiklander #define NODE_ID_TO_BLOCK_NUM(id)	((id) - 1)
5550a81498SJens Wiklander 
5650a81498SJens Wiklander /*
5750a81498SJens Wiklander  * The hash tree is implemented as a binary tree with the purpose to ensure
5850a81498SJens Wiklander  * integrity of the data in the nodes. The data in the nodes their turn
5950a81498SJens Wiklander  * provides both integrity and confidentiality of the data blocks.
6050a81498SJens Wiklander  *
6150a81498SJens Wiklander  * The hash tree is saved in a file as:
6250a81498SJens Wiklander  * +----------------------------+
6350a81498SJens Wiklander  * | htree_image.0		|
6450a81498SJens Wiklander  * | htree_image.1		|
6550a81498SJens Wiklander  * +----------------------------+
6650a81498SJens Wiklander  * | htree_node_image.1.0	|
6750a81498SJens Wiklander  * | htree_node_image.1.1	|
6850a81498SJens Wiklander  * +----------------------------+
6950a81498SJens Wiklander  * | htree_node_image.2.0	|
7050a81498SJens Wiklander  * | htree_node_image.2.1	|
7150a81498SJens Wiklander  * +----------------------------+
7250a81498SJens Wiklander  * | htree_node_image.3.0	|
7350a81498SJens Wiklander  * | htree_node_image.3.1	|
7450a81498SJens Wiklander  * +----------------------------+
7550a81498SJens Wiklander  * | htree_node_image.4.0	|
7650a81498SJens Wiklander  * | htree_node_image.4.1	|
7750a81498SJens Wiklander  * +----------------------------+
7850a81498SJens Wiklander  * ...
7950a81498SJens Wiklander  *
8050a81498SJens Wiklander  * htree_image is the header of the file, there's two instances of it. One
8150a81498SJens Wiklander  * which is committed and the other is used when updating the file. Which
8250a81498SJens Wiklander  * is committed is indicated by the "counter" field, the one with the
8350a81498SJens Wiklander  * largest value is selected.
8450a81498SJens Wiklander  *
8550a81498SJens Wiklander  * htree_node_image is a node in the hash tree, each node has two instances
8650a81498SJens Wiklander  * which is committed is decided by the parent node .flag bit
87e2adafecSJens Wiklander  * HTREE_NODE_COMMITTED_CHILD. Which version is the committed version of
8850a81498SJens Wiklander  * node 1 is determined by the by the lowest bit of the counter field in
8950a81498SJens Wiklander  * the header.
9050a81498SJens Wiklander  *
9150a81498SJens Wiklander  * Note that nodes start counting at 1 while blocks at 0, this means that
9250a81498SJens Wiklander  * block 0 is represented by node 1.
9350a81498SJens Wiklander  *
9450a81498SJens Wiklander  * Where different elements are stored in the file is managed by the file
9550a81498SJens Wiklander  * system. In the case of SQL FS the version of the node/block is ignored
9650a81498SJens Wiklander  * as the atomic update is finalized with a call to
9750a81498SJens Wiklander  * tee_fs_rpc_end_transaction().
9850a81498SJens Wiklander  */
9950a81498SJens Wiklander 
10050a81498SJens Wiklander #define HTREE_NODE_COMMITTED_BLOCK	BIT32(0)
10150a81498SJens Wiklander /* n is 0 or 1 */
10250a81498SJens Wiklander #define HTREE_NODE_COMMITTED_CHILD(n)	BIT32(1 + (n))
10350a81498SJens Wiklander 
10450a81498SJens Wiklander struct htree_node {
10550a81498SJens Wiklander 	size_t id;
10650a81498SJens Wiklander 	bool dirty;
107e2adafecSJens Wiklander 	bool block_updated;
10850a81498SJens Wiklander 	struct tee_fs_htree_node_image node;
10950a81498SJens Wiklander 	struct htree_node *parent;
11050a81498SJens Wiklander 	struct htree_node *child[2];
11150a81498SJens Wiklander };
11250a81498SJens Wiklander 
11350a81498SJens Wiklander struct tee_fs_htree {
11450a81498SJens Wiklander 	struct htree_node root;
11550a81498SJens Wiklander 	struct tee_fs_htree_image head;
11650a81498SJens Wiklander 	uint8_t fek[TEE_FS_HTREE_FEK_SIZE];
11750a81498SJens Wiklander 	struct tee_fs_htree_imeta imeta;
11850a81498SJens Wiklander 	bool dirty;
119*0c4e1284SJens Wiklander 	const TEE_UUID *uuid;
12050a81498SJens Wiklander 	const struct tee_fs_htree_storage *stor;
12150a81498SJens Wiklander 	void *stor_aux;
12250a81498SJens Wiklander };
12350a81498SJens Wiklander 
12450a81498SJens Wiklander struct traverse_arg;
12550a81498SJens Wiklander typedef TEE_Result (*traverse_cb_t)(struct traverse_arg *targ,
12650a81498SJens Wiklander 				    struct htree_node *node);
12750a81498SJens Wiklander struct traverse_arg {
12850a81498SJens Wiklander 	struct tee_fs_htree *ht;
12950a81498SJens Wiklander 	traverse_cb_t cb;
13050a81498SJens Wiklander 	void *arg;
13150a81498SJens Wiklander };
13250a81498SJens Wiklander 
13350a81498SJens Wiklander static TEE_Result rpc_read(struct tee_fs_htree *ht, enum tee_fs_htree_type type,
13450a81498SJens Wiklander 			   size_t idx, size_t vers, void *data, size_t dlen)
13550a81498SJens Wiklander {
13650a81498SJens Wiklander 	TEE_Result res;
13750a81498SJens Wiklander 	struct tee_fs_rpc_operation op;
13850a81498SJens Wiklander 	size_t bytes;
13950a81498SJens Wiklander 	void *p;
14050a81498SJens Wiklander 
14150a81498SJens Wiklander 	res = ht->stor->rpc_read_init(ht->stor_aux, &op, type, idx, vers, &p);
14250a81498SJens Wiklander 	if (res != TEE_SUCCESS)
14350a81498SJens Wiklander 		return res;
14450a81498SJens Wiklander 
14564fa6c0aSJens Wiklander 	res = ht->stor->rpc_read_final(&op, &bytes);
14650a81498SJens Wiklander 	if (res != TEE_SUCCESS)
14750a81498SJens Wiklander 		return res;
14850a81498SJens Wiklander 
14950a81498SJens Wiklander 	if (bytes != dlen)
15050a81498SJens Wiklander 		return TEE_ERROR_CORRUPT_OBJECT;
15150a81498SJens Wiklander 
15250a81498SJens Wiklander 	memcpy(data, p, dlen);
15350a81498SJens Wiklander 	return TEE_SUCCESS;
15450a81498SJens Wiklander }
15550a81498SJens Wiklander 
15650a81498SJens Wiklander static TEE_Result rpc_read_head(struct tee_fs_htree *ht, size_t vers,
15750a81498SJens Wiklander 				struct tee_fs_htree_image *head)
15850a81498SJens Wiklander {
15950a81498SJens Wiklander 	return rpc_read(ht, TEE_FS_HTREE_TYPE_HEAD, 0, vers,
16050a81498SJens Wiklander 			head, sizeof(*head));
16150a81498SJens Wiklander }
16250a81498SJens Wiklander 
16350a81498SJens Wiklander static TEE_Result rpc_read_node(struct tee_fs_htree *ht, size_t node_id,
16450a81498SJens Wiklander 				size_t vers,
16550a81498SJens Wiklander 				struct tee_fs_htree_node_image *node)
16650a81498SJens Wiklander {
16750a81498SJens Wiklander 	return rpc_read(ht, TEE_FS_HTREE_TYPE_NODE, node_id - 1, vers,
16850a81498SJens Wiklander 			node, sizeof(*node));
16950a81498SJens Wiklander }
17050a81498SJens Wiklander 
17150a81498SJens Wiklander static TEE_Result rpc_write(struct tee_fs_htree *ht,
17250a81498SJens Wiklander 			    enum tee_fs_htree_type type, size_t idx,
17350a81498SJens Wiklander 			    size_t vers, const void *data, size_t dlen)
17450a81498SJens Wiklander {
17550a81498SJens Wiklander 	TEE_Result res;
17650a81498SJens Wiklander 	struct tee_fs_rpc_operation op;
17750a81498SJens Wiklander 	void *p;
17850a81498SJens Wiklander 
17950a81498SJens Wiklander 	res = ht->stor->rpc_write_init(ht->stor_aux, &op, type, idx, vers, &p);
18050a81498SJens Wiklander 	if (res != TEE_SUCCESS)
18150a81498SJens Wiklander 		return res;
18250a81498SJens Wiklander 
18350a81498SJens Wiklander 	memcpy(p, data, dlen);
18464fa6c0aSJens Wiklander 	return ht->stor->rpc_write_final(&op);
18550a81498SJens Wiklander }
18650a81498SJens Wiklander 
18750a81498SJens Wiklander static TEE_Result rpc_write_head(struct tee_fs_htree *ht, size_t vers,
18850a81498SJens Wiklander 				 const struct tee_fs_htree_image *head)
18950a81498SJens Wiklander {
19050a81498SJens Wiklander 	return rpc_write(ht, TEE_FS_HTREE_TYPE_HEAD, 0, vers,
19150a81498SJens Wiklander 			 head, sizeof(*head));
19250a81498SJens Wiklander }
19350a81498SJens Wiklander 
19450a81498SJens Wiklander static TEE_Result rpc_write_node(struct tee_fs_htree *ht, size_t node_id,
19550a81498SJens Wiklander 				 size_t vers,
19650a81498SJens Wiklander 				 const struct tee_fs_htree_node_image *node)
19750a81498SJens Wiklander {
19850a81498SJens Wiklander 	return rpc_write(ht, TEE_FS_HTREE_TYPE_NODE, node_id - 1, vers,
19950a81498SJens Wiklander 			 node, sizeof(*node));
20050a81498SJens Wiklander }
20150a81498SJens Wiklander 
20250a81498SJens Wiklander static TEE_Result traverse_post_order(struct traverse_arg *targ,
20350a81498SJens Wiklander 				      struct htree_node *node)
20450a81498SJens Wiklander {
20550a81498SJens Wiklander 	TEE_Result res;
20650a81498SJens Wiklander 
20750a81498SJens Wiklander 	/*
20850a81498SJens Wiklander 	 * This function is recursing but not very deep, only with Log(N)
20950a81498SJens Wiklander 	 * maximum depth.
21050a81498SJens Wiklander 	 */
21150a81498SJens Wiklander 
21250a81498SJens Wiklander 	if (!node)
21350a81498SJens Wiklander 		return TEE_SUCCESS;
21450a81498SJens Wiklander 
21550a81498SJens Wiklander 	res = traverse_post_order(targ, node->child[0]);
21650a81498SJens Wiklander 	if (res != TEE_SUCCESS)
21750a81498SJens Wiklander 		return res;
21850a81498SJens Wiklander 
21950a81498SJens Wiklander 	res = traverse_post_order(targ, node->child[1]);
22050a81498SJens Wiklander 	if (res != TEE_SUCCESS)
22150a81498SJens Wiklander 		return res;
22250a81498SJens Wiklander 
22350a81498SJens Wiklander 	return targ->cb(targ, node);
22450a81498SJens Wiklander }
22550a81498SJens Wiklander 
22650a81498SJens Wiklander static TEE_Result htree_traverse_post_order(struct tee_fs_htree *ht,
22750a81498SJens Wiklander 					    traverse_cb_t cb, void *arg)
22850a81498SJens Wiklander {
22950a81498SJens Wiklander 	struct traverse_arg targ = { ht, cb, arg };
23050a81498SJens Wiklander 
23150a81498SJens Wiklander 	return traverse_post_order(&targ, &ht->root);
23250a81498SJens Wiklander }
23350a81498SJens Wiklander 
23450a81498SJens Wiklander static size_t node_id_to_level(size_t node_id)
23550a81498SJens Wiklander {
23650a81498SJens Wiklander 	assert(node_id && node_id < UINT_MAX);
23750a81498SJens Wiklander 	/* Calculate level of the node, root node (1) has level 1 */
23850a81498SJens Wiklander 	return sizeof(unsigned int) * 8 - __builtin_clz(node_id);
23950a81498SJens Wiklander }
24050a81498SJens Wiklander 
24150a81498SJens Wiklander static struct htree_node *find_closest_node(struct tee_fs_htree *ht,
24250a81498SJens Wiklander 					    size_t node_id)
24350a81498SJens Wiklander {
24450a81498SJens Wiklander 	struct htree_node *node = &ht->root;
24550a81498SJens Wiklander 	size_t level = node_id_to_level(node_id);
24650a81498SJens Wiklander 	size_t n;
24750a81498SJens Wiklander 
24850a81498SJens Wiklander 	/* n = 1 because root node is level 1 */
24950a81498SJens Wiklander 	for (n = 1; n < level; n++) {
25050a81498SJens Wiklander 		struct htree_node *child;
25150a81498SJens Wiklander 		size_t bit_idx;
25250a81498SJens Wiklander 
25350a81498SJens Wiklander 		/*
25450a81498SJens Wiklander 		 * The difference between levels of the current node and
25550a81498SJens Wiklander 		 * the node we're looking for tells which bit decides
25650a81498SJens Wiklander 		 * direction in the tree.
25750a81498SJens Wiklander 		 *
25850a81498SJens Wiklander 		 * As the first bit has index 0 we'll subtract 1
25950a81498SJens Wiklander 		 */
26050a81498SJens Wiklander 		bit_idx = level - n - 1;
26150a81498SJens Wiklander 		child = node->child[((node_id >> bit_idx) & 1)];
26250a81498SJens Wiklander 		if (!child)
26350a81498SJens Wiklander 			return node;
26450a81498SJens Wiklander 		node = child;
26550a81498SJens Wiklander 	}
26650a81498SJens Wiklander 
26750a81498SJens Wiklander 	return node;
26850a81498SJens Wiklander }
26950a81498SJens Wiklander 
27050a81498SJens Wiklander static struct htree_node *find_node(struct tee_fs_htree *ht, size_t node_id)
27150a81498SJens Wiklander {
27250a81498SJens Wiklander 	struct htree_node *node = find_closest_node(ht, node_id);
27350a81498SJens Wiklander 
27450a81498SJens Wiklander 	if (node && node->id == node_id)
27550a81498SJens Wiklander 		return node;
27650a81498SJens Wiklander 	return NULL;
27750a81498SJens Wiklander }
27850a81498SJens Wiklander 
27950a81498SJens Wiklander static TEE_Result get_node(struct tee_fs_htree *ht, bool create,
28050a81498SJens Wiklander 			   size_t node_id, struct htree_node **node_ret)
28150a81498SJens Wiklander {
28250a81498SJens Wiklander 	struct htree_node *node;
28350a81498SJens Wiklander 	struct htree_node *nc;
28450a81498SJens Wiklander 	size_t n;
28550a81498SJens Wiklander 
28650a81498SJens Wiklander 	node = find_closest_node(ht, node_id);
28750a81498SJens Wiklander 	if (!node)
28850a81498SJens Wiklander 		return TEE_ERROR_GENERIC;
28950a81498SJens Wiklander 	if (node->id == node_id)
29050a81498SJens Wiklander 		goto ret_node;
29150a81498SJens Wiklander 
29250a81498SJens Wiklander 	/*
29350a81498SJens Wiklander 	 * Trying to read beyond end of file should be caught earlier than
29450a81498SJens Wiklander 	 * here.
29550a81498SJens Wiklander 	 */
29650a81498SJens Wiklander 	if (!create)
29750a81498SJens Wiklander 		return TEE_ERROR_GENERIC;
29850a81498SJens Wiklander 
29950a81498SJens Wiklander 	/*
30050a81498SJens Wiklander 	 * Add missing nodes, some nodes may already be there. When we've
30150a81498SJens Wiklander 	 * processed the range all nodes up to node_id will be in the tree.
30250a81498SJens Wiklander 	 */
30350a81498SJens Wiklander 	for (n = node->id + 1; n <= node_id; n++) {
30450a81498SJens Wiklander 		node = find_closest_node(ht, n);
30550a81498SJens Wiklander 		if (node->id == n)
30650a81498SJens Wiklander 			continue;
30750a81498SJens Wiklander 		/* Node id n should be a child of node */
30850a81498SJens Wiklander 		assert((n >> 1) == node->id);
30950a81498SJens Wiklander 		assert(!node->child[n & 1]);
31050a81498SJens Wiklander 
31150a81498SJens Wiklander 		nc = calloc(1, sizeof(*nc));
31250a81498SJens Wiklander 		if (!nc)
31350a81498SJens Wiklander 			return TEE_ERROR_OUT_OF_MEMORY;
31450a81498SJens Wiklander 		nc->id = n;
31550a81498SJens Wiklander 		nc->parent = node;
31650a81498SJens Wiklander 		node->child[n & 1] = nc;
31750a81498SJens Wiklander 		node = nc;
31850a81498SJens Wiklander 	}
31950a81498SJens Wiklander 
32050a81498SJens Wiklander 	if (node->id > ht->imeta.max_node_id)
32150a81498SJens Wiklander 		ht->imeta.max_node_id = node->id;
32250a81498SJens Wiklander 
32350a81498SJens Wiklander ret_node:
32450a81498SJens Wiklander 	*node_ret = node;
32550a81498SJens Wiklander 	return TEE_SUCCESS;
32650a81498SJens Wiklander }
32750a81498SJens Wiklander 
32850a81498SJens Wiklander static int get_idx_from_counter(uint32_t counter0, uint32_t counter1)
32950a81498SJens Wiklander {
33050a81498SJens Wiklander 	if (!(counter0 & 1)) {
33150a81498SJens Wiklander 		if (!(counter1 & 1))
33250a81498SJens Wiklander 			return 0;
33350a81498SJens Wiklander 		if (counter0 > counter1)
33450a81498SJens Wiklander 			return 0;
33550a81498SJens Wiklander 		else
33650a81498SJens Wiklander 			return 1;
33750a81498SJens Wiklander 	}
33850a81498SJens Wiklander 
33950a81498SJens Wiklander 	if (counter1 & 1)
34050a81498SJens Wiklander 		return 1;
34150a81498SJens Wiklander 	else
34250a81498SJens Wiklander 		return -1;
34350a81498SJens Wiklander }
34450a81498SJens Wiklander 
345f28e5060SJens Wiklander static TEE_Result init_head_from_data(struct tee_fs_htree *ht,
346f28e5060SJens Wiklander 				      const uint8_t *hash)
34750a81498SJens Wiklander {
34850a81498SJens Wiklander 	TEE_Result res;
34950a81498SJens Wiklander 	int idx;
35050a81498SJens Wiklander 
351f28e5060SJens Wiklander 	if (hash) {
352f28e5060SJens Wiklander 		for (idx = 0;; idx++) {
353f28e5060SJens Wiklander 			res = rpc_read_node(ht, 1, idx, &ht->root.node);
354f28e5060SJens Wiklander 			if (res != TEE_SUCCESS)
355f28e5060SJens Wiklander 				return res;
356f28e5060SJens Wiklander 
357f28e5060SJens Wiklander 			if (!memcmp(ht->root.node.hash, hash,
358f28e5060SJens Wiklander 				    sizeof(ht->root.node.hash))) {
359f28e5060SJens Wiklander 				res = rpc_read_head(ht, idx, &ht->head);
360f28e5060SJens Wiklander 				if (res != TEE_SUCCESS)
361f28e5060SJens Wiklander 					return res;
362f28e5060SJens Wiklander 				break;
363f28e5060SJens Wiklander 			}
364f28e5060SJens Wiklander 
365f28e5060SJens Wiklander 			if (idx)
366f28e5060SJens Wiklander 				return TEE_ERROR_SECURITY;
367f28e5060SJens Wiklander 		}
368f28e5060SJens Wiklander 	} else {
369f28e5060SJens Wiklander 		struct tee_fs_htree_image head[2];
370f28e5060SJens Wiklander 
37150a81498SJens Wiklander 		for (idx = 0; idx < 2; idx++) {
37250a81498SJens Wiklander 			res = rpc_read_head(ht, idx, head + idx);
37350a81498SJens Wiklander 			if (res != TEE_SUCCESS)
37450a81498SJens Wiklander 				return res;
37550a81498SJens Wiklander 		}
37650a81498SJens Wiklander 
37750a81498SJens Wiklander 		idx = get_idx_from_counter(head[0].counter, head[1].counter);
37850a81498SJens Wiklander 		if (idx < 0)
37950a81498SJens Wiklander 			return TEE_ERROR_SECURITY;
38050a81498SJens Wiklander 
38150a81498SJens Wiklander 		res = rpc_read_node(ht, 1, idx, &ht->root.node);
38250a81498SJens Wiklander 		if (res != TEE_SUCCESS)
38350a81498SJens Wiklander 			return res;
38450a81498SJens Wiklander 
38550a81498SJens Wiklander 		ht->head = head[idx];
386f28e5060SJens Wiklander 	}
387f28e5060SJens Wiklander 
38850a81498SJens Wiklander 	ht->root.id = 1;
38950a81498SJens Wiklander 
39050a81498SJens Wiklander 	return TEE_SUCCESS;
39150a81498SJens Wiklander }
39250a81498SJens Wiklander 
39350a81498SJens Wiklander static TEE_Result init_tree_from_data(struct tee_fs_htree *ht)
39450a81498SJens Wiklander {
39550a81498SJens Wiklander 	TEE_Result res;
39650a81498SJens Wiklander 	struct tee_fs_htree_node_image node_image;
39750a81498SJens Wiklander 	struct htree_node *node;
39850a81498SJens Wiklander 	struct htree_node *nc;
39950a81498SJens Wiklander 	size_t committed_version;
40050a81498SJens Wiklander 	size_t node_id = 2;
40150a81498SJens Wiklander 
40250a81498SJens Wiklander 	while (node_id <= ht->imeta.max_node_id) {
40350a81498SJens Wiklander 		node = find_node(ht, node_id >> 1);
40450a81498SJens Wiklander 		if (!node)
40550a81498SJens Wiklander 			return TEE_ERROR_GENERIC;
40650a81498SJens Wiklander 		committed_version = !!(node->node.flags &
40750a81498SJens Wiklander 				    HTREE_NODE_COMMITTED_CHILD(node_id & 1));
40850a81498SJens Wiklander 
40950a81498SJens Wiklander 		res = rpc_read_node(ht, node_id, committed_version,
41050a81498SJens Wiklander 				    &node_image);
41150a81498SJens Wiklander 		if (res != TEE_SUCCESS)
41250a81498SJens Wiklander 			return res;
41350a81498SJens Wiklander 
41450a81498SJens Wiklander 		res = get_node(ht, true, node_id, &nc);
41550a81498SJens Wiklander 		if (res != TEE_SUCCESS)
41650a81498SJens Wiklander 			return res;
41750a81498SJens Wiklander 		nc->node = node_image;
41850a81498SJens Wiklander 		node_id++;
41950a81498SJens Wiklander 	}
42050a81498SJens Wiklander 
42150a81498SJens Wiklander 	return TEE_SUCCESS;
42250a81498SJens Wiklander }
42350a81498SJens Wiklander 
42450a81498SJens Wiklander static TEE_Result calc_node_hash(struct htree_node *node, void *ctx,
42550a81498SJens Wiklander 				 uint8_t *digest)
42650a81498SJens Wiklander {
42750a81498SJens Wiklander 	TEE_Result res;
42850a81498SJens Wiklander 	uint32_t alg = TEE_FS_HTREE_HASH_ALG;
42950a81498SJens Wiklander 	uint8_t *ndata = (uint8_t *)&node->node + sizeof(node->node.hash);
43050a81498SJens Wiklander 	size_t nsize = sizeof(node->node) - sizeof(node->node.hash);
43150a81498SJens Wiklander 
43250a81498SJens Wiklander 	res = crypto_ops.hash.init(ctx, alg);
43350a81498SJens Wiklander 	if (res != TEE_SUCCESS)
43450a81498SJens Wiklander 		return res;
43550a81498SJens Wiklander 
43650a81498SJens Wiklander 	res = crypto_ops.hash.update(ctx, alg, ndata, nsize);
43750a81498SJens Wiklander 	if (res != TEE_SUCCESS)
43850a81498SJens Wiklander 		return res;
43950a81498SJens Wiklander 
44050a81498SJens Wiklander 	if (node->child[0]) {
44150a81498SJens Wiklander 		res = crypto_ops.hash.update(ctx, alg,
44250a81498SJens Wiklander 					     node->child[0]->node.hash,
44350a81498SJens Wiklander 					     sizeof(node->child[0]->node.hash));
44450a81498SJens Wiklander 		if (res != TEE_SUCCESS)
44550a81498SJens Wiklander 			return res;
44650a81498SJens Wiklander 	}
44750a81498SJens Wiklander 
44850a81498SJens Wiklander 	if (node->child[1]) {
44950a81498SJens Wiklander 		res = crypto_ops.hash.update(ctx, alg,
45050a81498SJens Wiklander 					     node->child[1]->node.hash,
45150a81498SJens Wiklander 					     sizeof(node->child[1]->node.hash));
45250a81498SJens Wiklander 		if (res != TEE_SUCCESS)
45350a81498SJens Wiklander 			return res;
45450a81498SJens Wiklander 	}
45550a81498SJens Wiklander 
45650a81498SJens Wiklander 	return crypto_ops.hash.final(ctx, alg, digest, TEE_FS_HTREE_HASH_SIZE);
45750a81498SJens Wiklander }
45850a81498SJens Wiklander 
45950a81498SJens Wiklander static TEE_Result authenc_init(void **ctx_ret, TEE_OperationMode mode,
46050a81498SJens Wiklander 			       struct tee_fs_htree *ht,
46150a81498SJens Wiklander 			       struct tee_fs_htree_node_image *ni,
46250a81498SJens Wiklander 			       size_t payload_len)
46350a81498SJens Wiklander {
46450a81498SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
46550a81498SJens Wiklander 	const uint32_t alg = TEE_FS_HTREE_AUTH_ENC_ALG;
46650a81498SJens Wiklander 	uint8_t *ctx;
46750a81498SJens Wiklander 	size_t ctx_size;
46850a81498SJens Wiklander 	size_t aad_len = TEE_FS_HTREE_FEK_SIZE + TEE_FS_HTREE_IV_SIZE;
46950a81498SJens Wiklander 	uint8_t *iv;
47050a81498SJens Wiklander 
47150a81498SJens Wiklander 	if (ni) {
47250a81498SJens Wiklander 		iv = ni->iv;
47350a81498SJens Wiklander 	} else {
47450a81498SJens Wiklander 		iv = ht->head.iv;
47550a81498SJens Wiklander 		aad_len += TEE_FS_HTREE_HASH_SIZE + sizeof(ht->head.counter);
47650a81498SJens Wiklander 	}
47750a81498SJens Wiklander 
47850a81498SJens Wiklander 	if (mode == TEE_MODE_ENCRYPT) {
47950a81498SJens Wiklander 		res = crypto_ops.prng.read(iv, TEE_FS_HTREE_IV_SIZE);
48050a81498SJens Wiklander 		if (res != TEE_SUCCESS)
48150a81498SJens Wiklander 			return res;
48250a81498SJens Wiklander 	}
48350a81498SJens Wiklander 
48450a81498SJens Wiklander 	res = crypto_ops.authenc.get_ctx_size(alg, &ctx_size);
48550a81498SJens Wiklander 	if (res != TEE_SUCCESS)
48650a81498SJens Wiklander 		return res;
48750a81498SJens Wiklander 
48850a81498SJens Wiklander 	ctx = malloc(ctx_size);
48950a81498SJens Wiklander 	if (!ctx) {
49050a81498SJens Wiklander 		EMSG("request memory size %zu failed", ctx_size);
49150a81498SJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
49250a81498SJens Wiklander 	}
49350a81498SJens Wiklander 
49450a81498SJens Wiklander 	res = crypto_ops.authenc.init(ctx, alg, mode,
49550a81498SJens Wiklander 				      ht->fek, TEE_FS_HTREE_FEK_SIZE,
49650a81498SJens Wiklander 				      iv, TEE_FS_HTREE_IV_SIZE,
49750a81498SJens Wiklander 				      TEE_FS_HTREE_TAG_SIZE, aad_len,
49850a81498SJens Wiklander 				      payload_len);
49950a81498SJens Wiklander 	if (res != TEE_SUCCESS)
50050a81498SJens Wiklander 		goto exit;
50150a81498SJens Wiklander 
50250a81498SJens Wiklander 	if (!ni) {
50350a81498SJens Wiklander 		res = crypto_ops.authenc.update_aad(ctx, alg, mode,
50450a81498SJens Wiklander 						    ht->root.node.hash,
50550a81498SJens Wiklander 						    TEE_FS_HTREE_FEK_SIZE);
50650a81498SJens Wiklander 		if (res != TEE_SUCCESS)
50750a81498SJens Wiklander 			goto exit;
50850a81498SJens Wiklander 
50950a81498SJens Wiklander 		res = crypto_ops.authenc.update_aad(ctx, alg, mode,
51050a81498SJens Wiklander 						    (void *)&ht->head.counter,
51150a81498SJens Wiklander 						    sizeof(ht->head.counter));
51250a81498SJens Wiklander 		if (res != TEE_SUCCESS)
51350a81498SJens Wiklander 			goto exit;
51450a81498SJens Wiklander 	}
51550a81498SJens Wiklander 
51650a81498SJens Wiklander 	res = crypto_ops.authenc.update_aad(ctx, alg, mode, ht->head.enc_fek,
51750a81498SJens Wiklander 					    TEE_FS_HTREE_FEK_SIZE);
51850a81498SJens Wiklander 	if (res != TEE_SUCCESS)
51950a81498SJens Wiklander 		goto exit;
52050a81498SJens Wiklander 
52150a81498SJens Wiklander 	res = crypto_ops.authenc.update_aad(ctx, alg, mode, iv,
52250a81498SJens Wiklander 					    TEE_FS_HTREE_IV_SIZE);
52350a81498SJens Wiklander 
52450a81498SJens Wiklander exit:
52550a81498SJens Wiklander 	if (res == TEE_SUCCESS)
52650a81498SJens Wiklander 		*ctx_ret = ctx;
52750a81498SJens Wiklander 	else
52850a81498SJens Wiklander 		free(ctx);
52950a81498SJens Wiklander 
53050a81498SJens Wiklander 	return res;
53150a81498SJens Wiklander }
53250a81498SJens Wiklander 
53350a81498SJens Wiklander static TEE_Result authenc_decrypt_final(void *ctx, const uint8_t *tag,
53450a81498SJens Wiklander 					const void *crypt, size_t len,
53550a81498SJens Wiklander 					void *plain)
53650a81498SJens Wiklander {
53750a81498SJens Wiklander 	TEE_Result res;
53850a81498SJens Wiklander 	size_t out_size = len;
53950a81498SJens Wiklander 
54050a81498SJens Wiklander 	res = crypto_ops.authenc.dec_final(ctx, TEE_FS_HTREE_AUTH_ENC_ALG,
54150a81498SJens Wiklander 					   crypt, len, plain, &out_size,
54250a81498SJens Wiklander 					   tag, TEE_FS_HTREE_TAG_SIZE);
54350a81498SJens Wiklander 	crypto_ops.authenc.final(ctx, TEE_FS_HTREE_AUTH_ENC_ALG);
54450a81498SJens Wiklander 	free(ctx);
54550a81498SJens Wiklander 
54650a81498SJens Wiklander 	if (res == TEE_SUCCESS && out_size != len)
54750a81498SJens Wiklander 		return TEE_ERROR_GENERIC;
54850a81498SJens Wiklander 	if (res == TEE_ERROR_MAC_INVALID)
54950a81498SJens Wiklander 		return TEE_ERROR_CORRUPT_OBJECT;
55050a81498SJens Wiklander 
55150a81498SJens Wiklander 	return res;
55250a81498SJens Wiklander }
55350a81498SJens Wiklander 
55450a81498SJens Wiklander static TEE_Result authenc_encrypt_final(void *ctx, uint8_t *tag,
55550a81498SJens Wiklander 					const void *plain, size_t len,
55650a81498SJens Wiklander 					void *crypt)
55750a81498SJens Wiklander {
55850a81498SJens Wiklander 	TEE_Result res;
55950a81498SJens Wiklander 	size_t out_size = len;
56050a81498SJens Wiklander 	size_t out_tag_size = TEE_FS_HTREE_TAG_SIZE;
56150a81498SJens Wiklander 
56250a81498SJens Wiklander 	res = crypto_ops.authenc.enc_final(ctx, TEE_FS_HTREE_AUTH_ENC_ALG,
56350a81498SJens Wiklander 					   plain, len, crypt, &out_size,
56450a81498SJens Wiklander 					   tag, &out_tag_size);
56550a81498SJens Wiklander 	crypto_ops.authenc.final(ctx, TEE_FS_HTREE_AUTH_ENC_ALG);
56650a81498SJens Wiklander 	free(ctx);
56750a81498SJens Wiklander 
56850a81498SJens Wiklander 	if (res == TEE_SUCCESS &&
56950a81498SJens Wiklander 	    (out_size != len || out_tag_size != TEE_FS_HTREE_TAG_SIZE))
57050a81498SJens Wiklander 		return TEE_ERROR_GENERIC;
57150a81498SJens Wiklander 
57250a81498SJens Wiklander 	return res;
57350a81498SJens Wiklander }
57450a81498SJens Wiklander 
57550a81498SJens Wiklander static TEE_Result verify_root(struct tee_fs_htree *ht)
57650a81498SJens Wiklander {
57750a81498SJens Wiklander 	TEE_Result res;
57850a81498SJens Wiklander 	void *ctx;
57950a81498SJens Wiklander 
580*0c4e1284SJens Wiklander 	res = tee_fs_fek_crypt(ht->uuid, TEE_MODE_DECRYPT, ht->head.enc_fek,
58150a81498SJens Wiklander 			       sizeof(ht->fek), ht->fek);
58250a81498SJens Wiklander 	if (res != TEE_SUCCESS)
58350a81498SJens Wiklander 		return res;
58450a81498SJens Wiklander 
58550a81498SJens Wiklander 	res = authenc_init(&ctx, TEE_MODE_DECRYPT, ht, NULL, sizeof(ht->imeta));
58650a81498SJens Wiklander 	if (res != TEE_SUCCESS)
58750a81498SJens Wiklander 		return res;
58850a81498SJens Wiklander 
58950a81498SJens Wiklander 	return authenc_decrypt_final(ctx, ht->head.tag, ht->head.imeta,
59050a81498SJens Wiklander 				     sizeof(ht->imeta), &ht->imeta);
59150a81498SJens Wiklander }
59250a81498SJens Wiklander 
59350a81498SJens Wiklander static TEE_Result verify_node(struct traverse_arg *targ,
59450a81498SJens Wiklander 			      struct htree_node *node)
59550a81498SJens Wiklander {
59650a81498SJens Wiklander 	void *ctx = targ->arg;
59750a81498SJens Wiklander 	TEE_Result res;
59850a81498SJens Wiklander 	uint8_t digest[TEE_FS_HTREE_HASH_SIZE];
59950a81498SJens Wiklander 
60050a81498SJens Wiklander 	res = calc_node_hash(node, ctx, digest);
60150a81498SJens Wiklander 	if (res == TEE_SUCCESS &&
60250a81498SJens Wiklander 	    buf_compare_ct(digest, node->node.hash, sizeof(digest)))
60350a81498SJens Wiklander 		return TEE_ERROR_CORRUPT_OBJECT;
60450a81498SJens Wiklander 
60550a81498SJens Wiklander 	return res;
60650a81498SJens Wiklander }
60750a81498SJens Wiklander 
60850a81498SJens Wiklander static TEE_Result verify_tree(struct tee_fs_htree *ht)
60950a81498SJens Wiklander {
61050a81498SJens Wiklander 	TEE_Result res;
61150a81498SJens Wiklander 	size_t size;
61250a81498SJens Wiklander 	void *ctx;
61350a81498SJens Wiklander 
61450a81498SJens Wiklander 	if (!crypto_ops.hash.get_ctx_size || !crypto_ops.hash.init ||
61550a81498SJens Wiklander 	    !crypto_ops.hash.update || !crypto_ops.hash.final)
61650a81498SJens Wiklander 		return TEE_ERROR_NOT_SUPPORTED;
61750a81498SJens Wiklander 
61850a81498SJens Wiklander 	res = crypto_ops.hash.get_ctx_size(TEE_FS_HTREE_HASH_ALG, &size);
61950a81498SJens Wiklander 	if (res != TEE_SUCCESS)
62050a81498SJens Wiklander 		return res;
62150a81498SJens Wiklander 
62250a81498SJens Wiklander 	ctx = malloc(size);
62350a81498SJens Wiklander 	if (!ctx)
62450a81498SJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
62550a81498SJens Wiklander 
62650a81498SJens Wiklander 	res = htree_traverse_post_order(ht, verify_node, ctx);
62750a81498SJens Wiklander 	free(ctx);
62850a81498SJens Wiklander 
62950a81498SJens Wiklander 	return res;
63050a81498SJens Wiklander }
63150a81498SJens Wiklander 
63250a81498SJens Wiklander static TEE_Result init_root_node(struct tee_fs_htree *ht)
63350a81498SJens Wiklander {
63450a81498SJens Wiklander 	TEE_Result res;
63550a81498SJens Wiklander 	size_t size;
63650a81498SJens Wiklander 	void *ctx;
63750a81498SJens Wiklander 
63850a81498SJens Wiklander 	res = crypto_ops.hash.get_ctx_size(TEE_FS_HTREE_HASH_ALG, &size);
63950a81498SJens Wiklander 	if (res != TEE_SUCCESS)
64050a81498SJens Wiklander 		return res;
64150a81498SJens Wiklander 	ctx = malloc(size);
64250a81498SJens Wiklander 	if (!ctx)
64350a81498SJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
64450a81498SJens Wiklander 
64550a81498SJens Wiklander 	ht->root.id = 1;
64650a81498SJens Wiklander 
64750a81498SJens Wiklander 	res = calc_node_hash(&ht->root, ctx, ht->root.node.hash);
64850a81498SJens Wiklander 	free(ctx);
64950a81498SJens Wiklander 
65050a81498SJens Wiklander 	return res;
65150a81498SJens Wiklander }
65250a81498SJens Wiklander 
653*0c4e1284SJens Wiklander TEE_Result tee_fs_htree_open(bool create, uint8_t *hash, const TEE_UUID *uuid,
65450a81498SJens Wiklander 			     const struct tee_fs_htree_storage *stor,
65550a81498SJens Wiklander 			     void *stor_aux, struct tee_fs_htree **ht_ret)
65650a81498SJens Wiklander {
65750a81498SJens Wiklander 	TEE_Result res;
65850a81498SJens Wiklander 	struct tee_fs_htree *ht = calloc(1, sizeof(*ht));
65950a81498SJens Wiklander 
66050a81498SJens Wiklander 	if (!ht)
66150a81498SJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
66250a81498SJens Wiklander 
663*0c4e1284SJens Wiklander 	ht->uuid = uuid;
66450a81498SJens Wiklander 	ht->stor = stor;
66550a81498SJens Wiklander 	ht->stor_aux = stor_aux;
66650a81498SJens Wiklander 
66750a81498SJens Wiklander 	if (create) {
668e2adafecSJens Wiklander 		const struct tee_fs_htree_image dummy_head = { .counter = 0 };
669e2adafecSJens Wiklander 
67050a81498SJens Wiklander 		res = crypto_ops.prng.read(ht->fek, sizeof(ht->fek));
67150a81498SJens Wiklander 		if (res != TEE_SUCCESS)
67250a81498SJens Wiklander 			goto out;
67350a81498SJens Wiklander 
674*0c4e1284SJens Wiklander 		res = tee_fs_fek_crypt(ht->uuid, TEE_MODE_ENCRYPT, ht->fek,
67550a81498SJens Wiklander 				       sizeof(ht->fek), ht->head.enc_fek);
67650a81498SJens Wiklander 		if (res != TEE_SUCCESS)
67750a81498SJens Wiklander 			goto out;
67850a81498SJens Wiklander 
67950a81498SJens Wiklander 		res = init_root_node(ht);
68050a81498SJens Wiklander 		if (res != TEE_SUCCESS)
68150a81498SJens Wiklander 			goto out;
68250a81498SJens Wiklander 
68350a81498SJens Wiklander 		ht->dirty = true;
684f28e5060SJens Wiklander 		res = tee_fs_htree_sync_to_storage(&ht, hash);
685e2adafecSJens Wiklander 		if (res != TEE_SUCCESS)
686e2adafecSJens Wiklander 			goto out;
687e2adafecSJens Wiklander 		res = rpc_write_head(ht, 0, &dummy_head);
68850a81498SJens Wiklander 	} else {
689f28e5060SJens Wiklander 		res = init_head_from_data(ht, hash);
69050a81498SJens Wiklander 		if (res != TEE_SUCCESS)
69150a81498SJens Wiklander 			goto out;
69250a81498SJens Wiklander 
69350a81498SJens Wiklander 		res = verify_root(ht);
69450a81498SJens Wiklander 		if (res != TEE_SUCCESS)
69550a81498SJens Wiklander 			goto out;
69650a81498SJens Wiklander 
69750a81498SJens Wiklander 		res = init_tree_from_data(ht);
69850a81498SJens Wiklander 		if (res != TEE_SUCCESS)
69950a81498SJens Wiklander 			goto out;
70050a81498SJens Wiklander 
70150a81498SJens Wiklander 		res = verify_tree(ht);
70250a81498SJens Wiklander 	}
70350a81498SJens Wiklander out:
70450a81498SJens Wiklander 	if (res == TEE_SUCCESS)
70550a81498SJens Wiklander 		*ht_ret = ht;
70650a81498SJens Wiklander 	else
70750a81498SJens Wiklander 		tee_fs_htree_close(&ht);
70850a81498SJens Wiklander 	return res;
70950a81498SJens Wiklander }
71050a81498SJens Wiklander 
71150a81498SJens Wiklander struct tee_fs_htree_meta *tee_fs_htree_get_meta(struct tee_fs_htree *ht)
71250a81498SJens Wiklander {
71350a81498SJens Wiklander 	return &ht->imeta.meta;
71450a81498SJens Wiklander }
71550a81498SJens Wiklander 
71650a81498SJens Wiklander static TEE_Result free_node(struct traverse_arg *targ __unused,
71750a81498SJens Wiklander 			    struct htree_node *node)
71850a81498SJens Wiklander {
71950a81498SJens Wiklander 	if (node->parent)
72050a81498SJens Wiklander 		free(node);
72150a81498SJens Wiklander 	return TEE_SUCCESS;
72250a81498SJens Wiklander }
72350a81498SJens Wiklander 
72450a81498SJens Wiklander void tee_fs_htree_close(struct tee_fs_htree **ht)
72550a81498SJens Wiklander {
72650a81498SJens Wiklander 	if (!*ht)
72750a81498SJens Wiklander 		return;
72850a81498SJens Wiklander 	htree_traverse_post_order(*ht, free_node, NULL);
72950a81498SJens Wiklander 	free(*ht);
73050a81498SJens Wiklander 	*ht = NULL;
73150a81498SJens Wiklander }
73250a81498SJens Wiklander 
73350a81498SJens Wiklander static TEE_Result htree_sync_node_to_storage(struct traverse_arg *targ,
73450a81498SJens Wiklander 					     struct htree_node *node)
73550a81498SJens Wiklander {
73650a81498SJens Wiklander 	TEE_Result res;
73750a81498SJens Wiklander 	uint8_t vers;
73850a81498SJens Wiklander 
739e2adafecSJens Wiklander 	/*
740e2adafecSJens Wiklander 	 * The node can be dirty while the block isn't updated due to
741e2adafecSJens Wiklander 	 * updated children, but if block is updated the node has to be
742e2adafecSJens Wiklander 	 * dirty.
743e2adafecSJens Wiklander 	 */
744e2adafecSJens Wiklander 	assert(node->dirty >= node->block_updated);
745e2adafecSJens Wiklander 
74650a81498SJens Wiklander 	if (!node->dirty)
74750a81498SJens Wiklander 		return TEE_SUCCESS;
74850a81498SJens Wiklander 
74950a81498SJens Wiklander 	if (node->parent) {
75050a81498SJens Wiklander 		uint32_t f = HTREE_NODE_COMMITTED_CHILD(node->id & 1);
75150a81498SJens Wiklander 
75250a81498SJens Wiklander 		node->parent->dirty = true;
75350a81498SJens Wiklander 		node->parent->node.flags ^= f;
75450a81498SJens Wiklander 		vers = !!(node->parent->node.flags & f);
75550a81498SJens Wiklander 	} else {
75650a81498SJens Wiklander 		/*
75750a81498SJens Wiklander 		 * Counter isn't updated yet, it's increased just before
75850a81498SJens Wiklander 		 * writing the header.
75950a81498SJens Wiklander 		 */
76050a81498SJens Wiklander 		vers = !(targ->ht->head.counter & 1);
76150a81498SJens Wiklander 	}
76250a81498SJens Wiklander 
76350a81498SJens Wiklander 	res = calc_node_hash(node, targ->arg, node->node.hash);
76450a81498SJens Wiklander 	if (res != TEE_SUCCESS)
76550a81498SJens Wiklander 		return res;
76650a81498SJens Wiklander 
76750a81498SJens Wiklander 	node->dirty = false;
768e2adafecSJens Wiklander 	node->block_updated = false;
76950a81498SJens Wiklander 
77050a81498SJens Wiklander 	return rpc_write_node(targ->ht, node->id, vers, &node->node);
77150a81498SJens Wiklander }
77250a81498SJens Wiklander 
77350a81498SJens Wiklander static TEE_Result update_root(struct tee_fs_htree *ht)
77450a81498SJens Wiklander {
77550a81498SJens Wiklander 	TEE_Result res;
77650a81498SJens Wiklander 	void *ctx;
77750a81498SJens Wiklander 
77850a81498SJens Wiklander 	ht->head.counter++;
77950a81498SJens Wiklander 
78050a81498SJens Wiklander 	res = authenc_init(&ctx, TEE_MODE_ENCRYPT, ht, NULL, sizeof(ht->imeta));
78150a81498SJens Wiklander 	if (res != TEE_SUCCESS)
78250a81498SJens Wiklander 		return res;
78350a81498SJens Wiklander 
78450a81498SJens Wiklander 	return authenc_encrypt_final(ctx, ht->head.tag, &ht->imeta,
78550a81498SJens Wiklander 				     sizeof(ht->imeta), &ht->head.imeta);
78650a81498SJens Wiklander }
78750a81498SJens Wiklander 
788f28e5060SJens Wiklander TEE_Result tee_fs_htree_sync_to_storage(struct tee_fs_htree **ht_arg,
789f28e5060SJens Wiklander 					uint8_t *hash)
79050a81498SJens Wiklander {
79150a81498SJens Wiklander 	TEE_Result res;
79250a81498SJens Wiklander 	struct tee_fs_htree *ht = *ht_arg;
79350a81498SJens Wiklander 	size_t size;
79450a81498SJens Wiklander 	void *ctx;
79550a81498SJens Wiklander 
79650a81498SJens Wiklander 	if (!ht)
79750a81498SJens Wiklander 		return TEE_ERROR_CORRUPT_OBJECT;
79850a81498SJens Wiklander 
799a48d0254SJens Wiklander 	if (!ht->dirty)
800a48d0254SJens Wiklander 		return TEE_SUCCESS;
801a48d0254SJens Wiklander 
80250a81498SJens Wiklander 	res = crypto_ops.hash.get_ctx_size(TEE_FS_HTREE_HASH_ALG, &size);
80350a81498SJens Wiklander 	if (res != TEE_SUCCESS)
80450a81498SJens Wiklander 		return res;
80550a81498SJens Wiklander 	ctx = malloc(size);
80650a81498SJens Wiklander 	if (!ctx)
80750a81498SJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
80850a81498SJens Wiklander 
80950a81498SJens Wiklander 	res = htree_traverse_post_order(ht, htree_sync_node_to_storage, ctx);
81050a81498SJens Wiklander 	if (res != TEE_SUCCESS)
81150a81498SJens Wiklander 		goto out;
81250a81498SJens Wiklander 
81350a81498SJens Wiklander 	/* All the nodes are written to storage now. Time to update root. */
81450a81498SJens Wiklander 	res = update_root(ht);
81550a81498SJens Wiklander 	if (res != TEE_SUCCESS)
81650a81498SJens Wiklander 		goto out;
81750a81498SJens Wiklander 
81850a81498SJens Wiklander 	res = rpc_write_head(ht, ht->head.counter & 1, &ht->head);
81950a81498SJens Wiklander 	if (res != TEE_SUCCESS)
82050a81498SJens Wiklander 		goto out;
82150a81498SJens Wiklander 
82250a81498SJens Wiklander 	ht->dirty = false;
823f28e5060SJens Wiklander 	if (hash)
824f28e5060SJens Wiklander 		memcpy(hash, ht->root.node.hash, sizeof(ht->root.node.hash));
82550a81498SJens Wiklander out:
82650a81498SJens Wiklander 	free(ctx);
82750a81498SJens Wiklander 	if (res != TEE_SUCCESS)
82850a81498SJens Wiklander 		tee_fs_htree_close(ht_arg);
82950a81498SJens Wiklander 	return res;
83050a81498SJens Wiklander }
83150a81498SJens Wiklander 
83250a81498SJens Wiklander static TEE_Result get_block_node(struct tee_fs_htree *ht, bool create,
833e2adafecSJens Wiklander 				 size_t block_num, struct htree_node **node)
83450a81498SJens Wiklander {
83550a81498SJens Wiklander 	TEE_Result res;
83650a81498SJens Wiklander 	struct htree_node *nd;
83750a81498SJens Wiklander 
83850a81498SJens Wiklander 	res = get_node(ht, create, BLOCK_NUM_TO_NODE_ID(block_num), &nd);
839e2adafecSJens Wiklander 	if (res == TEE_SUCCESS)
84050a81498SJens Wiklander 		*node = nd;
84150a81498SJens Wiklander 
84250a81498SJens Wiklander 	return res;
84350a81498SJens Wiklander }
84450a81498SJens Wiklander 
84550a81498SJens Wiklander TEE_Result tee_fs_htree_write_block(struct tee_fs_htree **ht_arg,
84650a81498SJens Wiklander 				    size_t block_num, const void *block)
84750a81498SJens Wiklander {
84850a81498SJens Wiklander 	struct tee_fs_htree *ht = *ht_arg;
84950a81498SJens Wiklander 	TEE_Result res;
85050a81498SJens Wiklander 	struct tee_fs_rpc_operation op;
85150a81498SJens Wiklander 	struct htree_node *node = NULL;
85250a81498SJens Wiklander 	uint8_t block_vers;
85350a81498SJens Wiklander 	void *ctx;
85450a81498SJens Wiklander 	void *enc_block;
85550a81498SJens Wiklander 
85650a81498SJens Wiklander 	if (!ht)
85750a81498SJens Wiklander 		return TEE_ERROR_CORRUPT_OBJECT;
85850a81498SJens Wiklander 
859e2adafecSJens Wiklander 	res = get_block_node(ht, true, block_num, &node);
86050a81498SJens Wiklander 	if (res != TEE_SUCCESS)
86150a81498SJens Wiklander 		goto out;
86250a81498SJens Wiklander 
863e2adafecSJens Wiklander 	if (!node->block_updated)
864e2adafecSJens Wiklander 		node->node.flags ^= HTREE_NODE_COMMITTED_BLOCK;
865e2adafecSJens Wiklander 
866e2adafecSJens Wiklander 	block_vers = !!(node->node.flags & HTREE_NODE_COMMITTED_BLOCK);
86750a81498SJens Wiklander 	res = ht->stor->rpc_write_init(ht->stor_aux, &op,
86850a81498SJens Wiklander 				       TEE_FS_HTREE_TYPE_BLOCK, block_num,
86950a81498SJens Wiklander 				       block_vers, &enc_block);
87050a81498SJens Wiklander 	if (res != TEE_SUCCESS)
87150a81498SJens Wiklander 		goto out;
87250a81498SJens Wiklander 
87350a81498SJens Wiklander 	res = authenc_init(&ctx, TEE_MODE_ENCRYPT, ht, &node->node,
87450a81498SJens Wiklander 			   ht->stor->block_size);
87550a81498SJens Wiklander 	if (res != TEE_SUCCESS)
87650a81498SJens Wiklander 		goto out;
87750a81498SJens Wiklander 	res = authenc_encrypt_final(ctx, node->node.tag, block,
87850a81498SJens Wiklander 				    ht->stor->block_size, enc_block);
87950a81498SJens Wiklander 	if (res != TEE_SUCCESS)
88050a81498SJens Wiklander 		goto out;
88150a81498SJens Wiklander 
88264fa6c0aSJens Wiklander 	res = ht->stor->rpc_write_final(&op);
88350a81498SJens Wiklander 	if (res != TEE_SUCCESS)
88450a81498SJens Wiklander 		goto out;
88550a81498SJens Wiklander 
886e2adafecSJens Wiklander 	node->block_updated = true;
88750a81498SJens Wiklander 	node->dirty = true;
88850a81498SJens Wiklander 	ht->dirty = true;
88950a81498SJens Wiklander out:
89050a81498SJens Wiklander 	if (res != TEE_SUCCESS)
89150a81498SJens Wiklander 		tee_fs_htree_close(ht_arg);
89250a81498SJens Wiklander 	return res;
89350a81498SJens Wiklander }
89450a81498SJens Wiklander 
89550a81498SJens Wiklander TEE_Result tee_fs_htree_read_block(struct tee_fs_htree **ht_arg,
89650a81498SJens Wiklander 				   size_t block_num, void *block)
89750a81498SJens Wiklander {
89850a81498SJens Wiklander 	struct tee_fs_htree *ht = *ht_arg;
89950a81498SJens Wiklander 	TEE_Result res;
90050a81498SJens Wiklander 	struct tee_fs_rpc_operation op;
90150a81498SJens Wiklander 	struct htree_node *node;
90250a81498SJens Wiklander 	uint8_t block_vers;
90350a81498SJens Wiklander 	size_t len;
90450a81498SJens Wiklander 	void *ctx;
90550a81498SJens Wiklander 	void *enc_block;
90650a81498SJens Wiklander 
90750a81498SJens Wiklander 	if (!ht)
90850a81498SJens Wiklander 		return TEE_ERROR_CORRUPT_OBJECT;
90950a81498SJens Wiklander 
910e2adafecSJens Wiklander 	res = get_block_node(ht, false, block_num, &node);
91150a81498SJens Wiklander 	if (res != TEE_SUCCESS)
91250a81498SJens Wiklander 		goto out;
91350a81498SJens Wiklander 
914e2adafecSJens Wiklander 	block_vers = !!(node->node.flags & HTREE_NODE_COMMITTED_BLOCK);
91550a81498SJens Wiklander 	res = ht->stor->rpc_read_init(ht->stor_aux, &op,
91650a81498SJens Wiklander 				      TEE_FS_HTREE_TYPE_BLOCK, block_num,
91750a81498SJens Wiklander 				      block_vers, &enc_block);
91850a81498SJens Wiklander 	if (res != TEE_SUCCESS)
91950a81498SJens Wiklander 		goto out;
92050a81498SJens Wiklander 
92164fa6c0aSJens Wiklander 	res = ht->stor->rpc_read_final(&op, &len);
92250a81498SJens Wiklander 	if (res != TEE_SUCCESS)
92350a81498SJens Wiklander 		goto out;
92450a81498SJens Wiklander 	if (len != ht->stor->block_size) {
92550a81498SJens Wiklander 		res = TEE_ERROR_CORRUPT_OBJECT;
92650a81498SJens Wiklander 		goto out;
92750a81498SJens Wiklander 	}
92850a81498SJens Wiklander 
92950a81498SJens Wiklander 	res = authenc_init(&ctx, TEE_MODE_DECRYPT, ht, &node->node,
93050a81498SJens Wiklander 			   ht->stor->block_size);
93150a81498SJens Wiklander 	if (res != TEE_SUCCESS)
93250a81498SJens Wiklander 		goto out;
93350a81498SJens Wiklander 
93450a81498SJens Wiklander 	res = authenc_decrypt_final(ctx, node->node.tag, enc_block,
93550a81498SJens Wiklander 				    ht->stor->block_size, block);
93650a81498SJens Wiklander out:
93750a81498SJens Wiklander 	if (res != TEE_SUCCESS)
93850a81498SJens Wiklander 		tee_fs_htree_close(ht_arg);
93950a81498SJens Wiklander 	return res;
94050a81498SJens Wiklander }
94150a81498SJens Wiklander 
94250a81498SJens Wiklander TEE_Result tee_fs_htree_truncate(struct tee_fs_htree **ht_arg, size_t block_num)
94350a81498SJens Wiklander {
94450a81498SJens Wiklander 	struct tee_fs_htree *ht = *ht_arg;
94550a81498SJens Wiklander 	size_t node_id = BLOCK_NUM_TO_NODE_ID(block_num);
94650a81498SJens Wiklander 	struct htree_node *node;
94750a81498SJens Wiklander 
94850a81498SJens Wiklander 	if (!ht)
94950a81498SJens Wiklander 		return TEE_ERROR_CORRUPT_OBJECT;
95050a81498SJens Wiklander 
95150a81498SJens Wiklander 	while (node_id < ht->imeta.max_node_id) {
95250a81498SJens Wiklander 		node = find_closest_node(ht, ht->imeta.max_node_id);
95350a81498SJens Wiklander 		assert(node && node->id == ht->imeta.max_node_id);
95450a81498SJens Wiklander 		assert(!node->child[0] && !node->child[1]);
95550a81498SJens Wiklander 		assert(node->parent);
95650a81498SJens Wiklander 		assert(node->parent->child[node->id & 1] == node);
95750a81498SJens Wiklander 		node->parent->child[node->id & 1] = NULL;
95850a81498SJens Wiklander 		free(node);
95950a81498SJens Wiklander 		ht->imeta.max_node_id--;
96050a81498SJens Wiklander 		ht->dirty = true;
96150a81498SJens Wiklander 	}
96250a81498SJens Wiklander 
96350a81498SJens Wiklander 	return TEE_SUCCESS;
96450a81498SJens Wiklander }
965