mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
feat(mbedtls): Support custom storage backend for persistent PSA keys
This commit is contained in:
@@ -167,6 +167,114 @@ ESP-IDF 为 Mbed TLS 提供了基于预设的配置系统,用于简化设置
|
||||
X.509 证书解析、验证和证书包管理。
|
||||
|
||||
|
||||
PSA ITS 自定义存储后端
|
||||
-----------------------
|
||||
|
||||
ESP-IDF 的 PSA 内部可信存储 (Internal Trusted Storage, ITS) 实现默认使用 NVS 作为持久化 PSA Crypto 密钥的存储后端。自定义存储后端功能允许将保留范围内的 PSA 密钥 ID 路由到用户提供的存储实现,而其他密钥继续使用 NVS。
|
||||
|
||||
适用场景包括:
|
||||
|
||||
- 某些密钥需要存储在不同的文件系统中(如 FATFS、SPIFFS、littlefs)
|
||||
- 密钥需要硬件保护的加密存储(例如通过 TEE 安全存储)
|
||||
- 不同类别的密钥需要使用不同的存储分区
|
||||
|
||||
启用自定义后端
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
通过 ``menuconfig`` 在 ``Component Config`` > ``mbedTLS`` 中启用该功能:
|
||||
|
||||
- :ref:`CONFIG_MBEDTLS_PSA_ITS_CUSTOM_STORAGE_BACKEND`:启用自定义存储后端
|
||||
- :ref:`CONFIG_MBEDTLS_PSA_ITS_CUSTOM_BACKEND_UID_MIN`:自定义密钥 ID 范围的起始值(默认 ``0x30000000``)
|
||||
- :ref:`CONFIG_MBEDTLS_PSA_ITS_CUSTOM_BACKEND_UID_MAX`:自定义密钥 ID 范围的结束值(默认 ``0x3FFFFFFF``)
|
||||
|
||||
配置范围内的 PSA 密钥 ID 会被路由到已注册的后端。其他所有密钥 ID(以及随机种子等 PSA 内部数据)继续使用默认的 NVS 后端。
|
||||
|
||||
实现自定义后端
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
实现 ``esp_psa_its_custom_ops_t`` 回调结构体,并在使用自定义范围内的 PSA Crypto 密钥之前进行注册:
|
||||
|
||||
.. 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)
|
||||
{
|
||||
/* 存储 uid 对应的 blob */
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/* 读取 uid 对应的 blob */
|
||||
}
|
||||
|
||||
static psa_status_t my_get_info(void *ctx, const psa_storage_uid_t uid,
|
||||
struct psa_storage_info_t *p_info)
|
||||
{
|
||||
/* 返回 uid 对应 blob 的大小和标志位 */
|
||||
}
|
||||
|
||||
static psa_status_t my_remove(void *ctx, const psa_storage_uid_t uid)
|
||||
{
|
||||
/* 删除 uid 对应的 blob */
|
||||
}
|
||||
|
||||
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, /* 可选的用户上下文 */
|
||||
};
|
||||
|
||||
/* 在使用自定义范围内的 PSA 密钥之前注册 */
|
||||
esp_psa_its_register_custom_backend(&my_ops);
|
||||
|
||||
回调函数的签名与 PSA ITS API 保持一致。每个回调接收原始的 ``psa_storage_uid_t``\ (而非字符串),允许实现根据数值型密钥 ID 进行路由决策。``ctx`` 指针会作为第一个参数传递给每个回调。
|
||||
|
||||
.. note::
|
||||
|
||||
只有持久化密钥会经过 ITS 层。PSA 要求持久化密钥必须调用 ``psa_set_key_id()``,因此应用程序始终可以控制分配哪些密钥 ID,进而决定它们落在哪个范围内。
|
||||
|
||||
如有需要,后端实现需自行处理 ``psa_storage_create_flags_t`` 的语义。
|
||||
|
||||
处理 PSA 密钥文件格式
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
通过 ``psa_its_set()`` / ``psa_its_get()`` 传输的字节流采用 Mbed TLS `存储规范 <https://github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/docs/architecture/mbed-crypto-storage-specification.md>`__\ 中描述的 PSA 持久密钥文件格式。原样存储该 blob 的后端无需查看其内容;在写入时剥离头部以节省空间,或在读取时合成 blob 的后端(例如,将预配置的硬件密钥暴露为持久 PSA 密钥)则需要自行构造或解析。
|
||||
|
||||
为此,ESP-IDF 在 ``esp_psa_key_file.h`` 中提供以下辅助函数:
|
||||
|
||||
- :cpp:func:`esp_psa_key_file_pack` —— 将 ``psa_key_attributes_t`` 结构和原始密钥字节封装为密钥 blob。
|
||||
- :cpp:func:`esp_psa_key_file_unpack` —— 将密钥 blob 解析回属性以及指向密钥字节段的指针。
|
||||
- :cpp:func:`esp_psa_key_file_size` —— 根据给定的密钥字节长度返回 blob 的总大小。
|
||||
|
||||
这些辅助函数直接实现规范文档中描述的字节布局,不依赖任何 Mbed TLS 内部函数。例如,仅存储内部密钥字节的后端可以在读取时重建 blob:
|
||||
|
||||
.. 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 现在包含完整的 PSA 持久密钥文件;按 psa_its_get() 的 offset/length
|
||||
* 参数将所请求的窗口复制到 p_data。 */
|
||||
|
||||
完整的可运行示例(使用自定义 NVS 命名空间作为自定义后端)请参考 :example:`security/psa_its_custom_backend`。
|
||||
|
||||
应用示例
|
||||
--------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user