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