mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
feat(mbedtls/psa_esp_rsa_ds): Expose persistent key buffer format/parse helpers
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user