1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 /*
7 * PSA ITS emulator over settings.
8 */
9
10 #include <stdlib.h>
11
12 #include <zephyr/bluetooth/mesh.h>
13 #include <../library/psa_crypto_its.h>
14
15 #define LOG_MODULE_NAME pts_its_emu
16
17 #include <zephyr/logging/log.h>
18 #include "mesh/net.h"
19 #include "mesh/settings.h"
20
21 LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF);
22
23 /* The value of 52 bytes was measured practically in the mbedTLS psa security storage. */
24 #define MAX_ITEM_LENGTH 52
25 #define MAX_ITEM_NUMBER MBEDTLS_PSA_KEY_SLOT_COUNT
26
27 typedef struct {
28 uint32_t size;
29 psa_storage_create_flags_t flags;
30 uint8_t data[MAX_ITEM_LENGTH];
31 } psa_its_pst_item_t;
32
33 typedef struct {
34 psa_storage_uid_t uid;
35 psa_its_pst_item_t pst_item;
36 } psa_its_item_t;
37
38 static psa_its_item_t item[MAX_ITEM_NUMBER];
39
get_item_by_uid(psa_storage_uid_t uid)40 static psa_its_item_t *get_item_by_uid(psa_storage_uid_t uid)
41 {
42 for (int i = 0; i < MAX_ITEM_NUMBER; i++) {
43 if (uid == item[i].uid) {
44 return &item[i];
45 }
46 }
47
48 return NULL;
49 }
50
itsemul_set(const char * name,size_t len_rd,settings_read_cb read_cb,void * cb_arg)51 static int itsemul_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg)
52 {
53 ssize_t len;
54 uint64_t uid;
55 psa_its_item_t *p_item;
56
57 LOG_DBG("read out uid: %s", name);
58
59 if (!name) {
60 LOG_ERR("Insufficient number of arguments");
61 return -ENOENT;
62 }
63
64 uid = strtoull(name, NULL, 10);
65 if (uid == ULLONG_MAX) {
66 LOG_ERR("Invalid format for uid");
67 return -EINVAL;
68 }
69
70 p_item = get_item_by_uid(uid);
71 if (p_item == NULL) {
72 p_item = get_item_by_uid(0ull);
73 }
74
75 if (p_item == NULL) {
76 LOG_ERR("Insufficient sources for %llu", uid);
77 return -EINVAL;
78 }
79
80 p_item->uid = uid;
81
82 len = read_cb(cb_arg, &p_item->pst_item, len_rd);
83 if (len < 0) {
84 LOG_ERR("Failed to read value (err %zd)", len);
85 return -EINVAL;
86 }
87
88 LOG_HEXDUMP_DBG(&p_item->pst_item, len, "pst_item:");
89
90 if (len != len_rd) {
91 LOG_ERR("Unexpected length (%zd != %zu)", len, len_rd);
92 return -EINVAL;
93 }
94
95 return 0;
96 }
97
98 SETTINGS_STATIC_HANDLER_DEFINE(psa_its_emu, "itsemul", NULL, itsemul_set, NULL, NULL);
99
psa_its_get_info(psa_storage_uid_t uid,struct psa_storage_info_t * p_info)100 psa_status_t psa_its_get_info(psa_storage_uid_t uid, struct psa_storage_info_t *p_info)
101 {
102 psa_its_item_t *p_item;
103
104 LOG_DBG("get info uid: %llu", uid);
105
106 p_item = get_item_by_uid(uid);
107 if (p_item == NULL) {
108 return PSA_ERROR_DOES_NOT_EXIST;
109 }
110
111 p_info->flags = p_item->pst_item.flags;
112 p_info->size = p_item->pst_item.size;
113
114 LOG_DBG("flags: %lu, size: %lu", p_info->flags, p_info->size);
115
116 return PSA_SUCCESS;
117 }
118
psa_its_get(psa_storage_uid_t uid,uint32_t data_offset,uint32_t data_length,void * p_data,size_t * p_data_length)119 psa_status_t psa_its_get(psa_storage_uid_t uid, uint32_t data_offset, uint32_t data_length,
120 void *p_data, size_t *p_data_length)
121 {
122 psa_its_item_t *p_item;
123 psa_its_pst_item_t *p_pst_item;
124
125 LOG_DBG("get uid: %llu", uid);
126
127 p_item = get_item_by_uid(uid);
128 if (p_item == NULL) {
129 return PSA_ERROR_DOES_NOT_EXIST;
130 }
131
132 p_pst_item = &p_item->pst_item;
133
134 if (data_offset > p_pst_item->size) {
135 return PSA_ERROR_DATA_CORRUPT;
136 }
137
138 *p_data_length = MIN(p_pst_item->size - data_offset, data_length);
139 memcpy(p_data, p_pst_item->data + data_offset, *p_data_length);
140
141 return PSA_SUCCESS;
142 }
143
psa_its_set(psa_storage_uid_t uid,uint32_t data_length,const void * p_data,psa_storage_create_flags_t create_flags)144 psa_status_t psa_its_set(psa_storage_uid_t uid, uint32_t data_length, const void *p_data,
145 psa_storage_create_flags_t create_flags)
146 {
147 char path[40];
148 psa_its_item_t *p_item;
149 psa_its_pst_item_t *p_pst_item;
150 psa_status_t status = PSA_SUCCESS;
151
152 LOG_DBG("Set uid: %llu, len: %lu", uid, data_length);
153
154 if (data_length > MAX_ITEM_LENGTH) {
155 LOG_ERR("Too long item data: %lu > " STRINGIFY(MAX_ITEM_LENGTH), data_length);
156 }
157
158 p_item = get_item_by_uid(uid);
159 if (p_item == NULL) {
160 p_item = get_item_by_uid(0ull);
161 }
162
163 if (p_item == NULL) {
164 return PSA_ERROR_STORAGE_FAILURE;
165 }
166
167 snprintk(path, sizeof(path), "itsemul/%llu", uid);
168
169 p_item->uid = uid;
170 p_pst_item = &p_item->pst_item;
171 p_pst_item->size = data_length;
172 p_pst_item->flags = create_flags;
173 memcpy(p_pst_item->data, p_data, data_length);
174
175 if (settings_save_one(path, p_pst_item, sizeof(psa_its_pst_item_t))) {
176 LOG_ERR("Failed to store its item: %s", path);
177 status = PSA_ERROR_STORAGE_FAILURE;
178 } else {
179 LOG_DBG("Stored its item: %s", path);
180 }
181
182 return status;
183 }
184
psa_its_remove(psa_storage_uid_t uid)185 psa_status_t psa_its_remove(psa_storage_uid_t uid)
186 {
187 char path[40];
188 psa_status_t status = PSA_SUCCESS;
189 psa_its_item_t *p_item;
190
191 LOG_DBG("remove uid: %llu", uid);
192
193 p_item = get_item_by_uid(uid);
194 if (p_item == NULL) {
195 return status;
196 }
197 memset(p_item, 0, sizeof(psa_its_item_t));
198
199 snprintk(path, sizeof(path), "itsemul/%llu", uid);
200
201 if (settings_delete(path)) {
202 LOG_ERR("Failed to remove its item: %s", path);
203 status = PSA_ERROR_STORAGE_FAILURE;
204 } else {
205 LOG_DBG("Removed its item: %s", path);
206 }
207
208 return status;
209 }
210