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