blob: 0598b40a3892c94670b2b339038667e717bc25bc [file] [log] [blame]
/*
* 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;
}