1 /*
2 * Copyright (c) 2018-2023, Arm Limited. All rights reserved.
3 * Copyright (c) 2020, Cypress Semiconductor Corporation. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 */
8
9
10 #include <stdbool.h>
11 #include <string.h>
12
13 #include "config_tfm.h"
14 #include "its_flash_fs.h"
15 #include "its_flash_fs_dblock.h"
16 #include "its_utils.h"
17
18 /* Filesystem-internal flags, which cannot be passed by the caller */
19 #define ITS_FLASH_FS_INTERNAL_FLAGS_MASK (UINT32_MAX - ((1U << 24) - 1))
20 /* Flag that indicates the file is to be deleted in the next block update */
21 #define ITS_FLASH_FS_FLAG_DELETE (1U << 24)
22
23 static psa_status_t its_flash_fs_delete_idx(struct its_flash_fs_ctx_t *fs_ctx,
24 uint32_t del_file_idx);
25
its_flash_fs_file_write_aligned_data(struct its_flash_fs_ctx_t * fs_ctx,const struct its_block_meta_t * block_meta,const struct its_file_meta_t * file_meta,size_t offset,size_t size,const uint8_t * data)26 static psa_status_t its_flash_fs_file_write_aligned_data(
27 struct its_flash_fs_ctx_t *fs_ctx,
28 const struct its_block_meta_t *block_meta,
29 const struct its_file_meta_t *file_meta,
30 size_t offset,
31 size_t size,
32 const uint8_t *data)
33 {
34 #if (ITS_FLASH_MAX_ALIGNMENT != 1)
35 /* Check that the offset is aligned with the flash program unit */
36 if (!ITS_UTILS_IS_ALIGNED(offset, fs_ctx->cfg->program_unit)) {
37 return PSA_ERROR_INVALID_ARGUMENT;
38 }
39
40 /* Set the size to be aligned with the flash program unit */
41 size = ITS_UTILS_ALIGN(size, fs_ctx->cfg->program_unit);
42 #endif
43
44 /* It is not permitted to create gaps in the file */
45 if (offset > file_meta->cur_size) {
46 return PSA_ERROR_INVALID_ARGUMENT;
47 }
48
49 /* Check that the new data is contained within the file's max size */
50 if (its_utils_check_contained_in(file_meta->max_size, offset, size)
51 != PSA_SUCCESS) {
52 return PSA_ERROR_INVALID_ARGUMENT;
53 }
54
55 return its_flash_fs_dblock_write_file(fs_ctx, block_meta, file_meta, offset,
56 size, data);
57 }
58
59 /* TODO This is very similar to (static) its_num_active_dblocks() */
its_flash_fs_num_active_dblocks(const struct its_flash_fs_config_t * cfg)60 static uint32_t its_flash_fs_num_active_dblocks(
61 const struct its_flash_fs_config_t *cfg)
62 {
63 /* Total number of datablocks is the number of dedicated datablocks plus
64 * logical datablock 0 stored in the metadata block.
65 */
66 if (cfg->num_blocks == 2) {
67 /* Metadata and data are stored in the same physical block, and the
68 * other block is required for power failure safe operation.
69 */
70 /* There are no dedicated data blocks when only two blocks are available
71 */
72 return 1;
73 } else {
74 /* One metadata block and two scratch blocks are reserved. One scratch
75 * block for metadata operations and the other for file data operations.
76 */
77 return cfg->num_blocks - 2;
78 }
79 }
80
its_flash_fs_all_metadata_size(const struct its_flash_fs_config_t * cfg)81 static size_t its_flash_fs_all_metadata_size(
82 const struct its_flash_fs_config_t *cfg)
83 {
84 return sizeof(struct its_metadata_block_header_t)
85 + (its_flash_fs_num_active_dblocks(cfg)
86 * sizeof(struct its_block_meta_t))
87 + (cfg->max_num_files * sizeof(struct its_file_meta_t));
88 }
89
90 /**
91 * \brief Validates the configuration of the flash filesystem.
92 *
93 * This function checks that the flash block provided is compatible with the
94 * flash_fs described by the cfg parameter.
95 *
96 * \param[in] cfg Filesystem config
97 *
98 * \return Returns error code as specified in \ref psa_status_t
99 */
its_flash_fs_validate_config(const struct its_flash_fs_config_t * cfg)100 static psa_status_t its_flash_fs_validate_config(
101 const struct its_flash_fs_config_t *cfg)
102 {
103 psa_status_t ret = PSA_SUCCESS;
104
105 /* The minimum number of blocks is 2. In this case, metadata and data are
106 * stored in the same physical block, and the other block is required for
107 * power failure safe operation.
108 * If at least 1 data block is available, 1 data scratch block is required
109 * for power failure safe operation. So, in this case, the minimum number of
110 * blocks is 4 (2 metadata block + 2 data blocks).
111 */
112 if ((cfg->num_blocks < 2) || (cfg->num_blocks == 3)) {
113 ret = PSA_ERROR_INVALID_ARGUMENT;
114 }
115
116 if (cfg->num_blocks == 2) {
117 /* Metadata and data are stored in the same physical block */
118 if (cfg->max_file_size >
119 cfg->block_size - its_flash_fs_all_metadata_size(cfg)) {
120 ret = PSA_ERROR_INVALID_ARGUMENT;
121 }
122 }
123
124 /* It is not required that all files fit in ITS flash area at the same time.
125 * So, it is possible that a create action fails because flash is full.
126 * However, the larger file must have enough space in the ITS flash area to
127 * be created, at least, when the ITS flash area is empty.
128 */
129 if (cfg->max_file_size > cfg->block_size) {
130 ret = PSA_ERROR_INVALID_ARGUMENT;
131 }
132
133 /* Metadata must fit in a flash block */
134 if (its_flash_fs_all_metadata_size(cfg) > cfg->block_size) {
135 ret = PSA_ERROR_INVALID_ARGUMENT;
136 }
137
138 return ret;
139 }
140
its_flash_fs_init_ctx(its_flash_fs_ctx_t * fs_ctx,const struct its_flash_fs_config_t * fs_cfg,const struct its_flash_fs_ops_t * fs_ops)141 psa_status_t its_flash_fs_init_ctx(its_flash_fs_ctx_t *fs_ctx,
142 const struct its_flash_fs_config_t *fs_cfg,
143 const struct its_flash_fs_ops_t *fs_ops)
144 {
145 psa_status_t err;
146
147 if (!fs_ctx || !fs_cfg || !fs_ops) {
148 return PSA_ERROR_INVALID_ARGUMENT;
149 }
150
151 /* Check for valid filesystem configuration */
152 err = its_flash_fs_validate_config(fs_cfg);
153 if (err != PSA_SUCCESS) {
154 return err;
155 }
156
157 /* Zero the context */
158 memset(fs_ctx, 0, sizeof(*fs_ctx));
159
160 /* Associate the filesystem config and operations with the context */
161 fs_ctx->cfg = fs_cfg;
162 fs_ctx->ops = fs_ops;
163
164 return PSA_SUCCESS;
165 }
166
its_flash_fs_prepare(its_flash_fs_ctx_t * fs_ctx)167 psa_status_t its_flash_fs_prepare(its_flash_fs_ctx_t *fs_ctx)
168 {
169 psa_status_t err;
170 uint32_t idx;
171
172 /* Initialize metadata block with the valid/active metablock */
173 err = its_flash_fs_mblock_init(fs_ctx);
174 if (err != PSA_SUCCESS) {
175 return err;
176 }
177
178 /* Check if a file marked for deletion has been left behind by a power
179 * failure. If so, delete it.
180 */
181 err = its_flash_fs_mblock_get_file_idx_flag(fs_ctx,
182 ITS_FLASH_FS_FLAG_DELETE, &idx);
183 if (err == PSA_SUCCESS) {
184 return its_flash_fs_delete_idx(fs_ctx, idx);
185 } else if (err != PSA_ERROR_DOES_NOT_EXIST) {
186 return err;
187 }
188
189 return PSA_SUCCESS;
190 }
191
its_flash_fs_wipe_all(struct its_flash_fs_ctx_t * fs_ctx)192 psa_status_t its_flash_fs_wipe_all(struct its_flash_fs_ctx_t *fs_ctx)
193 {
194 /* Clean and initialize the metadata block */
195 return its_flash_fs_mblock_reset_metablock(fs_ctx);
196 }
197
its_flash_fs_file_get_info(struct its_flash_fs_ctx_t * fs_ctx,const uint8_t * fid,struct its_flash_fs_file_info_t * info)198 psa_status_t its_flash_fs_file_get_info(struct its_flash_fs_ctx_t *fs_ctx,
199 const uint8_t *fid,
200 struct its_flash_fs_file_info_t *info)
201 {
202 psa_status_t err;
203 uint32_t idx;
204 struct its_file_meta_t tmp_metadata;
205
206 /* Get the meta data index and meta data */
207 err = its_flash_fs_mblock_get_file_idx_meta(fs_ctx, fid, &idx, &tmp_metadata);
208 if (err != PSA_SUCCESS) {
209 return PSA_ERROR_DOES_NOT_EXIST;
210 }
211 info->size_max = tmp_metadata.max_size;
212 info->size_current = tmp_metadata.cur_size;
213 info->flags = tmp_metadata.flags & ITS_FLASH_FS_USER_FLAGS_MASK;
214
215 #ifdef ITS_ENCRYPTION
216 memcpy(info->nonce, tmp_metadata.nonce, TFM_ITS_ENC_NONCE_LENGTH);
217 memcpy(info->tag, tmp_metadata.tag, TFM_ITS_AUTH_TAG_LENGTH);
218 #endif
219
220 return PSA_SUCCESS;
221 }
222
its_flash_fs_file_write(struct its_flash_fs_ctx_t * fs_ctx,const uint8_t * fid,struct its_flash_fs_file_info_t * finfo,size_t data_size,size_t offset,const uint8_t * data)223 psa_status_t its_flash_fs_file_write(struct its_flash_fs_ctx_t *fs_ctx,
224 const uint8_t *fid,
225 struct its_flash_fs_file_info_t *finfo,
226 size_t data_size,
227 size_t offset,
228 const uint8_t *data)
229 {
230 struct its_block_meta_t block_meta;
231 struct its_file_meta_t file_meta = {0};
232 uint32_t cur_phys_block;
233 psa_status_t err;
234 uint32_t idx;
235 uint32_t old_idx = ITS_METADATA_INVALID_INDEX;
236 uint32_t new_idx = ITS_METADATA_INVALID_INDEX;
237 bool use_spare;
238
239 if (finfo == NULL) {
240 return PSA_ERROR_INVALID_ARGUMENT;
241 }
242
243 /* Do not permit the user to pass filesystem-internal flags */
244 if (finfo->flags & ITS_FLASH_FS_INTERNAL_FLAGS_MASK) {
245 return PSA_ERROR_INVALID_ARGUMENT;
246 }
247
248 #if (ITS_FLASH_MAX_ALIGNMENT != 1)
249 /* Set the max_size to be aligned with the flash program unit */
250 finfo->size_max = ITS_UTILS_ALIGN(finfo->size_max, fs_ctx->cfg->program_unit);
251 #endif
252
253 /* Check if the file already exists */
254 err = its_flash_fs_mblock_get_file_idx_meta(fs_ctx, fid, &old_idx, &file_meta);
255 if (err == PSA_SUCCESS) {
256 if (finfo->flags & ITS_FLASH_FS_FLAG_TRUNCATE) {
257 if (file_meta.max_size == finfo->size_max) {
258 /* Truncate and reuse the existing file, which is already the
259 * correct size.
260 */
261 file_meta.cur_size = 0;
262 file_meta.flags = finfo->flags;
263 new_idx = old_idx;
264 } else {
265 /* Mark the existing file to be deleted in this block update. It
266 * will be deleted in a second block update, and if there is a
267 * power failure before that block update completes, then
268 * deletion will be re-attempted based on this flag.
269 */
270 file_meta.flags |= ITS_FLASH_FS_FLAG_DELETE;
271 err = its_flash_fs_mblock_update_scratch_file_meta(fs_ctx,
272 old_idx,
273 &file_meta);
274 if (err != PSA_SUCCESS) {
275 return PSA_ERROR_GENERIC_ERROR;
276 }
277 }
278 } else {
279 /* Write to existing file */
280 new_idx = old_idx;
281 }
282 } else if (err == PSA_ERROR_DOES_NOT_EXIST) {
283 /* The create flag must be supplied to create a new file */
284 if (!(finfo->flags & ITS_FLASH_FS_FLAG_CREATE)) {
285 return PSA_ERROR_DOES_NOT_EXIST;
286 }
287 } else {
288 return err;
289 }
290
291 /* If the existing file was not reused, then a new one must be reserved */
292 if (new_idx == ITS_METADATA_INVALID_INDEX) {
293 /* Check that the file's maximum size is valid */
294 if (finfo->size_max > fs_ctx->cfg->max_file_size) {
295 return PSA_ERROR_INVALID_ARGUMENT;
296 }
297
298 /* Only use the spare file if there is an old file to be deleted */
299 use_spare = (old_idx != ITS_METADATA_INVALID_INDEX);
300
301 /* Try to reserve a new file based on the input parameters */
302 err = its_flash_fs_mblock_reserve_file(fs_ctx, fid, use_spare,
303 finfo->size_max, finfo->flags, &new_idx,
304 &file_meta, &block_meta);
305 if (err != PSA_SUCCESS) {
306 return err;
307 }
308 } else {
309 /* Read existing block metadata */
310 err = its_flash_fs_mblock_read_block_metadata(fs_ctx, file_meta.lblock,
311 &block_meta);
312 if (err != PSA_SUCCESS) {
313 return PSA_ERROR_GENERIC_ERROR;
314 }
315 }
316
317 if (data_size != 0) {
318 /* Write the content into scratch data block */
319 err = its_flash_fs_file_write_aligned_data(fs_ctx, &block_meta,
320 &file_meta, offset,
321 data_size, data);
322 if (err != PSA_SUCCESS) {
323 return PSA_ERROR_GENERIC_ERROR;
324 }
325
326 /* Update the file's current size if required */
327 if (offset + data_size > file_meta.cur_size) {
328 /* Update the file metadata */
329 file_meta.cur_size = offset + data_size;
330 }
331
332 cur_phys_block = block_meta.phy_id;
333
334 /* Cur scratch block become the active datablock */
335 block_meta.phy_id =
336 its_flash_fs_mblock_cur_data_scratch_id(fs_ctx, file_meta.lblock);
337
338 /* Swap the scratch data block */
339 its_flash_fs_mblock_set_data_scratch(fs_ctx, cur_phys_block,
340 file_meta.lblock);
341 }
342
343 /* Update block metadata in scratch metadata block */
344 err = its_flash_fs_mblock_update_scratch_block_meta(fs_ctx,
345 file_meta.lblock,
346 &block_meta);
347 if (err != PSA_SUCCESS) {
348 return PSA_ERROR_GENERIC_ERROR;
349 }
350
351 #ifdef ITS_ENCRYPTION
352 memcpy(file_meta.nonce, finfo->nonce, sizeof(finfo->nonce));
353 memcpy(file_meta.tag, finfo->tag, sizeof(finfo->tag));
354 #endif
355
356 /* Write file metadata in the scratch metadata block */
357 err = its_flash_fs_mblock_update_scratch_file_meta(fs_ctx, new_idx,
358 &file_meta);
359 if (err != PSA_SUCCESS) {
360 return PSA_ERROR_GENERIC_ERROR;
361 }
362
363 /* Copy the file metadata entries from the start to the smaller of the two
364 * indexes.
365 */
366 idx = ITS_UTILS_MIN(new_idx, old_idx);
367 err = its_flash_fs_mblock_cp_file_meta(fs_ctx, 0, idx);
368 if (err != PSA_SUCCESS) {
369 return PSA_ERROR_GENERIC_ERROR;
370 }
371
372 /* Copy the file metadata entries between the two indexes, if necessary */
373 if (old_idx != ITS_METADATA_INVALID_INDEX && old_idx != new_idx) {
374 err = its_flash_fs_mblock_cp_file_meta(fs_ctx, idx + 1,
375 ITS_UTILS_MAX(new_idx, old_idx));
376 if (err != PSA_SUCCESS) {
377 return PSA_ERROR_GENERIC_ERROR;
378 }
379
380 idx = ITS_UTILS_MAX(new_idx, old_idx);
381 }
382
383 /* Copy rest of the file metadata entries */
384 err = its_flash_fs_mblock_cp_file_meta(fs_ctx, idx + 1,
385 fs_ctx->cfg->max_num_files);
386 if (err != PSA_SUCCESS) {
387 return PSA_ERROR_GENERIC_ERROR;
388 }
389
390 /* The file data in the logical block 0 is stored in same physical block
391 * where the metadata is stored. A change in the metadata requires a swap of
392 * physical blocks. So, the file data stored in the current metadata block
393 * needs to be copied to the scratch block, if the data of the file
394 * processed is not located in the logical block 0. When file data is
395 * located in the logical block 0, that copy has been done while processing
396 * the file data.
397 */
398 if ((file_meta.lblock != ITS_LOGICAL_DBLOCK0) || (data_size == 0)) {
399 err = its_flash_fs_mblock_migrate_lb0_data_to_scratch(fs_ctx);
400 if (err != PSA_SUCCESS) {
401 return PSA_ERROR_GENERIC_ERROR;
402 }
403 }
404
405 /* Write metadata header, swap metadata blocks and erase scratch blocks */
406 err = its_flash_fs_mblock_meta_update_finalize(fs_ctx);
407 if (err != PSA_SUCCESS) {
408 return err;
409 }
410
411 /* Delete the old file in a second block update.
412 * Note: A power failure after this point, but before the deletion has
413 * completed, will leave the old file in the filesystem, so it is always
414 * necessary to check for files to be deleted at initialisation time.
415 */
416 if (old_idx != ITS_METADATA_INVALID_INDEX && old_idx != new_idx) {
417 err = its_flash_fs_delete_idx(fs_ctx, old_idx);
418 }
419
420 return err;
421 }
422
its_flash_fs_delete_idx(struct its_flash_fs_ctx_t * fs_ctx,uint32_t del_file_idx)423 static psa_status_t its_flash_fs_delete_idx(struct its_flash_fs_ctx_t *fs_ctx,
424 uint32_t del_file_idx)
425 {
426 size_t del_file_data_idx;
427 uint32_t del_file_lblock;
428 size_t del_file_max_size;
429 psa_status_t err;
430 size_t src_offset = fs_ctx->cfg->block_size;
431 size_t nbr_bytes_to_move = 0;
432 uint32_t idx;
433 struct its_file_meta_t file_meta;
434 struct its_block_meta_t block_meta;
435
436 err = its_flash_fs_mblock_read_file_meta(fs_ctx, del_file_idx, &file_meta);
437 if (err != PSA_SUCCESS) {
438 return err;
439 }
440
441 if (its_utils_validate_fid(file_meta.id) != PSA_SUCCESS) {
442 return PSA_ERROR_DOES_NOT_EXIST;
443 }
444
445 /* Save logical block, data_index and max_size to be used later on */
446 del_file_lblock = file_meta.lblock;
447 del_file_data_idx = file_meta.data_idx;
448 del_file_max_size = file_meta.max_size;
449
450 /* Remove file metadata */
451 file_meta = (struct its_file_meta_t){0};
452
453 /* Update file metadata in to the scratch block */
454 err = its_flash_fs_mblock_update_scratch_file_meta(fs_ctx, del_file_idx,
455 &file_meta);
456 if (err != PSA_SUCCESS) {
457 return err;
458 }
459
460 /* Read all file metadata */
461 for (idx = 0; idx < fs_ctx->cfg->max_num_files; idx++) {
462 if (idx == del_file_idx) {
463 /* Skip deleted file */
464 continue;
465 }
466
467 /* Read file meta for the given file index */
468 err = its_flash_fs_mblock_read_file_meta(fs_ctx, idx, &file_meta);
469 if (err != PSA_SUCCESS) {
470 return err;
471 }
472
473 /* Check if the file is located in the same logical block and has a
474 * valid FID.
475 */
476 if ((file_meta.lblock == del_file_lblock) &&
477 (its_utils_validate_fid(file_meta.id) == PSA_SUCCESS)) {
478 /* If a file is located after the data to delete, this
479 * needs to be moved.
480 */
481 if (file_meta.data_idx > del_file_data_idx) {
482 /* Check if this is the position after the deleted
483 * data. This will be the first file data to move.
484 */
485 if (src_offset > file_meta.data_idx) {
486 src_offset = file_meta.data_idx;
487 }
488
489 /* Set the new file data index location in the
490 * data block.
491 */
492 file_meta.data_idx -= del_file_max_size;
493
494 /* Increase number of bytes to move */
495 nbr_bytes_to_move += file_meta.max_size;
496 }
497 }
498 /* Update file metadata in to the scratch block */
499 err = its_flash_fs_mblock_update_scratch_file_meta(fs_ctx, idx,
500 &file_meta);
501 if (err != PSA_SUCCESS) {
502 return err;
503 }
504 }
505
506 if (del_file_max_size == 0) {
507 /* If the asset max size is 0, there is no need to compact the data block.
508 * Copy the block metadata and the block data to scratch metadata block.
509 */
510 err = its_flash_fs_mblock_read_block_metadata(fs_ctx, ITS_LOGICAL_DBLOCK0, &block_meta);
511 if (err != PSA_SUCCESS) {
512 return err;
513 }
514 err = its_flash_fs_mblock_update_scratch_block_meta(fs_ctx, ITS_LOGICAL_DBLOCK0,
515 &block_meta);
516 } else {
517 /* Compact data block */
518 err = its_flash_fs_dblock_compact_block(fs_ctx, del_file_lblock,
519 del_file_max_size,
520 src_offset, del_file_data_idx,
521 nbr_bytes_to_move);
522 }
523
524 if (err != PSA_SUCCESS) {
525 return err;
526 }
527
528 /* If the max size of file to delete is not 0:
529 * The file data in the logical block 0 is stored in same physical block
530 * where the metadata is stored. A change in the metadata requires a
531 * swap of physical blocks. So, the file data stored in the current
532 * metadata block needs to be copied in the scratch block, if the data
533 * of the file processed is not located in the logical block 0. When an
534 * file data is located in the logical block 0, that copy has been done
535 * while processing the file data.
536 * If the max size of file to delete is 0:
537 * The file metadata and block metadata has been updated into the scratch
538 * metadata block, copy the file data to the scratch block.
539 */
540 if ((del_file_max_size != 0 && del_file_lblock != ITS_LOGICAL_DBLOCK0) ||
541 (del_file_max_size == 0)) {
542 err = its_flash_fs_mblock_migrate_lb0_data_to_scratch(fs_ctx);
543 if (err != PSA_SUCCESS) {
544 return PSA_ERROR_GENERIC_ERROR;
545 }
546 }
547
548 /* Update the metablock header, swap scratch and active blocks,
549 * erase scratch blocks.
550 */
551 return its_flash_fs_mblock_meta_update_finalize(fs_ctx);
552 }
553
its_flash_fs_file_delete(struct its_flash_fs_ctx_t * fs_ctx,const uint8_t * fid)554 psa_status_t its_flash_fs_file_delete(struct its_flash_fs_ctx_t *fs_ctx,
555 const uint8_t *fid)
556 {
557 psa_status_t err;
558 uint32_t del_file_idx;
559
560 /* Get the file index. */
561 err = its_flash_fs_mblock_get_file_idx_meta(fs_ctx, fid, &del_file_idx, NULL);
562 if (err != PSA_SUCCESS) {
563 return PSA_ERROR_DOES_NOT_EXIST;
564 }
565
566 return its_flash_fs_delete_idx(fs_ctx, del_file_idx);
567 }
568
its_flash_fs_file_read(struct its_flash_fs_ctx_t * fs_ctx,const uint8_t * fid,size_t size,size_t offset,uint8_t * data)569 psa_status_t its_flash_fs_file_read(struct its_flash_fs_ctx_t *fs_ctx,
570 const uint8_t *fid,
571 size_t size,
572 size_t offset,
573 uint8_t *data)
574 {
575 psa_status_t err;
576 uint32_t idx;
577 struct its_file_meta_t tmp_metadata;
578
579 /* Get the file index and meta data */
580 err = its_flash_fs_mblock_get_file_idx_meta(fs_ctx, fid, &idx, &tmp_metadata);
581 if (err != PSA_SUCCESS) {
582 return PSA_ERROR_DOES_NOT_EXIST;
583 }
584
585 /* Boundary check the incoming request */
586 err = its_utils_check_contained_in(tmp_metadata.cur_size, offset, size);
587 if (err != PSA_SUCCESS) {
588 return err;
589 }
590
591 /* Read the file from flash */
592 err = its_flash_fs_dblock_read_file(fs_ctx, &tmp_metadata, offset, size,
593 data);
594 if (err != PSA_SUCCESS) {
595 return PSA_ERROR_GENERIC_ERROR;
596 }
597
598 return PSA_SUCCESS;
599 }
600