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