feat(mbedtls/psa_esp_rsa_ds): Expose persistent key buffer format/parse helpers

This commit is contained in:
harshal.patil
2026-05-09 08:52:51 +05:30
parent b3214f13c6
commit b5d53b87ef
2 changed files with 194 additions and 32 deletions

View File

@@ -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;
}
}

View File

@@ -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
*