/src/mbedtls/library/psa_crypto_slot_management.c
Line | Count | Source (jump to first uncovered line) |
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 | 45 | #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 | 3.84k | #define KEY_ID_SLOT_INDEX_WIDTH 25u |
92 | 1.50k | #define KEY_ID_SLICE_INDEX_WIDTH 5u |
93 | | |
94 | 3.99k | #define KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH 16u |
95 | 8.94k | #define KEY_SLOT_VOLATILE_SLICE_COUNT 22u |
96 | 0 | #define KEY_SLICE_COUNT (KEY_SLOT_VOLATILE_SLICE_COUNT + 1u) |
97 | 4.95k | #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 | 826 | { |
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 | 826 | return (psa_key_id_t) (0x40000000u | |
136 | 826 | (slice_idx << KEY_ID_SLOT_INDEX_WIDTH) | |
137 | 826 | slot_idx); |
138 | 826 | } |
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 | 1.50k | { |
144 | 1.50k | size_t mask = (1LU << KEY_ID_SLICE_INDEX_WIDTH) - 1; |
145 | 1.50k | return (key_id >> KEY_ID_SLOT_INDEX_WIDTH) & mask; |
146 | 1.50k | } |
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 | 1.50k | { |
152 | 1.50k | return key_id & ((1LU << KEY_ID_SLOT_INDEX_WIDTH) - 1); |
153 | 1.50k | } |
154 | | |
155 | | /* In global_data.first_free_slot_index, use this special value to |
156 | | * indicate that the slice is full. */ |
157 | 826 | #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 | | { |
162 | | return KEY_SLOT_VOLATILE_SLICE_COUNT; |
163 | | } |
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 | 2.37k | { |
197 | 2.37k | uint8_t initialized; |
198 | | |
199 | | #if defined(MBEDTLS_THREADING_C) |
200 | | mbedtls_mutex_lock(&mbedtls_threading_psa_globaldata_mutex); |
201 | | #endif /* defined(MBEDTLS_THREADING_C) */ |
202 | | |
203 | 2.37k | initialized = global_data.key_slots_initialized; |
204 | | |
205 | | #if defined(MBEDTLS_THREADING_C) |
206 | | mbedtls_mutex_unlock(&mbedtls_threading_psa_globaldata_mutex); |
207 | | #endif /* defined(MBEDTLS_THREADING_C) */ |
208 | | |
209 | 2.37k | return initialized; |
210 | 2.37k | } |
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.99k | { |
261 | 3.99k | if (slice_idx == KEY_SLOT_CACHE_SLICE_INDEX) { |
262 | 0 | return PERSISTENT_KEY_CACHE_COUNT; |
263 | 3.99k | } else { |
264 | | #if defined(MBEDTLS_TEST_HOOKS) |
265 | | if (mbedtls_test_hook_psa_volatile_key_slice_length != NULL) { |
266 | | return mbedtls_test_hook_psa_volatile_key_slice_length(slice_idx); |
267 | | } |
268 | | #endif |
269 | 3.99k | return KEY_SLOT_VOLATILE_SLICE_BASE_LENGTH << slice_idx; |
270 | 3.99k | } |
271 | 3.99k | } |
272 | | |
273 | | static inline psa_key_slot_t *get_volatile_key_slot(psa_key_id_t key_id) |
274 | 1.50k | { |
275 | 1.50k | size_t slice_idx = slice_index_of_volatile_key_id(key_id); |
276 | 1.50k | if (slice_idx >= KEY_SLOT_VOLATILE_SLICE_COUNT) { |
277 | 0 | return NULL; |
278 | 0 | } |
279 | 1.50k | size_t slot_idx = slot_index_of_volatile_key_id(key_id); |
280 | 1.50k | if (slot_idx >= key_slice_length(slice_idx)) { |
281 | 0 | return NULL; |
282 | 0 | } |
283 | 1.50k | psa_key_slot_t *slice = global_data.key_slices[slice_idx]; |
284 | 1.50k | if (slice == NULL) { |
285 | 0 | return NULL; |
286 | 0 | } |
287 | 1.50k | return &slice[slot_idx]; |
288 | 1.50k | } |
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 | 35 | { |
297 | 35 | return &global_data.key_slices[slice_idx][slot_idx]; |
298 | 35 | } |
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 | 1.50k | { |
386 | 1.50k | psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; |
387 | 1.50k | psa_key_id_t key_id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(key); |
388 | 1.50k | size_t slot_idx; |
389 | 1.50k | psa_key_slot_t *slot = NULL; |
390 | | |
391 | 1.50k | if (psa_key_id_is_volatile(key_id)) { |
392 | 1.50k | 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 | 1.50k | if (slot != NULL && |
397 | 1.50k | slot->state == PSA_SLOT_FULL && |
398 | 1.50k | mbedtls_svc_key_id_equal(key, slot->attr.id)) { |
399 | 1.47k | status = PSA_SUCCESS; |
400 | 1.47k | } else { |
401 | 35 | status = PSA_ERROR_DOES_NOT_EXIST; |
402 | 35 | } |
403 | 1.50k | } 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 | 1.50k | if (status == PSA_SUCCESS) { |
421 | 1.47k | status = psa_register_read(slot); |
422 | 1.47k | if (status == PSA_SUCCESS) { |
423 | 1.47k | *p_slot = slot; |
424 | 1.47k | } |
425 | 1.47k | } |
426 | | |
427 | 1.50k | return status; |
428 | 1.50k | } |
429 | | |
430 | | psa_status_t psa_initialize_key_slots(void) |
431 | 10 | { |
432 | 10 | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
433 | 10 | global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX] = |
434 | 10 | mbedtls_calloc(PERSISTENT_KEY_CACHE_COUNT, |
435 | 10 | sizeof(*global_data.key_slices[KEY_SLOT_CACHE_SLICE_INDEX])); |
436 | 10 | 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 | 10 | global_data.key_slots_initialized = 1; |
448 | 10 | return PSA_SUCCESS; |
449 | 10 | } |
450 | | |
451 | | void psa_wipe_all_key_slots(void) |
452 | 0 | { |
453 | 0 | for (size_t slice_idx = 0; slice_idx < KEY_SLICE_COUNT; slice_idx++) { |
454 | 0 | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
455 | 0 | if (global_data.key_slices[slice_idx] == NULL) { |
456 | 0 | continue; |
457 | 0 | } |
458 | 0 | #endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
459 | 0 | for (size_t slot_idx = 0; slot_idx < key_slice_length(slice_idx); slot_idx++) { |
460 | 0 | psa_key_slot_t *slot = get_key_slot(slice_idx, slot_idx); |
461 | 0 | #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 | 0 | if (slot->state == PSA_SLOT_EMPTY) { |
476 | 0 | continue; |
477 | 0 | } |
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 | 0 | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
484 | 0 | mbedtls_free(global_data.key_slices[slice_idx]); |
485 | 0 | global_data.key_slices[slice_idx] = NULL; |
486 | 0 | #endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
487 | 0 | } |
488 | |
|
489 | 0 | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
490 | 0 | for (size_t slice_idx = 0; slice_idx < KEY_SLOT_VOLATILE_SLICE_COUNT; slice_idx++) { |
491 | 0 | global_data.first_free_slot_index[slice_idx] = 0; |
492 | 0 | } |
493 | 0 | #endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
494 | | |
495 | | /* The global data mutex is already held when calling this function. */ |
496 | 0 | global_data.key_slots_initialized = 0; |
497 | 0 | } |
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 | 826 | { |
504 | 826 | size_t slice_idx; |
505 | 826 | for (slice_idx = 0; slice_idx < KEY_SLOT_VOLATILE_SLICE_COUNT; slice_idx++) { |
506 | 826 | if (global_data.first_free_slot_index[slice_idx] != FREE_SLOT_INDEX_NONE) { |
507 | 826 | break; |
508 | 826 | } |
509 | 826 | } |
510 | 826 | if (slice_idx == KEY_SLOT_VOLATILE_SLICE_COUNT) { |
511 | 0 | return PSA_ERROR_INSUFFICIENT_MEMORY; |
512 | 0 | } |
513 | | |
514 | 826 | if (global_data.key_slices[slice_idx] == NULL) { |
515 | 5 | global_data.key_slices[slice_idx] = |
516 | 5 | mbedtls_calloc(key_slice_length(slice_idx), |
517 | 5 | sizeof(psa_key_slot_t)); |
518 | 5 | if (global_data.key_slices[slice_idx] == NULL) { |
519 | 0 | return PSA_ERROR_INSUFFICIENT_MEMORY; |
520 | 0 | } |
521 | 5 | } |
522 | 826 | psa_key_slot_t *slice = global_data.key_slices[slice_idx]; |
523 | | |
524 | 826 | size_t slot_idx = global_data.first_free_slot_index[slice_idx]; |
525 | 826 | *key_id = volatile_key_id_of_index(slice_idx, slot_idx); |
526 | | |
527 | 826 | psa_key_slot_t *slot = &slice[slot_idx]; |
528 | 826 | size_t next_free = slot_idx + 1 + slot->var.free.next_free_relative_to_next; |
529 | 826 | if (next_free >= key_slice_length(slice_idx)) { |
530 | 0 | next_free = FREE_SLOT_INDEX_NONE; |
531 | 0 | } |
532 | 826 | 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 | 826 | slot->var.free.next_free_relative_to_next = 0; |
536 | | |
537 | 826 | psa_status_t status = psa_key_slot_state_transition(slot, |
538 | 826 | PSA_SLOT_EMPTY, |
539 | 826 | PSA_SLOT_FILLING); |
540 | 826 | 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 | 826 | *p_slot = slot; |
550 | | /* We assert at compile time that the slice index fits in uint8_t. */ |
551 | 826 | slot->slice_index = (uint8_t) slice_idx; |
552 | 826 | return PSA_SUCCESS; |
553 | 826 | } |
554 | | |
555 | | psa_status_t psa_free_key_slot(size_t slice_idx, |
556 | | psa_key_slot_t *slot) |
557 | 861 | { |
558 | | |
559 | 861 | 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 | 35 | return PSA_SUCCESS; |
563 | 35 | } |
564 | 826 | if (slice_idx >= KEY_SLOT_VOLATILE_SLICE_COUNT) { |
565 | 0 | return PSA_ERROR_CORRUPTION_DETECTED; |
566 | 0 | } |
567 | | |
568 | 826 | psa_key_slot_t *slice = global_data.key_slices[slice_idx]; |
569 | 826 | psa_key_slot_t *slice_end = slice + key_slice_length(slice_idx); |
570 | 826 | 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 | 826 | size_t slot_idx = slot - slice; |
580 | | |
581 | 826 | size_t next_free = global_data.first_free_slot_index[slice_idx]; |
582 | 826 | 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 | 826 | global_data.first_free_slot_index[slice_idx] = slot_idx; |
588 | 826 | slot->var.free.next_free_relative_to_next = |
589 | 826 | (int32_t) next_free - (int32_t) slot_idx - 1; |
590 | | |
591 | 826 | return PSA_SUCCESS; |
592 | 826 | } |
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 | 861 | { |
598 | 861 | psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; |
599 | 861 | size_t slot_idx; |
600 | 861 | psa_key_slot_t *selected_slot, *unused_persistent_key_slot; |
601 | | |
602 | 861 | if (!psa_get_key_slots_initialized()) { |
603 | 0 | status = PSA_ERROR_BAD_STATE; |
604 | 0 | goto error; |
605 | 0 | } |
606 | | |
607 | 861 | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
608 | 861 | if (volatile_key_id != NULL) { |
609 | 826 | return psa_allocate_volatile_key_slot(volatile_key_id, p_slot); |
610 | 826 | } |
611 | 35 | #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 | 35 | selected_slot = unused_persistent_key_slot = NULL; |
618 | 35 | for (slot_idx = 0; slot_idx < PERSISTENT_KEY_CACHE_COUNT; slot_idx++) { |
619 | 35 | psa_key_slot_t *slot = get_key_slot(KEY_SLOT_CACHE_SLICE_INDEX, slot_idx); |
620 | 35 | if (slot->state == PSA_SLOT_EMPTY) { |
621 | 35 | selected_slot = slot; |
622 | 35 | break; |
623 | 35 | } |
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 | 35 | if ((selected_slot == NULL) && |
641 | 35 | (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 | 35 | if (selected_slot != NULL) { |
651 | 35 | status = psa_key_slot_state_transition(selected_slot, PSA_SLOT_EMPTY, |
652 | 35 | PSA_SLOT_FILLING); |
653 | 35 | if (status != PSA_SUCCESS) { |
654 | 0 | goto error; |
655 | 0 | } |
656 | | |
657 | 35 | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
658 | 35 | selected_slot->slice_index = KEY_SLOT_CACHE_SLICE_INDEX; |
659 | 35 | #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 + slot_idx; |
667 | | } |
668 | | #endif |
669 | 35 | *p_slot = selected_slot; |
670 | | |
671 | 35 | return PSA_SUCCESS; |
672 | 35 | } |
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 | 35 | { |
684 | 35 | psa_status_t status = PSA_SUCCESS; |
685 | 35 | uint8_t *key_data = NULL; |
686 | 35 | size_t key_data_length = 0; |
687 | | |
688 | 35 | status = psa_load_persistent_key(&slot->attr, |
689 | 35 | &key_data, &key_data_length); |
690 | 35 | if (status != PSA_SUCCESS) { |
691 | 35 | goto exit; |
692 | 35 | } |
693 | | |
694 | | #if defined(MBEDTLS_PSA_CRYPTO_SE_C) |
695 | | /* Special handling is required for loading keys associated with a |
696 | | * dynamically registered SE interface. */ |
697 | | const psa_drv_se_t *drv; |
698 | | psa_drv_se_context_t *drv_context; |
699 | | if (psa_get_se_driver(slot->attr.lifetime, &drv, &drv_context)) { |
700 | | psa_se_key_data_storage_t *data; |
701 | | |
702 | | if (key_data_length != sizeof(*data)) { |
703 | | status = PSA_ERROR_DATA_INVALID; |
704 | | goto exit; |
705 | | } |
706 | | data = (psa_se_key_data_storage_t *) key_data; |
707 | | status = psa_copy_key_material_into_slot( |
708 | | slot, data->slot_number, sizeof(data->slot_number)); |
709 | | goto exit; |
710 | | } |
711 | | #endif /* MBEDTLS_PSA_CRYPTO_SE_C */ |
712 | | |
713 | 0 | status = psa_copy_key_material_into_slot(slot, key_data, key_data_length); |
714 | 0 | if (status != PSA_SUCCESS) { |
715 | 0 | goto exit; |
716 | 0 | } |
717 | | |
718 | 35 | exit: |
719 | 35 | psa_free_persistent_key_data(key_data, key_data_length); |
720 | 35 | return status; |
721 | 0 | } |
722 | | #endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */ |
723 | | |
724 | | #if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS) |
725 | | |
726 | | static psa_status_t psa_load_builtin_key_into_slot(psa_key_slot_t *slot) |
727 | | { |
728 | | psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; |
729 | | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
730 | | psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_VOLATILE; |
731 | | psa_drv_slot_number_t slot_number = 0; |
732 | | size_t key_buffer_size = 0; |
733 | | size_t key_buffer_length = 0; |
734 | | |
735 | | if (!psa_key_id_is_builtin( |
736 | | MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id))) { |
737 | | return PSA_ERROR_DOES_NOT_EXIST; |
738 | | } |
739 | | |
740 | | /* Check the platform function to see whether this key actually exists */ |
741 | | status = mbedtls_psa_platform_get_builtin_key( |
742 | | slot->attr.id, &lifetime, &slot_number); |
743 | | if (status != PSA_SUCCESS) { |
744 | | return status; |
745 | | } |
746 | | |
747 | | /* Set required key attributes to ensure get_builtin_key can retrieve the |
748 | | * full attributes. */ |
749 | | psa_set_key_id(&attributes, slot->attr.id); |
750 | | psa_set_key_lifetime(&attributes, lifetime); |
751 | | |
752 | | /* Get the full key attributes from the driver in order to be able to |
753 | | * calculate the required buffer size. */ |
754 | | status = psa_driver_wrapper_get_builtin_key( |
755 | | slot_number, &attributes, |
756 | | NULL, 0, NULL); |
757 | | if (status != PSA_ERROR_BUFFER_TOO_SMALL) { |
758 | | /* Builtin keys cannot be defined by the attributes alone */ |
759 | | if (status == PSA_SUCCESS) { |
760 | | status = PSA_ERROR_CORRUPTION_DETECTED; |
761 | | } |
762 | | return status; |
763 | | } |
764 | | |
765 | | /* If the key should exist according to the platform, then ask the driver |
766 | | * what its expected size is. */ |
767 | | status = psa_driver_wrapper_get_key_buffer_size(&attributes, |
768 | | &key_buffer_size); |
769 | | if (status != PSA_SUCCESS) { |
770 | | return status; |
771 | | } |
772 | | |
773 | | /* Allocate a buffer of the required size and load the builtin key directly |
774 | | * into the (now properly sized) slot buffer. */ |
775 | | status = psa_allocate_buffer_to_slot(slot, key_buffer_size); |
776 | | if (status != PSA_SUCCESS) { |
777 | | return status; |
778 | | } |
779 | | |
780 | | status = psa_driver_wrapper_get_builtin_key( |
781 | | slot_number, &attributes, |
782 | | slot->key.data, slot->key.bytes, &key_buffer_length); |
783 | | if (status != PSA_SUCCESS) { |
784 | | goto exit; |
785 | | } |
786 | | |
787 | | /* Copy actual key length and core attributes into the slot on success */ |
788 | | slot->key.bytes = key_buffer_length; |
789 | | slot->attr = attributes; |
790 | | exit: |
791 | | if (status != PSA_SUCCESS) { |
792 | | psa_remove_key_data_from_memory(slot); |
793 | | } |
794 | | return status; |
795 | | } |
796 | | #endif /* MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ |
797 | | |
798 | | psa_status_t psa_get_and_lock_key_slot(mbedtls_svc_key_id_t key, |
799 | | psa_key_slot_t **p_slot) |
800 | 1.50k | { |
801 | 1.50k | psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; |
802 | | |
803 | 1.50k | *p_slot = NULL; |
804 | 1.50k | if (!psa_get_key_slots_initialized()) { |
805 | 0 | return PSA_ERROR_BAD_STATE; |
806 | 0 | } |
807 | | |
808 | | #if defined(MBEDTLS_THREADING_C) |
809 | | /* We need to set status as success, otherwise CORRUPTION_DETECTED |
810 | | * would be returned if the lock fails. */ |
811 | | status = PSA_SUCCESS; |
812 | | /* If the key is persistent and not loaded, we cannot unlock the mutex |
813 | | * between checking if the key is loaded and setting the slot as FULL, |
814 | | * as otherwise another thread may load and then destroy the key |
815 | | * in the meantime. */ |
816 | | PSA_THREADING_CHK_RET(mbedtls_mutex_lock( |
817 | | &mbedtls_threading_key_slot_mutex)); |
818 | | #endif |
819 | | /* |
820 | | * On success, the pointer to the slot is passed directly to the caller |
821 | | * thus no need to unlock the key slot here. |
822 | | */ |
823 | 1.50k | status = psa_get_and_lock_key_slot_in_memory(key, p_slot); |
824 | 1.50k | if (status != PSA_ERROR_DOES_NOT_EXIST) { |
825 | | #if defined(MBEDTLS_THREADING_C) |
826 | | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
827 | | &mbedtls_threading_key_slot_mutex)); |
828 | | #endif |
829 | 1.47k | return status; |
830 | 1.47k | } |
831 | | |
832 | | /* Loading keys from storage requires support for such a mechanism */ |
833 | 35 | #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) || \ |
834 | 35 | defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS) |
835 | | |
836 | 35 | status = psa_reserve_free_key_slot(NULL, p_slot); |
837 | 35 | if (status != PSA_SUCCESS) { |
838 | | #if defined(MBEDTLS_THREADING_C) |
839 | | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
840 | | &mbedtls_threading_key_slot_mutex)); |
841 | | #endif |
842 | 0 | return status; |
843 | 0 | } |
844 | | |
845 | 35 | (*p_slot)->attr.id = key; |
846 | 35 | (*p_slot)->attr.lifetime = PSA_KEY_LIFETIME_PERSISTENT; |
847 | | |
848 | 35 | status = PSA_ERROR_DOES_NOT_EXIST; |
849 | | #if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS) |
850 | | /* Load keys in the 'builtin' range through their own interface */ |
851 | | status = psa_load_builtin_key_into_slot(*p_slot); |
852 | | #endif /* MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ |
853 | | |
854 | 35 | #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) |
855 | 35 | if (status == PSA_ERROR_DOES_NOT_EXIST) { |
856 | 35 | status = psa_load_persistent_key_into_slot(*p_slot); |
857 | 35 | } |
858 | 35 | #endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */ |
859 | | |
860 | 35 | if (status != PSA_SUCCESS) { |
861 | 35 | psa_wipe_key_slot(*p_slot); |
862 | | |
863 | | /* If the key does not exist, we need to return |
864 | | * PSA_ERROR_INVALID_HANDLE. */ |
865 | 35 | if (status == PSA_ERROR_DOES_NOT_EXIST) { |
866 | 35 | status = PSA_ERROR_INVALID_HANDLE; |
867 | 35 | } |
868 | 35 | } else { |
869 | | /* Add implicit usage flags. */ |
870 | 0 | psa_extend_key_usage_flags(&(*p_slot)->attr.policy.usage); |
871 | |
|
872 | 0 | psa_key_slot_state_transition((*p_slot), PSA_SLOT_FILLING, |
873 | 0 | PSA_SLOT_FULL); |
874 | 0 | status = psa_register_read(*p_slot); |
875 | 0 | } |
876 | | |
877 | | #else /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ |
878 | | status = PSA_ERROR_INVALID_HANDLE; |
879 | | #endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ |
880 | | |
881 | 35 | if (status != PSA_SUCCESS) { |
882 | 35 | *p_slot = NULL; |
883 | 35 | } |
884 | | #if defined(MBEDTLS_THREADING_C) |
885 | | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
886 | | &mbedtls_threading_key_slot_mutex)); |
887 | | #endif |
888 | 35 | return status; |
889 | 35 | } |
890 | | |
891 | | psa_status_t psa_unregister_read(psa_key_slot_t *slot) |
892 | 1.47k | { |
893 | 1.47k | if (slot == NULL) { |
894 | 0 | return PSA_SUCCESS; |
895 | 0 | } |
896 | 1.47k | if ((slot->state != PSA_SLOT_FULL) && |
897 | 1.47k | (slot->state != PSA_SLOT_PENDING_DELETION)) { |
898 | 0 | return PSA_ERROR_CORRUPTION_DETECTED; |
899 | 0 | } |
900 | | |
901 | | /* If we are the last reader and the slot is marked for deletion, |
902 | | * we must wipe the slot here. */ |
903 | 1.47k | if ((slot->state == PSA_SLOT_PENDING_DELETION) && |
904 | 1.47k | (slot->var.occupied.registered_readers == 1)) { |
905 | 826 | return psa_wipe_key_slot(slot); |
906 | 826 | } |
907 | | |
908 | 648 | if (psa_key_slot_has_readers(slot)) { |
909 | 648 | slot->var.occupied.registered_readers--; |
910 | 648 | return PSA_SUCCESS; |
911 | 648 | } |
912 | | |
913 | | /* |
914 | | * As the return error code may not be handled in case of multiple errors, |
915 | | * do our best to report if there are no registered readers. Assert with |
916 | | * MBEDTLS_TEST_HOOK_TEST_ASSERT that there are registered readers: |
917 | | * if the MBEDTLS_TEST_HOOKS configuration option is enabled and |
918 | | * the function is called as part of the execution of a test suite, the |
919 | | * execution of the test suite is stopped in error if the assertion fails. |
920 | | */ |
921 | 0 | MBEDTLS_TEST_HOOK_TEST_ASSERT(psa_key_slot_has_readers(slot)); |
922 | 0 | return PSA_ERROR_CORRUPTION_DETECTED; |
923 | 648 | } |
924 | | |
925 | | psa_status_t psa_unregister_read_under_mutex(psa_key_slot_t *slot) |
926 | 648 | { |
927 | 648 | psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; |
928 | | #if defined(MBEDTLS_THREADING_C) |
929 | | /* We need to set status as success, otherwise CORRUPTION_DETECTED |
930 | | * would be returned if the lock fails. */ |
931 | | status = PSA_SUCCESS; |
932 | | PSA_THREADING_CHK_RET(mbedtls_mutex_lock( |
933 | | &mbedtls_threading_key_slot_mutex)); |
934 | | #endif |
935 | 648 | status = psa_unregister_read(slot); |
936 | | #if defined(MBEDTLS_THREADING_C) |
937 | | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
938 | | &mbedtls_threading_key_slot_mutex)); |
939 | | #endif |
940 | 648 | return status; |
941 | 648 | } |
942 | | |
943 | | psa_status_t psa_validate_key_location(psa_key_lifetime_t lifetime, |
944 | | psa_se_drv_table_entry_t **p_drv) |
945 | 826 | { |
946 | 826 | if (psa_key_lifetime_is_external(lifetime)) { |
947 | | #if defined(MBEDTLS_PSA_CRYPTO_SE_C) |
948 | | /* Check whether a driver is registered against this lifetime */ |
949 | | psa_se_drv_table_entry_t *driver = psa_get_se_driver_entry(lifetime); |
950 | | if (driver != NULL) { |
951 | | if (p_drv != NULL) { |
952 | | *p_drv = driver; |
953 | | } |
954 | | return PSA_SUCCESS; |
955 | | } |
956 | | #else /* MBEDTLS_PSA_CRYPTO_SE_C */ |
957 | 0 | (void) p_drv; |
958 | 0 | #endif /* MBEDTLS_PSA_CRYPTO_SE_C */ |
959 | | |
960 | | /* Key location for external keys gets checked by the wrapper */ |
961 | 0 | return PSA_SUCCESS; |
962 | 826 | } else { |
963 | | /* Local/internal keys are always valid */ |
964 | 826 | return PSA_SUCCESS; |
965 | 826 | } |
966 | 826 | } |
967 | | |
968 | | psa_status_t psa_validate_key_persistence(psa_key_lifetime_t lifetime) |
969 | 826 | { |
970 | 826 | if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) { |
971 | | /* Volatile keys are always supported */ |
972 | 826 | return PSA_SUCCESS; |
973 | 826 | } else { |
974 | | /* Persistent keys require storage support */ |
975 | 0 | #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) |
976 | 0 | if (PSA_KEY_LIFETIME_IS_READ_ONLY(lifetime)) { |
977 | 0 | return PSA_ERROR_INVALID_ARGUMENT; |
978 | 0 | } else { |
979 | 0 | return PSA_SUCCESS; |
980 | 0 | } |
981 | | #else /* MBEDTLS_PSA_CRYPTO_STORAGE_C */ |
982 | | return PSA_ERROR_NOT_SUPPORTED; |
983 | | #endif /* !MBEDTLS_PSA_CRYPTO_STORAGE_C */ |
984 | 0 | } |
985 | 826 | } |
986 | | |
987 | | psa_status_t psa_open_key(mbedtls_svc_key_id_t key, psa_key_handle_t *handle) |
988 | 0 | { |
989 | 0 | #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) || \ |
990 | 0 | defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS) |
991 | 0 | psa_status_t status; |
992 | 0 | psa_key_slot_t *slot; |
993 | |
|
994 | 0 | status = psa_get_and_lock_key_slot(key, &slot); |
995 | 0 | if (status != PSA_SUCCESS) { |
996 | 0 | *handle = PSA_KEY_HANDLE_INIT; |
997 | 0 | if (status == PSA_ERROR_INVALID_HANDLE) { |
998 | 0 | status = PSA_ERROR_DOES_NOT_EXIST; |
999 | 0 | } |
1000 | |
|
1001 | 0 | return status; |
1002 | 0 | } |
1003 | | |
1004 | 0 | *handle = key; |
1005 | |
|
1006 | 0 | return psa_unregister_read_under_mutex(slot); |
1007 | |
|
1008 | | #else /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ |
1009 | | (void) key; |
1010 | | *handle = PSA_KEY_HANDLE_INIT; |
1011 | | return PSA_ERROR_NOT_SUPPORTED; |
1012 | | #endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */ |
1013 | 0 | } |
1014 | | |
1015 | | psa_status_t psa_close_key(psa_key_handle_t handle) |
1016 | 0 | { |
1017 | 0 | psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; |
1018 | 0 | psa_key_slot_t *slot; |
1019 | |
|
1020 | 0 | if (psa_key_handle_is_null(handle)) { |
1021 | 0 | return PSA_SUCCESS; |
1022 | 0 | } |
1023 | | |
1024 | | #if defined(MBEDTLS_THREADING_C) |
1025 | | /* We need to set status as success, otherwise CORRUPTION_DETECTED |
1026 | | * would be returned if the lock fails. */ |
1027 | | status = PSA_SUCCESS; |
1028 | | PSA_THREADING_CHK_RET(mbedtls_mutex_lock( |
1029 | | &mbedtls_threading_key_slot_mutex)); |
1030 | | #endif |
1031 | 0 | status = psa_get_and_lock_key_slot_in_memory(handle, &slot); |
1032 | 0 | if (status != PSA_SUCCESS) { |
1033 | 0 | if (status == PSA_ERROR_DOES_NOT_EXIST) { |
1034 | 0 | status = PSA_ERROR_INVALID_HANDLE; |
1035 | 0 | } |
1036 | | #if defined(MBEDTLS_THREADING_C) |
1037 | | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
1038 | | &mbedtls_threading_key_slot_mutex)); |
1039 | | #endif |
1040 | 0 | return status; |
1041 | 0 | } |
1042 | | |
1043 | 0 | if (slot->var.occupied.registered_readers == 1) { |
1044 | 0 | status = psa_wipe_key_slot(slot); |
1045 | 0 | } else { |
1046 | 0 | status = psa_unregister_read(slot); |
1047 | 0 | } |
1048 | | #if defined(MBEDTLS_THREADING_C) |
1049 | | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
1050 | | &mbedtls_threading_key_slot_mutex)); |
1051 | | #endif |
1052 | |
|
1053 | 0 | return status; |
1054 | 0 | } |
1055 | | |
1056 | | psa_status_t psa_purge_key(mbedtls_svc_key_id_t key) |
1057 | 0 | { |
1058 | 0 | psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; |
1059 | 0 | psa_key_slot_t *slot; |
1060 | |
|
1061 | | #if defined(MBEDTLS_THREADING_C) |
1062 | | /* We need to set status as success, otherwise CORRUPTION_DETECTED |
1063 | | * would be returned if the lock fails. */ |
1064 | | status = PSA_SUCCESS; |
1065 | | PSA_THREADING_CHK_RET(mbedtls_mutex_lock( |
1066 | | &mbedtls_threading_key_slot_mutex)); |
1067 | | #endif |
1068 | 0 | status = psa_get_and_lock_key_slot_in_memory(key, &slot); |
1069 | 0 | if (status != PSA_SUCCESS) { |
1070 | | #if defined(MBEDTLS_THREADING_C) |
1071 | | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
1072 | | &mbedtls_threading_key_slot_mutex)); |
1073 | | #endif |
1074 | 0 | return status; |
1075 | 0 | } |
1076 | | |
1077 | 0 | if ((!PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) && |
1078 | 0 | (slot->var.occupied.registered_readers == 1)) { |
1079 | 0 | status = psa_wipe_key_slot(slot); |
1080 | 0 | } else { |
1081 | 0 | status = psa_unregister_read(slot); |
1082 | 0 | } |
1083 | | #if defined(MBEDTLS_THREADING_C) |
1084 | | PSA_THREADING_CHK_RET(mbedtls_mutex_unlock( |
1085 | | &mbedtls_threading_key_slot_mutex)); |
1086 | | #endif |
1087 | |
|
1088 | 0 | return status; |
1089 | 0 | } |
1090 | | |
1091 | | void mbedtls_psa_get_stats(mbedtls_psa_stats_t *stats) |
1092 | 0 | { |
1093 | 0 | memset(stats, 0, sizeof(*stats)); |
1094 | |
|
1095 | 0 | for (size_t slice_idx = 0; slice_idx < KEY_SLICE_COUNT; slice_idx++) { |
1096 | 0 | #if defined(MBEDTLS_PSA_KEY_STORE_DYNAMIC) |
1097 | 0 | if (global_data.key_slices[slice_idx] == NULL) { |
1098 | 0 | continue; |
1099 | 0 | } |
1100 | 0 | #endif /* MBEDTLS_PSA_KEY_STORE_DYNAMIC */ |
1101 | 0 | for (size_t slot_idx = 0; slot_idx < key_slice_length(slice_idx); slot_idx++) { |
1102 | 0 | const psa_key_slot_t *slot = get_key_slot(slice_idx, slot_idx); |
1103 | 0 | if (slot->state == PSA_SLOT_EMPTY) { |
1104 | 0 | ++stats->empty_slots; |
1105 | 0 | continue; |
1106 | 0 | } |
1107 | 0 | if (psa_key_slot_has_readers(slot)) { |
1108 | 0 | ++stats->locked_slots; |
1109 | 0 | } |
1110 | 0 | if (PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) { |
1111 | 0 | ++stats->volatile_slots; |
1112 | 0 | } else { |
1113 | 0 | psa_key_id_t id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id); |
1114 | 0 | ++stats->persistent_slots; |
1115 | 0 | if (id > stats->max_open_internal_key_id) { |
1116 | 0 | stats->max_open_internal_key_id = id; |
1117 | 0 | } |
1118 | 0 | } |
1119 | 0 | if (PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime) != |
1120 | 0 | PSA_KEY_LOCATION_LOCAL_STORAGE) { |
1121 | 0 | psa_key_id_t id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id); |
1122 | 0 | ++stats->external_slots; |
1123 | 0 | if (id > stats->max_open_external_key_id) { |
1124 | 0 | stats->max_open_external_key_id = id; |
1125 | 0 | } |
1126 | 0 | } |
1127 | 0 | } |
1128 | 0 | } |
1129 | 0 | } |
1130 | | |
1131 | | #endif /* MBEDTLS_PSA_CRYPTO_C */ |