mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
feat(mbedtls): Support custom storage backend for persistent PSA keys
This commit is contained in:
@@ -167,6 +167,114 @@ The new mbedTLS configuration system is organized into logical categories for ea
|
||||
X.509 certificate parsing, validation, and certificate bundle management.
|
||||
|
||||
|
||||
PSA ITS Custom Storage Backend
|
||||
-------------------------------
|
||||
|
||||
ESP-IDF's PSA Internal Trusted Storage (ITS) implementation uses NVS as its default backend for storing persistent PSA Crypto keys. The custom storage backend feature allows routing a reserved range of PSA key IDs to a user-provided storage implementation, while all other keys continue using NVS.
|
||||
|
||||
This is useful when:
|
||||
|
||||
- Certain keys need to be stored on a different filesystem (FATFS, SPIFFS, littlefs)
|
||||
- Keys require hardware-protected encryption (e.g., via TEE secure storage)
|
||||
- Different storage partitions are needed for different key categories
|
||||
|
||||
Enabling the Custom Backend
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Enable the feature via ``menuconfig`` under ``Component Config`` > ``mbedTLS``:
|
||||
|
||||
- :ref:`CONFIG_MBEDTLS_PSA_ITS_CUSTOM_STORAGE_BACKEND`: Enable the custom storage backend
|
||||
- :ref:`CONFIG_MBEDTLS_PSA_ITS_CUSTOM_BACKEND_UID_MIN`: Start of the custom key ID range (default ``0x30000000``)
|
||||
- :ref:`CONFIG_MBEDTLS_PSA_ITS_CUSTOM_BACKEND_UID_MAX`: End of the custom key ID range (default ``0x3FFFFFFF``)
|
||||
|
||||
PSA key IDs within the configured range are routed to the registered backend. All other key IDs (and internal PSA data such as the random seed) continue using the default NVS backend.
|
||||
|
||||
Implementing a Custom Backend
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Implement the ``esp_psa_its_custom_ops_t`` callback structure and register it before using PSA Crypto with keys in the custom range:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "esp_psa_its.h"
|
||||
|
||||
static psa_status_t my_set(void *ctx, const psa_storage_uid_t uid,
|
||||
const uint32_t data_length, const void *p_data,
|
||||
const psa_storage_create_flags_t create_flags)
|
||||
{
|
||||
/* Store the blob identified by uid */
|
||||
}
|
||||
|
||||
static psa_status_t my_get(void *ctx, const psa_storage_uid_t uid,
|
||||
const uint32_t data_offset, const uint32_t data_length,
|
||||
void *p_data, size_t *p_data_length)
|
||||
{
|
||||
/* Retrieve the blob identified by uid */
|
||||
}
|
||||
|
||||
static psa_status_t my_get_info(void *ctx, const psa_storage_uid_t uid,
|
||||
struct psa_storage_info_t *p_info)
|
||||
{
|
||||
/* Return size and flags for the blob identified by uid */
|
||||
}
|
||||
|
||||
static psa_status_t my_remove(void *ctx, const psa_storage_uid_t uid)
|
||||
{
|
||||
/* Delete the blob identified by uid */
|
||||
}
|
||||
|
||||
static esp_psa_its_custom_ops_t my_ops = {
|
||||
.set = my_set,
|
||||
.get = my_get,
|
||||
.get_info = my_get_info,
|
||||
.remove = my_remove,
|
||||
.ctx = NULL, /* optional user context */
|
||||
};
|
||||
|
||||
/* Register before using PSA keys in the custom range */
|
||||
esp_psa_its_register_custom_backend(&my_ops);
|
||||
|
||||
The callback signatures mirror the PSA ITS API. Each callback receives the raw ``psa_storage_uid_t`` (not a string), allowing the implementation to make routing decisions based on the numeric key ID. The ``ctx`` pointer is passed as the first argument to every callback.
|
||||
|
||||
.. note::
|
||||
|
||||
Only persistent keys flow through the ITS layer. PSA requires ``psa_set_key_id()`` for persistent keys, so the application always controls which key IDs it assigns and thus which range they fall into.
|
||||
|
||||
The backend implementation is responsible for enforcing ``psa_storage_create_flags_t`` semantics if needed.
|
||||
|
||||
Working with the PSA Key Blob Format
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The byte stream that flows through ``psa_its_set()`` / ``psa_its_get()`` is the PSA persistent key blob format documented in the Mbed TLS `storage specification <https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/docs/architecture/mbed-crypto-storage-specification.md>`__. Backends that store the blob verbatim do not need to look inside it. Backends that strip the header on write (to save space) or synthesise the blob on read (for example, to expose a pre-provisioned hardware key) need to construct or parse it themselves.
|
||||
|
||||
ESP-IDF provides two helpers in ``esp_psa_key_file.h`` for this:
|
||||
|
||||
- :cpp:func:`esp_psa_key_file_pack` — assemble a key blob from a ``psa_key_attributes_t`` structure and raw key material bytes.
|
||||
- :cpp:func:`esp_psa_key_file_unpack` — parse a key blob back into attributes and a pointer into the key material section.
|
||||
- :cpp:func:`esp_psa_key_file_size` — return the total blob size for a given material length.
|
||||
|
||||
These helpers implement the documented byte layout directly and do not depend on any internal Mbed TLS function. For example, a backend that stores only the inner key bytes can rebuild the blob on read:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "esp_psa_key_file.h"
|
||||
|
||||
psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
|
||||
psa_set_key_lifetime(&attr, PSA_KEY_LIFETIME_PERSISTENT);
|
||||
psa_set_key_type(&attr, PSA_KEY_TYPE_AES);
|
||||
psa_set_key_bits(&attr, key_data_len * 8);
|
||||
psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
|
||||
psa_set_key_algorithm(&attr, PSA_ALG_CBC_NO_PADDING);
|
||||
|
||||
size_t blob_size = esp_psa_key_file_size(key_data_len);
|
||||
uint8_t *blob = calloc(1, blob_size);
|
||||
size_t written = 0;
|
||||
esp_psa_key_file_pack(&attr, key_data, key_data_len, blob, blob_size, &written);
|
||||
/* blob now holds the full PSA persistent key file; copy the requested
|
||||
* window into p_data per psa_its_get()'s offset/length arguments. */
|
||||
|
||||
For a complete working example using a custom NVS namespace as the custom backend, refer to :example:`security/psa_its_custom_backend`.
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user