1 /*
2 * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
3 * Copyright (c) 2024 Cypress Semiconductor Corporation (an Infineon company)
4 * or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 *
8 */
9
10 #include "ps_object_system.h"
11
12 #include <stdbool.h>
13 #include <stddef.h>
14 #include <string.h>
15
16 #include "cmsis_compiler.h"
17 #include "psa/internal_trusted_storage.h"
18 #ifdef PS_ENCRYPTION
19 #include "ps_encrypted_object.h"
20 #endif
21 #include "ps_object_defs.h"
22 #include "ps_object_table.h"
23 #include "ps_utils.h"
24 #include "tfm_ps_req_mngr.h"
25 #include "tfm_log_unpriv.h"
26 #include "utilities.h"
27
28 #ifndef PS_ENCRYPTION
29 /* Gets the size of object written to the object system below */
30 #define PS_OBJECT_SIZE(max_size) (PS_OBJECT_HEADER_SIZE + (max_size))
31 #define PS_OBJECT_START_POSITION 0
32 #endif /* PS_ENCRYPTION */
33
34 /* Allocate static variables to process objects */
35 static struct ps_object_t g_ps_object;
36 static struct ps_obj_table_info_t g_obj_tbl_info;
37
38 /**
39 * \brief Initialize g_ps_object based on the input parameters and empty data.
40 *
41 * \param[in] uid Unique identifier for the data
42 * \param[in] client_id Identifier of the asset's owner (client)
43 * \param[in] create_flags Object create flags
44 * \param[in] size Object size
45 * \param[out] obj Object to initialize
46 *
47 */
48 __attribute__ ((always_inline))
ps_init_empty_object(psa_storage_uid_t uid,int32_t client_id,psa_storage_create_flags_t create_flags,uint32_t size,struct ps_object_t * obj)49 __STATIC_INLINE void ps_init_empty_object(
50 psa_storage_uid_t uid,
51 int32_t client_id,
52 psa_storage_create_flags_t create_flags,
53 uint32_t size,
54 struct ps_object_t *obj)
55 {
56 /* Set all object data to 0 */
57 (void)memset(obj, PS_DEFAULT_EMPTY_BUFF_VAL, PS_MAX_OBJECT_SIZE);
58
59 #ifdef PS_ENCRYPTION
60 obj->header.crypto.ref.uid = uid;
61 obj->header.crypto.ref.client_id = client_id;
62 #if PS_AES_KEY_USAGE_LIMIT != 0
63 obj->header.crypto.ref.key_gen_nr = ps_object_table_current_gen();
64 #endif
65 #else
66 /* Initialize object version */
67 obj->header.version = 0;
68 #endif /* PS_ENCRYPTION */
69
70 /* Set object header based on input parameters */
71 obj->header.info.max_size = size;
72 obj->header.info.create_flags = create_flags;
73 }
74
75 /**
76 * \brief Update the object table for the specified object with the content
77 * of g_obj_tbl_info. Also removes the old object table.
78 *
79 * \param[in] uid Unique identifier for the data
80 * \param[in] client_id Identifier of the asset's owner (client)
81 *
82 * \return Returns error code as specified in \ref psa_status_t
83 */
ps_update_table(psa_storage_uid_t uid,int32_t client_id)84 static psa_status_t ps_update_table(psa_storage_uid_t uid, int32_t client_id)
85 {
86 psa_status_t err;
87
88 /* Update the table with the new internal ID, etc for the object, and
89 * store it in the persistent area.
90 */
91 err = ps_object_table_set_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
92 if (err == PSA_SUCCESS) {
93 /* Delete old object table from the persistent area */
94 err = ps_object_table_delete_old_table();
95 } else {
96 /* Remove object as object table is not persistent and propagate
97 * object table manipulation error.
98 */
99 (void)psa_its_remove(g_obj_tbl_info.fid);
100 }
101
102 return err;
103 }
104
105 #ifdef PS_ENCRYPTION
106 #if PS_AES_KEY_USAGE_LIMIT != 0
107 /**
108 * \brief Update the key generation number in g_ps_object and clear
109 * g_obj_tbl_info.num_blocks.
110 */
ps_switch_key(void)111 static void ps_switch_key(void)
112 {
113 if (g_ps_object.header.crypto.ref.key_gen_nr == UINT32_MAX) {
114 /* We've run out of keys */
115 tfm_core_panic();
116 }
117 g_ps_object.header.crypto.ref.key_gen_nr++;
118 g_obj_tbl_info.num_blocks = 0;
119 }
120 #endif /* PS_AES_KEY_USAGE_LIMIT == 0 */
121
122 /**
123 * \brief Check whether the encryption key usage limit (if any) would be
124 * reached after an operation encrypting/decrypting the specified
125 * number of blocks. If so, switch the encryption key.
126 *
127 * Note that if the key is switched then g_obj_tbl_info.num_blocks will be
128 * changed. It is the caller's responsibility to write out the objects,
129 * encrypted with the new key, and to ensure that any such change gets
130 * reflected in the object table.
131 *
132 * \param[in] num_blocks Number of encryption blocks used.
133 *
134 * \return Returns error code as specified in \ref psa_status_t
135 */
ps_switch_keys_if_necessary(uint32_t num_blocks)136 static psa_status_t ps_switch_keys_if_necessary(uint32_t num_blocks)
137 {
138 psa_status_t err = PSA_SUCCESS;
139
140 /* Only necessary if there's a key usage limit */
141 #if PS_AES_KEY_USAGE_LIMIT == 0
142 (void)num_blocks;
143 #else
144 /* Always need to be able to decrypt the object once more to read it back */
145 if (g_obj_tbl_info.num_blocks + num_blocks > PS_AES_KEY_USAGE_LIMIT) {
146 ps_switch_key();
147 /* Re-store object, using new key */
148 err = ps_encrypted_object_write(g_obj_tbl_info.fid, &g_ps_object);
149 g_obj_tbl_info.num_blocks += num_blocks;
150 }
151 #endif /* PS_AES_KEY_USAGE_LIMIT == 0 */
152 return err;
153 }
154 #else
155 enum read_type_t {
156 READ_HEADER_ONLY = 0,
157 READ_ALL_OBJECT,
158 };
159
160 /**
161 * \brief Reads and validates an object header based on its object table info
162 * stored in g_obj_tbl_info.
163 *
164 * \param[in] type Read type as specified in \ref read_type_t
165 *
166 * \return Returns error code as specified in \ref psa_status_t
167 */
ps_read_object(enum read_type_t type)168 static psa_status_t ps_read_object(enum read_type_t type)
169 {
170 psa_status_t err;
171 size_t data_length;
172
173 /* Read object header */
174 err = psa_its_get(g_obj_tbl_info.fid,
175 PS_OBJECT_START_POSITION,
176 PS_OBJECT_HEADER_SIZE,
177 (void *)&g_ps_object.header,
178 &data_length);
179 if (err != PSA_SUCCESS) {
180 return err;
181 }
182
183 /* As PS encryption support is not enabled, check file ID and version to
184 * detect inconsistency after read the object header from flash.
185 */
186 if (g_ps_object.header.fid != g_obj_tbl_info.fid ||
187 g_ps_object.header.version != g_obj_tbl_info.version) {
188 return PSA_ERROR_DATA_CORRUPT;
189 }
190
191 /* Read object data if any */
192 if (type == READ_ALL_OBJECT && g_ps_object.header.info.current_size > 0) {
193 err = psa_its_get(g_obj_tbl_info.fid,
194 PS_OBJECT_HEADER_SIZE,
195 g_ps_object.header.info.current_size,
196 (void *)g_ps_object.data,
197 &data_length);
198 if (err != PSA_SUCCESS) {
199 return err;
200 }
201 }
202
203 return PSA_SUCCESS;
204 }
205
206 /**
207 * \brief Writes an object based on its object table info stored in
208 * g_obj_tbl_info and the input parameter.
209 *
210 * \param[in] wrt_size Number of bytes to write
211 *
212 * \return Returns error code as specified in \ref psa_status_t
213 */
ps_write_object(uint32_t wrt_size)214 static psa_status_t ps_write_object(uint32_t wrt_size)
215 {
216 /* Add object identification and increase object version */
217 g_ps_object.header.fid = g_obj_tbl_info.fid;
218 g_ps_object.header.version++;
219
220 /* Save object version to be stored in the object table */
221 g_obj_tbl_info.version = g_ps_object.header.version;
222
223 return psa_its_set(g_obj_tbl_info.fid, wrt_size,
224 (const void *)&g_ps_object,
225 PSA_STORAGE_FLAG_NONE);
226 }
227
228 #endif /* !PS_ENCRYPTION */
229
230 /**
231 * \brief Writes g_ps_object, encrypting it if necessary. Also uses g_obj_tbl_info.
232 *
233 * \param[in] uid Unique identifier for the data
234 * \param[in] client_id Identifier of the asset's owner (client)
235 * \param[out] p_blocks New number of encryption blocks needed to read/write
236 * the object, if changed.
237 *
238 * \return Returns error code as specified in \ref psa_status_t
239 */
ps_store_object(psa_storage_uid_t uid,int32_t client_id,uint32_t * p_blocks)240 static psa_status_t ps_store_object(psa_storage_uid_t uid, int32_t client_id, uint32_t *p_blocks)
241 {
242 psa_status_t err;
243 #ifndef PS_ENCRYPTION
244 uint32_t wrt_size;
245 #endif
246
247 #ifdef PS_ENCRYPTION
248 #if PS_AES_KEY_USAGE_LIMIT == 0
249 err = ps_encrypted_object_write(g_obj_tbl_info.fid, &g_ps_object);
250 #else
251 uint32_t num_blocks = ps_encrypted_object_blocks(g_ps_object.header.info.current_size);
252
253 /* Switch to new key if this write will not leave enough blocks to read the object */
254 if (2 * num_blocks >= PS_AES_KEY_USAGE_LIMIT - g_obj_tbl_info.num_blocks) {
255 ps_switch_key();
256 }
257
258 err = ps_encrypted_object_write(g_obj_tbl_info.fid, &g_ps_object);
259 g_obj_tbl_info.num_blocks += num_blocks;
260 /* If the write succeeded, the number of encryption blocks needed has changed */
261 if (err == PSA_SUCCESS) {
262 *p_blocks = num_blocks;
263 }
264 #endif /* PS_AES_KEY_USAGE_LIMIT == 0 */
265 #else
266 wrt_size = PS_OBJECT_SIZE(g_ps_object.header.info.current_size);
267
268 /* Write g_ps_object */
269 err = ps_write_object(wrt_size);
270 #endif /* PS_ENCRYPTION */
271
272 return err;
273 }
274
ps_system_prepare(void)275 psa_status_t ps_system_prepare(void)
276 {
277 psa_status_t err;
278
279 /* Reuse the allocated g_ps_object.data to store a temporary object table
280 * data to be validate inside the function.
281 * The stored date will be cleaned up when the g_ps_object.data will
282 * be used for the first time in the object system.
283 */
284 err = ps_object_table_init(g_ps_object.data);
285
286 #ifdef PS_ENCRYPTION
287 #if PS_AES_KEY_USAGE_LIMIT != 0
288 /* Sanity check that the largest allowed object can actually be written and read back */
289 if (2 * ps_encrypted_object_blocks(PS_MAX_ASSET_SIZE) > PS_AES_KEY_USAGE_LIMIT) {
290 ERROR_UNPRIV_RAW("Config error: PS_AES_KEY_USAGE_LIMIT prevents storing largest allowable PS object\n");
291 return PSA_ERROR_GENERIC_ERROR;
292 }
293 /* Ensure that we can never overflow a uint32_t block counter */
294 if (ps_encrypted_object_blocks(PS_MAX_ASSET_SIZE) > UINT32_MAX - PS_AES_KEY_USAGE_LIMIT) {
295 ERROR_UNPRIV_RAW("Config error: PS_AES_KEY_USAGE_LIMIT too large to safely count key usage\n");
296 return PSA_ERROR_GENERIC_ERROR;
297 }
298 #endif
299 g_obj_tbl_info.tag = g_ps_object.header.crypto.ref.tag;
300 #endif
301
302 return err;
303 }
304
ps_object_read(psa_storage_uid_t uid,int32_t client_id,uint32_t offset,uint32_t size,size_t * p_data_length)305 psa_status_t ps_object_read(psa_storage_uid_t uid, int32_t client_id,
306 uint32_t offset, uint32_t size,
307 size_t *p_data_length)
308 {
309 psa_status_t err;
310 #ifdef PS_ENCRYPTION
311 uint32_t num_blocks;
312 #endif
313
314 /* Retrieve the object information from the object table if the object
315 * exists.
316 */
317 err = ps_object_table_get_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
318 if (err != PSA_SUCCESS) {
319 return err;
320 }
321
322 /* Read object */
323 #ifdef PS_ENCRYPTION
324 g_ps_object.header.crypto.ref.uid = uid;
325 g_ps_object.header.crypto.ref.client_id = client_id;
326
327 err = ps_encrypted_object_read(g_obj_tbl_info.fid, &g_ps_object, &num_blocks);
328 #if PS_AES_KEY_USAGE_LIMIT != 0
329 g_obj_tbl_info.num_blocks += num_blocks;
330 #endif
331 #else
332 /* Read object header */
333 err = ps_read_object(READ_ALL_OBJECT);
334 #endif /* PS_ENCRYPTION */
335 if (err != PSA_SUCCESS) {
336 goto update_table_and_return;
337 }
338
339 /* Boundary check the incoming request */
340 if (offset > g_ps_object.header.info.current_size) {
341 err = PSA_ERROR_INVALID_ARGUMENT;
342 goto switch_keys_and_return;
343 }
344
345 size = PS_UTILS_MIN(size,
346 g_ps_object.header.info.current_size - offset);
347
348 /* Copy the decrypted object data to the output buffer */
349 ps_req_mngr_write_asset_data(g_ps_object.data + offset, size);
350
351 *p_data_length = size;
352
353 switch_keys_and_return:
354 #ifdef PS_ENCRYPTION
355 if (err == PSA_SUCCESS) {
356 err = ps_switch_keys_if_necessary(num_blocks);
357 } else {
358 (void)ps_switch_keys_if_necessary(num_blocks);
359 }
360 #endif
361
362 update_table_and_return:
363 #if defined(PS_ENCRYPTION) && (PS_AES_KEY_USAGE_LIMIT != 0)
364 if (err == PSA_SUCCESS) {
365 err = ps_update_table(uid, client_id);
366 } else {
367 (void)ps_update_table(uid, client_id);
368 }
369 #endif
370
371 /* Remove data stored in the object before leaving the function */
372 (void)memset(&g_ps_object, PS_DEFAULT_EMPTY_BUFF_VAL,
373 PS_MAX_OBJECT_SIZE);
374
375 return err;
376 }
377
ps_object_create(psa_storage_uid_t uid,int32_t client_id,psa_storage_create_flags_t create_flags,uint32_t size)378 psa_status_t ps_object_create(psa_storage_uid_t uid, int32_t client_id,
379 psa_storage_create_flags_t create_flags,
380 uint32_t size)
381 {
382 psa_status_t err;
383 uint32_t old_fid = PS_INVALID_FID;
384 uint32_t fid_am_reserved = 1;
385 uint32_t num_blocks;
386 bool object_exists = false;
387
388 /* Boundary check the incoming request */
389 if (size > PS_MAX_ASSET_SIZE) {
390 return PSA_ERROR_INVALID_ARGUMENT;
391 }
392
393 /* Retrieve the object information from the object table if the object
394 * exists.
395 */
396 err = ps_object_table_get_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
397 if (err == PSA_SUCCESS) {
398 object_exists = true;
399 #ifdef PS_ENCRYPTION
400 /* Read the object */
401 g_ps_object.header.crypto.ref.uid = uid;
402 g_ps_object.header.crypto.ref.client_id = client_id;
403
404 err = ps_encrypted_object_read(g_obj_tbl_info.fid, &g_ps_object, &num_blocks);
405 #if PS_AES_KEY_USAGE_LIMIT != 0
406 g_obj_tbl_info.num_blocks += num_blocks;
407 #endif /* PS_AES_KEY_USAGE_LIMIT */
408 #else
409 /* Read the object header */
410 err = ps_read_object(READ_HEADER_ONLY);
411 #endif /* PS_ENCRYPTION */
412 if (err != PSA_SUCCESS) {
413 goto update_table_and_return;
414 }
415
416 /* If the object exists and has the write once flag set, then it cannot
417 * be modified.
418 */
419 if (g_ps_object.header.info.create_flags
420 & PSA_STORAGE_FLAG_WRITE_ONCE) {
421 err = PSA_ERROR_NOT_PERMITTED;
422 goto switch_keys_and_return;
423 }
424
425 /* Update the create flags and max object size */
426 g_ps_object.header.info.create_flags = create_flags;
427 g_ps_object.header.info.max_size = size;
428
429 /* Save old file ID */
430 old_fid = g_obj_tbl_info.fid;
431 } else if (err == PSA_ERROR_DOES_NOT_EXIST) {
432 /* If the object does not exist, then initialize it based on the input
433 * arguments and empty content. Requests 2 FIDs to prevent exhaustion.
434 */
435 fid_am_reserved = 2;
436 ps_init_empty_object(uid, client_id, create_flags, size, &g_ps_object);
437 #if PS_AES_KEY_USAGE_LIMIT != 0
438 g_obj_tbl_info.num_blocks = 0;
439 #endif
440 } else {
441 return err;
442 }
443
444 /* Update the object data */
445 err = ps_req_mngr_read_asset_data(g_ps_object.data, size);
446 if (err != PSA_SUCCESS) {
447 goto switch_keys_and_return;
448 }
449
450 /* Get new file ID */
451 err = ps_object_table_get_free_fid(fid_am_reserved,
452 &g_obj_tbl_info.fid);
453 if (err != PSA_SUCCESS) {
454 goto switch_keys_and_return;
455 }
456
457 /* Update the current object size */
458 g_ps_object.header.info.current_size = size;
459
460 err = ps_store_object(uid, client_id, &num_blocks);
461 if (err != PSA_SUCCESS) {
462 /* If we failed to store the updated object, we need to keep the old version */
463 if (old_fid != PS_INVALID_FID) {
464 g_obj_tbl_info.fid = old_fid;
465 }
466 goto switch_keys_and_return;
467 }
468
469 switch_keys_and_return:
470 #ifdef PS_ENCRYPTION
471 /* In the normal case, we will switch keys before writing, if necessary.
472 * This is here for the error path when we didn't already write the object
473 */
474 if ((old_fid != PS_INVALID_FID) && (err != PSA_SUCCESS)) {
475 (void)ps_switch_keys_if_necessary(num_blocks);
476 }
477 #endif /* PS_ENCRYPTION */
478
479 update_table_and_return:
480 if (err == PSA_SUCCESS) {
481 err = ps_update_table(uid, client_id);
482 } else {
483 /* If the object didn't already exist and we failed to add it, no need to update the table */
484 if (object_exists) {
485 (void)ps_update_table(uid, client_id);
486 }
487 }
488
489 if ((err == PSA_SUCCESS) && (old_fid != PS_INVALID_FID)) {
490 /* Remove old object */
491 err = psa_its_remove(old_fid);
492 }
493
494 /* Remove data stored in the object before leaving the function */
495 (void)memset(&g_ps_object, PS_DEFAULT_EMPTY_BUFF_VAL, PS_MAX_OBJECT_SIZE);
496
497 return err;
498 }
499
ps_object_write(psa_storage_uid_t uid,int32_t client_id,uint32_t offset,uint32_t size)500 psa_status_t ps_object_write(psa_storage_uid_t uid, int32_t client_id,
501 uint32_t offset, uint32_t size)
502 {
503 psa_status_t err;
504 uint32_t old_fid = PS_INVALID_FID;
505 uint32_t num_blocks;
506
507 /* Retrieve the object information from the object table if the object
508 * exists.
509 */
510 err = ps_object_table_get_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
511 if (err != PSA_SUCCESS) {
512 return err;
513 }
514
515 /* Read the object */
516 #ifdef PS_ENCRYPTION
517 g_ps_object.header.crypto.ref.uid = uid;
518 g_ps_object.header.crypto.ref.client_id = client_id;
519
520 err = ps_encrypted_object_read(g_obj_tbl_info.fid, &g_ps_object, &num_blocks);
521 #if PS_AES_KEY_USAGE_LIMIT != 0
522 g_obj_tbl_info.num_blocks += num_blocks;
523 #endif
524 #else
525 err = ps_read_object(READ_ALL_OBJECT);
526 #endif /* PS_ENCRYPTION */
527 if (err != PSA_SUCCESS) {
528 goto update_table_and_return;
529 }
530
531 /* If the object has the write once flag set, then it cannot be modified. */
532 if (g_ps_object.header.info.create_flags & PSA_STORAGE_FLAG_WRITE_ONCE) {
533 err = PSA_ERROR_NOT_PERMITTED;
534 goto switch_keys_and_return;
535 }
536
537 /* Offset must not be larger than the object's current size to prevent gaps
538 * being created in the object data.
539 */
540 if (offset > g_ps_object.header.info.current_size) {
541 err = PSA_ERROR_INVALID_ARGUMENT;
542 goto switch_keys_and_return;
543 }
544
545 /* Boundary check the incoming request */
546 err = ps_utils_check_contained_in(g_ps_object.header.info.max_size,
547 offset, size);
548 if (err != PSA_SUCCESS) {
549 goto switch_keys_and_return;
550 }
551
552 /* Update the object data */
553 err = ps_req_mngr_read_asset_data(g_ps_object.data + offset, size);
554 if (err != PSA_SUCCESS) {
555 goto switch_keys_and_return;
556 }
557
558 /* Save old file ID */
559 old_fid = g_obj_tbl_info.fid;
560
561 /* Get new file ID */
562 err = ps_object_table_get_free_fid(1, &g_obj_tbl_info.fid);
563 if (err != PSA_SUCCESS) {
564 goto switch_keys_and_return;
565 }
566
567 /* Update the current object size if necessary */
568 if ((offset + size) > g_ps_object.header.info.current_size) {
569 g_ps_object.header.info.current_size = offset + size;
570 }
571
572 err = ps_store_object(uid, client_id, &num_blocks);
573 if (err != PSA_SUCCESS) {
574 /* We couldn't write the new data, so keep the old */
575 g_obj_tbl_info.fid = old_fid;
576 goto switch_keys_and_return;
577 }
578
579 switch_keys_and_return:
580 #ifdef PS_ENCRYPTION
581 /* In the normal case, we will switch keys before writing, if necessary.
582 * This is here for the error path when we didn't already write the object
583 */
584 if (err != PSA_SUCCESS) {
585 (void)ps_switch_keys_if_necessary(num_blocks);
586 }
587 #endif /* PS_ENCRYPTION */
588
589 update_table_and_return:
590 if (err == PSA_SUCCESS) {
591 err = ps_update_table(uid, client_id);
592 } else {
593 (void)ps_update_table(uid, client_id);
594 }
595
596 if (err == PSA_SUCCESS) {
597 /* Remove old object */
598 err = psa_its_remove(old_fid);
599 }
600
601 /* Remove data stored in the object before leaving the function */
602 (void)memset(&g_ps_object, PS_DEFAULT_EMPTY_BUFF_VAL,
603 PS_MAX_OBJECT_SIZE);
604
605 return err;
606 }
607
ps_object_get_info(psa_storage_uid_t uid,int32_t client_id,struct psa_storage_info_t * info)608 psa_status_t ps_object_get_info(psa_storage_uid_t uid, int32_t client_id,
609 struct psa_storage_info_t *info)
610 {
611 psa_status_t err;
612 #ifdef PS_ENCRYPTION
613 uint32_t num_blocks;
614 #endif
615
616 /* Retrieve the object information from the object table if the object
617 * exists.
618 */
619 err = ps_object_table_get_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
620 if (err != PSA_SUCCESS) {
621 return err;
622 }
623
624 #ifdef PS_ENCRYPTION
625 g_ps_object.header.crypto.ref.uid = uid;
626 g_ps_object.header.crypto.ref.client_id = client_id;
627
628 err = ps_encrypted_object_read(g_obj_tbl_info.fid, &g_ps_object, &num_blocks);
629 #if PS_AES_KEY_USAGE_LIMIT != 0
630 g_obj_tbl_info.num_blocks += num_blocks;
631 #endif
632 #else
633 err = ps_read_object(READ_HEADER_ONLY);
634 #endif /* PS_ENCRYPTION */
635 if (err != PSA_SUCCESS) {
636 goto update_table_and_return;
637 }
638
639 /* Copy PS object info to the PSA PS info struct */
640 info->size = g_ps_object.header.info.current_size;
641 info->capacity = g_ps_object.header.info.max_size;
642 info->flags = g_ps_object.header.info.create_flags;
643
644 #ifdef PS_ENCRYPTION
645 err = ps_switch_keys_if_necessary(num_blocks);
646 #endif /* PS_ENCRYPTION */
647
648 update_table_and_return:
649 #ifdef PS_ENCRYPTION
650 #if PS_AES_KEY_USAGE_LIMIT != 0
651 if (err == PSA_SUCCESS) {
652 err = ps_update_table(uid, client_id);
653 } else {
654 (void)ps_update_table(uid, client_id);
655 }
656 #endif
657 #endif
658
659 /* Remove data stored in the object before leaving the function */
660 (void)memset(&g_ps_object, PS_DEFAULT_EMPTY_BUFF_VAL,
661 PS_MAX_OBJECT_SIZE);
662
663 return err;
664 }
665
ps_object_delete(psa_storage_uid_t uid,int32_t client_id)666 psa_status_t ps_object_delete(psa_storage_uid_t uid, int32_t client_id)
667 {
668 psa_status_t err;
669 #ifdef PS_ENCRYPTION
670 uint32_t num_blocks;
671 #endif
672
673 /* Retrieve the object information from the object table if the object
674 * exists.
675 */
676 err = ps_object_table_get_obj_tbl_info(uid, client_id, &g_obj_tbl_info);
677 if (err != PSA_SUCCESS) {
678 return err;
679 }
680
681 #ifdef PS_ENCRYPTION
682 g_ps_object.header.crypto.ref.uid = uid;
683 g_ps_object.header.crypto.ref.client_id = client_id;
684
685 err = ps_encrypted_object_read(g_obj_tbl_info.fid, &g_ps_object, &num_blocks);
686 #if PS_AES_KEY_USAGE_LIMIT != 0
687 g_obj_tbl_info.num_blocks += num_blocks;
688 #endif
689 #else
690 err = ps_read_object(READ_HEADER_ONLY);
691 #endif /* PS_ENCRYPTION */
692 if (err != PSA_SUCCESS) {
693 goto update_table_and_return;
694 }
695
696 /* Check that the write once flag is not set */
697 if (g_ps_object.header.info.create_flags & PSA_STORAGE_FLAG_WRITE_ONCE) {
698 err = PSA_ERROR_NOT_PERMITTED;
699 goto switch_keys_and_return;
700 }
701
702 /* Delete object from the table and stores the table in the persistent
703 * area.
704 */
705 err = ps_object_table_delete_object(uid, client_id);
706 if (err != PSA_SUCCESS) {
707 goto switch_keys_and_return;
708 }
709
710 #if PS_AES_KEY_USAGE_LIMIT != 0
711 /* Ensure that the key will change if this object is ever re-created */
712 if (g_ps_object.header.crypto.ref.key_gen_nr >= ps_object_table_current_gen()) {
713 ps_object_table_set_gen(g_ps_object.header.crypto.ref.key_gen_nr + 1);
714 }
715 #endif
716
717 /* Delete old object table from the persistent area */
718 err = ps_object_table_delete_old_table();
719 if (err != PSA_SUCCESS) {
720 goto switch_keys_and_return;
721 }
722
723 /* Remove old object */
724 err = psa_its_remove(g_obj_tbl_info.fid);
725
726 switch_keys_and_return:
727 #ifdef PS_ENCRYPTION
728 /* If the object isn't actually deleted, we may need to switch keys */
729 if (err != PSA_SUCCESS) {
730 (void)ps_switch_keys_if_necessary(num_blocks);
731 }
732 #endif
733
734 update_table_and_return:
735 #ifdef PS_ENCRYPTION
736 #if PS_AES_KEY_USAGE_LIMIT != 0
737 if (err != PSA_SUCCESS) {
738 (void)ps_update_table(uid, client_id);
739 }
740 #endif
741 #endif
742
743 /* Remove data stored in the object before leaving the function */
744 (void)memset(&g_ps_object, PS_DEFAULT_EMPTY_BUFF_VAL,
745 PS_MAX_OBJECT_SIZE);
746
747 return err;
748 }
749
ps_system_wipe_all(void)750 psa_status_t ps_system_wipe_all(void)
751 {
752 /* This function may get called as a corrective action
753 * if a system level security violation is detected.
754 * This could be asynchronous to normal system operation
755 * and state of the ps system lock is unknown. Hence
756 * this function doesn't block on the lock and directly
757 * moves to erasing the flash instead.
758 */
759 return ps_object_table_create();
760 }
761