From b5d53b87efcd1b6c153ed7edb79e30d86123bf3a Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Sat, 9 May 2026 08:52:51 +0530 Subject: [PATCH] feat(mbedtls/psa_esp_rsa_ds): Expose persistent key buffer format/parse helpers --- .../esp_rsa_ds/psa_crypto_driver_esp_rsa_ds.c | 143 ++++++++++++++---- .../include/psa_crypto_driver_esp_rsa_ds.h | 83 ++++++++++ 2 files changed, 194 insertions(+), 32 deletions(-) diff --git a/components/mbedtls/port/psa_driver/esp_rsa_ds/psa_crypto_driver_esp_rsa_ds.c b/components/mbedtls/port/psa_driver/esp_rsa_ds/psa_crypto_driver_esp_rsa_ds.c index af0a812cdcc..c9de6d206fe 100644 --- a/components/mbedtls/port/psa_driver/esp_rsa_ds/psa_crypto_driver_esp_rsa_ds.c +++ b/components/mbedtls/port/psa_driver/esp_rsa_ds/psa_crypto_driver_esp_rsa_ds.c @@ -347,7 +347,7 @@ void esp_rsa_ds_release_ds_lock(void) } } -static int esp_rsa_ds_validate_opaque_key(const esp_rsa_ds_opaque_key_t *opaque_key) +static psa_status_t esp_rsa_ds_validate_opaque_key(const esp_rsa_ds_opaque_key_t *opaque_key) { if (opaque_key == NULL) { return PSA_ERROR_INVALID_ARGUMENT; @@ -392,6 +392,111 @@ static int esp_rsa_ds_validate_opaque_key(const esp_rsa_ds_opaque_key_t *opaque_ return PSA_SUCCESS; } +/** + * Serialize an already-validated opaque key into the persistent inline + * storage layout (eFuse or Key Manager, selected from key_recovery_info). + * Internal helper — does not validate inputs. + */ +static psa_status_t rsa_ds_format_persistent_key_buffer_internal( + const esp_rsa_ds_opaque_key_t *opaque_key, + uint8_t *buf, size_t buf_size, size_t *out_len) +{ +#if SOC_KEY_MANAGER_SUPPORTED + if (opaque_key->key_recovery_info) { + if (buf_size < sizeof(esp_rsa_ds_km_key_storage_t)) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + esp_rsa_ds_km_key_storage_t *storage = (esp_rsa_ds_km_key_storage_t *)buf; + memset(storage, 0, sizeof(*storage)); + storage->metadata.version = ESP_RSA_DS_KEY_STORAGE_VERSION_V1; + storage->metadata.key_source = ESP_RSA_DS_KEY_SOURCE_KEY_MGR; + storage->rsa_length_bits = opaque_key->ds_data_ctx->rsa_length_bits; + memcpy(&storage->ds_data, opaque_key->ds_data_ctx->esp_ds_data, sizeof(esp_ds_data_t)); + memcpy(&storage->key_recovery_info, opaque_key->key_recovery_info, + sizeof(esp_key_mgr_key_recovery_info_t)); + *out_len = sizeof(esp_rsa_ds_km_key_storage_t); + return PSA_SUCCESS; + } +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + + if (buf_size < sizeof(esp_rsa_ds_efuse_key_storage_t)) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + esp_rsa_ds_efuse_key_storage_t *storage = (esp_rsa_ds_efuse_key_storage_t *)buf; + memset(storage, 0, sizeof(*storage)); + storage->metadata.version = ESP_RSA_DS_KEY_STORAGE_VERSION_V1; + storage->metadata.key_source = ESP_RSA_DS_KEY_SOURCE_EFUSE; + storage->efuse_key_id = opaque_key->ds_data_ctx->efuse_key_id; + storage->rsa_length_bits = opaque_key->ds_data_ctx->rsa_length_bits; + memcpy(&storage->ds_data, opaque_key->ds_data_ctx->esp_ds_data, sizeof(esp_ds_data_t)); + *out_len = sizeof(esp_rsa_ds_efuse_key_storage_t); + return PSA_SUCCESS; +} + +size_t esp_rsa_ds_persistent_key_buffer_size(const esp_rsa_ds_opaque_key_t *opaque_key) +{ + if (opaque_key == NULL) { + return 0; + } + return esp_rsa_ds_get_storage_size(opaque_key, true); +} + +psa_status_t esp_rsa_ds_format_persistent_key_buffer(const esp_rsa_ds_opaque_key_t *opaque_key, + uint8_t *buf, size_t buf_size, + size_t *out_len) +{ + if (opaque_key == NULL || buf == NULL || out_len == NULL) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + psa_status_t ret = esp_rsa_ds_validate_opaque_key(opaque_key); + if (ret != PSA_SUCCESS) { + return ret; + } + + return rsa_ds_format_persistent_key_buffer_internal(opaque_key, buf, buf_size, out_len); +} + +psa_status_t esp_rsa_ds_parse_persistent_key_buffer(const uint8_t *buf, size_t buf_len, + esp_rsa_ds_opaque_key_t *out) +{ + if (buf == NULL || out == NULL || out->ds_data_ctx == NULL) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + esp_rsa_ds_key_source_t key_source = ESP_RSA_DS_KEY_SOURCE_EFUSE; + uint16_t rsa_length_bits = 0; + const esp_ds_data_t *ds_data = NULL; + hmac_key_id_t hmac_id = 0; +#if SOC_KEY_MANAGER_SUPPORTED + esp_key_mgr_key_recovery_info_t *km_ri = NULL; +#endif + + psa_status_t status = esp_rsa_ds_extract_storage( + buf, buf_len, /* is_persistent = */ true, + &key_source, &rsa_length_bits, &ds_data, &hmac_id +#if SOC_KEY_MANAGER_SUPPORTED + , &km_ri +#endif + ); + if (status != PSA_SUCCESS) { + return status; + } + + /* Aliases into buf — caller must not write through these pointers and + * must keep buf alive for as long as out is used. */ + out->ds_data_ctx->esp_ds_data = (esp_ds_data_t *)ds_data; + out->ds_data_ctx->efuse_key_id = (uint8_t)hmac_id; + out->ds_data_ctx->rsa_length_bits = rsa_length_bits; +#if SOC_KEY_MANAGER_SUPPORTED + out->key_recovery_info = km_ri; +#else + (void)key_source; +#endif + + return PSA_SUCCESS; +} + psa_status_t esp_rsa_ds_opaque_sign_hash_start( esp_rsa_ds_opaque_sign_hash_operation_t *operation, const psa_key_attributes_t *attributes, @@ -678,7 +783,7 @@ psa_status_t esp_rsa_ds_opaque_import_key( } const esp_rsa_ds_opaque_key_t *opaque_key = (const esp_rsa_ds_opaque_key_t *)data; - int ret = esp_rsa_ds_validate_opaque_key(opaque_key); + psa_status_t ret = esp_rsa_ds_validate_opaque_key(opaque_key); if (ret != PSA_SUCCESS) { return ret; } @@ -709,36 +814,10 @@ psa_status_t esp_rsa_ds_opaque_import_key( *key_buffer_length = sizeof(esp_rsa_ds_volatile_key_storage_t); } else { /* Persistent: deep-copy all data into self-contained storage struct */ -#if SOC_KEY_MANAGER_SUPPORTED - if (key_source == ESP_RSA_DS_KEY_SOURCE_KEY_MGR) { - if (key_buffer_size < sizeof(esp_rsa_ds_km_key_storage_t)) { - return PSA_ERROR_BUFFER_TOO_SMALL; - } - - esp_rsa_ds_km_key_storage_t *storage = (esp_rsa_ds_km_key_storage_t *)key_buffer; - storage->metadata.version = ESP_RSA_DS_KEY_STORAGE_VERSION_V1; - storage->metadata.key_source = ESP_RSA_DS_KEY_SOURCE_KEY_MGR; - storage->rsa_length_bits = opaque_key->ds_data_ctx->rsa_length_bits; - memcpy(&storage->ds_data, opaque_key->ds_data_ctx->esp_ds_data, sizeof(esp_ds_data_t)); - memcpy(&storage->key_recovery_info, opaque_key->key_recovery_info, - sizeof(esp_key_mgr_key_recovery_info_t)); - *key_buffer_length = sizeof(esp_rsa_ds_km_key_storage_t); - } else -#endif /* SOC_KEY_MANAGER_SUPPORTED */ - { - if (key_buffer_size < sizeof(esp_rsa_ds_efuse_key_storage_t)) { - return PSA_ERROR_BUFFER_TOO_SMALL; - } - - esp_rsa_ds_efuse_key_storage_t *storage = (esp_rsa_ds_efuse_key_storage_t *)key_buffer; - storage->metadata.version = ESP_RSA_DS_KEY_STORAGE_VERSION_V1; - storage->metadata.key_source = ESP_RSA_DS_KEY_SOURCE_EFUSE; - storage->efuse_key_id = opaque_key->ds_data_ctx->efuse_key_id; - storage->reserved = 0; - storage->rsa_length_bits = opaque_key->ds_data_ctx->rsa_length_bits; - memset(storage->reserved2, 0, sizeof(storage->reserved2)); - memcpy(&storage->ds_data, opaque_key->ds_data_ctx->esp_ds_data, sizeof(esp_ds_data_t)); - *key_buffer_length = sizeof(esp_rsa_ds_efuse_key_storage_t); + psa_status_t status = rsa_ds_format_persistent_key_buffer_internal( + opaque_key, key_buffer, key_buffer_size, key_buffer_length); + if (status != PSA_SUCCESS) { + return status; } } diff --git a/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_rsa_ds.h b/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_rsa_ds.h index d762a20f2cc..a9e3d2c8f20 100644 --- a/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_rsa_ds.h +++ b/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_rsa_ds.h @@ -38,6 +38,89 @@ extern "C" { PSA_KEY_PERSISTENCE_VOLATILE, \ PSA_KEY_LOCATION_ESP_RSA_DS) +/** + * @brief Buffer size needed to serialize an ESP-RSA DS key into the persistent + * storage layout used by this driver. + * + * The size depends on the key source: eFuse-sourced keys and Key Manager-sourced + * keys (KM-capable SoCs only) use different inline storage structs. The source + * is inferred from @p opaque_key — the Key Manager layout is selected when + * @p opaque_key->key_recovery_info is non-NULL. + * + * @param opaque_key User-facing opaque key (must be non-NULL). + * @return Storage buffer size in bytes, or 0 if @p opaque_key is NULL. + */ +size_t esp_rsa_ds_persistent_key_buffer_size(const esp_rsa_ds_opaque_key_t *opaque_key); + +/** + * @brief Serialize an ESP-RSA DS key into the persistent storage layout that + * this driver expects when loading a persistent key from PSA storage. + * + * Custom PSA ITS backends that synthesize persistent RSA-DS key blobs at + * read time can use this helper to produce the @c key_data payload, then wrap + * it with esp_psa_its_pack_key_blob() to build the full PSA persistent key blob. + * + * The output layout (eFuse vs Key Manager) is selected automatically from + * @p opaque_key, mirroring the import path. Validation of @p opaque_key is + * performed before serialization. + * + * @param opaque_key User-facing opaque key. + * @param buf Output buffer (caller-allocated, sized via + * esp_rsa_ds_persistent_key_buffer_size()). + * @param buf_size Size of @p buf in bytes. + * @param[out] out_len Bytes written to @p buf on success. + * + * @return PSA_SUCCESS on success + * @return PSA_ERROR_INVALID_ARGUMENT if any required input is NULL or the + * opaque key fields are invalid + * @return PSA_ERROR_BUFFER_TOO_SMALL if @p buf_size is insufficient + */ +psa_status_t esp_rsa_ds_format_persistent_key_buffer(const esp_rsa_ds_opaque_key_t *opaque_key, + uint8_t *buf, size_t buf_size, + size_t *out_len); + +/** + * @brief Parse an ESP-RSA DS persistent key buffer. + * + * Inverse of esp_rsa_ds_format_persistent_key_buffer(): validates the + * key-storage metadata (version + source) in @p buf, then fills @p out + * with the same opaque-key shape the format path consumes. + * + * The caller owns the storage for @p out, including the @c esp_ds_data_ctx_t + * it points to (@p out->ds_data_ctx must be non-NULL before the call). + * On success, scalar fields (@c efuse_key_id, @c rsa_length_bits) are filled + * into the caller's @c esp_ds_data_ctx_t, and the @c esp_ds_data pointer + * — together with @c out->key_recovery_info on KM-capable SoCs — aliases + * into @p buf. Those pointers remain valid only for as long as @p buf is, + * and must not be written through. + * + * The key source (eFuse vs Key Manager) is conveyed implicitly: on success, + * @c out->key_recovery_info is non-NULL iff the buffer was produced from a + * Key-Manager-backed key. This mirrors how the format path discriminates + * via the same field. + * + * Custom PSA ITS backends that accept writes (translating PSA-formatted + * blobs handed to psa_its_set() into a native storage format) can use this + * helper after first stripping the PSA wrapper with esp_psa_its_unpack_key_blob(). + * + * @param buf Input buffer (as produced by esp_rsa_ds_format_persistent_key_buffer() + * or written by the driver's import path). + * @param buf_len Length of @p buf in bytes. + * @param[in,out] out Opaque key to fill. @p out->ds_data_ctx must point to a + * caller-allocated @c esp_ds_data_ctx_t. + * + * @return PSA_SUCCESS on success + * @return PSA_ERROR_INVALID_ARGUMENT if @p buf, @p out, or @p out->ds_data_ctx + * is NULL, or @p buf_len is too small, or + * the buffer is internally inconsistent + * (e.g. invalid RSA length) + * @return PSA_ERROR_DATA_INVALID if the metadata version or key source is + * unrecognized, or the embedded esp_ds_data_t + * does not match the declared key length + */ +psa_status_t esp_rsa_ds_parse_persistent_key_buffer(const uint8_t *buf, size_t buf_len, + esp_rsa_ds_opaque_key_t *out); + /** * @brief Start the RSA DS opaque sign hash operation *