| /* |
| * Copyright (c) 2023 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| /* |
| * PSA ITS emulator over settings. |
| */ |
| |
| #include <stdlib.h> |
| |
| #include <zephyr/bluetooth/mesh.h> |
| #include <../library/psa_crypto_its.h> |
| |
| #define LOG_MODULE_NAME pts_its_emu |
| |
| #include <zephyr/logging/log.h> |
| #include "mesh/net.h" |
| #include "mesh/settings.h" |
| |
| LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF); |
| |
| /* The value of 52 bytes was measured practically in the mbedTLS psa security storage. */ |
| #define MAX_ITEM_LENGTH 52 |
| #define MAX_ITEM_NUMBER MBEDTLS_PSA_KEY_SLOT_COUNT |
| |
| typedef struct { |
| uint32_t size; |
| psa_storage_create_flags_t flags; |
| uint8_t data[MAX_ITEM_LENGTH]; |
| } psa_its_pst_item_t; |
| |
| typedef struct { |
| psa_storage_uid_t uid; |
| psa_its_pst_item_t pst_item; |
| } psa_its_item_t; |
| |
| static psa_its_item_t item[MAX_ITEM_NUMBER]; |
| |
| static psa_its_item_t *get_item_by_uid(psa_storage_uid_t uid) |
| { |
| for (int i = 0; i < MAX_ITEM_NUMBER; i++) { |
| if (uid == item[i].uid) { |
| return &item[i]; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| static int itsemul_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) |
| { |
| ssize_t len; |
| uint64_t uid; |
| psa_its_item_t *p_item; |
| |
| LOG_DBG("read out uid: %s", name); |
| |
| if (!name) { |
| LOG_ERR("Insufficient number of arguments"); |
| return -ENOENT; |
| } |
| |
| uid = strtoull(name, NULL, 10); |
| if (uid == ULLONG_MAX) { |
| LOG_ERR("Invalid format for uid"); |
| return -EINVAL; |
| } |
| |
| p_item = get_item_by_uid(uid); |
| if (p_item == NULL) { |
| p_item = get_item_by_uid(0ull); |
| } |
| |
| if (p_item == NULL) { |
| LOG_ERR("Insufficient sources for %llu", uid); |
| return -EINVAL; |
| } |
| |
| p_item->uid = uid; |
| |
| len = read_cb(cb_arg, &p_item->pst_item, len_rd); |
| if (len < 0) { |
| LOG_ERR("Failed to read value (err %zd)", len); |
| return -EINVAL; |
| } |
| |
| LOG_HEXDUMP_DBG(&p_item->pst_item, len, "pst_item:"); |
| |
| if (len != len_rd) { |
| LOG_ERR("Unexpected length (%zd != %zu)", len, len_rd); |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| SETTINGS_STATIC_HANDLER_DEFINE(psa_its_emu, "itsemul", NULL, itsemul_set, NULL, NULL); |
| |
| psa_status_t psa_its_get_info(psa_storage_uid_t uid, struct psa_storage_info_t *p_info) |
| { |
| psa_its_item_t *p_item; |
| |
| LOG_DBG("get info uid: %llu", uid); |
| |
| p_item = get_item_by_uid(uid); |
| if (p_item == NULL) { |
| return PSA_ERROR_DOES_NOT_EXIST; |
| } |
| |
| p_info->flags = p_item->pst_item.flags; |
| p_info->size = p_item->pst_item.size; |
| |
| LOG_DBG("flags: %lu, size: %lu", p_info->flags, p_info->size); |
| |
| return PSA_SUCCESS; |
| } |
| |
| psa_status_t psa_its_get(psa_storage_uid_t uid, uint32_t data_offset, uint32_t data_length, |
| void *p_data, size_t *p_data_length) |
| { |
| psa_its_item_t *p_item; |
| psa_its_pst_item_t *p_pst_item; |
| |
| LOG_DBG("get uid: %llu", uid); |
| |
| p_item = get_item_by_uid(uid); |
| if (p_item == NULL) { |
| return PSA_ERROR_DOES_NOT_EXIST; |
| } |
| |
| p_pst_item = &p_item->pst_item; |
| |
| if (data_offset > p_pst_item->size) { |
| return PSA_ERROR_DATA_CORRUPT; |
| } |
| |
| *p_data_length = MIN(p_pst_item->size - data_offset, data_length); |
| memcpy(p_data, p_pst_item->data + data_offset, *p_data_length); |
| |
| return PSA_SUCCESS; |
| } |
| |
| psa_status_t psa_its_set(psa_storage_uid_t uid, uint32_t data_length, const void *p_data, |
| psa_storage_create_flags_t create_flags) |
| { |
| char path[40]; |
| psa_its_item_t *p_item; |
| psa_its_pst_item_t *p_pst_item; |
| psa_status_t status = PSA_SUCCESS; |
| |
| LOG_DBG("Set uid: %llu, len: %lu", uid, data_length); |
| |
| if (data_length > MAX_ITEM_LENGTH) { |
| LOG_ERR("Too long item data: %lu > " STRINGIFY(MAX_ITEM_LENGTH), data_length); |
| } |
| |
| p_item = get_item_by_uid(uid); |
| if (p_item == NULL) { |
| p_item = get_item_by_uid(0ull); |
| } |
| |
| if (p_item == NULL) { |
| return PSA_ERROR_STORAGE_FAILURE; |
| } |
| |
| snprintk(path, sizeof(path), "itsemul/%llu", uid); |
| |
| p_item->uid = uid; |
| p_pst_item = &p_item->pst_item; |
| p_pst_item->size = data_length; |
| p_pst_item->flags = create_flags; |
| memcpy(p_pst_item->data, p_data, data_length); |
| |
| if (settings_save_one(path, p_pst_item, sizeof(psa_its_pst_item_t))) { |
| LOG_ERR("Failed to store its item: %s", path); |
| status = PSA_ERROR_STORAGE_FAILURE; |
| } else { |
| LOG_DBG("Stored its item: %s", path); |
| } |
| |
| return status; |
| } |
| |
| psa_status_t psa_its_remove(psa_storage_uid_t uid) |
| { |
| char path[40]; |
| psa_status_t status = PSA_SUCCESS; |
| psa_its_item_t *p_item; |
| |
| LOG_DBG("remove uid: %llu", uid); |
| |
| p_item = get_item_by_uid(uid); |
| if (p_item == NULL) { |
| return status; |
| } |
| memset(p_item, 0, sizeof(psa_its_item_t)); |
| |
| snprintk(path, sizeof(path), "itsemul/%llu", uid); |
| |
| if (settings_delete(path)) { |
| LOG_ERR("Failed to remove its item: %s", path); |
| status = PSA_ERROR_STORAGE_FAILURE; |
| } else { |
| LOG_DBG("Removed its item: %s", path); |
| } |
| |
| return status; |
| } |