1 /* Copyright (c) 2024 Nordic Semiconductor
2 * SPDX-License-Identifier: Apache-2.0
3 */
4 #include <zephyr/secure_storage/its.h>
5 #include <zephyr/secure_storage/its/store.h>
6 #include <zephyr/secure_storage/its/transform.h>
7 #include <zephyr/logging/log.h>
8 #include <zephyr/sys/util.h>
9 #include <zephyr/toolchain.h>
10 #include <string.h>
11
12 LOG_MODULE_DECLARE(secure_storage, CONFIG_SECURE_STORAGE_LOG_LEVEL);
13
14 #ifndef CONFIG_SECURE_STORAGE_64_BIT_UID
15 BUILD_ASSERT(sizeof(secure_storage_its_uid_t) == 4); /* ITS UIDs are 32-bit */
16 BUILD_ASSERT(1 << SECURE_STORAGE_ITS_CALLER_ID_BIT_SIZE >= SECURE_STORAGE_ITS_CALLER_COUNT);
17 BUILD_ASSERT(SECURE_STORAGE_ITS_CALLER_ID_BIT_SIZE + SECURE_STORAGE_ITS_UID_BIT_SIZE == 32);
18 #endif
19
make_its_uid(secure_storage_its_caller_id_t caller_id,psa_storage_uid_t uid,secure_storage_its_uid_t * its_uid)20 static psa_status_t make_its_uid(secure_storage_its_caller_id_t caller_id, psa_storage_uid_t uid,
21 secure_storage_its_uid_t *its_uid)
22 {
23 if (uid == 0) {
24 return PSA_ERROR_INVALID_ARGUMENT;
25 }
26
27 #ifndef CONFIG_SECURE_STORAGE_64_BIT_UID
28 /* Check that the UID is not bigger than the maximum defined size. */
29 if (uid & GENMASK64(63, SECURE_STORAGE_ITS_UID_BIT_SIZE)) {
30 LOG_DBG("UID %u/%#llx cannot be used as it has bits set past "
31 "the first " STRINGIFY(SECURE_STORAGE_ITS_UID_BIT_SIZE) " ones.",
32 caller_id, (unsigned long long)uid);
33 return PSA_ERROR_INVALID_ARGUMENT;
34 }
35 #endif /* !CONFIG_SECURE_STORAGE_64_BIT_UID */
36
37 *its_uid = (secure_storage_its_uid_t){.caller_id = caller_id, .uid = uid};
38 return PSA_SUCCESS;
39 }
40
log_failed_operation(const char * operation,const char * preposition,psa_status_t ret)41 static void log_failed_operation(const char *operation, const char *preposition, psa_status_t ret)
42 {
43 LOG_ERR("Failed to %s data %s storage. (%d)", operation, preposition, ret);
44 }
45
get_stored_data(secure_storage_its_uid_t uid,uint8_t stored_data[static SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE],size_t * stored_data_len)46 static psa_status_t get_stored_data(
47 secure_storage_its_uid_t uid,
48 uint8_t stored_data[static SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE],
49 size_t *stored_data_len)
50 {
51 psa_status_t ret;
52
53 ret = secure_storage_its_store_get(uid, SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE,
54 stored_data, stored_data_len);
55 if (ret != PSA_SUCCESS) {
56 if (ret != PSA_ERROR_DOES_NOT_EXIST) {
57 log_failed_operation("retrieve", "from", ret);
58 }
59 }
60 return ret;
61 }
62
transform_stored_data(secure_storage_its_uid_t uid,size_t stored_data_len,const uint8_t stored_data[static SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE],size_t data_size,void * data,size_t * data_len,psa_storage_create_flags_t * create_flags)63 static psa_status_t transform_stored_data(
64 secure_storage_its_uid_t uid, size_t stored_data_len,
65 const uint8_t stored_data[static SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE],
66 size_t data_size, void *data, size_t *data_len,
67 psa_storage_create_flags_t *create_flags)
68 {
69 psa_status_t ret;
70
71 ret = secure_storage_its_transform_from_store(uid, stored_data_len, stored_data,
72 data_size, data, data_len, create_flags);
73 if (ret != PSA_SUCCESS) {
74 log_failed_operation("transform", "from", ret);
75 return PSA_ERROR_GENERIC_ERROR;
76 }
77 return PSA_SUCCESS;
78 }
79
get_entry(secure_storage_its_uid_t uid,size_t data_size,uint8_t * data,size_t * data_len,psa_storage_create_flags_t * create_flags)80 static psa_status_t get_entry(secure_storage_its_uid_t uid, size_t data_size, uint8_t *data,
81 size_t *data_len, psa_storage_create_flags_t *create_flags)
82 {
83 psa_status_t ret;
84 uint8_t stored_data[SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE];
85 size_t stored_data_len;
86
87 ret = get_stored_data(uid, stored_data, &stored_data_len);
88 if (ret != PSA_SUCCESS) {
89 return ret;
90 }
91
92 return transform_stored_data(uid, stored_data_len, stored_data, data_size, data, data_len,
93 create_flags);
94 }
95
keep_stored_entry(secure_storage_its_uid_t uid,size_t data_length,const void * p_data,psa_storage_create_flags_t create_flags,psa_status_t * ret)96 static bool keep_stored_entry(secure_storage_its_uid_t uid, size_t data_length, const void *p_data,
97 psa_storage_create_flags_t create_flags, psa_status_t *ret)
98 {
99 psa_storage_create_flags_t existing_create_flags;
100 uint8_t existing_data[CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE];
101 size_t existing_data_len;
102
103 *ret = get_entry(uid, sizeof(existing_data), existing_data, &existing_data_len,
104 &existing_create_flags);
105 if (*ret != PSA_SUCCESS) {
106 /* The entry either doesn't exist or is corrupted. */
107 /* Allow overwriting corrupted entries to not be stuck with them forever. */
108 return false;
109 }
110 if (existing_create_flags & PSA_STORAGE_FLAG_WRITE_ONCE) {
111 *ret = PSA_ERROR_NOT_PERMITTED;
112 return true;
113 }
114 if (existing_data_len == data_length &&
115 existing_create_flags == create_flags &&
116 !memcmp(existing_data, p_data, data_length)) {
117 #ifdef CONFIG_SECURE_STORAGE_64_BIT_UID
118 LOG_DBG("Not writing entry %u/%#llx to storage because its stored data"
119 " (of length %zu) is identical.", uid.caller_id,
120 (unsigned long long)uid.uid, data_length);
121 #else
122 LOG_DBG("Not writing entry %u/%#lx to storage because its stored data"
123 " (of length %zu) is identical.", uid.caller_id,
124 (unsigned long)uid.uid, data_length);
125 #endif
126 *ret = PSA_SUCCESS;
127 return true;
128 }
129 return false;
130 }
131
store_entry(secure_storage_its_uid_t uid,size_t data_length,const void * p_data,psa_storage_create_flags_t create_flags)132 static psa_status_t store_entry(secure_storage_its_uid_t uid, size_t data_length,
133 const void *p_data, psa_storage_create_flags_t create_flags)
134 {
135 psa_status_t ret;
136 uint8_t stored_data[SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE];
137 size_t stored_data_len;
138
139 ret = secure_storage_its_transform_to_store(uid, data_length, p_data, create_flags,
140 stored_data, &stored_data_len);
141 if (ret != PSA_SUCCESS) {
142 log_failed_operation("transform", "for", ret);
143 return PSA_ERROR_GENERIC_ERROR;
144 }
145
146 ret = secure_storage_its_store_set(uid, stored_data_len, stored_data);
147 if (ret != PSA_SUCCESS) {
148 log_failed_operation("write", "to", ret);
149 }
150 return ret;
151 }
152
secure_storage_its_set(secure_storage_its_caller_id_t caller_id,psa_storage_uid_t uid,size_t data_length,const void * p_data,psa_storage_create_flags_t create_flags)153 psa_status_t secure_storage_its_set(secure_storage_its_caller_id_t caller_id, psa_storage_uid_t uid,
154 size_t data_length, const void *p_data,
155 psa_storage_create_flags_t create_flags)
156 {
157 psa_status_t ret;
158 secure_storage_its_uid_t its_uid;
159
160 if (make_its_uid(caller_id, uid, &its_uid) != PSA_SUCCESS) {
161 return PSA_ERROR_INVALID_ARGUMENT;
162 }
163 if (create_flags & ~SECURE_STORAGE_ALL_CREATE_FLAGS) {
164 return PSA_ERROR_NOT_SUPPORTED;
165 }
166 if (data_length > CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE) {
167 LOG_DBG("Passed data length (%zu) exceeds maximum allowed (%u).",
168 data_length, CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE);
169 return PSA_ERROR_INVALID_ARGUMENT;
170 }
171
172 if (keep_stored_entry(its_uid, data_length, p_data, create_flags, &ret)) {
173 return ret;
174 }
175
176 ret = store_entry(its_uid, data_length, p_data, create_flags);
177 return ret;
178 }
secure_storage_its_get(secure_storage_its_caller_id_t caller_id,psa_storage_uid_t uid,size_t data_offset,size_t data_size,void * p_data,size_t * p_data_length)179 psa_status_t secure_storage_its_get(secure_storage_its_caller_id_t caller_id, psa_storage_uid_t uid,
180 size_t data_offset, size_t data_size,
181 void *p_data, size_t *p_data_length)
182 {
183 psa_status_t ret;
184 secure_storage_its_uid_t its_uid;
185 uint8_t stored_data[SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE];
186 size_t stored_data_len;
187 psa_storage_create_flags_t create_flags;
188
189 if (make_its_uid(caller_id, uid, &its_uid) != PSA_SUCCESS) {
190 return PSA_ERROR_INVALID_ARGUMENT;
191 }
192 if (data_size == 0) {
193 *p_data_length = 0;
194 return PSA_SUCCESS;
195 }
196
197 ret = get_stored_data(its_uid, stored_data, &stored_data_len);
198 if (ret != PSA_SUCCESS) {
199 return ret;
200 }
201 if (data_offset == 0
202 && data_size >= SECURE_STORAGE_ITS_TRANSFORM_DATA_SIZE(stored_data_len)) {
203 /* All the data fits directly in the provided buffer. */
204 return transform_stored_data(its_uid, stored_data_len, stored_data, data_size,
205 p_data, p_data_length, &create_flags);
206 }
207 uint8_t data[CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE];
208 size_t data_len;
209
210 ret = transform_stored_data(its_uid, stored_data_len, stored_data, sizeof(data), data,
211 &data_len, &create_flags);
212 if (ret == PSA_SUCCESS) {
213 if (data_offset > data_len) {
214 LOG_DBG("Passed data offset (%zu) exceeds existing data length (%zu).",
215 data_offset, data_len);
216 return PSA_ERROR_INVALID_ARGUMENT;
217 }
218 *p_data_length = MIN(data_size, data_len - data_offset);
219 memcpy(p_data, data + data_offset, *p_data_length);
220 }
221 return ret;
222 }
223
secure_storage_its_get_info(secure_storage_its_caller_id_t caller_id,psa_storage_uid_t uid,struct psa_storage_info_t * p_info)224 psa_status_t secure_storage_its_get_info(secure_storage_its_caller_id_t caller_id,
225 psa_storage_uid_t uid, struct psa_storage_info_t *p_info)
226 {
227 psa_status_t ret;
228 secure_storage_its_uid_t its_uid;
229 uint8_t data[CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE];
230
231 if (make_its_uid(caller_id, uid, &its_uid) != PSA_SUCCESS) {
232 return PSA_ERROR_INVALID_ARGUMENT;
233 }
234
235 ret = get_entry(its_uid, sizeof(data), data, &p_info->size, &p_info->flags);
236 if (ret == PSA_SUCCESS) {
237 p_info->capacity = p_info->size;
238 }
239 return ret;
240 }
241
secure_storage_its_remove(secure_storage_its_caller_id_t caller_id,psa_storage_uid_t uid)242 psa_status_t secure_storage_its_remove(secure_storage_its_caller_id_t caller_id,
243 psa_storage_uid_t uid)
244 {
245 psa_status_t ret;
246 secure_storage_its_uid_t its_uid;
247 psa_storage_create_flags_t create_flags;
248 uint8_t data[CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE];
249 size_t data_len;
250
251 if (make_its_uid(caller_id, uid, &its_uid) != PSA_SUCCESS) {
252 return PSA_ERROR_INVALID_ARGUMENT;
253 }
254
255 ret = get_entry(its_uid, sizeof(data), data, &data_len, &create_flags);
256 if (ret == PSA_SUCCESS && (create_flags & PSA_STORAGE_FLAG_WRITE_ONCE)) {
257 return PSA_ERROR_NOT_PERMITTED;
258 }
259 /* Allow overwriting corrupted entries as well to not be stuck with them forever. */
260 if (ret == PSA_SUCCESS ||
261 ret == PSA_ERROR_STORAGE_FAILURE ||
262 ret == PSA_ERROR_GENERIC_ERROR) {
263 ret = secure_storage_its_store_remove(its_uid);
264 if (ret != PSA_SUCCESS) {
265 log_failed_operation("remove", "from", ret);
266 return PSA_ERROR_STORAGE_FAILURE;
267 }
268 }
269 return ret;
270 }
271