TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ps_object_table.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "ps_object_table.h"
9 
10 #include <stddef.h>
11 
12 #include "cmsis_compiler.h"
14 #include "flash_layout.h"
17 #include "tfm_memory_utils.h"
18 #include "ps_utils.h"
19 #include "tfm_ps_defs.h"
20 
21 /* FIXME: Duplicated from flash info */
22 #define PS_FLASH_DEFAULT_VAL 0xFFU
23 
29 #define PS_OBJECT_SYSTEM_VERSION 0x01
30 
37 #ifdef PS_ENCRYPTION
38  uint8_t tag[PS_TAG_LEN_BYTES];
39 #else
40  uint32_t version;
41 #endif
43  int32_t client_id;
44 };
45 
46 /* Specifies number of entries in the table. The number of entries is the
47  * number of assets, defined in asset_defs.h, plus one extra entry to store
48  * a new object when the code processes a change in a file.
49  */
50 #define PS_OBJ_TABLE_ENTRIES (PS_NUM_ASSETS + 1)
51 
58 #ifdef PS_ENCRYPTION
59  union ps_crypto_t crypto;
60 #endif
61 
62  uint8_t version;
64 #ifndef PS_ROLLBACK_PROTECTION
65  uint8_t swap_count;
68 #endif /* PS_ROLLBACK_PROTECTION */
69 
73 };
74 
75 /* Object table indexes */
76 #define PS_OBJ_TABLE_IDX_0 0
77 #define PS_OBJ_TABLE_IDX_1 1
78 
79 /* Number of object tables (active and scratch) */
80 #define PS_NUM_OBJ_TABLES 2
81 
93 #define PS_TABLE_FS_ID(idx) (idx + 1)
94 
105 #define PS_OBJECT_FS_ID(idx) ((idx + 1) + \
106  PS_TABLE_FS_ID(PS_OBJ_TABLE_IDX_1))
107 
117 #define PS_OBJECT_FS_ID_TO_IDX(fid) ((fid - 1) - \
118  PS_TABLE_FS_ID(PS_OBJ_TABLE_IDX_1))
119 
127  uint8_t active_table;
128  uint8_t scratch_table;
129 };
130 
131 /* Object table context */
132 static struct ps_obj_table_ctx_t ps_obj_table_ctx;
133 
134 /* Object table size */
135 #define PS_OBJ_TABLE_SIZE sizeof(struct ps_obj_table_t)
136 
137 /* Object table entry size */
138 #define PS_OBJECTS_TABLE_ENTRY_SIZE sizeof(struct ps_obj_table_entry_t)
139 
140 /* Size of the data that is not required to authenticate */
141 #define PS_NON_AUTH_OBJ_TABLE_SIZE sizeof(union ps_crypto_t)
142 
143 /* Start position to store the object table data in the FS object */
144 #define PS_OBJECT_TABLE_OBJECT_OFFSET 0
145 
146 /* The associated data is the header minus the crypto data */
147 #define PS_CRYPTO_ASSOCIATED_DATA(crypto) ((uint8_t *)crypto + \
148  PS_NON_AUTH_OBJ_TABLE_SIZE)
149 
150 #ifdef PS_ROLLBACK_PROTECTION
151 #define PS_OBJ_TABLE_AUTH_DATA_SIZE (PS_OBJ_TABLE_SIZE - \
152  PS_NON_AUTH_OBJ_TABLE_SIZE)
153 
154 struct ps_crypto_assoc_data_t {
155  uint8_t obj_table_data[PS_OBJ_TABLE_AUTH_DATA_SIZE];
156  uint32_t nv_counter;
157 };
158 
159 #define PS_CRYPTO_ASSOCIATED_DATA_LEN sizeof(struct ps_crypto_assoc_data_t)
160 
161 #else
162 
163 /* The associated data is the header, minus the the tag data */
164 #define PS_CRYPTO_ASSOCIATED_DATA_LEN (PS_OBJ_TABLE_SIZE - \
165  PS_NON_AUTH_OBJ_TABLE_SIZE)
166 #endif /* PS_ROLLBACK_PROTECTION */
167 
168 /* The ps_object_table_init function uses the static memory allocated for
169  * the object data manipulation, in ps_object_table.c (g_ps_object), to load a
170  * temporary object table to be validated at that stage.
171  * To make sure the object table data fits in the static memory allocated for
172  * object manipulation, the following macro checks if the memory allocated is
173  * big enough, at compile time
174  */
175 
176 /* Check at compilation time if metadata fits in g_ps_object.data */
178  PS_OBJ_TABLE_SIZE, PS_MAX_ASSET_SIZE);
179 
185 };
186 
187 /* Specifies that PS NV counter value is invalid */
188 #define PS_INVALID_NVC_VALUE 0
189 
205 #ifdef PS_ROLLBACK_PROTECTION
206  uint32_t nvc_1;
207  uint32_t nvc_3;
208 #endif /* PS_ROLLBACK_PROTECTION */
209 };
210 
217 __attribute__ ((always_inline))
218 __STATIC_INLINE void ps_object_table_fs_read_table(
219  struct ps_obj_table_init_ctx_t *init_ctx)
220 {
221  psa_status_t err;
222  size_t data_length;
223 
224  /* Read file with the table 0 data */
225 
229  (void *)init_ctx->p_table[PS_OBJ_TABLE_IDX_0],
230  &data_length);
231  if (err != PSA_SUCCESS) {
232  init_ctx->table_state[PS_OBJ_TABLE_IDX_0] = PS_OBJ_TABLE_INVALID;
233  }
234 
235  /* Read file with the table 1 data */
239  (void *)init_ctx->p_table[PS_OBJ_TABLE_IDX_1],
240  &data_length);
241  if (err != PSA_SUCCESS) {
242  init_ctx->table_state[PS_OBJ_TABLE_IDX_1] = PS_OBJ_TABLE_INVALID;
243  }
244 }
245 
254 __attribute__ ((always_inline))
256  struct ps_obj_table_t *obj_table)
257 {
258  psa_status_t err;
259  uint32_t obj_table_id = PS_TABLE_FS_ID(ps_obj_table_ctx.scratch_table);
260  uint8_t swap_table_idxs = ps_obj_table_ctx.scratch_table;
261 
262  /* Create file to store object table in the FS */
263  err = psa_its_set(obj_table_id,
265  (const void *)obj_table,
267 
268  if (err != PSA_SUCCESS) {
269  return err;
270  }
271 
272  /* Swap active and scratch table values */
273  ps_obj_table_ctx.scratch_table = ps_obj_table_ctx.active_table;
274  ps_obj_table_ctx.active_table = swap_table_idxs;
275 
276  return PSA_SUCCESS;
277 }
278 
279 #ifdef PS_ENCRYPTION
280 #ifdef PS_ROLLBACK_PROTECTION
281 
288 static psa_status_t ps_object_table_align_nv_counters(uint32_t nvc_1)
289 {
290  psa_status_t err;
291  uint32_t nvc_x_val = 0;
292 
293  /* Align PS NVC 2 with NVC 1 */
294  err = ps_read_nv_counter(TFM_PS_NV_COUNTER_2, &nvc_x_val);
295  if (err != PSA_SUCCESS) {
297  }
298 
299  for (; nvc_x_val < nvc_1; nvc_x_val++) {
301  if (err != PSA_SUCCESS) {
302  return err;
303  }
304  }
305 
306  /* Align PS NVC 3 with NVC 1 */
307  err = ps_read_nv_counter(TFM_PS_NV_COUNTER_3, &nvc_x_val);
308  if (err != PSA_SUCCESS) {
310  }
311 
312  for (; nvc_x_val < nvc_1; nvc_x_val++) {
314  if (err != PSA_SUCCESS) {
315  return err;
316  }
317  }
318 
319  return PSA_SUCCESS;
320 }
321 
331 __attribute__ ((always_inline))
332 __STATIC_INLINE psa_status_t ps_object_table_nvc_generate_auth_tag(
333  uint32_t nvc_1,
334  struct ps_obj_table_t *obj_table)
335 {
336  struct ps_crypto_assoc_data_t assoc_data;
337  union ps_crypto_t *crypto = &obj_table->crypto;
338 
339  /* Get new IV */
340  ps_crypto_get_iv(crypto);
341 
342  assoc_data.nv_counter = nvc_1;
343  (void)tfm_memcpy(assoc_data.obj_table_data,
345  PS_OBJ_TABLE_AUTH_DATA_SIZE);
346 
347  return ps_crypto_generate_auth_tag(crypto, (const uint8_t *)&assoc_data,
349 }
350 
358 static void ps_object_table_authenticate(uint8_t table_idx,
359  struct ps_obj_table_init_ctx_t *init_ctx)
360 {
361  struct ps_crypto_assoc_data_t assoc_data;
362  union ps_crypto_t *crypto = &init_ctx->p_table[table_idx]->crypto;
363  psa_status_t err;
364 
365  /* Init associated data with NVC 1 */
366  assoc_data.nv_counter = init_ctx->nvc_1;
367  (void)tfm_memcpy(assoc_data.obj_table_data,
369  PS_OBJ_TABLE_AUTH_DATA_SIZE);
370 
371  err = ps_crypto_authenticate(crypto, (const uint8_t *)&assoc_data,
373  if (err == PSA_SUCCESS) {
374  init_ctx->table_state[table_idx] = PS_OBJ_TABLE_NVC_1_VALID;
375  return;
376  }
377 
378  if (init_ctx->nvc_3 == PS_INVALID_NVC_VALUE) {
379  init_ctx->table_state[table_idx] = PS_OBJ_TABLE_INVALID;
380  return;
381  }
382 
383  /* Check with NVC 3 */
384  assoc_data.nv_counter = init_ctx->nvc_3;
385 
386  err = ps_crypto_authenticate(crypto, (const uint8_t *)&assoc_data,
388  if (err != PSA_SUCCESS) {
389  init_ctx->table_state[table_idx] = PS_OBJ_TABLE_INVALID;
390  } else {
391  init_ctx->table_state[table_idx] = PS_OBJ_TABLE_NVC_3_VALID;
392  }
393 }
394 
402 __attribute__ ((always_inline))
403 __STATIC_INLINE psa_status_t ps_object_table_nvc_authenticate(
404  struct ps_obj_table_init_ctx_t *init_ctx)
405 {
406  psa_status_t err;
407  uint32_t nvc_2;
408 
409  err = ps_read_nv_counter(TFM_PS_NV_COUNTER_1, &init_ctx->nvc_1);
410  if (err != PSA_SUCCESS) {
411  return err;
412  }
413 
415  if (err != PSA_SUCCESS) {
416  return err;
417  }
418 
419  err = ps_read_nv_counter(TFM_PS_NV_COUNTER_3, &init_ctx->nvc_3);
420  if (err != PSA_SUCCESS) {
421  return err;
422  }
423 
424  /* Check if NVC 3 value can be used to validate an object table */
425  if (init_ctx->nvc_3 != nvc_2) {
426  /* If NVC 3 is different from NVC 2, it is possible to load an old PS
427  * area image in the system by manipulating the FS to return a system
428  * error from the file system layer and triggering power fault before
429  * increasing the NVC 3. So, in that case, NVC 3 value cannot be used to
430  * validate an old object table at the init process.
431  */
432  init_ctx->nvc_3 = PS_INVALID_NVC_VALUE;
433  }
434 
435  /* Authenticate table 0 if data is valid */
436  if (init_ctx->table_state[PS_OBJ_TABLE_IDX_0] != PS_OBJ_TABLE_INVALID) {
437  ps_object_table_authenticate(PS_OBJ_TABLE_IDX_0, init_ctx);
438  }
439 
440  /* Authenticate table 1 if data is valid */
441  if (init_ctx->table_state[PS_OBJ_TABLE_IDX_1] != PS_OBJ_TABLE_INVALID) {
442  ps_object_table_authenticate(PS_OBJ_TABLE_IDX_1, init_ctx);
443  }
444 
445  return PSA_SUCCESS;
446 }
447 #else /* PS_ROLLBACK_PROTECTION */
448 
457 __attribute__ ((always_inline))
458 __STATIC_INLINE psa_status_t ps_object_table_generate_auth_tag(
459  struct ps_obj_table_t *obj_table)
460 {
461  union ps_crypto_t *crypto = &obj_table->crypto;
462 
463  /* Get new IV */
464  ps_crypto_get_iv(crypto);
465 
466  return ps_crypto_generate_auth_tag(crypto,
469 }
470 
477 __attribute__ ((always_inline))
478 __STATIC_INLINE void ps_object_table_authenticate_ctx_tables(
479  struct ps_obj_table_init_ctx_t *init_ctx)
480 {
481  psa_status_t err;
482  union ps_crypto_t *crypto =
483  &init_ctx->p_table[PS_OBJ_TABLE_IDX_0]->crypto;
484 
485  /* Authenticate table 0 if data is valid */
486  if (init_ctx->table_state[PS_OBJ_TABLE_IDX_0] != PS_OBJ_TABLE_INVALID) {
487  err = ps_crypto_authenticate(crypto,
490  if (err != PSA_SUCCESS) {
491  init_ctx->table_state[PS_OBJ_TABLE_IDX_0] = PS_OBJ_TABLE_INVALID;
492  }
493  }
494 
495  /* Authenticate table 1 if data is valid */
496  if (init_ctx->table_state[PS_OBJ_TABLE_IDX_1] != PS_OBJ_TABLE_INVALID) {
497  crypto = &init_ctx->p_table[PS_OBJ_TABLE_IDX_1]->crypto;
498 
499  err = ps_crypto_authenticate(crypto,
502  if (err != PSA_SUCCESS) {
503  init_ctx->table_state[PS_OBJ_TABLE_IDX_1] = PS_OBJ_TABLE_INVALID;
504  }
505  }
506 }
507 #endif /* PS_ROLLBACK_PROTECTION */
508 #endif /* PS_ENCRYPTION */
509 
517 static psa_status_t ps_object_table_save_table(
518  struct ps_obj_table_t *obj_table)
519 {
520  psa_status_t err;
521 
522 #ifdef PS_ROLLBACK_PROTECTION
523  uint32_t nvc_1 = 0;
524 
526  if (err != PSA_SUCCESS) {
527  return err;
528  }
529 
531  if (err != PSA_SUCCESS) {
532  return err;
533  }
534 #else
535  obj_table->swap_count++;
536 
537  if (obj_table->swap_count == PS_FLASH_DEFAULT_VAL) {
538  /* When a flash block is erased, the default value is usually 0xFF
539  * (i.e. all 1s). Since the swap count is updated last (when encryption
540  * is disabled), it is possible that due to a power failure, the swap
541  * count value in metadata header is 0xFFFF..., which mean it will
542  * appear to be most recent block.
543  */
544  obj_table->swap_count = 0;
545  }
546 #endif /* PS_ROLLBACK_PROTECTION */
547 
548 #ifdef PS_ENCRYPTION
549  /* Set object table key */
550  err = ps_crypto_setkey();
551  if (err != PSA_SUCCESS) {
552  return err;
553  }
554 
555 #ifdef PS_ROLLBACK_PROTECTION
556  /* Generate authentication tag from the current table content and PS
557  * NV counter 1.
558  */
559  err = ps_object_table_nvc_generate_auth_tag(nvc_1, obj_table);
560 #else
561  /* Generate authentication tag from the current table content */
562  err = ps_object_table_generate_auth_tag(obj_table);
563 #endif /* PS_ROLLBACK_PROTECTION */
564 
565  if (err != PSA_SUCCESS) {
566  (void)ps_crypto_destroykey();
567  return err;
568  }
569 
570  err = ps_crypto_destroykey();
571  if (err != PSA_SUCCESS) {
572  return err;
573  }
574 #endif /* PS_ENCRYPTION */
575 
576  err = ps_object_table_fs_write_table(obj_table);
577 
578 #ifdef PS_ROLLBACK_PROTECTION
579  if (err != PSA_SUCCESS) {
580  return err;
581  }
582 
583  /* Align PS NV counters to have the same value */
584  err = ps_object_table_align_nv_counters(nvc_1);
585 #endif /* PS_ROLLBACK_PROTECTION */
586 
587  return err;
588 }
589 
596 __attribute__ ((always_inline))
597 __STATIC_INLINE void ps_object_table_validate_version(
598  struct ps_obj_table_init_ctx_t *init_ctx)
599 {
600  /* Looks for exact version number.
601  * FIXME: backward compatibility could be considered in future revisions.
602  */
604  init_ctx->p_table[PS_OBJ_TABLE_IDX_0]->version) {
605  init_ctx->table_state[PS_OBJ_TABLE_IDX_0] = PS_OBJ_TABLE_INVALID;
606  }
607 
609  init_ctx->p_table[PS_OBJ_TABLE_IDX_1]->version) {
610  init_ctx->table_state[PS_OBJ_TABLE_IDX_1] = PS_OBJ_TABLE_INVALID;
611  }
612 }
613 
622 static psa_status_t ps_set_active_object_table(
623  const struct ps_obj_table_init_ctx_t *init_ctx)
624 {
625 #ifndef PS_ROLLBACK_PROTECTION
626  uint8_t table0_swap_count =
628  uint8_t table1_swap_count =
630 #endif
631 
632  /* Check if there is an invalid object table */
634  && (init_ctx->table_state[PS_OBJ_TABLE_IDX_1] ==
636  /* Both tables are invalid */
638  } else if (init_ctx->table_state[PS_OBJ_TABLE_IDX_0] ==
640  /* Table 0 is invalid, the active one is table 1 */
641  ps_obj_table_ctx.active_table = PS_OBJ_TABLE_IDX_1;
642  ps_obj_table_ctx.scratch_table = PS_OBJ_TABLE_IDX_0;
643 
644  /* As table 1 is the active object, load the content into the
645  * PS object table context.
646  */
647  (void)tfm_memcpy(&ps_obj_table_ctx.obj_table,
648  init_ctx->p_table[PS_OBJ_TABLE_IDX_1],
650 
651  return PSA_SUCCESS;
652  } else if (init_ctx->table_state[PS_OBJ_TABLE_IDX_1] ==
654  /* Table 1 is invalid, the active one is table 0 */
655  ps_obj_table_ctx.active_table = PS_OBJ_TABLE_IDX_0;
656  ps_obj_table_ctx.scratch_table = PS_OBJ_TABLE_IDX_1;
657 
658  /* As table 0 is already in the PS object table context, it is not
659  * needed to copy the table in the context.
660  */
661 
662  return PSA_SUCCESS;
663  }
664 
665 #ifdef PS_ROLLBACK_PROTECTION
666  if (init_ctx->table_state[PS_OBJ_TABLE_IDX_1] ==
668  /* Table 0 is invalid, the active one is table 1 */
669  ps_obj_table_ctx.active_table = PS_OBJ_TABLE_IDX_1;
670  ps_obj_table_ctx.scratch_table = PS_OBJ_TABLE_IDX_0;
671  } else {
672  /* In case both tables are valid or table 0 is valid, table 0 is the
673  * valid on as it is already in the PS object table context.
674  */
675  ps_obj_table_ctx.active_table = PS_OBJ_TABLE_IDX_0;
676  ps_obj_table_ctx.scratch_table = PS_OBJ_TABLE_IDX_1;
677  }
678 #else
679  /* Logic: if the swap count is 0, then it has rolled over. The object table
680  * with a swap count of 0 is the latest one, unless the other block has a
681  * swap count of 1, in which case the roll over occurred in the previous
682  * update. In all other cases, the table with the highest swap count is the
683  * latest one.
684  */
685  if ((table1_swap_count == 0) && (table0_swap_count != 1)) {
686  /* Table 1 swap count has rolled over and table 0 swap count has not,
687  * so table 1 is the latest.
688  */
689  ps_obj_table_ctx.active_table = PS_OBJ_TABLE_IDX_1;
690  ps_obj_table_ctx.scratch_table = PS_OBJ_TABLE_IDX_0;
691 
692  } else if ((table0_swap_count == 0) && (table1_swap_count != 1)) {
693  /* Table 0 swap count has rolled over and table 1 swap count has not,
694  * so table 0 is the latest.
695  */
696  ps_obj_table_ctx.active_table = PS_OBJ_TABLE_IDX_0;
697  ps_obj_table_ctx.scratch_table = PS_OBJ_TABLE_IDX_1;
698 
699  } else if (table1_swap_count > table0_swap_count) {
700  /* Neither swap count has just rolled over and table 1 has a
701  * higher swap count, so table 1 is the latest.
702  */
703  ps_obj_table_ctx.active_table = PS_OBJ_TABLE_IDX_1;
704  ps_obj_table_ctx.scratch_table = PS_OBJ_TABLE_IDX_0;
705 
706  } else {
707  /* Neither swap count has just rolled over and table 0 has a
708  * higher or equal swap count, so table 0 is the latest.
709  */
710  ps_obj_table_ctx.active_table = PS_OBJ_TABLE_IDX_0;
711  ps_obj_table_ctx.scratch_table = PS_OBJ_TABLE_IDX_1;
712  }
713 #endif /* PS_ROLLBACK_PROTECTION */
714 
715  /* If active object table is table 1, then copy the content into the
716  * PS object table context.
717  */
718  if (ps_obj_table_ctx.active_table == PS_OBJ_TABLE_IDX_1) {
719  (void)tfm_memcpy(&ps_obj_table_ctx.obj_table,
720  init_ctx->p_table[PS_OBJ_TABLE_IDX_1],
722  }
723 
724  return PSA_SUCCESS;
725 }
726 
737 static psa_status_t ps_get_object_entry_idx(psa_storage_uid_t uid,
738  int32_t client_id,
739  uint32_t *idx)
740 {
741  uint32_t i;
742  struct ps_obj_table_t *p_table = &ps_obj_table_ctx.obj_table;
743 
744  for (i = 0; i < PS_OBJ_TABLE_ENTRIES; i++) {
745  if (p_table->obj_db[i].uid == uid
746  && p_table->obj_db[i].client_id == client_id) {
747  *idx = i;
748  return PSA_SUCCESS;
749  }
750  }
751 
753 }
754 
769 __attribute__ ((always_inline))
770 __STATIC_INLINE psa_status_t ps_table_free_idx(uint32_t idx_num,
771  uint32_t *idx)
772 {
773  uint32_t i;
774  uint32_t last_free = 0;
775  struct ps_obj_table_t *p_table = &ps_obj_table_ctx.obj_table;
776 
777  if (idx_num == 0) {
779  }
780 
781  for (i = 0; i < PS_OBJ_TABLE_ENTRIES && idx_num > 0; i++) {
782  if (p_table->obj_db[i].uid == TFM_PS_INVALID_UID) {
783  last_free = i;
784  idx_num--;
785  }
786  }
787 
788  if (idx_num != 0) {
790  } else {
791  *idx = last_free;
792  return PSA_SUCCESS;
793  }
794 }
795 
802 static void ps_table_delete_entry(uint32_t idx)
803 {
804  /* Initialise object table entry structure */
805  (void)tfm_memset(&ps_obj_table_ctx.obj_table.obj_db[idx],
807 }
808 
810 {
811  struct ps_obj_table_t *p_table = &ps_obj_table_ctx.obj_table;
812 
813  /* Initialize object structure */
814  (void)tfm_memset(&ps_obj_table_ctx, PS_DEFAULT_EMPTY_BUFF_VAL,
815  sizeof(struct ps_obj_table_ctx_t));
816 
817  /* Invert the other in the context as ps_object_table_save_table will
818  * use the scratch index to create and store the current table.
819  */
820  ps_obj_table_ctx.active_table = PS_OBJ_TABLE_IDX_1;
821  ps_obj_table_ctx.scratch_table = PS_OBJ_TABLE_IDX_0;
822 
824 
825  /* Save object table contents */
826  return ps_object_table_save_table(p_table);
827 }
828 
830 {
831  psa_status_t err;
832  struct ps_obj_table_init_ctx_t init_ctx = {
833  .p_table = {&ps_obj_table_ctx.obj_table, NULL},
834  .table_state = {PS_OBJ_TABLE_VALID, PS_OBJ_TABLE_VALID},
835 #ifdef PS_ROLLBACK_PROTECTION
836  .nvc_1 = 0U,
837  .nvc_3 = 0U,
838 #endif /* PS_ROLLBACK_PROTECTION */
839  };
840 
841  init_ctx.p_table[PS_OBJ_TABLE_IDX_1] = (struct ps_obj_table_t *)obj_data;
842 
843  /* Read table from the file system */
845 
846 #ifdef PS_ENCRYPTION
847  /* Set object table key */
848  err = ps_crypto_setkey();
849  if (err != PSA_SUCCESS) {
850  return err;
851  }
852 
853 #ifdef PS_ROLLBACK_PROTECTION
854  /* Authenticate table */
855  err = ps_object_table_nvc_authenticate(&init_ctx);
856  if (err != PSA_SUCCESS) {
857  (void)ps_crypto_destroykey();
858  return err;
859  }
860 #else
861  ps_object_table_authenticate_ctx_tables(&init_ctx);
862 #endif /* PS_ROLLBACK_PROTECTION */
863 
864  err = ps_crypto_destroykey();
865  if (err != PSA_SUCCESS) {
866  return err;
867  }
868 #endif /* PS_ENCRYPTION */
869 
870  /* Check tables version */
872 
873  /* Set active tables */
874  err = ps_set_active_object_table(&init_ctx);
875  if (err != PSA_SUCCESS) {
876  return err;
877  }
878 
879  /* Remove the old object table file */
880  err = psa_its_remove(PS_TABLE_FS_ID(ps_obj_table_ctx.scratch_table));
881  if (err != PSA_SUCCESS && err != PSA_ERROR_DOES_NOT_EXIST) {
882  return err;
883  }
884 
885 #ifdef PS_ROLLBACK_PROTECTION
886  /* Align PS NV counters */
887  err = ps_object_table_align_nv_counters(init_ctx.nvc_1);
888  if (err != PSA_SUCCESS) {
889  return err;
890  }
891 #endif /* PS_ROLLBACK_PROTECTION */
892 
893 #ifdef PS_ENCRYPTION
894  ps_crypto_set_iv(&ps_obj_table_ctx.obj_table.crypto);
895 #endif
896 
897  return PSA_SUCCESS;
898 }
899 
901  int32_t client_id)
902 {
903  uint32_t idx = 0;
904 
905  return ps_get_object_entry_idx(uid, client_id, &idx);
906 }
907 
909  uint32_t *p_fid)
910 {
911  psa_status_t err;
912  uint32_t fid;
913  uint32_t idx;
914 
915  err = ps_table_free_idx(fid_num, &idx);
916  if (err != PSA_SUCCESS) {
917  return err;
918  }
919 
920  /* There first two file IDs are reserved for the active table
921  * and scratch table files.
922  */
923  fid = PS_OBJECT_FS_ID(idx);
924 
925  /* If there is a file in the persistent area with that ID then remove it.
926  * That can happen when the system is rebooted (e.g. power cut, ...) in the
927  * middle of a create, write or delete operation.
928  */
929  err = psa_its_remove(fid);
930  if (err != PSA_SUCCESS && err != PSA_ERROR_DOES_NOT_EXIST) {
931  return err;
932  }
933 
934  *p_fid = fid;
935 
936  return PSA_SUCCESS;
937 }
938 
940  int32_t client_id,
941  const struct ps_obj_table_info_t *obj_tbl_info)
942 {
943  psa_status_t err;
944  uint32_t idx = 0;
945  uint32_t backup_idx = 0;
946  struct ps_obj_table_entry_t backup_entry = {
947 #ifdef PS_ENCRYPTION
948  .tag = {0U},
949 #else
950  .version = 0U,
951 #endif /* PS_ENCRYPTION */
952  .uid = TFM_PS_INVALID_UID,
953  .client_id = 0,
954  };
955  struct ps_obj_table_t *p_table = &ps_obj_table_ctx.obj_table;
956 
957  err = ps_get_object_entry_idx(uid, client_id, &backup_idx);
958  if (err == PSA_SUCCESS) {
959  /* If an entry exists for this UID, it creates a backup copy in case
960  * an error happens while updating the new table in the filesystem.
961  */
962  (void)tfm_memcpy(&backup_entry, &p_table->obj_db[backup_idx],
964 
965  /* Deletes old object information if it exist in the table */
966  ps_table_delete_entry(backup_idx);
967  }
968 
969  idx = PS_OBJECT_FS_ID_TO_IDX(obj_tbl_info->fid);
970  p_table->obj_db[idx].uid = uid;
971  p_table->obj_db[idx].client_id = client_id;
972 
973  /* Add new object information */
974 #ifdef PS_ENCRYPTION
975  (void)tfm_memcpy(p_table->obj_db[idx].tag, obj_tbl_info->tag,
977 #else
978  p_table->obj_db[idx].version = obj_tbl_info->version;
979 #endif
980 
981  err = ps_object_table_save_table(p_table);
982  if (err != PSA_SUCCESS) {
983  if (backup_entry.uid != TFM_PS_INVALID_UID) {
984  /* Rollback the change in the table */
985  (void)tfm_memcpy(&p_table->obj_db[backup_idx], &backup_entry,
987  }
988 
989  ps_table_delete_entry(idx);
990  }
991 
992  return err;
993 }
994 
996  int32_t client_id,
997  struct ps_obj_table_info_t *obj_tbl_info)
998 {
999  psa_status_t err;
1000  uint32_t idx;
1001  struct ps_obj_table_t *p_table = &ps_obj_table_ctx.obj_table;
1002 
1003  err = ps_get_object_entry_idx(uid, client_id, &idx);
1004  if (err != PSA_SUCCESS) {
1005  return err;
1006  }
1007 
1008  obj_tbl_info->fid = PS_OBJECT_FS_ID(idx);
1009 
1010 #ifdef PS_ENCRYPTION
1011  (void)tfm_memcpy(obj_tbl_info->tag, p_table->obj_db[idx].tag,
1013 #else
1014  obj_tbl_info->version = p_table->obj_db[idx].version;
1015 #endif
1016 
1017  return PSA_SUCCESS;
1018 }
1019 
1021  int32_t client_id)
1022 {
1023  uint32_t backup_idx = 0;
1024  struct ps_obj_table_entry_t backup_entry;
1025  psa_status_t err;
1026  struct ps_obj_table_t *p_table = &ps_obj_table_ctx.obj_table;
1027 
1028  /* Create a backup copy in case an error happens while updating the new
1029  * table in the filesystem.
1030  */
1031  err = ps_get_object_entry_idx(uid, client_id, &backup_idx);
1032  if (err != PSA_SUCCESS) {
1033  /* If the object is not present in the table, it returns an error
1034  * to not generate a new file where the table content is the same.
1035  * Otherwise, that could be used by an attacker to get the encryption
1036  * key.
1037  */
1038  return err;
1039  }
1040 
1041  (void)tfm_memcpy(&backup_entry, &p_table->obj_db[backup_idx],
1043 
1044  ps_table_delete_entry(backup_idx);
1045 
1046  err = ps_object_table_save_table(p_table);
1047  if (err != PSA_SUCCESS) {
1048  /* Rollback the change in the table */
1049  (void)tfm_memcpy(&p_table->obj_db[backup_idx], &backup_entry,
1051  }
1052 
1053  return err;
1054 }
1055 
1057 {
1058  uint32_t table_id = PS_TABLE_FS_ID(ps_obj_table_ctx.scratch_table);
1059 
1060  return psa_its_remove(table_id);
1061 }
#define PS_OBJ_TABLE_IDX_0
void ps_crypto_set_iv(const union ps_crypto_t *crypto)
Provides current IV value to crypto layer.
#define PS_OBJ_TABLE_SIZE
enum ps_obj_table_state table_state[2]
psa_status_t ps_increment_nv_counter(enum tfm_nv_counter_t counter_id)
Increments the given non-volatile (NV) counter.
psa_status_t ps_object_table_init(uint8_t *obj_data)
Initializes object table.
__STATIC_INLINE void * tfm_memset(void *ptr, int value, size_t num)
#define PSA_SUCCESS
Definition: crypto_values.h:35
__STATIC_INLINE void ps_object_table_validate_version(struct ps_obj_table_init_ctx_t *init_ctx)
Checks the validity of the table version.
#define PS_TAG_LEN_BYTES
#define PS_CRYPTO_ASSOCIATED_DATA(crypto)
struct ps_obj_table_t obj_table
psa_status_t ps_crypto_setkey(void)
Sets the key to use for crypto operations for the current client.
struct ps_obj_table_entry_t obj_db[(PS_NUM_ASSETS+1)]
#define PS_FLASH_DEFAULT_VAL
#define PS_TABLE_FS_ID(idx)
File ID to be used in order to store the object table in the file system.
#define PS_OBJ_TABLE_ENTRIES
psa_status_t psa_its_get(psa_storage_uid_t uid, size_t data_offset, size_t data_size, void *p_data, size_t *p_data_length)
Retrieve data associated with a provided UID.
psa_status_t psa_its_remove(psa_storage_uid_t uid)
Remove the provided uid and its associated data from the storage.
psa_storage_uid_t uid
psa_status_t ps_object_table_delete_object(psa_storage_uid_t uid, int32_t client_id)
Deletes the table entry for the provided UID and client ID pair.
#define PSA_ERROR_INSUFFICIENT_STORAGE
#define PS_CRYPTO_ASSOCIATED_DATA_LEN
#define PS_NUM_OBJ_TABLES
psa_status_t ps_read_nv_counter(enum tfm_nv_counter_t counter_id, uint32_t *val)
Reads the given non-volatile (NV) counter.
#define TFM_PS_NV_COUNTER_1
psa_status_t ps_object_table_delete_old_table(void)
Deletes old object table from the persistent area.
int32_t client_id
#define PSA_ERROR_GENERIC_ERROR
Definition: crypto_values.h:43
#define PSA_ERROR_INVALID_ARGUMENT
psa_status_t psa_its_set(psa_storage_uid_t uid, size_t data_length, const void *p_data, psa_storage_create_flags_t create_flags)
Create a new, or modify an existing, uid/value pair.
__STATIC_INLINE void ps_object_table_fs_read_table(struct ps_obj_table_init_ctx_t *init_ctx)
Reads object table from persistent memory.
#define TFM_PS_NV_COUNTER_3
#define PS_OBJECT_TABLE_OBJECT_OFFSET
Object table structure.
#define PS_INVALID_NVC_VALUE
psa_status_t ps_crypto_generate_auth_tag(union ps_crypto_t *crypto, const uint8_t *add, uint32_t add_len)
Generates authentication tag for given data.
__STATIC_INLINE psa_status_t ps_object_table_fs_write_table(struct ps_obj_table_t *obj_table)
Writes object table in persistent memory.
Object table context structure.
char OBJ_TABLE_NOT_FIT_IN_STATIC_OBJ_DATA_BUF[(sizeof(struct ps_obj_table_t)<=PS_MAX_ASSET_SIZE)*2-1]
uint32_t version
psa_status_t ps_object_table_obj_exist(psa_storage_uid_t uid, int32_t client_id)
Checks if there is an entry in the table for the provided UID and client ID pair. ...
psa_status_t ps_crypto_authenticate(const union ps_crypto_t *crypto, const uint8_t *add, uint32_t add_len)
Authenticate given data against the tag.
psa_status_t ps_object_table_get_obj_tbl_info(psa_storage_uid_t uid, int32_t client_id, struct ps_obj_table_info_t *obj_tbl_info)
Gets object table information from the object table for the provided UID and client ID pair...
#define PS_OBJ_TABLE_IDX_1
struct ps_obj_table_t * p_table[2]
#define PS_UTILS_BOUND_CHECK(err_msg, data_size, data_buf_size)
Macro to check, at compilation time, if data fits in data buffer.
Definition: ps_utils.h:35
__STATIC_INLINE void * tfm_memcpy(void *dest, const void *src, size_t num)
psa_status_t ps_object_table_get_free_fid(uint32_t fid_num, uint32_t *p_fid)
Gets a not in use file ID.
uint64_t psa_storage_uid_t
psa_status_t ps_crypto_destroykey(void)
Destroys the transient key used for crypto operations.
#define PS_OBJECT_FS_ID_TO_IDX(fid)
Gets object index in the table based on the file ID.
#define PS_OBJECT_SYSTEM_VERSION
Current object system version.
void ps_crypto_get_iv(union ps_crypto_t *crypto)
Gets a new IV value into the crypto union.
#define TFM_PS_INVALID_UID
Definition: tfm_ps_defs.h:16
#define TFM_PS_NV_COUNTER_2
#define PSA_STORAGE_FLAG_NONE
__STATIC_INLINE psa_status_t ps_table_free_idx(uint32_t idx_num, uint32_t *idx)
Gets free index in the table.
#define PSA_ERROR_DOES_NOT_EXIST
Definition: crypto_values.h:89
psa_status_t ps_object_table_create(void)
Creates object table.
int32_t psa_status_t
Function return status.
Definition: crypto_types.h:43
#define PS_OBJECT_FS_ID(idx)
File ID to be used in order to store an object in the file system.
psa_status_t ps_object_table_set_obj_tbl_info(psa_storage_uid_t uid, int32_t client_id, const struct ps_obj_table_info_t *obj_tbl_info)
Sets object table information in the object table and stores it persistently, for the provided UID an...
#define PS_OBJECTS_TABLE_ENTRY_SIZE
ps_obj_table_state
Object table information structure.
#define PS_DEFAULT_EMPTY_BUFF_VAL
Definition: ps_utils.h:21