xref: /optee_os/core/kernel/ree_fs_ta.c (revision b2f0c846a4b0bb813018626ac6d8c3a07ebac95e)
1c34c183aSMarouene Boubakri // SPDX-License-Identifier: BSD-2-Clause
2c34c183aSMarouene Boubakri /*
3c34c183aSMarouene Boubakri  * Copyright (c) 2017, 2019, Linaro Limited
4c34c183aSMarouene Boubakri  * Copyright (c) 2020, Arm Limited.
5c34c183aSMarouene Boubakri  */
6c34c183aSMarouene Boubakri 
7c34c183aSMarouene Boubakri /*
8c34c183aSMarouene Boubakri  * Security properties of REE-FS TAs
9c34c183aSMarouene Boubakri  * =================================
10c34c183aSMarouene Boubakri  *
11c34c183aSMarouene Boubakri  * Authentication only
12c34c183aSMarouene Boubakri  * -------------------
13c34c183aSMarouene Boubakri  *
14c34c183aSMarouene Boubakri  * Required security properties:
15c34c183aSMarouene Boubakri  * 1. Authentication and non-repudiation of a TA to Service Provider (SP).
16c34c183aSMarouene Boubakri  * 2. Integrity of a TA.
17c34c183aSMarouene Boubakri  *
18c34c183aSMarouene Boubakri  * To satisfy (1) and (2), SP needs to sign TA and OP-TEE core needs to verify
19c34c183aSMarouene Boubakri  * the signature using SP public key with computed hash of the TA.
20c34c183aSMarouene Boubakri  *
21c34c183aSMarouene Boubakri  * Authentication along with Confidentiality
22c34c183aSMarouene Boubakri  * -----------------------------------------
23c34c183aSMarouene Boubakri  *
24c34c183aSMarouene Boubakri  * Required security properties:
25c34c183aSMarouene Boubakri  * 1. Authentication and non-repudiation of a TA to Service Provider (SP).
26c34c183aSMarouene Boubakri  * 2. Confidentiality of a TA.
27c34c183aSMarouene Boubakri  * 3. Integrity of an encrypted TA blob.
28c34c183aSMarouene Boubakri  *
29c34c183aSMarouene Boubakri  * To satisfy (1), SP needs to sign plain TA and OP-TEE core needs to verify the
30c34c183aSMarouene Boubakri  * signature using SP public key with computed hash of the TA.
31c34c183aSMarouene Boubakri  *
32c34c183aSMarouene Boubakri  * To satisfy (2) and (3), SP needs to do authenticated encryption of TA and
33c34c183aSMarouene Boubakri  * OP-TEE core needs to do authenticated decryption of TA to retrieve its
34c34c183aSMarouene Boubakri  * contents. Here encryption provides the confidentiality of TA and MAC tag
35c34c183aSMarouene Boubakri  * provides the integrity of encrypted TA blob.
36c34c183aSMarouene Boubakri  */
37c34c183aSMarouene Boubakri 
38c34c183aSMarouene Boubakri #include <assert.h>
39c34c183aSMarouene Boubakri #include <crypto/crypto.h>
40c8219657SJens Wiklander #include <fault_mitigation.h>
41c34c183aSMarouene Boubakri #include <initcall.h>
42c34c183aSMarouene Boubakri #include <kernel/thread.h>
43c34c183aSMarouene Boubakri #include <kernel/ts_store.h>
44ef44161fSJens Wiklander #include <kernel/user_access.h>
45c34c183aSMarouene Boubakri #include <mm/core_memprot.h>
46c34c183aSMarouene Boubakri #include <mm/mobj.h>
47de19cacbSJens Wiklander #include <mm/phys_mem.h>
48c8219657SJens Wiklander #include <mm/tee_mm.h>
49c34c183aSMarouene Boubakri #include <optee_rpc_cmd.h>
50c34c183aSMarouene Boubakri #include <signed_hdr.h>
51c34c183aSMarouene Boubakri #include <stdlib.h>
52c34c183aSMarouene Boubakri #include <string.h>
53c34c183aSMarouene Boubakri #include <tee/tee_pobj.h>
54c34c183aSMarouene Boubakri #include <tee/tee_ta_enc_manager.h>
55c34c183aSMarouene Boubakri #include <tee/uuid.h>
56de19cacbSJens Wiklander #include <tee_api_defines_extensions.h>
57de19cacbSJens Wiklander #include <tee_api_types.h>
58c34c183aSMarouene Boubakri #include <utee_defines.h>
59c34c183aSMarouene Boubakri 
60c34c183aSMarouene Boubakri struct ree_fs_ta_handle {
61c34c183aSMarouene Boubakri 	struct shdr *nw_ta; /* Non-secure (shared memory) */
62c34c183aSMarouene Boubakri 	size_t nw_ta_size;
63c34c183aSMarouene Boubakri 	struct mobj *mobj;
64c34c183aSMarouene Boubakri 	size_t offs;
65c34c183aSMarouene Boubakri 	struct shdr *shdr; /* Verified secure copy of @nw_ta's signed header */
66c34c183aSMarouene Boubakri 	void *hash_ctx;
67c34c183aSMarouene Boubakri 	void *enc_ctx;
68c34c183aSMarouene Boubakri 	struct shdr_bootstrap_ta *bs_hdr;
69c34c183aSMarouene Boubakri 	struct shdr_encrypted_ta *ehdr;
70c34c183aSMarouene Boubakri };
71c34c183aSMarouene Boubakri 
72ce20b8ecSJens Wiklander struct ver_db_entry {
73ce20b8ecSJens Wiklander 	uint8_t uuid[sizeof(TEE_UUID)];
74ce20b8ecSJens Wiklander 	uint32_t version;
75ce20b8ecSJens Wiklander };
76ce20b8ecSJens Wiklander 
77ce20b8ecSJens Wiklander struct ver_db_hdr {
78c34c183aSMarouene Boubakri 	uint32_t db_version;
79c34c183aSMarouene Boubakri 	uint32_t nb_entries;
80c34c183aSMarouene Boubakri };
81c34c183aSMarouene Boubakri 
82ce20b8ecSJens Wiklander static const char ta_ver_db[] = "ta_ver.db";
83c34d0d91SJens Wiklander static const char subkey_ver_db[] = "subkey_ver.db";
84ce20b8ecSJens Wiklander static struct mutex ver_db_mutex = MUTEX_INITIALIZER;
85c34c183aSMarouene Boubakri 
check_update_version(const char * db_name,const uint8_t uuid[sizeof (TEE_UUID)],uint32_t version)86c34d0d91SJens Wiklander static TEE_Result check_update_version(const char *db_name,
87c34d0d91SJens Wiklander 				       const uint8_t uuid[sizeof(TEE_UUID)],
88c34d0d91SJens Wiklander 				       uint32_t version)
89c34d0d91SJens Wiklander {
90c34d0d91SJens Wiklander 	struct ver_db_entry db_entry = { };
91c34d0d91SJens Wiklander 	const struct tee_file_operations *ops = NULL;
92c34d0d91SJens Wiklander 	struct tee_file_handle *fh = NULL;
93c34d0d91SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
94c34d0d91SJens Wiklander 	bool entry_found = false;
95c34d0d91SJens Wiklander 	size_t len = 0;
96c34d0d91SJens Wiklander 	unsigned int i = 0;
97c34d0d91SJens Wiklander 	struct ver_db_hdr db_hdr = { };
98c34d0d91SJens Wiklander 	struct tee_pobj pobj = {
99c34d0d91SJens Wiklander 		.obj_id = (void *)db_name,
100c34d0d91SJens Wiklander 		.obj_id_len = strlen(db_name) + 1,
101c34d0d91SJens Wiklander 	};
102c34d0d91SJens Wiklander 
103c34d0d91SJens Wiklander 	ops = tee_svc_storage_file_ops(TEE_STORAGE_PRIVATE);
104c34d0d91SJens Wiklander 	if (!ops)
105c34d0d91SJens Wiklander 		return TEE_SUCCESS; /* Compiled with no secure storage */
106c34d0d91SJens Wiklander 
107c34d0d91SJens Wiklander 	mutex_lock(&ver_db_mutex);
108c34d0d91SJens Wiklander 
109c34d0d91SJens Wiklander 	res = ops->open(&pobj, NULL, &fh);
110c34d0d91SJens Wiklander 	if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND)
111c34d0d91SJens Wiklander 		goto out;
112c34d0d91SJens Wiklander 
113c34d0d91SJens Wiklander 	if (res == TEE_ERROR_ITEM_NOT_FOUND) {
114*b2f0c846SOx Yeh 		/* Database does not exist: create and initialize header */
11541a624daSGavin Liu 		res = ops->create(&pobj, false, NULL, 0, NULL, 0, &db_hdr, NULL,
11641a624daSGavin Liu 				   sizeof(db_hdr), &fh);
117c34d0d91SJens Wiklander 		if (res != TEE_SUCCESS)
118c34d0d91SJens Wiklander 			goto out;
119c34d0d91SJens Wiklander 	} else {
120c34d0d91SJens Wiklander 		len = sizeof(db_hdr);
121c34d0d91SJens Wiklander 
122b2284b11SJens Wiklander 		res = ops->read(fh, 0, &db_hdr, NULL, &len);
123*b2f0c846SOx Yeh 		if (res != TEE_SUCCESS)
124*b2f0c846SOx Yeh 			goto out;
125*b2f0c846SOx Yeh 		/*
126*b2f0c846SOx Yeh 		 * If a power loss occurred during database creation, the
127*b2f0c846SOx Yeh 		 * header may not have been written. Write the header to
128*b2f0c846SOx Yeh 		 * complete initialization.
129*b2f0c846SOx Yeh 		 */
130*b2f0c846SOx Yeh 		if (len == 0) {
131*b2f0c846SOx Yeh 			res = ops->write(fh, 0, &db_hdr, NULL, sizeof(db_hdr));
132*b2f0c846SOx Yeh 			if (res != TEE_SUCCESS)
133c34d0d91SJens Wiklander 				goto out;
134c34d0d91SJens Wiklander 		} else if (len != sizeof(db_hdr)) {
135c34d0d91SJens Wiklander 			res = TEE_ERROR_BAD_STATE;
136c34d0d91SJens Wiklander 			goto out;
137c34d0d91SJens Wiklander 		}
138c34d0d91SJens Wiklander 	}
139c34d0d91SJens Wiklander 
140c34d0d91SJens Wiklander 	for (i = 0; i < db_hdr.nb_entries; i++) {
141c34d0d91SJens Wiklander 		len = sizeof(db_entry);
142c34d0d91SJens Wiklander 
143c34d0d91SJens Wiklander 		res = ops->read(fh, sizeof(db_hdr) + (i * len), &db_entry,
144b2284b11SJens Wiklander 				NULL, &len);
145c34d0d91SJens Wiklander 		if (res != TEE_SUCCESS) {
146c34d0d91SJens Wiklander 			goto out;
147c34d0d91SJens Wiklander 		} else if (len != sizeof(db_entry)) {
148c34d0d91SJens Wiklander 			res = TEE_ERROR_BAD_STATE;
149c34d0d91SJens Wiklander 			goto out;
150c34d0d91SJens Wiklander 		}
151c34d0d91SJens Wiklander 
152c34d0d91SJens Wiklander 		if (!memcmp(uuid, db_entry.uuid, sizeof(TEE_UUID))) {
153c34d0d91SJens Wiklander 			entry_found = true;
154c34d0d91SJens Wiklander 			break;
155c34d0d91SJens Wiklander 		}
156c34d0d91SJens Wiklander 	}
157c34d0d91SJens Wiklander 
158c34d0d91SJens Wiklander 	if (entry_found) {
159c34d0d91SJens Wiklander 		if (db_entry.version > version) {
160c34d0d91SJens Wiklander 			res = TEE_ERROR_ACCESS_CONFLICT;
161c34d0d91SJens Wiklander 			goto out;
162c34d0d91SJens Wiklander 		} else if (db_entry.version < version) {
163c34d0d91SJens Wiklander 			memcpy(db_entry.uuid, uuid, sizeof(TEE_UUID));
164c34d0d91SJens Wiklander 			db_entry.version = version;
165c34d0d91SJens Wiklander 			len = sizeof(db_entry);
166c34d0d91SJens Wiklander 			res = ops->write(fh, sizeof(db_hdr) + (i * len),
167b2284b11SJens Wiklander 					 &db_entry, NULL, len);
168c34d0d91SJens Wiklander 			if (res != TEE_SUCCESS)
169c34d0d91SJens Wiklander 				goto out;
170c34d0d91SJens Wiklander 		}
171c34d0d91SJens Wiklander 	} else {
172c34d0d91SJens Wiklander 		memcpy(db_entry.uuid, uuid, sizeof(TEE_UUID));
173c34d0d91SJens Wiklander 		db_entry.version = version;
174c34d0d91SJens Wiklander 		len = sizeof(db_entry);
175c34d0d91SJens Wiklander 		res = ops->write(fh, sizeof(db_hdr) + (db_hdr.nb_entries * len),
176b2284b11SJens Wiklander 				 &db_entry, NULL, len);
177c34d0d91SJens Wiklander 		if (res != TEE_SUCCESS)
178c34d0d91SJens Wiklander 			goto out;
179c34d0d91SJens Wiklander 
180c34d0d91SJens Wiklander 		db_hdr.nb_entries++;
181b2284b11SJens Wiklander 		res = ops->write(fh, 0, &db_hdr, NULL, sizeof(db_hdr));
182c34d0d91SJens Wiklander 		if (res != TEE_SUCCESS)
183c34d0d91SJens Wiklander 			goto out;
184c34d0d91SJens Wiklander 	}
185c34d0d91SJens Wiklander 
186c34d0d91SJens Wiklander out:
187c34d0d91SJens Wiklander 	ops->close(&fh);
188c34d0d91SJens Wiklander 	mutex_unlock(&ver_db_mutex);
189c34d0d91SJens Wiklander 	return res;
190c34d0d91SJens Wiklander }
191c34d0d91SJens Wiklander 
192c34c183aSMarouene Boubakri /*
193c34c183aSMarouene Boubakri  * Load a TA via RPC with UUID defined by input param @uuid. The virtual
194c34c183aSMarouene Boubakri  * address of the raw TA binary is received in out parameter @ta.
195c34c183aSMarouene Boubakri  */
rpc_load(const TEE_UUID * uuid,struct shdr ** ta,size_t * ta_size,struct mobj ** mobj)196c34c183aSMarouene Boubakri static TEE_Result rpc_load(const TEE_UUID *uuid, struct shdr **ta,
197c34c183aSMarouene Boubakri 			   size_t *ta_size, struct mobj **mobj)
198c34c183aSMarouene Boubakri {
199c34c183aSMarouene Boubakri 	TEE_Result res;
200c34c183aSMarouene Boubakri 	struct thread_param params[2];
201c34c183aSMarouene Boubakri 
202c34c183aSMarouene Boubakri 	if (!uuid || !ta || !mobj || !ta_size)
203c34c183aSMarouene Boubakri 		return TEE_ERROR_BAD_PARAMETERS;
204c34c183aSMarouene Boubakri 
205c34c183aSMarouene Boubakri 	memset(params, 0, sizeof(params));
206c34c183aSMarouene Boubakri 	params[0].attr = THREAD_PARAM_ATTR_VALUE_IN;
207c34c183aSMarouene Boubakri 	tee_uuid_to_octets((void *)&params[0].u.value, uuid);
208c34c183aSMarouene Boubakri 	params[1].attr = THREAD_PARAM_ATTR_MEMREF_OUT;
209c34c183aSMarouene Boubakri 
210c34c183aSMarouene Boubakri 	res = thread_rpc_cmd(OPTEE_RPC_CMD_LOAD_TA, 2, params);
211c34c183aSMarouene Boubakri 	if (res != TEE_SUCCESS)
212c34c183aSMarouene Boubakri 		return res;
213c34c183aSMarouene Boubakri 
214c34c183aSMarouene Boubakri 	*mobj = thread_rpc_alloc_payload(params[1].u.memref.size);
215c34c183aSMarouene Boubakri 	if (!*mobj)
216c34c183aSMarouene Boubakri 		return TEE_ERROR_OUT_OF_MEMORY;
217c34c183aSMarouene Boubakri 
2189c4aaf67SJens Wiklander 	*ta = mobj_get_va(*mobj, 0, params[1].u.memref.size);
2199c4aaf67SJens Wiklander 	if (!*ta) {
220c34c183aSMarouene Boubakri 		res = TEE_ERROR_SHORT_BUFFER;
221c34c183aSMarouene Boubakri 		goto exit;
222c34c183aSMarouene Boubakri 	}
223c34c183aSMarouene Boubakri 	/* We don't expect NULL as thread_rpc_alloc_payload() was successful */
224c34c183aSMarouene Boubakri 	assert(*ta);
225c34c183aSMarouene Boubakri 	*ta_size = params[1].u.memref.size;
226c34c183aSMarouene Boubakri 
227c34c183aSMarouene Boubakri 	params[0].attr = THREAD_PARAM_ATTR_VALUE_IN;
228c34c183aSMarouene Boubakri 	tee_uuid_to_octets((void *)&params[0].u.value, uuid);
229c34c183aSMarouene Boubakri 	params[1].attr = THREAD_PARAM_ATTR_MEMREF_OUT;
230c34c183aSMarouene Boubakri 	params[1].u.memref.offs = 0;
231c34c183aSMarouene Boubakri 	params[1].u.memref.mobj = *mobj;
232c34c183aSMarouene Boubakri 
233c34c183aSMarouene Boubakri 	res = thread_rpc_cmd(OPTEE_RPC_CMD_LOAD_TA, 2, params);
234c34c183aSMarouene Boubakri exit:
235c34c183aSMarouene Boubakri 	if (res != TEE_SUCCESS)
236c34c183aSMarouene Boubakri 		thread_rpc_free_payload(*mobj);
237c34c183aSMarouene Boubakri 
238c34c183aSMarouene Boubakri 	return res;
239c34c183aSMarouene Boubakri }
240c34c183aSMarouene Boubakri 
ree_fs_ta_open(const TEE_UUID * uuid,struct ts_store_handle ** h)241c34c183aSMarouene Boubakri static TEE_Result ree_fs_ta_open(const TEE_UUID *uuid,
242c34c183aSMarouene Boubakri 				 struct ts_store_handle **h)
243c34c183aSMarouene Boubakri {
244c34d0d91SJens Wiklander 	uint8_t next_uuid[sizeof(TEE_UUID)] = { };
245c34c183aSMarouene Boubakri 	struct ree_fs_ta_handle *handle;
246c34d0d91SJens Wiklander 	uint8_t *next_uuid_ptr = NULL;
247c34c183aSMarouene Boubakri 	struct shdr *shdr = NULL;
248c34c183aSMarouene Boubakri 	struct mobj *mobj = NULL;
249c34c183aSMarouene Boubakri 	void *hash_ctx = NULL;
250c34c183aSMarouene Boubakri 	struct shdr *ta = NULL;
251c34c183aSMarouene Boubakri 	size_t ta_size = 0;
25249a87500SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
25349a87500SJens Wiklander 	size_t offs = 0;
254c34c183aSMarouene Boubakri 	struct shdr_bootstrap_ta *bs_hdr = NULL;
255c34c183aSMarouene Boubakri 	struct shdr_encrypted_ta *ehdr = NULL;
25649a87500SJens Wiklander 	size_t shdr_sz = 0;
257c34d0d91SJens Wiklander 	uint32_t max_depth = UINT32_MAX;
2582d7720f1SJens Wiklander 	struct ftmn ftmn = { };
2592d7720f1SJens Wiklander 	unsigned int incr0_count = 0;
260c34c183aSMarouene Boubakri 
261c34c183aSMarouene Boubakri 	handle = calloc(1, sizeof(*handle));
262c34c183aSMarouene Boubakri 	if (!handle)
263c34c183aSMarouene Boubakri 		return TEE_ERROR_OUT_OF_MEMORY;
264c34c183aSMarouene Boubakri 
265c34c183aSMarouene Boubakri 	/* Request TA from tee-supplicant */
266c34c183aSMarouene Boubakri 	res = rpc_load(uuid, &ta, &ta_size, &mobj);
267c34c183aSMarouene Boubakri 	if (res != TEE_SUCCESS)
268c34c183aSMarouene Boubakri 		goto error;
269c34c183aSMarouene Boubakri 
270c34c183aSMarouene Boubakri 	/* Make secure copy of signed header */
271ec1aa4faSJens Wiklander 	shdr = shdr_alloc_and_copy(0, ta, ta_size);
272c34c183aSMarouene Boubakri 	if (!shdr) {
273c34c183aSMarouene Boubakri 		res = TEE_ERROR_SECURITY;
274c34c183aSMarouene Boubakri 		goto error_free_payload;
275c34c183aSMarouene Boubakri 	}
276c34c183aSMarouene Boubakri 
277c34c183aSMarouene Boubakri 	/* Validate header signature */
2782d7720f1SJens Wiklander 	FTMN_CALL_FUNC(res, &ftmn, FTMN_INCR0, shdr_verify_signature, shdr);
2792d7720f1SJens Wiklander 	incr0_count++;
280c34c183aSMarouene Boubakri 	if (res != TEE_SUCCESS)
281c34c183aSMarouene Boubakri 		goto error_free_payload;
282c34d0d91SJens Wiklander 
283c34d0d91SJens Wiklander 	shdr_sz = SHDR_GET_SIZE(shdr);
284c34d0d91SJens Wiklander 	if (!shdr_sz) {
285c34d0d91SJens Wiklander 		res = TEE_ERROR_SECURITY;
286c34d0d91SJens Wiklander 		goto error_free_payload;
287c34d0d91SJens Wiklander 	}
288c34d0d91SJens Wiklander 	offs = shdr_sz;
289c34d0d91SJens Wiklander 
290c34d0d91SJens Wiklander 	while (shdr->img_type == SHDR_SUBKEY) {
291c34d0d91SJens Wiklander 		struct shdr_pub_key pub_key = { };
292c34d0d91SJens Wiklander 
293c34d0d91SJens Wiklander 		if (offs > ta_size) {
294c34d0d91SJens Wiklander 			res = TEE_ERROR_SECURITY;
295c34d0d91SJens Wiklander 			goto error_free_payload;
296c34d0d91SJens Wiklander 		}
297c34d0d91SJens Wiklander 
298c34d0d91SJens Wiklander 		res = shdr_load_pub_key(shdr, offs, (const void *)ta,
299c34d0d91SJens Wiklander 					ta_size, next_uuid_ptr, max_depth,
300c34d0d91SJens Wiklander 					&pub_key);
301c34d0d91SJens Wiklander 		if (res)
302c34d0d91SJens Wiklander 			goto error_free_payload;
303c34d0d91SJens Wiklander 
304c34d0d91SJens Wiklander 		if (ADD_OVERFLOW(offs, shdr->img_size, &offs) ||
305c34d0d91SJens Wiklander 		    ADD_OVERFLOW(offs, pub_key.name_size, &offs) ||
306c34d0d91SJens Wiklander 		    offs > ta_size) {
307c34d0d91SJens Wiklander 			res = TEE_ERROR_SECURITY;
308c34d0d91SJens Wiklander 			goto error_free_payload;
309c34d0d91SJens Wiklander 		}
310c34d0d91SJens Wiklander 		max_depth = pub_key.max_depth;
311c34d0d91SJens Wiklander 		memcpy(next_uuid, pub_key.next_uuid, sizeof(TEE_UUID));
312c34d0d91SJens Wiklander 		next_uuid_ptr = next_uuid;
313c34d0d91SJens Wiklander 
314c34d0d91SJens Wiklander 		res = check_update_version(subkey_ver_db, pub_key.uuid,
315c34d0d91SJens Wiklander 					   pub_key.version);
316c34d0d91SJens Wiklander 		if (res) {
317c34d0d91SJens Wiklander 			res = TEE_ERROR_SECURITY;
318c34d0d91SJens Wiklander 			shdr_free_pub_key(&pub_key);
319c34d0d91SJens Wiklander 			goto error_free_payload;
320c34d0d91SJens Wiklander 		}
321c34d0d91SJens Wiklander 
322c34d0d91SJens Wiklander 		shdr_free(shdr);
323c34d0d91SJens Wiklander 		shdr = shdr_alloc_and_copy(offs, ta, ta_size);
324c34d0d91SJens Wiklander 		res = TEE_ERROR_SECURITY;
3252d7720f1SJens Wiklander 		if (shdr) {
3262d7720f1SJens Wiklander 			FTMN_CALL_FUNC(res, &ftmn, FTMN_INCR0,
3272d7720f1SJens Wiklander 				       shdr_verify_signature2, &pub_key, shdr);
3282d7720f1SJens Wiklander 			incr0_count++;
3292d7720f1SJens Wiklander 		}
330c34d0d91SJens Wiklander 		shdr_free_pub_key(&pub_key);
331c34d0d91SJens Wiklander 		if (res)
332c34d0d91SJens Wiklander 			goto error_free_payload;
333c34d0d91SJens Wiklander 
334c34d0d91SJens Wiklander 		shdr_sz = SHDR_GET_SIZE(shdr);
335c34d0d91SJens Wiklander 		if (!shdr_sz) {
336c34d0d91SJens Wiklander 			res = TEE_ERROR_SECURITY;
337c34d0d91SJens Wiklander 			goto error_free_payload;
338c34d0d91SJens Wiklander 		}
339c34d0d91SJens Wiklander 		offs += shdr_sz;
340c34d0d91SJens Wiklander 		if (offs > ta_size) {
341c34d0d91SJens Wiklander 			res = TEE_ERROR_SECURITY;
342c34d0d91SJens Wiklander 			goto error_free_payload;
343c34d0d91SJens Wiklander 		}
344c34d0d91SJens Wiklander 	}
345c34d0d91SJens Wiklander 
346c34c183aSMarouene Boubakri 	if (shdr->img_type != SHDR_TA && shdr->img_type != SHDR_BOOTSTRAP_TA &&
347c34c183aSMarouene Boubakri 	    shdr->img_type != SHDR_ENCRYPTED_TA) {
348c34c183aSMarouene Boubakri 		res = TEE_ERROR_SECURITY;
349c34c183aSMarouene Boubakri 		goto error_free_payload;
350c34c183aSMarouene Boubakri 	}
351c34c183aSMarouene Boubakri 
352c34c183aSMarouene Boubakri 	/*
353c34d0d91SJens Wiklander 	 * If we're verifying this TA using a subkey, make sure that
354c34d0d91SJens Wiklander 	 * the UUID of the TA belongs to the namespace defined by the subkey.
355c34d0d91SJens Wiklander 	 * The namespace is defined as in RFC4122, that is, valid UUID
356c34d0d91SJens Wiklander 	 * is calculated as a V5 UUID SHA-512(subkey UUID, "name string").
357c34d0d91SJens Wiklander 	 */
358c34d0d91SJens Wiklander 	if (next_uuid_ptr) {
359c34d0d91SJens Wiklander 		TEE_UUID check_uuid = { };
360c34d0d91SJens Wiklander 
361c34d0d91SJens Wiklander 		tee_uuid_from_octets(&check_uuid, next_uuid_ptr);
362c34d0d91SJens Wiklander 		if (memcmp(&check_uuid, uuid, sizeof(*uuid))) {
363c34d0d91SJens Wiklander 			res = TEE_ERROR_SECURITY;
364c34d0d91SJens Wiklander 			goto error_free_payload;
365c34d0d91SJens Wiklander 		}
366c34d0d91SJens Wiklander 	}
367c34d0d91SJens Wiklander 
368c34d0d91SJens Wiklander 	/*
369c34c183aSMarouene Boubakri 	 * Initialize a hash context and run the algorithm over the signed
370c34c183aSMarouene Boubakri 	 * header (less the final file hash and its signature of course)
371c34c183aSMarouene Boubakri 	 */
372c34c183aSMarouene Boubakri 	res = crypto_hash_alloc_ctx(&hash_ctx,
373c34c183aSMarouene Boubakri 				    TEE_DIGEST_HASH_TO_ALGO(shdr->algo));
374c34c183aSMarouene Boubakri 	if (res != TEE_SUCCESS)
375c34c183aSMarouene Boubakri 		goto error_free_payload;
376c34c183aSMarouene Boubakri 	res = crypto_hash_init(hash_ctx);
377c34c183aSMarouene Boubakri 	if (res != TEE_SUCCESS)
378c34c183aSMarouene Boubakri 		goto error_free_hash;
379c34c183aSMarouene Boubakri 	res = crypto_hash_update(hash_ctx, (uint8_t *)shdr, sizeof(*shdr));
380c34c183aSMarouene Boubakri 	if (res != TEE_SUCCESS)
381c34c183aSMarouene Boubakri 		goto error_free_hash;
382c34c183aSMarouene Boubakri 
383c34c183aSMarouene Boubakri 	if (shdr->img_type == SHDR_BOOTSTRAP_TA ||
384c34c183aSMarouene Boubakri 	    shdr->img_type == SHDR_ENCRYPTED_TA) {
38549a87500SJens Wiklander 		TEE_UUID bs_uuid = { };
38649a87500SJens Wiklander 		size_t sz = shdr_sz;
387c34c183aSMarouene Boubakri 
38849a87500SJens Wiklander 		if (ADD_OVERFLOW(sz, sizeof(*bs_hdr), &sz) || ta_size < sz) {
389c34c183aSMarouene Boubakri 			res = TEE_ERROR_SECURITY;
390c34c183aSMarouene Boubakri 			goto error_free_hash;
391c34c183aSMarouene Boubakri 		}
392c34c183aSMarouene Boubakri 
393c34c183aSMarouene Boubakri 		bs_hdr = malloc(sizeof(*bs_hdr));
394c34c183aSMarouene Boubakri 		if (!bs_hdr) {
395c34c183aSMarouene Boubakri 			res = TEE_ERROR_OUT_OF_MEMORY;
396c34c183aSMarouene Boubakri 			goto error_free_hash;
397c34c183aSMarouene Boubakri 		}
398c34c183aSMarouene Boubakri 
399c34c183aSMarouene Boubakri 		memcpy(bs_hdr, (uint8_t *)ta + offs, sizeof(*bs_hdr));
400c34c183aSMarouene Boubakri 
401c34c183aSMarouene Boubakri 		/*
402c34c183aSMarouene Boubakri 		 * There's a check later that the UUID embedded inside the
403c34c183aSMarouene Boubakri 		 * ELF is matching, but since we now have easy access to
404c34c183aSMarouene Boubakri 		 * the expected uuid of the TA we check it a bit earlier
405c34c183aSMarouene Boubakri 		 * here.
406c34c183aSMarouene Boubakri 		 */
407c34c183aSMarouene Boubakri 		tee_uuid_from_octets(&bs_uuid, bs_hdr->uuid);
408c34c183aSMarouene Boubakri 		if (memcmp(&bs_uuid, uuid, sizeof(TEE_UUID))) {
409c34c183aSMarouene Boubakri 			res = TEE_ERROR_SECURITY;
410c34c183aSMarouene Boubakri 			goto error_free_hash;
411c34c183aSMarouene Boubakri 		}
412c34c183aSMarouene Boubakri 
413c34c183aSMarouene Boubakri 		res = crypto_hash_update(hash_ctx, (uint8_t *)bs_hdr,
414c34c183aSMarouene Boubakri 					 sizeof(*bs_hdr));
415c34c183aSMarouene Boubakri 		if (res != TEE_SUCCESS)
416c34c183aSMarouene Boubakri 			goto error_free_hash;
417c34c183aSMarouene Boubakri 		offs += sizeof(*bs_hdr);
418c34c183aSMarouene Boubakri 		handle->bs_hdr = bs_hdr;
419c34c183aSMarouene Boubakri 	}
420c34c183aSMarouene Boubakri 
421c34c183aSMarouene Boubakri 	if (shdr->img_type == SHDR_ENCRYPTED_TA) {
42249a87500SJens Wiklander 		struct shdr_encrypted_ta img_ehdr = { };
42349a87500SJens Wiklander 		size_t sz = shdr_sz;
42449a87500SJens Wiklander 		size_t ehdr_sz = 0;
425c34c183aSMarouene Boubakri 
42649a87500SJens Wiklander 		if (ADD_OVERFLOW(sz, sizeof(struct shdr_bootstrap_ta), &sz) ||
42749a87500SJens Wiklander 		    ADD_OVERFLOW(sz, sizeof(img_ehdr), &sz) ||
42849a87500SJens Wiklander 		    ta_size < sz) {
429c34c183aSMarouene Boubakri 			res = TEE_ERROR_SECURITY;
430c34c183aSMarouene Boubakri 			goto error_free_hash;
431c34c183aSMarouene Boubakri 		}
432c34c183aSMarouene Boubakri 
433c34c183aSMarouene Boubakri 		memcpy(&img_ehdr, ((uint8_t *)ta + offs), sizeof(img_ehdr));
43449a87500SJens Wiklander 		ehdr_sz = SHDR_ENC_GET_SIZE(&img_ehdr);
43549a87500SJens Wiklander 		sz -= sizeof(img_ehdr);
43649a87500SJens Wiklander 		if (!ehdr_sz || ADD_OVERFLOW(sz, ehdr_sz, &sz) ||
43749a87500SJens Wiklander 		    ta_size < sz) {
43849a87500SJens Wiklander 			res = TEE_ERROR_SECURITY;
43949a87500SJens Wiklander 			goto error_free_hash;
44049a87500SJens Wiklander 		}
441c34c183aSMarouene Boubakri 
44219b1ce2bSJens Wiklander 		/*
44319b1ce2bSJens Wiklander 		 * This is checked further down too, but we must sanity
44419b1ce2bSJens Wiklander 		 * check shdr->img_size before it's used below.
44519b1ce2bSJens Wiklander 		 */
4469eabc2b4SJens Wiklander 		if (ta_size != offs + ehdr_sz + shdr->img_size) {
44719b1ce2bSJens Wiklander 			res = TEE_ERROR_SECURITY;
44819b1ce2bSJens Wiklander 			goto error_free_hash;
44919b1ce2bSJens Wiklander 		}
45049a87500SJens Wiklander 
45149a87500SJens Wiklander 		ehdr = malloc(ehdr_sz);
452c34c183aSMarouene Boubakri 		if (!ehdr) {
453c34c183aSMarouene Boubakri 			res = TEE_ERROR_OUT_OF_MEMORY;
454c34c183aSMarouene Boubakri 			goto error_free_hash;
455c34c183aSMarouene Boubakri 		}
456c34c183aSMarouene Boubakri 
457827c9002SJens Wiklander 		*ehdr = img_ehdr;
458827c9002SJens Wiklander 		memcpy((uint8_t *)ehdr + sizeof(img_ehdr),
459827c9002SJens Wiklander 		       (uint8_t *)ta + offs + sizeof(img_ehdr),
460827c9002SJens Wiklander 		       ehdr_sz - sizeof(img_ehdr));
461c34c183aSMarouene Boubakri 
46249a87500SJens Wiklander 		res = crypto_hash_update(hash_ctx, (uint8_t *)ehdr, ehdr_sz);
463c34c183aSMarouene Boubakri 		if (res != TEE_SUCCESS)
464c34c183aSMarouene Boubakri 			goto error_free_hash;
465c34c183aSMarouene Boubakri 
466c34c183aSMarouene Boubakri 		res = tee_ta_decrypt_init(&handle->enc_ctx, ehdr,
467c34c183aSMarouene Boubakri 					  shdr->img_size);
468c34c183aSMarouene Boubakri 		if (res != TEE_SUCCESS)
469c34c183aSMarouene Boubakri 			goto error_free_hash;
470c34c183aSMarouene Boubakri 
47149a87500SJens Wiklander 		offs += ehdr_sz;
472c34c183aSMarouene Boubakri 		handle->ehdr = ehdr;
473c34c183aSMarouene Boubakri 	}
474c34c183aSMarouene Boubakri 
475c34c183aSMarouene Boubakri 	if (ta_size != offs + shdr->img_size) {
476c34c183aSMarouene Boubakri 		res = TEE_ERROR_SECURITY;
477c34c183aSMarouene Boubakri 		goto error_free_hash;
478c34c183aSMarouene Boubakri 	}
479c34c183aSMarouene Boubakri 
480c34c183aSMarouene Boubakri 	handle->nw_ta = ta;
481c34c183aSMarouene Boubakri 	handle->nw_ta_size = ta_size;
482c34c183aSMarouene Boubakri 	handle->offs = offs;
483c34c183aSMarouene Boubakri 	handle->hash_ctx = hash_ctx;
484c34c183aSMarouene Boubakri 	handle->shdr = shdr;
485c34c183aSMarouene Boubakri 	handle->mobj = mobj;
486c34c183aSMarouene Boubakri 	*h = (struct ts_store_handle *)handle;
4872d7720f1SJens Wiklander 	FTMN_CALLEE_DONE_CHECK(&ftmn, FTMN_INCR1,
4882d7720f1SJens Wiklander 			       FTMN_STEP_COUNT(incr0_count), TEE_SUCCESS);
489c34c183aSMarouene Boubakri 	return TEE_SUCCESS;
490c34c183aSMarouene Boubakri 
491c34c183aSMarouene Boubakri error_free_hash:
492c34c183aSMarouene Boubakri 	crypto_hash_free_ctx(hash_ctx);
493c34c183aSMarouene Boubakri error_free_payload:
494c34c183aSMarouene Boubakri 	thread_rpc_free_payload(mobj);
495c34c183aSMarouene Boubakri error:
496c34c183aSMarouene Boubakri 	free(ehdr);
497c34c183aSMarouene Boubakri 	free(bs_hdr);
498c34c183aSMarouene Boubakri 	shdr_free(shdr);
499c34c183aSMarouene Boubakri 	free(handle);
5002d7720f1SJens Wiklander 	FTMN_SET_CHECK_RES_NOT_ZERO(&ftmn, FTMN_INCR1, res);
5012d7720f1SJens Wiklander 	FTMN_CALLEE_DONE_CHECK(&ftmn, FTMN_INCR1,
5022d7720f1SJens Wiklander 			       FTMN_STEP_COUNT(incr0_count, 1), res);
503c34c183aSMarouene Boubakri 	return res;
504c34c183aSMarouene Boubakri }
505c34c183aSMarouene Boubakri 
ree_fs_ta_get_size(const struct ts_store_handle * h,size_t * size)506c34c183aSMarouene Boubakri static TEE_Result ree_fs_ta_get_size(const struct ts_store_handle *h,
507c34c183aSMarouene Boubakri 				     size_t *size)
508c34c183aSMarouene Boubakri {
509c34c183aSMarouene Boubakri 	struct ree_fs_ta_handle *handle = (struct ree_fs_ta_handle *)h;
510c34c183aSMarouene Boubakri 
511c34c183aSMarouene Boubakri 	*size = handle->shdr->img_size;
512c34c183aSMarouene Boubakri 	return TEE_SUCCESS;
513c34c183aSMarouene Boubakri }
514c34c183aSMarouene Boubakri 
ree_fs_ta_get_tag(const struct ts_store_handle * h,uint8_t * tag,unsigned int * tag_len)515c34c183aSMarouene Boubakri static TEE_Result ree_fs_ta_get_tag(const struct ts_store_handle *h,
516c34c183aSMarouene Boubakri 				    uint8_t *tag, unsigned int *tag_len)
517c34c183aSMarouene Boubakri {
518c34c183aSMarouene Boubakri 	struct ree_fs_ta_handle *handle = (struct ree_fs_ta_handle *)h;
519c34c183aSMarouene Boubakri 
520c34c183aSMarouene Boubakri 	if (!tag || *tag_len < handle->shdr->hash_size) {
521c34c183aSMarouene Boubakri 		*tag_len = handle->shdr->hash_size;
522c34c183aSMarouene Boubakri 		return TEE_ERROR_SHORT_BUFFER;
523c34c183aSMarouene Boubakri 	}
524c34c183aSMarouene Boubakri 	*tag_len = handle->shdr->hash_size;
525c34c183aSMarouene Boubakri 
526c34c183aSMarouene Boubakri 	memcpy(tag, SHDR_GET_HASH(handle->shdr), handle->shdr->hash_size);
527c34c183aSMarouene Boubakri 
528c34c183aSMarouene Boubakri 	return TEE_SUCCESS;
529c34c183aSMarouene Boubakri }
530c34c183aSMarouene Boubakri 
check_digest(struct ree_fs_ta_handle * h)531c34c183aSMarouene Boubakri static TEE_Result check_digest(struct ree_fs_ta_handle *h)
532c34c183aSMarouene Boubakri {
533c34c183aSMarouene Boubakri 	void *digest = NULL;
534c34c183aSMarouene Boubakri 	TEE_Result res;
535c34c183aSMarouene Boubakri 
536c34c183aSMarouene Boubakri 	digest = malloc(h->shdr->hash_size);
537c34c183aSMarouene Boubakri 	if (!digest)
538c34c183aSMarouene Boubakri 		return TEE_ERROR_OUT_OF_MEMORY;
539c34c183aSMarouene Boubakri 	res = crypto_hash_final(h->hash_ctx, digest, h->shdr->hash_size);
540c34c183aSMarouene Boubakri 	if (res != TEE_SUCCESS) {
541c34c183aSMarouene Boubakri 		res = TEE_ERROR_SECURITY;
542c34c183aSMarouene Boubakri 		goto out;
543c34c183aSMarouene Boubakri 	}
544c8219657SJens Wiklander 	if (FTMN_CALLEE_DONE_MEMCMP(memcmp, digest, SHDR_GET_HASH(h->shdr),
545c8219657SJens Wiklander 				    h->shdr->hash_size))
546c34c183aSMarouene Boubakri 		res = TEE_ERROR_SECURITY;
547c34c183aSMarouene Boubakri out:
548c34c183aSMarouene Boubakri 	free(digest);
549c34c183aSMarouene Boubakri 	return res;
550c34c183aSMarouene Boubakri }
551c34c183aSMarouene Boubakri 
ree_fs_ta_read(struct ts_store_handle * h,void * data_core,void * data_user,size_t len)552ef44161fSJens Wiklander static TEE_Result ree_fs_ta_read(struct ts_store_handle *h, void *data_core,
553ef44161fSJens Wiklander 				 void *data_user, size_t len)
554c34c183aSMarouene Boubakri {
555c34c183aSMarouene Boubakri 	struct ree_fs_ta_handle *handle = (struct ree_fs_ta_handle *)h;
556c34c183aSMarouene Boubakri 	uint8_t *src = (uint8_t *)handle->nw_ta + handle->offs;
557ef44161fSJens Wiklander 	size_t bb_len = MIN(1024U, len);
558c34c183aSMarouene Boubakri 	size_t next_offs = 0;
559c34c183aSMarouene Boubakri 	TEE_Result res = TEE_SUCCESS;
560ef44161fSJens Wiklander 	size_t num_bytes = 0;
561ef44161fSJens Wiklander 	size_t dst_len = 0;
562ef44161fSJens Wiklander 	void *dst = NULL;
563ef44161fSJens Wiklander 	void *bb = NULL;
564ef44161fSJens Wiklander 
565c34c183aSMarouene Boubakri 
566c34c183aSMarouene Boubakri 	if (ADD_OVERFLOW(handle->offs, len, &next_offs) ||
567c34c183aSMarouene Boubakri 	    next_offs > handle->nw_ta_size)
568c34c183aSMarouene Boubakri 		return TEE_ERROR_BAD_PARAMETERS;
569c34c183aSMarouene Boubakri 
570ef44161fSJens Wiklander 	if (data_core) {
571ef44161fSJens Wiklander 		dst = data_core;
572ef44161fSJens Wiklander 		dst_len = len;
573c34c183aSMarouene Boubakri 	} else {
574ef44161fSJens Wiklander 		bb = bb_alloc(bb_len);
575ef44161fSJens Wiklander 		if (!bb)
576c34c183aSMarouene Boubakri 			return TEE_ERROR_OUT_OF_MEMORY;
577ef44161fSJens Wiklander 		dst = bb;
578ef44161fSJens Wiklander 		dst_len = bb_len;
579ef44161fSJens Wiklander 	}
580c34c183aSMarouene Boubakri 
581ef44161fSJens Wiklander 	/*
582ef44161fSJens Wiklander 	 * This loop will only run once if data_core is non-NULL, but as
583ef44161fSJens Wiklander 	 * many times as needed if the bounce buffer bb is used. That's why
584ef44161fSJens Wiklander 	 * dst doesn't need to be updated in the loop.
585ef44161fSJens Wiklander 	 */
586c34c183aSMarouene Boubakri 	while (num_bytes < len) {
587ef44161fSJens Wiklander 		size_t n = MIN(dst_len, len - num_bytes);
588c34c183aSMarouene Boubakri 
589ef44161fSJens Wiklander 		if (handle->shdr->img_type == SHDR_ENCRYPTED_TA) {
590ef44161fSJens Wiklander 			res = tee_ta_decrypt_update(handle->enc_ctx, dst,
591c34c183aSMarouene Boubakri 						    src + num_bytes, n);
592ef44161fSJens Wiklander 			if (res) {
593ef44161fSJens Wiklander 				res = TEE_ERROR_SECURITY;
594ef44161fSJens Wiklander 				goto out;
595ef44161fSJens Wiklander 			}
596ef44161fSJens Wiklander 		} else {
597ef44161fSJens Wiklander 			memcpy(dst, src + num_bytes, n);
598ef44161fSJens Wiklander 		}
599ef44161fSJens Wiklander 
600ef44161fSJens Wiklander 		res = crypto_hash_update(handle->hash_ctx, dst, n);
601ef44161fSJens Wiklander 		if (res) {
602ef44161fSJens Wiklander 			res = TEE_ERROR_SECURITY;
603ef44161fSJens Wiklander 			goto out;
604ef44161fSJens Wiklander 		}
605ef44161fSJens Wiklander 		if (data_user) {
606ef44161fSJens Wiklander 			res = copy_to_user((uint8_t *)data_user + num_bytes,
607ef44161fSJens Wiklander 					   dst, n);
608ef44161fSJens Wiklander 			if (res) {
609ef44161fSJens Wiklander 				res = TEE_ERROR_SECURITY;
610ef44161fSJens Wiklander 				goto out;
611ef44161fSJens Wiklander 			}
612ef44161fSJens Wiklander 		}
613c34c183aSMarouene Boubakri 		num_bytes += n;
614c34c183aSMarouene Boubakri 	}
615c34c183aSMarouene Boubakri 
616c34c183aSMarouene Boubakri 	handle->offs = next_offs;
617c34c183aSMarouene Boubakri 	if (handle->offs == handle->nw_ta_size) {
618c34c183aSMarouene Boubakri 		if (handle->shdr->img_type == SHDR_ENCRYPTED_TA) {
619c34c183aSMarouene Boubakri 			/*
620c34c183aSMarouene Boubakri 			 * Last read: time to finalize authenticated
621c34c183aSMarouene Boubakri 			 * decryption.
622c34c183aSMarouene Boubakri 			 */
623c34c183aSMarouene Boubakri 			res = tee_ta_decrypt_final(handle->enc_ctx,
624c34c183aSMarouene Boubakri 						   handle->ehdr, NULL, NULL, 0);
625ef44161fSJens Wiklander 			if (res != TEE_SUCCESS) {
626ef44161fSJens Wiklander 				res = TEE_ERROR_SECURITY;
627ef44161fSJens Wiklander 				goto out;
628ef44161fSJens Wiklander 			}
629c34c183aSMarouene Boubakri 		}
630c34c183aSMarouene Boubakri 		/*
631c34c183aSMarouene Boubakri 		 * Last read: time to check if our digest matches the expected
632c34c183aSMarouene Boubakri 		 * one (from the signed header)
633c34c183aSMarouene Boubakri 		 */
634c34c183aSMarouene Boubakri 		res = check_digest(handle);
635c34c183aSMarouene Boubakri 		if (res != TEE_SUCCESS)
636ef44161fSJens Wiklander 			goto out;
637c34c183aSMarouene Boubakri 
638c34c183aSMarouene Boubakri 		if (handle->bs_hdr)
639ce20b8ecSJens Wiklander 			res = check_update_version(ta_ver_db,
640ce20b8ecSJens Wiklander 						   handle->bs_hdr->uuid,
641ce20b8ecSJens Wiklander 						   handle->bs_hdr->ta_version);
642c34c183aSMarouene Boubakri 	}
643ef44161fSJens Wiklander out:
644ef44161fSJens Wiklander 	bb_free(bb, bb_len);
645c34c183aSMarouene Boubakri 	return res;
646c34c183aSMarouene Boubakri }
647c34c183aSMarouene Boubakri 
ree_fs_ta_close(struct ts_store_handle * h)648c34c183aSMarouene Boubakri static void ree_fs_ta_close(struct ts_store_handle *h)
649c34c183aSMarouene Boubakri {
650c34c183aSMarouene Boubakri 	struct ree_fs_ta_handle *handle = (struct ree_fs_ta_handle *)h;
651c34c183aSMarouene Boubakri 
652c34c183aSMarouene Boubakri 	if (!handle)
653c34c183aSMarouene Boubakri 		return;
654c34c183aSMarouene Boubakri 	thread_rpc_free_payload(handle->mobj);
655c34c183aSMarouene Boubakri 	crypto_hash_free_ctx(handle->hash_ctx);
656c34c183aSMarouene Boubakri 	free(handle->shdr);
657c34c183aSMarouene Boubakri 	free(handle->ehdr);
658c34c183aSMarouene Boubakri 	free(handle->bs_hdr);
659c34c183aSMarouene Boubakri 	free(handle);
660c34c183aSMarouene Boubakri }
661c34c183aSMarouene Boubakri 
662c34c183aSMarouene Boubakri #ifndef CFG_REE_FS_TA_BUFFERED
663c34c183aSMarouene Boubakri REGISTER_TA_STORE(9) = {
664c34c183aSMarouene Boubakri 	.description = "REE",
665c34c183aSMarouene Boubakri 	.open = ree_fs_ta_open,
666c34c183aSMarouene Boubakri 	.get_size = ree_fs_ta_get_size,
667c34c183aSMarouene Boubakri 	.get_tag = ree_fs_ta_get_tag,
668c34c183aSMarouene Boubakri 	.read = ree_fs_ta_read,
669c34c183aSMarouene Boubakri 	.close = ree_fs_ta_close,
670c34c183aSMarouene Boubakri };
671c34c183aSMarouene Boubakri #endif
672c34c183aSMarouene Boubakri 
673c34c183aSMarouene Boubakri #ifdef CFG_REE_FS_TA_BUFFERED
674c34c183aSMarouene Boubakri 
675c34c183aSMarouene Boubakri /*
676c34c183aSMarouene Boubakri  * This is a wrapper around the "REE FS" TA store.
677c34c183aSMarouene Boubakri  * The whole TA/library is read into a temporary buffer during .open(). This
678c34c183aSMarouene Boubakri  * allows the binary to be authenticated before any data is read and processed
679c34c183aSMarouene Boubakri  * by the upper layer (ELF loader).
680c34c183aSMarouene Boubakri  */
681c34c183aSMarouene Boubakri 
682c34c183aSMarouene Boubakri struct buf_ree_fs_ta_handle {
683c34c183aSMarouene Boubakri 	struct ts_store_handle *h; /* Note: a REE FS TA store handle */
684c34c183aSMarouene Boubakri 	size_t ta_size;
685c34c183aSMarouene Boubakri 	tee_mm_entry_t *mm;
686c34c183aSMarouene Boubakri 	uint8_t *buf;
687c34c183aSMarouene Boubakri 	size_t offs;
688c34c183aSMarouene Boubakri 	uint8_t *tag;
689c34c183aSMarouene Boubakri 	unsigned int tag_len;
690c34c183aSMarouene Boubakri };
691c34c183aSMarouene Boubakri 
buf_ta_open(const TEE_UUID * uuid,struct ts_store_handle ** h)692c34c183aSMarouene Boubakri static TEE_Result buf_ta_open(const TEE_UUID *uuid,
693c34c183aSMarouene Boubakri 			      struct ts_store_handle **h)
694c34c183aSMarouene Boubakri {
695c34c183aSMarouene Boubakri 	struct buf_ree_fs_ta_handle *handle = NULL;
696c8219657SJens Wiklander 	struct ftmn ftmn = { };
697c34c183aSMarouene Boubakri 	TEE_Result res = TEE_SUCCESS;
698c34c183aSMarouene Boubakri 
699c34c183aSMarouene Boubakri 	handle = calloc(1, sizeof(*handle));
700c34c183aSMarouene Boubakri 	if (!handle)
701c34c183aSMarouene Boubakri 		return TEE_ERROR_OUT_OF_MEMORY;
7022d7720f1SJens Wiklander 	FTMN_PUSH_LINKED_CALL(&ftmn, FTMN_FUNC_HASH("ree_fs_ta_open"));
703c34c183aSMarouene Boubakri 	res = ree_fs_ta_open(uuid, &handle->h);
704c8219657SJens Wiklander 	if (!res)
705c8219657SJens Wiklander 		FTMN_SET_CHECK_RES_FROM_CALL(&ftmn, FTMN_INCR0, res);
706c8219657SJens Wiklander 	FTMN_POP_LINKED_CALL(&ftmn);
707c34c183aSMarouene Boubakri 	if (res)
708c8219657SJens Wiklander 		goto err_free_handle;
709c8219657SJens Wiklander 	ftmn_checkpoint(&ftmn, FTMN_INCR1);
710c8219657SJens Wiklander 
711c34c183aSMarouene Boubakri 	res = ree_fs_ta_get_size(handle->h, &handle->ta_size);
712c34c183aSMarouene Boubakri 	if (res)
713c34c183aSMarouene Boubakri 		goto err;
714c34c183aSMarouene Boubakri 
715c34c183aSMarouene Boubakri 	res = ree_fs_ta_get_tag(handle->h, NULL, &handle->tag_len);
716c34c183aSMarouene Boubakri 	if (res != TEE_ERROR_SHORT_BUFFER) {
717c34c183aSMarouene Boubakri 		res = TEE_ERROR_GENERIC;
718c34c183aSMarouene Boubakri 		goto err;
719c34c183aSMarouene Boubakri 	}
720c34c183aSMarouene Boubakri 	handle->tag = malloc(handle->tag_len);
721c34c183aSMarouene Boubakri 	if (!handle->tag) {
722c34c183aSMarouene Boubakri 		res = TEE_ERROR_OUT_OF_MEMORY;
723c34c183aSMarouene Boubakri 		goto err;
724c34c183aSMarouene Boubakri 	}
725c34c183aSMarouene Boubakri 	res = ree_fs_ta_get_tag(handle->h, handle->tag, &handle->tag_len);
726c34c183aSMarouene Boubakri 	if (res)
727c34c183aSMarouene Boubakri 		goto err;
728c34c183aSMarouene Boubakri 
729de19cacbSJens Wiklander 	handle->mm = phys_mem_ta_alloc(handle->ta_size);
730c34c183aSMarouene Boubakri 	if (!handle->mm) {
731c34c183aSMarouene Boubakri 		res = TEE_ERROR_OUT_OF_MEMORY;
732c34c183aSMarouene Boubakri 		goto err;
733c34c183aSMarouene Boubakri 	}
734c34c183aSMarouene Boubakri 	handle->buf = phys_to_virt(tee_mm_get_smem(handle->mm),
7352f2f69dfSJens Wiklander 				   MEM_AREA_SEC_RAM_OVERALL, handle->ta_size);
736c34c183aSMarouene Boubakri 	if (!handle->buf) {
737c34c183aSMarouene Boubakri 		res = TEE_ERROR_OUT_OF_MEMORY;
738c34c183aSMarouene Boubakri 		goto err;
739c34c183aSMarouene Boubakri 	}
740c8219657SJens Wiklander 
741c8219657SJens Wiklander 	FTMN_PUSH_LINKED_CALL(&ftmn, FTMN_FUNC_HASH("check_digest"));
742ef44161fSJens Wiklander 	res = ree_fs_ta_read(handle->h, handle->buf, NULL, handle->ta_size);
743c8219657SJens Wiklander 	if (!res)
744c8219657SJens Wiklander 		FTMN_SET_CHECK_RES_FROM_CALL(&ftmn, FTMN_INCR0, res);
745c8219657SJens Wiklander 	FTMN_POP_LINKED_CALL(&ftmn);
746c34c183aSMarouene Boubakri 	if (res)
747c34c183aSMarouene Boubakri 		goto err;
748c8219657SJens Wiklander 	ftmn_checkpoint(&ftmn, FTMN_INCR1);
749c8219657SJens Wiklander 
750c34c183aSMarouene Boubakri 	*h = (struct ts_store_handle *)handle;
751c8219657SJens Wiklander 	ree_fs_ta_close(handle->h);
752c8219657SJens Wiklander 	return ftmn_return_res(&ftmn, FTMN_STEP_COUNT(2, 2), TEE_SUCCESS);
753c8219657SJens Wiklander 
754c34c183aSMarouene Boubakri err:
755c34c183aSMarouene Boubakri 	ree_fs_ta_close(handle->h);
756c34c183aSMarouene Boubakri 	tee_mm_free(handle->mm);
757c34c183aSMarouene Boubakri 	free(handle->tag);
758c8219657SJens Wiklander err_free_handle:
759c34c183aSMarouene Boubakri 	free(handle);
760c34c183aSMarouene Boubakri 	return res;
761c34c183aSMarouene Boubakri }
762c34c183aSMarouene Boubakri 
buf_ta_get_size(const struct ts_store_handle * h,size_t * size)763c34c183aSMarouene Boubakri static TEE_Result buf_ta_get_size(const struct ts_store_handle *h,
764c34c183aSMarouene Boubakri 				  size_t *size)
765c34c183aSMarouene Boubakri {
766c34c183aSMarouene Boubakri 	struct buf_ree_fs_ta_handle *handle = (struct buf_ree_fs_ta_handle *)h;
767c34c183aSMarouene Boubakri 
768c34c183aSMarouene Boubakri 	*size = handle->ta_size;
769c34c183aSMarouene Boubakri 	return TEE_SUCCESS;
770c34c183aSMarouene Boubakri }
771c34c183aSMarouene Boubakri 
buf_ta_read(struct ts_store_handle * h,void * data_core,void * data_user,size_t len)772ef44161fSJens Wiklander static TEE_Result buf_ta_read(struct ts_store_handle *h, void *data_core,
773ef44161fSJens Wiklander 			      void *data_user, size_t len)
774c34c183aSMarouene Boubakri {
775c34c183aSMarouene Boubakri 	struct buf_ree_fs_ta_handle *handle = (struct buf_ree_fs_ta_handle *)h;
776c34c183aSMarouene Boubakri 	uint8_t *src = handle->buf + handle->offs;
777ef44161fSJens Wiklander 	TEE_Result res = TEE_SUCCESS;
778c34c183aSMarouene Boubakri 	size_t next_offs = 0;
779c34c183aSMarouene Boubakri 
780c34c183aSMarouene Boubakri 	if (ADD_OVERFLOW(handle->offs, len, &next_offs) ||
781c34c183aSMarouene Boubakri 	    next_offs > handle->ta_size)
782c34c183aSMarouene Boubakri 		return TEE_ERROR_BAD_PARAMETERS;
783c34c183aSMarouene Boubakri 
784ef44161fSJens Wiklander 	if (data_core)
785ef44161fSJens Wiklander 		memcpy(data_core, src, len);
786ef44161fSJens Wiklander 	if (data_user) {
787ef44161fSJens Wiklander 		res = copy_to_user(data_user, src, len);
788ef44161fSJens Wiklander 		if (res)
789ef44161fSJens Wiklander 			return res;
790ef44161fSJens Wiklander 	}
791c34c183aSMarouene Boubakri 	handle->offs = next_offs;
792c34c183aSMarouene Boubakri 	return TEE_SUCCESS;
793c34c183aSMarouene Boubakri }
794c34c183aSMarouene Boubakri 
buf_ta_get_tag(const struct ts_store_handle * h,uint8_t * tag,unsigned int * tag_len)795c34c183aSMarouene Boubakri static TEE_Result buf_ta_get_tag(const struct ts_store_handle *h,
796c34c183aSMarouene Boubakri 				 uint8_t *tag, unsigned int *tag_len)
797c34c183aSMarouene Boubakri {
798c34c183aSMarouene Boubakri 	struct buf_ree_fs_ta_handle *handle = (struct buf_ree_fs_ta_handle *)h;
799c34c183aSMarouene Boubakri 
800c34c183aSMarouene Boubakri 	*tag_len = handle->tag_len;
801c34c183aSMarouene Boubakri 	if (!tag || *tag_len < handle->tag_len)
802c34c183aSMarouene Boubakri 		return TEE_ERROR_SHORT_BUFFER;
803c34c183aSMarouene Boubakri 
804c34c183aSMarouene Boubakri 	memcpy(tag, handle->tag, handle->tag_len);
805c34c183aSMarouene Boubakri 
806c34c183aSMarouene Boubakri 	return TEE_SUCCESS;
807c34c183aSMarouene Boubakri }
808c34c183aSMarouene Boubakri 
buf_ta_close(struct ts_store_handle * h)809c34c183aSMarouene Boubakri static void buf_ta_close(struct ts_store_handle *h)
810c34c183aSMarouene Boubakri {
811c34c183aSMarouene Boubakri 	struct buf_ree_fs_ta_handle *handle = (struct buf_ree_fs_ta_handle *)h;
812c34c183aSMarouene Boubakri 
813c34c183aSMarouene Boubakri 	if (!handle)
814c34c183aSMarouene Boubakri 		return;
815c34c183aSMarouene Boubakri 	tee_mm_free(handle->mm);
816c34c183aSMarouene Boubakri 	free(handle->tag);
817c34c183aSMarouene Boubakri 	free(handle);
818c34c183aSMarouene Boubakri }
819c34c183aSMarouene Boubakri 
820c34c183aSMarouene Boubakri REGISTER_TA_STORE(9) = {
821c34c183aSMarouene Boubakri 	.description = "REE [buffered]",
822c34c183aSMarouene Boubakri 	.open = buf_ta_open,
823c34c183aSMarouene Boubakri 	.get_size = buf_ta_get_size,
824c34c183aSMarouene Boubakri 	.get_tag = buf_ta_get_tag,
825c34c183aSMarouene Boubakri 	.read = buf_ta_read,
826c34c183aSMarouene Boubakri 	.close = buf_ta_close,
827c34c183aSMarouene Boubakri };
828c34c183aSMarouene Boubakri 
829c34c183aSMarouene Boubakri #endif /* CFG_REE_FS_TA_BUFFERED */
830