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
log_failed_operation(const char * operation,const char * preposition,psa_status_t ret)14 static void log_failed_operation(const char *operation, const char *preposition, psa_status_t ret)
15 {
16 LOG_ERR("Failed to %s data %s storage. (%d)", operation, preposition, ret);
17 }
18
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)19 static psa_status_t get_stored_data(
20 secure_storage_its_uid_t uid,
21 uint8_t stored_data[static SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE],
22 size_t *stored_data_len)
23 {
24 psa_status_t ret;
25
26 ret = secure_storage_its_store_get(uid, SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE,
27 stored_data, stored_data_len);
28 if (ret != PSA_SUCCESS) {
29 if (ret != PSA_ERROR_DOES_NOT_EXIST) {
30 log_failed_operation("retrieve", "from", ret);
31 }
32 return ret;
33 }
34 return PSA_SUCCESS;
35 }
36
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)37 static psa_status_t transform_stored_data(
38 secure_storage_its_uid_t uid, size_t stored_data_len,
39 const uint8_t stored_data[static SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE],
40 size_t data_size, void *data, size_t *data_len,
41 psa_storage_create_flags_t *create_flags)
42 {
43 psa_status_t ret;
44
45 ret = secure_storage_its_transform_from_store(uid, stored_data_len, stored_data,
46 data_size, data, data_len, create_flags);
47 if (ret != PSA_SUCCESS) {
48 log_failed_operation("transform", "from", ret);
49 return PSA_ERROR_STORAGE_FAILURE;
50 }
51 return PSA_SUCCESS;
52 }
53
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)54 static psa_status_t get_entry(secure_storage_its_uid_t uid, size_t data_size, uint8_t *data,
55 size_t *data_len, psa_storage_create_flags_t *create_flags)
56 {
57 psa_status_t ret;
58 uint8_t stored_data[SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE];
59 size_t stored_data_len;
60
61 ret = get_stored_data(uid, stored_data, &stored_data_len);
62 if (ret != PSA_SUCCESS) {
63 return ret;
64 }
65
66 return transform_stored_data(uid, stored_data_len, stored_data, data_size, data, data_len,
67 create_flags);
68 }
69
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)70 static bool keep_stored_entry(secure_storage_its_uid_t uid, size_t data_length, const void *p_data,
71 psa_storage_create_flags_t create_flags, psa_status_t *ret)
72 {
73 psa_storage_create_flags_t existing_create_flags;
74 uint8_t existing_data[CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE];
75 size_t existing_data_len;
76
77 *ret = get_entry(uid, sizeof(existing_data), existing_data, &existing_data_len,
78 &existing_create_flags);
79 if (*ret != PSA_SUCCESS) {
80 /* The entry either doesn't exist or is corrupted. */
81 /* Allow overwriting corrupted entries to not be stuck with them forever. */
82 return false;
83 }
84 if (existing_create_flags & PSA_STORAGE_FLAG_WRITE_ONCE) {
85 *ret = PSA_ERROR_NOT_PERMITTED;
86 return true;
87 }
88 if (existing_data_len == data_length &&
89 existing_create_flags == create_flags &&
90 !memcmp(existing_data, p_data, data_length)) {
91 LOG_DBG("Not writing entry %u/%llu to storage because its stored data"
92 " (of length %zu) is identical.", uid.caller_id, uid.uid, data_length);
93 *ret = PSA_SUCCESS;
94 return true;
95 }
96 return false;
97 }
98
store_entry(secure_storage_its_uid_t uid,size_t data_length,const void * p_data,psa_storage_create_flags_t create_flags)99 static psa_status_t store_entry(secure_storage_its_uid_t uid, size_t data_length,
100 const void *p_data, psa_storage_create_flags_t create_flags)
101 {
102 psa_status_t ret;
103 uint8_t stored_data[SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE];
104 size_t stored_data_len;
105
106 ret = secure_storage_its_transform_to_store(uid, data_length, p_data, create_flags,
107 stored_data, &stored_data_len);
108 if (ret != PSA_SUCCESS) {
109 log_failed_operation("transform", "for", ret);
110 return PSA_ERROR_STORAGE_FAILURE;
111 }
112
113 ret = secure_storage_its_store_set(uid, stored_data_len, stored_data);
114 if (ret != PSA_SUCCESS) {
115 log_failed_operation("write", "to", ret);
116 }
117 return ret;
118 }
119
secure_storage_its_set(secure_storage_its_uid_t uid,size_t data_length,const void * p_data,psa_storage_create_flags_t create_flags)120 psa_status_t secure_storage_its_set(secure_storage_its_uid_t uid, size_t data_length,
121 const void *p_data, psa_storage_create_flags_t create_flags)
122 {
123 psa_status_t ret;
124
125 if (uid.uid == 0 || (p_data == NULL && data_length != 0)) {
126 return PSA_ERROR_INVALID_ARGUMENT;
127 }
128 if (create_flags & ~SECURE_STORAGE_ALL_CREATE_FLAGS) {
129 return PSA_ERROR_NOT_SUPPORTED;
130 }
131 if (data_length > CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE) {
132 LOG_DBG("Passed data length (%zu) exceeds maximum allowed (%u).",
133 data_length, CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE);
134 return PSA_ERROR_INSUFFICIENT_STORAGE;
135 }
136
137 if (keep_stored_entry(uid, data_length, p_data, create_flags, &ret)) {
138 return ret;
139 }
140
141 ret = store_entry(uid, data_length, p_data, create_flags);
142 return ret;
143 }
144
secure_storage_its_get(secure_storage_its_uid_t uid,size_t data_offset,size_t data_size,void * p_data,size_t * p_data_length)145 psa_status_t secure_storage_its_get(secure_storage_its_uid_t uid, size_t data_offset,
146 size_t data_size, void *p_data, size_t *p_data_length)
147 {
148 if (uid.uid == 0 || (p_data == NULL && data_size != 0) || p_data_length == NULL) {
149 return PSA_ERROR_INVALID_ARGUMENT;
150 }
151 if (data_size == 0) {
152 *p_data_length = 0;
153 return PSA_SUCCESS;
154 }
155 psa_status_t ret;
156 uint8_t stored_data[SECURE_STORAGE_ITS_TRANSFORM_MAX_STORED_DATA_SIZE];
157 size_t stored_data_len;
158 psa_storage_create_flags_t create_flags;
159
160 ret = get_stored_data(uid, stored_data, &stored_data_len);
161 if (ret != PSA_SUCCESS) {
162 return ret;
163 }
164 if (data_offset == 0
165 && data_size >= SECURE_STORAGE_ITS_TRANSFORM_DATA_SIZE(stored_data_len)) {
166 /* All the data fits directly in the provided buffer. */
167 return transform_stored_data(uid, stored_data_len, stored_data, data_size, p_data,
168 p_data_length, &create_flags);
169 }
170 uint8_t data[CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE];
171 size_t data_len;
172
173 ret = transform_stored_data(uid, stored_data_len, stored_data, sizeof(data), data,
174 &data_len, &create_flags);
175 if (ret == PSA_SUCCESS) {
176 if (data_offset > data_len) {
177 LOG_DBG("Passed data offset (%zu) exceeds existing data length (%zu).",
178 data_offset, data_len);
179 return PSA_ERROR_INVALID_ARGUMENT;
180 }
181 *p_data_length = MIN(data_size, data_len - data_offset);
182 memcpy(p_data, data + data_offset, *p_data_length);
183 }
184 return ret;
185 }
186
secure_storage_its_get_info(secure_storage_its_uid_t uid,struct psa_storage_info_t * p_info)187 psa_status_t secure_storage_its_get_info(secure_storage_its_uid_t uid,
188 struct psa_storage_info_t *p_info)
189 {
190 psa_status_t ret;
191 uint8_t data[CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE];
192
193 if (uid.uid == 0 || p_info == NULL) {
194 return PSA_ERROR_INVALID_ARGUMENT;
195 }
196
197 ret = get_entry(uid, sizeof(data), data, &p_info->size, &p_info->flags);
198 if (ret == PSA_SUCCESS) {
199 p_info->capacity = p_info->size;
200 }
201 return ret;
202 }
203
secure_storage_its_remove(secure_storage_its_uid_t uid)204 psa_status_t secure_storage_its_remove(secure_storage_its_uid_t uid)
205 {
206 psa_status_t ret;
207 psa_storage_create_flags_t create_flags;
208 uint8_t data[CONFIG_SECURE_STORAGE_ITS_MAX_DATA_SIZE];
209 size_t data_len;
210
211 if (uid.uid == 0) {
212 return PSA_ERROR_INVALID_ARGUMENT;
213 }
214
215 ret = get_entry(uid, sizeof(data), data, &data_len, &create_flags);
216 if (ret == PSA_SUCCESS && (create_flags & PSA_STORAGE_FLAG_WRITE_ONCE)) {
217 return PSA_ERROR_NOT_PERMITTED;
218 }
219 /* Allow overwriting corrupted entries as well to not be stuck with them forever. */
220 if (ret == PSA_SUCCESS || ret == PSA_ERROR_STORAGE_FAILURE) {
221 ret = secure_storage_its_store_remove(uid);
222 if (ret != PSA_SUCCESS) {
223 log_failed_operation("remove", "from", ret);
224 return PSA_ERROR_STORAGE_FAILURE;
225 }
226 }
227 return ret;
228 }
229