/src/mbedtls/library/psa_crypto_slot_management.c
Line | Count | Source |
1 | | /* |
2 | | * PSA crypto layer on top of Mbed TLS crypto |
3 | | */ |
4 | | /* |
5 | | * Copyright The Mbed TLS Contributors |
6 | | * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later |
7 | | */ |
8 | | |
9 | | #include "common.h" |
10 | | |
11 | | #if defined(MBEDTLS_PSA_CRYPTO_C) |
12 | | |
13 | | #include "psa/crypto.h" |
14 | | |
15 | | #include "psa_crypto_core.h" |
16 | | #include "psa_crypto_driver_wrappers_no_static.h" |
17 | | #include "psa_crypto_slot_management.h" |
18 | | #include "psa_crypto_storage.h" |
19 | | #if defined(MBEDTLS_PSA_CRYPTO_SE_C) |
20 | | #include "psa_crypto_se.h" |
21 | | #endif |
22 | | |
23 | | #include <stdlib.h> |
24 | | #include <string.h> |
25 | | #include "mbedtls/platform.h" |
26 | | #if defined(MBEDTLS_THREADING_C) |
27 | | #include "mbedtls/threading.h" |
28 | | #endif |
29 | | |
30 | | |
31 | | |
32 | | /* Make sure we have distinct ranges of key identifiers for distinct |
33 | | * purposes. */ |
34 | | MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_USER_MIN < PSA_KEY_ID_USER_MAX, |
35 | | "Empty user key ID range"); |
36 | | MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VENDOR_MIN < PSA_KEY_ID_VENDOR_MAX, |
37 | | "Empty vendor key ID range"); |
38 | | MBEDTLS_STATIC_ASSERT(MBEDTLS_PSA_KEY_ID_BUILTIN_MIN <= MBEDTLS_PSA_KEY_ID_BUILTIN_MAX, |
39 | | "Empty builtin key ID range"); |
40 | | MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VOLATILE_MIN <= PSA_KEY_ID_VOLATILE_MAX, |
41 | | "Empty volatile key ID range"); |
42 | | |
43 | | MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_USER_MAX < PSA_KEY_ID_VENDOR_MIN || |
44 | | PSA_KEY_ID_VENDOR_MAX < PSA_KEY_ID_USER_MIN, |
45 | | "Overlap between user key IDs and vendor key IDs"); |
46 | | |
47 | | MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VENDOR_MIN <= MBEDTLS_PSA_KEY_ID_BUILTIN_MIN && |
48 | | MBEDTLS_PSA_KEY_ID_BUILTIN_MAX <= PSA_KEY_ID_VENDOR_MAX, |
49 | | "Builtin key identifiers are not in the vendor range"); |
50 | | |
51 | | MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VENDOR_MIN <= PSA_KEY_ID_VOLATILE_MIN && |
52 | | PSA_KEY_ID_VOLATILE_MAX <= PSA_KEY_ID_VENDOR_MAX, |
53 | | "Volatile key identifiers are not in the vendor range"); |
54 | | |
55 | | MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VOLATILE_MAX < MBEDTLS_PSA_KEY_ID_BUILTIN_MIN || |
56 | | MBEDTLS_PSA_KEY_ID_BUILTIN_MAX < PSA_KEY_ID_VOLATILE_MIN, |
57 | | "Overlap between builtin key IDs and volatile key IDs"); |
58 | | |
59 | | |
60 | | |
61 | | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
62 | | |
63 | | /* Dynamic key store. |
64 | | * |
65 | | * The key store consists of multiple slices. |
66 | | * |
67 | | * The volatile keys are stored in variable-sized tables called slices. |
68 | | * Slices are allocated on demand and deallocated when possible. |
69 | | * The size of slices increases exponentially, so the average overhead |
70 | | * (number of slots that are allocated but not used) is roughly |
71 | | * proportional to the number of keys (with a factor that grows |
72 | | * when the key store is fragmented). |
73 | | * |
74 | | * One slice is dedicated to the cache of persistent and built-in keys. |
75 | | * For simplicity, they are separated from volatile keys. This cache |
76 | | * slice has a fixed size and has the slice index KEY_SLOT_CACHE_SLICE_INDEX, |
77 | | * located after the slices for volatile keys. |
78 | | */ |
79 | | |
80 | | /* Size of the last slice containing the cache of persistent and built-in keys. */ |
81 | 3.74k | #define PERSISTENT_KEY_CACHE_COUNT MBEDTLS_PSA_KEY_SLOT_COUNT |
82 | | |
83 | | /* Volatile keys are stored in slices 0 through |
84 | | * (KEY_SLOT_VOLATILE_SLICE_COUNT - 1) inclusive. |
85 | | * Each slice is twice the size of the previous slice. |
86 | | * Volatile key identifiers encode the slice number as follows: |
87 | | * bits 30..31: 0b10 (mandated by the PSA Crypto specification). |
88 | | * bits 25..29: slice index (0...KEY_SLOT_VOLATILE_SLICE_COUNT-1) |
89 | | * bits 0..24: slot index in slice |
90 | | */ |
91 | 0 | #define KEY_ID_SLOT_INDEX_WIDTH 25u |
92 | 0 | #define KEY_ID_SLICE_INDEX_WIDTH 5u |
93 | | |
94 | 0 | #define KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH 16u |
95 | 9.13k | #define KEY_SLOT_VOLATILE_SLICE_COUNT 22u |
96 | 2.64k | #define KEY_SLICE_COUNT (KEY_SLOT_VOLATILE_SLICE_COUNT + 1u) |
97 | 3.96k | #define KEY_SLOT_CACHE_SLICE_INDEX KEY_SLOT_VOLATILE_SLICE_COUNT |
98 | | |
99 | | |
100 | | /* Check that the length of the largest slice (calculated as |
101 | | * KEY_SLICE_LENGTH_MAX below) does not overflow size_t. We use |
102 | | * an indirect method in case the calculation of KEY_SLICE_LENGTH_MAX |
103 | | * itself overflows uintmax_t: if (BASE_LENGTH << c) |
104 | | * overflows size_t then BASE_LENGTH > SIZE_MAX >> c. |
105 | | */ |
106 | | #if (KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH > \ |
107 | | SIZE_MAX >> (KEY_SLOT_VOLATILE_SLICE_COUNT - 1)) |
108 | | #error "Maximum slice length overflows size_t" |
109 | | #endif |
110 | | |
111 | | #if KEY_ID_SLICE_INDEX_WIDTH + KEY_ID_SLOT_INDEX_WIDTH > 30 |
112 | | #error "Not enough room in volatile key IDs for slice index and slot index" |
113 | | #endif |
114 | | #if KEY_SLOT_VOLATILE_SLICE_COUNT > (1 << KEY_ID_SLICE_INDEX_WIDTH) |
115 | | #error "Too many slices to fit the slice index in a volatile key ID" |
116 | | #endif |
117 | | #define KEY_SLICE_LENGTH_MAX \ |
118 | | (KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH << (KEY_SLOT_VOLATILE_SLICE_COUNT - 1)) |
119 | | #if KEY_SLICE_LENGTH_MAX > 1 << KEY_ID_SLOT_INDEX_WIDTH |
120 | | #error "Not enough room in volatile key IDs for a slot index in the largest slice" |
121 | | #endif |
122 | | #if KEY_ID_SLICE_INDEX_WIDTH > 8 |
123 | | #error "Slice index does not fit in uint8_t for psa_key_slot_t::slice_index" |
124 | | #endif |
125 | | |
126 | | |
127 | | /* Calculate the volatile key id to use for a given slot. |
128 | | * This function assumes valid parameter values. */ |
129 | | static psa_key_id_t volatile_key_id_of_index(size_t slice_idx, |
130 | | size_t slot_idx) |
131 | 0 | { |
132 | | /* We assert above that the slice and slot indexes fit in separate |
133 | | * bit-fields inside psa_key_id_t, which is a 32-bit type per the |
134 | | * PSA Cryptography specification. */ |
135 | 0 | return (psa_key_id_t) (0x40000000u | |
136 | 0 | (slice_idx << KEY_ID_SLOT_INDEX_WIDTH) | |
137 | 0 | slot_idx); |
138 | 0 | } |
139 | | |
140 | | /* Calculate the slice containing the given volatile key. |
141 | | * This function assumes valid parameter values. */ |
142 | | static size_t slice_index_of_volatile_key_id(psa_key_id_t key_id) |
143 | 0 | { |
144 | 0 | size_t mask = (1LU << KEY_ID_SLICE_INDEX_WIDTH) - 1; |
145 | 0 | return (key_id >> KEY_ID_SLOT_INDEX_WIDTH) & mask; |
146 | 0 | } |
147 | | |
148 | | /* Calculate the index of the slot containing the given volatile key. |
149 | | * This function assumes valid parameter values. */ |
150 | | static size_t slot_index_of_volatile_key_id(psa_key_id_t key_id) |
151 | 0 | { |
152 | 0 | return key_id & ((1LU << KEY_ID_SLOT_INDEX_WIDTH) - 1); |
153 | 0 | } |
154 | | |
155 | | /* In global_data.first_free_slot_index, use this special value to |
156 | | * indicate that the slice is full. */ |
157 | 0 | #define FREE_SLOT_INDEX_NONE ((size_t) -1) |
158 | | |
159 | | #if defined(MBEDTLS_TEST_HOOKS) |
160 | | size_t psa_key_slot_volatile_slice_count(void) |
161 | 0 | { |
162 | 0 | return KEY_SLOT_VOLATILE_SLICE_COUNT; |
163 | 0 | } |
164 | | #endif |
165 | | |
166 | | #else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
167 | | |
168 | | /* Static key store. |
169 | | * |
170 | | * All the keys (volatile or persistent) are in a single slice. |
171 | | * We only use slices as a concept to allow some differences between |
172 | | * static and dynamic key store management to be buried in auxiliary |
173 | | * functions. |
174 | | */ |
175 | | |
176 | | #define PERSISTENT_KEY_CACHE_COUNT MBEDTLS_PSA_KEY_SLOT_COUNT |
177 | | #define KEY_SLICE_COUNT 1u |
178 | | #define KEY_SLOT_CACHE_SLICE_INDEX 0 |
179 | | |
180 | | #endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
181 | | |
182 | | |
183 | | typedef struct { |
184 | | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
185 | | psa_key_slot_t *key_slices[KEY_SLICE_COUNT]; |
186 | | size_t first_free_slot_index[KEY_SLOT_VOLATILE_SLICE_COUNT]; |
187 | | #else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
188 | | psa_key_slot_t key_slots[MBEDTLS_PSA_KEY_SLOT_COUNT]; |
189 | | #endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
190 | | uint8_t key_slots_initialized; |
191 | | } psa_global_data_t; |
192 | | |
193 | | static psa_global_data_t global_data; |
194 | | |
195 | | static uint8_t psa_get_key_slots_initialized(void) |
196 | 0 | { |
197 | 0 | uint8_t initialized; |
198 | |
|
199 | 0 | #if defined(MBEDTLS_THREADING_C) |
200 | 0 | mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex); |
201 | 0 | #endif /* defined(MBEDTLS_THREADING_C) */ |
202 | |
|
203 | 0 | initialized = global_data.key_slots_initialized; |
204 | |
|
205 | 0 | #if defined(MBEDTLS_THREADING_C) |
206 | 0 | mbedtls_mutex_unlock(&mbedtls_threading_psa_globaldata_mutex); |
207 | 0 | #endif /* defined(MBEDTLS_THREADING_C) */ |
208 | |
|
209 | 0 | return initialized; |
210 | 0 | } |
211 | | |
212 | | |
213 | | |
214 | | /** The length of the given slice in the key slot table. |
215 | | * |
216 | | * \param slice_idx The slice number. It must satisfy |
217 | | * 0 <= slice_idx < KEY_SLICE_COUNT. |
218 | | * |
219 | | * \return The number of elements in the given slice. |
220 | | */ |
221 | | static inline size_t key_slice_length(size_t slice_idx); |
222 | | |
223 | | /** Get a pointer to the slot where the given volatile key is located. |
224 | | * |
225 | | * \param key_id The key identifier. It must be a valid volatile key |
226 | | * identifier. |
227 | | * \return A pointer to the only slot that the given key |
228 | | * can be in. Note that the slot may be empty or |
229 | | * contain a different key. |
230 | | */ |
231 | | static inline psa_key_slot_t *get_volatile_key_slot(psa_key_id_t key_id); |
232 | | |
233 | | /** Get a pointer to an entry in the persistent key cache. |
234 | | * |
235 | | * \param slot_idx The index in the table. It must satisfy |
236 | | * 0 <= slot_idx < PERSISTENT_KEY_CACHE_COUNT. |
237 | | * \return A pointer to the slot containing the given |
238 | | * persistent key cache entry. |
239 | | */ |
240 | | static inline psa_key_slot_t *get_persistent_key_slot(size_t slot_idx); |
241 | | |
242 | | /** Get a pointer to a slot given by slice and index. |
243 | | * |
244 | | * \param slice_idx The slice number. It must satisfy |
245 | | * 0 <= slice_idx < KEY_SLICE_COUNT. |
246 | | * \param slot_idx An index in the given slice. It must satisfy |
247 | | * 0 <= slot_idx < key_slice_length(slice_idx). |
248 | | * |
249 | | * \return A pointer to the given slot. |
250 | | */ |
251 | | static inline psa_key_slot_t *get_key_slot(size_t slice_idx, size_t slot_idx); |
252 | | |
253 | | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
254 | | |
255 | | #if defined(MBEDTLS_TEST_HOOKS) |
256 | | size_t (*mbedtls_test_hook_psa_volatile_key_slice_length)(size_t slice_idx) = NULL; |
257 | | #endif |
258 | | |
259 | | static inline size_t key_slice_length(size_t slice_idx) |
260 | 3.63k | { |
261 | 3.63k | if (slice_idx == KEY_SLOT_CACHE_SLICE_INDEX) { |
262 | 3.63k | return PERSISTENT_KEY_CACHE_COUNT; |
263 | 3.63k | } else { |
264 | 0 | #if defined(MBEDTLS_TEST_HOOKS) |
265 | 0 | if (mbedtls_test_hook_psa_volatile_key_slice_length != NULL) { |
266 | 0 | return mbedtls_test_hook_psa_volatile_key_slice_length(slice_idx); |
267 | 0 | } |
268 | 0 | #endif |
269 | 0 | return KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH << slice_idx; |
270 | 0 | } |
271 | 3.63k | } |
272 | | |
273 | | static inline psa_key_slot_t *get_volatile_key_slot(psa_key_id_t key_id) |
274 | 0 | { |
275 | 0 | size_t slice_idx = slice_index_of_volatile_key_id(key_id); |
276 | 0 | if (slice_idx >= KEY_SLOT_VOLATILE_SLICE_COUNT) { |
277 | 0 | return NULL; |
278 | 0 | } |
279 | 0 | size_t slot_idx = slot_index_of_volatile_key_id(key_id); |
280 | 0 | if (slot_idx >= key_slice_length(slice_idx)) { |
281 | 0 | return NULL; |
282 | 0 | } |
283 | 0 | psa_key_slot_t *slice = global_data.key_slices[slice_idx]; |
284 | 0 | if (slice == NULL) { |
285 | 0 | return NULL; |
286 | 0 | } |
287 | 0 | return &slice[slot_idx]; |
288 | 0 | } |
289 | | |
290 | | static inline psa_key_slot_t *get_persistent_key_slot(size_t slot_idx) |
291 | 0 | { |
292 | 0 | return &global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX][slot_idx]; |
293 | 0 | } |
294 | | |
295 | | static inline psa_key_slot_t *get_key_slot(size_t slice_idx, size_t slot_idx) |
296 | 3.52k | { |
297 | 3.52k | return &global_data.key_slices[slice_idx][slot_idx]; |
298 | 3.52k | } |
299 | | |
300 | | #else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
301 | | |
302 | | static inline size_t key_slice_length(size_t slice_idx) |
303 | | { |
304 | | (void) slice_idx; |
305 | | return ARRAY_LENGTH(global_data.key_slots); |
306 | | } |
307 | | |
308 | | static inline psa_key_slot_t *get_volatile_key_slot(psa_key_id_t key_id) |
309 | | { |
310 | | MBEDTLS_STATIC_ASSERT(ARRAY_LENGTH(global_data.key_slots) <= |
311 | | PSA_KEY_ID_VOLATILE_MAX - PSA_KEY_ID_VOLATILE_MIN + 1, |
312 | | "The key slot array is larger than the volatile key ID range"); |
313 | | return &global_data.key_slots[key_id - PSA_KEY_ID_VOLATILE_MIN]; |
314 | | } |
315 | | |
316 | | static inline psa_key_slot_t *get_persistent_key_slot(size_t slot_idx) |
317 | | { |
318 | | return &global_data.key_slots[slot_idx]; |
319 | | } |
320 | | |
321 | | static inline psa_key_slot_t *get_key_slot(size_t slice_idx, size_t slot_idx) |
322 | | { |
323 | | (void) slice_idx; |
324 | | return &global_data.key_slots[slot_idx]; |
325 | | } |
326 | | |
327 | | #endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
328 | | |
329 | | |
330 | | |
331 | | int psa_is_valid_key_id(mbedtls_svc_key_id_t key, int vendor_ok) |
332 | 0 | { |
333 | 0 | psa_key_id_t key_id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key); |
334 | |
|
335 | 0 | if ((PSA_KEY_ID_USER_MIN <= key_id) && |
336 | 0 | (key_id <= PSA_KEY_ID_USER_MAX)) { |
337 | 0 | return 1; |
338 | 0 | } |
339 | | |
340 | 0 | if (vendor_ok && |
341 | 0 | (PSA_KEY_ID_VENDOR_MIN <= key_id) && |
342 | 0 | (key_id <= PSA_KEY_ID_VENDOR_MAX)) { |
343 | 0 | return 1; |
344 | 0 | } |
345 | | |
346 | 0 | return 0; |
347 | 0 | } |
348 | | |
349 | | /** Get the description in memory of a key given its identifier and lock it. |
350 | | * |
351 | | * The descriptions of volatile keys and loaded persistent keys are |
352 | | * stored in key slots. This function returns a pointer to the key slot |
353 | | * containing the description of a key given its identifier. |
354 | | * |
355 | | * The function searches the key slots containing the description of the key |
356 | | * with \p key identifier. The function does only read accesses to the key |
357 | | * slots. The function does not load any persistent key thus does not access |
358 | | * any storage. |
359 | | * |
360 | | * For volatile key identifiers, only one key slot is queried as a volatile |
361 | | * key with identifier key_id can only be stored in slot of index |
362 | | * ( key_id - #PSA_KEY_ID_VOLATILE_MIN ). |
363 | | * |
364 | | * On success, the function locks the key slot. It is the responsibility of |
365 | | * the caller to unlock the key slot when it does not access it anymore. |
366 | | * |
367 | | * If multi-threading is enabled, the caller must hold the |
368 | | * global key slot mutex. |
369 | | * |
370 | | * \param key Key identifier to query. |
371 | | * \param[out] p_slot On success, `*p_slot` contains a pointer to the |
372 | | * key slot containing the description of the key |
373 | | * identified by \p key. |
374 | | * |
375 | | * \retval #PSA_SUCCESS |
376 | | * The pointer to the key slot containing the description of the key |
377 | | * identified by \p key was returned. |
378 | | * \retval #PSA_ERROR_INVALID_HANDLE |
379 | | * \p key is not a valid key identifier. |
380 | | * \retval #PSA_ERROR_DOES_NOT_EXIST |
381 | | * There is no key with key identifier \p key in the key slots. |
382 | | */ |
383 | | static psa_status_t psa_get_and_lock_key_slot_in_memory( |
384 | | mbedtls_svc_key_id_t key, psa_key_slot_t **p_slot) |
385 | 0 | { |
386 | 0 | psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; |
387 | 0 | psa_key_id_t key_id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key); |
388 | 0 | size_t slot_idx; |
389 | 0 | psa_key_slot_t *slot = NULL; |
390 | |
|
391 | 0 | if (psa_key_id_is_volatile(key_id)) { |
392 | 0 | slot = get_volatile_key_slot(key_id); |
393 | | |
394 | | /* Check if both the PSA key identifier key_id and the owner |
395 | | * identifier of key match those of the key slot. */ |
396 | 0 | if (slot != NULL && |
397 | 0 | slot->state == PSA_SLOT_FULL && |
398 | 0 | mbedtls_svc_key_id_equal(key, slot->attr.id)) { |
399 | 0 | status = PSA_SUCCESS; |
400 | 0 | } else { |
401 | 0 | status = PSA_ERROR_DOES_NOT_EXIST; |
402 | 0 | } |
403 | 0 | } else { |
404 | 0 | if (!psa_is_valid_key_id(key, 1)) { |
405 | 0 | return PSA_ERROR_INVALID_HANDLE; |
406 | 0 | } |
407 | | |
408 | 0 | for (slot_idx = 0; slot_idx < PERSISTENT_KEY_CACHE_COUNT; slot_idx++) { |
409 | 0 | slot = get_persistent_key_slot(slot_idx); |
410 | | /* Only consider slots which are in a full state. */ |
411 | 0 | if ((slot->state == PSA_SLOT_FULL) && |
412 | 0 | (mbedtls_svc_key_id_equal(key, slot->attr.id))) { |
413 | 0 | break; |
414 | 0 | } |
415 | 0 | } |
416 | 0 | status = (slot_idx < MBEDTLS_PSA_KEY_SLOT_COUNT) ? |
417 | 0 | PSA_SUCCESS : PSA_ERROR_DOES_NOT_EXIST; |
418 | 0 | } |
419 | | |
420 | 0 | if (status == PSA_SUCCESS) { |
421 | 0 | status = psa_register_read(slot); |
422 | 0 | if (status == PSA_SUCCESS) { |
423 | 0 | *p_slot = slot; |
424 | 0 | } |
425 | 0 | } |
426 | |
|
427 | 0 | return status; |
428 | 0 | } |
429 | | |
430 | | psa_status_t psa_initialize_key_slots(void) |
431 | 110 | { |
432 | 110 | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
433 | 110 | global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX] = |
434 | 110 | mbedtls_calloc(PERSISTENT_KEY_CACHE_COUNT, |
435 | 110 | sizeof(*global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX])); |
436 | 110 | if (global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX] == NULL) { |
437 | 0 | return PSA_ERROR_INSUFFICIENT_MEMORY; |
438 | 0 | } |
439 | | #else /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
440 | | /* Nothing to do: program startup and psa_wipe_all_key_slots() both |
441 | | * guarantee that the key slots are initialized to all-zero, which |
442 | | * means that all the key slots are in a valid, empty state. The global |
443 | | * data mutex is already held when calling this function, so no need to |
444 | | * lock it here, to set the flag. */ |
445 | | #endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
446 | | |
447 | 110 | global_data.key_slots_initialized = 1; |
448 | 110 | return PSA_SUCCESS; |
449 | 110 | } |
450 | | |
451 | | void psa_wipe_all_key_slots(void) |
452 | 110 | { |
453 | 2.64k | for (size_t slice_idx = 0; slice_idx < KEY_SLICE_COUNT; slice_idx++) { |
454 | 2.53k | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
455 | 2.53k | if (global_data.key_slices[slice_idx] == NULL) { |
456 | 2.42k | continue; |
457 | 2.42k | } |
458 | 110 | #endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
459 | 3.63k | for (size_t slot_idx = 0; slot_idx < key_slice_length(slice_idx); slot_idx++) { |
460 | 3.52k | psa_key_slot_t *slot = get_key_slot(slice_idx, slot_idx); |
461 | 3.52k | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
462 | | /* When MBEDTLS_PSA_KEY_STORE_DYNAMIC is disabled, calling |
463 | | * psa_wipe_key_slot() on an unused slot is useless, but it |
464 | | * happens to work (because we flip the state to PENDING_DELETION). |
465 | | * |
466 | | * When MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled, |
467 | | * psa_wipe_key_slot() needs to have a valid slice_index |
468 | | * field, but that value might not be correct in a |
469 | | * free slot, so we must not call it. |
470 | | * |
471 | | * Bypass the call to psa_wipe_key_slot() if the slot is empty, |
472 | | * but only if MBEDTLS_PSA_KEY_STORE_DYNAMIC is enabled, to save |
473 | | * a few bytes of code size otherwise. |
474 | | */ |
475 | 3.52k | if (slot->state == PSA_SLOT_EMPTY) { |
476 | 3.52k | continue; |
477 | 3.52k | } |
478 | 0 | #endif |
479 | 0 | slot->var.occupied.registered_readers = 1; |
480 | 0 | slot->state = PSA_SLOT_PENDING_DELETION; |
481 | 0 | (void) psa_wipe_key_slot(slot); |
482 | 0 | } |
483 | 110 | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
484 | 110 | mbedtls_free(global_data.key_slices[slice_idx]); |
485 | 110 | global_data.key_slices[slice_idx] = NULL; |
486 | 110 | #endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
487 | 110 | } |
488 | | |
489 | 110 | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
490 | 2.53k | for (size_t slice_idx = 0; slice_idx < KEY_SLOT_VOLATILE_SLICE_COUNT; slice_idx++) { |
491 | 2.42k | global_data.first_free_slot_index[slice_idx] = 0; |
492 | 2.42k | } |
493 | 110 | #endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
494 | | |
495 | | /* The global data mutex is already held when calling this function. */ |
496 | 110 | global_data.key_slots_initialized = 0; |
497 | 110 | } |
498 | | |
499 | | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
500 | | |
501 | | static psa_status_t psa_allocate_volatile_key_slot(psa_key_id_t *key_id, |
502 | | psa_key_slot_t **p_slot) |
503 | 0 | { |
504 | 0 | size_t slice_idx; |
505 | 0 | for (slice_idx = 0; slice_idx < KEY_SLOT_VOLATILE_SLICE_COUNT; slice_idx++) { |
506 | 0 | if (global_data.first_free_slot_index[slice_idx] != FREE_SLOT_INDEX_NONE) { |
507 | 0 | break; |
508 | 0 | } |
509 | 0 | } |
510 | 0 | if (slice_idx == KEY_SLOT_VOLATILE_SLICE_COUNT) { |
511 | 0 | return PSA_ERROR_INSUFFICIENT_MEMORY; |
512 | 0 | } |
513 | | |
514 | 0 | if (global_data.key_slices[slice_idx] == NULL) { |
515 | 0 | global_data.key_slices[slice_idx] = |
516 | 0 | mbedtls_calloc(key_slice_length(slice_idx), |
517 | 0 | sizeof(psa_key_slot_t)); |
518 | 0 | if (global_data.key_slices[slice_idx] == NULL) { |
519 | 0 | return PSA_ERROR_INSUFFICIENT_MEMORY; |
520 | 0 | } |
521 | 0 | } |
522 | 0 | psa_key_slot_t *slice = global_data.key_slices[slice_idx]; |
523 | |
|
524 | 0 | size_t slot_idx = global_data.first_free_slot_index[slice_idx]; |
525 | 0 | *key_id = volatile_key_id_of_index(slice_idx, slot_idx); |
526 | |
|
527 | 0 | psa_key_slot_t *slot = &slice[slot_idx]; |
528 | 0 | size_t next_free = slot_idx + 1 + slot->var.free.next_free_relative_to_next; |
529 | 0 | if (next_free >= key_slice_length(slice_idx)) { |
530 | 0 | next_free = FREE_SLOT_INDEX_NONE; |
531 | 0 | } |
532 | 0 | global_data.first_free_slot_index[slice_idx] = next_free; |
533 | | /* The .next_free field is not meaningful when the slot is not free, |
534 | | * so give it the same content as freshly initialized memory. */ |
535 | 0 | slot->var.free.next_free_relative_to_next = 0; |
536 | |
|
537 | 0 | psa_status_t status = psa_key_slot_state_transition(slot, |
538 | 0 | PSA_SLOT_EMPTY, |
539 | 0 | PSA_SLOT_FILLING); |
540 | 0 | if (status != PSA_SUCCESS) { |
541 | | /* The only reason for failure is if the slot state was not empty. |
542 | | * This indicates that something has gone horribly wrong. |
543 | | * In this case, we leave the slot out of the free list, and stop |
544 | | * modifying it. This minimizes any further corruption. The slot |
545 | | * is a memory leak, but that's a lesser evil. */ |
546 | 0 | return status; |
547 | 0 | } |
548 | | |
549 | 0 | *p_slot = slot; |
550 | | /* We assert at compile time that the slice index fits in uint8_t. */ |
551 | 0 | slot->slice_index = (uint8_t) slice_idx; |
552 | 0 | return PSA_SUCCESS; |
553 | 0 | } |
554 | | |
555 | | psa_status_t psa_free_key_slot(size_t slice_idx, |
556 | | psa_key_slot_t *slot) |
557 | 0 | { |
558 | |
|
559 | 0 | if (slice_idx == KEY_SLOT_CACHE_SLICE_INDEX) { |
560 | | /* This is a cache entry. We don't maintain a free list, so |
561 | | * there's nothing to do. */ |
562 | 0 | return PSA_SUCCESS; |
563 | 0 | } |
564 | 0 | if (slice_idx >= KEY_SLOT_VOLATILE_SLICE_COUNT) { |
565 | 0 | return PSA_ERROR_CORRUPTION_DETECTED; |
566 | 0 | } |
567 | | |
568 | 0 | psa_key_slot_t *slice = global_data.key_slices[slice_idx]; |
569 | 0 | psa_key_slot_t *slice_end = slice + key_slice_length(slice_idx); |
570 | 0 | if (slot < slice || slot >= slice_end) { |
571 | | /* The slot isn't actually in the slice! We can't detect that |
572 | | * condition for sure, because the pointer comparison itself is |
573 | | * undefined behavior in that case. That same condition makes the |
574 | | * subtraction to calculate the slot index also UB. |
575 | | * Give up now to avoid causing further corruption. |
576 | | */ |
577 | 0 | return PSA_ERROR_CORRUPTION_DETECTED; |
578 | 0 | } |
579 | 0 | size_t slot_idx = slot - slice; |
580 | |
|
581 | 0 | size_t next_free = global_data.first_free_slot_index[slice_idx]; |
582 | 0 | if (next_free >= key_slice_length(slice_idx)) { |
583 | | /* The slot was full. The newly freed slot thus becomes the |
584 | | * end of the free list. */ |
585 | 0 | next_free = key_slice_length(slice_idx); |
586 | 0 | } |
587 | 0 | global_data.first_free_slot_index[slice_idx] = slot_idx; |
588 | 0 | slot->var.free.next_free_relative_to_next = |
589 | 0 | (int32_t) next_free - (int32_t) slot_idx - 1; |
590 | |
|
591 | 0 | return PSA_SUCCESS; |
592 | 0 | } |
593 | | #endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
594 | | |
595 | | psa_status_t psa_reserve_free_key_slot(psa_key_id_t *volatile_key_id, |
596 | | psa_key_slot_t **p_slot) |
597 | 0 | { |
598 | 0 | psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; |
599 | 0 | size_t slot_idx; |
600 | 0 | psa_key_slot_t *selected_slot, *unused_persistent_key_slot; |
601 | |
|
602 | 0 | if (!psa_get_key_slots_initialized()) { |
603 | 0 | status = PSA_ERROR_BAD_STATE; |
604 | 0 | goto error; |
605 | 0 | } |
606 | | |
607 | 0 | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
608 | 0 | if (volatile_key_id != NULL) { |
609 | 0 | return psa_allocate_volatile_key_slot(volatile_key_id, p_slot); |
610 | 0 | } |
611 | 0 | #endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
612 | | |
613 | | /* With a dynamic key store, allocate an entry in the cache slice, |
614 | | * applicable only to non-volatile keys that get cached in RAM. |
615 | | * With a static key store, allocate an entry in the sole slice, |
616 | | * applicable to all keys. */ |
617 | 0 | selected_slot = unused_persistent_key_slot = NULL; |
618 | 0 | for (slot_idx = 0; slot_idx < PERSISTENT_KEY_CACHE_COUNT; slot_idx++) { |
619 | 0 | psa_key_slot_t *slot = get_key_slot(KEY_SLOT_CACHE_SLICE_INDEX, slot_idx); |
620 | 0 | if (slot->state == PSA_SLOT_EMPTY) { |
621 | 0 | selected_slot = slot; |
622 | 0 | break; |
623 | 0 | } |
624 | | |
625 | 0 | if ((unused_persistent_key_slot == NULL) && |
626 | 0 | (slot->state == PSA_SLOT_FULL) && |
627 | 0 | (!psa_key_slot_has_readers(slot)) && |
628 | 0 | (!PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime))) { |
629 | 0 | unused_persistent_key_slot = slot; |
630 | 0 | } |
631 | 0 | } |
632 | | |
633 | | /* |
634 | | * If there is no unused key slot and there is at least one unlocked key |
635 | | * slot containing the description of a persistent key, recycle the first |
636 | | * such key slot we encountered. If we later need to operate on the |
637 | | * persistent key we are evicting now, we will reload its description from |
638 | | * storage. |
639 | | */ |
640 | 0 | if ((selected_slot == NULL) && |
641 | 0 | (unused_persistent_key_slot != NULL)) { |
642 | 0 | selected_slot = unused_persistent_key_slot; |
643 | 0 | psa_register_read(selected_slot); |
644 | 0 | status = psa_wipe_key_slot(selected_slot); |
645 | 0 | if (status != PSA_SUCCESS) { |
646 | 0 | goto error; |
647 | 0 | } |
648 | 0 | } |
649 | | |
650 | 0 | if (selected_slot != NULL) { |
651 | 0 | status = psa_key_slot_state_transition(selected_slot, PSA_SLOT_EMPTY, |
652 | 0 | PSA_SLOT_FILLING); |
653 | 0 | if (status != PSA_SUCCESS) { |
654 | 0 | goto error; |
655 | 0 | } |
656 | | |
657 | 0 | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
658 | 0 | selected_slot->slice_index = KEY_SLOT_CACHE_SLICE_INDEX; |
659 | 0 | #endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
660 | |
|
661 | | #if !defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
662 | | if (volatile_key_id != NULL) { |
663 | | /* Refresh slot_idx, for when the slot is not the original |
664 | | * selected_slot but rather unused_persistent_key_slot. */ |
665 | | slot_idx = selected_slot - global_data.key_slots; |
666 | | *volatile_key_id = PSA_KEY_ID_VOLATILE_MIN + (psa_key_id_t) slot_idx; |
667 | | } |
668 | | #endif |
669 | 0 | *p_slot = selected_slot; |
670 | |
|
671 | 0 | return PSA_SUCCESS; |
672 | 0 | } |
673 | 0 | status = PSA_ERROR_INSUFFICIENT_MEMORY; |
674 | |
|
675 | 0 | error: |
676 | 0 | *p_slot = NULL; |
677 | |
|
678 | 0 | return status; |
679 | 0 | } |
680 | | |
681 | | #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) |
682 | | static psa_status_t psa_load_persistent_key_into_slot(psa_key_slot_t *slot) |
683 | 0 | { |
684 | 0 | psa_status_t status = PSA_SUCCESS; |
685 | 0 | uint8_t *key_data = NULL; |
686 | 0 | size_t key_data_length = 0; |
687 | 0 | psa_key_id_t key_id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id); |
688 | | |
689 | | /* Do not try to load a persistent key whose ID is in the volatile range. */ |
690 | 0 | if ((key_id >= PSA_KEY_ID_VOLATILE_MIN) && (key_id <= PSA_KEY_ID_VOLATILE_MAX)) { |
691 | 0 | return PSA_ERROR_DOES_NOT_EXIST; |
692 | 0 | } |
693 | | |
694 | 0 | status = psa_load_persistent_key(&slot->attr, |
695 | 0 | &key_data, &key_data_length); |
696 | 0 | if (status != PSA_SUCCESS) { |
697 | 0 | goto exit; |
698 | 0 | } |
699 | | |
700 | 0 | #if defined(MBEDTLS_PSA_CRYPTO_SE_C) |
701 | | /* Special handling is required for loading keys associated with a |
702 | | * dynamically registered SE interface. */ |
703 | 0 | const psa_drv_se_t *drv; |
704 | 0 | psa_drv_se_context_t *drv_context; |
705 | 0 | if (psa_get_se_driver(slot->attr.lifetime, &drv, &drv_context)) { |
706 | 0 | psa_se_key_data_storage_t *data; |
707 | |
|
708 | 0 | if (key_data_length != sizeof(*data)) { |
709 | 0 | status = PSA_ERROR_DATA_INVALID; |
710 | 0 | goto exit; |
711 | 0 | } |
712 | 0 | data = (psa_se_key_data_storage_t *) key_data; |
713 | 0 | status = psa_copy_key_material_into_slot( |
714 | 0 | slot, data->slot_number, sizeof(data->slot_number)); |
715 | 0 | goto exit; |
716 | 0 | } |
717 | 0 | #endif /* MBEDTLS_PSA_CRYPTO_SE_C */ |
718 | | |
719 | 0 | status = psa_copy_key_material_into_slot(slot, key_data, key_data_length); |
720 | 0 | if (status != PSA_SUCCESS) { |
721 | 0 | goto exit; |
722 | 0 | } |
723 | | |
724 | 0 | exit: |
725 | 0 | psa_free_persistent_key_data(key_data, key_data_length); |
726 | 0 | return status; |
727 | 0 | } |
728 | | #endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */ |
729 | | |
730 | | #if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS) |
731 | | |
732 | | static psa_status_t psa_load_builtin_key_into_slot(psa_key_slot_t *slot) |
733 | 0 | { |
734 | 0 | psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; |
735 | 0 | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
736 | 0 | psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_VOLATILE; |
737 | 0 | psa_drv_slot_number_t slot_number = 0; |
738 | 0 | size_t key_buffer_size = 0; |
739 | 0 | size_t key_buffer_length = 0; |
740 | |
|
741 | 0 | if (!psa_key_id_is_builtin( |
742 | 0 | MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id))) { |
743 | 0 | return PSA_ERROR_DOES_NOT_EXIST; |
744 | 0 | } |
745 | | |
746 | | /* Check the platform function to see whether this key actually exists */ |
747 | 0 | status = mbedtls_psa_platform_get_builtin_key( |
748 | 0 | slot->attr.id, &lifetime, &slot_number); |
749 | 0 | if (status != PSA_SUCCESS) { |
750 | 0 | return status; |
751 | 0 | } |
752 | | |
753 | | /* Set required key attributes to ensure get_builtin_key can retrieve the |
754 | | * full attributes. */ |
755 | 0 | psa_set_key_id(&attributes, slot->attr.id); |
756 | 0 | psa_set_key_lifetime(&attributes, lifetime); |
757 | | |
758 | | /* Get the full key attributes from the driver in order to be able to |
759 | | * calculate the required buffer size. */ |
760 | 0 | status = psa_driver_wrapper_get_builtin_key( |
761 | 0 | slot_number, &attributes, |
762 | 0 | NULL, 0, NULL); |
763 | 0 | if (status != PSA_ERROR_BUFFER_TOO_SMALL) { |
764 | | /* Builtin keys cannot be defined by the attributes alone */ |
765 | 0 | if (status == PSA_SUCCESS) { |
766 | 0 | status = PSA_ERROR_CORRUPTION_DETECTED; |
767 | 0 | } |
768 | 0 | return status; |
769 | 0 | } |
770 | | |
771 | | /* If the key should exist according to the platform, then ask the driver |
772 | | * what its expected size is. */ |
773 | 0 | status = psa_driver_wrapper_get_key_buffer_size(&attributes, |
774 | 0 | &key_buffer_size); |
775 | 0 | if (status != PSA_SUCCESS) { |
776 | 0 | return status; |
777 | 0 | } |
778 | | |
779 | | /* Allocate a buffer of the required size and load the builtin key directly |
780 | | * into the (now properly sized) slot buffer. */ |
781 | 0 | status = psa_allocate_buffer_to_slot(slot, key_buffer_size); |
782 | 0 | if (status != PSA_SUCCESS) { |
783 | 0 | return status; |
784 | 0 | } |
785 | | |
786 | 0 | status = psa_driver_wrapper_get_builtin_key( |
787 | 0 | slot_number, &attributes, |
788 | 0 | slot->key.data, slot->key.bytes, &key_buffer_length); |
789 | 0 | if (status != PSA_SUCCESS) { |
790 | 0 | goto exit; |
791 | 0 | } |
792 | | |
793 | | /* Copy actual key length and core attributes into the slot on success */ |
794 | 0 | slot->key.bytes = key_buffer_length; |
795 | 0 | slot->attr = attributes; |
796 | 0 | exit: |
797 | 0 | if (status != PSA_SUCCESS) { |
798 | 0 | psa_remove_key_data_from_memory(slot); |
799 | 0 | } |
800 | 0 | return status; |
801 | 0 | } |
802 | | #endif /* MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ |
803 | | |
804 | | psa_status_t psa_get_and_lock_key_slot(mbedtls_svc_key_id_t key, |
805 | | psa_key_slot_t **p_slot) |
806 | 0 | { |
807 | 0 | psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; |
808 | |
|
809 | 0 | *p_slot = NULL; |
810 | 0 | if (!psa_get_key_slots_initialized()) { |
811 | 0 | return PSA_ERROR_BAD_STATE; |
812 | 0 | } |
813 | | |
814 | 0 | #if defined(MBEDTLS_THREADING_C) |
815 | | /* We need to set status as success, otherwise CORRUPTION_DETECTED |
816 | | * would be returned if the lock fails. */ |
817 | 0 | status = PSA_SUCCESS; |
818 | | /* If the key is persistent and not loaded, we cannot unlock the mutex |
819 | | * between checking if the key is loaded and setting the slot as FULL, |
820 | | * as otherwise another thread may load and then destroy the key |
821 | | * in the meantime. */ |
822 | 0 | PSA_THREADING_CHK_RET(mbedtls_mutex_lock( |
823 | 0 | &mbedtls_threading_key_slot_mutex)); |
824 | 0 | #endif |
825 | | /* |
826 | | * On success, the pointer to the slot is passed directly to the caller |
827 | | * thus no need to unlock the key slot here. |
828 | | */ |
829 | 0 | status = psa_get_and_lock_key_slot_in_memory(key, p_slot); |
830 | 0 | if (status != PSA_ERROR_DOES_NOT_EXIST) { |
831 | 0 | #if defined(MBEDTLS_THREADING_C) |
832 | 0 | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
833 | 0 | &mbedtls_threading_key_slot_mutex)); |
834 | 0 | #endif |
835 | 0 | return status; |
836 | 0 | } |
837 | | |
838 | | /* Loading keys from storage requires support for such a mechanism */ |
839 | 0 | #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) || \ |
840 | 0 | defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS) |
841 | | |
842 | 0 | status = psa_reserve_free_key_slot(NULL, p_slot); |
843 | 0 | if (status != PSA_SUCCESS) { |
844 | 0 | #if defined(MBEDTLS_THREADING_C) |
845 | 0 | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
846 | 0 | &mbedtls_threading_key_slot_mutex)); |
847 | 0 | #endif |
848 | 0 | return status; |
849 | 0 | } |
850 | | |
851 | 0 | (*p_slot)->attr.id = key; |
852 | 0 | (*p_slot)->attr.lifetime = PSA_KEY_LIFETIME_PERSISTENT; |
853 | |
|
854 | 0 | status = PSA_ERROR_DOES_NOT_EXIST; |
855 | 0 | #if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS) |
856 | | /* Load keys in the 'builtin' range through their own interface */ |
857 | 0 | status = psa_load_builtin_key_into_slot(*p_slot); |
858 | 0 | #endif /* MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ |
859 | |
|
860 | 0 | #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) |
861 | 0 | if (status == PSA_ERROR_DOES_NOT_EXIST) { |
862 | 0 | status = psa_load_persistent_key_into_slot(*p_slot); |
863 | 0 | } |
864 | 0 | #endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */ |
865 | |
|
866 | 0 | if (status != PSA_SUCCESS) { |
867 | 0 | psa_wipe_key_slot(*p_slot); |
868 | | |
869 | | /* If the key does not exist, we need to return |
870 | | * PSA_ERROR_INVALID_HANDLE. */ |
871 | 0 | if (status == PSA_ERROR_DOES_NOT_EXIST) { |
872 | 0 | status = PSA_ERROR_INVALID_HANDLE; |
873 | 0 | } |
874 | 0 | } else { |
875 | | /* Add implicit usage flags. */ |
876 | 0 | psa_extend_key_usage_flags(&(*p_slot)->attr.policy.usage); |
877 | |
|
878 | 0 | psa_key_slot_state_transition((*p_slot), PSA_SLOT_FILLING, |
879 | 0 | PSA_SLOT_FULL); |
880 | 0 | status = psa_register_read(*p_slot); |
881 | 0 | } |
882 | |
|
883 | | #else /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ |
884 | | status = PSA_ERROR_INVALID_HANDLE; |
885 | | #endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ |
886 | |
|
887 | 0 | if (status != PSA_SUCCESS) { |
888 | 0 | *p_slot = NULL; |
889 | 0 | } |
890 | 0 | #if defined(MBEDTLS_THREADING_C) |
891 | 0 | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
892 | 0 | &mbedtls_threading_key_slot_mutex)); |
893 | 0 | #endif |
894 | 0 | return status; |
895 | 0 | } |
896 | | |
897 | | psa_status_t psa_unregister_read(psa_key_slot_t *slot) |
898 | 0 | { |
899 | 0 | if (slot == NULL) { |
900 | 0 | return PSA_SUCCESS; |
901 | 0 | } |
902 | 0 | if ((slot->state != PSA_SLOT_FULL) && |
903 | 0 | (slot->state != PSA_SLOT_PENDING_DELETION)) { |
904 | 0 | return PSA_ERROR_CORRUPTION_DETECTED; |
905 | 0 | } |
906 | | |
907 | | /* If we are the last reader and the slot is marked for deletion, |
908 | | * we must wipe the slot here. */ |
909 | 0 | if ((slot->state == PSA_SLOT_PENDING_DELETION) && |
910 | 0 | (slot->var.occupied.registered_readers == 1)) { |
911 | 0 | return psa_wipe_key_slot(slot); |
912 | 0 | } |
913 | | |
914 | 0 | if (psa_key_slot_has_readers(slot)) { |
915 | 0 | slot->var.occupied.registered_readers--; |
916 | 0 | return PSA_SUCCESS; |
917 | 0 | } |
918 | | |
919 | | /* |
920 | | * As the return error code may not be handled in case of multiple errors, |
921 | | * do our best to report if there are no registered readers. Assert with |
922 | | * MBEDTLS_TEST_HOOK_TEST_ASSERT that there are registered readers: |
923 | | * if the MBEDTLS_TEST_HOOKS configuration option is enabled and |
924 | | * the function is called as part of the execution of a test suite, the |
925 | | * execution of the test suite is stopped in error if the assertion fails. |
926 | | */ |
927 | 0 | MBEDTLS_TEST_HOOK_TEST_ASSERT(psa_key_slot_has_readers(slot)); |
928 | 0 | return PSA_ERROR_CORRUPTION_DETECTED; |
929 | 0 | } |
930 | | |
931 | | psa_status_t psa_unregister_read_under_mutex(psa_key_slot_t *slot) |
932 | 0 | { |
933 | 0 | psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; |
934 | 0 | #if defined(MBEDTLS_THREADING_C) |
935 | | /* We need to set status as success, otherwise CORRUPTION_DETECTED |
936 | | * would be returned if the lock fails. */ |
937 | 0 | status = PSA_SUCCESS; |
938 | 0 | PSA_THREADING_CHK_RET(mbedtls_mutex_lock( |
939 | 0 | &mbedtls_threading_key_slot_mutex)); |
940 | 0 | #endif |
941 | 0 | status = psa_unregister_read(slot); |
942 | 0 | #if defined(MBEDTLS_THREADING_C) |
943 | 0 | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
944 | 0 | &mbedtls_threading_key_slot_mutex)); |
945 | 0 | #endif |
946 | 0 | return status; |
947 | 0 | } |
948 | | |
949 | | psa_status_t psa_validate_key_location(psa_key_lifetime_t lifetime, |
950 | | psa_se_drv_table_entry_t **p_drv) |
951 | 0 | { |
952 | 0 | if (psa_key_lifetime_is_external(lifetime)) { |
953 | 0 | #if defined(MBEDTLS_PSA_CRYPTO_SE_C) |
954 | | /* Check whether a driver is registered against this lifetime */ |
955 | 0 | psa_se_drv_table_entry_t *driver = psa_get_se_driver_entry(lifetime); |
956 | 0 | if (driver != NULL) { |
957 | 0 | if (p_drv != NULL) { |
958 | 0 | *p_drv = driver; |
959 | 0 | } |
960 | 0 | return PSA_SUCCESS; |
961 | 0 | } |
962 | | #else /* MBEDTLS_PSA_CRYPTO_SE_C */ |
963 | | (void) p_drv; |
964 | | #endif /* MBEDTLS_PSA_CRYPTO_SE_C */ |
965 | | |
966 | | /* Key location for external keys gets checked by the wrapper */ |
967 | 0 | return PSA_SUCCESS; |
968 | 0 | } else { |
969 | | /* Local/internal keys are always valid */ |
970 | 0 | return PSA_SUCCESS; |
971 | 0 | } |
972 | 0 | } |
973 | | |
974 | | psa_status_t psa_validate_key_persistence(psa_key_lifetime_t lifetime) |
975 | 0 | { |
976 | 0 | if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) { |
977 | | /* Volatile keys are always supported */ |
978 | 0 | return PSA_SUCCESS; |
979 | 0 | } else { |
980 | | /* Persistent keys require storage support */ |
981 | 0 | #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) |
982 | 0 | if (PSA_KEY_LIFETIME_IS_READ_ONLY(lifetime)) { |
983 | 0 | return PSA_ERROR_INVALID_ARGUMENT; |
984 | 0 | } else { |
985 | 0 | return PSA_SUCCESS; |
986 | 0 | } |
987 | | #else /* MBEDTLS_PSA_CRYPTO_STORAGE_C */ |
988 | | return PSA_ERROR_NOT_SUPPORTED; |
989 | | #endif /* !MBEDTLS_PSA_CRYPTO_STORAGE_C */ |
990 | 0 | } |
991 | 0 | } |
992 | | |
993 | | psa_status_t psa_open_key(mbedtls_svc_key_id_t key, psa_key_handle_t *handle) |
994 | 0 | { |
995 | 0 | #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) || \ |
996 | 0 | defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS) |
997 | 0 | psa_status_t status; |
998 | 0 | psa_key_slot_t *slot; |
999 | |
|
1000 | 0 | status = psa_get_and_lock_key_slot(key, &slot); |
1001 | 0 | if (status != PSA_SUCCESS) { |
1002 | 0 | *handle = PSA_KEY_HANDLE_INIT; |
1003 | 0 | if (status == PSA_ERROR_INVALID_HANDLE) { |
1004 | 0 | status = PSA_ERROR_DOES_NOT_EXIST; |
1005 | 0 | } |
1006 | |
|
1007 | 0 | return status; |
1008 | 0 | } |
1009 | | |
1010 | 0 | *handle = key; |
1011 | |
|
1012 | 0 | return psa_unregister_read_under_mutex(slot); |
1013 | |
|
1014 | | #else /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ |
1015 | | (void) key; |
1016 | | *handle = PSA_KEY_HANDLE_INIT; |
1017 | | return PSA_ERROR_NOT_SUPPORTED; |
1018 | | #endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ |
1019 | 0 | } |
1020 | | |
1021 | | psa_status_t psa_close_key(psa_key_handle_t handle) |
1022 | 0 | { |
1023 | 0 | psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; |
1024 | 0 | psa_key_slot_t *slot; |
1025 | |
|
1026 | 0 | if (psa_key_handle_is_null(handle)) { |
1027 | 0 | return PSA_SUCCESS; |
1028 | 0 | } |
1029 | | |
1030 | 0 | #if defined(MBEDTLS_THREADING_C) |
1031 | | /* We need to set status as success, otherwise CORRUPTION_DETECTED |
1032 | | * would be returned if the lock fails. */ |
1033 | 0 | status = PSA_SUCCESS; |
1034 | 0 | PSA_THREADING_CHK_RET(mbedtls_mutex_lock( |
1035 | 0 | &mbedtls_threading_key_slot_mutex)); |
1036 | 0 | #endif |
1037 | 0 | status = psa_get_and_lock_key_slot_in_memory(handle, &slot); |
1038 | 0 | if (status != PSA_SUCCESS) { |
1039 | 0 | if (status == PSA_ERROR_DOES_NOT_EXIST) { |
1040 | 0 | status = PSA_ERROR_INVALID_HANDLE; |
1041 | 0 | } |
1042 | 0 | #if defined(MBEDTLS_THREADING_C) |
1043 | 0 | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
1044 | 0 | &mbedtls_threading_key_slot_mutex)); |
1045 | 0 | #endif |
1046 | 0 | return status; |
1047 | 0 | } |
1048 | | |
1049 | 0 | if (slot->var.occupied.registered_readers == 1) { |
1050 | 0 | status = psa_wipe_key_slot(slot); |
1051 | 0 | } else { |
1052 | 0 | status = psa_unregister_read(slot); |
1053 | 0 | } |
1054 | 0 | #if defined(MBEDTLS_THREADING_C) |
1055 | 0 | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
1056 | 0 | &mbedtls_threading_key_slot_mutex)); |
1057 | 0 | #endif |
1058 | |
|
1059 | 0 | return status; |
1060 | 0 | } |
1061 | | |
1062 | | psa_status_t psa_purge_key(mbedtls_svc_key_id_t key) |
1063 | 0 | { |
1064 | 0 | psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; |
1065 | 0 | psa_key_slot_t *slot; |
1066 | |
|
1067 | 0 | #if defined(MBEDTLS_THREADING_C) |
1068 | | /* We need to set status as success, otherwise CORRUPTION_DETECTED |
1069 | | * would be returned if the lock fails. */ |
1070 | 0 | status = PSA_SUCCESS; |
1071 | 0 | PSA_THREADING_CHK_RET(mbedtls_mutex_lock( |
1072 | 0 | &mbedtls_threading_key_slot_mutex)); |
1073 | 0 | #endif |
1074 | 0 | status = psa_get_and_lock_key_slot_in_memory(key, &slot); |
1075 | 0 | if (status != PSA_SUCCESS) { |
1076 | 0 | #if defined(MBEDTLS_THREADING_C) |
1077 | 0 | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
1078 | 0 | &mbedtls_threading_key_slot_mutex)); |
1079 | 0 | #endif |
1080 | 0 | return status; |
1081 | 0 | } |
1082 | | |
1083 | 0 | if ((!PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) && |
1084 | 0 | (slot->var.occupied.registered_readers == 1)) { |
1085 | 0 | status = psa_wipe_key_slot(slot); |
1086 | 0 | } else { |
1087 | 0 | status = psa_unregister_read(slot); |
1088 | 0 | } |
1089 | 0 | #if defined(MBEDTLS_THREADING_C) |
1090 | 0 | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
1091 | 0 | &mbedtls_threading_key_slot_mutex)); |
1092 | 0 | #endif |
1093 | |
|
1094 | 0 | return status; |
1095 | 0 | } |
1096 | | |
1097 | | void mbedtls_psa_get_stats(mbedtls_psa_stats_t *stats) |
1098 | 0 | { |
1099 | 0 | memset(stats, 0, sizeof(*stats)); |
1100 | |
|
1101 | 0 | for (size_t slice_idx = 0; slice_idx < KEY_SLICE_COUNT; slice_idx++) { |
1102 | 0 | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
1103 | 0 | if (global_data.key_slices[slice_idx] == NULL) { |
1104 | 0 | continue; |
1105 | 0 | } |
1106 | 0 | #endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
1107 | 0 | for (size_t slot_idx = 0; slot_idx < key_slice_length(slice_idx); slot_idx++) { |
1108 | 0 | const psa_key_slot_t *slot = get_key_slot(slice_idx, slot_idx); |
1109 | 0 | if (slot->state == PSA_SLOT_EMPTY) { |
1110 | 0 | ++stats->empty_slots; |
1111 | 0 | continue; |
1112 | 0 | } |
1113 | 0 | if (psa_key_slot_has_readers(slot)) { |
1114 | 0 | ++stats->locked_slots; |
1115 | 0 | } |
1116 | 0 | if (PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) { |
1117 | 0 | ++stats->volatile_slots; |
1118 | 0 | } else { |
1119 | 0 | psa_key_id_t id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id); |
1120 | 0 | ++stats->persistent_slots; |
1121 | 0 | if (id > stats->max_open_internal_key_id) { |
1122 | 0 | stats->max_open_internal_key_id = id; |
1123 | 0 | } |
1124 | 0 | } |
1125 | 0 | if (PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime) != |
1126 | 0 | PSA_KEY_LOCATION_LOCAL_STORAGE) { |
1127 | 0 | psa_key_id_t id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id); |
1128 | 0 | ++stats->external_slots; |
1129 | 0 | if (id > stats->max_open_external_key_id) { |
1130 | 0 | stats->max_open_external_key_id = id; |
1131 | 0 | } |
1132 | 0 | } |
1133 | 0 | } |
1134 | 0 | } |
1135 | 0 | } |
1136 | | |
1137 | | #endif /* MBEDTLS_PSA_CRYPTO_C */ |