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
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License"); you may
9 * not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 #include "common.h"
22
23 #if defined(MBEDTLS_PSA_CRYPTO_C)
24
25 #include "psa/crypto.h"
26
27 #include "psa_crypto_core.h"
28 #include "psa_crypto_driver_wrappers.h"
29 #include "psa_crypto_slot_management.h"
30 #include "psa_crypto_storage.h"
31 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
32 #include "psa_crypto_se.h"
33 #endif
34
35 #include <stdlib.h>
36 #include <string.h>
37 #if defined(MBEDTLS_PLATFORM_C)
38 #include "mbedtls/platform.h"
39 #else
40 #define mbedtls_calloc calloc
41 #define mbedtls_free free
42 #endif
43
44 #define ARRAY_LENGTH( array ) ( sizeof( array ) / sizeof( *( array ) ) )
45
46 typedef struct
47 {
48 psa_key_slot_t key_slots[MBEDTLS_PSA_KEY_SLOT_COUNT];
49 unsigned key_slots_initialized : 1;
50 } psa_global_data_t;
51
52 static psa_global_data_t global_data;
53
psa_is_valid_key_id(mbedtls_svc_key_id_t key,int vendor_ok)54 int psa_is_valid_key_id( mbedtls_svc_key_id_t key, int vendor_ok )
55 {
56 psa_key_id_t key_id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID( key );
57
58 if( ( PSA_KEY_ID_USER_MIN <= key_id ) &&
59 ( key_id <= PSA_KEY_ID_USER_MAX ) )
60 return( 1 );
61
62 if( vendor_ok &&
63 ( PSA_KEY_ID_VENDOR_MIN <= key_id ) &&
64 ( key_id <= PSA_KEY_ID_VENDOR_MAX ) )
65 return( 1 );
66
67 return( 0 );
68 }
69
70 /** Get the description in memory of a key given its identifier and lock it.
71 *
72 * The descriptions of volatile keys and loaded persistent keys are
73 * stored in key slots. This function returns a pointer to the key slot
74 * containing the description of a key given its identifier.
75 *
76 * The function searches the key slots containing the description of the key
77 * with \p key identifier. The function does only read accesses to the key
78 * slots. The function does not load any persistent key thus does not access
79 * any storage.
80 *
81 * For volatile key identifiers, only one key slot is queried as a volatile
82 * key with identifier key_id can only be stored in slot of index
83 * ( key_id - #PSA_KEY_ID_VOLATILE_MIN ).
84 *
85 * On success, the function locks the key slot. It is the responsibility of
86 * the caller to unlock the key slot when it does not access it anymore.
87 *
88 * \param key Key identifier to query.
89 * \param[out] p_slot On success, `*p_slot` contains a pointer to the
90 * key slot containing the description of the key
91 * identified by \p key.
92 *
93 * \retval #PSA_SUCCESS
94 * The pointer to the key slot containing the description of the key
95 * identified by \p key was returned.
96 * \retval #PSA_ERROR_INVALID_HANDLE
97 * \p key is not a valid key identifier.
98 * \retval #PSA_ERROR_DOES_NOT_EXIST
99 * There is no key with key identifier \p key in the key slots.
100 */
psa_get_and_lock_key_slot_in_memory(mbedtls_svc_key_id_t key,psa_key_slot_t ** p_slot)101 static psa_status_t psa_get_and_lock_key_slot_in_memory(
102 mbedtls_svc_key_id_t key, psa_key_slot_t **p_slot )
103 {
104 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
105 psa_key_id_t key_id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID( key );
106 size_t slot_idx;
107 psa_key_slot_t *slot = NULL;
108
109 if( psa_key_id_is_volatile( key_id ) )
110 {
111 slot = &global_data.key_slots[ key_id - PSA_KEY_ID_VOLATILE_MIN ];
112
113 /*
114 * Check if both the PSA key identifier key_id and the owner
115 * identifier of key match those of the key slot.
116 *
117 * Note that, if the key slot is not occupied, its PSA key identifier
118 * is equal to zero. This is an invalid value for a PSA key identifier
119 * and thus cannot be equal to the valid PSA key identifier key_id.
120 */
121 status = mbedtls_svc_key_id_equal( key, slot->attr.id ) ?
122 PSA_SUCCESS : PSA_ERROR_DOES_NOT_EXIST;
123 }
124 else
125 {
126 if ( !psa_is_valid_key_id( key, 1 ) )
127 return( PSA_ERROR_INVALID_HANDLE );
128
129 for( slot_idx = 0; slot_idx < MBEDTLS_PSA_KEY_SLOT_COUNT; slot_idx++ )
130 {
131 slot = &global_data.key_slots[ slot_idx ];
132 if( mbedtls_svc_key_id_equal( key, slot->attr.id ) )
133 break;
134 }
135 status = ( slot_idx < MBEDTLS_PSA_KEY_SLOT_COUNT ) ?
136 PSA_SUCCESS : PSA_ERROR_DOES_NOT_EXIST;
137 }
138
139 if( status == PSA_SUCCESS )
140 {
141 status = psa_lock_key_slot( slot );
142 if( status == PSA_SUCCESS )
143 *p_slot = slot;
144 }
145
146 return( status );
147 }
148
psa_initialize_key_slots(void)149 psa_status_t psa_initialize_key_slots( void )
150 {
151 /* Nothing to do: program startup and psa_wipe_all_key_slots() both
152 * guarantee that the key slots are initialized to all-zero, which
153 * means that all the key slots are in a valid, empty state. */
154 global_data.key_slots_initialized = 1;
155 return( PSA_SUCCESS );
156 }
157
psa_wipe_all_key_slots(void)158 void psa_wipe_all_key_slots( void )
159 {
160 size_t slot_idx;
161
162 for( slot_idx = 0; slot_idx < MBEDTLS_PSA_KEY_SLOT_COUNT; slot_idx++ )
163 {
164 psa_key_slot_t *slot = &global_data.key_slots[ slot_idx ];
165 slot->lock_count = 1;
166 (void) psa_wipe_key_slot( slot );
167 }
168 global_data.key_slots_initialized = 0;
169 }
170
psa_get_empty_key_slot(psa_key_id_t * volatile_key_id,psa_key_slot_t ** p_slot)171 psa_status_t psa_get_empty_key_slot( psa_key_id_t *volatile_key_id,
172 psa_key_slot_t **p_slot )
173 {
174 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
175 size_t slot_idx;
176 psa_key_slot_t *selected_slot, *unlocked_persistent_key_slot;
177
178 if( ! global_data.key_slots_initialized )
179 {
180 status = PSA_ERROR_BAD_STATE;
181 goto error;
182 }
183
184 selected_slot = unlocked_persistent_key_slot = NULL;
185 for( slot_idx = 0; slot_idx < MBEDTLS_PSA_KEY_SLOT_COUNT; slot_idx++ )
186 {
187 psa_key_slot_t *slot = &global_data.key_slots[ slot_idx ];
188 if( ! psa_is_key_slot_occupied( slot ) )
189 {
190 selected_slot = slot;
191 break;
192 }
193
194 if( ( unlocked_persistent_key_slot == NULL ) &&
195 ( ! PSA_KEY_LIFETIME_IS_VOLATILE( slot->attr.lifetime ) ) &&
196 ( ! psa_is_key_slot_locked( slot ) ) )
197 unlocked_persistent_key_slot = slot;
198 }
199
200 /*
201 * If there is no unused key slot and there is at least one unlocked key
202 * slot containing the description of a persistent key, recycle the first
203 * such key slot we encountered. If we later need to operate on the
204 * persistent key we are evicting now, we will reload its description from
205 * storage.
206 */
207 if( ( selected_slot == NULL ) &&
208 ( unlocked_persistent_key_slot != NULL ) )
209 {
210 selected_slot = unlocked_persistent_key_slot;
211 selected_slot->lock_count = 1;
212 psa_wipe_key_slot( selected_slot );
213 }
214
215 if( selected_slot != NULL )
216 {
217 status = psa_lock_key_slot( selected_slot );
218 if( status != PSA_SUCCESS )
219 goto error;
220
221 *volatile_key_id = PSA_KEY_ID_VOLATILE_MIN +
222 ( (psa_key_id_t)( selected_slot - global_data.key_slots ) );
223 *p_slot = selected_slot;
224
225 return( PSA_SUCCESS );
226 }
227 status = PSA_ERROR_INSUFFICIENT_MEMORY;
228
229 error:
230 *p_slot = NULL;
231 *volatile_key_id = 0;
232
233 return( status );
234 }
235
236 #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
psa_load_persistent_key_into_slot(psa_key_slot_t * slot)237 static psa_status_t psa_load_persistent_key_into_slot( psa_key_slot_t *slot )
238 {
239 psa_status_t status = PSA_SUCCESS;
240 uint8_t *key_data = NULL;
241 size_t key_data_length = 0;
242
243 status = psa_load_persistent_key( &slot->attr,
244 &key_data, &key_data_length );
245 if( status != PSA_SUCCESS )
246 goto exit;
247
248 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
249 /* Special handling is required for loading keys associated with a
250 * dynamically registered SE interface. */
251 const psa_drv_se_t *drv;
252 psa_drv_se_context_t *drv_context;
253 if( psa_get_se_driver( slot->attr.lifetime, &drv, &drv_context ) )
254 {
255 psa_se_key_data_storage_t *data;
256
257 if( key_data_length != sizeof( *data ) )
258 {
259 status = PSA_ERROR_DATA_INVALID;
260 goto exit;
261 }
262 data = (psa_se_key_data_storage_t *) key_data;
263 status = psa_copy_key_material_into_slot(
264 slot, data->slot_number, sizeof( data->slot_number ) );
265 goto exit;
266 }
267 #endif /* MBEDTLS_PSA_CRYPTO_SE_C */
268
269 status = psa_copy_key_material_into_slot( slot, key_data, key_data_length );
270
271 exit:
272 psa_free_persistent_key_data( key_data, key_data_length );
273 return( status );
274 }
275 #endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
276
277 #if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
278
psa_load_builtin_key_into_slot(psa_key_slot_t * slot)279 static psa_status_t psa_load_builtin_key_into_slot( psa_key_slot_t *slot )
280 {
281 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
282 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
283 psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_VOLATILE;
284 psa_drv_slot_number_t slot_number = 0;
285 size_t key_buffer_size = 0;
286 size_t key_buffer_length = 0;
287
288 if( ! psa_key_id_is_builtin(
289 MBEDTLS_SVC_KEY_ID_GET_KEY_ID( slot->attr.id ) ) )
290 {
291 return( PSA_ERROR_DOES_NOT_EXIST );
292 }
293
294 /* Check the platform function to see whether this key actually exists */
295 status = mbedtls_psa_platform_get_builtin_key(
296 slot->attr.id, &lifetime, &slot_number );
297 if( status != PSA_SUCCESS )
298 return( status );
299
300 /* Set required key attributes to ensure get_builtin_key can retrieve the
301 * full attributes. */
302 psa_set_key_id( &attributes, slot->attr.id );
303 psa_set_key_lifetime( &attributes, lifetime );
304
305 /* Get the full key attributes from the driver in order to be able to
306 * calculate the required buffer size. */
307 status = psa_driver_wrapper_get_builtin_key(
308 slot_number, &attributes,
309 NULL, 0, NULL );
310 if( status != PSA_ERROR_BUFFER_TOO_SMALL )
311 {
312 /* Builtin keys cannot be defined by the attributes alone */
313 if( status == PSA_SUCCESS )
314 status = PSA_ERROR_CORRUPTION_DETECTED;
315 return( status );
316 }
317
318 /* If the key should exist according to the platform, then ask the driver
319 * what its expected size is. */
320 status = psa_driver_wrapper_get_key_buffer_size( &attributes,
321 &key_buffer_size );
322 if( status != PSA_SUCCESS )
323 return( status );
324
325 /* Allocate a buffer of the required size and load the builtin key directly
326 * into the (now properly sized) slot buffer. */
327 status = psa_allocate_buffer_to_slot( slot, key_buffer_size );
328 if( status != PSA_SUCCESS )
329 return( status );
330
331 status = psa_driver_wrapper_get_builtin_key(
332 slot_number, &attributes,
333 slot->key.data, slot->key.bytes, &key_buffer_length );
334 if( status != PSA_SUCCESS )
335 goto exit;
336
337 /* Copy actual key length and core attributes into the slot on success */
338 slot->key.bytes = key_buffer_length;
339 slot->attr = attributes.core;
340
341 exit:
342 if( status != PSA_SUCCESS )
343 psa_remove_key_data_from_memory( slot );
344 return( status );
345 }
346 #endif /* MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
347
psa_get_and_lock_key_slot(mbedtls_svc_key_id_t key,psa_key_slot_t ** p_slot)348 psa_status_t psa_get_and_lock_key_slot( mbedtls_svc_key_id_t key,
349 psa_key_slot_t **p_slot )
350 {
351 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
352
353 *p_slot = NULL;
354 if( ! global_data.key_slots_initialized )
355 return( PSA_ERROR_BAD_STATE );
356
357 /*
358 * On success, the pointer to the slot is passed directly to the caller
359 * thus no need to unlock the key slot here.
360 */
361 status = psa_get_and_lock_key_slot_in_memory( key, p_slot );
362 if( status != PSA_ERROR_DOES_NOT_EXIST )
363 return( status );
364
365 /* Loading keys from storage requires support for such a mechanism */
366 #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) || \
367 defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
368 psa_key_id_t volatile_key_id;
369
370 status = psa_get_empty_key_slot( &volatile_key_id, p_slot );
371 if( status != PSA_SUCCESS )
372 return( status );
373
374 (*p_slot)->attr.id = key;
375 (*p_slot)->attr.lifetime = PSA_KEY_LIFETIME_PERSISTENT;
376
377 status = PSA_ERROR_DOES_NOT_EXIST;
378 #if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
379 /* Load keys in the 'builtin' range through their own interface */
380 status = psa_load_builtin_key_into_slot( *p_slot );
381 #endif /* MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
382
383 #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
384 if( status == PSA_ERROR_DOES_NOT_EXIST )
385 status = psa_load_persistent_key_into_slot( *p_slot );
386 #endif /* defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) */
387
388 if( status != PSA_SUCCESS )
389 {
390 psa_wipe_key_slot( *p_slot );
391 if( status == PSA_ERROR_DOES_NOT_EXIST )
392 status = PSA_ERROR_INVALID_HANDLE;
393 }
394 else
395 /* Add implicit usage flags. */
396 psa_extend_key_usage_flags( &(*p_slot)->attr.policy.usage );
397
398 return( status );
399 #else /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
400 return( PSA_ERROR_INVALID_HANDLE );
401 #endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
402 }
403
psa_unlock_key_slot(psa_key_slot_t * slot)404 psa_status_t psa_unlock_key_slot( psa_key_slot_t *slot )
405 {
406 if( slot == NULL )
407 return( PSA_SUCCESS );
408
409 if( slot->lock_count > 0 )
410 {
411 slot->lock_count--;
412 return( PSA_SUCCESS );
413 }
414
415 /*
416 * As the return error code may not be handled in case of multiple errors,
417 * do our best to report if the lock counter is equal to zero. Assert with
418 * MBEDTLS_TEST_HOOK_TEST_ASSERT that the lock counter is strictly greater
419 * than zero: if the MBEDTLS_TEST_HOOKS configuration option is enabled and
420 * the function is called as part of the execution of a test suite, the
421 * execution of the test suite is stopped in error if the assertion fails.
422 */
423 MBEDTLS_TEST_HOOK_TEST_ASSERT( slot->lock_count > 0 );
424 return( PSA_ERROR_CORRUPTION_DETECTED );
425 }
426
psa_validate_key_location(psa_key_lifetime_t lifetime,psa_se_drv_table_entry_t ** p_drv)427 psa_status_t psa_validate_key_location( psa_key_lifetime_t lifetime,
428 psa_se_drv_table_entry_t **p_drv )
429 {
430 if ( psa_key_lifetime_is_external( lifetime ) )
431 {
432 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
433 /* Check whether a driver is registered against this lifetime */
434 psa_se_drv_table_entry_t *driver = psa_get_se_driver_entry( lifetime );
435 if( driver != NULL )
436 {
437 if (p_drv != NULL)
438 *p_drv = driver;
439 return( PSA_SUCCESS );
440 }
441 #else /* MBEDTLS_PSA_CRYPTO_SE_C */
442 (void) p_drv;
443 #endif /* MBEDTLS_PSA_CRYPTO_SE_C */
444
445 #if defined(MBEDTLS_PSA_CRYPTO_DRIVERS)
446 /* Key location for external keys gets checked by the wrapper */
447 return( PSA_SUCCESS );
448 #else /* MBEDTLS_PSA_CRYPTO_DRIVERS */
449 /* No support for external lifetimes at all, or dynamic interface
450 * did not find driver for requested lifetime. */
451 return( PSA_ERROR_INVALID_ARGUMENT );
452 #endif /* MBEDTLS_PSA_CRYPTO_DRIVERS */
453 }
454 else
455 /* Local/internal keys are always valid */
456 return( PSA_SUCCESS );
457 }
458
psa_validate_key_persistence(psa_key_lifetime_t lifetime)459 psa_status_t psa_validate_key_persistence( psa_key_lifetime_t lifetime )
460 {
461 if ( PSA_KEY_LIFETIME_IS_VOLATILE( lifetime ) )
462 {
463 /* Volatile keys are always supported */
464 return( PSA_SUCCESS );
465 }
466 else
467 {
468 /* Persistent keys require storage support */
469 #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
470 if( PSA_KEY_LIFETIME_IS_READ_ONLY( lifetime ) )
471 return( PSA_ERROR_INVALID_ARGUMENT );
472 else
473 return( PSA_SUCCESS );
474 #else /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
475 return( PSA_ERROR_NOT_SUPPORTED );
476 #endif /* !MBEDTLS_PSA_CRYPTO_STORAGE_C */
477 }
478 }
479
psa_open_key(mbedtls_svc_key_id_t key,psa_key_handle_t * handle)480 psa_status_t psa_open_key( mbedtls_svc_key_id_t key, psa_key_handle_t *handle )
481 {
482 #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) || \
483 defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
484 psa_status_t status;
485 psa_key_slot_t *slot;
486
487 status = psa_get_and_lock_key_slot( key, &slot );
488 if( status != PSA_SUCCESS )
489 {
490 *handle = PSA_KEY_HANDLE_INIT;
491 if( status == PSA_ERROR_INVALID_HANDLE )
492 status = PSA_ERROR_DOES_NOT_EXIST;
493
494 return( status );
495 }
496
497 *handle = key;
498
499 return( psa_unlock_key_slot( slot ) );
500
501 #else /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
502 (void) key;
503 *handle = PSA_KEY_HANDLE_INIT;
504 return( PSA_ERROR_NOT_SUPPORTED );
505 #endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C || MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
506 }
507
psa_close_key(psa_key_handle_t handle)508 psa_status_t psa_close_key( psa_key_handle_t handle )
509 {
510 psa_status_t status;
511 psa_key_slot_t *slot;
512
513 if( psa_key_handle_is_null( handle ) )
514 return( PSA_SUCCESS );
515
516 status = psa_get_and_lock_key_slot_in_memory( handle, &slot );
517 if( status != PSA_SUCCESS )
518 {
519 if( status == PSA_ERROR_DOES_NOT_EXIST )
520 status = PSA_ERROR_INVALID_HANDLE;
521
522 return( status );
523 }
524 if( slot->lock_count <= 1 )
525 return( psa_wipe_key_slot( slot ) );
526 else
527 return( psa_unlock_key_slot( slot ) );
528 }
529
psa_purge_key(mbedtls_svc_key_id_t key)530 psa_status_t psa_purge_key( mbedtls_svc_key_id_t key )
531 {
532 psa_status_t status;
533 psa_key_slot_t *slot;
534
535 status = psa_get_and_lock_key_slot_in_memory( key, &slot );
536 if( status != PSA_SUCCESS )
537 return( status );
538
539 if( ( ! PSA_KEY_LIFETIME_IS_VOLATILE( slot->attr.lifetime ) ) &&
540 ( slot->lock_count <= 1 ) )
541 return( psa_wipe_key_slot( slot ) );
542 else
543 return( psa_unlock_key_slot( slot ) );
544 }
545
mbedtls_psa_get_stats(mbedtls_psa_stats_t * stats)546 void mbedtls_psa_get_stats( mbedtls_psa_stats_t *stats )
547 {
548 size_t slot_idx;
549
550 memset( stats, 0, sizeof( *stats ) );
551
552 for( slot_idx = 0; slot_idx < MBEDTLS_PSA_KEY_SLOT_COUNT; slot_idx++ )
553 {
554 const psa_key_slot_t *slot = &global_data.key_slots[ slot_idx ];
555 if( psa_is_key_slot_locked( slot ) )
556 {
557 ++stats->locked_slots;
558 }
559 if( ! psa_is_key_slot_occupied( slot ) )
560 {
561 ++stats->empty_slots;
562 continue;
563 }
564 if( PSA_KEY_LIFETIME_IS_VOLATILE( slot->attr.lifetime ) )
565 ++stats->volatile_slots;
566 else
567 {
568 psa_key_id_t id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID( slot->attr.id );
569 ++stats->persistent_slots;
570 if( id > stats->max_open_internal_key_id )
571 stats->max_open_internal_key_id = id;
572 }
573 if( PSA_KEY_LIFETIME_GET_LOCATION( slot->attr.lifetime ) !=
574 PSA_KEY_LOCATION_LOCAL_STORAGE )
575 {
576 psa_key_id_t id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID( slot->attr.id );
577 ++stats->external_slots;
578 if( id > stats->max_open_external_key_id )
579 stats->max_open_external_key_id = id;
580 }
581 }
582 }
583
584 #endif /* MBEDTLS_PSA_CRYPTO_C */
585