diff --git a/components/mbedtls/mbedtls b/components/mbedtls/mbedtls index 8bfdb425305..6cc42afad30 160000 --- a/components/mbedtls/mbedtls +++ b/components/mbedtls/mbedtls @@ -1 +1 @@ -Subproject commit 8bfdb42530588ab6027ab6a5e7bd34385cb749d2 +Subproject commit 6cc42afad309e861f4c07e6f106e2ab14a9cb8e5 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 476cd5241c6..44d8c8c97dc 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 @@ -11,10 +11,12 @@ #include "psa_crypto_driver_esp_rsa_ds.h" #include "psa_crypto_driver_esp_rsa_ds_contexts.h" +#include "psa_crypto_driver_esp_opaque_common.h" #include "include/psa_crypto_driver_esp_rsa_ds_utilities.h" #include "esp_log.h" #include "esp_efuse.h" +#include "esp_assert.h" #include "soc/soc_caps.h" #if SOC_KEY_MANAGER_SUPPORTED @@ -28,6 +30,281 @@ static const char *TAG = "PSA_RSA_DS"; static SemaphoreHandle_t s_ds_lock = NULL; static int s_timeout_ms = 0; +/* + * Per-source storage structs — internal to the driver. + * These are what actually get persisted to NVS, not the user-facing esp_rsa_ds_opaque_key_t. + * + * All storage structs share a common prefix: [version][key_source] + * so that the driver can identify the key source at operation time. + */ +typedef enum { + ESP_RSA_DS_KEY_STORAGE_VERSION_INVALID = 0, + ESP_RSA_DS_KEY_STORAGE_VERSION_V1 = 1, + ESP_RSA_DS_KEY_STORAGE_VERSION_MAX = 2, +} esp_rsa_ds_key_storage_version_t; + +typedef enum { + ESP_RSA_DS_KEY_SOURCE_EFUSE = 0, + ESP_RSA_DS_KEY_SOURCE_KEY_MGR = 1, +} esp_rsa_ds_key_source_t; + +/* Storage structs use uint8_t for key_source instead of enum + * to ensure stable serialized size across compilers. */ + +typedef struct __attribute__((packed)) { + uint8_t version; + uint8_t key_source; /* esp_rsa_ds_key_source_t */ +} esp_rsa_ds_common_key_storage_metadata_t; + +ESP_STATIC_ASSERT(sizeof(esp_rsa_ds_common_key_storage_metadata_t) == 2 * sizeof(uint8_t), + "esp_rsa_ds_common_key_storage_metadata_t must be exactly 2 bytes"); + +/* esp_ds_data_t is serialised verbatim into NVS as part of the persistent storage structs, + * and its first field is an enum (esp_digital_signature_length_t). esp_ds.h documents that + * "in IDF, the enum type length is the same as of type unsigned" — assert it here so a + * future toolchain change that shrinks enums fails the build instead of silently making + * existing stored DS keys unreadable. */ +ESP_STATIC_ASSERT(sizeof(esp_digital_signature_length_t) == sizeof(unsigned), + "esp_digital_signature_length_t must be sized as unsigned for stable NVS layout of esp_ds_data_t"); + +/** + * Pointer-based storage for volatile keys. + * The caller must keep all referenced data valid until psa_destroy_key(). + * This avoids deep-copying esp_ds_data_t (~1600 bytes), preserving the + * heap savings of mmap'd flash data from esp_secure_cert_mgr. + */ +typedef struct { + esp_rsa_ds_common_key_storage_metadata_t metadata; + esp_ds_data_ctx_t *ds_data_ctx; +#if SOC_KEY_MANAGER_SUPPORTED + esp_key_mgr_key_recovery_info_t *key_recovery_info; +#endif /* SOC_KEY_MANAGER_SUPPORTED */ +} esp_rsa_ds_volatile_key_storage_t; + +/** + * Inline storage for persistent eFuse DS keys. + * All data is deep-copied — no external references. + */ +typedef struct { + esp_rsa_ds_common_key_storage_metadata_t metadata; + uint8_t efuse_key_id; + uint8_t reserved; /* explicit padding */ + uint16_t rsa_length_bits; + uint8_t reserved2[2]; /* explicit padding for ds_data 4-byte alignment */ + esp_ds_data_t ds_data; +} esp_rsa_ds_efuse_key_storage_t; + +ESP_STATIC_ASSERT(offsetof(esp_rsa_ds_efuse_key_storage_t, ds_data) % 4 == 0, + "ds_data must be 4-byte aligned in esp_rsa_ds_efuse_key_storage_t"); + +#if SOC_KEY_MANAGER_SUPPORTED +/** + * Inline storage for persistent Key Manager DS keys. + * All data is deep-copied — no external references. + */ +typedef struct { + esp_rsa_ds_common_key_storage_metadata_t metadata; + uint16_t rsa_length_bits; + esp_ds_data_t ds_data; + esp_key_mgr_key_recovery_info_t key_recovery_info; +} esp_rsa_ds_km_key_storage_t; + +ESP_STATIC_ASSERT(offsetof(esp_rsa_ds_km_key_storage_t, ds_data) % 4 == 0, + "ds_data must be 4-byte aligned in esp_rsa_ds_km_key_storage_t"); +ESP_STATIC_ASSERT(offsetof(esp_rsa_ds_km_key_storage_t, key_recovery_info) % 4 == 0, + "key_recovery_info must be 4-byte aligned in esp_rsa_ds_km_key_storage_t"); +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + +/** + * @brief Read the key_source tag from any storage struct. + * + * All storage structs share the layout: [version(1)][key_source(1)][...] + */ +static inline esp_rsa_ds_key_source_t rsa_ds_storage_get_key_source(const uint8_t *key_buffer) +{ + return (esp_rsa_ds_key_source_t)key_buffer[1]; +} + +/** + * @brief Calculate the storage buffer size for an import operation. + * + * For volatile keys: returns pointer-based storage size (small). + * For persistent keys: inspects the user struct to determine key source + * and returns the corresponding inline storage struct size (large). + */ +static size_t esp_rsa_ds_get_storage_size(const esp_rsa_ds_opaque_key_t *key, bool persistent) +{ + if (!persistent) { + return sizeof(esp_rsa_ds_volatile_key_storage_t); + } + +#if SOC_KEY_MANAGER_SUPPORTED + if (key->key_recovery_info) { + return sizeof(esp_rsa_ds_km_key_storage_t); + } +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + + (void)key; + return sizeof(esp_rsa_ds_efuse_key_storage_t); +} + +/** + * @brief Calculate the expected storage size from an already-serialized storage buffer. + * + * @param key_buffer The storage buffer. + * @param key_buffer_size Size of @p key_buffer in bytes. + * @param persistent true if the key is persistent (inline data), false if volatile. + * @param[out] expected_storage_size The expected minimum buffer size. + */ +static psa_status_t esp_rsa_ds_get_expected_storage_size(const uint8_t *key_buffer, + size_t key_buffer_size, + bool persistent, + size_t *expected_storage_size) +{ + if (key_buffer_size < sizeof(esp_rsa_ds_common_key_storage_metadata_t)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (key_buffer[0] == ESP_RSA_DS_KEY_STORAGE_VERSION_INVALID || key_buffer[0] >= ESP_RSA_DS_KEY_STORAGE_VERSION_MAX) { + return PSA_ERROR_DATA_INVALID; + } + + *expected_storage_size = 0; + + if (!persistent) { + *expected_storage_size = sizeof(esp_rsa_ds_volatile_key_storage_t); + return PSA_SUCCESS; + } + + esp_rsa_ds_key_source_t key_source = rsa_ds_storage_get_key_source(key_buffer); + + switch (key_source) { +#if SOC_KEY_MANAGER_SUPPORTED + case ESP_RSA_DS_KEY_SOURCE_KEY_MGR: + *expected_storage_size = sizeof(esp_rsa_ds_km_key_storage_t); + return PSA_SUCCESS; +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + case ESP_RSA_DS_KEY_SOURCE_EFUSE: + *expected_storage_size = sizeof(esp_rsa_ds_efuse_key_storage_t); + return PSA_SUCCESS; + default: + return PSA_ERROR_DATA_INVALID; + } +} + +/** + * @brief Validate a storage buffer and extract the per-source DS parameters. + * + * Centralises the metadata + size validation and the per-source pointer/value extraction + * shared by the sign-hash and asymmetric-decrypt entry points. On success, all out-params + * are filled. On failure, out-params are left untouched. + * + * @param key_buffer The PSA storage buffer. + * @param key_buffer_size Size of @p key_buffer in bytes. + * @param is_persistent Persistence flag derived from the PSA key attributes. + * @param[out] key_source Storage key source tag (eFuse / Key Manager). + * @param[out] rsa_length_bits RSA key length in bits, taken from the storage struct. + * @param[out] ds_data Pointer to the in-storage @c esp_ds_data_t (volatile: caller's + * mmap'd flash buffer; persistent: the inline copy). + * @param[out] hmac_key_id HMAC key id for the DS peripheral. + * @param[out] km_ri Pointer to the @c esp_key_mgr_key_recovery_info_t to pass to + * @c esp_key_mgr_activate_key, or NULL when the key source is + * not Key Manager. Only present on KM-capable SoCs. + * + * @return PSA_SUCCESS, or a PSA error if validation fails. + */ +static psa_status_t esp_rsa_ds_extract_storage( + const uint8_t *key_buffer, + size_t key_buffer_size, + bool is_persistent, + esp_rsa_ds_key_source_t *key_source, + uint16_t *rsa_length_bits, + const esp_ds_data_t **ds_data, + hmac_key_id_t *hmac_key_id +#if SOC_KEY_MANAGER_SUPPORTED + , esp_key_mgr_key_recovery_info_t **km_ri +#endif /* SOC_KEY_MANAGER_SUPPORTED */ +) +{ + size_t expected_storage_size = 0; + psa_status_t status = esp_rsa_ds_get_expected_storage_size(key_buffer, key_buffer_size, + is_persistent, &expected_storage_size); + if (status != PSA_SUCCESS) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (key_buffer_size < expected_storage_size) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + esp_rsa_ds_key_source_t src = rsa_ds_storage_get_key_source(key_buffer); + uint16_t bits = 0; + const esp_ds_data_t *data = NULL; + hmac_key_id_t hmac_id = 0; +#if SOC_KEY_MANAGER_SUPPORTED + esp_key_mgr_key_recovery_info_t *ri = NULL; +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + + if (!is_persistent) { + const esp_rsa_ds_volatile_key_storage_t *ptr_st = + (const esp_rsa_ds_volatile_key_storage_t *)key_buffer; + bits = ptr_st->ds_data_ctx->rsa_length_bits; + data = ptr_st->ds_data_ctx->esp_ds_data; + hmac_id = ptr_st->ds_data_ctx->efuse_key_id; +#if SOC_KEY_MANAGER_SUPPORTED + if (src == ESP_RSA_DS_KEY_SOURCE_KEY_MGR) { + hmac_id = HMAC_KEY_KM; + ri = ptr_st->key_recovery_info; + } +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + } else { + switch (src) { + case ESP_RSA_DS_KEY_SOURCE_EFUSE: { + const esp_rsa_ds_efuse_key_storage_t *efuse_st = + (const esp_rsa_ds_efuse_key_storage_t *)key_buffer; + bits = efuse_st->rsa_length_bits; + data = &efuse_st->ds_data; + hmac_id = efuse_st->efuse_key_id; + break; + } +#if SOC_KEY_MANAGER_SUPPORTED + case ESP_RSA_DS_KEY_SOURCE_KEY_MGR: { + const esp_rsa_ds_km_key_storage_t *km_st = + (const esp_rsa_ds_km_key_storage_t *)key_buffer; + bits = km_st->rsa_length_bits; + data = &km_st->ds_data; + hmac_id = HMAC_KEY_KM; + /* esp_key_mgr_activate_key() takes a non-const pointer for API compatibility + * but does not modify the recovery info. The cast away const is therefore safe; + * if that contract ever changes, copy the recovery info to a local first. */ + ri = (esp_key_mgr_key_recovery_info_t *)&km_st->key_recovery_info; + break; + } +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + default: + return PSA_ERROR_INVALID_ARGUMENT; + } + } + + if (bits % 32 != 0 || bits < 1024 || bits > SOC_DS_SIGNATURE_MAX_BIT_LEN) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (data->rsa_length != (bits / 32) - 1) { + return PSA_ERROR_DATA_INVALID; + } + + *key_source = src; + *rsa_length_bits = bits; + *ds_data = data; + *hmac_key_id = hmac_id; +#if SOC_KEY_MANAGER_SUPPORTED + *km_ri = ri; +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + + return PSA_SUCCESS; +} + void esp_rsa_ds_release_ds_lock(void); static int esp_rsa_ds_pad(esp_rsa_ds_padding_t padding, psa_algorithm_t hash_alg, unsigned int hashlen, @@ -129,37 +406,48 @@ psa_status_t esp_rsa_ds_opaque_sign_hash_start( return PSA_ERROR_INVALID_ARGUMENT; } - if (key_buffer_size < sizeof(esp_rsa_ds_opaque_key_t)) { - return PSA_ERROR_INVALID_ARGUMENT; - } + bool is_persistent = esp_opaque_key_is_persistent(attributes); if (!PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) && !PSA_ALG_IS_RSA_PSS(alg)) { return PSA_ERROR_NOT_SUPPORTED; } - operation->alg = alg; + 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_key_id = 0; +#if SOC_KEY_MANAGER_SUPPORTED + esp_key_mgr_key_recovery_info_t *km_ri = NULL; +#endif /* SOC_KEY_MANAGER_SUPPORTED */ - const esp_rsa_ds_opaque_key_t *opaque_key = (const esp_rsa_ds_opaque_key_t *)key_buffer; - operation->esp_rsa_ds_opaque_key = opaque_key; - - if (esp_rsa_ds_validate_opaque_key(opaque_key) != PSA_SUCCESS) { - return PSA_ERROR_INVALID_ARGUMENT; + psa_status_t status = esp_rsa_ds_extract_storage( + key_buffer, key_buffer_size, is_persistent, + &key_source, &rsa_length_bits, &ds_data, &hmac_key_id +#if SOC_KEY_MANAGER_SUPPORTED + , &km_ri +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + ); + if (status != PSA_SUCCESS) { + return status; } + operation->alg = alg; + operation->key_buffer = key_buffer; + if ((xSemaphoreTake(s_ds_lock, s_timeout_ms / portTICK_PERIOD_MS) != pdTRUE)) { return PSA_ERROR_GENERIC_ERROR; } esp_rsa_ds_padding_t padding = ESP_RSA_DS_PADDING_INVALID; - if (PSA_ALG_IS_RSA_PSS(operation->alg)) { + if (PSA_ALG_IS_RSA_PSS(alg)) { padding = ESP_RSA_DS_PADDING_PSS; - } else if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(operation->alg)) { + } else if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg)) { padding = ESP_RSA_DS_PADDING_PKCS_V15; } - psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH(operation->alg); + psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH(alg); - const size_t words_len = (opaque_key->ds_data_ctx->rsa_length_bits / 32); + const size_t words_len = rsa_length_bits / 32; const size_t rsa_len_bytes = words_len * 4; operation->sig_buffer_size = rsa_len_bytes; operation->sig_buffer = NULL; @@ -170,7 +458,7 @@ psa_status_t esp_rsa_ds_opaque_sign_hash_start( return PSA_ERROR_INSUFFICIENT_MEMORY; } - psa_status_t status = esp_rsa_ds_pad( + status = esp_rsa_ds_pad( padding, hash_alg, hash_length, hash, -1, em, rsa_len_bytes); if (status != PSA_SUCCESS) { goto error; @@ -188,24 +476,21 @@ psa_status_t esp_rsa_ds_opaque_sign_hash_start( sig_words[i] = SWAP_INT32(em_words[words_len - (i + 1)]); } - hmac_key_id_t hmac_key_id = opaque_key->ds_data_ctx->efuse_key_id; - #if SOC_KEY_MANAGER_SUPPORTED - esp_key_mgr_key_recovery_info_t *km_key_recovery_info = operation->esp_rsa_ds_opaque_key->key_recovery_info; - if (km_key_recovery_info) { - err = esp_key_mgr_activate_key(km_key_recovery_info); + if (key_source == ESP_RSA_DS_KEY_SOURCE_KEY_MGR) { + err = esp_key_mgr_activate_key(km_ri); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to activate key: 0x%x", err); status = PSA_ERROR_INVALID_HANDLE; goto error; } - hmac_key_id = HMAC_KEY_KM; operation->is_km_key_active = true; + operation->km_ri = km_ri; } #endif /* SOC_KEY_MANAGER_SUPPORTED */ err = esp_ds_start_sign((const void *)operation->sig_buffer, - opaque_key->ds_data_ctx->esp_ds_data, + ds_data, hmac_key_id, &operation->esp_rsa_ds_ctx); if (err != ESP_OK) { @@ -239,7 +524,7 @@ psa_status_t esp_rsa_ds_opaque_sign_hash_complete( return PSA_ERROR_BAD_STATE; } - int expected_signature_size = operation->esp_rsa_ds_opaque_key->ds_data_ctx->rsa_length_bits / 8; + size_t expected_signature_size = operation->sig_buffer_size; if (signature_size < expected_signature_size) { return PSA_ERROR_BUFFER_TOO_SMALL; } @@ -277,15 +562,15 @@ psa_status_t esp_rsa_ds_opaque_sign_hash_abort( return PSA_ERROR_INVALID_ARGUMENT; } - if (operation->esp_rsa_ds_opaque_key) { #if SOC_KEY_MANAGER_SUPPORTED - esp_key_mgr_key_recovery_info_t *km_key_recovery_info = operation->esp_rsa_ds_opaque_key->key_recovery_info; - if (km_key_recovery_info && operation->is_km_key_active) { - esp_key_mgr_deactivate_key(km_key_recovery_info->key_type); - operation->is_km_key_active = false; - } + if (operation->is_km_key_active) { + esp_key_mgr_deactivate_key(operation->km_ri->key_type); + operation->is_km_key_active = false; + } #endif /* SOC_KEY_MANAGER_SUPPORTED */ - operation->esp_rsa_ds_opaque_key = NULL; + + if (operation->key_buffer) { + operation->key_buffer = NULL; } if (operation->esp_rsa_ds_ctx) { @@ -362,33 +647,100 @@ psa_status_t esp_rsa_ds_opaque_import_key( return PSA_ERROR_INVALID_ARGUMENT; } - if (key_buffer_size < sizeof(esp_rsa_ds_opaque_key_t)) { - return PSA_ERROR_BUFFER_TOO_SMALL; - } - 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); if (ret != PSA_SUCCESS) { return ret; } - /* Shallow copy: key buffer holds the context; esp_ds_data points to the caller's data. - * The key material (esp_rsa_ds_opaque_key_t and the esp_ds_data_t it points to) must remain - * valid until psa_destroy_key() is called on this key. */ - memcpy(key_buffer, opaque_key, sizeof(esp_rsa_ds_opaque_key_t)); - *key_buffer_length = sizeof(esp_rsa_ds_opaque_key_t); + bool is_persistent = esp_opaque_key_is_persistent(attributes); + + esp_rsa_ds_key_source_t key_source = ESP_RSA_DS_KEY_SOURCE_EFUSE; +#if SOC_KEY_MANAGER_SUPPORTED + if (opaque_key->key_recovery_info) { + key_source = ESP_RSA_DS_KEY_SOURCE_KEY_MGR; + } +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + + if (!is_persistent) { + /* Volatile: store pointers only — caller keeps data alive. + * This preserves the heap savings of mmap'd flash data from esp_secure_cert_mgr. */ + if (key_buffer_size < sizeof(esp_rsa_ds_volatile_key_storage_t)) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + esp_rsa_ds_volatile_key_storage_t *storage = (esp_rsa_ds_volatile_key_storage_t *)key_buffer; + storage->metadata.version = ESP_RSA_DS_KEY_STORAGE_VERSION_V1; + storage->metadata.key_source = key_source; + storage->ds_data_ctx = opaque_key->ds_data_ctx; +#if SOC_KEY_MANAGER_SUPPORTED + storage->key_recovery_info = opaque_key->key_recovery_info; +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + *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); + } + } + *bits = opaque_key->ds_data_ctx->rsa_length_bits; return PSA_SUCCESS; } size_t esp_rsa_ds_opaque_size_function( + const psa_key_attributes_t *attributes, psa_key_type_t key_type, - size_t key_bits) + const uint8_t *data, + size_t data_length) { (void)key_type; - (void)key_bits; - return sizeof(esp_rsa_ds_opaque_key_t); + bool is_persistent = esp_opaque_key_is_persistent(attributes); + + if (!data || data_length < sizeof(esp_rsa_ds_opaque_key_t)) { + /* Data too short to inspect the user struct — return the largest possible + * size for the persistence flavor so import has enough room to write whichever + * variant ends up being needed. import_key() does the real validation. */ + if (!is_persistent) { + return sizeof(esp_rsa_ds_volatile_key_storage_t); + } +#if SOC_KEY_MANAGER_SUPPORTED + return sizeof(esp_rsa_ds_km_key_storage_t); +#else + return sizeof(esp_rsa_ds_efuse_key_storage_t); +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + } + + return esp_rsa_ds_get_storage_size((const esp_rsa_ds_opaque_key_t *)data, is_persistent); } void esp_rsa_ds_opaque_set_session_timeout(int timeout_ms) @@ -416,8 +768,7 @@ psa_status_t esp_rsa_ds_opaque_asymmetric_decrypt( esp_err_t err = ESP_FAIL; - if (!attributes || !key || key_length < sizeof(esp_rsa_ds_opaque_key_t) || - !input || input_length < 1 || !output || !output_length) { + if (!attributes || !key || !input || input_length < 1 || !output || !output_length) { return PSA_ERROR_INVALID_ARGUMENT; } @@ -425,14 +776,28 @@ psa_status_t esp_rsa_ds_opaque_asymmetric_decrypt( return PSA_ERROR_NOT_SUPPORTED; } - const esp_rsa_ds_opaque_key_t *opaque_key = (const esp_rsa_ds_opaque_key_t *)key; + bool is_persistent = esp_opaque_key_is_persistent(attributes); - if (esp_rsa_ds_validate_opaque_key(opaque_key) != PSA_SUCCESS) { - 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_key_id = 0; +#if SOC_KEY_MANAGER_SUPPORTED + esp_key_mgr_key_recovery_info_t *km_ri = NULL; +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + + psa_status_t status = esp_rsa_ds_extract_storage( + key, key_length, is_persistent, + &key_source, &rsa_length_bits, &ds_data, &hmac_key_id +#if SOC_KEY_MANAGER_SUPPORTED + , &km_ri +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + ); + if (status != PSA_SUCCESS) { + return status; } - size_t key_bits = opaque_key->ds_data_ctx->rsa_length_bits; - if (input_length != (key_bits / 8)) { + if (input_length != (rsa_length_bits / 8)) { return PSA_ERROR_INVALID_ARGUMENT; } @@ -447,7 +812,7 @@ psa_status_t esp_rsa_ds_opaque_asymmetric_decrypt( return PSA_ERROR_GENERIC_ERROR; } - size_t ilen = key_bits / 8; + size_t ilen = rsa_length_bits / 8; size_t data_len = ilen / 4; uint32_t *em_words = heap_caps_malloc_prefer(sizeof(uint32_t) * data_len, 1, MALLOC_CAP_32BIT | MALLOC_CAP_INTERNAL, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL); if (em_words == NULL) { @@ -459,49 +824,41 @@ psa_status_t esp_rsa_ds_opaque_asymmetric_decrypt( em_words[i] = SWAP_INT32(((uint32_t *)input)[(data_len) - (i + 1)]); } - esp_rsa_ds_opaque_sign_hash_operation_t operation = {0}; - operation.alg = alg; - operation.esp_rsa_ds_opaque_key = opaque_key; - operation.sig_buffer = em_words; - - hmac_key_id_t hmac_key_id = opaque_key->ds_data_ctx->efuse_key_id; #if SOC_KEY_MANAGER_SUPPORTED - esp_key_mgr_key_recovery_info_t *km_key_recovery_info = opaque_key->key_recovery_info; - if (km_key_recovery_info) { - err = esp_key_mgr_activate_key(km_key_recovery_info); + bool is_km_key_active = false; + if (key_source == ESP_RSA_DS_KEY_SOURCE_KEY_MGR) { + err = esp_key_mgr_activate_key(km_ri); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to activate key: 0x%x", err); heap_caps_free(em_words); esp_rsa_ds_release_ds_lock(); return PSA_ERROR_INVALID_HANDLE; } - hmac_key_id = HMAC_KEY_KM; - operation.is_km_key_active = true; + is_km_key_active = true; } #endif /* SOC_KEY_MANAGER_SUPPORTED */ + esp_ds_context_t *ds_ctx = NULL; err = esp_ds_start_sign((const void *)em_words, - opaque_key->ds_data_ctx->esp_ds_data, + ds_data, hmac_key_id, - &operation.esp_rsa_ds_ctx); + &ds_ctx); if (err != ESP_OK) { heap_caps_free(em_words); #if SOC_KEY_MANAGER_SUPPORTED - if (km_key_recovery_info && operation.is_km_key_active) { - esp_key_mgr_deactivate_key(km_key_recovery_info->key_type); - operation.is_km_key_active = false; - } + if (is_km_key_active) { + esp_key_mgr_deactivate_key(km_ri->key_type); + } #endif /* SOC_KEY_MANAGER_SUPPORTED */ esp_rsa_ds_release_ds_lock(); return PSA_ERROR_GENERIC_ERROR; } - err = esp_ds_finish_sign((void *)em_words, operation.esp_rsa_ds_ctx); + err = esp_ds_finish_sign((void *)em_words, ds_ctx); #if SOC_KEY_MANAGER_SUPPORTED - if (km_key_recovery_info && operation.is_km_key_active) { - esp_key_mgr_deactivate_key(km_key_recovery_info->key_type); - operation.is_km_key_active = false; + if (is_km_key_active) { + esp_key_mgr_deactivate_key(km_ri->key_type); } #endif /* SOC_KEY_MANAGER_SUPPORTED */ 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 c5a88205b43..d762a20f2cc 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 @@ -22,14 +22,13 @@ extern "C" { #define PSA_KEY_LOCATION_ESP_RSA_DS ((psa_key_location_t) 0x800003) -/* IDF-15427: ESP-PSA driver does not support persistent RSA DS keys as of now */ -#if 0 -/* @brief Construct a lifetime for ESP RSA DS keys with default persistence */ +/** + * @brief Construct a persistent lifetime for ESP RSA DS keys + */ #define PSA_KEY_LIFETIME_ESP_RSA_DS \ PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( \ PSA_KEY_PERSISTENCE_DEFAULT, \ PSA_KEY_LOCATION_ESP_RSA_DS) -#endif /** * @brief Construct a volatile lifetime for ESP RSA DS keys @@ -145,15 +144,23 @@ psa_status_t esp_rsa_ds_opaque_import_key( size_t *bits); /** - * @brief Return the size of the RSA DS opaque key in bytes + * @brief Return the storage buffer size required for an RSA DS opaque key * - * @param key_type Key type - * @param key_bits Key bits - * @return Size of the RSA DS opaque key in bytes + * For volatile keys, returns a small pointer-based storage size. + * For persistent keys, inspects the user-facing import data to determine + * the key source and returns the corresponding inline storage struct size. + * + * @param attributes Key attributes (used to check persistence) + * @param key_type Key type + * @param data Import data (user-facing esp_rsa_ds_opaque_key_t) + * @param data_length Length of import data + * @return Size of the storage buffer in bytes, or 0 on error */ size_t esp_rsa_ds_opaque_size_function( + const psa_key_attributes_t *attributes, psa_key_type_t key_type, - size_t key_bits); + const uint8_t *data, + size_t data_length); /** * @brief Set the timeout for the RSA DS session diff --git a/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_rsa_ds_contexts.h b/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_rsa_ds_contexts.h index 713b96fcf65..c907e711f4d 100644 --- a/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_rsa_ds_contexts.h +++ b/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_rsa_ds_contexts.h @@ -35,9 +35,14 @@ typedef enum { * @brief ESP DS data context * This context is used to store the ESP DS data. * - * When passed to psa_import_key() for PSA_KEY_LIFETIME_ESP_RSA_DS_VOLATILE, the key material - * (this struct and the esp_ds_data_t pointed to by esp_ds_data) must remain valid - * until psa_destroy_key() is called on the imported key. + * For persistent keys (PSA_KEY_LIFETIME_ESP_RSA_DS), the driver deep-copies + * all referenced data at import time. The caller's data does not need to + * remain valid after psa_import_key() returns. + * + * For volatile keys (PSA_KEY_LIFETIME_ESP_RSA_DS_VOLATILE), the driver stores + * pointers to the caller's data. This struct and the esp_ds_data_t pointed to + * by esp_ds_data must remain valid until psa_destroy_key() is called. + * This preserves the heap savings of mmap'd flash data from esp_secure_cert_mgr. */ typedef struct { esp_ds_data_t *esp_ds_data; /**< Pointer to the esp ds data */ @@ -55,9 +60,10 @@ typedef struct { #if !(__DOXYGEN__) // No need to document these structures, these are internal to the driver /* The buffers are stored in the little-endian format */ typedef struct { - const esp_rsa_ds_opaque_key_t *esp_rsa_ds_opaque_key; /**< Pointer to the esp ds opaque key */ + const uint8_t *key_buffer; /**< Pointer to per-source storage struct in key slot */ #if SOC_KEY_MANAGER_SUPPORTED bool is_km_key_active; /**< Flag indicating if the Key Manager key is active for this operation */ + esp_key_mgr_key_recovery_info_t *km_ri; /**< Pointer to the key recovery info for DS key */ #endif /* SOC_KEY_MANAGER_SUPPORTED */ psa_algorithm_t alg; /**< Algorithm used in the sign operation */ uint32_t *sig_buffer; /**< Buffer to hold the signature */ diff --git a/docs/en/api-reference/peripherals/ds.rst b/docs/en/api-reference/peripherals/ds.rst index 6cac5199176..c2ad72223bc 100644 --- a/docs/en/api-reference/peripherals/ds.rst +++ b/docs/en/api-reference/peripherals/ds.rst @@ -113,8 +113,17 @@ To use the DS peripheral for signing or decryption in application code (outside psa_destroy_key(key_id); -Example for SSL Mutual Authentication Using DS ----------------------------------------------- +Persistent vs. Volatile RSA_DS PSA Keys +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The driver supports two PSA key lifetimes for RSA_DS keys: + +- ``PSA_KEY_LIFETIME_ESP_RSA_DS_VOLATILE`` (used in the example above) stores only pointers to the caller-supplied ``esp_ds_data_ctx_t`` and any Key Manager recovery info in the PSA key slot. The referenced buffers must remain valid until :cpp:func:`psa_destroy_key` is called. This avoids deep-copying large blobs such as :cpp:type:`esp_ds_data_t` (≈1200-1600 bytes, chip-dependent) when they already live in mmap'd flash via ``esp_secure_cert_mgr``. + +- ``PSA_KEY_LIFETIME_ESP_RSA_DS`` (persistent) deep-copies the encrypted key material into the PSA key slot at :cpp:func:`psa_import_key` time and PSA persists it to NVS together with the rest of the key attributes. The caller is free to release the import-time buffers once :cpp:func:`psa_import_key` returns; subsequent :cpp:func:`psa_sign_hash` / :cpp:func:`psa_asymmetric_decrypt` calls retrieve the bytes back from NVS automatically. Use this lifetime when the application wants the key to survive reboots without having to reload the ``esp_ds_data_ctx_t`` from external storage on every boot. + +Example for SSL Mutual Authentication Using RSA_DS +--------------------------------------------------- The SSL mutual authentication example that previously lived under ``examples/protocols/mqtt/ssl_ds`` is now shipped with the standalone `espressif/mqtt `__ component. Follow the component documentation to fetch the SSL DS example and build it together with ESP-MQTT. The example continues to use ``mqtt_client`` (implemented by ESP-MQTT) to connect to ``test.mosquitto.org`` over mutual-authenticated TLS, with the TLS portion handled by ESP-TLS. diff --git a/docs/zh_CN/api-reference/peripherals/ds.rst b/docs/zh_CN/api-reference/peripherals/ds.rst index 22aa2d288d8..dc3a97bf725 100644 --- a/docs/zh_CN/api-reference/peripherals/ds.rst +++ b/docs/zh_CN/api-reference/peripherals/ds.rst @@ -113,8 +113,17 @@ TLS 连接所需的 DS 外设配置 psa_destroy_key(key_id); -使用 DS 外设进行 SSL 双向认证 ------------------------------ +持久化与易失性 RSA_DS PSA 密钥 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +驱动支持两种 PSA 密钥生命周期: + +- ``PSA_KEY_LIFETIME_ESP_RSA_DS_VOLATILE`` (上述示例中使用)只在 PSA 密钥 槽中保存指向调用方提供的 ``esp_ds_data_ctx_t`` 以及密钥管理器恢复信息的 指针。被引用的缓冲区必须保持有效,直到调用 :cpp:func:`psa_destroy_key` 为止。这样可避免对大块数据(例如 :cpp:type:`esp_ds_data_t`,约 1200–1600 字节,因芯片而异)进行深拷贝;当这些数据已经通过 ``esp_secure_cert_mgr`` 从 flash 中以 mmap 形式可用时,这一点尤其有用。 + +- ``PSA_KEY_LIFETIME_ESP_RSA_DS`` (持久化)在调用 :cpp:func:`psa_import_key` 时将加密的密钥数据深拷贝到 PSA 密钥槽中,并 由 PSA 与其他密钥属性一同持久化到 NVS。导入返回后,调用方即可释放原始 缓冲区;后续的 :cpp:func:`psa_sign_hash` 和 :cpp:func:`psa_asymmetric_decrypt` 调用会自动从 NVS 取回所需数据。 当应用希望密钥在重启后依然可用,且无需在每次启动时重新从外部存储 载入 ``esp_ds_data_ctx_t`` 时,应使用此生命周期。 + +使用 RSA_DS 外设进行 SSL 双向认证 +------------------------------------ 此前位于 ``examples/protocols/mqtt/ssl_ds`` 目录下的 SSL 双向认证示例现已随独立的 `espressif/mqtt `__ 组件一同提供。请参照该组件文档获取 SSL DS 示例,并与 ESP-MQTT 一同构建。该示例仍使用 ``mqtt_client`` (由 ESP-MQTT 实现),通过双向认证 TLS 连接至 ``test.mosquitto.org``,其中 TLS 通信层仍由 ESP-TLS 实现。