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 *)¶ms[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 *)¶ms[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