diff --git a/components/esp-tls/esp_tls_mbedtls.c b/components/esp-tls/esp_tls_mbedtls.c index 46aab343699..4e13617ee8a 100644 --- a/components/esp-tls/esp_tls_mbedtls.c +++ b/components/esp-tls/esp_tls_mbedtls.c @@ -639,7 +639,9 @@ static esp_err_t set_pki_context(esp_tls_t *tls, const esp_tls_pki_t *pki) esp_ecdsa_opaque_key_t opaque_key = { .curve = curve, .efuse_block = tls->ecdsa_efuse_blk, - .use_km_key = false, +#if SOC_KEY_MANAGER_SUPPORTED + .key_recovery_info = NULL, +#endif /* SOC_KEY_MANAGER_SUPPORTED */ }; // Import opaque key reference @@ -1420,6 +1422,10 @@ static esp_err_t esp_mbedtls_init_pk_ctx_for_ds(const void *pki) psa_key_id_t ds_key_id = 0; psa_status_t status = PSA_ERROR_GENERIC_ERROR; + + esp_rsa_ds_opaque_key_t rsa_ds_opaque_key = {0}; + rsa_ds_opaque_key.ds_data_ctx = ds_data; + psa_key_attributes_t ds_key_attributes = PSA_KEY_ATTRIBUTES_INIT; psa_algorithm_t alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH); #ifdef CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 @@ -1427,14 +1433,14 @@ static esp_err_t esp_mbedtls_init_pk_ctx_for_ds(const void *pki) #endif /* CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 */ psa_set_key_type(&ds_key_attributes, PSA_KEY_TYPE_RSA_KEY_PAIR); - psa_set_key_bits(&ds_key_attributes, ds_data->rsa_length_bits); + psa_set_key_bits(&ds_key_attributes, rsa_ds_opaque_key.ds_data_ctx->rsa_length_bits); psa_set_key_usage_flags(&ds_key_attributes, PSA_KEY_USAGE_SIGN_HASH); psa_set_key_algorithm(&ds_key_attributes, alg); - psa_set_key_lifetime(&ds_key_attributes, PSA_KEY_LIFETIME_ESP_RSA_DS); + psa_set_key_lifetime(&ds_key_attributes, PSA_KEY_LIFETIME_ESP_RSA_DS_VOLATILE); status = psa_import_key(&ds_key_attributes, - (const uint8_t *)ds_data, - sizeof(esp_ds_data_ctx_t), - &ds_key_id); + (const uint8_t *)&rsa_ds_opaque_key, + sizeof(rsa_ds_opaque_key), + &ds_key_id); psa_reset_key_attributes(&ds_key_attributes); if (status != PSA_SUCCESS) { ESP_LOGE(TAG, "Failed to import DS key to PSA, status = %d", status); diff --git a/components/esp_hal_security/include/hal/key_mgr_types.h b/components/esp_hal_security/include/hal/key_mgr_types.h index 48d764b9015..14f3a8c6652 100644 --- a/components/esp_hal_security/include/hal/key_mgr_types.h +++ b/components/esp_hal_security/include/hal/key_mgr_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -48,7 +48,7 @@ typedef enum { ESP_KEY_MGR_PSRAM_XTS_AES_KEY, /* PSRAM XTS-AES key */ } esp_key_mgr_key_type_t; -/* +/** * @brief Key Manager key usage type */ typedef enum { @@ -112,30 +112,37 @@ typedef enum { ESP_KEY_MGR_FORCE_USE_KM_DS_KEY = 3, } esp_key_mgr_force_use_km_key_t; -// store huk info, occupy 96 words +/** + * @brief HUK info structure, stores HUK recovery information + */ typedef struct PACKED_ATTR { #define HUK_INFO_LEN 660 - uint8_t info[HUK_INFO_LEN]; - uint32_t crc; + uint8_t info[HUK_INFO_LEN]; /*!< HUK info data */ + uint32_t crc; /*!< CRC of the HUK info */ } esp_key_mgr_huk_info_t; -// store key info, occupy 512 bits +/** + * @brief Key info structure, stores key recovery information (512 bits) + */ typedef struct PACKED_ATTR { #define KEY_INFO_LEN 64 - uint8_t info[KEY_INFO_LEN]; - uint32_t crc; + uint8_t info[KEY_INFO_LEN]; /*!< Key info data */ + uint32_t crc; /*!< CRC of the key info */ } esp_key_mgr_key_info_t; +/** + * @brief Key recovery info structure containing all data needed to recover a deployed key + */ typedef struct WORD_ALIGNED_ATTR PACKED_ATTR { #define KEY_HUK_SECTOR_MAGIC 0xDEA5CE5A - uint32_t magic; - uint32_t version; // for backward compatibility - uint8_t key_type; - uint8_t key_len; - uint8_t key_deployment_mode; - uint8_t reserved[13]; - esp_key_mgr_huk_info_t huk_info; - esp_key_mgr_key_info_t key_info[2]; // at most 2 key info (XTS-512_1 and XTS-512_2), at least use 1 + uint32_t magic; /*!< Magic number for validation */ + uint32_t version; /*!< Version for backward compatibility */ + uint8_t key_type; /*!< Type of the deployed key */ + uint8_t key_len; /*!< Length of the deployed key */ + uint8_t key_deployment_mode; /*!< Deployment mode used for the key */ + uint8_t reserved[13]; /*!< Reserved for future use */ + esp_key_mgr_huk_info_t huk_info; /*!< HUK recovery info */ + esp_key_mgr_key_info_t key_info[2]; /*!< Key info (up to 2 entries for XTS-AES-256) */ } esp_key_mgr_key_recovery_info_t; #ifdef __cplusplus diff --git a/components/esp_security/include/esp_key_mgr.h b/components/esp_security/include/esp_key_mgr.h index 5e768c681d7..f54b7cdd33c 100644 --- a/components/esp_security/include/esp_key_mgr.h +++ b/components/esp_security/include/esp_key_mgr.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -33,36 +33,48 @@ extern "C" { #define KEY_MGR_ECDH0_INFO_SIZE 64 #define KEY_MGR_PLAINTEXT_KEY_SIZE 32 +/** + * @brief Configuration for deploying a key in AES mode + */ typedef struct { - esp_key_mgr_key_type_t key_type; - esp_key_mgr_key_len_t key_len; - bool use_pre_generated_huk_info; - bool use_pre_generated_sw_init_key; - WORD_ALIGNED_ATTR esp_key_mgr_huk_info_t huk_info; - WORD_ALIGNED_ATTR uint8_t sw_init_key[KEY_MGR_SW_INIT_KEY_SIZE]; - WORD_ALIGNED_ATTR uint8_t k2_info[KEY_MGR_K2_INFO_SIZE]; - WORD_ALIGNED_ATTR uint8_t k1_encrypted[2][KEY_MGR_K1_ENCRYPTED_SIZE]; + esp_key_mgr_key_type_t key_type; /*!< Type of key to deploy */ + esp_key_mgr_key_len_t key_len; /*!< Length of the key */ + bool use_pre_generated_huk_info; /*!< Use pre-generated HUK info if true */ + bool use_pre_generated_sw_init_key; /*!< Use pre-generated software init key if true */ + WORD_ALIGNED_ATTR esp_key_mgr_huk_info_t huk_info; /*!< HUK recovery info */ + WORD_ALIGNED_ATTR uint8_t sw_init_key[KEY_MGR_SW_INIT_KEY_SIZE]; /*!< Software init key */ + WORD_ALIGNED_ATTR uint8_t k2_info[KEY_MGR_K2_INFO_SIZE]; /*!< K2 info for AES deployment */ + WORD_ALIGNED_ATTR uint8_t k1_encrypted[2][KEY_MGR_K1_ENCRYPTED_SIZE]; /*!< Encrypted K1 key data */ } esp_key_mgr_aes_key_config_t; +/** + * @brief Configuration for deploying a key in ECDH0 mode + */ typedef struct { - esp_key_mgr_key_type_t key_type; - esp_key_mgr_key_len_t key_len; - bool use_pre_generated_huk_info; - WORD_ALIGNED_ATTR esp_key_mgr_huk_info_t huk_info; - WORD_ALIGNED_ATTR uint8_t k1_G[2][KEY_MGR_ECDH0_INFO_SIZE]; + esp_key_mgr_key_type_t key_type; /*!< Type of key to deploy */ + esp_key_mgr_key_len_t key_len; /*!< Length of the key */ + bool use_pre_generated_huk_info; /*!< Use pre-generated HUK info if true */ + WORD_ALIGNED_ATTR esp_key_mgr_huk_info_t huk_info; /*!< HUK recovery info */ + WORD_ALIGNED_ATTR uint8_t k1_G[2][KEY_MGR_ECDH0_INFO_SIZE]; /*!< K1*G points for ECDH0 deployment */ } esp_key_mgr_ecdh0_key_config_t; +/** + * @brief Configuration for deploying a key in Random mode + */ typedef struct { - esp_key_mgr_key_type_t key_type; - esp_key_mgr_key_len_t key_len; - bool use_pre_generated_huk_info; - WORD_ALIGNED_ATTR esp_key_mgr_huk_info_t huk_info; + esp_key_mgr_key_type_t key_type; /*!< Type of key to deploy */ + esp_key_mgr_key_len_t key_len; /*!< Length of the key */ + bool use_pre_generated_huk_info; /*!< Use pre-generated HUK info if true */ + WORD_ALIGNED_ATTR esp_key_mgr_huk_info_t huk_info; /*!< HUK recovery info */ } esp_key_mgr_random_key_config_t; +/** + * @brief ECDH0 key info generated during ECDH0 deployment + */ typedef struct { - esp_key_mgr_key_type_t key_type; - esp_key_mgr_key_len_t key_len; - WORD_ALIGNED_ATTR uint8_t k2_G[2][KEY_MGR_ECDH0_INFO_SIZE]; + esp_key_mgr_key_type_t key_type; /*!< Type of key */ + esp_key_mgr_key_len_t key_len; /*!< Length of the key */ + WORD_ALIGNED_ATTR uint8_t k2_G[2][KEY_MGR_ECDH0_INFO_SIZE]; /*!< K2*G points from ECDH0 deployment */ } esp_key_mgr_ecdh0_info_t; /** @@ -74,63 +86,66 @@ void key_mgr_wait_for_state(esp_key_mgr_state_t state); /** * @brief Deploy key in AES deployment mode - * @input - * key_config(input) AES key configuration - * key_info(output) A writable struct of esp_key_mgr_key_info_t type. - * The recovery information for the the deployed key shall be stored here (Make sure that the memory is valid during the deployment process). + * + * @param[in] key_config AES key configuration + * @param[out] key_info A writable struct of esp_key_mgr_key_recovery_info_t type. + * The recovery information for the deployed key shall be stored here. * @return - * ESP_OK for success - * ESP_FAIL/relevant error code for failure + * - ESP_OK on success + * - ESP_FAIL or relevant error code on failure */ esp_err_t esp_key_mgr_deploy_key_in_aes_mode(const esp_key_mgr_aes_key_config_t *key_config, esp_key_mgr_key_recovery_info_t *key_info); /** * @brief Deploy key in ECDH0 deployment mode - * @input - * key_config(input) ECDH0 key configuration - * key_info(output) A writable struct of esp_key_mgr_key_info_t type. The recovery key info for the deployed key shall be stored here (Make sure that the memory is valid during the deployment process). - * ecdh0_key_info A writable struct of esp_key_mgr_ecdh0_info_t. The ecdh0 info to recover the actual key shall be stored here. + * + * @param[in] key_config ECDH0 key configuration + * @param[out] key_info A writable struct of esp_key_mgr_key_recovery_info_t type. + * The recovery key info for the deployed key shall be stored here. + * @param[out] ecdh0_key_info A writable struct of esp_key_mgr_ecdh0_info_t type. + * The ECDH0 info to recover the actual key shall be stored here. * @return - * ESP_OK for success - * ESP_FAIL/relevant error code for failure + * - ESP_OK on success + * - ESP_FAIL or relevant error code on failure */ esp_err_t esp_key_mgr_deploy_key_in_ecdh0_mode(const esp_key_mgr_ecdh0_key_config_t *key_config, esp_key_mgr_key_recovery_info_t *key_info, esp_key_mgr_ecdh0_info_t *ecdh0_key_info); /** * @brief Deploy key in Random deployment mode - * @input - * key_config(input) Random key configuration - * key_info(output) A writable struct of esp_key_mgr_key_info_t type. The recovery key info for the deployed key shall be stored here (Make sure that the memory is valid during the deployment process). + * + * @param[in] key_config Random key configuration + * @param[out] key_info A writable struct of esp_key_mgr_key_recovery_info_t type. + * The recovery key info for the deployed key shall be stored here. * @return - * ESP_OK for success - * ESP_FAIL/relevant error code for failure + * - ESP_OK on success + * - ESP_FAIL or relevant error code on failure */ esp_err_t esp_key_mgr_deploy_key_in_random_mode(const esp_key_mgr_random_key_config_t *key_config, esp_key_mgr_key_recovery_info_t *key_info); -/* +/** * @brief Recover and Activate a key from the given key info * - * @note - * Once a key of particular type is activated through Key Manager, - * then a different key of the same type cannot be activated at the same time. - * This key must be deactivated first through a call to esp_key_mgr_deactivate_key() - * before activating other key of the same type - * @input - * key_info The key info required to recover the key + * @note Once a key of particular type is activated through Key Manager, + * then a different key of the same type cannot be activated at the same time. + * This key must be deactivated first through a call to esp_key_mgr_deactivate_key() + * before activating other key of the same type. + * + * @param[in] key_recovery_info The key recovery info required to recover the key * @return - * ESP_OK for success - * ESP_FAIL/relevant error code for failure + * - ESP_OK on success + * - ESP_FAIL or relevant error code on failure */ esp_err_t esp_key_mgr_activate_key(esp_key_mgr_key_recovery_info_t *key_recovery_info); -/* - * @brief De-activate a key from the given key info - * The key which is de-activated can no longer be used for any operation - * @input - * key_info The key info required to recover the key +/** + * @brief De-activate a key of the given type + * + * The key which is de-activated can no longer be used for any operation. + * + * @param[in] key_type The type of the key to deactivate * @return - * ESP_OK for success - * ESP_FAIL/relevant error code for failure + * - ESP_OK on success + * - ESP_FAIL or relevant error code on failure */ esp_err_t esp_key_mgr_deactivate_key(esp_key_mgr_key_type_t key_type); diff --git a/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c b/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c index b400fd8aaf3..f0f3742bf48 100644 --- a/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c +++ b/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c @@ -156,8 +156,10 @@ static esp_err_t compute_nvs_keys_with_hmac(esp_efuse_block_t key_blk, nvs_sec_c // Create opaque key reference esp_hmac_opaque_key_t opaque_key = { - .use_km_key = false, - .efuse_block = (uint8_t)key_blk, +#if SOC_KEY_MANAGER_SUPPORTED + .key_recovery_info = NULL, +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + .efuse_key_id = hmac_key_id, }; // Import the opaque key diff --git a/components/mbedtls/esp_tee/esp_tee_mbedtls.cmake b/components/mbedtls/esp_tee/esp_tee_mbedtls.cmake index 9bf64d29ade..c2527532cad 100644 --- a/components/mbedtls/esp_tee/esp_tee_mbedtls.cmake +++ b/components/mbedtls/esp_tee/esp_tee_mbedtls.cmake @@ -59,12 +59,13 @@ foreach(target ${mbedtls_targets}) elseif(CONFIG_MBEDTLS_COMPILER_OPTIMIZATION_PERF) target_compile_options(${target} PRIVATE "-O2") endif() + target_link_libraries(${target} PUBLIC idf::esp_hal_security) + target_link_libraries(${target} PRIVATE idf::esp_security) endforeach() target_link_libraries(${COMPONENT_LIB} INTERFACE ${mbedtls_targets}) -target_link_libraries(tfpsacrypto PUBLIC idf::esp_hal_security) -target_link_libraries(tfpsacrypto PRIVATE idf::esp_security) +target_link_libraries(tfpsacrypto PUBLIC idf::esp_security) target_include_directories(tfpsacrypto PRIVATE ${crypto_port_inc_dirs}) diff --git a/components/mbedtls/port/esp_hmac_pbkdf2.c b/components/mbedtls/port/esp_hmac_pbkdf2.c index 0a8fb8f8451..796dbf2c1d1 100644 --- a/components/mbedtls/port/esp_hmac_pbkdf2.c +++ b/components/mbedtls/port/esp_hmac_pbkdf2.c @@ -52,8 +52,11 @@ esp_err_t esp_hmac_derive_pbkdf2_key(hmac_key_id_t key_id, const uint8_t *salt, // Create opaque key reference esp_hmac_opaque_key_t opaque_key = { - .use_km_key = false, - .efuse_block = (uint8_t)(EFUSE_BLK_KEY0 + key_id), + // TODO: Support key recovery info for HMAC key in PBKDF2 after PSA migration of this API is done +#if SOC_KEY_MANAGER_SUPPORTED + .key_recovery_info = NULL, +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + .efuse_key_id = key_id, }; // Import the opaque key diff --git a/components/mbedtls/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa.c b/components/mbedtls/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa.c index c966e0fd9c1..c981aac0e72 100644 --- a/components/mbedtls/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa.c +++ b/components/mbedtls/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa.c @@ -20,6 +20,10 @@ #include "esp_efuse.h" #include "esp_efuse_chip.h" +#if SOC_KEY_MANAGER_SUPPORTED +#include "esp_key_mgr.h" +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + #if SOC_ECDSA_SUPPORTED #include "hal/ecdsa_types.h" #include "hal/ecdsa_hal.h" @@ -358,8 +362,8 @@ psa_status_t esp_ecdsa_transparent_verify_hash( */ static bool is_efuse_blk_valid(int high_blk, int low_blk) { - return (high_blk >= EFUSE_BLK0 && high_blk < EFUSE_BLK_MAX && - low_blk >= EFUSE_BLK0 && low_blk < EFUSE_BLK_MAX); + return ((high_blk == 0 || (high_blk >= EFUSE_BLK_KEY0 && high_blk < EFUSE_BLK_KEY_MAX)) && + (low_blk >= EFUSE_BLK_KEY0 && low_blk < EFUSE_BLK_KEY_MAX)); } #endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */ @@ -442,15 +446,18 @@ static psa_status_t validate_ecdsa_opaque_key_attributes(const psa_key_attribute { esp_ecdsa_curve_t expected_curve = psa_bits_to_ecdsa_curve(PSA_BITS_TO_BYTES(psa_get_key_bits(attributes))); - if (expected_curve != opaque_key->curve) { + if (expected_curve == ESP_ECDSA_CURVE_MAX || expected_curve != opaque_key->curve) { return PSA_ERROR_INVALID_ARGUMENT; } #if CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN - if (!(opaque_key->use_km_key + if (!(0 +#if SOC_KEY_MANAGER_SUPPORTED + || opaque_key->key_recovery_info +#endif /* SOC_KEY_MANAGER_SUPPORTED */ #if CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN || opaque_key->tee_key_id -#endif +#endif /* CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN */ )) { psa_status_t status = esp_ecdsa_validate_efuse_block(opaque_key->curve, opaque_key->efuse_block); if (status != PSA_SUCCESS) { @@ -512,7 +519,7 @@ psa_status_t esp_ecdsa_opaque_sign_hash_start( return PSA_ERROR_INVALID_ARGUMENT; } - esp_ecdsa_opaque_key_t *opaque_key = (esp_ecdsa_opaque_key_t *) key_buffer; + const esp_ecdsa_opaque_key_t *opaque_key = (const esp_ecdsa_opaque_key_t *) key_buffer; psa_status_t status = validate_ecdsa_opaque_key_attributes(attributes, opaque_key); if (status != PSA_SUCCESS) { return status; @@ -579,7 +586,7 @@ psa_status_t esp_ecdsa_opaque_sign_hash_complete( } #if CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN - esp_ecdsa_opaque_key_t *opaque_key = operation->opaque_key; + const esp_ecdsa_opaque_key_t *opaque_key = operation->opaque_key; if (opaque_key->tee_key_id) { esp_tee_sec_storage_type_t tee_sec_storage_type = esp_ecdsa_curve_to_tee_sec_storage_type(opaque_key->curve); if (tee_sec_storage_type == (esp_tee_sec_storage_type_t) -1) { @@ -625,6 +632,17 @@ psa_status_t esp_ecdsa_opaque_sign_hash_complete( uint8_t zeroes[MAX_ECDSA_COMPONENT_LEN] = {0}; +#if SOC_KEY_MANAGER_SUPPORTED + esp_key_mgr_key_recovery_info_t *key_recovery_info = operation->opaque_key->key_recovery_info; + if (key_recovery_info) { + esp_err_t err = esp_key_mgr_activate_key(key_recovery_info); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to activate key: 0x%x", err); + return PSA_ERROR_INVALID_HANDLE; + } + } +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + // Acquire hardware esp_ecdsa_acquire_hardware(); @@ -648,10 +666,13 @@ psa_status_t esp_ecdsa_opaque_sign_hash_complete( } #endif /* CONFIG_MBEDTLS_ECDSA_DETERMINISTIC && !SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP */ +#if SOC_KEY_MANAGER_SUPPORTED // Set key source (consistent with esp_ecdsa_pk_conf_t) - if (operation->opaque_key->use_km_key) { + if (key_recovery_info) { conf.use_km_key = 1; - } else { + } else +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + { conf.efuse_key_blk = operation->opaque_key->efuse_block; } @@ -683,6 +704,12 @@ psa_status_t esp_ecdsa_opaque_sign_hash_complete( esp_ecdsa_release_hardware(); +#if SOC_KEY_MANAGER_SUPPORTED + if (key_recovery_info) { + esp_key_mgr_deactivate_key(key_recovery_info->key_type); + } +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + // Convert r from little-endian to big-endian and copy to output change_endianess(operation->r, signature, component_len); // Convert s from little-endian to big-endian and copy to output @@ -814,9 +841,18 @@ psa_status_t esp_ecdsa_opaque_export_public_key( .curve = opaque_key->curve, }; - if (opaque_key->use_km_key) { +#if SOC_KEY_MANAGER_SUPPORTED + esp_key_mgr_key_recovery_info_t *key_recovery_info = opaque_key->key_recovery_info; + if (key_recovery_info) { + esp_err_t err = esp_key_mgr_activate_key(key_recovery_info); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to activate key: 0x%x", err); + return PSA_ERROR_INVALID_HANDLE; + } conf.use_km_key = 1; - } else { + } else +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + { conf.efuse_key_blk = opaque_key->efuse_block; } @@ -834,6 +870,12 @@ psa_status_t esp_ecdsa_opaque_export_public_key( esp_ecdsa_release_hardware(); +#if SOC_KEY_MANAGER_SUPPORTED + if (key_recovery_info) { + esp_key_mgr_deactivate_key(key_recovery_info->key_type); + } +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + // Format: uncompressed point (ECDSA_UNCOMPRESSED_POINT_FORMAT byte followed by x and y coordinates) data[0] = ECDSA_UNCOMPRESSED_POINT_FORMAT; diff --git a/components/mbedtls/port/psa_driver/esp_mac/psa_crypto_driver_esp_hmac_opaque.c b/components/mbedtls/port/psa_driver/esp_mac/psa_crypto_driver_esp_hmac_opaque.c index 3a2de7e1122..0c54eb86891 100644 --- a/components/mbedtls/port/psa_driver/esp_mac/psa_crypto_driver_esp_hmac_opaque.c +++ b/components/mbedtls/port/psa_driver/esp_mac/psa_crypto_driver_esp_hmac_opaque.c @@ -13,10 +13,21 @@ #include "hal/hmac_types.h" #include "esp_hmac.h" +#if SOC_KEY_MANAGER_SUPPORTED +#include "esp_key_mgr.h" +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + static bool validate_hmac_opaque_key_attributes(const esp_hmac_opaque_key_t *opaque_key) { - // efuse_block is uint8_t, so it's always >= 0 (EFUSE_BLK0) - if (opaque_key->efuse_block < EFUSE_BLK_MAX && esp_efuse_get_key_purpose(opaque_key->efuse_block) == ESP_EFUSE_KEY_PURPOSE_HMAC_UP) { +#if SOC_KEY_MANAGER_SUPPORTED + if (opaque_key->key_recovery_info) { + return true; + } +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + + // efuse_key_id is uint8_t, so opaque_key->efuse_key_id + EFUSE_BLK_KEY0 >= EFUSE_BLK_KEY0 + if (((opaque_key->efuse_key_id + EFUSE_BLK_KEY0) < EFUSE_BLK_KEY_MAX) + && (esp_efuse_get_key_purpose(EFUSE_BLK_KEY0 + opaque_key->efuse_key_id) == ESP_EFUSE_KEY_PURPOSE_HMAC_UP)) { return true; } return false; @@ -97,29 +108,34 @@ psa_status_t esp_hmac_setup_opaque( return PSA_SUCCESS; } -static hmac_key_id_t translate_efuse_block_to_hmac_key_id(uint8_t efuse_block) -{ - return (hmac_key_id_t) (efuse_block - EFUSE_BLK_KEY0); -} - psa_status_t esp_hmac_update_opaque(esp_hmac_opaque_operation_t *esp_hmac_ctx, const uint8_t *data, size_t data_length) { if (!esp_hmac_ctx || !data || data_length == 0) { return PSA_ERROR_INVALID_ARGUMENT; } - hmac_key_id_t hmac_key_id = HMAC_KEY_MAX; + hmac_key_id_t hmac_key_id = esp_hmac_ctx->opaque_key->efuse_key_id; -#if SOC_KEY_MANAGER_HMAC_KEY_DEPLOY - if (esp_hmac_ctx->opaque_key->use_km_key) { +#if SOC_KEY_MANAGER_SUPPORTED && !ESP_TEE_BUILD + esp_key_mgr_key_recovery_info_t *key_recovery_info = esp_hmac_ctx->opaque_key->key_recovery_info; + if (key_recovery_info) { + esp_err_t err = esp_key_mgr_activate_key(key_recovery_info); + if (err != ESP_OK) { + ESP_LOGE("ESP_HMAC_OPAQUE", "Failed to activate key: 0x%x", err); + return PSA_ERROR_INVALID_HANDLE; + } hmac_key_id = HMAC_KEY_KM; - } else -#endif /* SOC_KEY_MANAGER_HMAC_KEY_DEPLOY */ - { - hmac_key_id = translate_efuse_block_to_hmac_key_id(esp_hmac_ctx->opaque_key->efuse_block); } +#endif /* SOC_KEY_MANAGER_SUPPORTED && !ESP_TEE_BUILD */ esp_err_t hmac_ret = esp_hmac_calculate(hmac_key_id, data, data_length, esp_hmac_ctx->hmac); + +#if SOC_KEY_MANAGER_SUPPORTED && !ESP_TEE_BUILD + if (key_recovery_info) { + esp_key_mgr_deactivate_key(key_recovery_info->key_type); + } +#endif /* SOC_KEY_MANAGER_SUPPORTED && !ESP_TEE_BUILD */ + if (hmac_ret == ESP_ERR_INVALID_ARG) { return PSA_ERROR_INVALID_ARGUMENT; } else if (hmac_ret == ESP_FAIL) { 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 6f1b24223e3..476cd5241c6 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 @@ -17,6 +17,10 @@ #include "esp_efuse.h" #include "soc/soc_caps.h" +#if SOC_KEY_MANAGER_SUPPORTED +#include "esp_key_mgr.h" +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + #define ESP_RSA_DS_TIMEOUT_BUFFER_MS 1000 static const char *TAG = "PSA_RSA_DS"; @@ -65,36 +69,48 @@ void esp_rsa_ds_release_ds_lock(void) } } -static int esp_rsa_ds_validate_opaque_key(const esp_ds_data_ctx_t *opaque_key) +static int esp_rsa_ds_validate_opaque_key(const esp_rsa_ds_opaque_key_t *opaque_key) { if (opaque_key == NULL) { return PSA_ERROR_INVALID_ARGUMENT; } - if (opaque_key->esp_ds_data == NULL) { + + if (opaque_key->ds_data_ctx == NULL) { return PSA_ERROR_INVALID_ARGUMENT; } - if (EFUSE_BLK_KEY0 + opaque_key->efuse_key_id >= EFUSE_BLK_KEY_MAX) { + if (opaque_key->ds_data_ctx->esp_ds_data == NULL) { return PSA_ERROR_INVALID_ARGUMENT; } - if (opaque_key->rsa_length_bits % 32 != 0) { + if (opaque_key->ds_data_ctx->rsa_length_bits % 32 != 0) { return PSA_ERROR_INVALID_ARGUMENT; } - if (opaque_key->rsa_length_bits < 1024 || opaque_key->rsa_length_bits > SOC_DS_SIGNATURE_MAX_BIT_LEN) { + if (opaque_key->ds_data_ctx->rsa_length_bits < 1024 || opaque_key->ds_data_ctx->rsa_length_bits > SOC_DS_SIGNATURE_MAX_BIT_LEN) { return PSA_ERROR_INVALID_ARGUMENT; } /* DS data rsa_length must match rsa_length_bits so we can use the key's data directly in sign operations */ - if (opaque_key->esp_ds_data->rsa_length != (opaque_key->rsa_length_bits / 32) - 1) { + if (opaque_key->ds_data_ctx->esp_ds_data->rsa_length != (opaque_key->ds_data_ctx->rsa_length_bits / 32) - 1) { return PSA_ERROR_INVALID_ARGUMENT; } - esp_efuse_purpose_t purpose = esp_efuse_get_key_purpose(EFUSE_BLK_KEY0 + opaque_key->efuse_key_id); - if (purpose != ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE) { - return PSA_ERROR_NOT_PERMITTED; +#if SOC_KEY_MANAGER_SUPPORTED + if (!opaque_key->key_recovery_info) { +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + if ((opaque_key->ds_data_ctx->efuse_key_id + EFUSE_BLK_KEY0) >= EFUSE_BLK_KEY_MAX) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + esp_efuse_purpose_t purpose = esp_efuse_get_key_purpose(EFUSE_BLK_KEY0 + opaque_key->ds_data_ctx->efuse_key_id); + if (purpose != ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE) { + return PSA_ERROR_NOT_PERMITTED; + } +#if SOC_KEY_MANAGER_SUPPORTED } +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + return PSA_SUCCESS; } @@ -107,11 +123,13 @@ psa_status_t esp_rsa_ds_opaque_sign_hash_start( const uint8_t *hash, size_t hash_length) { + esp_err_t err = ESP_FAIL; + if (!attributes || !key_buffer || !hash || !operation) { return PSA_ERROR_INVALID_ARGUMENT; } - if (key_buffer_size < sizeof(esp_ds_data_ctx_t)) { + if (key_buffer_size < sizeof(esp_rsa_ds_opaque_key_t)) { return PSA_ERROR_INVALID_ARGUMENT; } @@ -121,7 +139,7 @@ psa_status_t esp_rsa_ds_opaque_sign_hash_start( operation->alg = alg; - const esp_ds_data_ctx_t *opaque_key = (const esp_ds_data_ctx_t *)key_buffer; + 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) { @@ -141,7 +159,7 @@ psa_status_t esp_rsa_ds_opaque_sign_hash_start( psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH(operation->alg); - const size_t words_len = (opaque_key->rsa_length_bits / 32); + const size_t words_len = (opaque_key->ds_data_ctx->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,9 +188,25 @@ psa_status_t esp_rsa_ds_opaque_sign_hash_start( sig_words[i] = SWAP_INT32(em_words[words_len - (i + 1)]); } - esp_err_t err = esp_ds_start_sign((const void *)operation->sig_buffer, - opaque_key->esp_ds_data, - (hmac_key_id_t) opaque_key->efuse_key_id, + 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 (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; + } +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + + err = esp_ds_start_sign((const void *)operation->sig_buffer, + opaque_key->ds_data_ctx->esp_ds_data, + hmac_key_id, &operation->esp_rsa_ds_ctx); if (err != ESP_OK) { status = PSA_ERROR_GENERIC_ERROR; @@ -184,13 +218,7 @@ error: heap_caps_free(em); em = NULL; } - if (status != PSA_SUCCESS) { - if (operation->sig_buffer) { - heap_caps_free(operation->sig_buffer); - operation->sig_buffer = NULL; - } - esp_rsa_ds_release_ds_lock(); - } + return status; } @@ -199,6 +227,10 @@ psa_status_t esp_rsa_ds_opaque_sign_hash_complete( uint8_t *signature, size_t signature_size, size_t *signature_length) { + if (!operation) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (!signature || !signature_length || !operation) { return PSA_ERROR_INVALID_ARGUMENT; } @@ -207,16 +239,14 @@ 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->rsa_length_bits / 8; + int expected_signature_size = operation->esp_rsa_ds_opaque_key->ds_data_ctx->rsa_length_bits / 8; if (signature_size < expected_signature_size) { return PSA_ERROR_BUFFER_TOO_SMALL; } esp_err_t err = esp_ds_finish_sign((void *)operation->sig_buffer, operation->esp_rsa_ds_ctx); + operation->esp_rsa_ds_ctx = NULL; if (err != ESP_OK) { - memset(operation->sig_buffer, 0, operation->sig_buffer_size); - heap_caps_free(operation->sig_buffer); - esp_rsa_ds_release_ds_lock(); return PSA_ERROR_GENERIC_ERROR; } @@ -228,10 +258,15 @@ psa_status_t esp_rsa_ds_opaque_sign_hash_complete( } *signature_length = expected_signature_size; - memset(operation->sig_buffer, 0, operation->sig_buffer_size); - heap_caps_free(operation->sig_buffer); - operation->sig_buffer = NULL; + esp_rsa_ds_release_ds_lock(); + + if (operation->sig_buffer) { + memset(operation->sig_buffer, 0, operation->sig_buffer_size); + heap_caps_free(operation->sig_buffer); + operation->sig_buffer = NULL; + } + return PSA_SUCCESS; } @@ -242,6 +277,24 @@ 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; + } +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + operation->esp_rsa_ds_opaque_key = NULL; + } + + if (operation->esp_rsa_ds_ctx) { +#if !ESP_TEE_BUILD + free(operation->esp_rsa_ds_ctx); +#endif + operation->esp_rsa_ds_ctx = NULL; + } + // Free allocated memory if exists if (operation->sig_buffer) { memset(operation->sig_buffer, 0, operation->sig_buffer_size); @@ -305,26 +358,26 @@ psa_status_t esp_rsa_ds_opaque_import_key( size_t *key_buffer_length, size_t *bits) { - if (!attributes || !data || data_length < 1 || !key_buffer || !key_buffer_length || !bits) { + if (!attributes || !data || data_length < sizeof(esp_rsa_ds_opaque_key_t) || !key_buffer || !key_buffer_length || !bits) { return PSA_ERROR_INVALID_ARGUMENT; } - if (key_buffer_size < sizeof(esp_ds_data_ctx_t)) { + if (key_buffer_size < sizeof(esp_rsa_ds_opaque_key_t)) { return PSA_ERROR_BUFFER_TOO_SMALL; } - const esp_ds_data_ctx_t *opaque_key = (const esp_ds_data_ctx_t *)data; + 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_ds_data_ctx_t and the esp_ds_data_t it points to) must remain + * 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_ds_data_ctx_t)); - *key_buffer_length = sizeof(esp_ds_data_ctx_t); - *bits = opaque_key->rsa_length_bits; + memcpy(key_buffer, opaque_key, sizeof(esp_rsa_ds_opaque_key_t)); + *key_buffer_length = sizeof(esp_rsa_ds_opaque_key_t); + *bits = opaque_key->ds_data_ctx->rsa_length_bits; return PSA_SUCCESS; } @@ -335,7 +388,7 @@ size_t esp_rsa_ds_opaque_size_function( (void)key_type; (void)key_bits; - return sizeof(esp_ds_data_ctx_t); + return sizeof(esp_rsa_ds_opaque_key_t); } void esp_rsa_ds_opaque_set_session_timeout(int timeout_ms) @@ -360,7 +413,10 @@ psa_status_t esp_rsa_ds_opaque_asymmetric_decrypt( { (void)salt; (void)salt_length; - if (!attributes || !key || key_length < sizeof(esp_ds_data_ctx_t) || + + 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) { return PSA_ERROR_INVALID_ARGUMENT; } @@ -369,13 +425,13 @@ psa_status_t esp_rsa_ds_opaque_asymmetric_decrypt( return PSA_ERROR_NOT_SUPPORTED; } - const esp_ds_data_ctx_t *opaque_key = (const esp_ds_data_ctx_t *)key; + const esp_rsa_ds_opaque_key_t *opaque_key = (const esp_rsa_ds_opaque_key_t *)key; if (esp_rsa_ds_validate_opaque_key(opaque_key) != PSA_SUCCESS) { return PSA_ERROR_INVALID_ARGUMENT; } - size_t key_bits = opaque_key->rsa_length_bits; + size_t key_bits = opaque_key->ds_data_ctx->rsa_length_bits; if (input_length != (key_bits / 8)) { return PSA_ERROR_INVALID_ARGUMENT; } @@ -408,17 +464,47 @@ psa_status_t esp_rsa_ds_opaque_asymmetric_decrypt( operation.esp_rsa_ds_opaque_key = opaque_key; operation.sig_buffer = em_words; - esp_err_t err = esp_ds_start_sign((const void *)em_words, - opaque_key->esp_ds_data, - (hmac_key_id_t) opaque_key->efuse_key_id, + 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); + 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; + } +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + + err = esp_ds_start_sign((const void *)em_words, + opaque_key->ds_data_ctx->esp_ds_data, + hmac_key_id, &operation.esp_rsa_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; + } +#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); + +#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; + } +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + if (err != ESP_OK) { heap_caps_free(em_words); esp_rsa_ds_release_ds_lock(); @@ -430,6 +516,7 @@ psa_status_t esp_rsa_ds_opaque_asymmetric_decrypt( // Remove padding uint32_t *out_tmp = heap_caps_malloc_prefer(sizeof(uint32_t) * data_len, 1, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL); if (out_tmp == NULL) { + memset(em_words, 0, sizeof(uint32_t) * data_len); heap_caps_free(em_words); return PSA_ERROR_INSUFFICIENT_MEMORY; } diff --git a/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_ecdsa_contexts.h b/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_ecdsa_contexts.h index 2a4d28b5ddb..78fe73a6204 100644 --- a/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_ecdsa_contexts.h +++ b/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_ecdsa_contexts.h @@ -11,6 +11,10 @@ #include "psa/crypto_driver_common.h" #include "sdkconfig.h" +#if SOC_KEY_MANAGER_SUPPORTED +#include "esp_key_mgr.h" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -46,8 +50,10 @@ typedef struct { #if CONFIG_MBEDTLS_TEE_SEC_STG_ECDSA_SIGN const char *tee_key_id; /**< TEE secure storage key id */ #endif - bool use_km_key; /**< Use key deployed in the key manager */ - uint8_t efuse_block; /**< eFuse block id for ECDSA private key */ +#if SOC_KEY_MANAGER_SUPPORTED + esp_key_mgr_key_recovery_info_t *key_recovery_info; /**< Pointer to the key recovery info for ECDSA key */ +#endif + uint8_t efuse_block; /**< eFuse block id for ECDSA private key e.g. EFUSE_BLK_KEY0, EFUSE_BLK_KEY1 */ } esp_ecdsa_opaque_key_t; #if !(__DOXYGEN__) // No need to document these structures, these are internal to the driver @@ -66,7 +72,7 @@ typedef struct { /* The buffers are stored in the little-endian format */ typedef struct { psa_algorithm_t alg; - esp_ecdsa_opaque_key_t *opaque_key; + const esp_ecdsa_opaque_key_t *opaque_key; uint8_t r[MAX_ECDSA_COMPONENT_LEN]; uint8_t s[MAX_ECDSA_COMPONENT_LEN]; uint8_t sha[MAX_ECDSA_SHA_LEN]; diff --git a/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_hmac_opaque_contexts.h b/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_hmac_opaque_contexts.h index 19ce8d705a9..1bad31ff37c 100644 --- a/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_hmac_opaque_contexts.h +++ b/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_hmac_opaque_contexts.h @@ -9,6 +9,11 @@ #include "esp_types.h" #include "soc/soc_caps.h" #include "psa/crypto_driver_common.h" +#include "hal/hmac_types.h" + +#if SOC_KEY_MANAGER_SUPPORTED +#include "esp_key_mgr.h" +#endif #ifdef __cplusplus extern "C" { @@ -23,8 +28,10 @@ extern "C" { * @brief Structure to store opaque HMAC key. */ typedef struct { - bool use_km_key; /**< Use key deployed in the key manager */ - uint8_t efuse_block; /**< eFuse block id for HMAC key */ + uint8_t efuse_key_id; /**< eFuse key block id for HMAC key */ +#if SOC_KEY_MANAGER_SUPPORTED + esp_key_mgr_key_recovery_info_t *key_recovery_info; /**< Pointer to the key recovery info for HMAC key */ +#endif /* SOC_KEY_MANAGER_SUPPORTED */ } esp_hmac_opaque_key_t; /** 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 862282dc42c..c5a88205b43 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,8 +22,19 @@ 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 */ #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 + */ +#define PSA_KEY_LIFETIME_ESP_RSA_DS_VOLATILE \ PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( \ PSA_KEY_PERSISTENCE_VOLATILE, \ PSA_KEY_LOCATION_ESP_RSA_DS) @@ -110,7 +121,7 @@ psa_status_t esp_rsa_ds_opaque_signature_sign_hash( /** * @brief Import the RSA DS opaque key - * The data should be of type esp_ds_data_ctx_t and should be + * The data should be of type esp_rsa_ds_opaque_key_t and should be * already initialised with DS data and efuse key id. * * @param attributes Key attributes 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 70cec0e0555..f471f925941 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 @@ -10,6 +10,12 @@ #if defined(ESP_RSA_DS_DRIVER_ENABLED) #include "psa/crypto_driver_common.h" #include "esp_ds.h" +#include "hal/hmac_types.h" + +#include "soc/soc_caps.h" +#if SOC_KEY_MANAGER_SUPPORTED +#include "esp_key_mgr.h" +#endif #ifdef __cplusplus extern "C" { @@ -29,20 +35,30 @@ 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, the key material + * 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. */ typedef struct { esp_ds_data_t *esp_ds_data; /**< Pointer to the esp ds data */ - uint8_t efuse_key_id; /**< efuse block id in which DS_KEY is stored e.g. 0,1*/ + hmac_key_id_t efuse_key_id; /**< efuse block id in which the HMAC key for the DS peripheral is stored e.g. 0,1*/ uint16_t rsa_length_bits; /**< length of RSA private key in bits e.g. 2048 */ } esp_ds_data_ctx_t; +typedef struct { + esp_ds_data_ctx_t *ds_data_ctx; +#if SOC_KEY_MANAGER_SUPPORTED + esp_key_mgr_key_recovery_info_t *key_recovery_info; /**< Pointer to the key recovery info for DS key */ +#endif /* SOC_KEY_MANAGER_SUPPORTED */ +} esp_rsa_ds_opaque_key_t; + #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_ds_data_ctx_t *esp_rsa_ds_opaque_key; /**< Pointer to the esp ds opaque key */ + const esp_rsa_ds_opaque_key_t *esp_rsa_ds_opaque_key; /**< Pointer to the esp ds opaque key */ +#if SOC_KEY_MANAGER_SUPPORTED + bool is_km_key_active; /**< Flag indicating if the Key Manager key is active for this operation */ +#endif /* SOC_KEY_MANAGER_SUPPORTED */ psa_algorithm_t alg; /**< Algorithm used in the sign operation */ uint32_t *sig_buffer; /**< Buffer to hold the signature */ size_t sig_buffer_size; /**< Size of the signature buffer */ diff --git a/components/mbedtls/test_apps/main/test_ds_sign_and_decrypt.c b/components/mbedtls/test_apps/main/test_ds_sign_and_decrypt.c index d9eff1bb603..3d550cdd201 100644 --- a/components/mbedtls/test_apps/main/test_ds_sign_and_decrypt.c +++ b/components/mbedtls/test_apps/main/test_ds_sign_and_decrypt.c @@ -57,43 +57,44 @@ TEST_CASE("ds sign test pkcs1_v15 PSA validation", "[ds_rsa_psa]") psa_status_t status; psa_algorithm_t alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256); - esp_ds_data_ctx_t *ds_key = esp_secure_cert_get_ds_ctx(); - TEST_ASSERT_NOT_NULL(ds_key); + esp_rsa_ds_opaque_key_t rsa_ds_opaque_key = {0}; + rsa_ds_opaque_key.ds_data_ctx = esp_secure_cert_get_ds_ctx(); + TEST_ASSERT_NOT_NULL(rsa_ds_opaque_key.ds_data_ctx); - ds_key->efuse_key_id = EFUSE_BLK_MAX; // Invalid efuse key id to trigger validation failure + rsa_ds_opaque_key.ds_data_ctx->efuse_key_id = EFUSE_BLK_KEY_MAX; // Invalid efuse block to trigger validation failure psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR); - psa_set_key_bits(&attributes, ds_key->rsa_length_bits); + psa_set_key_bits(&attributes, rsa_ds_opaque_key.ds_data_ctx->rsa_length_bits); psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH); psa_set_key_algorithm(&attributes, alg); - psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS_VOLATILE); status = psa_import_key(&attributes, - (const uint8_t *)ds_key, - sizeof(*ds_key), + (const uint8_t *)&rsa_ds_opaque_key, + sizeof(rsa_ds_opaque_key), &keyt_id); TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status); - ds_key->efuse_key_id = EFUSE_BLK0 + 0; // Reset to valid efuse key id - ds_key->rsa_length_bits = 1000; // Invalid RSA length to trigger validation failure + rsa_ds_opaque_key.ds_data_ctx->efuse_key_id = EFUSE_BLK_KEY0; // Reset to valid efuse block + rsa_ds_opaque_key.ds_data_ctx->rsa_length_bits = 1000; // Invalid RSA length to trigger validation failure status = psa_import_key(&attributes, - (const uint8_t *)ds_key, - sizeof(*ds_key), + (const uint8_t *)&rsa_ds_opaque_key, + sizeof(rsa_ds_opaque_key), &keyt_id); TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status); - ds_key->rsa_length_bits = 2048; // Reset to valid RSA length - esp_ds_data_t *ds_data_backup = ds_key->esp_ds_data; - ds_key->esp_ds_data = NULL; // NULL esp_ds_data to trigger validation failure + rsa_ds_opaque_key.ds_data_ctx->rsa_length_bits = 2048; // Reset to valid RSA length + esp_ds_data_t *ds_data_backup = rsa_ds_opaque_key.ds_data_ctx->esp_ds_data; + rsa_ds_opaque_key.ds_data_ctx->esp_ds_data = NULL; // NULL esp_ds_data to trigger validation failure status = psa_import_key(&attributes, - (const uint8_t *)ds_key, - sizeof(*ds_key), + (const uint8_t *)&rsa_ds_opaque_key, + sizeof(rsa_ds_opaque_key), &keyt_id); TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status); - ds_key->esp_ds_data = ds_data_backup; // Restore esp_ds_data + rsa_ds_opaque_key.ds_data_ctx->esp_ds_data = ds_data_backup; // Restore esp_ds_data - esp_secure_cert_free_ds_ctx(ds_key); + esp_secure_cert_free_ds_ctx(rsa_ds_opaque_key.ds_data_ctx); } TEST_CASE("ds sign test pkcs1_v15 PSA", "[ds_rsa_psa]") @@ -102,18 +103,19 @@ TEST_CASE("ds sign test pkcs1_v15 PSA", "[ds_rsa_psa]") psa_status_t status; psa_algorithm_t alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256); - esp_ds_data_ctx_t *ds_key = esp_secure_cert_get_ds_ctx(); - TEST_ASSERT_NOT_NULL(ds_key); + esp_rsa_ds_opaque_key_t rsa_ds_opaque_key = {0}; + rsa_ds_opaque_key.ds_data_ctx = esp_secure_cert_get_ds_ctx(); + TEST_ASSERT_NOT_NULL(rsa_ds_opaque_key.ds_data_ctx); psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR); - psa_set_key_bits(&attributes, ds_key->rsa_length_bits); + psa_set_key_bits(&attributes, rsa_ds_opaque_key.ds_data_ctx->rsa_length_bits); psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH); psa_set_key_algorithm(&attributes, alg); - psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS_VOLATILE); status = psa_import_key(&attributes, - (const uint8_t *)ds_key, - sizeof(*ds_key), + (const uint8_t *)&rsa_ds_opaque_key, + sizeof(rsa_ds_opaque_key), &keyt_id); TEST_ASSERT_EQUAL(PSA_SUCCESS, status); @@ -136,7 +138,7 @@ TEST_CASE("ds sign test pkcs1_v15 PSA", "[ds_rsa_psa]") psa_reset_key_attributes(&attributes); // Free the DS context to prevent memory leak - esp_secure_cert_free_ds_ctx(ds_key); + esp_secure_cert_free_ds_ctx(rsa_ds_opaque_key.ds_data_ctx); // Because we have wrapped around the ds_start_sign and ds_finish_sign functions, // we are not actually performing the real signing operation. That test is done in the @@ -169,18 +171,19 @@ TEST_CASE("ds sign test pkcs1_v21 PSA", "[ds_rsa_psa]") psa_key_id_t keyt_id; psa_status_t status; psa_algorithm_t alg = PSA_ALG_RSA_PSS(PSA_ALG_SHA_256); - esp_ds_data_ctx_t *ds_key = esp_secure_cert_get_ds_ctx(); - TEST_ASSERT_NOT_NULL(ds_key); + esp_rsa_ds_opaque_key_t rsa_ds_opaque_key = {0}; + rsa_ds_opaque_key.ds_data_ctx = esp_secure_cert_get_ds_ctx(); + TEST_ASSERT_NOT_NULL(rsa_ds_opaque_key.ds_data_ctx); psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR); - psa_set_key_bits(&attributes, ds_key->rsa_length_bits); + psa_set_key_bits(&attributes, rsa_ds_opaque_key.ds_data_ctx->rsa_length_bits); psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH); psa_set_key_algorithm(&attributes, alg); - psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS_VOLATILE); status = psa_import_key(&attributes, - (const uint8_t *)ds_key, - sizeof(*ds_key), + (const uint8_t *)&rsa_ds_opaque_key, + sizeof(rsa_ds_opaque_key), &keyt_id); TEST_ASSERT_EQUAL(PSA_SUCCESS, status); @@ -203,7 +206,7 @@ TEST_CASE("ds sign test pkcs1_v21 PSA", "[ds_rsa_psa]") psa_reset_key_attributes(&attributes); // Free the DS context to prevent memory leak - esp_secure_cert_free_ds_ctx(ds_key); + esp_secure_cert_free_ds_ctx(rsa_ds_opaque_key.ds_data_ctx); } /* Generated external data for OAEP padding */ @@ -232,20 +235,21 @@ TEST_CASE("ds decrypt test pkcs1_v21 PSA", "[ds_rsa]") psa_status_t status; psa_algorithm_t alg = PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256); - esp_ds_data_ctx_t *ds_key = esp_secure_cert_get_ds_ctx(); - TEST_ASSERT_NOT_NULL(ds_key); + esp_rsa_ds_opaque_key_t rsa_ds_opaque_key = {0}; + rsa_ds_opaque_key.ds_data_ctx = esp_secure_cert_get_ds_ctx(); + TEST_ASSERT_NOT_NULL(rsa_ds_opaque_key.ds_data_ctx); - printf("DS Key RSA Length Bits: %d\n", ds_key->rsa_length_bits); + printf("DS Key RSA Length Bits: %d\n", rsa_ds_opaque_key.ds_data_ctx->rsa_length_bits); psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR); - psa_set_key_bits(&attributes, ds_key->rsa_length_bits); + psa_set_key_bits(&attributes, rsa_ds_opaque_key.ds_data_ctx->rsa_length_bits); psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT); psa_set_key_algorithm(&attributes, alg); - psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS_VOLATILE); status = psa_import_key(&attributes, - (const uint8_t *)ds_key, - sizeof(*ds_key), + (const uint8_t *)&rsa_ds_opaque_key, + sizeof(rsa_ds_opaque_key), &keyt_id); TEST_ASSERT_EQUAL(PSA_SUCCESS, status); @@ -265,7 +269,7 @@ TEST_CASE("ds decrypt test pkcs1_v21 PSA", "[ds_rsa]") psa_reset_key_attributes(&attributes); // Free the DS context to prevent memory leak - esp_secure_cert_free_ds_ctx(ds_key); + esp_secure_cert_free_ds_ctx(rsa_ds_opaque_key.ds_data_ctx); } #endif /* CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 */ @@ -294,20 +298,21 @@ TEST_CASE("ds decrypt test pkcs1_v15 PSA", "[ds_rsa]") psa_status_t status; psa_algorithm_t alg = PSA_ALG_RSA_PKCS1V15_CRYPT; - esp_ds_data_ctx_t *ds_key = esp_secure_cert_get_ds_ctx(); - TEST_ASSERT_NOT_NULL(ds_key); + esp_rsa_ds_opaque_key_t rsa_ds_opaque_key = {0}; + rsa_ds_opaque_key.ds_data_ctx = esp_secure_cert_get_ds_ctx(); + TEST_ASSERT_NOT_NULL(rsa_ds_opaque_key.ds_data_ctx); - printf("DS Key RSA Length Bits: %d\n", ds_key->rsa_length_bits); + printf("DS Key RSA Length Bits: %d\n", rsa_ds_opaque_key.ds_data_ctx->rsa_length_bits); psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR); - psa_set_key_bits(&attributes, ds_key->rsa_length_bits); + psa_set_key_bits(&attributes, rsa_ds_opaque_key.ds_data_ctx->rsa_length_bits); psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT); psa_set_key_algorithm(&attributes, alg); - psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS_VOLATILE); status = psa_import_key(&attributes, - (const uint8_t *)ds_key, - sizeof(*ds_key), + (const uint8_t *)&rsa_ds_opaque_key, + sizeof(rsa_ds_opaque_key), &keyt_id); TEST_ASSERT_EQUAL(PSA_SUCCESS, status); @@ -327,7 +332,7 @@ TEST_CASE("ds decrypt test pkcs1_v15 PSA", "[ds_rsa]") psa_reset_key_attributes(&attributes); // Free the DS context to prevent memory leak - esp_secure_cert_free_ds_ctx(ds_key); + esp_secure_cert_free_ds_ctx(rsa_ds_opaque_key.ds_data_ctx); } int __wrap_esp_ds_start_sign(const void *message, const esp_ds_data_t *data, hmac_key_id_t key_id, esp_ds_context_t **esp_ds_ctx) diff --git a/components/mbedtls/test_apps/main/test_psa_ecdsa.c b/components/mbedtls/test_apps/main/test_psa_ecdsa.c index c9c1d25f785..814993077da 100644 --- a/components/mbedtls/test_apps/main/test_psa_ecdsa.c +++ b/components/mbedtls/test_apps/main/test_psa_ecdsa.c @@ -300,7 +300,7 @@ const uint8_t k1_ecdsa192_encrypt[] = { 0xde, 0xe9, 0x9c, 0x89, 0xf2, 0x3b, 0x29, 0xb7, 0x9e, 0x33, 0xec, 0x76, 0x75, 0x2f, 0x3e, 0xab, 0x61, 0x06, 0x4d, 0xea, 0x05, 0x2c, 0xc3, 0x29, 0x1c, 0x7f, 0xb7, 0x3d, 0xb8, 0x1c, 0xb2, 0x17, }; -void test_ecdsa_sign(esp_ecdsa_curve_t curve, const uint8_t *hash, const uint8_t *pub_x, const uint8_t *pub_y, bool is_deterministic, int efuse_key_block) +void test_ecdsa_sign(esp_ecdsa_curve_t curve, const uint8_t *hash, const uint8_t *pub_x, const uint8_t *pub_y, bool is_deterministic, int efuse_key_block, void *key_recovery_info) { size_t hash_len = HASH_LEN; uint8_t signature[2 * MAX_ECDSA_COMPONENT_LEN]; @@ -330,13 +330,15 @@ void test_ecdsa_sign(esp_ecdsa_curve_t curve, const uint8_t *hash, const uint8_t psa_key_id_t priv_key_id = 0; psa_key_attributes_t priv_attr = PSA_KEY_ATTRIBUTES_INIT; - esp_ecdsa_opaque_key_t opaque_key = { - .curve = curve, - }; + esp_ecdsa_opaque_key_t opaque_key = { 0 }; + opaque_key.curve = curve; - if (efuse_key_block == USE_ECDSA_KEY_FROM_KEY_MANAGER) { - opaque_key.use_km_key = true; - } else { +#if SOC_KEY_MANAGER_SUPPORTED + if (key_recovery_info) { + opaque_key.key_recovery_info = (esp_key_mgr_key_recovery_info_t *) key_recovery_info; + } else +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + { opaque_key.efuse_block = efuse_key_block; } @@ -372,21 +374,21 @@ TEST_CASE("mbedtls ECDSA signature generation on SECP256R1", "[mbedtls][efuse_ke if (!ecdsa_ll_is_supported()) { TEST_IGNORE_MESSAGE("ECDSA is not supported"); } - test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, false, SECP256R1_EFUSE_BLOCK); + test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, false, SECP256R1_EFUSE_BLOCK, NULL); } #ifdef SOC_ECDSA_SUPPORT_CURVE_P384 TEST_CASE("mbedtls ECDSA signature generation on SECP384R1", "[mbedtls][efuse_key]") { uint8_t efuse_key_block = HAL_ECDSA_COMBINE_KEY_BLOCKS(SECP384R1_EFUSE_BLOCK_HIGH, SECP384R1_EFUSE_BLOCK_LOW); - test_ecdsa_sign(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, false, efuse_key_block); + test_ecdsa_sign(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, false, efuse_key_block, NULL); } #endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */ #if SOC_KEY_MANAGER_SUPPORTED -static void deploy_key_in_key_manager(const uint8_t *k1_encrypted, esp_key_mgr_key_type_t key_type, esp_key_mgr_key_len_t key_len) { +static void deploy_key_in_key_manager(const uint8_t *k1_encrypted, esp_key_mgr_key_type_t key_type, esp_key_mgr_key_len_t key_len, esp_key_mgr_key_recovery_info_t *key_recovery_info) { esp_key_mgr_aes_key_config_t *key_config = NULL; key_config = heap_caps_calloc(1, sizeof(esp_key_mgr_aes_key_config_t), MALLOC_CAP_INTERNAL); TEST_ASSERT_NOT_NULL(key_config); @@ -398,16 +400,10 @@ static void deploy_key_in_key_manager(const uint8_t *k1_encrypted, esp_key_mgr_k memcpy(key_config->k1_encrypted[0], (uint8_t*) k1_encrypted, KEY_MGR_K1_ENCRYPTED_SIZE); memcpy(key_config->sw_init_key, (uint8_t*) init_key, KEY_MGR_SW_INIT_KEY_SIZE); - esp_key_mgr_key_recovery_info_t *key_info = NULL; - key_info = heap_caps_calloc(1, sizeof(esp_key_mgr_key_recovery_info_t), MALLOC_CAP_INTERNAL); - TEST_ASSERT_NOT_NULL(key_info); - - esp_key_mgr_deploy_key_in_aes_mode(key_config, key_info); + TEST_ASSERT_EQUAL(ESP_OK, esp_key_mgr_deploy_key_in_aes_mode(key_config, key_recovery_info)); ESP_LOGI(TAG, "Key deployed successfully"); - esp_key_mgr_activate_key(key_info); - free(key_info); free(key_config); } @@ -417,9 +413,13 @@ TEST_CASE("mbedtls ECDSA signature generation on SECP256R1", "[mbedtls][key_mana TEST_IGNORE_MESSAGE("Key manager is not supported"); } - deploy_key_in_key_manager(k1_ecdsa256_encrypt, ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_ECDSA_LEN_256); - test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, false, USE_ECDSA_KEY_FROM_KEY_MANAGER); - esp_key_mgr_deactivate_key(ESP_KEY_MGR_ECDSA_KEY); + esp_key_mgr_key_recovery_info_t *key_recovery_info; + key_recovery_info = heap_caps_calloc(1, sizeof(esp_key_mgr_key_recovery_info_t), MALLOC_CAP_INTERNAL); + TEST_ASSERT_NOT_NULL(key_recovery_info); + + deploy_key_in_key_manager(k1_ecdsa256_encrypt, ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_ECDSA_LEN_256, key_recovery_info); + test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, false, USE_ECDSA_KEY_FROM_KEY_MANAGER, (void *) key_recovery_info); + free(key_recovery_info); } #endif /* SOC_KEY_MANAGER_SUPPORTED */ @@ -430,7 +430,7 @@ TEST_CASE("mbedtls ECDSA deterministic signature generation on SECP256R1", "[mbe if (!ecdsa_ll_is_deterministic_mode_supported()) { ESP_LOGI(TAG, "Skipping test because ECDSA deterministic mode is not supported."); } else { - test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, true, SECP256R1_EFUSE_BLOCK); + test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, true, SECP256R1_EFUSE_BLOCK, NULL); } } @@ -438,7 +438,7 @@ TEST_CASE("mbedtls ECDSA deterministic signature generation on SECP256R1", "[mbe TEST_CASE("mbedtls ECDSA deterministic signature generation on SECP384R1", "[mbedtls][efuse_key]") { uint8_t efuse_key_block = HAL_ECDSA_COMBINE_KEY_BLOCKS(SECP384R1_EFUSE_BLOCK_HIGH, SECP384R1_EFUSE_BLOCK_LOW); - test_ecdsa_sign(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, true, efuse_key_block); + test_ecdsa_sign(ESP_ECDSA_CURVE_SECP384R1, sha, ecdsa384_pub_x, ecdsa384_pub_y, true, efuse_key_block, NULL); } #endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */ @@ -449,16 +449,20 @@ TEST_CASE("mbedtls ECDSA deterministic signature generation on SECP256R1", "[mbe if (!ecdsa_ll_is_deterministic_mode_supported()) { ESP_LOGI(TAG, "Skipping test because ECDSA deterministic mode is not supported."); } else { - deploy_key_in_key_manager(k1_ecdsa256_encrypt, ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_ECDSA_LEN_256); - test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, true, USE_ECDSA_KEY_FROM_KEY_MANAGER); - esp_key_mgr_deactivate_key(ESP_KEY_MGR_ECDSA_KEY); + esp_key_mgr_key_recovery_info_t *key_recovery_info; + key_recovery_info = heap_caps_calloc(1, sizeof(esp_key_mgr_key_recovery_info_t), MALLOC_CAP_INTERNAL); + TEST_ASSERT_NOT_NULL(key_recovery_info); + + deploy_key_in_key_manager(k1_ecdsa256_encrypt, ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_ECDSA_LEN_256, key_recovery_info); + test_ecdsa_sign(ESP_ECDSA_CURVE_SECP256R1, sha, ecdsa256_pub_x, ecdsa256_pub_y, true, USE_ECDSA_KEY_FROM_KEY_MANAGER, (void *) key_recovery_info); + free(key_recovery_info); } } #endif /* SOC_KEY_MANAGER_SUPPORTED */ #endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE */ #ifdef SOC_ECDSA_SUPPORT_EXPORT_PUBKEY -void test_ecdsa_export_pubkey(esp_ecdsa_curve_t curve, const uint8_t *pub_x, const uint8_t *pub_y, int efuse_key_block) +void test_ecdsa_export_pubkey(esp_ecdsa_curve_t curve, const uint8_t *pub_x, const uint8_t *pub_y, int efuse_key_block, void *key_recovery_info) { uint8_t export_pub_key[1 + 2 * MAX_ECDSA_COMPONENT_LEN] = {0}; size_t len = 0; @@ -466,9 +470,8 @@ void test_ecdsa_export_pubkey(esp_ecdsa_curve_t curve, const uint8_t *pub_x, con psa_key_id_t priv_key_id = 0; psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT; - esp_ecdsa_opaque_key_t opaque_key = { - .curve = curve, - }; + esp_ecdsa_opaque_key_t opaque_key = { 0 }; + opaque_key.curve = curve; size_t plen = 0; psa_algorithm_t sha_alg = 0; @@ -490,9 +493,12 @@ void test_ecdsa_export_pubkey(esp_ecdsa_curve_t curve, const uint8_t *pub_x, con } size_t plen_bytes = plen / 8; - if (efuse_key_block == USE_ECDSA_KEY_FROM_KEY_MANAGER) { - opaque_key.use_km_key = true; - } else { +#if SOC_KEY_MANAGER_SUPPORTED + if (key_recovery_info) { + opaque_key.key_recovery_info = (esp_key_mgr_key_recovery_info_t *) key_recovery_info; + } else +#endif + { opaque_key.efuse_block = efuse_key_block; } // Set attributes for opaque private key @@ -525,14 +531,14 @@ TEST_CASE("mbedtls ECDSA export public key on SECP256R1", "[mbedtls][efuse_key]" if (!ecdsa_ll_is_supported()) { TEST_IGNORE_MESSAGE("ECDSA is not supported"); } - test_ecdsa_export_pubkey(ESP_ECDSA_CURVE_SECP256R1, ecdsa256_pub_x, ecdsa256_pub_y, SECP256R1_EFUSE_BLOCK); + test_ecdsa_export_pubkey(ESP_ECDSA_CURVE_SECP256R1, ecdsa256_pub_x, ecdsa256_pub_y, SECP256R1_EFUSE_BLOCK, NULL); } #ifdef SOC_ECDSA_SUPPORT_CURVE_P384 TEST_CASE("mbedtls ECDSA export public key on SECP384R1", "[mbedtls][efuse_key]") { uint8_t efuse_key_block = HAL_ECDSA_COMBINE_KEY_BLOCKS(SECP384R1_EFUSE_BLOCK_HIGH, SECP384R1_EFUSE_BLOCK_LOW); - test_ecdsa_export_pubkey(ESP_ECDSA_CURVE_SECP384R1, ecdsa384_pub_x, ecdsa384_pub_y, efuse_key_block); + test_ecdsa_export_pubkey(ESP_ECDSA_CURVE_SECP384R1, ecdsa384_pub_x, ecdsa384_pub_y, efuse_key_block, NULL); } #endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */ @@ -544,9 +550,13 @@ TEST_CASE("mbedtls ECDSA export public key on SECP256R1", "[mbedtls][key_manager TEST_IGNORE_MESSAGE("Key manager is not supported"); } - deploy_key_in_key_manager(k1_ecdsa256_encrypt, ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_ECDSA_LEN_256); - test_ecdsa_export_pubkey(ESP_ECDSA_CURVE_SECP256R1, ecdsa256_pub_x, ecdsa256_pub_y, USE_ECDSA_KEY_FROM_KEY_MANAGER); - esp_key_mgr_deactivate_key(ESP_KEY_MGR_ECDSA_KEY); + esp_key_mgr_key_recovery_info_t *key_recovery_info; + key_recovery_info = heap_caps_calloc(1, sizeof(esp_key_mgr_key_recovery_info_t), MALLOC_CAP_INTERNAL); + TEST_ASSERT_NOT_NULL(key_recovery_info); + + deploy_key_in_key_manager(k1_ecdsa256_encrypt, ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_ECDSA_LEN_256, key_recovery_info); + test_ecdsa_export_pubkey(ESP_ECDSA_CURVE_SECP256R1, ecdsa256_pub_x, ecdsa256_pub_y, USE_ECDSA_KEY_FROM_KEY_MANAGER, (void *) key_recovery_info); + free(key_recovery_info); } #endif diff --git a/docs/conf_common.py b/docs/conf_common.py index fc03ca0a1a2..2f277112944 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -368,6 +368,7 @@ conditional_include_dict = { 'SOC_ECDSA_SUPPORTED': ['api-reference/peripherals/ecdsa.rst'], 'SOC_HMAC_SUPPORTED': ['api-reference/peripherals/hmac.rst'], 'SOC_ASYNC_MEMCPY_SUPPORTED': ['api-reference/system/async_memcpy.rst'], + 'SOC_KEY_MANAGER_SUPPORTED': ['api-reference/peripherals/key_manager.rst'], 'CONFIG_IDF_TARGET_ARCH_XTENSA': XTENSA_DOCS, 'CONFIG_IDF_TARGET_ARCH_RISCV': RISCV_DOCS, 'SOC_TEMP_SENSOR_SUPPORTED': TEMP_SENSOR_DOCS, diff --git a/docs/docs_not_updated/esp32h4.txt b/docs/docs_not_updated/esp32h4.txt index 0478270ca81..69384789600 100644 --- a/docs/docs_not_updated/esp32h4.txt +++ b/docs/docs_not_updated/esp32h4.txt @@ -128,6 +128,7 @@ api-reference/peripherals/sdspi_share.rst api-reference/peripherals/ana_cmpr.rst api-reference/peripherals/adc_continuous.rst api-reference/peripherals/hmac.rst +api-reference/peripherals/key_manager.rst api-reference/peripherals/sdspi_host.rst api-reference/peripherals/vad.rst api-reference/peripherals/i2s.rst diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index d5b4ecb2686..6eb474d7c65 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -374,6 +374,8 @@ PREDEFINED = \ configTASKLIST_INCLUDE_COREID=1 \ configUSE_SB_COMPLETED_CALLBACK=1 \ PRIVILEGED_FUNCTION= \ + PACKED_ATTR= \ + WORD_ALIGNED_ATTR= \ "ESP_EVENT_DECLARE_BASE(x)=extern esp_event_base_t x" ## Do not complain about not having dot diff --git a/docs/doxygen/Doxyfile_esp32c5 b/docs/doxygen/Doxyfile_esp32c5 index d9a797a88d2..6c1f49e6776 100644 --- a/docs/doxygen/Doxyfile_esp32c5 +++ b/docs/doxygen/Doxyfile_esp32c5 @@ -22,4 +22,6 @@ INPUT += \ $(PROJECT_PATH)/components/esp_tee/include/esp_tee.h \ $(PROJECT_PATH)/components/esp_tee/subproject/components/tee_sec_storage/include/esp_tee_sec_storage.h \ $(PROJECT_PATH)/components/esp_tee/subproject/components/tee_ota_ops/include/esp_tee_ota_ops.h \ + $(PROJECT_PATH)/components/esp_security/include/esp_key_mgr.h \ + $(PROJECT_PATH)/components/esp_hal_security/include/hal/key_mgr_types.h \ $(PROJECT_PATH)/components/mbedtls/port/include/psa/initial_attestation.h \ diff --git a/docs/doxygen/Doxyfile_esp32p4 b/docs/doxygen/Doxyfile_esp32p4 index df7585741bc..71b2c33c1a3 100644 --- a/docs/doxygen/Doxyfile_esp32p4 +++ b/docs/doxygen/Doxyfile_esp32p4 @@ -53,4 +53,6 @@ INPUT += \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h \ $(PROJECT_PATH)/components/ulp/lp_core/shared/include/ulp_lp_core_lp_uart_shared.h \ $(PROJECT_PATH)/components/ulp/lp_core/shared/include/ulp_lp_core_lp_vad_shared.h \ - $(PROJECT_PATH)/components/ulp/ulp_common/include/ulp_common.h + $(PROJECT_PATH)/components/ulp/ulp_common/include/ulp_common.h \ + $(PROJECT_PATH)/components/esp_security/include/esp_key_mgr.h \ + $(PROJECT_PATH)/components/esp_hal_security/include/hal/key_mgr_types.h diff --git a/docs/en/api-reference/peripherals/ds.rst b/docs/en/api-reference/peripherals/ds.rst index bb4da2d3695..6cac5199176 100644 --- a/docs/en/api-reference/peripherals/ds.rst +++ b/docs/en/api-reference/peripherals/ds.rst @@ -3,7 +3,13 @@ Digital Signature (DS) :link_to_translation:`zh_CN:[中文]` -The Digital Signature (DS) module provides hardware acceleration of signing messages based on RSA. It uses pre-encrypted parameters to calculate a signature. The parameters are encrypted using HMAC as a key-derivation function. In turn, the HMAC uses eFuses as the input key. The whole process happens in hardware so that neither the decryption key for the RSA parameters nor the input key for the HMAC key derivation function can be seen by the software while calculating the signature. +The Digital Signature (DS) module provides hardware acceleration of signing messages based on RSA. It uses pre-encrypted parameters to calculate a signature. The parameters are encrypted using HMAC as a key-derivation function. In turn, the HMAC uses eFuses as the input key. + +.. only:: SOC_KEY_MANAGER_SUPPORTED + + On {IDF_TARGET_NAME}, the Digital Signature (DS) module can also use a key stored in the Key Manager instead of an eFuse key block. The AES encryption key can be directly deployed in the Key Manager with the type :cpp:enumerator:`ESP_KEY_MGR_DS_KEY`. Refer to :ref:`key-manager` for more details. + +The whole process happens in hardware so that neither the decryption key for the RSA parameters nor the input key for the HMAC key derivation function can be seen by the software while calculating the signature. For more detailed information on the hardware involved in the signature calculation and the registers used, see **{IDF_TARGET_NAME} Technical Reference Manual** > **Digital Signature (DS)** [`PDF <{IDF_TARGET_TRM_EN_URL}#digsig>`__]. @@ -112,7 +118,11 @@ Example for SSL Mutual Authentication Using 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. +.. only:: SOC_KEY_MANAGER_SUPPORTED + + In case both the :cpp:member:`esp_ds_data_ctx_t::efuse_key_id` and :cpp:member:`esp_rsa_ds_opaque_key_t::key_recovery_info` are set, the ESP-DS PSA driver prefers using the Key Manager-based DS key over the eFuse-based DS key. + API Reference ------------- -.. include-build-file:: inc/esp_ds.inc +.. include-build-file:: inc/psa_crypto_driver_esp_rsa_ds_contexts.inc diff --git a/docs/en/api-reference/peripherals/ecdsa.rst b/docs/en/api-reference/peripherals/ecdsa.rst index 6a2e5a16026..13c7940cf28 100644 --- a/docs/en/api-reference/peripherals/ecdsa.rst +++ b/docs/en/api-reference/peripherals/ecdsa.rst @@ -24,7 +24,14 @@ Supported Features ECDSA on {IDF_TARGET_NAME} -------------------------- -On {IDF_TARGET_NAME}, the ECDSA module works with a secret key burnt into an eFuse block. This eFuse key is made completely inaccessible (default mode) for any resources outside the cryptographic modules, thus avoiding key leakage. +On {IDF_TARGET_NAME}, the ECDSA module works with a secret key burnt into an eFuse block. + +.. only:: SOC_KEY_MANAGER_SUPPORTED + + On {IDF_TARGET_NAME}, the ECDSA module also supports storing a secret key in the Key Manager. Refer to :ref:`key-manager` for more details. + +This key is made completely inaccessible (default mode) for any resources outside the cryptographic modules, thus avoiding key leakage. + ECDSA Key Storage ^^^^^^^^^^^^^^^^^ @@ -53,6 +60,8 @@ ECDSA Key Storage ECDSA key can be programmed externally through ``idf.py`` script. Here is an example of how to program the ECDSA key: +Using eFuses to store the ECDSA key: + .. code:: bash idf.py efuse-burn-key ECDSA_KEY @@ -69,9 +78,18 @@ ECDSA key can be programmed externally through ``idf.py`` script. Here is an exa Six physical eFuse blocks can be used as keys for the ECDSA module: block 4 ~ block 9. E.g., for block 4 (which is the first key block) , the argument should be ``BLOCK_KEY0``. +.. only:: SOC_KEY_MANAGER_SUPPORTED + + Using the Key Manager to store the ECDSA key: + + ECDSA private keys can be stored in the Key Manager. Refer to :ref:`key-manager` for more details. + + Deploy an ECDSA key into the Key Manager and store the generated Key Recovery info in the flash memory for persistent keys. Alternatively the ECDSA key can also be programmed through the application running on the target. +Using eFuses to store the ECDSA key: + Following code snippet uses :cpp:func:`esp_efuse_write_key` to set physical key block 0 in the eFuse with key purpose as :cpp:enumerator:`esp_efuse_purpose_t::ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY`: .. code-block:: c diff --git a/docs/en/api-reference/peripherals/hmac.rst b/docs/en/api-reference/peripherals/hmac.rst index 90e249406f5..876a2c64d65 100644 --- a/docs/en/api-reference/peripherals/hmac.rst +++ b/docs/en/api-reference/peripherals/hmac.rst @@ -26,7 +26,13 @@ However, the HMAC itself is not bound to this use case. It can also be used for HMAC on {IDF_TARGET_NAME} ----------------------------- -On {IDF_TARGET_NAME}, the HMAC module works with a secret key burnt into the eFuses. This eFuse key can be made completely inaccessible for any resources outside the cryptographic modules, thus avoiding key leakage. +On {IDF_TARGET_NAME}, the HMAC module works with a secret key burnt into the eFuses. + +.. only:: SOC_KEY_MANAGER_SUPPORTED + + On {IDF_TARGET_NAME}, the HMAC module also supports storing a secret key in the Key Manager. Refer to :ref:`key-manager` for more details. + +This key can be made completely inaccessible for any resources outside the cryptographic modules, thus avoiding key leakage. Furthermore, {IDF_TARGET_NAME} has three different application scenarios for its HMAC module: @@ -142,6 +148,8 @@ Application Outline The following code is an outline of how to set an eFuse key and then use it to calculate an HMAC for software usage. +Using eFuses to store the HMAC key: + We use ``esp_efuse_write_key`` to set physical key block 4 in the eFuse for the HMAC module together with its purpose. ``ESP_EFUSE_KEY_PURPOSE_HMAC_UP`` (8) means that this key can only be used for HMAC generation for software usage: .. code-block:: c @@ -162,6 +170,8 @@ We use ``esp_efuse_write_key`` to set physical key block 4 in the eFuse for the Now we can calculate an HMAC for software usage with the saved key through the PSA Crypto API. +Using an eFuse-based HMAC key: + .. code-block:: c #include "psa/crypto.h" @@ -181,10 +191,9 @@ Now we can calculate an HMAC for software usage with the saved key through the P psa_set_key_bits(&attributes, 256); psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_HMAC_VOLATILE); - // Create opaque key reference + // Create opaque key reference for eFuse-based key esp_hmac_opaque_key_t opaque_key = { - .use_km_key = false, - .efuse_block = EFUSE_BLK_KEY4, + .efuse_key_id = HMAC_KEY4, }; // Import the opaque key diff --git a/docs/en/api-reference/peripherals/index.rst b/docs/en/api-reference/peripherals/index.rst index 57f27be74d4..332735d0ba7 100644 --- a/docs/en/api-reference/peripherals/index.rst +++ b/docs/en/api-reference/peripherals/index.rst @@ -23,6 +23,7 @@ Peripherals API :SOC_I2S_SUPPORTED: i2s :SOC_ISP_SUPPORTED: isp :SOC_JPEG_CODEC_SUPPORTED: jpeg + :SOC_KEY_MANAGER_SUPPORTED: key_manager lcd/index :SOC_GP_LDO_SUPPORTED: ldo_regulator ledc diff --git a/docs/en/api-reference/peripherals/key_manager.rst b/docs/en/api-reference/peripherals/key_manager.rst new file mode 100644 index 00000000000..47c4c89ada4 --- /dev/null +++ b/docs/en/api-reference/peripherals/key_manager.rst @@ -0,0 +1,171 @@ +.. _key-manager: + +Key Manager +=========== + +:link_to_translation:`zh_CN:[中文]` + +The {IDF_TARGET_NAME}'s Key Manager peripheral provides hardware-assisted **key deployment and recovery** for cryptographic keys. It allows cryptographic keys to be provisioned and used without storing plaintext key material in flash, RAM, or eFuses. + +The Key Manager is intended for applications that require secure handling of long-term cryptographic keys. + +.. only:: esp32p4 + + .. note:: + + The Key Manager peripheral is only supported on ESP32-P4 chip revision >= v3.0. + +.. only:: esp32c5 + + .. note:: + + The Key Manager peripheral is only supported on ESP32-C5 chip revision >= v1.2. + +Key Manager provides the following properties: + +- **Device uniqueness** + + Keys are cryptographically bound to a Hardware Unique Key (HUK) that is unique to each chip. + +- **No plaintext key storage** + + Key material is never exposed to software accessible memory. + +- **Flexible key lifecycle** + + Keys can be deployed, recovered, or replaced by a newer key without reprogramming the eFuses for each key. + +- **Resistance to physical extraction** + + Reading flash or eFuses contents would not reveal usable key material. + +Hardware Unique Key (HUK) +------------------------- + +The Hardware Unique Key (HUK) is a device-specific unique key generated entirely in hardware HUK peripheral. It is generated using SRAM Physical Unclonable Function (PUF) and is reconstructed using the HUK recovery info stored in the key recovery info of a Key Manager deployed key. See **{IDF_TARGET_NAME} Technical Reference Manual** > **Chapter Key Manager** [`PDF <{IDF_TARGET_TRM_EN_URL}>`__] > **HUK Generator** for more details about the HUK peripheral. + +The HUK acts as the root of trust for all keys deployed through the Key Manager. + +Key Deployment and Key Recovery +------------------------------- + +The Key Manager operates in two distinct phases: + +- **Key deployment** + + A cryptographic key is generated or securely introduced into the chip, and it gets bound to the HUK. This step is usually performed during manufacturing, first boot up or when generating transient or persistent keys during the application runtime. + +- **Key recovery** + + On subsequent boots, a Key Manager-deployed persistent key is restored using the previously generated key recovery information, without exposing the key value. + +During deployment, the Key Manager generates a data structure referred to as :cpp:type:`esp_key_mgr_key_recovery_info_t`. In case of persistent keys, the applications must store this data in non-volatile storage (for example, flash) in order to recover the key on later boots. + +Supported Key Types +------------------- + +The Key Manager can manage keys for the following key types: + +.. list:: + + :SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY: - ECDSA + :SOC_KEY_MANAGER_FE_KEY_DEPLOY: - Flash Encryption (XTS-AES) + :SOC_KEY_MANAGER_HMAC_KEY_DEPLOY: - HMAC + :SOC_KEY_MANAGER_DS_KEY_DEPLOY: - Digital Signature peripherals + :SOC_KEY_MANAGER_FE_KEY_DEPLOY: - PSRAM Encryption + +Each key is associated with a :cpp:type:`esp_key_mgr_key_purpose_t`, which defines how the key can be used by hardware peripherals. + +Key Deployment Modes +-------------------- + +The Key Manager provides multiple key deployment modes to support different provisioning and security requirements. + +Random Deploy Mode +^^^^^^^^^^^^^^^^^^ + +In this mode, the Key Manager generates a random private key internally. + +- The key value is never known to the application software. +- No external key material is required. +- Intended for use cases where the key does not need to be backed up or exported. + +AES Deploy Mode +^^^^^^^^^^^^^^^ + +In this mode, a user-specified private key is securely deployed. + +- The key is encrypted before being transmitted to the chip. +- Auxiliary key material is used to protect the deployment process. +- Intended for factory provisioning scenarios where the key value must be predefined. + +ECDH0 Deploy Mode +^^^^^^^^^^^^^^^^^ + +In this mode, a private key is negotiated using Elliptic Curve Diffie-Hellman (ECDH). + +- The final private key is never transmitted. +- The deployment process can occur over an untrusted channel. +- Intended for high-security provisioning environments. + +For detailed information various deployment modes, see **{IDF_TARGET_NAME} Technical Reference Manual** > **Chapter Key Manager** [`PDF <{IDF_TARGET_TRM_EN_URL}>`__] > **Section Key Manager**. + +.. ECDH1 Deploy Mode +.. ~~~~~~~~~~~~~~~~~ +.. +.. This mode is similar to ECDH0 Deploy Mode, with additional flexibility for manufacturing workflows. +.. +.. - Supports negotiated key deployment using auxiliary recovery data +.. - Allows updating deployed keys by replacing auxiliary information +.. - Intended for large-scale manufacturing with controlled trust assumptions + +Typical Workflows +----------------- + +First Boot or Manufacturing +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A typical provisioning flow includes: + +1. Generating the Hardware Unique Key (HUK) +2. Deploying required cryptographic keys using an appropriate deployment mode +3. Storing the generated ``key_recovery_info`` in non-volatile storage +4. Locking relevant security configuration eFuses, if required + +This process is usually performed once per device. + +Normal Boot +^^^^^^^^^^^ + +During a normal boot: + +1. The application provides the previously generated and stored ``key_recovery_info`` of a Key Manager-deployed key. +2. The HUK is reconstructed automatically by hardware. +3. The Key Manager recovers the deployed key internally. +4. Cryptographic peripherals can use the recovered key. + +Security Considerations +----------------------- + +Applications using the Key Manager should consider the following: + +- Protect the ``key_recovery_info`` of a Key Manager-deployed key against unauthorized modification or loss. +- Lock Key Manager's security-related eFuses after successful key deployment to prevent re-deployment of a key of the same type. +- Avoid deploying new XTS-AES keys when Flash Encryption is already enabled unless explicitly intended. + +API Reference +------------- + +.. include-build-file:: inc/esp_key_mgr.inc +.. include-build-file:: inc/key_mgr_types.inc + +Examples +-------- + +See :example:`security/key_manager` for an example demonstrating key deployment using the Key Manager and using the deployed key to perform signing operations. + +This example shows how to: + +- Initialize the Key Manager +- Deploy keys using the AES deployment mode +- Use the PSA interface to perform signing operations using the Key Manager deployed key diff --git a/docs/en/security/esp32c5_log.inc b/docs/en/security/esp32c5_log.inc index 5b9848cc9a2..59e43e76a6d 100644 --- a/docs/en/security/esp32c5_log.inc +++ b/docs/en/security/esp32c5_log.inc @@ -66,68 +66,72 @@ ------ +.. first_boot_enc_km + +.. code-block:: none + + ESP-ROM:esp32c5-eco3-20250704 + Build:Jul 4 2025 + rst:0x1 (POWERON),boot:0x18 (SPI_FAST_FLASH_BOOT) + SPI mode:DIO, clock div:1 + load:0x40855820,len:0x3a60 + load:0x4084bba0,len:0xdf4 + load:0x4084e5a0,len:0x566c + entry 0x4084bbaa + I (23) boot: ESP-IDF v6.0-dev-3140-ge16a2fb13ad-dirt 2nd stage bootloader + I (24) boot: compile time Oct 27 2025 15:35:09 + I (67) boot: chip revision: v1.1 + I (70) boot: efuse block revision: v0.3 + I (88) boot.esp32c5: SPI Speed : 80MHz + I (92) boot.esp32c5: SPI Mode : DIO + I (96) boot.esp32c5: SPI Flash Size : 2MB + I (103) boot: Enabling RNG early entropy source... + I (138) boot: Partition Table: + I (141) boot: ## Label Usage Type ST Offset Length + I (154) boot: 0 nvs WiFi data 01 02 0000e000 00006000 + I (168) boot: 1 phy_init RF data 01 01 00014000 00001000 + I (182) boot: 2 factory factory app 00 00 00020000 00100000 + I (189) boot: End of partition table + I (283) esp_image: segment 0: paddr=00020020 vaddr=42070020 size=32f1ch (208668) map + I (377) esp_image: segment 1: paddr=00052f44 vaddr=40800000 size=0a2a4h ( 41636) load + I (445) esp_image: segment 2: paddr=0005d1f0 vaddr=4080a300 size=02ccch ( 11468) load + I (512) esp_image: segment 3: paddr=0005fec4 vaddr=00000000 size=00154h ( 340) + I (580) esp_image: segment 4: paddr=00060020 vaddr=42000020 size=63804h (407556) map + I (761) boot: Loaded app from partition at offset 0x20000 + I (764) boot: Checking flash encryption... + I (788) efuse: Batch mode of writing fields is enabled + I (807) flash_encrypt: Deploying new flash encryption key using Key Manager + W (898) flash_encrypt: Not disabling UART bootloader encryption + I (904) flash_encrypt: Disable UART bootloader cache... + W (917) flash_encrypt: Not disabling JTAG - SECURITY COMPROMISED + I (930) efuse: BURN BLOCK0 + I (935) efuse: BURN BLOCK0 - OK (all write block bits are set) + I (938) efuse: Batch mode. Prepared fields are committed + I (1028) esp_image: segment 0: paddr=00002020 vaddr=40855820 size=03a60h ( 14944) + I (1096) esp_image: segment 1: paddr=00005a88 vaddr=4084bba0 size=00df4h ( 3572) + I (1165) esp_image: segment 2: paddr=00006884 vaddr=4084e5a0 size=0566ch ( 22124) + I (1508) flash_encrypt: bootloader encrypted successfully + I (1535) flash_encrypt: partition table encrypted and loaded successfully + I (1616) esp_image: segment 0: paddr=00020020 vaddr=42070020 size=32f1ch (208668) map + I (1711) esp_image: segment 1: paddr=00052f44 vaddr=40800000 size=0a2a4h ( 41636) + I (1779) esp_image: segment 2: paddr=0005d1f0 vaddr=4080a300 size=02ccch ( 11468) + I (1847) esp_image: segment 3: paddr=0005fec4 vaddr=00000000 size=00154h ( 340) + I (1916) esp_image: segment 4: paddr=00060020 vaddr=42000020 size=63804h (407556) map + I (2096) flash_encrypt: Encrypting partition 2 at offset 0x20000 (length 0xa3850)... + I (5652) flash_encrypt: Done encrypting + I (5667) efuse: BURN BLOCK0 + I (5671) efuse: BURN BLOCK0 - OK (all write block bits are set) + I (5675) flash_encrypt: Flash encryption completed + I (5679) boot: Resetting with flash encryption enabled... + + +------ + + .. already_en_enc .. code-block:: none - rst:0x1 (POWERON),boot:0x3d (SPI_FAST_FLASH_BOOT) - SPI mode:DIO, clock div:2 - load:0x40855c10,len:0x2be8 - load:0x4084c7a0,len:0x6f8 - load:0x4084e9a0,len:0x418c - entry 0x4084c804 - I (32) boot: ESP-IDF v5.3-dev-3860-g5d36288649 2nd stage bootloader - I (33) boot: compile time May 7 2024 17:24:43 - I (34) boot: chip revision: v0.0 - I (37) boot.esp32c5: SPI Speed : 40MHz - I (42) boot.esp32c5: SPI Mode : DIO - I (46) boot.esp32c5: SPI Flash Size : 2MB - I (51) boot: Enabling RNG early entropy source... - I (64) boot: Partition Table: - I (67) boot: ## Label Usage Type ST Offset Length - I (74) boot: 0 nvs WiFi data 01 02 0000e000 00006000 - I (82) boot: 1 storage Unknown data 01 ff 00014000 00001000 - I (89) boot: 2 factory factory app 00 00 00020000 00100000 - I (97) boot: 3 nvs_key NVS keys 01 04 00120000 00001000 - I (104) boot: 4 custom_nvs WiFi data 01 02 00121000 00006000 - I (113) boot: End of partition table - I (116) esp_image: segment 0: paddr=00020020 vaddr=42010020 size=095c4h ( 38340) map - I (169) esp_image: segment 1: paddr=000295ec vaddr=40800000 size=06a2ch ( 27180) load - I (197) esp_image: segment 2: paddr=00030020 vaddr=42000020 size=0f4d4h ( 62676) map - I (256) esp_image: segment 3: paddr=0003f4fc vaddr=40806a2c size=00b78h ( 2936) load - I (261) esp_image: segment 4: paddr=0004007c vaddr=408075b0 size=00d18h ( 3352) load - I (269) boot: Loaded app from partition at offset 0x20000 - I (270) boot: Checking flash encryption... - I (273) efuse: Batch mode of writing fields is enabled - I (278) flash_encrypt: Generating new flash encryption key... - I (295) efuse: Writing EFUSE_BLK_KEY0 with purpose 4 - W (300) flash_encrypt: Not disabling UART bootloader encryption - I (305) flash_encrypt: Disable JTAG... - I (312) efuse: BURN BLOCK4 - I (317) efuse: BURN BLOCK4 - OK (write block == read block) - I (319) efuse: BURN BLOCK0 - I (325) efuse: BURN BLOCK0 - OK (all write block bits are set) - I (330) efuse: Batch mode. Prepared fields are committed - I (335) esp_image: segment 0: paddr=00002020 vaddr=40855c10 size=02be8h ( 11240) - I (353) esp_image: segment 1: paddr=00004c10 vaddr=4084c7a0 size=006f8h ( 1784) - I (356) esp_image: segment 2: paddr=00005310 vaddr=4084e9a0 size=0418ch ( 16780) - I (1131) flash_encrypt: bootloader encrypted successfully - I (1229) flash_encrypt: partition table encrypted and loaded successfully - I (1230) flash_encrypt: Encrypting partition 1 at offset 0x14000 (length 0x1000)... - I (1325) flash_encrypt: Done encrypting - I (1325) esp_image: segment 0: paddr=00020020 vaddr=42010020 size=095c4h ( 38340) map - I (1362) esp_image: segment 1: paddr=000295ec vaddr=40800000 size=06a2ch ( 27180) - I (1389) esp_image: segment 2: paddr=00030020 vaddr=42000020 size=0f4d4h ( 62676) map - I (1448) esp_image: segment 3: paddr=0003f4fc vaddr=40806a2c size=00b78h ( 2936) - I (1453) esp_image: segment 4: paddr=0004007c vaddr=408075b0 size=00d18h ( 3352) - I (1458) flash_encrypt: Encrypting partition 2 at offset 0x20000 (length 0x100000)... - I (24332) flash_encrypt: Done encrypting - I (24332) flash_encrypt: Encrypting partition 3 at offset 0x120000 (length 0x1000)... - I (24422) flash_encrypt: Done encrypting - I (24423) efuse: BURN BLOCK0 - I (24425) efuse: BURN BLOCK0 - OK (all write block bits are set) - I (24427) flash_encrypt: Flash encryption completed - I (24431) boot: Resetting with flash encryption enabled... ESP-ROM:esp32c5-20240329 Build:Mar 29 2024 rst:0x3 (RTC_SW_HPSYS),boot:0x3d (SPI_FAST_FLASH_BOOT) @@ -193,3 +197,79 @@ ------ + + +.. already_en_enc_km + +.. code-block:: none + + ESP-ROM:esp32c5-eco3-20250704 + Build:Jul 4 2025 + rst:0x1 (POWERON),boot:0x18 (SPI_FAST_FLASH_BOOT) + use sector0 for km info + use KM derived key + SPI mode:DIO, clock div:1 + load:0x40855820,len:0x3a94 + load:0x4084bba0,len:0xd84 + load:0x4084e5a0,len:0x5670 + entry 0x4084bbaa + I (27) boot: ESP-IDF v6.0-dev-3139-gb813f413096-dirt 2nd stage bootloader + I (28) boot: compile time Oct 27 2025 18:14:49 + W (39) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1 + W (53) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1 + W (67) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1 + W (80) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1 + W (94) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1 + W (108) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1 + I (116) boot: chip revision: v1.1 + I (119) boot: efuse block revision: v0.3 + I (137) boot.esp32c5: SPI Speed : 80MHz + I (141) boot.esp32c5: SPI Mode : DIO + I (145) boot.esp32c5: SPI Flash Size : 2MB + I (149) boot: Enabling RNG early entropy source... + W (163) MMU: mmu_ll_write_entry mmu_id=0, entry_id=0, mmu_val=0x00000000, target=1 + I (191) boot: Partition Table: + I (194) boot: ## Label Usage Type ST Offset Length + I (208) boot: 0 nvs WiFi data 01 02 0000e000 00006000 + I (222) boot: 1 phy_init RF data 01 01 00014000 00001000 + I (235) boot: 2 factory factory app 00 00 00020000 00100000 + I (242) boot: End of partition table + I (396) esp_image: segment 0: paddr=00020020 vaddr=42070020 size=32f1ch (208668) map + I (539) esp_image: segment 1: paddr=00052f44 vaddr=40800000 size=0a2a4h ( 41636) load + I (629) esp_image: segment 2: paddr=0005d1f0 vaddr=4080a300 size=02ccch ( 11468) load + I (719) esp_image: segment 3: paddr=0005fec4 vaddr=00000000 size=00154h ( 340) + I (816) esp_image: segment 4: paddr=00060020 vaddr=42000020 size=6378ch (407436) map + I (1114) boot: Loaded app from partition at offset 0x20000 + I (1116) boot: Checking flash encryption... + I (1133) flash_encrypt: flash encryption is enabled (1 plaintext flashes left) + I (1140) boot: Disabling RNG early entropy source... + I (1301) MSPI Timing: Enter flash timing tuning + I (1434) cpu_start: Unicore app + I (1468) cpu_start: GPIO 12 and 11 are used as console UART I/O pins + I (1479) cpu_start: Pro cpu start user code + I (1483) cpu_start: cpu freq: 240000000 Hz + I (1493) app_init: Application information: + I (1496) app_init: Project name: mbedtls_test + I (1501) app_init: App version: qa-test-esp32c61-master-2025070 + I (1507) app_init: Compile time: Oct 27 2025 15:56:18 + I (1512) app_init: ELF file SHA256: c5f7f520c... + I (1517) app_init: ESP-IDF: v6.0-dev-3140-ge16a2fb13ad-dirt + I (1528) efuse_init: Min chip rev: v1.0 + I (1532) efuse_init: Max chip rev: v1.99 + I (1536) efuse_init: Chip rev: v1.1 + I (1669) heap_init: Initializing. RAM available for dynamic allocation: + I (1680) heap_init: At 4080FCB0 len 0004C8F0 (306 KiB): RAM + I (1685) heap_init: At 4085C5A0 len 00002F58 (11 KiB): RAM + I (1695) heap_init: At 50000000 len 00003FE8 (15 KiB): RTCRAM + I (1800) spi_flash: detected chip: generic + I (1804) spi_flash: flash io: dio + W (1807) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header. + W (1833) flash_encrypt: Flash encryption mode is DEVELOPMENT (not secure) + I (1867) sleep_gpio: Configure to isolate all GPIO pins in sleep state + I (1873) sleep_gpio: Enable automatic switching of GPIO sleep configuration + I (1926) main_task: Started on CPU0 + I (1926) main_task: Calling app_main() + I (1936) main_task: Returned from app_main() + + +------ diff --git a/docs/en/security/esp32p4_log.inc b/docs/en/security/esp32p4_log.inc index ae977774011..be398ee0d33 100644 --- a/docs/en/security/esp32p4_log.inc +++ b/docs/en/security/esp32p4_log.inc @@ -70,6 +70,72 @@ ------ +.. first_boot_enc_km + +.. code-block:: none + + ESP-ROM:esp32p4-eco5-20250430 + Build:Apr 30 2025 + rst:0x17 (CHIP_USB_UART_RESET),boot:0xc (SPI_FAST_FLASH_BOOT) + Core0 Saved PC:0x4fc0130e + Core1 Saved PC:0x4fc05fa4 + SPI mode:DIO, clock div:1 + load:0x4ffb6240,len:0x3870 + load:0x4ffac2c0,len:0x179c + load:0x4ffaefc0,len:0x4ed8 + entry 0x4ffac2ca + I (38) boot: ESP-IDF v6.0-dev-2918-g6629f96afca-dirt 2nd stage bootloader + I (38) boot: compile time Oct 14 2025 08:50:07 + I (39) boot: Multicore bootloader + I (85) boot: chip revision: v3.0 + I (88) boot: efuse block revision: v1.0 + I (106) boot.esp32p4: SPI Speed : 80MHz + I (110) boot.esp32p4: SPI Mode : DIO + I (114) boot.esp32p4: SPI Flash Size : 2MB + I (121) boot: Enabling RNG early entropy source... + I (156) boot: Partition Table: + I (159) boot: ## Label Usage Type ST Offset Length + I (173) boot: 0 factory factory app 00 00 00010000 00150000 + I (187) boot: 1 storage Unknown data 01 81 00160000 00050000 + I (194) boot: End of partition table + I (287) esp_image: segment 0: paddr=00010020 vaddr=40030020 size=0d1e8h ( 53736) map + I (355) esp_image: segment 1: paddr=0001d210 vaddr=30100000 size=00044h ( 68) load + I (423) esp_image: segment 2: paddr=0001d25c vaddr=4ff20000 size=02dbch ( 11708) load + I (491) esp_image: segment 3: paddr=00020020 vaddr=40000020 size=21834h (137268) map + I (567) esp_image: segment 4: paddr=0004185c vaddr=4ff22dbc size=094e8h ( 38120) load + I (635) esp_image: segment 5: paddr=0004ad4c vaddr=4ff2c300 size=044ech ( 17644) load + I (750) boot: Loaded app from partition at offset 0x10000 + I (752) boot: Checking flash encryption... + I (777) efuse: Batch mode of writing fields is enabled + I (796) flash_encrypt: Deploying new flash encryption key using Key Manager + W (933) flash_encrypt: Not disabling UART bootloader encryption + I (939) flash_encrypt: Disable UART bootloader cache... + W (952) flash_encrypt: Not disabling JTAG - SECURITY COMPROMISED + I (965) efuse: BURN BLOCK0 + I (970) efuse: BURN BLOCK0 - OK (write block == read block) + I (973) efuse: Batch mode. Prepared fields are committed + I (1063) esp_image: segment 0: paddr=00002020 vaddr=4ffb6240 size=03870h ( 14448) + I (1132) esp_image: segment 1: paddr=00005898 vaddr=4ffac2c0 size=0179ch ( 6044) + I (1200) esp_image: segment 2: paddr=0000703c vaddr=4ffaefc0 size=04ed8h ( 20184) + I (1725) flash_encrypt: bootloader encrypted successfully + I (1769) flash_encrypt: partition table encrypted and loaded successfully + I (1851) esp_image: segment 0: paddr=00010020 vaddr=40030020 size=0d1e8h ( 53736) map + I (1919) esp_image: segment 1: paddr=0001d210 vaddr=30100000 size=00044h ( 68) + I (1988) esp_image: segment 2: paddr=0001d25c vaddr=4ff20000 size=02dbch ( 11708) + I (2056) esp_image: segment 3: paddr=00020020 vaddr=40000020 size=21834h (137268) map + I (2133) esp_image: segment 4: paddr=0004185c vaddr=4ff22dbc size=094e8h ( 38120) + I (2202) esp_image: segment 5: paddr=0004ad4c vaddr=4ff2c300 size=044ech ( 17644) + I (2315) flash_encrypt: Encrypting partition 0 at offset 0x10000 (length 0x3f260)... + I (4978) flash_encrypt: Done encrypting + I (4992) efuse: BURN BLOCK0 + I (4997) efuse: BURN BLOCK0 - OK (all write block bits are set) + I (5001) flash_encrypt: Flash encryption completed + I (5005) boot: Resetting with flash encryption enabled... + + +------ + + .. already_en_enc .. code-block:: none @@ -152,3 +218,77 @@ I (595) main_task: Returned from app_main() ------ + + +.. already_en_enc_km + +.. code-block:: none + + ESP-ROM:esp32p4-eco5-20250430 + Build:Apr 30 2025 + rst:0x3 (SW_SYS_RESET),boot:0xc (SPI_FAST_FLASH_BOOT) + Core0 Saved PC:0x4ffb0910 + Core1 Saved PC:0x4fc05fa4 + SPI mode:DIO, clock div:1 + load:0x4ffb6240,len:0x3870 + load:0x4ffac2c0,len:0x179c + load:0x4ffaefc0,len:0x4ed8 + entry 0x4ffac2ca + I (37) boot: ESP-IDF v6.0-dev-2918-g6629f96afca-dirt 2nd stage bootloader + I (38) boot: compile time Oct 14 2025 08:50:07 + I (38) boot: Multicore bootloader + I (84) boot: chip revision: v3.0 + I (87) boot: efuse block revision: v1.0 + I (106) boot.esp32p4: SPI Speed : 80MHz + I (110) boot.esp32p4: SPI Mode : DIO + I (113) boot.esp32p4: SPI Flash Size : 2MB + I (121) boot: Enabling RNG early entropy source... + I (155) boot: Partition Table: + I (158) boot: ## Label Usage Type ST Offset Length + I (172) boot: 0 factory factory app 00 00 00010000 00150000 + I (186) boot: 1 storage Unknown data 01 81 00160000 00050000 + I (193) boot: End of partition table + I (287) esp_image: segment 0: paddr=00010020 vaddr=40030020 size=0d1e8h ( 53736) map + I (355) esp_image: segment 1: paddr=0001d210 vaddr=30100000 size=00044h ( 68) load + I (422) esp_image: segment 2: paddr=0001d25c vaddr=4ff20000 size=02dbch ( 11708) load + I (491) esp_image: segment 3: paddr=00020020 vaddr=40000020 size=21834h (137268) map + I (567) esp_image: segment 4: paddr=0004185c vaddr=4ff22dbc size=094e8h ( 38120) load + I (635) esp_image: segment 5: paddr=0004ad4c vaddr=4ff2c300 size=044ech ( 17644) load + I (750) boot: Loaded app from partition at offset 0x10000 + I (752) boot: Checking flash encryption... + I (769) flash_encrypt: flash encryption is enabled (1 plaintext flashes left) + I (776) boot: Disabling RNG early entropy source... + W (847) pmu_pvt: blk_version is less than 2, pvt auto dbias init not supported in efuse. + I (855) cpu_start: Multicore app + I (890) cpu_start: GPIO 38 and 37 are used as console UART I/O pins + I (901) cpu_start: Pro cpu start user code + I (905) cpu_start: cpu freq: 400000000 Hz + I (914) app_init: Application information: + I (918) app_init: Project name: crypto_test + I (922) app_init: App version: qa-test-esp32c61-master-2025070 + I (928) app_init: Compile time: Oct 14 2025 08:50:07 + I (933) app_init: ELF file SHA256: 847005dd4... + I (938) app_init: ESP-IDF: v6.0-dev-2918-g6629f96afca-dirt + I (949) efuse_init: Min chip rev: v3.0 + I (953) efuse_init: Max chip rev: v3.99 + I (957) efuse_init: Chip rev: v3.0 + I (1126) heap_init: Initializing. RAM available for dynamic allocation: + I (1137) heap_init: At 4FF33B20 len 000874A0 (541 KiB): RAM + I (1143) heap_init: At 4FFBAFC0 len 00004BF0 (18 KiB): RAM + I (1153) heap_init: At 50108080 len 00007F80 (31 KiB): RTCRAM + I (1163) heap_init: At 30100044 len 00001FBC (7 KiB): TCM + I (1261) spi_flash: detected chip: gd + I (1264) spi_flash: flash io: dio + W (1267) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header. + W (1293) flash_encrypt: Flash encryption mode is DEVELOPMENT (not secure) + I (1357) main_task: Started on CPU0 + I (1407) main_task: Calling app_main() + I (1407) main_task: Returned from app_main() + + Example to check Flash Encryption status + This is esp32p4 chip with 2 CPU core(s), WiFi, silicon revision v0.0, 2MB external flash + FLASH_CRYPT_CNT eFuse value is 1 + Flash encryption feature is enabled in DEVELOPMENT mode + + +------ diff --git a/docs/en/security/flash-encryption.rst b/docs/en/security/flash-encryption.rst index 7609919bd4d..e3991f78845 100644 --- a/docs/en/security/flash-encryption.rst +++ b/docs/en/security/flash-encryption.rst @@ -13,7 +13,7 @@ This is a quick start guide to {IDF_TARGET_NAME}'s flash encryption feature. Usi .. note:: - In this guide, most used commands are in the form of ``idf.py secure-``, which is a wrapper around corresponding ``espsecure ``. The ``idf.py`` based commands provides more user-friendly experience, although may lack some of the advanced functionality of their ``espsecure`` based counterparts. + In this guide, most used commands are in the form of ``idf.py secure-``, which is a wrapper around corresponding ``espsecure ``. The ``idf.py`` based commands provide a more user-friendly experience, although may lack some of the advanced functionality of their ``espsecure`` based counterparts. Introduction ------------ @@ -26,7 +26,7 @@ Flash encryption is intended for encrypting the contents of the {IDF_TARGET_NAME .. important:: - For production use, flash encryption should be enabled in the "Release" mode only. + For production use, flash encryption should be enabled in the release mode only. .. important:: @@ -73,7 +73,7 @@ The flash encryption operation is controlled by various eFuses available on {IDF - 2 * - ``flash_encryption`` (block1) - AES key storage. - - 256 bit key block + - 256-bit key block * - ``FLASH_CRYPT_CONFIG`` - Controls the AES encryption process. - 4 @@ -84,7 +84,7 @@ The flash encryption operation is controlled by various eFuses available on {IDF - If set, disables flash decryption while running in UART Firmware Download mode. - 1 * - ``{IDF_TARGET_CRYPT_CNT}`` - - A :math:`2^n` number that indicating whether the contents of flash have been encrypted. + - A :math:`2^n` number indicating whether the contents of flash have been encrypted. * If an odd number of bits are set (e.g., ``0b0000001`` or ``0b0000111``), this indicates the contents of flash are encrypted. The contents will need to be transparently decrypted when read. * If an even number of bits are set (e.g., ``0b0000000`` or ``0b0000011``), this indicates the contents of flash are unencrypted (i.e., plain text). @@ -93,7 +93,35 @@ The flash encryption operation is controlled by various eFuses available on {IDF - 7 -.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256 +.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256 and SOC_KEY_MANAGER_SUPPORTED + + .. list-table:: eFuses Used in Flash Encryption + :widths: 25 40 10 + :header-rows: 0 + + * - **eFuse** + - **Description** + - **Bit Depth** + * - ``BLOCK_KEYN`` + - AES key storage. N is between 0 and 5. When using a Key Manager-based key, this eFuse is not used. + - One 256-bit key block for XTS_AES_128; two 256-bit key blocks for XTS_AES_256 (512-bit total). + * - ``KEY_PURPOSE_N`` + - Controls the purpose of eFuse block ``BLOCK_KEYN``, where N is between 0 and 5. Possible values: ``2`` for ``XTS_AES_256_KEY_1``, ``3`` for ``XTS_AES_256_KEY_2``, and ``4`` for ``XTS_AES_128_KEY``. Final AES key is derived based on the value of one or two of these purpose eFuses. For a detailed description of the possible combinations, see **{IDF_TARGET_NAME} Technical Reference Manual** > **External Memory Encryption and Decryption (XTS_AES)** [`PDF <{IDF_TARGET_TRM_EN_URL}#extmemencr>`__]. When enabling Flash Encryption using a Key Manager-based key, this eFuse is not used. + - 4 + * - ``KM_XTS_KEY_LENGTH_256`` + - When enabling Flash Encryption using a Key Manager-based key, this eFuse is used to control the length of the XTS-AES key. Set this eFuse to 1 to use a 128-bit key, and to 0 to use a 256-bit key. This eFuse field is unused when enabling Flash Encryption using an eFuse-based key. + - 1 + * - ``FORCE_USE_KEY_MANAGER_KEY`` + - When enabling Flash Encryption using a Key Manager-based key, this eFuse is used to force the Key Manager to use the XTS-AES key. Set the bit 1 of this eFuse to use the Key Manager-based key. This eFuse field is unused when enabling Flash Encryption using an eFuse-based key. + - 1 + * - ``DIS_DOWNLOAD_MANUAL_ENCRYPT`` + - If set, disables Flash Encryption when in download bootmodes. + - 1 + * - ``{IDF_TARGET_CRYPT_CNT}`` + - Enables encryption and decryption, when an SPI boot mode is set. Feature is enabled if 1 or 3 bits are set in the eFuse, disabled otherwise. + - 3 + +.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_KEY_MANAGER_SUPPORTED .. list-table:: eFuses Used in Flash Encryption :widths: 25 40 10 @@ -104,9 +132,9 @@ The flash encryption operation is controlled by various eFuses available on {IDF - **Bit Depth** * - ``BLOCK_KEYN`` - AES key storage. N is between 0 and 5. - - One 256 bit key block for XTS_AES_128, Two 256 bit key blocks for XTS_AES_256 (512 bit total) + - One 256-bit key block for XTS_AES_128, Two 256-bit key blocks for XTS_AES_256 (512 bit total) * - ``KEY_PURPOSE_N`` - - Controls the purpose of eFuse block ``BLOCK_KEYN``, where N is between 0 and 5. Possible values: ``2`` for ``XTS_AES_256_KEY_1`` , ``3`` for ``XTS_AES_256_KEY_2``, and ``4`` for ``XTS_AES_128_KEY``. Final AES key is derived based on the value of one or two of these purpose eFuses. For a detailed description of the possible combinations, see *{IDF_TARGET_NAME} Technical Reference Manual* > *External Memory Encryption and Decryption (XTS_AES)* [`PDF <{IDF_TARGET_TRM_EN_URL}#extmemencr>`__]. + - Controls the purpose of eFuse block ``BLOCK_KEYN``, where N is between 0 and 5. Possible values: ``2`` for ``XTS_AES_256_KEY_1`` , ``3`` for ``XTS_AES_256_KEY_2``, and ``4`` for ``XTS_AES_128_KEY``. Final AES key is derived based on the value of one or two of these purpose eFuses. For a detailed description of the possible combinations, see **{IDF_TARGET_NAME} Technical Reference Manual** > **External Memory Encryption and Decryption (XTS_AES)** [`PDF <{IDF_TARGET_TRM_EN_URL}#extmemencr>`__]. - 4 * - ``DIS_DOWNLOAD_MANUAL_ENCRYPT`` - If set, disables flash encryption when in download bootmodes. @@ -115,7 +143,35 @@ The flash encryption operation is controlled by various eFuses available on {IDF - Enables encryption and decryption, when an SPI boot mode is set. Feature is enabled if 1 or 3 bits are set in the eFuse, disabled otherwise. - 3 -.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK +.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK and SOC_KEY_MANAGER_SUPPORTED + + .. list-table:: eFuses Used in Flash Encryption + :widths: 25 40 10 + :header-rows: 0 + + * - **eFuse** + - **Description** + - **Bit Depth** + * - ``BLOCK_KEYN`` + - AES key storage. N is between 0 and 5. When using a Key Manager-based key, this eFuse is not used. + - 256-bit key block. + * - ``KEY_PURPOSE_N`` + - Control the purpose of eFuse block ``BLOCK_KEYN``, where N is between 0 and 5. For flash encryption, the only valid value is ``4`` for ``XTS_AES_128_KEY``. When enabling Flash Encryption using a Key Manager-based key, this eFuse is not used. + - 4 + * - ``KM_XTS_KEY_LENGTH_256`` + - When enabling Flash Encryption using a Key Manager-based key, this eFuse is used to control the length of the XTS-AES key. Set this eFuse to 1 to use a 128-bit key, and to 0 to use a 256-bit key. This eFuse field is unused when enabling Flash Encryption using an eFuse-based key. + - 1 + * - ``FORCE_USE_KEY_MANAGER_KEY`` + - When enabling Flash Encryption using a Key Manager-based key, this eFuse is used to force the Key Manager to use the XTS-AES key. Set the bit 1 of this eFuse to use the Key Manager-based key. This eFuse field is unused when enabling Flash Encryption using an eFuse-based key. + - 1 + * - ``DIS_DOWNLOAD_MANUAL_ENCRYPT`` + - If set, disable flash encryption when in download bootmodes. + - 1 + * - ``{IDF_TARGET_CRYPT_CNT}`` + - Enable encryption and decryption, when an SPI boot mode is set. Feature is enabled if 1 or 3 bits are set in the eFuse, disabled otherwise. + - 3 + +.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK and not SOC_KEY_MANAGER_SUPPORTED .. list-table:: eFuses Used in Flash Encryption :widths: 25 40 10 @@ -126,7 +182,7 @@ The flash encryption operation is controlled by various eFuses available on {IDF - **Bit Depth** * - ``BLOCK_KEYN`` - AES key storage. N is between 0 and 5. - - 256 bit key block + - 256-bit key block * - ``KEY_PURPOSE_N`` - Control the purpose of eFuse block ``BLOCK_KEYN``, where N is between 0 and 5. For flash encryption, the only valid value is ``4`` for ``XTS_AES_128_KEY``. - 4 @@ -181,7 +237,7 @@ Assuming that the eFuse values are in their default states and the second stage 1. On the first power-on reset, all data in flash is un-encrypted (plaintext). The first stage (ROM) bootloader loads the second stage bootloader. - 2. Second stage bootloader reads the ``{IDF_TARGET_CRYPT_CNT}`` eFuse value (``0b0000000``). Since the value is ``0`` (even number of bits set), it configures and enables the flash encryption block. It also sets the ``FLASH_CRYPT_CONFIG`` eFuse to 0xF. For more information on the flash encryption block, see *{IDF_TARGET_NAME} Technical Reference Manual* > *eFuse Controller (eFuse)* > *Flash Encryption Block* [`PDF <{IDF_TARGET_TRM_EN_URL}#efuse>`__]. + 2. Second stage bootloader reads the ``{IDF_TARGET_CRYPT_CNT}`` eFuse value (``0b0000000``). Since the value is ``0`` (even number of bits set), it configures and enables the flash encryption block. It also sets the ``FLASH_CRYPT_CONFIG`` eFuse to 0xF. For more information on the flash encryption block, see **{IDF_TARGET_NAME} Technical Reference Manual** > **eFuse Controller (eFuse)** > **Flash Encryption Block** [`PDF <{IDF_TARGET_TRM_EN_URL}#efuse>`__]. 3. Second stage bootloader first checks if a valid key is already present in the eFuse (e.g., burned using espefuse tool), then the process of key generation is skipped and the same key is used for flash encryption process. Otherwise, Second stage bootloader uses RNG (random) module to generate an AES-256 bit key and then writes it into the ``flash_encryption`` eFuse. The key cannot be accessed via software as the write and read protection bits for the ``flash_encryption`` eFuse are set. The flash encryption operations happen entirely by hardware, and the key cannot be accessed via software. @@ -195,13 +251,46 @@ Assuming that the eFuse values are in their default states and the second stage 8. The device is then rebooted to start executing the encrypted image. The second stage bootloader calls the flash decryption block to decrypt the flash contents and then loads the decrypted contents into IRAM. -.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256 +.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256 and SOC_KEY_MANAGER_SUPPORTED 1. On the first power-on reset, all data in flash is un-encrypted (plaintext). The first stage (ROM) bootloader loads the second stage bootloader. - 2. Second stage bootloader reads the ``{IDF_TARGET_CRYPT_CNT}`` eFuse value (``0b000``). Since the value is ``0`` (even number of bits set), it configures and enables the flash encryption block. For more information on the flash encryption block, see *{IDF_TARGET_NAME} Technical Reference Manual* > *eFuse Controller (eFuse)* > *Auto Encryption Block* [`PDF <{IDF_TARGET_TRM_EN_URL}#efuse>`__]. + 2. Second stage bootloader reads the ``{IDF_TARGET_CRYPT_CNT}`` eFuse value (``0b000``). Since the value is ``0`` (even number of bits set), it configures and enables the flash encryption block. For more information on the flash encryption block, see **{IDF_TARGET_NAME} Technical Reference Manual** > **eFuse Controller (eFuse)** > **Manual Encryption Block** [`PDF <{IDF_TARGET_TRM_EN_URL}#efuse>`__]. - 3. Second stage bootloader first checks if a valid key is already present in the eFuse (e.g., burned using espefuse tool) then the process of key generation is skipped and the same key is used for flash encryption process. Otherwise, second stage bootloader uses RNG (random) module to generate an 256 bit or 512 bit key, depending on the value of :ref:`Size of generated XTS-AES key `, and then writes it into respectively one or two `BLOCK_KEYN` eFuses. The software also updates the ``KEY_PURPOSE_N`` for the blocks where the keys were stored. The key cannot be accessed via software as the write and read protection bits for one or two `BLOCK_KEYN` eFuses are set. ``KEY_PURPOSE_N`` field is write-protected as well. The flash encryption operations happen entirely by hardware, and the key cannot be accessed via software. + 3. Second stage bootloader first checks if a valid key already exists, to decide whether to skip the key generation step: + + - If Flash Encryption is intended to be enabled using an eFuse-based key, it checks if a valid key is already present in the eFuse (e.g., burned using espefuse tool). + - If Flash Encryption is intended to be enabled using a Key Manager-based key, it checks if there exists a valid key recovery info in the flash memory at the addresses: 0x0 and 0x1000. + + If the check passes, the process of key generation is skipped and the same key is used for the flash encryption process. + + 4. Otherwise, if using an eFuse-based key, second stage bootloader uses RNG (random) module to generate an 256-bit or 512-bit key, depending on the value of :ref:`Size of generated XTS-AES key `, and then writes it into respectively one or two ``BLOCK_KEYN`` eFuses. The software also updates the ``KEY_PURPOSE_N`` for the blocks where the keys were stored. The key cannot be accessed via software as the write and read protection bits for one or two ``BLOCK_KEYN`` eFuses are set. ``KEY_PURPOSE_N`` field is write-protected as well. Whereas if using a Key Manager-based key, second stage bootloader writes the key recovery info to the flash memory at the address 0x0, followed by programming the ``KM_XTS_KEY_LENGTH_256`` and the ``FORCE_USE_KEY_MANAGER_KEY`` eFuses. The flash encryption operations happen entirely by hardware, and the key cannot be accessed via software. + + 5. Flash encryption block encrypts the flash contents – the second stage bootloader, applications and partitions marked as ``encrypted``. Encrypting in-place can take time, up to a minute for large partitions. + + 6. Second stage bootloader sets the first available bit in ``{IDF_TARGET_CRYPT_CNT}`` (0b001) to mark the flash contents as encrypted. Odd number of bits is set. + + 7. For :ref:`flash-enc-development-mode`, the second stage bootloader allows the UART bootloader to re-flash encrypted binaries. Also, the ``{IDF_TARGET_CRYPT_CNT}`` eFuse bits are NOT write-protected. In addition, the second stage bootloader by default sets the following eFuse bits: + + .. list:: + + :esp32s2: - ``DIS_BOOT_REMAP`` + - ``DIS_DOWNLOAD_ICACHE`` + - ``DIS_DOWNLOAD_DCACHE`` + - ``HARD_DIS_JTAG`` + - ``DIS_LEGACY_SPI_BOOT`` + + 8. For :ref:`flash-enc-release-mode`, the second stage bootloader sets all the eFuse bits set under development mode as well as ``DIS_DOWNLOAD_MANUAL_ENCRYPT``. It also write-protects the ``{IDF_TARGET_CRYPT_CNT}`` eFuse bits. To modify this behavior, see :ref:`uart-bootloader-encryption`. + + 9. The device is then rebooted to start executing the encrypted image. The second stage bootloader calls the flash decryption block to decrypt the flash contents and then loads the decrypted contents into IRAM. + +.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_KEY_MANAGER_SUPPORTED + + 1. On the first power-on reset, all data in flash is un-encrypted (plaintext). The first stage (ROM) bootloader loads the second stage bootloader. + + 2. Second stage bootloader reads the ``{IDF_TARGET_CRYPT_CNT}`` eFuse value (``0b000``). Since the value is ``0`` (even number of bits set), it configures and enables the flash encryption block. For more information on the flash encryption block, see **{IDF_TARGET_NAME} Technical Reference Manual** > **eFuse Controller (eFuse)** > **Auto Encryption Block** [`PDF <{IDF_TARGET_TRM_EN_URL}#efuse>`__]. + + 3. Second stage bootloader first checks if a valid key is already present in the eFuse (e.g., burned using espefuse tool) then the process of key generation is skipped and the same key is used for flash encryption process. Otherwise, second stage bootloader uses RNG (random) module to generate a 256-bit or 512-bit key, depending on the value of :ref:`Size of generated XTS-AES key `, and then writes it into respectively one or two ``BLOCK_KEYN`` eFuses. The software also updates the ``KEY_PURPOSE_N`` for the blocks where the keys were stored. The key cannot be accessed via software as the write and read protection bits for one or two `BLOCK_KEYN` eFuses are set. ``KEY_PURPOSE_N`` field is write-protected as well. The flash encryption operations happen entirely by hardware, and the key cannot be accessed via software. 4. Flash encryption block encrypts the flash contents - the second stage bootloader, applications and partitions marked as ``encrypted``. Encrypting in-place can take time, up to a minute for large partitions. @@ -221,31 +310,58 @@ Assuming that the eFuse values are in their default states and the second stage 8. The device is then rebooted to start executing the encrypted image. The second stage bootloader calls the flash decryption block to decrypt the flash contents and then loads the decrypted contents into IRAM. +.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK and SOC_KEY_MANAGER_SUPPORTED + + 1. On the first power-on reset, all data in flash is un-encrypted (plaintext). The first stage (ROM) bootloader loads the second stage bootloader. + + 2. Second stage bootloader reads the ``{IDF_TARGET_CRYPT_CNT}`` eFuse value (``0b000``). Since the value is ``0`` (even number of bits set), it configures and enables the flash encryption block. For more information on the flash encryption block, see `{IDF_TARGET_NAME} Technical Reference Manual <{IDF_TARGET_TRM_EN_URL}>`_. + + 3. Second stage bootloader first checks if a valid key already exists, to decide whether to skip the key generation step: + + - If Flash Encryption is intended to be enabled using an eFuse-based key, it checks if a valid key is already present in the eFuse (e.g., burned using espefuse tool). + - If Flash Encryption is intended to be enabled using a Key Manager-based key, it checks if there exists a valid key recovery info in the flash memory at the addresses: 0x0 and 0x1000. + + If the check passes, the process of key generation is skipped and the same key is used for the flash encryption process. + + 4. Otherwise, if using an eFuse-based key second stage bootloader uses RNG (random) module to generate a 256-bit key, and then writes it into respectively one ``BLOCK_KEYN`` eFuse block. The software also updates the ``KEY_PURPOSE_N`` for the block where the key were stored. The key cannot be accessed via software as the write and read protection bits for the ``BLOCK_KEYN`` eFuse block is set. ``KEY_PURPOSE_N`` field is write-protected as well. Whereas if using a Key Manager-based key, second stage bootloader writes the key recovery info to the flash memory at the address 0x0, followed by programming the ``KM_XTS_KEY_LENGTH_256`` and the ``FORCE_USE_KEY_MANAGER_KEY`` eFuses. The flash encryption operations happen entirely by hardware, and the key cannot be accessed via software. + + 5. Flash encryption block encrypts the flash contents - the second stage bootloader, applications and partitions marked as ``encrypted``. Encrypting in-place can take time, up to a minute for large partitions. + + 6. Second stage bootloader sets the first available bit in ``{IDF_TARGET_CRYPT_CNT}`` (0b001) to mark the flash contents as encrypted. Odd number of bits is set. + + 7. For :ref:`flash-enc-development-mode`, the second stage bootloader allows the UART bootloader to re-flash encrypted binaries. Also, the ``{IDF_TARGET_CRYPT_CNT}`` eFuse bits are NOT write-protected. In addition, the second stage bootloader by default sets the eFuse bits ``DIS_DOWNLOAD_ICACHE``, ``DIS_PAD_JTAG``, ``DIS_USB_JTAG`` and ``DIS_LEGACY_SPI_BOOT``. + + 8. For :ref:`flash-enc-release-mode`, the second stage bootloader sets all the eFuse bits set under development mode as well as ``DIS_DOWNLOAD_MANUAL_ENCRYPT``. It also write-protects the ``{IDF_TARGET_CRYPT_CNT}`` eFuse bits. To modify this behavior, see :ref:`uart-bootloader-encryption`. + + 9. The device is then rebooted to start executing the encrypted image. The second stage bootloader calls the flash decryption block to decrypt the flash contents and then loads the decrypted contents into IRAM. + .. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK 1. On the first power-on reset, all data in flash is un-encrypted (plaintext). The first stage (ROM) bootloader loads the second stage bootloader. 2. Second stage bootloader reads the ``{IDF_TARGET_CRYPT_CNT}`` eFuse value (``0b000``). Since the value is ``0`` (even number of bits set), it configures and enables the flash encryption block. For more information on the flash encryption block, see `{IDF_TARGET_NAME} Technical Reference Manual <{IDF_TARGET_TRM_EN_URL}>`_. - 3. Second stage bootloader uses RNG (random) module to generate an 256 bit key and then writes it into `BLOCK_KEYN` eFuse. The software also updates the ``KEY_PURPOSE_N`` for the block where the key is stored. The key cannot be accessed via software as the write and read protection bits for `BLOCK_KEYN` eFuse are set. ``KEY_PURPOSE_N`` field is write-protected as well. The flash encryption is completely conducted by hardware, and the key cannot be accessed via software. If a valid key is already present in the eFuse (e.g., burned using espefuse tool) then the process of key generation is skipped and the same key is used for flash encryption process. + 3. Second stage bootloader first checks if a valid key is already present in the eFuse (e.g., burned using espefuse tool), then the process of key generation is skipped and the same key is used for flash encryption process. - 4. Flash encryption block encrypts the flash contents - the second stage bootloader, applications and partitions marked as ``encrypted``. Encrypting in-place can take time, up to a minute for large partitions. + 4. Otherwise, second stage bootloader uses RNG (random) module to generate a 256-bit key and then writes it into ``BLOCK_KEYN`` eFuse. The software also updates the ``KEY_PURPOSE_N`` for the block where the key is stored. The key cannot be accessed via software as the write and read protection bits for ``BLOCK_KEYN`` eFuse are set. ``KEY_PURPOSE_N`` field is write-protected as well. The flash encryption is completely conducted by hardware, and the key cannot be accessed via software. - 5. Second stage bootloader sets the first available bit in ``{IDF_TARGET_CRYPT_CNT}`` (0b001) to mark the flash contents as encrypted. Odd number of bits is set. + 5. Flash encryption block encrypts the flash contents - the second stage bootloader, applications and partitions marked as ``encrypted``. Encrypting in-place can take time, up to a minute for large partitions. - 6. For :ref:`flash-enc-development-mode`, the second stage bootloader allows the UART bootloader to re-flash encrypted binaries. Also, the ``{IDF_TARGET_CRYPT_CNT}`` eFuse bits are NOT write-protected. In addition, the second stage bootloader by default sets the eFuse bits ``DIS_DOWNLOAD_ICACHE``, ``DIS_PAD_JTAG``, ``DIS_USB_JTAG`` and ``DIS_LEGACY_SPI_BOOT``. + 6. Second stage bootloader sets the first available bit in ``{IDF_TARGET_CRYPT_CNT}`` (0b001) to mark the flash contents as encrypted. Odd number of bits is set. - 7. For :ref:`flash-enc-release-mode`, the second stage bootloader sets all the eFuse bits set under development mode as well as ``DIS_DOWNLOAD_MANUAL_ENCRYPT``. It also write-protects the ``{IDF_TARGET_CRYPT_CNT}`` eFuse bits. To modify this behavior, see :ref:`uart-bootloader-encryption`. + 7. For :ref:`flash-enc-development-mode`, the second stage bootloader allows the UART bootloader to re-flash encrypted binaries. Also, the ``{IDF_TARGET_CRYPT_CNT}`` eFuse bits are NOT write-protected. In addition, the second stage bootloader by default sets the eFuse bits ``DIS_DOWNLOAD_ICACHE``, ``DIS_PAD_JTAG``, ``DIS_USB_JTAG`` and ``DIS_LEGACY_SPI_BOOT``. - 8. The device is then rebooted to start executing the encrypted image. The second stage bootloader calls the flash decryption block to decrypt the flash contents and then loads the decrypted contents into IRAM. + 8. For :ref:`flash-enc-release-mode`, the second stage bootloader sets all the eFuse bits set under development mode as well as ``DIS_DOWNLOAD_MANUAL_ENCRYPT``. It also write-protects the ``{IDF_TARGET_CRYPT_CNT}`` eFuse bits. To modify this behavior, see :ref:`uart-bootloader-encryption`. + + 9. The device is then rebooted to start executing the encrypted image. The second stage bootloader calls the flash decryption block to decrypt the flash contents and then loads the decrypted contents into IRAM. .. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK - 1. On the first power-on reset, all data in flash is un-encrypted (plaintext). The first stage (ROM) bootloaders loads the second stage bootloader. + 1. On the first power-on reset, all data in flash is un-encrypted (plaintext). The first stage (ROM) bootloader loads the second stage bootloader. 2. The second stage bootloader reads the ``{IDF_TARGET_CRYPT_CNT}`` eFuse value (``0b000``). Since the value is ``0`` (even number of bits set), it configures and enables the flash encryption block. For more information on the flash encryption block, see `{IDF_TARGET_NAME} Technical Reference Manual <{IDF_TARGET_TRM_EN_URL}>`_. - 3. The second stage bootloader uses RNG (random) module to generate an 256 or 128 bit key (depends on :ref:`Size of generated XTS-AES key `) and then writes it into `BLOCK_KEY0` eFuse. The software also updates the ``XTS_KEY_LENGTH_256`` according to the chosen option. The key cannot be accessed via software as the write and read protection bits for ``BLOCK_KEY0`` eFuse are set. The flash encryption operations happen entirely by hardware, and the key cannot be accessed via software. If 128-bit flash encryption key is used, then only the lower 128 bits of the eFuse key block are read-protected, the remaining 128 bits are readable, which is required for secure boot. The entire eFuse block is write-protected. If the FE key is 256 bits long, then ``XTS_KEY_LENGTH_256`` is 1, otherwise it is 0. To prevent this eFuse from being accidentally changed in the future (from 0 to 1), we set a write-protect bit for the RELEASE mode. If a valid key is already present in the eFuse (e.g., burned using espefuse tool) then the process of key generation is skipped and the same key is used for flash encryption process. + 3. The second stage bootloader uses RNG (random) module to generate an 256 or 128 bit key (depends on :ref:`Size of generated XTS-AES key `) and then writes it into `BLOCK_KEY0` eFuse. The software also updates the ``XTS_KEY_LENGTH_256`` according to the chosen option. The key cannot be accessed via software as the write and read protection bits for ``BLOCK_KEY0`` eFuse are set. The flash encryption operations happen entirely by hardware, and the key cannot be accessed via software. If 128-bit flash encryption key is used, then only the lower 128 bits of the eFuse key block are read-protected, the remaining 128 bits are readable, which is required for secure boot. The entire eFuse block is write-protected. If the FE key is 256 bits long, then ``XTS_KEY_LENGTH_256`` is 1, otherwise it is 0. To prevent this eFuse from being accidentally changed in the future (from 0 to 1), we set a write-protect bit for the release mode. If a valid key is already present in the eFuse (e.g., burned using espefuse tool) then the process of key generation is skipped and the same key is used for flash encryption process. 4. Flash encryption block encrypts the flash contents - the second stage bootloader, applications and partitions marked as ``encrypted``. Encrypting in-place can take time, up to a minute for large partitions. @@ -297,14 +413,15 @@ To test flash encryption process, take the following steps: .. list:: - :ref:`Enable flash encryption on boot `. - - :ref:`Select encryption mode ` (**Development mode** by default). + - :ref:`Select encryption mode ` (**development mode** by default). :esp32: - :ref:`Select UART ROM download mode ` (**enabled** by default). Note that for the ESP32 target, the choice is only available when :ref:`CONFIG_ESP32_REV_MIN` level is set to 3 (ESP32 V3). :not esp32: - :ref:`Select UART ROM download mode ` (**enabled** by default). :SOC_FLASH_ENCRYPTION_XTS_AES_OPTIONS: - Set :ref:`Size of generated XTS-AES key `. + :SOC_KEY_MANAGER_SUPPORTED: - :ref:`Select the key source for the Flash Encryption key `. - :ref:`Select the appropriate bootloader log verbosity `. - Save the configuration and exit. -Enabling flash encryption will increase the size of bootloader, which might require updating partition table offset. See :ref:`bootloader-size`. + Enabling flash encryption will increase the size of bootloader, which might require updating partition table offset. See :ref:`bootloader-size`. 3. Run the command given below to build and flash the complete images. @@ -318,13 +435,27 @@ Enabling flash encryption will increase the size of bootloader, which might requ This command will write to flash memory unencrypted images: the second stage bootloader, the partition table and applications. Once the flashing is complete, {IDF_TARGET_NAME} will reset. On the next boot, the second stage bootloader encrypts: the second stage bootloader, application partitions and partitions marked as ``encrypted`` then resets. Encrypting in-place can take time, up to a minute for large partitions. After that, the application is decrypted at runtime and executed. -A sample output of the first {IDF_TARGET_NAME} boot after enabling flash encryption is given below: +.. only:: SOC_KEY_MANAGER_SUPPORTED + + A sample output of the first {IDF_TARGET_NAME} boot after enabling flash encryption using a Key Manager-based key is given below: + + .. include:: {IDF_TARGET_PATH_NAME}_log.inc + :start-after: first_boot_enc_km + :end-before: ------ + + A sample output of subsequent {IDF_TARGET_NAME} boot mentions that Flash Encryption is already enabled (ESP-ROM log mentions that the Key Manager-based key is being used): + + .. include:: {IDF_TARGET_PATH_NAME}_log.inc + :start-after: already_en_enc_km + :end-before: ------ + +A sample output of the first {IDF_TARGET_NAME} boot after enabling flash encryption using an eFuse-based key is given below: .. include:: {IDF_TARGET_PATH_NAME}_log.inc :start-after: first_boot_enc :end-before: ------ -A sample output of subsequent {IDF_TARGET_NAME} boots just mentions that flash encryption is already enabled: +A sample output of subsequent {IDF_TARGET_NAME} boot mentions that Flash Encryption is already enabled: .. include:: {IDF_TARGET_PATH_NAME}_log.inc :start-after: already_en_enc @@ -338,7 +469,7 @@ At this stage, if you need to update and re-flash binaries, see :ref:`encrypt-pa Using Host Generated Key """""""""""""""""""""""" -It is possible to pre-generate a flash encryption key on the host computer and burn it into the eFuse. This allows you to pre-encrypt data on the host and flash already encrypted data without needing a plaintext flash update. This feature can be used in both :ref:`flash-enc-development-mode` and :ref:`flash-enc-release-mode`. Without a pre-generated key, data is flashed in plaintext and then {IDF_TARGET_NAME} encrypts the data in-place. +It is possible to pre-generate a flash encryption key on the host computer and program it into the device. This allows you to pre-encrypt data on the host and flash already encrypted data without needing a plaintext flash update. This feature can be used in both :ref:`flash-enc-development-mode` and :ref:`flash-enc-release-mode`. Without a pre-generated key, data is flashed in plaintext and then {IDF_TARGET_NAME} encrypts the data in-place. .. note:: @@ -350,7 +481,7 @@ It is possible to pre-generate a flash encryption key on the host computer and b Note that {IDF_TARGET_NAME} only has one eFuse key block for both Secure Boot and Flash Encryption keys. Therefore, writing the host-generated Flash Encryption key must be done with Secure Boot key (if used), otherwise Secure Boot cannot be used. -To use a host generated key, take the following steps: +To use a host generated key and program it into the eFuses of the device, take the following steps: 1. Ensure that you have an {IDF_TARGET_NAME} device with default flash encryption eFuse settings as shown in :ref:`flash-encryption-efuse`. @@ -421,13 +552,13 @@ To use a host generated key, take the following steps: idf.py --port PORT efuse-burn-key BLOCK my_flash_encryption_key.bin XTS_AES_128_KEY - For AES-256 (512-bit key) - ``XTS_AES_256_KEY_1`` and ``XTS_AES_256_KEY_2``. ``idf.py`` supports burning both these two key purposes together with a 512 bit key to two separate key blocks via the virtual key purpose ``XTS_AES_256_KEY``. When this is used ``idf.py`` will burn the first 256 bit of the key to the specified ``BLOCK`` and burn the corresponding block key purpose to ``XTS_AES_256_KEY_1``. The last 256 bit of the key will be burned to the first free key block after ``BLOCK`` and the corresponding block key purpose to ``XTS_AES_256_KEY_2`` + For AES-256 (512-bit key) - ``XTS_AES_256_KEY_1`` and ``XTS_AES_256_KEY_2``. ``idf.py`` supports burning both these two key purposes together with a 512 bit key to two separate key blocks via the virtual key purpose ``XTS_AES_256_KEY``. When this is used ``idf.py`` will burn the first 256 bits of the key to the specified ``BLOCK`` and burn the corresponding block key purpose to ``XTS_AES_256_KEY_1``. The last 256 bits of the key will be burned to the first free key block after ``BLOCK`` and the corresponding block key purpose to ``XTS_AES_256_KEY_2`` .. code-block:: bash idf.py --port PORT efuse-burn-key BLOCK my_flash_encryption_key.bin XTS_AES_256_KEY - If you wish to specify exactly which two blocks are used then it is possible to divide key into two 256 bit keys, and manually burn each half with ``XTS_AES_256_KEY_1`` and ``XTS_AES_256_KEY_2`` as key purposes: + If you wish to specify exactly which two blocks are used then it is possible to divide key into two 256-bit keys, and manually burn each half with ``XTS_AES_256_KEY_1`` and ``XTS_AES_256_KEY_2`` as key purposes: .. code-block:: bash @@ -469,12 +600,12 @@ To use a host generated key, take the following steps: 4. In :ref:`project-configuration-menu`, do the following: - - :ref:`Enable flash encryption on boot ` - - :ref:`Select encryption mode ` (**Development mode** by default) - - :ref:`Select the appropriate bootloader log verbosity ` - - Save the configuration and exit. + - :ref:`Enable flash encryption on boot ` + - :ref:`Select encryption mode ` (**development mode** by default) + - :ref:`Select the appropriate bootloader log verbosity ` + - Save the configuration and exit. -Enabling flash encryption will increase the size of bootloader, which might require updating partition table offset. See :ref:`bootloader-size`. + Enabling flash encryption will increase the size of bootloader, which might require updating partition table offset. See :ref:`bootloader-size`. 5. Run the command given below to build and flash the complete images. @@ -488,9 +619,75 @@ Enabling flash encryption will increase the size of bootloader, which might requ This command will write to flash memory unencrypted images: the second stage bootloader, the partition table and applications. Once the flashing is complete, {IDF_TARGET_NAME} will reset. On the next boot, the second stage bootloader encrypts: the second stage bootloader, application partitions and partitions marked as ``encrypted`` then resets. Encrypting in-place can take time, up to a minute for large partitions. After that, the application is decrypted at runtime and executed. -If using Development Mode, then the easiest way to update and re-flash binaries is :ref:`encrypt-partitions`. +.. only:: SOC_KEY_MANAGER_SUPPORTED -If using Release Mode, then it is possible to pre-encrypt the binaries on the host and then flash them as ciphertext. See :ref:`manual-encryption`. + To use a host generated key and deploy it into the device's Key Manager of the device, take the following steps: + + 1. Ensure that you have an {IDF_TARGET_NAME} device with default flash encryption eFuse settings as shown in :ref:`flash-encryption-efuse`. + + See how to check :ref:`flash-encryption-status`. + + 2. Generate a random key by running: + + .. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256 + + If :ref:`Size of generated XTS-AES key ` is AES-128 (256-bit key): + + .. code-block:: bash + + idf.py secure-generate-flash-encryption-key my_flash_encryption_key.bin + + else if :ref:`Size of generated XTS-AES key ` is AES-256 (512-bit key): + + .. code-block:: bash + + idf.py secure-generate-flash-encryption-key --keylen 512 my_flash_encryption_key.bin + + + .. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK + + .. code-block:: bash + + idf.py secure-generate-flash-encryption-key my_flash_encryption_key.bin + + + 3. **Before the first encrypted boot**, deploy the key into your device's Key Manager via its AES-deploy mode, using an init key and an auxiliary key. + + 4. The deployment process will generate key recovery information for the deployed key. Store the information at the flash address 0x0 using the following command: + + .. code-block:: bash + + esptool --port PORT --baud BAUD write-flash 0x0 key_recovery_info.bin + + If the key is not deployed and the device is started after enabling Flash Encryption, the {IDF_TARGET_NAME} will generate and deploy a random key that software cannot access or modify. + + .. note:: + + This command does not include any user files which should be written to the partitions on the flash memory. Please write them manually before running this command. Otherwise, the files should be encrypted separately before writing. + + 5. In :ref:`project-configuration-menu`, do the following: + + - :ref:`Enable Flash Encryption on boot ` + - :ref:`Select encryption mode ` (**development mode** by default) + - :ref:`Select Flash Encryption key source as the Key Manager ` + - :ref:`Select the appropriate bootloader log verbosity ` + - Save the configuration and exit. + + Enabling flash encryption will increase the size of bootloader, which might require updating partition table offset. See :ref:`bootloader-size`. + + 6. Run the command given below to build and flash the complete images. + + .. code-block:: bash + + idf.py flash monitor + + .. note:: + + This command does not include any user files which should be written to the partitions on the flash memory. Please write them manually before running this command. Otherwise, the files should be encrypted separately before writing. + +If using development mode, then the easiest way to update and re-flash binaries is :ref:`encrypt-partitions`. + +If using release mode, then it is possible to pre-encrypt the binaries on the host and then flash them as ciphertext. See :ref:`manual-encryption`. .. _encrypt-partitions: @@ -504,7 +701,7 @@ If you update your application code (done in plaintext) and want to re-flash it, idf.py encrypted-app-flash monitor -If all partitions needs to be updated in encrypted format, run: +If all partitions need to be updated in encrypted format, run: .. code-block:: bash @@ -519,7 +716,7 @@ If all partitions needs to be updated in encrypted format, run: Release Mode ^^^^^^^^^^^^ -In Release mode, UART bootloader cannot perform flash encryption operations. New plaintext images can ONLY be downloaded using the over-the-air (OTA) scheme which will encrypt the plaintext image before writing to flash. +In release mode, UART bootloader cannot perform flash encryption operations. New plaintext images can ONLY be downloaded using the over-the-air (OTA) scheme which will encrypt the plaintext image before writing to flash. To use this mode, take the following steps: @@ -531,16 +728,16 @@ To use this mode, take the following steps: .. list:: - - :ref:`Enable flash encryption on boot `. - :esp32: - :ref:`Select Release mode `. (Note that once Release mode is selected, the ``DISABLE_DL_ENCRYPT`` and ``DISABLE_DL_DECRYPT`` eFuse bits will be burned to disable flash encryption hardware in ROM Download Mode.) + - :ref:`Enable Flash Encryption on boot `. + :esp32: - :ref:`Select release mode `. (Note that once release mode is selected, the ``DISABLE_DL_ENCRYPT`` and ``DISABLE_DL_DECRYPT`` eFuse bits will be burned to disable flash encryption hardware in ROM Download Mode.) :esp32: - :ref:`Select UART ROM download mode (Permanently disabled (recommended)) ` (Note that this option is only available when :ref:`CONFIG_ESP32_REV_MIN` is set to 3 (ESP32 V3).) The default choice is to keep UART ROM download mode enabled, however it is recommended to permanently disable this mode to reduce the options available to an attacker. - :not esp32: - :ref:`Select Release mode `. (Note that once Release mode is selected, the ``EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT`` eFuse bit will be burned to disable flash encryption hardware in ROM Download Mode.) + :not esp32: - :ref:`Select release mode `. (Note that once release mode is selected, the ``EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT`` eFuse bit will be burned to disable flash encryption hardware in ROM Download Mode.) :not esp32: - :ref:`Select UART ROM download mode (Permanently switch to Secure mode (recommended)) `. This is the default option, and is recommended. It is also possible to change this configuration setting to permanently disable UART ROM download mode, if this mode is not needed. :SOC_FLASH_ENCRYPTION_XTS_AES_SUPPORT_PSEUDO_ROUND: - :ref:`Select enable XTS-AES's pseudo rounds function `. This option is selected by default and its strength is configured to level low considering the performance impact on the flash encryption/decryption operations. Please refer to :ref:`xts-aes-pseudo-round-func` for more information regarding the performance impact per security level. - :ref:`Select the appropriate bootloader log verbosity `. - Save the configuration and exit. -Enabling flash encryption will increase the size of bootloader, which might require updating partition table offset. See :ref:`bootloader-size`. + Enabling flash encryption will increase the size of bootloader, which might require updating partition table offset. See :ref:`bootloader-size`. 3. Run the command given below to build and flash the complete images. @@ -555,7 +752,7 @@ Enabling flash encryption will increase the size of bootloader, which might requ This command will write to flash memory unencrypted images: the second stage bootloader, the partition table and applications. Once the flashing is complete, {IDF_TARGET_NAME} will reset. On the next boot, the second stage bootloader encrypts: the second stage bootloader, application partitions and partitions marked as ``encrypted`` then resets. Encrypting in-place can take time, up to a minute for large partitions. After that, the application is decrypted at runtime and executed. -Once the flash encryption is enabled in Release mode, the bootloader will write-protect the ``{IDF_TARGET_CRYPT_CNT}`` eFuse. +Once the flash encryption is enabled in release mode, the bootloader will write-protect the ``{IDF_TARGET_CRYPT_CNT}`` eFuse. For subsequent plaintext field updates, use :ref:`OTA scheme `. @@ -574,7 +771,7 @@ When using Flash Encryption in production: - Do not reuse the same flash encryption key between multiple devices. This means that an attacker who copies encrypted data from one device cannot transfer it to a second device. :esp32: - When using ESP32 V3, if the UART ROM Download Mode is not needed for a production device then it should be disabled to provide an extra level of protection. Do this by calling :cpp:func:`esp_efuse_disable_rom_download_mode` during application startup. Alternatively, configure the project :ref:`CONFIG_ESP32_REV_MIN` level to 3 (targeting ESP32 V3 only) and select the :ref:`CONFIG_SECURE_UART_ROM_DL_MODE` to "Permanently disable ROM Download Mode (recommended)". The ability to disable ROM Download Mode is not available on earlier ESP32 versions. - :not esp32: - The UART ROM Download Mode should be disabled entirely if it is not needed, or permanently set to "Secure Download Mode" otherwise. Secure Download Mode permanently limits the available commands to updating SPI config, changing baud rate, basic flash write, and returning a summary of the currently enabled security features with the `get-security-info` command. The default behaviour is to set Secure Download Mode on first boot in Release mode. To disable Download Mode entirely, select :ref:`CONFIG_SECURE_UART_ROM_DL_MODE` to "Permanently disable ROM Download Mode (recommended)" or call :cpp:func:`esp_efuse_disable_rom_download_mode` at runtime. + :not esp32: - The UART ROM Download Mode should be disabled entirely if it is not needed, or permanently set to "Secure Download Mode" otherwise. Secure Download Mode permanently limits the available commands to updating SPI config, changing baud rate, basic flash write, and returning a summary of the currently enabled security features with the `get-security-info` command. The default behaviour is to set Secure Download Mode on first boot in release mode. To disable Download Mode entirely, select :ref:`CONFIG_SECURE_UART_ROM_DL_MODE` to "Permanently disable ROM Download Mode (recommended)" or call :cpp:func:`esp_efuse_disable_rom_download_mode` at runtime. - Enable :doc:`Secure Boot ` as an extra layer of protection, and to prevent an attacker from selectively corrupting any part of the flash before boot. Enable Flash Encryption Externally @@ -589,55 +786,55 @@ Once flash encryption is enabled, the ``{IDF_TARGET_CRYPT_CNT}`` eFuse value wil 1. If the bootloader partition is re-flashed with a **plaintext second stage bootloader image**, the first stage (ROM) bootloader will fail to load the second stage bootloader resulting in the following failure: -.. only:: esp32 + .. only:: esp32 - .. code-block:: bash + .. code-block:: bash - rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - flash read err, 1000 - ets_main.c 371 - ets Jun 8 2016 00:22:57 + rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + flash read err, 1000 + ets_main.c 371 + ets Jun 8 2016 00:22:57 - rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - flash read err, 1000 - ets_main.c 371 - ets Jun 8 2016 00:22:57 + rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + flash read err, 1000 + ets_main.c 371 + ets Jun 8 2016 00:22:57 - rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - flash read err, 1000 - ets_main.c 371 - ets Jun 8 2016 00:22:57 + rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + flash read err, 1000 + ets_main.c 371 + ets Jun 8 2016 00:22:57 - rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - flash read err, 1000 - ets_main.c 371 - ets Jun 8 2016 00:22:57 + rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + flash read err, 1000 + ets_main.c 371 + ets Jun 8 2016 00:22:57 - rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - flash read err, 1000 - ets_main.c 371 - ets Jun 8 2016 00:22:57 + rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + flash read err, 1000 + ets_main.c 371 + ets Jun 8 2016 00:22:57 -.. only:: not esp32 + .. only:: not esp32 - .. code-block:: bash + .. code-block:: bash - rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - invalid header: 0xb414f76b - invalid header: 0xb414f76b - invalid header: 0xb414f76b - invalid header: 0xb414f76b - invalid header: 0xb414f76b - invalid header: 0xb414f76b - invalid header: 0xb414f76b + rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + invalid header: 0xb414f76b + invalid header: 0xb414f76b + invalid header: 0xb414f76b + invalid header: 0xb414f76b + invalid header: 0xb414f76b + invalid header: 0xb414f76b + invalid header: 0xb414f76b - .. note:: + .. note:: - The value of invalid header will be different for every application. + The value of invalid header will be different for every application. -.. note:: + .. note:: - This error also appears if the flash contents are erased or corrupted. + This error also appears if the flash contents are erased or corrupted. 2. If the second stage bootloader is encrypted, but the partition table is re-flashed with a **plaintext partition table image**, the bootloader will fail to read the partition table resulting in the following failure: @@ -700,7 +897,7 @@ Once flash encryption is enabled, the ``{IDF_TARGET_CRYPT_CNT}`` eFuse value wil {IDF_TARGET_NAME} Flash Encryption Status ----------------------------------------- -1. Ensure that you have an {IDF_TARGET_NAME} device with default flash encryption eFuse settings as shown in :ref:`flash-encryption-efuse`. +Ensure that you have an {IDF_TARGET_NAME} device with default flash encryption eFuse settings as shown in :ref:`flash-encryption-efuse`. To check if flash encryption on your {IDF_TARGET_NAME} device is enabled, do one of the following: @@ -758,7 +955,7 @@ It is recommended to use the partition write function :cpp:func:`esp_partition_w You can also pre-encrypt and write data using the function :cpp:func:`esp_flash_write_encrypted` -Also, the following ROM function exist but not supported in esp-idf applications: +Also, the following ROM functions exist but are not supported in ESP-IDF applications: - ``esp_rom_spiflash_write_encrypted`` pre-encrypts and writes data to flash - ``SPIWrite`` writes unencrypted data to flash @@ -790,9 +987,9 @@ Updating Encrypted Flash via Serial Flashing an encrypted device via serial bootloader requires that the serial bootloader download interface has not been permanently disabled via eFuse. -In Development Mode, the recommended method is :ref:`encrypt-partitions`. +In development mode, the recommended method is :ref:`encrypt-partitions`. -In Release Mode, if a copy of the same key stored in eFuse is available on the host then it is possible to pre-encrypt files on the host and then flash them. See :ref:`manual-encryption`. +In release mode, if a copy of the same key stored in eFuse is available on the host then it is possible to pre-encrypt files on the host and then flash them. See :ref:`manual-encryption`. Disabling Flash Encryption -------------------------- @@ -801,11 +998,11 @@ If flash encryption was enabled accidentally, flashing of plaintext data will so .. only:: esp32 - For flash encryption in Development mode, encryption can be disabled by burning the ``{IDF_TARGET_CRYPT_CNT}`` eFuse. It can only be done three times per chip by taking the following steps: + For flash encryption in development mode, encryption can be disabled by burning the ``{IDF_TARGET_CRYPT_CNT}`` eFuse. It can only be done three times per chip by taking the following steps: .. only:: not esp32 - For flash encryption in Development mode, encryption can be disabled by burning the ``{IDF_TARGET_CRYPT_CNT}`` eFuse. It can only be done one time per chip by taking the following steps: + For flash encryption in development mode, encryption can be disabled by burning the ``{IDF_TARGET_CRYPT_CNT}`` eFuse. It can only be done one time per chip by taking the following steps: #. In :ref:`project-configuration-menu`, disable :ref:`Enable flash encryption on boot `, then save and exit. #. Open project configuration menu again and **double-check** that you have disabled this option! If this option is left enabled, the bootloader will immediately re-enable encryption when it boots. @@ -828,7 +1025,9 @@ Key Points About Flash Encryption :esp32: - The flash encryption algorithm is AES-256, where the key is "tweaked" with the offset address of each 32 byte block of flash. This means that every 32-byte block (two consecutive 16 byte AES blocks) is encrypted with a unique key derived from the flash encryption key. - :SOC_FLASH_ENCRYPTION_XTS_AES_256: - Flash memory contents is encrypted using XTS-AES-128 or XTS-AES-256. The flash encryption key is 256 bits and 512 bits respectively and stored in one or two ``BLOCK_KEYN`` eFuses internal to the chip and, by default, is protected from software access. + :SOC_FLASH_ENCRYPTION_XTS_AES_256 and SOC_KEY_MANAGER_SUPPORTED: - Flash memory contents are encrypted using XTS-AES-128 or XTS-AES-256. The flash encryption key is 256 bits and 512 bits respectively and stored in one or two ``BLOCK_KEYN`` eFuses internal to the chip and, by default, is protected from software access. + + :SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_KEY_MANAGER_SUPPORTED: - Flash memory contents are encrypted using XTS-AES-128 or XTS-AES-256, with respective key sizes of 256 or 512 bits. If using an eFuse-based key, the key is stored in one or two internal ``BLOCK_KEYN`` eFuses. However, if using a Key Manager-based key, the key is stored within the Key Manager itself. In either case, the key is protected from software access by default. :SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_FLASH_ENCRYPTION_XTS_AES_128_DERIVED: - Flash memory contents is encrypted using XTS-AES-128. The flash encryption key is 256 bits and stored in one ``BLOCK_KEYN`` eFuse internal to the chip and, by default, is protected from software access. @@ -844,9 +1043,9 @@ Key Points About Flash Encryption Enabling flash encryption will increase the size of bootloader, which might require updating partition table offset. See :ref:`bootloader-size`. - .. important:: +.. important:: - Do not interrupt power to the {IDF_TARGET_NAME} while the first boot encryption pass is running. If power is interrupted, the flash contents will be corrupted and will require flashing with unencrypted data again. In this case, re-flashing will not count towards the flashing limit. + Do not interrupt power to the {IDF_TARGET_NAME} while the first boot encryption pass is running. If power is interrupted, the flash contents will be corrupted and will require flashing with unencrypted data again. In this case, re-flashing will not count towards the flashing limit. .. _flash-encryption-limitations: @@ -993,7 +1192,7 @@ However, before the first boot you can choose to keep any of these features enab JTAG Debugging ^^^^^^^^^^^^^^ -By default, when Flash Encryption is enabled (in either Development or Release mode) then JTAG debugging is disabled via eFuse. The bootloader does this on first boot, at the same time it enables flash encryption. +By default, when Flash Encryption is enabled (in either development or release mode) then JTAG debugging is disabled via eFuse. The bootloader does this on first boot, at the same time it enables flash encryption. See :ref:`jtag-debugging-security-features` for more information about using JTAG Debugging with Flash Encryption. @@ -1003,7 +1202,13 @@ See :ref:`jtag-debugging-security-features` for more information about using JTA Manually Encrypting Files ^^^^^^^^^^^^^^^^^^^^^^^^^ -Manually encrypting or decrypting files requires the flash encryption key to be pre-burned in eFuse (see :ref:`pregenerated-flash-encryption-key`) and a copy to be kept on the host. If the flash encryption is configured in Development Mode then it is not necessary to keep a copy of the key or follow these steps, the simpler :ref:`encrypt-partitions` steps can be used. +.. only:: SOC_KEY_MANAGER_SUPPORTED + + Manually encrypting or decrypting files require the flash encryption key to be deployed in the Key Manager or pre-burned in eFuses (see :ref:`pregenerated-flash-encryption-key`) and a copy to be kept on the host. If the flash encryption is configured in development mode, then it is not necessary to keep a copy of the key or follow these steps. The simpler :ref:`encrypt-partitions` steps can be used. + +.. only:: not SOC_KEY_MANAGER_SUPPORTED + + Manually encrypting or decrypting files require the flash encryption key to be pre-burned in eFuse (see :ref:`pregenerated-flash-encryption-key`) and a copy to be kept on the host. If the flash encryption is configured in development mode, then it is not necessary to keep a copy of the key or follow these steps. The simpler :ref:`encrypt-partitions` steps can be used. The key file should be a single raw binary file (example: ``key.bin``). @@ -1025,11 +1230,11 @@ The file ``my-app-ciphertext.bin`` can then be flashed to offset 0x10000 using ` .. note:: - If the flashed ciphertext file is not recognized by the {IDF_TARGET_NAME} when it boots, check that the keys match and that the command line arguments match exactly, including the correct offset. + If the flashed ciphertext file is not recognized by the {IDF_TARGET_NAME} when it boots, check that the keys match and that the command line arguments match exactly, including the correct offset. - .. only:: esp32 + .. only:: esp32 - If your ESP32 uses non-default :ref:`FLASH_CRYPT_CONFIG value in eFuse ` then you will need to pass the ``--flash-crypt-conf`` argument to ``idf.py`` command to set the matching value. This will not happen if the device configured flash encryption by itself, but may happen if burning eFuses manually to enable flash encryption. + If your ESP32 uses non-default :ref:`FLASH_CRYPT_CONFIG value in eFuse ` then you will need to pass the ``--flash-crypt-conf`` argument to ``idf.py`` command to set the matching value. This will not happen if the device configured flash encryption by itself, but may happen if burning eFuses manually to enable flash encryption. The command ``idf.py decrypt-flash-data`` can be used with the same options (and different input/output files), to decrypt ciphertext flash contents or a previously encrypted file. @@ -1089,13 +1294,13 @@ The following sections provide some reference information about the operation of Flash Encryption Algorithm ^^^^^^^^^^^^^^^^^^^^^^^^^^ - - {IDF_TARGET_NAME} use the XTS-AES block cipher mode with 256 bit or 512 bit key size for flash encryption. + - {IDF_TARGET_NAME} use the XTS-AES block cipher mode with 256-bit or 512-bit key size for flash encryption. - XTS-AES is a block cipher mode specifically designed for disc encryption and addresses the weaknesses other potential modes (e.g., AES-CTR) have for this use case. A detailed description of the XTS-AES algorithm can be found in `IEEE Std 1619-2007 `_. - The flash encryption key is stored in one or two ``BLOCK_KEYN`` eFuses and, by default, is protected from further writes or software readout. - - To see the full flash encryption algorithm implemented in Python, refer to the `_flash_encryption_operation()` function in the ``espsecure`` source code. + - To see the full flash encryption algorithm implemented in Python, refer to the ``_flash_encryption_operation()`` function in the ``espsecure`` source code. .. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK @@ -1105,7 +1310,7 @@ The following sections provide some reference information about the operation of Flash Encryption Algorithm ^^^^^^^^^^^^^^^^^^^^^^^^^^ - - {IDF_TARGET_NAME} use the XTS-AES block cipher mode with 256 bit size for flash encryption. + - {IDF_TARGET_NAME} use the XTS-AES block cipher mode with 256-bit size for flash encryption. - XTS-AES is a block cipher mode specifically designed for disc encryption and addresses the weaknesses other potential modes (e.g., AES-CTR) have for this use case. A detailed description of the XTS-AES algorithm can be found in `IEEE Std 1619-2007 `_. @@ -1120,7 +1325,7 @@ The following sections provide some reference information about the operation of Flash Encryption Algorithm ^^^^^^^^^^^^^^^^^^^^^^^^^^ - - {IDF_TARGET_NAME} use the XTS-AES block cipher mode with 256 bit size for flash encryption. In case the 128-bit key is stored in the eFuse key block, the final 256-bit AES key is obtained as SHA256(EFUSE_KEY0_FE_128BIT). + - {IDF_TARGET_NAME} use the XTS-AES block cipher mode with 256-bit size for flash encryption. In case the 128-bit key is stored in the eFuse key block, the final 256-bit AES key is obtained as SHA256(EFUSE_KEY0_FE_128BIT). - XTS-AES is a block cipher mode specifically designed for disc encryption and addresses the weaknesses other potential modes (e.g., AES-CTR) have for this use case. A detailed description of the XTS-AES algorithm can be found in `IEEE Std 1619-2007 `_. diff --git a/docs/en/security/security-features-enablement-workflows.rst b/docs/en/security/security-features-enablement-workflows.rst index 82b2710e59c..b1d87e244d1 100644 --- a/docs/en/security/security-features-enablement-workflows.rst +++ b/docs/en/security/security-features-enablement-workflows.rst @@ -61,19 +61,19 @@ Enable Flash Encryption and Secure Boot v2 Externally It is recommended to enable both Flash Encryption and Secure Boot v2 for a production use case. -When enabling the Flash Encryption and Secure Boot v2 together, they need to enable them in the following order: +When enabling the Flash Encryption and Secure Boot v2 together, they must be enabled in the following order: #. Enable the Flash Encryption feature by following the steps listed in :ref:`enable-flash-encryption-externally`. #. Enable the Secure Boot v2 feature by following the steps listed in :ref:`enable-secure-boot-v2-externally`. -The reason this particular ordering is that when enabling Secure Boot (SB) v2, it is necessary to keep the SB v2 key readable. To protect the key's readability, the write protection for ``RD_DIS`` (``ESP_EFUSE_WR_DIS_RD_DIS``) is applied. However, this action poses a challenge when attempting to enable Flash Encryption, as the Flash Encryption (FE) key needs to remain unreadable. This conflict arises because the ``RD_DIS`` is already write-protected, making it impossible to read protect the FE key. +The reason for this particular ordering is that when enabling Secure Boot (SB) v2, it is necessary to keep the SB v2 key readable. To protect the key's readability, the write protection for ``RD_DIS`` (``ESP_EFUSE_WR_DIS_RD_DIS``) is applied. However, this action poses a challenge when attempting to enable Flash Encryption, as the Flash Encryption (FE) key needs to remain unreadable. This conflict arises because the ``RD_DIS`` is already write-protected, making it impossible to read protect the FE key. .. _enable-flash-encryption-externally: Enable Flash Encryption Externally ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -In this case all the eFuses related to Flash Encryption are written with help of the espefuse tool. More details about Flash Encryption can process can be found in :doc:`/security/flash-encryption`. +In this case, all the eFuses related to Flash Encryption are written with help of the espefuse tool. More details about Flash Encryption process can be found in :doc:`/security/flash-encryption`. 1. Ensure that you have an {IDF_TARGET_NAME} device with default Flash Encryption eFuse settings as shown in :ref:`flash-encryption-efuse` @@ -130,14 +130,52 @@ In this case all the eFuses related to Flash Encryption are written with help of espsecure generate-flash-encryption-key --keylen 128 my_flash_encryption_key.bin -3. Burn the Flash Encryption key into eFuse +3. Program the generated Flash Encryption key into the device + + .. only:: SOC_KEY_MANAGER_SUPPORTED + + a. If you intend to use the Key Manager to store the Flash Encryption key, generate the Key Recovery Information for the Flash Encryption key and store it in the flash memory at the address 0x0 using the command: + + .. code-block:: bash + + esptool --port PORT write-flash 0x0 key_recovery_info.bin + + After storing the Key Recovery Information in flash memory, you also need to program the ``KM_XTS_KEY_LENGTH_256`` and the ``FORCE_USE_KEY_MANAGER_KEY`` eFuses. + + .. warning:: + + This action **cannot be reverted**. + + Bit 1 of the ``FORCE_USE_KEY_MANAGER_KEY`` eFuse is used to force using a Key Manager-based XTS-AES key. Once this eFuse is burned, eFuse-based Flash Encryption keys can no longer be used; the device will exclusively use the Key Manager for Flash Encryption key management. + + .. code-block:: bash + + espefuse --port PORT burn-efuse FORCE_USE_KEY_MANAGER_KEY 2 + + The ``KM_XTS_KEY_LENGTH_256`` eFuse controls the length of the Key-Manager based XTS-AES key. Set this eFuse to 1 to use a 128-bit key, and to 0 to use a 256-bit key. + + To use a 128-bit key, set the ``KM_XTS_KEY_LENGTH_256`` eFuse to 1. + + .. code-block:: bash + + espefuse --port PORT burn-efuse KM_XTS_KEY_LENGTH_256 1 + + Otherwise, to use a 256-bit key, set the ``KM_XTS_KEY_LENGTH_256`` eFuse to 0. + + .. code-block:: bash + + espefuse --port PORT burn-efuse KM_XTS_KEY_LENGTH_256 0 + + b. To store the Flash Encryption key in the eFuses, run the following commands: + + .. only:: not SOC_KEY_MANAGER_SUPPORTED + + To store the Flash Encryption key in the eFuses, run the following commands: .. warning:: This action **cannot be reverted**. - It can be done by running: - .. only:: not SOC_FLASH_ENCRYPTION_XTS_AES .. code-block:: bash @@ -183,13 +221,13 @@ In this case all the eFuses related to Flash Encryption are written with help of .. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK - For AES-128 (256-bit key) - ``XTS_AES_128_KEY`` (the ``XTS_KEY_LENGTH_256`` eFuse will be burn to 1): + For AES-128 (256-bit key) - ``XTS_AES_128_KEY`` (the ``XTS_KEY_LENGTH_256`` eFuse will be burned to 1): .. code-block:: bash espefuse --port PORT burn-key BLOCK_KEY0 flash_encryption_key256.bin XTS_AES_128_KEY - For AES-128 key derived from SHA256(128 eFuse bits) - ``XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS``. The FE key will be written in the lower part of eFuse BLOCK_KEY0. The upper 128 bits are not used and will remain available for reading by software. Using the special mode of the espefuse tool, shown in the ``For burning both keys together`` section below, the user can write their data to it using any espefuse commands. + For AES-128 key derived from SHA256 (128 eFuse bits) - ``XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS``. The FE key will be written in the lower part of eFuse BLOCK_KEY0. The upper 128 bits are not used and will remain available for reading by software. Using the special mode of the espefuse tool, shown in the ``For burning both keys together`` section below, the user can write their data to it using any espefuse commands. .. code-block:: bash @@ -244,7 +282,7 @@ In this case all the eFuses related to Flash Encryption are written with help of :SOC_EFUSE_DIS_DOWNLOAD_ICACHE: - ``DIS_DOWNLOAD_ICACHE``: Disable UART cache :SOC_EFUSE_DIS_DOWNLOAD_DCACHE: - ``DIS_DOWNLOAD_DCACHE``: Disable UART cache :SOC_EFUSE_HARD_DIS_JTAG: - ``HARD_DIS_JTAG``: Hard disable JTAG peripheral - :SOC_EFUSE_DIS_DIRECT_BOOT:- ``DIS_DIRECT_BOOT``: Disable direct boot (legacy SPI boot mode) + :SOC_EFUSE_DIS_DIRECT_BOOT: - ``DIS_DIRECT_BOOT``: Disable direct boot (legacy SPI boot mode) :SOC_EFUSE_DIS_LEGACY_SPI_BOOT: - ``DIS_LEGACY_SPI_BOOT``: Disable legacy SPI boot mode :SOC_EFUSE_DIS_USB_JTAG: - ``DIS_USB_JTAG``: Disable USB switch to JTAG :SOC_EFUSE_DIS_PAD_JTAG: - ``DIS_PAD_JTAG``: Disable JTAG permanently @@ -266,7 +304,7 @@ In this case all the eFuses related to Flash Encryption are written with help of B) Write protect security eFuses - After burning the respective eFuses we need to write_protect the security configurations. It can be done by burning following eFuse: + After burning the respective eFuses we need to write-protect the security configurations. It can be done by burning following eFuse: .. code:: bash @@ -499,12 +537,12 @@ In this workflow we shall use ``espsecure`` tool to generate signing keys and us :SOC_EFUSE_DIS_BOOT_REMAP: - ``DIS_BOOT_REMAP``: Disable capability to remap ROM to RAM address space. :SOC_EFUSE_HARD_DIS_JTAG: - ``HARD_DIS_JTAG``: Hard disable JTAG peripheral. :SOC_EFUSE_SOFT_DIS_JTAG: - ``SOFT_DIS_JTAG``: Disable software access to JTAG peripheral. - :SOC_EFUSE_DIS_DIRECT_BOOT:- ``DIS_DIRECT_BOOT``: Disable direct boot (legacy SPI boot mode). + :SOC_EFUSE_DIS_DIRECT_BOOT: - ``DIS_DIRECT_BOOT``: Disable direct boot (legacy SPI boot mode). :SOC_EFUSE_DIS_LEGACY_SPI_BOOT: - ``DIS_LEGACY_SPI_BOOT``: Disable legacy SPI boot mode. :SOC_EFUSE_DIS_USB_JTAG: - ``DIS_USB_JTAG``: Disable USB switch to JTAG. :SOC_EFUSE_DIS_PAD_JTAG: - ``DIS_PAD_JTAG``: Disable JTAG permanently. :SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS: - ``SECURE_BOOT_AGGRESSIVE_REVOKE``: Aggressive revocation of key digests, see :ref:`secure-boot-v2-aggressive-key-revocation` for more details. - :SOC_ECDSA_P192_CURVE_DEFAULT_DISABLED: - ``WR_DIS_ECDSA_CURVE_MODE``: Disable writing to the ECDSA curve mode eFuse bit. As this write protection bit is shared with ``ECC_FORCE_CONST_TIME``, it is recommended to write protect this bit only after configuring the ``ECC_FORCE_CONST_TIME`` eFuse. + :SOC_ECDSA_P192_CURVE_DEFAULT_DISABLED: - ``WR_DIS_ECDSA_CURVE_MODE``: Disable writing to the ECDSA curve mode eFuse bit. As this write protection bit is shared with ``ECC_FORCE_CONST_TIME``, it is recommended to write-protect this bit only after configuring the ``ECC_FORCE_CONST_TIME`` eFuse. :SOC_ECDSA_SUPPORT_CURVE_P384: - ``WR_DIS_SECURE_BOOT_SHA384_EN``: Disable writing to the SHA-384 Secure Boot eFuse bit. As this write protection bit is shared with ``XTS_DPA_PSEUDO_LEVEL`` and ``ECC_FORCE_CONST_TIME``, it is recommended to write protect this bit only after configuring all the other shared eFuses. The respective eFuses can be burned by running: diff --git a/docs/en/security/security.rst b/docs/en/security/security.rst index ca0a890d2db..8070c4b7804 100644 --- a/docs/en/security/security.rst +++ b/docs/en/security/security.rst @@ -11,7 +11,7 @@ This guide provides an overview of the overall security features available in va .. note:: - In this guide, most used commands are in the form of ``idf.py secure-``, which is a wrapper around corresponding ``espsecure ``. The ``idf.py`` based commands provides more user-friendly experience, although may lack some of the advanced functionality of their ``espsecure`` based counterparts. + In this guide, most used commands are in the form of ``idf.py secure-``, which is a wrapper around corresponding ``espsecure ``. The ``idf.py`` based commands provides a more user-friendly experience, although may lack some of the advanced functionality of their ``espsecure`` based counterparts. .. only:: TARGET_SUPPORT_QEMU @@ -70,7 +70,7 @@ Please refer to :doc:`flash-encryption` for detailed information about this feat .. only:: SOC_SPIRAM_SUPPORTED and not esp32 - If {IDF_TARGET_NAME} is connected to an external SPI RAM, the contents written to or read from the SPI RAM will also be encrypted and decrypted respectively (via the MMU's flash cache, provided that FLash Encryption is enabled). This provides an additional safety layer for the data stored in SPI RAM, hence configurations like ``CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC`` can be safely enabled in this case. + If {IDF_TARGET_NAME} is connected to an external SPI RAM, the contents written to or read from the SPI RAM will also be encrypted and decrypted respectively (via the MMU's flash cache, provided that Flash Encryption is enabled). This provides an additional safety layer for the data stored in SPI RAM, hence configurations like ``CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC`` can be safely enabled in this case. Flash Encryption Best Practices ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -101,6 +101,24 @@ Flash Encryption Best Practices Please refer to the :doc:`../api-reference/peripherals/ecdsa` and :doc:`../api-reference/peripherals/ds` guides for detailed documentation. +.. only:: SOC_KEY_MANAGER_SUPPORTED + + Key Manager + ~~~~~~~~~~~ + + The Key Manager peripheral in {IDF_TARGET_NAME} provides hardware-assisted **key deployment and recovery** for cryptographic keys. Keys are cryptographically bound to a Hardware Unique Key (HUK) that is unique to each chip, ensuring that key material is never exposed to software-accessible memory. + + The Key Manager supports key management for the following cryptographic peripherals: :doc:`ECDSA <../api-reference/peripherals/ecdsa>`, :doc:`HMAC <../api-reference/peripherals/hmac>`, :doc:`Digital Signature (DS) <../api-reference/peripherals/ds>`, and Flash Encryption. + + Please refer to :doc:`../api-reference/peripherals/key_manager` for detailed documentation. + + Key Manager Best Practices + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + + * Protect the ``key_recovery_info`` of a Key Manager-deployed key against unauthorized modification or loss. + * Lock Key Manager's security-related eFuses after successful key deployment to prevent re-deployment of a key of the same type. + * Avoid deploying new XTS-AES keys when Flash Encryption is already enabled unless explicitly intended. + .. only:: SOC_MEMPROT_SUPPORTED or SOC_CPU_IDRAM_SPLIT_USING_PMP Memory Protection @@ -124,7 +142,7 @@ Flash Encryption Best Practices DPA (Differential Power Analysis) Protection ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - {IDF_TARGET_NAME} has support for protection mechanisms against the Differential Power Analysis related security attacks. DPA protection dynamically adjusts the clock frequency of the crypto peripherals, thereby blurring the power consumption trajectory during its operation. Based on the configured DPA security level, the clock variation range changes. Please refer to the *{IDF_TARGET_NAME} Technical Reference Manual* [`PDF <{IDF_TARGET_TRM_EN_URL}>`__]. for more details on this topic. + {IDF_TARGET_NAME} has support for protection mechanisms against the Differential Power Analysis related security attacks. DPA protection dynamically adjusts the clock frequency of the crypto peripherals, thereby blurring the power consumption trajectory during its operation. Based on the configured DPA security level, the clock variation range changes. Please refer to the **{IDF_TARGET_NAME} Technical Reference Manual** [`PDF <{IDF_TARGET_TRM_EN_URL}>`__] for more details on this topic. :ref:`CONFIG_ESP_CRYPTO_DPA_PROTECTION_LEVEL` can help to select the DPA level. Higher level means better security, but it can also have an associated performance impact. By default, the lowest DPA level is kept enabled but it can be modified based on the security requirement. @@ -140,7 +158,7 @@ Flash Encryption Best Practices {IDF_TARGET_NAME} incorporates a pseudo-round function in the AES peripheral, thus enabling the peripheral to randomly insert pseudo-rounds before and after the original operation rounds and also generate a pseudo key to perform these dummy operations. These operations do not alter the original result, but they increase the complexity to perform side channel analysis attacks by randomizing the power profile. - :ref:`CONFIG_MBEDTLS_AES_USE_PSEUDO_ROUND_FUNC_STRENGTH` can be used to select the strength of the pseudo-round function. Increasing the strength improves the security provided, but would slow down the encrryption/decryption operations. + :ref:`CONFIG_MBEDTLS_AES_USE_PSEUDO_ROUND_FUNC_STRENGTH` can be used to select the strength of the pseudo-round function. Increasing the strength improves the security provided, but would slow down the encryption/decryption operations. .. list-table:: Performance impact on AES operations per strength level diff --git a/docs/zh_CN/api-reference/peripherals/ds.rst b/docs/zh_CN/api-reference/peripherals/ds.rst index 4036d0b2621..22aa2d288d8 100644 --- a/docs/zh_CN/api-reference/peripherals/ds.rst +++ b/docs/zh_CN/api-reference/peripherals/ds.rst @@ -3,7 +3,13 @@ :link_to_translation:`en:[English]` -数字签名 (DS) 模块利用 RSA 硬件加速器为信息签名。HMAC 作为密钥派生函数,使用 eFuse 作为输入密钥,输出一组加密参数。随后,数字签名模块利用这组预加密的参数,计算出签名。以上过程均在硬件中完成,因此在计算签名时,软件无法获取 RSA 参数的解密密钥,也无法获取 HMAC 密钥派生函数的输入密钥。 +数字签名 (DS) 模块提供基于 RSA 的消息签名硬件加速,并使用预加密参数来计算签名。这些参数通过 HMAC 作为密钥派生函数进行加密,而 HMAC 则以 eFuse 作为输入密钥。 + +.. only:: SOC_KEY_MANAGER_SUPPORTED + + 在 {IDF_TARGET_NAME} 上,数字签名 (DS) 模块也可以使用存储在密钥管理器中的密钥,而非 eFuse 密钥块。AES 加密密钥可以通过密钥管理器直接部署,类型为 :cpp:enumerator:`ESP_KEY_MGR_DS_KEY`。详情请参阅 :ref:`key-manager`。 + +以上过程均在硬件中完成,因此在计算签名时,软件无法获取 RSA 参数的解密密钥,也无法获取 HMAC 密钥派生函数的输入密钥。 签名计算所涉及的硬件信息以及所用寄存器的有关信息,请参阅 **{IDF_TARGET_NAME} 技术参考手册** > **数字签名 (DS)** [`PDF <{IDF_TARGET_TRM_CN_URL}#digsig>`__]。 @@ -112,7 +118,11 @@ TLS 连接所需的 DS 外设配置 此前位于 ``examples/protocols/mqtt/ssl_ds`` 目录下的 SSL 双向认证示例现已随独立的 `espressif/mqtt `__ 组件一同提供。请参照该组件文档获取 SSL DS 示例,并与 ESP-MQTT 一同构建。该示例仍使用 ``mqtt_client`` (由 ESP-MQTT 实现),通过双向认证 TLS 连接至 ``test.mosquitto.org``,其中 TLS 通信层仍由 ESP-TLS 实现。 +.. only:: SOC_KEY_MANAGER_SUPPORTED + + 如果 :cpp:member:`esp_ds_data_ctx_t::efuse_key_id` 和 :cpp:member:`esp_rsa_ds_opaque_key_t::key_recovery_info` 均已设置,ESP-DS PSA 驱动程序将优先使用基于密钥管理器的 DS 密钥,而非基于 eFuse 的 DS 密钥。 + API 参考 -------- -.. include-build-file:: inc/esp_ds.inc +.. include-build-file:: inc/psa_crypto_driver_esp_rsa_ds_contexts.inc diff --git a/docs/zh_CN/api-reference/peripherals/ecdsa.rst b/docs/zh_CN/api-reference/peripherals/ecdsa.rst index 00dabc7c0bc..d1890c0c708 100644 --- a/docs/zh_CN/api-reference/peripherals/ecdsa.rst +++ b/docs/zh_CN/api-reference/peripherals/ecdsa.rst @@ -24,7 +24,13 @@ ECDSA 外设可以为 TLS 双向身份验证等用例建立 **安全设备身份 {IDF_TARGET_NAME} 上的 ECDSA ---------------------------- -在 {IDF_TARGET_NAME} 上,ECDSA 模块使用烧录到 eFuse 块中的密钥。密码模块外的任何资源都不可访问此密钥(默认模式),从而避免密钥泄露。 +在 {IDF_TARGET_NAME} 上,ECDSA 模块使用烧录到 eFuse 块中的密钥。 + +.. only:: SOC_KEY_MANAGER_SUPPORTED + + 在 {IDF_TARGET_NAME} 上,ECDSA 模块也支持将密钥存储在密钥管理器中,详情请参阅 :ref:`key-manager`。 + +密码模块外的任何资源都不可访问此密钥(默认模式),从而避免密钥泄露。 ECDSA 密钥存储 ^^^^^^^^^^^^^^ @@ -53,6 +59,8 @@ ECDSA 密钥存储 ECDSA 密钥可以通过 ``idf.py`` 脚本在外部编程。以下是关于编程 ECDSA 密钥的示例: +使用 eFuse 存储 ECDSA 密钥: + .. code:: bash idf.py efuse-burn-key ECDSA_KEY @@ -70,8 +78,18 @@ ECDSA 密钥可以通过 ``idf.py`` 脚本在外部编程。以下是关于编 六个物理 eFuse 块可作为 ECDSA 模块的密钥:块 4 ~ 块 9。例如,对于块 4(第一个密钥块),参数为 ``BLOCK_KEY0``。 +.. only:: SOC_KEY_MANAGER_SUPPORTED + + 使用密钥管理器存储 ECDSA 密钥: + + ECDSA 私钥可以存储在密钥管理器中,详情请参阅 :ref:`key-manager`。 + + 将 ECDSA 密钥部署到密钥管理器中。对于持久密钥,需将生成的密钥恢复信息存储在 flash 中。 + 另外,ECDSA 密钥也可以通过在目标上运行的应用程序进行编程。 +使用 eFuse 存储 ECDSA 密钥: + 以下代码片段使用 :cpp:func:`esp_efuse_write_key` 将 eFuse 中的物理密钥块 0 的密钥目的设置为 :cpp:enumerator:`esp_efuse_purpose_t::ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY`: .. code-block:: c diff --git a/docs/zh_CN/api-reference/peripherals/hmac.rst b/docs/zh_CN/api-reference/peripherals/hmac.rst index 2c6a6c383e0..f723e1e33eb 100644 --- a/docs/zh_CN/api-reference/peripherals/hmac.rst +++ b/docs/zh_CN/api-reference/peripherals/hmac.rst @@ -26,7 +26,13 @@ {IDF_TARGET_NAME} 上的 HMAC ----------------------------- -在 {IDF_TARGET_NAME} HMAC 模块的 eFuse 中会烧录一个密钥,可将该 eFuse 密钥设置为禁止所有外部资源访问,避免密钥泄露。 +在 {IDF_TARGET_NAME} 上,HMAC 模块会使用烧录到 eFuse 中的密钥。 + +.. only:: SOC_KEY_MANAGER_SUPPORTED + + 在 {IDF_TARGET_NAME} 上,HMAC 模块也支持将密钥存储在密钥管理器中,详情请参阅 :ref:`key-manager`。 + +可将该密钥设置为禁止所有外部资源访问,避免密钥泄露。 此外,在 {IDF_TARGET_NAME} 上的 HMAC 有以下三种应用场景: @@ -142,6 +148,8 @@ HMAC 的第三种应用场景是将其作为密钥,启用软禁用的 JTAG 接 以下为针对特定应用场景的实例代码,可用于设置 eFuse 密钥,并将其用于计算支持软件使用的 HMAC。 +使用 eFuse 存储 HMAC 密钥: + ``esp_efuse_write_key`` 可以设置 eFuse 中的物理密钥块 4,并设置其功能。``ESP_EFUSE_KEY_PURPOSE_HMAC_UP`` (8) 表明,该密钥仅适用于生成支持软件使用的 HMAC。 .. code-block:: c @@ -162,6 +170,8 @@ HMAC 的第三种应用场景是将其作为密钥,启用软禁用的 JTAG 接 接下来可以通过 PSA Crypto API,使用已存储的密钥来计算供软件使用的 HMAC。 +使用基于 eFuse 的 HMAC 密钥: + .. code-block:: c #include "psa/crypto.h" @@ -181,10 +191,9 @@ HMAC 的第三种应用场景是将其作为密钥,启用软禁用的 JTAG 接 psa_set_key_bits(&attributes, 256); psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_HMAC_VOLATILE); - // 创建不透明密钥引用 + // 为基于 eFuse 的密钥创建不透明密钥引用 esp_hmac_opaque_key_t opaque_key = { - .use_km_key = false, - .efuse_block = EFUSE_BLK_KEY4, + .efuse_key_id = HMAC_KEY4, }; // 导入不透明密钥 diff --git a/docs/zh_CN/api-reference/peripherals/index.rst b/docs/zh_CN/api-reference/peripherals/index.rst index 55749a12441..b57c7cfd400 100644 --- a/docs/zh_CN/api-reference/peripherals/index.rst +++ b/docs/zh_CN/api-reference/peripherals/index.rst @@ -9,6 +9,7 @@ :SOC_ADC_SUPPORTED: adc/index :SOC_ANA_CMPR_SUPPORTED: ana_cmpr :SOC_BITSCRAMBLER_SUPPORTED: bitscrambler + :SOC_MIPI_CSI_SUPPORTED: camera_driver :SOC_CLK_TREE_SUPPORTED: clk_tree :SOC_DAC_SUPPORTED: dac :SOC_ECDSA_SUPPORTED: ecdsa @@ -21,10 +22,11 @@ :SOC_I2C_SUPPORTED: i2c :SOC_I2S_SUPPORTED: i2s :SOC_ISP_SUPPORTED: isp + :SOC_JPEG_CODEC_SUPPORTED: jpeg + :SOC_KEY_MANAGER_SUPPORTED: key_manager lcd/index :SOC_GP_LDO_SUPPORTED: ldo_regulator ledc - :SOC_MIPI_CSI_SUPPORTED: camera_driver :SOC_MCPWM_SUPPORTED: mcpwm :SOC_PARLIO_SUPPORTED: parlio/index :SOC_PCNT_SUPPORTED: pcnt @@ -41,7 +43,6 @@ :SOC_SPI_SUPPORT_SLAVE_HD_VER2: spi_slave_hd :SOC_LP_I2S_SUPPORTED: lp_i2s :SOC_LP_VAD_SUPPORTED: vad - :SOC_JPEG_CODEC_SUPPORTED: jpeg :SOC_TEMP_SENSOR_SUPPORTED: temp_sensor :SOC_TOUCH_SENSOR_SUPPORTED: cap_touch_sens :SOC_TWAI_SUPPORTED: twai diff --git a/docs/zh_CN/api-reference/peripherals/key_manager.rst b/docs/zh_CN/api-reference/peripherals/key_manager.rst new file mode 100644 index 00000000000..7623bec4528 --- /dev/null +++ b/docs/zh_CN/api-reference/peripherals/key_manager.rst @@ -0,0 +1,171 @@ +.. _key-manager: + +密钥管理器 +========== + +:link_to_translation:`en:[English]` + +{IDF_TARGET_NAME} 中的密钥管理器外设为加密密钥提供了硬件辅助的 **密钥部署和密钥恢复** 功能,用于配置和使用加密密钥,而无需将明文密钥内容存储在 flash、RAM 或 eFuse 中。 + +密钥管理器适用于需要安全处理常驻加密密钥的应用程序。 + +.. only:: esp32p4 + + .. note:: + + 密钥管理器外设仅支持 ESP32-P4 芯片版本 v3.x (rev >= 3)。 + +.. only:: esp32c5 + + .. note:: + + 密钥管理器外设仅支持 ESP32-C5 芯片版本 >= v1.2。 + +密钥管理器具有以下特性: + +- **设备唯一性** + + 密钥通过每块芯片独有的硬件唯一密钥 (HUK) 进行加密绑定。 + +- **无明文密钥存储** + + 密钥材料不会暴露于软件可访问的内存中。 + +- **灵活的密钥生命周期** + + 密钥可以被部署、恢复或替换为新密钥,无需为每个密钥重新烧录 eFuse。 + +- **抗物理提取** + + 读取 flash 或 eFuse 的内容不会泄露可用的密钥材料。 + +硬件唯一密钥 (HUK) +------------------- + +硬件唯一密钥 (HUK) 是完全由硬件 HUK 外设生成的设备专属密钥,源自 SRAM 物理不可克隆函数 (PUF)。重建 HUK 时,需要用到 HUK 恢复信息,该信息包含在密钥管理器为已部署密钥生成的密钥恢复信息中。有关 HUK 外设的更多信息,请参阅 **《{IDF_TARGET_NAME} 技术参考手册》** > **密钥管理器章节** [`PDF <{IDF_TARGET_TRM_CN_URL}>`__] > **HUK 生成器**。 + +HUK 是所有通过密钥管理器部署的密钥的信任根。 + +密钥部署与恢复 +-------------- + +密钥管理器分为两个不同的阶段运行: + +- **密钥部署** + + 加密密钥在芯片内部生成或被安全导入,并与 HUK 绑定。此步骤通常在生产阶段、首次启动时,或在应用程序运行并生成临时/持久密钥时执行。 + +- **密钥恢复** + + 在后续启动过程中,密钥管理器部署的持久密钥会使用先前生成的密钥恢复信息进行还原,而不会暴露密钥值。 + +在部署过程中,密钥管理器生成 :cpp:type:`esp_key_mgr_key_recovery_info_t` 数据结构。对于持久密钥,应用程序必须将此数据保存在非易失性存储器(例如 flash)中,以便在后续启动时恢复密钥。 + +支持的密钥类型 +-------------- + +密钥管理器可以管理以下密钥类型: + +.. list:: + + :SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY: - ECDSA + :SOC_KEY_MANAGER_FE_KEY_DEPLOY: - flash 加密 (XTS-AES) + :SOC_KEY_MANAGER_HMAC_KEY_DEPLOY: - HMAC + :SOC_KEY_MANAGER_DS_KEY_DEPLOY: - 数字签名外设 + :SOC_KEY_MANAGER_FE_KEY_DEPLOY: - PSRAM 加密 + +每个密钥都与一个 :cpp:type:`esp_key_mgr_key_purpose_t` 相关联,该类型定义了硬件外设如何使用密钥。 + +密钥部署模式 +------------ + +密钥管理器提供多种密钥部署模式,以满足不同的配置和安全需求。 + +随机部署模式 +^^^^^^^^^^^^ + +在此模式下,密钥管理器在内部生成一个随机私钥。 + +- 应用程序软件无法获取密钥值。 +- 不需要外部密钥材料。 +- 适用于不需要备份或导出密钥的场景。 + +AES 部署模式 +^^^^^^^^^^^^ + +在此模式下,可以安全部署用户指定的私钥。 + +- 密钥在传输到芯片之前进行加密。 +- 使用辅助密钥材料保护部署过程。 +- 适用于需要预定义密钥值的出厂配置场景。 + +ECDH0 部署模式 +^^^^^^^^^^^^^^ + +在此模式下,私钥通过椭圆曲线 Diffie-Hellman (ECDH) 协商生成。 + +- 最终私钥不会被传输。 +- 部署过程可以通过不受信任的信道进行。 +- 适用于高安全性的配置环境。 + +有关各种部署模式的详细信息,请参阅 **《{IDF_TARGET_NAME} 技术参考手册》** > **密钥管理器章节** [`PDF <{IDF_TARGET_TRM_EN_URL}>`__] > **密钥管理器小节**。 + +.. ECDH1 Deploy Mode +.. ~~~~~~~~~~~~~~~~~ +.. +.. This mode is similar to ECDH0 Deploy Mode, with additional flexibility for manufacturing workflows. +.. +.. - Supports negotiated key deployment using auxiliary recovery data +.. - Allows updating deployed keys by replacing auxiliary information +.. - Intended for large-scale manufacturing with controlled trust assumptions + +典型工作流程 +------------ + +首次启动或生产配置 +^^^^^^^^^^^^^^^^^^ + +典型的配置流程包括: + +1. 生成硬件唯一密钥 (HUK) +2. 使用恰当的部署模式部署所需的加密密钥 +3. 将生成的 ``key_recovery_info`` 保存至非易失性存储器中 +4. 如有需要,锁定相关安全配置 eFuse + +此过程通常每台设备仅执行一次。 + +正常启动 +^^^^^^^^ + +在正常启动过程中: + +1. 应用程序提供先前由密钥管理器部署的密钥所生成的 ``key_recovery_info`` +2. HUK 由硬件自动重建 +3. 密钥管理器在内部恢复已部署的密钥 +4. 密码外设可以使用已恢复的密钥 + +安全注意事项 +------------ + +使用密钥管理器的应用程序应注意以下事项: + +- 防止密钥管理器部署密钥的 ``key_recovery_info`` 遭受未授权的修改或丢失。 +- 密钥部署成功后,锁定密钥管理器安全相关的 eFuse,防止重新部署同类型密钥。 +- 除非明确需要,否则在已启用 flash 加密时,应避免部署新的 XTS-AES 密钥。 + +API 参考 +-------- + +.. include-build-file:: inc/esp_key_mgr.inc +.. include-build-file:: inc/key_mgr_types.inc + +应用示例 +-------- + +:example:`security/key_manager` 演示了如何使用密钥管理器进行密钥部署,以及如何使用已部署的密钥执行签名操作。 + +该示例展示了如何: + +- 初始化密钥管理器 +- 使用 AES 部署模式部署密钥 +- 使用 PSA 接口通过密钥管理器部署的密钥执行签名操作 diff --git a/docs/zh_CN/security/esp32c5_log.inc b/docs/zh_CN/security/esp32c5_log.inc index 5b9848cc9a2..59e43e76a6d 100644 --- a/docs/zh_CN/security/esp32c5_log.inc +++ b/docs/zh_CN/security/esp32c5_log.inc @@ -66,68 +66,72 @@ ------ +.. first_boot_enc_km + +.. code-block:: none + + ESP-ROM:esp32c5-eco3-20250704 + Build:Jul 4 2025 + rst:0x1 (POWERON),boot:0x18 (SPI_FAST_FLASH_BOOT) + SPI mode:DIO, clock div:1 + load:0x40855820,len:0x3a60 + load:0x4084bba0,len:0xdf4 + load:0x4084e5a0,len:0x566c + entry 0x4084bbaa + I (23) boot: ESP-IDF v6.0-dev-3140-ge16a2fb13ad-dirt 2nd stage bootloader + I (24) boot: compile time Oct 27 2025 15:35:09 + I (67) boot: chip revision: v1.1 + I (70) boot: efuse block revision: v0.3 + I (88) boot.esp32c5: SPI Speed : 80MHz + I (92) boot.esp32c5: SPI Mode : DIO + I (96) boot.esp32c5: SPI Flash Size : 2MB + I (103) boot: Enabling RNG early entropy source... + I (138) boot: Partition Table: + I (141) boot: ## Label Usage Type ST Offset Length + I (154) boot: 0 nvs WiFi data 01 02 0000e000 00006000 + I (168) boot: 1 phy_init RF data 01 01 00014000 00001000 + I (182) boot: 2 factory factory app 00 00 00020000 00100000 + I (189) boot: End of partition table + I (283) esp_image: segment 0: paddr=00020020 vaddr=42070020 size=32f1ch (208668) map + I (377) esp_image: segment 1: paddr=00052f44 vaddr=40800000 size=0a2a4h ( 41636) load + I (445) esp_image: segment 2: paddr=0005d1f0 vaddr=4080a300 size=02ccch ( 11468) load + I (512) esp_image: segment 3: paddr=0005fec4 vaddr=00000000 size=00154h ( 340) + I (580) esp_image: segment 4: paddr=00060020 vaddr=42000020 size=63804h (407556) map + I (761) boot: Loaded app from partition at offset 0x20000 + I (764) boot: Checking flash encryption... + I (788) efuse: Batch mode of writing fields is enabled + I (807) flash_encrypt: Deploying new flash encryption key using Key Manager + W (898) flash_encrypt: Not disabling UART bootloader encryption + I (904) flash_encrypt: Disable UART bootloader cache... + W (917) flash_encrypt: Not disabling JTAG - SECURITY COMPROMISED + I (930) efuse: BURN BLOCK0 + I (935) efuse: BURN BLOCK0 - OK (all write block bits are set) + I (938) efuse: Batch mode. Prepared fields are committed + I (1028) esp_image: segment 0: paddr=00002020 vaddr=40855820 size=03a60h ( 14944) + I (1096) esp_image: segment 1: paddr=00005a88 vaddr=4084bba0 size=00df4h ( 3572) + I (1165) esp_image: segment 2: paddr=00006884 vaddr=4084e5a0 size=0566ch ( 22124) + I (1508) flash_encrypt: bootloader encrypted successfully + I (1535) flash_encrypt: partition table encrypted and loaded successfully + I (1616) esp_image: segment 0: paddr=00020020 vaddr=42070020 size=32f1ch (208668) map + I (1711) esp_image: segment 1: paddr=00052f44 vaddr=40800000 size=0a2a4h ( 41636) + I (1779) esp_image: segment 2: paddr=0005d1f0 vaddr=4080a300 size=02ccch ( 11468) + I (1847) esp_image: segment 3: paddr=0005fec4 vaddr=00000000 size=00154h ( 340) + I (1916) esp_image: segment 4: paddr=00060020 vaddr=42000020 size=63804h (407556) map + I (2096) flash_encrypt: Encrypting partition 2 at offset 0x20000 (length 0xa3850)... + I (5652) flash_encrypt: Done encrypting + I (5667) efuse: BURN BLOCK0 + I (5671) efuse: BURN BLOCK0 - OK (all write block bits are set) + I (5675) flash_encrypt: Flash encryption completed + I (5679) boot: Resetting with flash encryption enabled... + + +------ + + .. already_en_enc .. code-block:: none - rst:0x1 (POWERON),boot:0x3d (SPI_FAST_FLASH_BOOT) - SPI mode:DIO, clock div:2 - load:0x40855c10,len:0x2be8 - load:0x4084c7a0,len:0x6f8 - load:0x4084e9a0,len:0x418c - entry 0x4084c804 - I (32) boot: ESP-IDF v5.3-dev-3860-g5d36288649 2nd stage bootloader - I (33) boot: compile time May 7 2024 17:24:43 - I (34) boot: chip revision: v0.0 - I (37) boot.esp32c5: SPI Speed : 40MHz - I (42) boot.esp32c5: SPI Mode : DIO - I (46) boot.esp32c5: SPI Flash Size : 2MB - I (51) boot: Enabling RNG early entropy source... - I (64) boot: Partition Table: - I (67) boot: ## Label Usage Type ST Offset Length - I (74) boot: 0 nvs WiFi data 01 02 0000e000 00006000 - I (82) boot: 1 storage Unknown data 01 ff 00014000 00001000 - I (89) boot: 2 factory factory app 00 00 00020000 00100000 - I (97) boot: 3 nvs_key NVS keys 01 04 00120000 00001000 - I (104) boot: 4 custom_nvs WiFi data 01 02 00121000 00006000 - I (113) boot: End of partition table - I (116) esp_image: segment 0: paddr=00020020 vaddr=42010020 size=095c4h ( 38340) map - I (169) esp_image: segment 1: paddr=000295ec vaddr=40800000 size=06a2ch ( 27180) load - I (197) esp_image: segment 2: paddr=00030020 vaddr=42000020 size=0f4d4h ( 62676) map - I (256) esp_image: segment 3: paddr=0003f4fc vaddr=40806a2c size=00b78h ( 2936) load - I (261) esp_image: segment 4: paddr=0004007c vaddr=408075b0 size=00d18h ( 3352) load - I (269) boot: Loaded app from partition at offset 0x20000 - I (270) boot: Checking flash encryption... - I (273) efuse: Batch mode of writing fields is enabled - I (278) flash_encrypt: Generating new flash encryption key... - I (295) efuse: Writing EFUSE_BLK_KEY0 with purpose 4 - W (300) flash_encrypt: Not disabling UART bootloader encryption - I (305) flash_encrypt: Disable JTAG... - I (312) efuse: BURN BLOCK4 - I (317) efuse: BURN BLOCK4 - OK (write block == read block) - I (319) efuse: BURN BLOCK0 - I (325) efuse: BURN BLOCK0 - OK (all write block bits are set) - I (330) efuse: Batch mode. Prepared fields are committed - I (335) esp_image: segment 0: paddr=00002020 vaddr=40855c10 size=02be8h ( 11240) - I (353) esp_image: segment 1: paddr=00004c10 vaddr=4084c7a0 size=006f8h ( 1784) - I (356) esp_image: segment 2: paddr=00005310 vaddr=4084e9a0 size=0418ch ( 16780) - I (1131) flash_encrypt: bootloader encrypted successfully - I (1229) flash_encrypt: partition table encrypted and loaded successfully - I (1230) flash_encrypt: Encrypting partition 1 at offset 0x14000 (length 0x1000)... - I (1325) flash_encrypt: Done encrypting - I (1325) esp_image: segment 0: paddr=00020020 vaddr=42010020 size=095c4h ( 38340) map - I (1362) esp_image: segment 1: paddr=000295ec vaddr=40800000 size=06a2ch ( 27180) - I (1389) esp_image: segment 2: paddr=00030020 vaddr=42000020 size=0f4d4h ( 62676) map - I (1448) esp_image: segment 3: paddr=0003f4fc vaddr=40806a2c size=00b78h ( 2936) - I (1453) esp_image: segment 4: paddr=0004007c vaddr=408075b0 size=00d18h ( 3352) - I (1458) flash_encrypt: Encrypting partition 2 at offset 0x20000 (length 0x100000)... - I (24332) flash_encrypt: Done encrypting - I (24332) flash_encrypt: Encrypting partition 3 at offset 0x120000 (length 0x1000)... - I (24422) flash_encrypt: Done encrypting - I (24423) efuse: BURN BLOCK0 - I (24425) efuse: BURN BLOCK0 - OK (all write block bits are set) - I (24427) flash_encrypt: Flash encryption completed - I (24431) boot: Resetting with flash encryption enabled... ESP-ROM:esp32c5-20240329 Build:Mar 29 2024 rst:0x3 (RTC_SW_HPSYS),boot:0x3d (SPI_FAST_FLASH_BOOT) @@ -193,3 +197,79 @@ ------ + + +.. already_en_enc_km + +.. code-block:: none + + ESP-ROM:esp32c5-eco3-20250704 + Build:Jul 4 2025 + rst:0x1 (POWERON),boot:0x18 (SPI_FAST_FLASH_BOOT) + use sector0 for km info + use KM derived key + SPI mode:DIO, clock div:1 + load:0x40855820,len:0x3a94 + load:0x4084bba0,len:0xd84 + load:0x4084e5a0,len:0x5670 + entry 0x4084bbaa + I (27) boot: ESP-IDF v6.0-dev-3139-gb813f413096-dirt 2nd stage bootloader + I (28) boot: compile time Oct 27 2025 18:14:49 + W (39) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1 + W (53) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1 + W (67) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1 + W (80) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1 + W (94) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1 + W (108) MMU: mmu_ll_write_entry mmu_id=0, entry_id=511, mmu_val=0x00000000, target=1 + I (116) boot: chip revision: v1.1 + I (119) boot: efuse block revision: v0.3 + I (137) boot.esp32c5: SPI Speed : 80MHz + I (141) boot.esp32c5: SPI Mode : DIO + I (145) boot.esp32c5: SPI Flash Size : 2MB + I (149) boot: Enabling RNG early entropy source... + W (163) MMU: mmu_ll_write_entry mmu_id=0, entry_id=0, mmu_val=0x00000000, target=1 + I (191) boot: Partition Table: + I (194) boot: ## Label Usage Type ST Offset Length + I (208) boot: 0 nvs WiFi data 01 02 0000e000 00006000 + I (222) boot: 1 phy_init RF data 01 01 00014000 00001000 + I (235) boot: 2 factory factory app 00 00 00020000 00100000 + I (242) boot: End of partition table + I (396) esp_image: segment 0: paddr=00020020 vaddr=42070020 size=32f1ch (208668) map + I (539) esp_image: segment 1: paddr=00052f44 vaddr=40800000 size=0a2a4h ( 41636) load + I (629) esp_image: segment 2: paddr=0005d1f0 vaddr=4080a300 size=02ccch ( 11468) load + I (719) esp_image: segment 3: paddr=0005fec4 vaddr=00000000 size=00154h ( 340) + I (816) esp_image: segment 4: paddr=00060020 vaddr=42000020 size=6378ch (407436) map + I (1114) boot: Loaded app from partition at offset 0x20000 + I (1116) boot: Checking flash encryption... + I (1133) flash_encrypt: flash encryption is enabled (1 plaintext flashes left) + I (1140) boot: Disabling RNG early entropy source... + I (1301) MSPI Timing: Enter flash timing tuning + I (1434) cpu_start: Unicore app + I (1468) cpu_start: GPIO 12 and 11 are used as console UART I/O pins + I (1479) cpu_start: Pro cpu start user code + I (1483) cpu_start: cpu freq: 240000000 Hz + I (1493) app_init: Application information: + I (1496) app_init: Project name: mbedtls_test + I (1501) app_init: App version: qa-test-esp32c61-master-2025070 + I (1507) app_init: Compile time: Oct 27 2025 15:56:18 + I (1512) app_init: ELF file SHA256: c5f7f520c... + I (1517) app_init: ESP-IDF: v6.0-dev-3140-ge16a2fb13ad-dirt + I (1528) efuse_init: Min chip rev: v1.0 + I (1532) efuse_init: Max chip rev: v1.99 + I (1536) efuse_init: Chip rev: v1.1 + I (1669) heap_init: Initializing. RAM available for dynamic allocation: + I (1680) heap_init: At 4080FCB0 len 0004C8F0 (306 KiB): RAM + I (1685) heap_init: At 4085C5A0 len 00002F58 (11 KiB): RAM + I (1695) heap_init: At 50000000 len 00003FE8 (15 KiB): RTCRAM + I (1800) spi_flash: detected chip: generic + I (1804) spi_flash: flash io: dio + W (1807) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header. + W (1833) flash_encrypt: Flash encryption mode is DEVELOPMENT (not secure) + I (1867) sleep_gpio: Configure to isolate all GPIO pins in sleep state + I (1873) sleep_gpio: Enable automatic switching of GPIO sleep configuration + I (1926) main_task: Started on CPU0 + I (1926) main_task: Calling app_main() + I (1936) main_task: Returned from app_main() + + +------ diff --git a/docs/zh_CN/security/esp32p4_log.inc b/docs/zh_CN/security/esp32p4_log.inc index ae977774011..be398ee0d33 100644 --- a/docs/zh_CN/security/esp32p4_log.inc +++ b/docs/zh_CN/security/esp32p4_log.inc @@ -70,6 +70,72 @@ ------ +.. first_boot_enc_km + +.. code-block:: none + + ESP-ROM:esp32p4-eco5-20250430 + Build:Apr 30 2025 + rst:0x17 (CHIP_USB_UART_RESET),boot:0xc (SPI_FAST_FLASH_BOOT) + Core0 Saved PC:0x4fc0130e + Core1 Saved PC:0x4fc05fa4 + SPI mode:DIO, clock div:1 + load:0x4ffb6240,len:0x3870 + load:0x4ffac2c0,len:0x179c + load:0x4ffaefc0,len:0x4ed8 + entry 0x4ffac2ca + I (38) boot: ESP-IDF v6.0-dev-2918-g6629f96afca-dirt 2nd stage bootloader + I (38) boot: compile time Oct 14 2025 08:50:07 + I (39) boot: Multicore bootloader + I (85) boot: chip revision: v3.0 + I (88) boot: efuse block revision: v1.0 + I (106) boot.esp32p4: SPI Speed : 80MHz + I (110) boot.esp32p4: SPI Mode : DIO + I (114) boot.esp32p4: SPI Flash Size : 2MB + I (121) boot: Enabling RNG early entropy source... + I (156) boot: Partition Table: + I (159) boot: ## Label Usage Type ST Offset Length + I (173) boot: 0 factory factory app 00 00 00010000 00150000 + I (187) boot: 1 storage Unknown data 01 81 00160000 00050000 + I (194) boot: End of partition table + I (287) esp_image: segment 0: paddr=00010020 vaddr=40030020 size=0d1e8h ( 53736) map + I (355) esp_image: segment 1: paddr=0001d210 vaddr=30100000 size=00044h ( 68) load + I (423) esp_image: segment 2: paddr=0001d25c vaddr=4ff20000 size=02dbch ( 11708) load + I (491) esp_image: segment 3: paddr=00020020 vaddr=40000020 size=21834h (137268) map + I (567) esp_image: segment 4: paddr=0004185c vaddr=4ff22dbc size=094e8h ( 38120) load + I (635) esp_image: segment 5: paddr=0004ad4c vaddr=4ff2c300 size=044ech ( 17644) load + I (750) boot: Loaded app from partition at offset 0x10000 + I (752) boot: Checking flash encryption... + I (777) efuse: Batch mode of writing fields is enabled + I (796) flash_encrypt: Deploying new flash encryption key using Key Manager + W (933) flash_encrypt: Not disabling UART bootloader encryption + I (939) flash_encrypt: Disable UART bootloader cache... + W (952) flash_encrypt: Not disabling JTAG - SECURITY COMPROMISED + I (965) efuse: BURN BLOCK0 + I (970) efuse: BURN BLOCK0 - OK (write block == read block) + I (973) efuse: Batch mode. Prepared fields are committed + I (1063) esp_image: segment 0: paddr=00002020 vaddr=4ffb6240 size=03870h ( 14448) + I (1132) esp_image: segment 1: paddr=00005898 vaddr=4ffac2c0 size=0179ch ( 6044) + I (1200) esp_image: segment 2: paddr=0000703c vaddr=4ffaefc0 size=04ed8h ( 20184) + I (1725) flash_encrypt: bootloader encrypted successfully + I (1769) flash_encrypt: partition table encrypted and loaded successfully + I (1851) esp_image: segment 0: paddr=00010020 vaddr=40030020 size=0d1e8h ( 53736) map + I (1919) esp_image: segment 1: paddr=0001d210 vaddr=30100000 size=00044h ( 68) + I (1988) esp_image: segment 2: paddr=0001d25c vaddr=4ff20000 size=02dbch ( 11708) + I (2056) esp_image: segment 3: paddr=00020020 vaddr=40000020 size=21834h (137268) map + I (2133) esp_image: segment 4: paddr=0004185c vaddr=4ff22dbc size=094e8h ( 38120) + I (2202) esp_image: segment 5: paddr=0004ad4c vaddr=4ff2c300 size=044ech ( 17644) + I (2315) flash_encrypt: Encrypting partition 0 at offset 0x10000 (length 0x3f260)... + I (4978) flash_encrypt: Done encrypting + I (4992) efuse: BURN BLOCK0 + I (4997) efuse: BURN BLOCK0 - OK (all write block bits are set) + I (5001) flash_encrypt: Flash encryption completed + I (5005) boot: Resetting with flash encryption enabled... + + +------ + + .. already_en_enc .. code-block:: none @@ -152,3 +218,77 @@ I (595) main_task: Returned from app_main() ------ + + +.. already_en_enc_km + +.. code-block:: none + + ESP-ROM:esp32p4-eco5-20250430 + Build:Apr 30 2025 + rst:0x3 (SW_SYS_RESET),boot:0xc (SPI_FAST_FLASH_BOOT) + Core0 Saved PC:0x4ffb0910 + Core1 Saved PC:0x4fc05fa4 + SPI mode:DIO, clock div:1 + load:0x4ffb6240,len:0x3870 + load:0x4ffac2c0,len:0x179c + load:0x4ffaefc0,len:0x4ed8 + entry 0x4ffac2ca + I (37) boot: ESP-IDF v6.0-dev-2918-g6629f96afca-dirt 2nd stage bootloader + I (38) boot: compile time Oct 14 2025 08:50:07 + I (38) boot: Multicore bootloader + I (84) boot: chip revision: v3.0 + I (87) boot: efuse block revision: v1.0 + I (106) boot.esp32p4: SPI Speed : 80MHz + I (110) boot.esp32p4: SPI Mode : DIO + I (113) boot.esp32p4: SPI Flash Size : 2MB + I (121) boot: Enabling RNG early entropy source... + I (155) boot: Partition Table: + I (158) boot: ## Label Usage Type ST Offset Length + I (172) boot: 0 factory factory app 00 00 00010000 00150000 + I (186) boot: 1 storage Unknown data 01 81 00160000 00050000 + I (193) boot: End of partition table + I (287) esp_image: segment 0: paddr=00010020 vaddr=40030020 size=0d1e8h ( 53736) map + I (355) esp_image: segment 1: paddr=0001d210 vaddr=30100000 size=00044h ( 68) load + I (422) esp_image: segment 2: paddr=0001d25c vaddr=4ff20000 size=02dbch ( 11708) load + I (491) esp_image: segment 3: paddr=00020020 vaddr=40000020 size=21834h (137268) map + I (567) esp_image: segment 4: paddr=0004185c vaddr=4ff22dbc size=094e8h ( 38120) load + I (635) esp_image: segment 5: paddr=0004ad4c vaddr=4ff2c300 size=044ech ( 17644) load + I (750) boot: Loaded app from partition at offset 0x10000 + I (752) boot: Checking flash encryption... + I (769) flash_encrypt: flash encryption is enabled (1 plaintext flashes left) + I (776) boot: Disabling RNG early entropy source... + W (847) pmu_pvt: blk_version is less than 2, pvt auto dbias init not supported in efuse. + I (855) cpu_start: Multicore app + I (890) cpu_start: GPIO 38 and 37 are used as console UART I/O pins + I (901) cpu_start: Pro cpu start user code + I (905) cpu_start: cpu freq: 400000000 Hz + I (914) app_init: Application information: + I (918) app_init: Project name: crypto_test + I (922) app_init: App version: qa-test-esp32c61-master-2025070 + I (928) app_init: Compile time: Oct 14 2025 08:50:07 + I (933) app_init: ELF file SHA256: 847005dd4... + I (938) app_init: ESP-IDF: v6.0-dev-2918-g6629f96afca-dirt + I (949) efuse_init: Min chip rev: v3.0 + I (953) efuse_init: Max chip rev: v3.99 + I (957) efuse_init: Chip rev: v3.0 + I (1126) heap_init: Initializing. RAM available for dynamic allocation: + I (1137) heap_init: At 4FF33B20 len 000874A0 (541 KiB): RAM + I (1143) heap_init: At 4FFBAFC0 len 00004BF0 (18 KiB): RAM + I (1153) heap_init: At 50108080 len 00007F80 (31 KiB): RTCRAM + I (1163) heap_init: At 30100044 len 00001FBC (7 KiB): TCM + I (1261) spi_flash: detected chip: gd + I (1264) spi_flash: flash io: dio + W (1267) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header. + W (1293) flash_encrypt: Flash encryption mode is DEVELOPMENT (not secure) + I (1357) main_task: Started on CPU0 + I (1407) main_task: Calling app_main() + I (1407) main_task: Returned from app_main() + + Example to check Flash Encryption status + This is esp32p4 chip with 2 CPU core(s), WiFi, silicon revision v0.0, 2MB external flash + FLASH_CRYPT_CNT eFuse value is 1 + Flash encryption feature is enabled in DEVELOPMENT mode + + +------ diff --git a/docs/zh_CN/security/flash-encryption.rst b/docs/zh_CN/security/flash-encryption.rst index 39a14a2b0c4..0c0c680ae41 100644 --- a/docs/zh_CN/security/flash-encryption.rst +++ b/docs/zh_CN/security/flash-encryption.rst @@ -26,7 +26,7 @@ flash 加密功能用于加密与 {IDF_TARGET_NAME} 搭载使用的片外 flash .. important:: - 对于生产用途,flash 加密仅应在“发布”模式下启用。 + 对于生产用途,flash 加密仅应在量产模式下启用。 .. important:: @@ -52,8 +52,8 @@ flash 加密功能用于加密与 {IDF_TARGET_NAME} 搭载使用的片外 flash .. _flash-encryption-efuse: -相关 eFuses ------------------------------- +相关 eFuse +---------- flash 加密操作由 {IDF_TARGET_NAME} 上的多个 eFuse 控制,具体 eFuse 名称及其描述请参见下表。``espefuse`` 工具和基于 ``idf.py`` 的 eFuse 指令也会使用下表中的 eFuse 名。为了能在 eFuse API 中使用,请在名称前加上 ``ESP_EFUSE_``,如:esp_efuse_read_field_bit (ESP_EFUSE_DISABLE_DL_ENCRYPT)。 @@ -61,7 +61,7 @@ flash 加密操作由 {IDF_TARGET_NAME} 上的多个 eFuse 控制,具体 eFuse .. only:: not SOC_FLASH_ENCRYPTION_XTS_AES - .. list-table:: flash 加密过程中使用的 eFuses + .. list-table:: 用于 flash 加密的 eFuse :widths: 25 40 10 :header-rows: 0 @@ -69,7 +69,7 @@ flash 加密操作由 {IDF_TARGET_NAME} 上的多个 eFuse 控制,具体 eFuse - **描述** - **位深** * - ``CODING_SCHEME`` - - 控制用于产生最终 256 位 AES 密钥的 block1 的实际位数。可能的值:``0`` 代表 256 位,``1`` 代表 192 位,``2`` 代表 128 位。最终的 AES 密钥根据 ``FLASH_CRYPT_CONFIG`` 值得出。 + - 控制用于产生最终 256 位 AES 密钥的 block1 的实际位数。可选值:``0`` 代表 256 位,``1`` 代表 192 位,``2`` 代表 128 位。最终的 AES 密钥根据 ``FLASH_CRYPT_CONFIG`` 值得出。 - 2 * - ``flash_encryption`` (block1) - AES 密钥存储。 @@ -86,16 +86,16 @@ flash 加密操作由 {IDF_TARGET_NAME} 上的多个 eFuse 控制,具体 eFuse * - ``{IDF_TARGET_CRYPT_CNT}`` - 通过 :math:`2^n` 数字来表示 flash 的内容是否已被加密. - * 如果设置了奇数个比特位(例如 ``0b0000001`` 或 ``0b0000111``), 表示 flash 的内容已加密。读取时,内容需要进行透明解密。 - * 如果设置了偶数个比特位(例如 ``0b0000000`` 或 ``0b0000011``), 表示 flash 的内容未被加密 (即明文)。 + * 如果设置了奇数个比特位(例如 ``0b0000001`` 或 ``0b0000111``),表示 flash 的内容已加密。读取时,内容需要进行透明解密。 + * 如果设置了偶数个比特位(例如 ``0b0000000`` 或 ``0b0000011``),表示 flash 的内容未被加密(即明文)。 - 随着每次连续的 flash 未加密(例如烧录一个新的未加密二进制文件)与进行 flash 加密(通过 :ref:`启动时启用 flash 加密功能 ` 选项), ``{IDF_TARGET_CRYPT_CNT}`` 的下一个的最高有效位 (MSB) 会被设置。 + 每次进行未加密的 flash 更新(例如烧录新的未加密二进制文件),并通过 :ref:`启动时启用 flash 加密功能 ` 选项对 flash 进行加密后,``{IDF_TARGET_CRYPT_CNT}`` 的下一个最高有效位 (MSB) 会被置为 1。 - 7 -.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256 +.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256 and SOC_KEY_MANAGER_SUPPORTED - .. list-table:: flash 加密过程中使用的 eFuses + .. list-table:: 用于 flash 加密的 eFuse :widths: 25 40 10 :header-rows: 0 @@ -103,21 +103,49 @@ flash 加密操作由 {IDF_TARGET_NAME} 上的多个 eFuse 控制,具体 eFuse - **描述** - **位深** * - ``BLOCK_KEYN`` - - AES 密钥存储,N 在 0-5 之间。 + - AES 密钥存储,其中 N 在 0~5 之间。使用基于密钥管理器的密钥时,不会使用此 eFuse。 - XTS_AES_128 有一个 256 位密钥块,XTS_AES_256 有两个 256 位密钥块(共 512 位)。 * - ``KEY_PURPOSE_N`` - - 控制 eFuse 块 ``BLOCK_KEYN`` 的目的,其中 N 在 0-5 之间。可能的值:``2`` 代表 ``XTS_AES_256_KEY_1``,``3`` 代表 ``XTS_AES_256_KEY_2``,``4`` 代表 ``XTS_AES_128_KEY``。最终 AES 密钥是基于其中一个或两个目的 eFuses 值推导。有关各种可能的组合,请参阅 *{IDF_TARGET_NAME} 技术参考手册* > *外部内存加密和解密(XTS_AES)* [`PDF <{IDF_TARGET_TRM_CN_URL}#extmemencr>`__]。 + - 控制 eFuse 块 ``BLOCK_KEYN`` 的用途,其中 N 在 0~5 之间。可选值:``2`` 代表 ``XTS_AES_256_KEY_1``;``3`` 代表 ``XTS_AES_256_KEY_2``;``4`` 代表 ``XTS_AES_128_KEY``。最终 AES 密钥通过其中一个或两个用于指定密钥用途的 eFuse 字段值推导得出。有关各种可能的组合,请参阅 **《{IDF_TARGET_NAME} 技术参考手册》** > **片外存储器加密与解密 (XTS_AES)** [`PDF <{IDF_TARGET_TRM_CN_URL}#extmemencr>`__]。若使用基于密钥管理器的密钥启用 flash 加密,则不会使用此 eFuse 字段。 + - 4 + * - ``KM_XTS_KEY_LENGTH_256`` + - 使用基于密钥管理器的密钥启用 flash 加密时,此 eFuse 字段用于控制 XTS-AES 密钥的长度。将此 eFuse 字段设置为 1 表示使用 128 位密钥,设置为 0 表示使用 256 位密钥。若使用基于 eFuse 的密钥启用 flash 加密,则不会使用此 eFuse 字段。 + - 1 + * - ``FORCE_USE_KEY_MANAGER_KEY`` + - 使用基于密钥管理器的密钥启用 flash 加密时,此 eFuse 用于强制密钥管理器使用 XTS-AES 密钥。将此 eFuse 的位 1 置为 1 以使用基于密钥管理器的密钥。若使用基于 eFuse 的密钥启用 flash 加密,则不会使用此 eFuse 字段。 + - 1 + * - ``DIS_DOWNLOAD_MANUAL_ENCRYPT`` + - 设置后,在下载启动模式下禁用 flash 加密。 + - 1 + * - ``{IDF_TARGET_CRYPT_CNT}`` + - 设置 SPI 启动模式后,可启用加密和解密。如果在 eFuse 中设置了一个或三个位,则启用此功能,否则将禁用。 + - 3 + +.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_KEY_MANAGER_SUPPORTED + + .. list-table:: 用于 flash 加密的 eFuse + :widths: 25 40 10 + :header-rows: 0 + + * - **eFuse** + - **描述** + - **位深** + * - ``BLOCK_KEYN`` + - AES 密钥存储,其中 N 在 0~5 之间。 + - XTS_AES_128 有一个 256 位密钥块,XTS_AES_256 有两个 256 位密钥块(共 512 位)。 + * - ``KEY_PURPOSE_N`` + - 控制 eFuse 块 ``BLOCK_KEYN`` 的用途,其中 N 在 0~5 之间。可选值:``2`` 代表 ``XTS_AES_256_KEY_1``;``3`` 代表 ``XTS_AES_256_KEY_2``;``4`` 代表 ``XTS_AES_128_KEY``。最终 AES 密钥通过其中一个或两个用于指定密钥用途的 eFuse 字段值推导得出。有关各种可能的组合,请参阅 **《{IDF_TARGET_NAME} 技术参考手册》** > **片外存储器加密与解密 (XTS_AES)** [`PDF <{IDF_TARGET_TRM_CN_URL}#extmemencr>`__]。 - 4 * - ``DIS_DOWNLOAD_MANUAL_ENCRYPT`` - 设置后,在下载启动模式下禁用 flash 加密。 - 1 * - ``{IDF_TARGET_CRYPT_CNT}`` - - 设置 SPI 启动模式后,可启用加密和解密。如果在 eFuse 中设置了 1 或 3 个比特位,则启用该功能,否则将禁用。 + - 设置 SPI 启动模式后,可启用加密和解密。如果在 eFuse 中设置了一个或三个位,则启用此功能,否则将禁用。 - 3 -.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK +.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK and SOC_KEY_MANAGER_SUPPORTED - .. list-table:: flash 加密过程中使用的 eFuses + .. list-table:: 用于 flash 加密的 eFuse :widths: 25 40 10 :header-rows: 0 @@ -125,21 +153,49 @@ flash 加密操作由 {IDF_TARGET_NAME} 上的多个 eFuse 控制,具体 eFuse - **描述** - **位深** * - ``BLOCK_KEYN`` - - AES 密钥存储,N 在 0-5 之间。 - - 256 位密钥块 + - AES 密钥存储,其中 N 在 0~5 之间。使用基于密钥管理器的密钥时,不会使用此 eFuse。 + - 256 位密钥块。 * - ``KEY_PURPOSE_N`` - - 控制 eFuse 块 ``BLOCK_KEYN`` 的目的,其中 N 在 0 到 5 之间。对于 flash 加密,唯一的有效值是 4,代表 ``XTS_AES_128_KEY``。 + - 控制 eFuse 块 ``BLOCK_KEYN`` 的用途,其中 N 在 0~5 之间。对于 flash 加密,唯一的有效值是 ``4``,代表 ``XTS_AES_128_KEY``。若使用基于密钥管理器的密钥启用 flash 加密,则不会使用此 eFuse 字段。 - 4 + * - ``KM_XTS_KEY_LENGTH_256`` + - 使用基于密钥管理器的密钥启用 flash 加密时,此 eFuse 字段用于控制 XTS-AES 密钥的长度。将此 eFuse 字段设置为 1 表示使用 128 位密钥,设置为 0 表示使用 256 位密钥。若使用基于 eFuse 的密钥启用 flash 加密,则不会使用此 eFuse 字段。 + - 1 + * - ``FORCE_USE_KEY_MANAGER_KEY`` + - 使用基于密钥管理器的密钥启用 flash 加密时,此 eFuse 用于强制密钥管理器使用 XTS-AES 密钥。将此 eFuse 的位 1 置为 1 以使用基于密钥管理器的密钥。若使用基于 eFuse 的密钥启用 flash 加密,则不会使用此 eFuse 字段。 + - 1 * - ``DIS_DOWNLOAD_MANUAL_ENCRYPT`` - - 设置后,则在下载引导模式时禁用 flash 加密。 + - 设置后,在下载启动模式下禁用 flash 加密。 - 1 * - ``{IDF_TARGET_CRYPT_CNT}`` - - 设置 SPI 启动模式后,可启用加密和解密。如果在 eFuse 中设置 1 或 3 个比特位,则启用该功能,否则将禁用。 + - 设置 SPI 启动模式后,可启用加密和解密。如果在 eFuse 中设置了一个或三个位,则启用此功能,否则将禁用。 + - 3 + +.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK and not SOC_KEY_MANAGER_SUPPORTED + + .. list-table:: 用于 flash 加密的 eFuse + :widths: 25 40 10 + :header-rows: 0 + + * - **eFuse** + - **描述** + - **位深** + * - ``BLOCK_KEYN`` + - AES 密钥存储,N 在 0~5 之间。 + - 256 位密钥块 + * - ``KEY_PURPOSE_N`` + - 控制 eFuse 块 ``BLOCK_KEYN`` 的用途,其中 N 在 0~5 之间。对于 flash 加密,唯一的有效值是 ``4``,代表 ``XTS_AES_128_KEY``。 + - 4 + * - ``DIS_DOWNLOAD_MANUAL_ENCRYPT`` + - 设置后,在下载引导模式时禁用 flash 加密。 + - 1 + * - ``{IDF_TARGET_CRYPT_CNT}`` + - 设置 SPI 启动模式后,可启用加密和解密。如果在 eFuse 中设置了一个或三个位,则启用此功能,否则将禁用。 - 3 .. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK - .. list-table:: flash 加密过程中使用的 eFuses + .. list-table:: 用于 flash 加密的 eFuse :widths: 25 40 10 :header-rows: 0 @@ -147,16 +203,16 @@ flash 加密操作由 {IDF_TARGET_NAME} 上的多个 eFuse 控制,具体 eFuse - **描述** - **位深** * - ``XTS_KEY_LENGTH_256`` - - 控制用于得出最终 256 位 AES 密钥的 eFuse 比特的实际数量。可能的值:``1`` 使用 eFuse 块的全部 256 位作为密钥,``0`` 使用 eFuse 块的低 128 位作为密钥(高 128 位保留给安全启动密钥)。对于 128 位选项,最终的 AES 密钥会以 SHA256 (EFUSE_KEY0_FE_128BIT) 的形式得出。 + - 控制用于产生最终 256 位 AES 密钥的 eFuse 位的实际数量。可选值:``1`` 使用 eFuse 块的全部 256 位作为密钥,``0`` 使用 eFuse 块的低 128 位作为密钥(高 128 位保留给安全启动密钥)。对于 128 位选项,最终的 AES 密钥会以 SHA256 (EFUSE_KEY0_FE_128BIT) 的形式得出。 - 1 * - ``BLOCK_KEY0`` - AES 密钥存储 - 256 位或 128 位密钥块 * - ``DIS_DOWNLOAD_MANUAL_ENCRYPT`` - - 设置后,则在下载引导模式时禁用 flash 加密。 + - 设置后,在下载引导模式时禁用 flash 加密。 - 1 * - ``{IDF_TARGET_CRYPT_CNT}`` - - 设置 SPI 启动模式后,可启用加密和解密。如果在 eFuse 中设置 1 或 3 个比特位,则启用该功能,否则将禁用。 + - 设置 SPI 启动模式后,可启用加密和解密。如果在 eFuse 中设置了一个或三个位,则启用此功能,否则将禁用。 - 3 .. note:: @@ -181,11 +237,11 @@ flash 的加密过程 1. 第一次开机复位时,flash 中的所有数据都是未加密的(明文)。一级 (ROM) 引导加载程序加载二级引导加载程序。 - 2. 二级引导加载程序将读取 ``{IDF_TARGET_CRYPT_CNT}`` eFuse 值 (``0b0000000``)。因为该值为 0(偶数位),二级引导加载程序将配置并启用 flash 加密块,同时将 ``FLASH_CRYPT_CONFIG`` eFuse 的值编程为 0xF。关于 flash 加密块的更多信息,请参考 *{IDF_TARGET_NAME} 技术参考手册* > *eFuse 控制器 (eFuse)* > *flash 加密块* [`PDF <{IDF_TARGET_TRM_CN_URL}#efuse>`__]。 + 2. 二级引导加载程序将读取 ``{IDF_TARGET_CRYPT_CNT}`` eFuse 值 (``0b0000000``)。因为该值为 0(偶数位),二级引导加载程序将配置并启用 flash 加密块,同时将 ``FLASH_CRYPT_CONFIG`` eFuse 的值编程为 0xF。关于 flash 加密块的更多信息,请参考 **《{IDF_TARGET_NAME} 技术参考手册》** > **eFuse 控制器 (eFuse)** > **flash 加密块** [`PDF <{IDF_TARGET_TRM_CN_URL}#efuse>`__]。 3. 二级引导加载程序首先检查 eFuse 中是否已经存在有效密钥(例如用 espefuse 工具烧写的密钥),如果存在,则会跳过密钥生成,并将该密钥用于 flash 加密过程。否则,二级引导加载程序会使用 RNG(随机数发生器)模块生成一个 AES-256 位密钥,并将其写入 ``flash_encryption`` eFuse 中。由于已设置了 ``flash_encryption`` eFuse 的读保护位和写保护位,因此无法通过软件访问密钥。flash 加密操作完全在硬件中完成,无法通过软件访问密钥。 - 4. flash 加密块将加密 flash 的内容(二级引导加载程序、应用程序、以及标有 ``加密`` 标志的分区)。就地加密可能会耗些时间(对于大分区最多需要一分钟)。 + 4. flash 加密块会加密 flash 中的内容,包括二级引导加载程序、应用程序、以及带有 ``encrypted`` 标志的分区。就地加密需要一定时间,对于大分区来说最多需要一分钟。 5. 二级引导加载程序将在 ``{IDF_TARGET_CRYPT_CNT}`` (0b0000001) 中设置第一个可用位来对已加密的 flash 内容进行标记。设置奇数个比特位。 @@ -195,15 +251,48 @@ flash 的加密过程 8. 重新启动设备以开始执行加密镜像。二级引导加载程序调用 flash 解密块来解密 flash 内容,然后将解密的内容加载到 IRAM 中。 -.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256 +.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256 and SOC_KEY_MANAGER_SUPPORTED 1. 第一次开机复位时,flash 中的所有数据都是未加密的(明文)。一级 (ROM) 引导加载程序加载二级引导加载程序。 - 2. 二级引导加载程序将读取 ``{IDF_TARGET_CRYPT_CNT}`` eFuse 值 (``0b000``)。因为该值为 0(偶数位),二级引导加载程序将配置并启用 flash 加密块。关于 flash 加密块的更多信息,请参考 *{IDF_TARGET_NAME} 技术参考手册* > *eFuse 控制器 (eFuse)* > *自动加密块* [`PDF <{IDF_TARGET_TRM_CN_URL}#efuse>`__]。 + 2. 二级引导加载程序将读取 ``{IDF_TARGET_CRYPT_CNT}`` eFuse 值 (``0b000``)。因为该值为 0(偶数位),二级引导加载程序将配置并启用 flash 加密块。关于 flash 加密块的更多信息,请参阅 **《{IDF_TARGET_NAME} 技术参考手册》** > **eFuse 控制器 (eFuse)** > **手动加密块** [`PDF <{IDF_TARGET_TRM_CN_URL}#efuse>`__]。 + + 3. 第二阶段引导加载程序会先判断是否已存在可用的密钥,从而决定是否跳过密钥生成步骤: + + - 若使用基于 eFuse 的密钥启用 flash 加密,则检查 eFuse 中是否已存在有效密钥(例如通过 espefuse 工具烧录的密钥)。 + - 若使用基于密钥管理器的密钥启用 flash 加密,则检查 flash 存储器的地址 0x0 和 0x1000 处是否存在有效的密钥恢复信息。 + + 检查通过,则跳过密钥生成过程,直接使用现有密钥进行 flash 加密。 + + 4. 如果使用基于 eFuse 的密钥,二级引导加载程序将使用 RNG(随机数发生器)模块生成 256 位或 512 位的密钥(具体位数取决于 :ref:`生成的 XTS-AES 密钥的大小 `),然后将其分别写入一个或两个 ``BLOCK_KEYN`` eFuse 块中。软件也为存储密钥的块更新了 ``KEY_PURPOSE_N``。由于上述一个或两个 ``BLOCK_KEYN`` eFuse 块已设置了读写保护位,因此无法通过软件访问密钥。``KEY_PURPOSE_N`` 字段也受写保护。如果使用基于密钥管理器的密钥,二级引导加载程序则将密钥恢复信息写入 flash 内存地址 0x0,随后烧录 ``KM_XTS_KEY_LENGTH_256`` 和 ``FORCE_USE_KEY_MANAGER_KEY`` eFuse 字段。flash 加密操作全部在硬件中完成,因此无法通过软件访问密钥。 + + 5. flash 加密块会加密 flash 中的内容,包括二级引导加载程序、应用程序、以及带有 ``encrypted`` 标志的分区。就地加密需要一定时间,对于大分区来说最多需要一分钟。 + + 6. 二级引导加载程序将 ``{IDF_TARGET_CRYPT_CNT}`` (0b001) 中的第一个可用位设置为 1,以标记 flash 内容为加密状态,此时位数为奇数。 + + 7. 对于 :ref:`flash-enc-development-mode`,二级引导加载程序允许 UART 引导加载程序重新烧录加密后的二进制文件。同时,``{IDF_TARGET_CRYPT_CNT}`` eFuse 位不受写入保护。此外,二级引导加载程序默认置位以下 eFuse 位: + + .. list:: + + :esp32s2: - ``DIS_BOOT_REMAP`` + - ``DIS_DOWNLOAD_ICACHE`` + - ``DIS_DOWNLOAD_DCACHE`` + - ``HARD_DIS_JTAG`` + - ``DIS_LEGACY_SPI_BOOT`` + + 8. 对于 :ref:`flash-enc-release-mode`,二级引导加载程序设置所有在开发模式下设置的 eFuse 位以及 ``DIS_DOWNLOAD_MANUAL_ENCRYPT``,同时写保护 ``{IDF_TARGET_CRYPT_CNT}`` eFuse 位。若要修改此行为,请参阅 :ref:`uart-bootloader-encryption`。 + + 9. 重新启动设备以开始执行加密镜像。二级引导加载程序调用 flash 解密块来解密 flash 内容,然后将解密后的内容加载到 IRAM 中。 + +.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_KEY_MANAGER_SUPPORTED + + 1. 第一次开机复位时,flash 中的所有数据都是未加密的(明文)。一级 (ROM) 引导加载程序加载二级引导加载程序。 + + 2. 二级引导加载程序将读取 ``{IDF_TARGET_CRYPT_CNT}`` eFuse 值 (``0b000``)。因为该值为 0(偶数位),二级引导加载程序将配置并启用 flash 加密块。关于 flash 加密块的更多信息,请参考 **《{IDF_TARGET_NAME} 技术参考手册》** > **eFuse 控制器 (eFuse)** > **自动加密块** [`PDF <{IDF_TARGET_TRM_CN_URL}#efuse>`__]。 3. 二级引导加载程序首先检查 eFuse 中是否已经存在有效密钥(例如用 espefuse 工具烧写的密钥),如果存在,则会跳过密钥生成,并将该密钥用于 flash 加密过程。否则,二级引导加载程序使用 RNG(随机数发生器)模块生成一个 256 位或 512 位的密钥,具体位数取决于 :ref:`生成的 XTS-AES 密钥的大小 `,然后将其分别写入一个或两个 `BLOCK_KEYN` eFuse 中。软件也为存储密钥的块更新了 ``KEY_PURPOSE_N``。由于上述一个或两个 ``BLOCK_KEYN`` eFuse 已设置了读保护和写保护位,因此无法通过软件访问密钥。``KEY_PURPOSE_N`` 字段也受写保护。flash 加密操作完全在硬件中完成,无法通过软件访问密钥。 - 4. flash 加密块将加密 flash 的内容(二级引导加载程序、应用程序、以及标有“加密”标志的分区)。就地加密可能会耗些时间(对于大分区最多需要一分钟)。 + 4. flash 加密块将加密 flash 的内容(二级引导加载程序、应用程序、以及标有”加密”标志的分区)。就地加密可能会耗些时间(对于大分区最多需要一分钟)。 5. 二级引导加载程序将在 ``{IDF_TARGET_CRYPT_CNT}`` (0b001) 中设置第一个可用位来对已加密的 flash 内容进行标记。设置奇数位。 @@ -217,27 +306,54 @@ flash 的加密过程 - ``HARD_DIS_JTAG`` - ``DIS_LEGACY_SPI_BOOT`` - 7. 对于 :ref:`flash-enc-release-mode`,二级引导加载程序设置所有在开发模式下设置的 eFuse 位。它还写保护 ``{IDF_TARGET_CRYPT_CNT}`` eFuse 位。要修改此行为,请参阅 :ref:`uart-bootloader-encryption`。 + 7. 对于 :ref:`flash-enc-release-mode`,二级引导加载程序设置所有在开发模式下设置的 eFuse 位以及 ``DIS_DOWNLOAD_MANUAL_ENCRYPT``。它还写保护 ``{IDF_TARGET_CRYPT_CNT}`` eFuse 位。要修改此行为,请参阅 :ref:`uart-bootloader-encryption`。 8. 重新启动设备以开始执行加密镜像。二级引导加载程序调用 flash 解密块来解密 flash 内容,然后将解密的内容加载到 IRAM 中。 +.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK and SOC_KEY_MANAGER_SUPPORTED + + 1. 第一次开机复位时,flash 中的所有数据都是未加密的(明文)。一级 (ROM) 引导加载程序加载二级引导加载程序。 + + 2. 二级引导加载程序将读取 ``{IDF_TARGET_CRYPT_CNT}`` eFuse 值 (``0b000``)。因为该值为 0(偶数位),二级引导加载程序将配置并启用 flash 加密块。关于 flash 加密块的更多信息,请参阅 `{IDF_TARGET_NAME} 技术参考手册 <{IDF_TARGET_TRM_CN_URL}>`_。 + + 3. 第二阶段引导加载程序会先判断是否已存在可用的密钥,从而决定是否跳过密钥生成步骤: + + - 若使用基于 eFuse 的密钥启用 flash 加密,则检查 eFuse 中是否已存在有效密钥(例如通过 espefuse 工具烧录的密钥)。 + - 若使用基于密钥管理器的密钥启用 flash 加密,则检查 flash 存储器的地址 0x0 和 0x1000 处是否存在有效的密钥恢复信息。 + + 检查通过,则跳过密钥生成过程,直接使用现有密钥进行 flash 加密。 + + 4. 如果使用基于 eFuse 的密钥,二级引导加载程序将使用 RNG(随机数发生器)模块生成一个 256 位密钥,然后将其写入 ``BLOCK_KEYN`` eFuse 块。软件也为存储密钥的块更新了 ``KEY_PURPOSE_N``。该 ``BLOCK_KEYN`` eFuse 已设置了读写保护位,因此无法通过软件访问密钥。``KEY_PURPOSE_N`` 字段也受写保护。如果使用基于密钥管理器的密钥,二级引导加载程序则将密钥恢复信息写入 flash 内存地址 0x0,随后烧录 ``KM_XTS_KEY_LENGTH_256`` 和 ``FORCE_USE_KEY_MANAGER_KEY`` eFuse 字段。flash 加密操作全部在硬件中完成,因此无法通过软件访问密钥。 + + 5. flash 加密块会加密 flash 中的内容,包括二级引导加载程序、应用程序、以及带有 ``encrypted`` 标志的分区。就地加密需要一定时间,对于大分区来说最多需要一分钟。 + + 6. 二级引导加载程序将 ``{IDF_TARGET_CRYPT_CNT}`` (0b001) 中的第一个可用位设置为 1,以标记 flash 内容为加密状态,此时位数为奇数。 + + 7. 对于 :ref:`flash-enc-development-mode`,二级引导加载程序允许 UART 引导加载程序重新烧录加密后的二进制文件。同时,``{IDF_TARGET_CRYPT_CNT}`` eFuse 位不受写入保护。此外,二级引导加载程序默认置位 ``DIS_DOWNLOAD_ICACHE``、 ``DIS_PAD_JTAG``、 ``DIS_USB_JTAG`` 和 ``DIS_LEGACY_SPI_BOOT``。 + + 8. 对于 :ref:`flash-enc-release-mode`,二级引导加载程序设置所有在开发模式下设置的 eFuse 位以及 ``DIS_DOWNLOAD_MANUAL_ENCRYPT``,同时写保护 ``{IDF_TARGET_CRYPT_CNT}`` eFuse 位。要修改此行为,请参阅 :ref:`uart-bootloader-encryption`。 + + 9. 重新启动设备以开始执行加密镜像。二级引导加载程序调用 flash 解密块来解密 flash 内容,然后将解密后的内容加载到 IRAM 中。 + .. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK 1. 第一次开机复位时,flash 中的所有数据都是未加密的(明文)。一级 (ROM) 引导加载程序加载二级引导加载程序。 - 2. 二级引导加载程序将读取 ``{IDF_TARGET_CRYPT_CNT}`` eFuse 值 (``0b000``)。因为该值为 0(偶数位),二级引导加载程序将配置并启用 flash 加密块。关于 flash 加密块的更多信息,请参考 `{IDF_TARGET_NAME} 技术参考手册 <{IDF_TARGET_TRM_CN_URL}>`_。 + 2. 二级引导加载程序将读取 ``{IDF_TARGET_CRYPT_CNT}`` eFuse 值 (``0b000``)。因为该值为 0(偶数位),二级引导加载程序将配置并启用 flash 加密块。关于 flash 加密块的更多信息,请参阅 `{IDF_TARGET_NAME} 技术参考手册 <{IDF_TARGET_TRM_CN_URL}>`_。 - 3. 二级引导加载程序使用 RNG(随机数发生器)模块生成 256 位密钥,然后将其写入 `BLOCK_KEYN` eFuse。软件也为存储密钥的块更新了 ``KEY_PURPOSE_N``。由于 ``BLOCK_KEYN`` eFuse 已设置了读保护和写保护位,因此无法通过软件访问密钥。``KEY_PURPOSE_N`` 字段也受写保护。flash 加密操作完全在硬件中完成,无法通过软件访问密钥。如果 eFuse 中已经存在有效密钥(例如用 espefuse 工具烧写的密钥),则会跳过密钥生成,并将该密钥用于 flash 加密过程。 + 3. 二级引导加载程序会先判断 eFuse 中是否已经存在有效密钥(例如用 espefuse 工具烧录的密钥),如果存在,则会跳过密钥生成,直接使用现有密钥进行 flash 加密。 - 4. flash 加密块将加密 flash 的内容(二级引导加载程序、应用程序、以及标有“加密”标志的分区)。就地加密可能会耗些时间(对于大分区最多需要一分钟)。 + 4. 如果 eFuse 中不存在可用密钥,则二级引导加载程序使用 RNG(随机数发生器)模块生成 256 位密钥,然后将其写入 ``BLOCK_KEYN`` eFuse。软件也为存储密钥的块更新了 ``KEY_PURPOSE_N``。``BLOCK_KEYN`` eFuse 已设置了读写保护位,因此无法通过软件访问密钥。``KEY_PURPOSE_N`` 字段也受写保护。flash 加密操作全部在硬件中完成,因此无法通过软件访问密钥。 - 5. 二级引导加载程序将在 ``{IDF_TARGET_CRYPT_CNT}`` (0b001) 中设置第一个可用位来对已加密的 flash 内容进行标记。设置奇数位。 + 5. flash 加密块会加密 flash 中的内容,包括二级引导加载程序、应用程序、以及带有 ``encrypted`` 标志的分区。就地加密需要一定时间,对于大分区来说最多需要一分钟。 - 6. 对于 :ref:`flash-enc-development-mode`,二级引导加载程序允许 UART 引导加载程序重新烧录加密后的二进制文件。同时,``{IDF_TARGET_CRYPT_CNT}`` eFuse 位不受写入保护。此外,默认情况下,二级引导加载程序设置 ``DIS_DOWNLOAD_ICACHE``、 ``DIS_PAD_JTAG``、 ``DIS_USB_JTAG`` 和 ``DIS_LEGACY_SPI_BOOT`` eFuse 位。 + 6. 二级引导加载程序将 ``{IDF_TARGET_CRYPT_CNT}`` (0b001) 中的第一个可用位设置为 1,以标记 flash 内容为加密状态,此时位数为奇数。 - 7. 对于 :ref:`flash-enc-release-mode`,二级引导加载程序设置所有在开发模式下设置的 eFuse 位以及 ``DIS_DOWNLOAD_MANUAL_ENCRYPT``。它还写保护 ``{IDF_TARGET_CRYPT_CNT}`` eFuse 位。要修改此行为,请参阅 :ref:`uart-bootloader-encryption`。 + 7. 对于 :ref:`flash-enc-development-mode`,二级引导加载程序允许 UART 引导加载程序重新烧录加密后的二进制文件。同时,``{IDF_TARGET_CRYPT_CNT}`` eFuse 位不受写入保护。此外,二级引导加载程序默认置位 ``DIS_DOWNLOAD_ICACHE``、 ``DIS_PAD_JTAG``、 ``DIS_USB_JTAG`` 和 ``DIS_LEGACY_SPI_BOOT``。 - 8. 重新启动设备以开始执行加密镜像。二级引导加载程序调用 flash 解密块来解密 flash 内容,然后将解密的内容加载到 IRAM 中。 + 8. 对于 :ref:`flash-enc-release-mode`,二级引导加载程序设置所有在开发模式下设置的 eFuse 位以及 ``DIS_DOWNLOAD_MANUAL_ENCRYPT``,同时写保护 ``{IDF_TARGET_CRYPT_CNT}`` eFuse 位。要修改此行为,请参阅 :ref:`uart-bootloader-encryption`。 + + 9. 重新启动设备以开始执行加密镜像。二级引导加载程序调用 flash 解密块来解密 flash 内容,然后将解密后的内容加载到 IRAM 中。 .. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK @@ -301,10 +417,11 @@ flash 加密设置 :esp32: - :ref:`选择 UART ROM 下载模式 ` (默认是 **启用**)。请注意,对于 ESP32 芯片,该选项仅在 :ref:`CONFIG_ESP32_REV_MIN` 级别设置为 3 时 (ESP32 V3) 可用。 :not esp32: - :ref:`选择 UART ROM 下载模式 ` (默认是 **启用**)。 :SOC_FLASH_ENCRYPTION_XTS_AES_OPTIONS: - 设置 :ref:`生成的 XTS-AES 密钥大小 `。 + :SOC_KEY_MANAGER_SUPPORTED: - :ref:`选择 flash 加密密钥的来源 `。 - :ref:`选择适当详细程度的引导加载程序日志 `。 - 保存配置并退出。 -启用 flash 加密将增大引导加载程序,因而可能需更新分区表偏移量。请参考 :ref:`引导加载程序大小 `。 + 启用 flash 加密将增大引导加载程序,因而可能需更新分区表偏移量。请参考 :ref:`引导加载程序大小 `。 3. 运行以下命令来构建和烧录完整的镜像。 @@ -316,15 +433,29 @@ flash 加密设置 这个命令不包括任何应该写入 flash 分区的用户文件。请在运行此命令前手动写入这些文件,否则在写入前应单独对这些文件进行加密。 -该命令将向 flash 写入未加密的镜像:二级引导加载程序、分区表和应用程序。烧录完成后,{IDF_TARGET_NAME} 将复位。在下一次启动时,二级引导加载程序会加密:二级引导加载程序、应用程序分区和标记为“加密”的分区,然后复位。就地加密可能需要时间,对于大分区最多需要一分钟。之后,应用程序在运行时解密并执行命令。 + 该命令将向 flash 写入未加密的镜像:二级引导加载程序、分区表和应用程序。烧录完成后,{IDF_TARGET_NAME} 将复位。在下一次启动时,二级引导加载程序会加密:二级引导加载程序、应用程序分区和标记为 ``encrypted`` 分区,然后复位。就地加密可能需要时间,对于大分区最多需要一分钟。之后,应用程序在运行时解密并执行。 -下面是启用 flash 加密后 {IDF_TARGET_NAME} 首次启动时的样例输出: +.. only:: SOC_KEY_MANAGER_SUPPORTED + + 下面是使用基于密钥管理器的密钥启用 flash 加密后,{IDF_TARGET_NAME} 首次启动时的样例输出: + + .. include:: {IDF_TARGET_PATH_NAME}_log.inc + :start-after: first_boot_enc_km + :end-before: ------ + + 下面是 {IDF_TARGET_NAME} 后续启动时的样例输出,说明 flash 加密已启用(ESP-ROM 日志会提示正在使用基于密钥管理器的密钥): + + .. include:: {IDF_TARGET_PATH_NAME}_log.inc + :start-after: already_en_enc_km + :end-before: ------ + +下面是使用基于 eFuse 的密钥启用 flash 加密后,{IDF_TARGET_NAME} 首次启动时的样例输出: .. include:: {IDF_TARGET_PATH_NAME}_log.inc :start-after: first_boot_enc :end-before: ------ -启用 flash 加密后,在下次启动时输出将显示已启用 flash 加密,样例输出如下: +下面是 {IDF_TARGET_NAME} 后续启动时的样例输出,说明 flash 加密已启用 .. include:: {IDF_TARGET_PATH_NAME}_log.inc :start-after: already_en_enc @@ -338,7 +469,7 @@ flash 加密设置 使用主机生成的密钥 """""""""""""""""""""""" -可在主机中预生成 flash 加密密钥,并将其烧录到 eFuse 密钥块中。这样,无需明文 flash 更新便可以在主机上预加密数据并将其烧录。该功能可在 :ref:`flash-enc-development-mode` 和 :ref:`flash-enc-release-mode` 两模式下使用。如果没有预生成的密钥,数据将以明文形式烧录,然后 {IDF_TARGET_NAME} 对数据进行就地加密。 +可在主机中预生成 flash 加密密钥,并将其烧录到设备中。这样,无需明文 flash 更新便可以在主机上预加密数据并将其烧录。该功能可在 :ref:`flash-enc-development-mode` 和 :ref:`flash-enc-release-mode` 两模式下使用。如果没有预生成的密钥,数据将以明文形式烧录,然后 {IDF_TARGET_NAME} 对数据进行就地加密。 .. note:: @@ -350,7 +481,7 @@ flash 加密设置 请注意, {IDF_TARGET_NAME} 只有一个 eFuse 密钥块,同时用于安全启动和 flash 加密密钥。因此,如果使用了安全启动密钥,则主机生成的 flash 加密密钥必须与安全启动密钥一起写入,否则将无法使用安全启动。 -使用主机生成的密钥需完成以下步骤: +如需使用主机生成的密钥并将其烧录至设备的 eFuse 中,请完成以下步骤: 1. 确保你的 {IDF_TARGET_NAME} 设备有 :ref:`flash-encryption-efuse` 中所示的 flash 加密 eFuse 的默认设置。 @@ -469,12 +600,12 @@ flash 加密设置 4. 在 :ref:`项目配置菜单 ` 中进行如下设置: - - :ref:`启动时启用 flash 加密功能 ` - - :ref:`选择加密模式 ` (默认为 **开发模式**) - - :ref:`选择适当详细程度的引导加载程序日志 ` - - 保存配置并退出 + - :ref:`启动时启用 flash 加密功能 ` + - :ref:`选择加密模式 ` (默认为 **开发模式**) + - :ref:`选择适当详细程度的引导加载程序日志 ` + - 保存配置并退出 -启用 flash 加密将增大引导加载程序,因而可能需更新分区表偏移量。请参考 :ref:`引导加载程序大小 `。 + 启用 flash 加密将增大引导加载程序,因而可能需更新分区表偏移量。请参考 :ref:`引导加载程序大小 `。 5. 运行以下命令来构建并烧录完整的镜像: @@ -486,7 +617,73 @@ flash 加密设置 这个命令不包括任何应该被写入 flash 上的分区的用户文件。请在运行此命令前手动写入这些文件,否则在写入前应单独对这些文件进行加密。 - 该命令将向 flash 写入未加密的镜像:二级引导加载程序、分区表和应用程序。烧录完成后,{IDF_TARGET_NAME} 将复位。在下一次启动时,二级引导加载程序会加密:二级引导加载程序、应用程序分区和标记为 ``加密`` 的分区,然后复位。就地加密可能需要时间,对于大的分区来说可能耗时一分钟。之后,应用程序在运行时被解密并执行。 + 该命令将向 flash 写入未加密的镜像:二级引导加载程序、分区表和应用程序。烧录完成后,{IDF_TARGET_NAME} 将复位。在下一次启动时,二级引导加载程序会加密:二级引导加载程序、应用程序分区和标记为 ``encrypted`` 的分区,然后复位。就地加密可能需要时间,对于大的分区来说可能耗时一分钟。之后,应用程序在运行时被解密并执行。 + +.. only:: SOC_KEY_MANAGER_SUPPORTED + + 如需使用主机生成的密钥并将其部署至设备的密钥管理器,请完成以下步骤: + + 1. 确保你的 {IDF_TARGET_NAME} 设备有 :ref:`flash-encryption-efuse` 中所示的 flash 加密 eFuse 的默认设置。 + + 请参考如何检查 :ref:`flash-encryption-status`。 + + 2. 通过运行以下命令生成一个随机密钥: + + .. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256 + + 如果 :ref:`生成的 XTS-AES 密钥大小 ` 是 AES-128(256 位密钥): + + .. code-block:: bash + + idf.py secure-generate-flash-encryption-key my_flash_encryption_key.bin + + 如果 :ref:`生成的 XTS-AES 密钥大小 ` 是 AES-256(512 位密钥): + + .. code-block:: bash + + idf.py secure-generate-flash-encryption-key --keylen 512 my_flash_encryption_key.bin + + + .. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK + + .. code-block:: bash + + idf.py secure-generate-flash-encryption-key my_flash_encryption_key.bin + + + 3. **在首次加密启动前**,使用密钥管理器的 AES 部署模式,通过初始化密钥和辅助密钥将密钥部署到设备的密钥管理器中。 + + 4. 部署过程将为已部署的密钥生成密钥恢复信息。使用以下命令将该信息存储到 flash 地址 0x0 处: + + .. code-block:: bash + + esptool --port PORT --baud BAUD write-flash 0x0 key_recovery_info.bin + + 如果未部署密钥就在启用 flash 加密后启动设备,{IDF_TARGET_NAME} 将生成并部署一个软件无法访问或修改的随机密钥。 + + .. note:: + + 上述命令不包括任何应该被写入 flash 分区的用户文件。请在运行此命令前手动写入这些文件,或者在写入前单独对这些文件进行加密。 + + 5. 在 :ref:`project-configuration-menu` 中进行如下设置: + + - :ref:`启动时启用 flash 加密功能 ` + - :ref:`选择加密模式 ` (默认为 **开发模式**) + - :ref:`选择 flash 加密密钥来源为密钥管理器 ` + - :ref:`选择适当详细程度的引导加载程序日志 ` + - 保存配置并退出。 + + 启用 flash 加密将增大引导加载程序,因而可能需更新分区表偏移量。详情请参阅 :ref:`bootloader-size`。 + + 6. 运行以下命令来构建并烧录完整的镜像: + + .. code-block:: bash + + idf.py flash monitor + + .. note:: + + 上述命令不包括任何应该被写入 flash 分区的用户文件。请在运行此命令前手动写入这些文件,或者在写入前单独对这些文件进行加密。 如果使用开发模式,那么更新和重新烧录二进制文件最简单的方法是 :ref:`encrypt-partitions`。 @@ -540,7 +737,7 @@ flash 加密设置 - :ref:`选择适当详细程度的引导加载程序日志级别 `。 - 保存配置并退出。 -启用 flash 加密将增大引导加载程序,因而可能需更新分区表偏移量。请参考 :ref:`引导加载程序大小 `。 + 启用 flash 加密将增大引导加载程序,因而可能需更新分区表偏移量。请参考 :ref:`引导加载程序大小 `。 3. 运行以下命令来构建并烧录完整的镜像: @@ -553,7 +750,7 @@ flash 加密设置 这个命令不包括任何应该被写入 flash 分区的用户文件。请在运行此命令前手动写入这些文件,否则在写入前应单独对这些文件进行加密。 - 该命令将向 flash 写入未加密的镜像:二级引导加载程序、分区表和应用程序。烧录完成后,{IDF_TARGET_NAME} 将复位。在下一次启动时,二级引导加载程序会加密:二级引导加载程序、应用程序分区和标记为 ``加密`` 的分区,然后复位。就地加密可能需要时间,对于大的分区来说可能耗时一分钟。之后,应用程序在运行时被解密并执行。 + 该命令将向 flash 写入未加密的镜像:二级引导加载程序、分区表和应用程序。烧录完成后,{IDF_TARGET_NAME} 将复位。在下一次启动时,二级引导加载程序会加密:二级引导加载程序、应用程序分区和标记为 ``encrypted`` 的分区,然后复位。就地加密可能需要时间,对于大的分区来说可能耗时一分钟。之后,应用程序在运行时被解密并执行。 一旦在量产模式下启用 flash 加密,引导加载程序将写保护 ``{IDF_TARGET_CRYPT_CNT}`` eFuse。 @@ -589,55 +786,55 @@ flash 加密设置 1. 如果通过 **明文二级引导加载程序镜像** 重新烧录了引导加载程序分区,则 ROM 加载器将无法加载二级引导加载程序,并会显示以下错误类型: -.. only:: esp32 + .. only:: esp32 - .. code-block:: bash + .. code-block:: bash - rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - flash read err, 1000 - ets_main.c 371 - ets Jun 8 2016 00:22:57 + rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + flash read err, 1000 + ets_main.c 371 + ets Jun 8 2016 00:22:57 - rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - flash read err, 1000 - ets_main.c 371 - ets Jun 8 2016 00:22:57 + rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + flash read err, 1000 + ets_main.c 371 + ets Jun 8 2016 00:22:57 - rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - flash read err, 1000 - ets_main.c 371 - ets Jun 8 2016 00:22:57 + rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + flash read err, 1000 + ets_main.c 371 + ets Jun 8 2016 00:22:57 - rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - flash read err, 1000 - ets_main.c 371 - ets Jun 8 2016 00:22:57 + rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + flash read err, 1000 + ets_main.c 371 + ets Jun 8 2016 00:22:57 - rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - flash read err, 1000 - ets_main.c 371 - ets Jun 8 2016 00:22:57 + rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + flash read err, 1000 + ets_main.c 371 + ets Jun 8 2016 00:22:57 -.. only:: not esp32 + .. only:: not esp32 - .. code-block:: bash + .. code-block:: bash - rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - invalid header: 0xb414f76b - invalid header: 0xb414f76b - invalid header: 0xb414f76b - invalid header: 0xb414f76b - invalid header: 0xb414f76b - invalid header: 0xb414f76b - invalid header: 0xb414f76b + rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + invalid header: 0xb414f76b + invalid header: 0xb414f76b + invalid header: 0xb414f76b + invalid header: 0xb414f76b + invalid header: 0xb414f76b + invalid header: 0xb414f76b + invalid header: 0xb414f76b - .. note:: + .. note:: - 不同应用程序中无效头文件的值不同。 + 不同应用程序中无效头文件的值不同。 -.. note:: + .. note:: - 如果 flash 内容被擦除或损坏,也会出现这个错误。 + 如果 flash 内容被擦除或损坏,也会出现这个错误。 2. 如果二级引导加载程序已加密,但通过 **明文分区表镜像** 重新烧录了分区表,引导加载程序将无法读取分区表,从而出现以下错误: @@ -700,7 +897,7 @@ flash 加密设置 {IDF_TARGET_NAME} flash 加密状态 ----------------------------------------- -1. 确保你的 {IDF_TARGET_NAME} 设备有 :ref:`flash-encryption-efuse` 中所示的 flash 加密 eFuse 的默认设置。 +确保你的 {IDF_TARGET_NAME} 设备有 :ref:`flash-encryption-efuse` 中所示的 flash 加密 eFuse 的默认设置。 要检查你的 {IDF_TARGET_NAME} 设备上是否启用了 flash 加密,请执行以下操作之一: @@ -758,7 +955,7 @@ flash 加密范围 也可以使用函数 :cpp:func:`esp_flash_write_encrypted` 预加密和写入数据。 -此外,esp-idf 应用程序中存在但不支持以下 ROM 函数: +此外,ESP-IDF 应用程序中存在但不支持以下 ROM 函数: - ``esp_rom_spiflash_write_encrypted`` 预加密并将数据写入 flash - ``SPIWrite`` 将未加密的数据写入 flash @@ -828,11 +1025,13 @@ flash 加密的要点 :esp32: - flash 加密算法采用的是 AES-256,其中密钥随着 flash 的每个 32 字节块的偏移地址“调整”。这意味着,每个 32 字节块(2 个连续的 16 字节 AES 块)使用从 flash 加密密钥中产生的一个特殊密钥进行加密。 - :esp32s2 or esp32s3: - 使用 XTS-AES-128 或 XTS-AES-256 加密 flash。flash 加密密钥分别为 256 位和 512 位,存储于芯片内部一个或两个 ``BLOCK_KEYN`` eFuse 中,并(默认)受保护,防止软件访问。 + :SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_KEY_MANAGER_SUPPORTED: - 使用 XTS-AES-128 或 XTS-AES-256 加密 flash。flash 加密密钥分别为 256 位和 512 位,存储于芯片内部的一个或两个 ``BLOCK_KEYN`` eFuse 块中。默认情况下,这些密钥受硬件保护,软件无法访问。 - :esp32c3: - 使用 XTS-AES-128 加密 flash。 flash 加密密钥为 256 位,存储于芯片内部的 ``BLOCK_KEYN`` eFuse 中,并(默认)受保护,防止软件访问。 + :SOC_FLASH_ENCRYPTION_XTS_AES_256 and SOC_KEY_MANAGER_SUPPORTED: - 使用 XTS-AES-128 或 XTS-AES-256 加密 flash。flash 加密密钥分别为 256 位和 512 位。若 flash 加密使用基于 eFuse 的密钥启用,则密钥存储于芯片内部的一个或两个 ``BLOCK_KEYN`` eFuse 块中;若 flash 加密使用基于密钥管理器的密钥启用,则 flash 加密密钥存储于密钥管理器中。默认情况下,这些密钥受硬件保护,软件无法访问。 - :esp32c2: - 使用 XTS-AES-128 加密 flash。 flash 加密密钥为 128 位或 256 位,存储于芯片内部的 ``BLOCK_KEY0`` eFuse 中,并(默认)受保护,防止软件访问。 + :SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_FLASH_ENCRYPTION_XTS_AES_128_DERIVED: - 使用 XTS-AES-128 加密 flash。flash 加密密钥为 256 位,存储于芯片内部的 ``BLOCK_KEYN`` eFuse 块中。默认情况下,该密钥受硬件保护,软件无法访问。 + + :SOC_FLASH_ENCRYPTION_XTS_AES_128_DERIVED: - 使用 XTS-AES-128 加密 flash。 flash 加密密钥为 128 位或 256 位,存储于芯片内部的 ``BLOCK_KEY0`` eFuse 块中。默认情况下,该密钥受硬件保护,软件无法访问。 - 通过 {IDF_TARGET_NAME} 的 flash 缓存映射功能,flash 可支持透明访问——任何映射到地址空间的 flash 区域在读取时都将被透明地解密。 @@ -842,11 +1041,11 @@ flash 加密的要点 - 如果已启用安全启动,重新烧录加密设备的引导加载程序则需要“可重新烧录”的安全启动摘要(可参考 :ref:`flash-encryption-and-secure-boot`)。 - 启用 flash 加密将增大引导加载程序,因此可能需更新分区表偏移量。请参考 :ref:`引导加载程序大小 `。 +启用 flash 加密将增大引导加载程序,因此可能需更新分区表偏移量。请参考 :ref:`引导加载程序大小 `。 - .. important:: +.. important:: - 在首次启动加密过程中,请勿切断 {IDF_TARGET_NAME} 的电源。如果电源被切断,flash 的内容将受到破坏,并需要重新烧录未加密数据。而这类重新烧录将不计入烧录限制次数。 + 在首次启动加密过程中,请勿切断 {IDF_TARGET_NAME} 的电源。如果电源被切断,flash 的内容将受到破坏,并需要重新烧录未加密数据。而这类重新烧录将不计入烧录限制次数。 .. _flash-encryption-limitations: @@ -883,7 +1082,7 @@ flash 加密与安全启动 - 在启用 flash 加密量产模式时,建议在首次启动时就设置 :ref:`xts-aes-pseudo-round-func` 所需的强度。如果你的工作流程需要在首次启动后更新该函数的强度,则应启用 :ref:`CONFIG_SECURE_BOOT_SKIP_WRITE_PROTECTION_SCA`,避免在启动过程中对该位进行写保护。 -.. _flash-encryption-without-secure-boot: +.. _flash-encryption-advanced-features: flash 加密的高级功能 -------------------------------- @@ -934,11 +1133,11 @@ flash 加密的高级功能 .. list:: - ``DIS_DOWNLOAD_MANUAL_ENCRYPT`` 在 UART 引导加载程序启动模式下运行时,禁止 flash 加密操作。 - :esp32s2 or esp32s3: - ``DIS_DOWNLOAD_ICACHE`` 和 ``DIS_DOWNLOAD_DCACHE`` 在 UART 引导加载程序模式下运行时禁止整个 MMU flash 缓存。 - :esp32c3 or esp32c2: - ``DIS_DOWNLOAD_ICACHE`` 在 UART 引导加载程序模式下运行时禁止整个 MMU flash 缓存。 + :SOC_EFUSE_DIS_DOWNLOAD_ICACHE and SOC_EFUSE_DIS_DOWNLOAD_DCACHE: - ``DIS_DOWNLOAD_ICACHE`` 和 ``DIS_DOWNLOAD_DCACHE`` 在 UART 引导加载程序模式下运行时禁止整个 MMU flash 缓存。 + :SOC_EFUSE_DIS_DOWNLOAD_ICACHE and not SOC_EFUSE_DIS_DOWNLOAD_DCACHE: - ``DIS_DOWNLOAD_ICACHE`` 在 UART 引导加载程序模式下运行时禁止整个 MMU flash 缓存。 :esp32s2: - ``HARD_DIS_JTAG`` 禁用 JTAG。 - :esp32c3: - ``DIS_PAD_JTAG`` 和 ``DIS_USB_JTAG`` 禁用 JTAG。 - :esp32s3: - ``HARD_DIS_JTAG`` 和 ``DIS_USB_JTAG`` 禁用 JTAG。 + :SOC_EFUSE_DIS_PAD_JTAG and SOC_EFUSE_DIS_USB_JTAG: - ``DIS_PAD_JTAG`` 和 ``DIS_USB_JTAG`` 禁用 JTAG。 + :SOC_EFUSE_HARD_DIS_JTAG and SOC_EFUSE_DIS_USB_JTAG: - ``HARD_DIS_JTAG`` 和 ``DIS_USB_JTAG`` 禁用 JTAG。 - ``DIS_DIRECT_BOOT``(即之前的 ``DIS_LEGACY_SPI_BOOT``)禁用传统的 SPI 启动模式。 :SOC_EFUSE_DIS_DOWNLOAD_MSPI: - ``DIS_DOWNLOAD_MSPI`` 在下载模式下禁用 MSPI 访问 @@ -1003,7 +1202,13 @@ JTAG 调试 手动加密文件 ^^^^^^^^^^^^^^^^^^^^ -手动加密或解密文件需要在 eFuse 中预烧录 flash 加密密钥(请参阅 :ref:`pregenerated-flash-encryption-key`)并在主机上保留一份副本。 如果 flash 加密配置在开发模式下,那么则不需要保留密钥的副本或遵循这些步骤,可以使用更简单的 :ref:`encrypt-partitions` 步骤。 +.. only:: SOC_KEY_MANAGER_SUPPORTED + + 手动加密或解密文件需要将 flash 加密密钥部署到密钥管理器或在 eFuse 中预烧录(请参阅 :ref:`pregenerated-flash-encryption-key`)并在主机上保留一份副本。如果 flash 加密配置在开发模式下,则不需要保留密钥的副本或遵循以下步骤,可以使用更简单的 :ref:`encrypt-partitions` 步骤。 + +.. only:: not SOC_KEY_MANAGER_SUPPORTED + + 手动加密或解密文件需要在 eFuse 中预烧录 flash 加密密钥(请参阅 :ref:`pregenerated-flash-encryption-key`)并在主机上保留一份副本。如果 flash 加密配置在开发模式下,则不需要保留密钥的副本或遵循以下步骤,可以使用更简单的 :ref:`encrypt-partitions` 步骤。 密钥文件应该是单个原始二进制文件(例如:``key.bin``)。 @@ -1025,7 +1230,7 @@ JTAG 调试 .. note:: - 如果 {IDF_TARGET_NAME} 在启动时无法识别烧录进去的密文文件,请检查密钥是否匹配以及命令行参数是否完全匹配,包括偏移量是否正确。 + 如果 {IDF_TARGET_NAME} 在启动时无法识别烧录进去的密文文件,请检查密钥是否匹配以及命令行参数是否完全匹配,包括偏移量是否正确。 .. only:: esp32 diff --git a/docs/zh_CN/security/security-features-enablement-workflows.rst b/docs/zh_CN/security/security-features-enablement-workflows.rst index f2004b54420..2773fece365 100644 --- a/docs/zh_CN/security/security-features-enablement-workflows.rst +++ b/docs/zh_CN/security/security-features-enablement-workflows.rst @@ -118,7 +118,7 @@ .. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK - 如果 :ref:` 生成的 AES-XTS 密钥的大小 ` 为 AES-128(256 位密钥): + 如果 :ref:`生成的 AES-XTS 密钥的大小 ` 为 AES-128(256 位密钥): .. code-block:: bash @@ -130,19 +130,57 @@ espsecure generate-flash-encryption-key --keylen 128 my_flash_encryption_key.bin -3. 将 flash 加密密钥烧录到 eFuse 中 +3. 将生成的 flash 加密密钥烧录到设备中 + + .. only:: SOC_KEY_MANAGER_SUPPORTED + + a. 若使用密钥管理器存储 flash 加密密钥,请为 flash 加密密钥生成密钥恢复信息,并使用以下命令将其保存至 flash 地址 0x0 处: + + .. code-block:: bash + + esptool --port PORT write-flash 0x0 key_recovery_info.bin + + 将密钥恢复信息存储至 flash 后,还需要烧录 ``KM_XTS_KEY_LENGTH_256`` 和 ``FORCE_USE_KEY_MANAGER_KEY`` eFuse。 + + .. warning:: + + 此操作 **无法回退**。 + + ``FORCE_USE_KEY_MANAGER_KEY`` eFuse 的第 1 位用于强制使用基于密钥管理器的 XTS-AES 密钥。 + + .. code-block:: bash + + espefuse --port PORT burn-efuse FORCE_USE_KEY_MANAGER_KEY 2 + + ``KM_XTS_KEY_LENGTH_256`` eFuse 用于控制基于密钥管理器的 XTS-AES 密钥长度。将该 eFuse 设置为 1 表示使用 128 位密钥,设置为 0 表示使用 256 位密钥。 + + 若使用 128 位密钥,请将 ``KM_XTS_KEY_LENGTH_256`` eFuse 设置为 1。 + + .. code-block:: bash + + espefuse --port PORT burn-efuse KM_XTS_KEY_LENGTH_256 1 + + 若使用 256 位密钥,请将 ``KM_XTS_KEY_LENGTH_256`` eFuse 设置为 0。 + + .. code-block:: bash + + espefuse --port PORT burn-efuse KM_XTS_KEY_LENGTH_256 0 + + b. 如需将 flash 加密密钥存储至 eFuse 中,请运行以下命令: + + .. only:: not SOC_KEY_MANAGER_SUPPORTED + + 如需将 flash 加密密钥存储在 eFuse 中,请运行以下命令: .. warning:: - 这个操作 **无法回退**。 - - 运行以下命令进行烧录: + 此操作 **无法回退**。 .. only:: not SOC_FLASH_ENCRYPTION_XTS_AES .. code-block:: bash - espefuse --port PORT burn-key flash-encryption my_flash_encryption_key.bin + espefuse --port PORT burn-key flash_encryption my_flash_encryption_key.bin .. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256 @@ -150,7 +188,7 @@ espefuse --port PORT burn-key BLOCK my_flash_encryption_key.bin KEYPURPOSE - 其中, ``BLOCK`` 是位于 ``BLOCK_KEY0`` 和 ``BLOCK_KEY5`` 之间的空闲密钥块, ``KEYPURPOSE`` 是 ``XTS_AES_256_KEY_1``, ``XTS_AES_256_KEY_2`` 或 ``XTS_AES_128_KEY``。有关密钥用途的说明,请参阅 `{IDF_TARGET_NAME} 技术参考手册 <{IDF_TARGET_TRM_EN_URL}>`__。 + 其中, ``BLOCK`` 是位于 ``BLOCK_KEY0`` 和 ``BLOCK_KEY5`` 之间的空闲密钥块, ``KEYPURPOSE`` 是 ``XTS_AES_256_KEY_1``, ``XTS_AES_256_KEY_2`` 或 ``XTS_AES_128_KEY``。有关密钥用途的说明,请参阅 `{IDF_TARGET_NAME} 技术参考手册 <{IDF_TARGET_TRM_CN_URL}>`__。 对于 AES-128(256 位密钥)- ``XTS_AES_128_KEY``: @@ -189,7 +227,7 @@ espefuse --port PORT burn-key BLOCK_KEY0 flash_encryption_key256.bin XTS_AES_128_KEY - 对于从 SHA256(128 eFuse 位)派生的 AES-128 密钥 - ``XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS``。FE 密钥会被写入 eFuse BLOCK_KEY0 的后半部分。前 128 位不会被使用,并保持可供软件读取状态。使用 espefuse 工具的特殊模式,可以用任何 espefuse 命令将数据写入其中,可参考下文 ``同时烧录两个密钥``。 + 对于从 SHA256(128 eFuse 位)派生的 AES-128 密钥 - ``XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS``。FE 密钥会被写入 eFuse BLOCK_KEY0 低位部分。高 128 位不会被使用,并保持可供软件读取状态。使用 espefuse 工具的特殊模式,可以用任何 espefuse 命令将数据写入其中,可参考下文 ``同时烧录两个密钥``。 .. code-block:: bash @@ -400,7 +438,7 @@ flash 加密指南 .. code:: bash - espsecure generate-signing-key --version 2 --scheme rsa3072 secure_boot_signinig_key.pem + espsecure generate-signing-key --version 2 --scheme rsa3072 secure_boot_signing_key.pem .. only:: SOC_SECURE_BOOT_V2_ECC @@ -499,12 +537,12 @@ flash 加密指南 :SOC_EFUSE_DIS_BOOT_REMAP: - ``DIS_BOOT_REMAP``:禁用将 ROM 重新映射到 RAM 地址空间的功能。 :SOC_EFUSE_HARD_DIS_JTAG: - ``HARD_DIS_JTAG``:硬禁用 JTAG 外设。 :SOC_EFUSE_SOFT_DIS_JTAG: - ``SOFT_DIS_JTAG``:禁止软件对 JTAG 外设的访问。 - :SOC_EFUSE_DIS_DIRECT_BOOT:- ``DIS_DIRECT_BOOT``: 禁用直接引导(旧版 SPI 引导模式)。 + :SOC_EFUSE_DIS_DIRECT_BOOT: - ``DIS_DIRECT_BOOT``: 禁用直接引导(旧版 SPI 引导模式)。 :SOC_EFUSE_DIS_LEGACY_SPI_BOOT: - ``DIS_LEGACY_SPI_BOOT``:禁用旧版 SPI 引导模式。 :SOC_EFUSE_DIS_USB_JTAG: - ``DIS_USB_JTAG``:禁止从 USB 切换到 JTAG。 :SOC_EFUSE_DIS_PAD_JTAG: - ``DIS_PAD_JTAG``:永久禁用 JTAG。 :SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS: - ``SECURE_BOOT_AGGRESSIVE_REVOKE``:主动吊销密钥摘要。详请请参阅 :ref:`secure-boot-v2-aggressive-key-revocation`。 - :SOC_ECDSA_P192_CURVE_DEFAULT_DISABLED: - ``WR_DIS_ECDSA_CURVE_MODE``:禁止写入 ECDSA 曲线模式的 eFuse 位。由于此写保护位与 ``ECC_FORCE_CONST_TIME`` 共享,建议先配置好 ``ECC_FORCE_CONST_TIME`` eFuse 字段后,再设置此写保护位)。 + :SOC_ECDSA_P192_CURVE_DEFAULT_DISABLED: - ``WR_DIS_ECDSA_CURVE_MODE``:禁止写入 ECDSA 曲线模式的 eFuse 位。由于此写保护位与 ``ECC_FORCE_CONST_TIME`` 共享,建议配置好 ``ECC_FORCE_CONST_TIME`` eFuse 字段后,再设置此写保护位。 :SOC_ECDSA_SUPPORT_CURVE_P384: - ``WR_DIS_SECURE_BOOT_SHA384_EN``:禁止写入 SHA-384 Secure Boot 的 eFuse 位。由于此写保护位与 ``XTS_DPA_PSEUDO_LEVEL`` 和 ``ECC_FORCE_CONST_TIME`` 共享,建议先配置好这两个 eFuse,再设置此写保护位。 运行以下命令烧录相应的 eFuse: @@ -677,7 +715,7 @@ Secure Boot v2 指南 3. 生成加密的 NVS 分区 - 主机上将会生成加密 NVS 分区。有关生成加密 NVS 分区的详细信息,请参阅读 :ref:`generate-encrypted-nvs-partition`。为此,CSV 文件中应该包含 NVS 文件的全部内容。详情请参阅 :ref:`nvs-csv-file-format`。 + 主机上将会生成加密 NVS 分区。有关生成加密 NVS 分区的详细信息,请参阅 :ref:`generate-encrypted-nvs-partition`。为此,CSV 文件中应该包含 NVS 文件的全部内容。详情请参阅 :ref:`nvs-csv-file-format`。 使用以下命令,可以生成加密的 NVS 分区: @@ -736,7 +774,7 @@ Secure Boot v2 指南 下文解释了上述命令中的一些参数: - * CSV 文件名 - 上述命名中的 `sample_singlepage_blob.csv` 是指包含 NVS 数据的 CSV 文件,请将其替换为所选文件。 + * CSV 文件名 - 上述命令中的 `sample_singlepage_blob.csv` 是指包含 NVS 数据的 CSV 文件,请将其替换为所选文件。 * NVS 分区大小 - 这是 NVS 分区的大小(以字节为单位)。请将上述命令中的示例值 ``0x3000`` 更新为你实际 NVS 分区的正确大小。 diff --git a/docs/zh_CN/security/security.rst b/docs/zh_CN/security/security.rst index 4f7792be59c..eb5b9cf6e51 100644 --- a/docs/zh_CN/security/security.rst +++ b/docs/zh_CN/security/security.rst @@ -3,7 +3,7 @@ {IDF_TARGET_CIPHER_SCHEME:default="RSA", esp32h2="RSA 或 ECDSA", esp32p4="RSA 或 ECDSA", esp32c5="RSA 或 ECDSA", esp32c61="ECDSA", esp32h21="RSA 或 ECDSA"} -{IDF_TARGET_SIG_PERI:default="DS", esp32h2="DS 或 ECDSA", esp32p4="DS 或 ECDSA", esp32c5="DS 或 ECDSA", esp32c61="ECDSA"} +{IDF_TARGET_SIG_PERI:default="DS", esp32h2="DS 或 ECDSA", esp32p4="DS 或 ECDSA", esp32c5="DS 或 ECDSA"} :link_to_translation:`en:[English]` @@ -101,6 +101,24 @@ flash 加密最佳实践 详情请参阅 :doc:`../api-reference/peripherals/ecdsa` 及 :doc:`../api-reference/peripherals/ds`。 +.. only:: SOC_KEY_MANAGER_SUPPORTED + + 密钥管理器 + ~~~~~~~~~~ + + {IDF_TARGET_NAME} 中的密钥管理器外设提供硬件辅助的 **密钥部署和恢复** 功能,适用于加密密钥。密钥通过每块芯片独有的硬件唯一密钥 (HUK) 进行加密绑定,确保密钥内容不会暴露给软件可访问的内存。 + + 密钥管理器支持以下加密外设的密钥管理::doc:`ECDSA <../api-reference/peripherals/ecdsa>`、:doc:`HMAC <../api-reference/peripherals/hmac>`、:doc:`数字签名 (DS) <../api-reference/peripherals/ds>` 以及 flash 加密。 + + 详情请参阅 :doc:`../api-reference/peripherals/key_manager`。 + + 密钥管理器最佳实践 + ^^^^^^^^^^^^^^^^^^ + + * 防止密钥管理器部署密钥的 ``key_recovery_info`` 遭受未授权修改或丢失。 + * 在成功部署密钥后,锁定密钥管理器相关的安全 eFuse,防止重新部署同类型密钥。 + * 除非明确需要,否则在已启用 flash 加密的情况下,避免部署新的 XTS-AES 密钥。 + .. only:: SOC_MEMPROT_SUPPORTED or SOC_CPU_IDRAM_SPLIT_USING_PMP 内存保护 @@ -124,7 +142,7 @@ flash 加密最佳实践 差分功耗分析 (DPA) 保护 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - {IDF_TARGET_NAME} 支持针对 DPA 相关安全攻击的保护机制。DPA 保护通过动态调整加密外设的时钟频率,在其运行期间模糊了功耗轨迹。时钟变化范围会根据配置的 DPA 安全级别改变。更多详情请参阅 *{IDF_TARGET_NAME} 技术参考手册* > [`PDF <{IDF_TARGET_TRM_CN_URL}>`__]。 + {IDF_TARGET_NAME} 支持针对 DPA 相关安全攻击的保护机制。DPA 保护通过动态调整加密外设的时钟频率,在其运行期间模糊了功耗轨迹。时钟变化范围会根据配置的 DPA 安全级别改变。详情请参阅 **《{IDF_TARGET_NAME} 技术参考手册》** [`PDF <{IDF_TARGET_TRM_CN_URL}>`__]。 通过 :ref:`CONFIG_ESP_CRYPTO_DPA_PROTECTION_LEVEL` 可以调整 DPA 级别。级别越高安全性越强,但也可能会影响性能。默认启用最低级别 DPA 保护,可以根据安全需求修改。 @@ -140,7 +158,7 @@ flash 加密最佳实践 {IDF_TARGET_NAME} 在 AES 外设中集成了伪轮次功能,使该外设能够在原始操作轮次前后随机插入伪轮次,并生成一个伪密钥来执行这些虚拟操作。 这些操作不会改变原始结果,但能够通过随机化功耗特征,提高实施侧信道分析攻击的复杂性。 - 可以使用 :ref:`CONFIG_MBEDTLS_AES_USE_PSEUDO_ROUND_FUNC_STRENGTH` 选择伪轮次功能的强度。提高强度会增强该功能所提供的安全性,但会加密/解密操作的速度。 + 可以使用 :ref:`CONFIG_MBEDTLS_AES_USE_PSEUDO_ROUND_FUNC_STRENGTH` 选择伪轮次功能的强度。提高强度会增强该功能所提供的安全性,但会减缓加密/解密操作的速度。 .. list-table:: 伪轮次功能的不同强度对 AES 操作性能的影响 diff --git a/examples/security/.build-test-rules.yml b/examples/security/.build-test-rules.yml index a21af384655..37974657c5e 100644 --- a/examples/security/.build-test-rules.yml +++ b/examples/security/.build-test-rules.yml @@ -3,10 +3,14 @@ examples/security/flash_encryption: disable: - if: CONFIG_NAME == "psram" and SOC_SPIRAM_SUPPORTED != 1 - - if: IDF_TARGET == "esp32p4" + - if: CONFIG_NAME == "key_mgr" and SOC_KEY_MANAGER_SUPPORTED != 1 + - if: IDF_TARGET in ["esp32s31"] temporary: true - reason: p4 rev3 migration # TODO: IDF-14367 + reason: not support yet # TODO: [ESP32S31] IDF-14628 disable_test: + - if: CONFIG_NAME == "key_mgr" + temporary: true + reason: lack of runners - if: IDF_TARGET in ["esp32s2", "esp32s3", "esp32c6", "esp32h2", "esp32c2", "esp32c5", "esp32c61"] temporary: true reason: lack of runners @@ -22,6 +26,16 @@ examples/security/hmac_soft_jtag: depends_filepatterns: - examples/security/hmac_soft_jtag/**/* +examples/security/key_manager: + disable: + - if: SOC_KEY_MANAGER_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET not in ["esp32c5"] + reason: sufficient to test on one Key Manager-supported chip + depends_components: + - esp_security + - mbedtls + examples/security/nvs_encryption_hmac: disable: - if: SOC_HMAC_SUPPORTED != 1 diff --git a/examples/security/README.md b/examples/security/README.md index 38978c5562e..8507d68bd55 100644 --- a/examples/security/README.md +++ b/examples/security/README.md @@ -37,6 +37,14 @@ The steps include: * Generating token data from the key. * Using commands to re-enable JTAG access. +## Key Manager Signing + +This example demonstrates how to use the Key Manager peripheral for cryptographic signing operations on Key Manager supported chips. The Key Manager provides secure key deployment and management, allowing keys to be used for cryptographic operations without exposing the raw key material. +The example showcases: +* ECDSA signing using Key Manager deployed keys via PSA Crypto API. +* RSA-DS (Digital Signature) signing using Key Manager deployed keys via PSA Crypto API. +* Key deployment in AES mode with pre-generated key material. + # ESP-TEE (Trusted Execution Environment) For examples demonstrating the ESP-TEE framework, please refer to the [ESP-TEE examples](tee/README.md) directory. It contains examples showcasing operations like AES encryption/decryption in the TEE, secure storage with signing and encryption capabilities, secure OTA updates for TEE applications, and entity attestation token generation. diff --git a/examples/security/flash_encryption/README.md b/examples/security/flash_encryption/README.md index 1dda7e4075c..533028dc66e 100644 --- a/examples/security/flash_encryption/README.md +++ b/examples/security/flash_encryption/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | # Flash Encryption @@ -14,6 +14,7 @@ The example also demonstrates: 2. Initialization of FATFS, formatting, writing and reading file. Both encrypted as well as non-encrypted. 3. Initialization of encrypted NVS partition. Both auto-generated as well as pre-generated NVS key scenarios are presented. 4. Flashing the example in Development as well as Release mode. +5. Using the Key Manager peripheral as the Flash Encryption key source (on targets with the Key Manager peripheral). ### NVS example The example demonstrates default and custom NVS partition initialisation when the flash encryption is enabled. From the code perspective the use of NVS API is transparent regardless of the flash encryption mode. @@ -36,6 +37,10 @@ idf.py menuconfig #### Flash encryption configuration Enable the flash encryption mode (Development or Release) under (`menuconfig -> Security Features`). Default usage mode is Development (recommended during test and development phase). +On targets that support the Key Manager peripheral (ESP32-C5, ESP32-P4), the flash encryption key source can be configured under (`menuconfig -> Security features -> Flash Encryption -> Flash Encryption key source`): +- **eFuse-based key** (default): The key is generated by the bootloader and stored in a `BLOCK_KEYN` eFuse. +- **Key Manager-based key**: The key is deployed into and managed by the Key Manager peripheral. See [Using Key Manager as Flash Encryption Key Source](#using-key-manager-as-flash-encryption-key-source) below. + Note: After enabling flash encryption, the bootloader size increases, which means that default offset of the partition table (`menuconfig -> Partition Table -> Offset of partition table`) has to be increased from default value of 0x8000 to prevent the bootloader from overlapping with the partition table. In this example, the offset of the partition table is incereased to 0xD000. If you chose the Release mode, for better security, you can also disable UART ROM download mode using (`menuconfig -> Security features -> UART ROM download mode -> Permanently disabled`) @@ -62,6 +67,35 @@ For convenience, file `sample_encryption_keys.bin` with a sample of pre-generate #### Configuration for FATFS encryption FATFS encryption example uses two additional partitions in the partition table. Both partitions are of type `data` and subtype `fat`. The first partition `fat_encrypted` has the encrypted flag set, the second partition `fat_not_encr` has the encryption flag off. Both partitions are defined in the partition configuration file `partitions_example.csv` +### Using Key Manager as Flash Encryption Key Source + +> **Note:** This feature is only available on targets with the Key Manager peripheral: **ESP32-C5** and **ESP32-P4**. + +On supported targets, the Flash Encryption key can be deployed into and managed by the [Key Manager](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c5/api-reference/peripherals/key_manager.html) peripheral instead of an eFuse block. This means the plaintext key material is never stored in eFuses, RAM, or flash - it is bound to the device's Hardware Unique Key (HUK) and accessible only to hardware peripherals. + +For the full workflow (key deployment, eFuse programming, and boot sequence), refer to the [Flash Encryption documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c5/security/flash-encryption.html). + +#### Configuration + +Enable Key Manager as the Flash Encryption key source in `menuconfig`: + +``` +menuconfig -> Security features -> Flash Encryption -> Flash Encryption key source -> Key Manager +``` + +This sets `CONFIG_SECURE_FLASH_ENCRYPTION_KEY_SOURCE_KEY_MGR=y`. The CI configuration for this mode is provided in `sdkconfig.ci.key_mgr`. The following snippet shows only the **Key Manager–specific** Flash Encryption configurations; other configurations (e.g., NVS encryption scheme) must be set separately as needed: + +``` +CONFIG_SECURE_FLASH_ENC_ENABLED=y +CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y +CONFIG_SECURE_FLASH_ENCRYPTION_KEY_SOURCE_KEY_MGR=y +CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y +``` + +> **Note on `CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED`:** This option is set in the CI configuration to prevent flash encryption from being accidentally enabled on clean CI runners. When this option is enabled, the bootloader refuses to boot unless flash encryption is already active on the device. **For local development**, you should **disable** this option (set `CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=n`) so that the bootloader can enable flash encryption on the first boot. + +When using the Key Manager, the flash encryption key is deployed via the Key Manager peripheral. If no key recovery info is found in flash, the bootloader will generate a random key and deploy it through the Key Manager. The key recovery info is stored in flash at address `0x0`. + ### Building ``` diff --git a/examples/security/flash_encryption/sdkconfig.ci.key_mgr b/examples/security/flash_encryption/sdkconfig.ci.key_mgr new file mode 100644 index 00000000000..13eba7db8af --- /dev/null +++ b/examples/security/flash_encryption/sdkconfig.ci.key_mgr @@ -0,0 +1,12 @@ +# Configurations for flash encryption. +CONFIG_SECURE_FLASH_ENC_ENABLED=y +CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y +CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC=y +CONFIG_SECURE_BOOT_ALLOW_JTAG=y +CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y +CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=y +CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y +CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y +CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC=y + +CONFIG_SECURE_FLASH_ENCRYPTION_KEY_SOURCE_KEY_MGR=y diff --git a/examples/security/key_manager/CMakeLists.txt b/examples/security/key_manager/CMakeLists.txt new file mode 100644 index 00000000000..699b1d5c56b --- /dev/null +++ b/examples/security/key_manager/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(key_manager) diff --git a/examples/security/key_manager/README.md b/examples/security/key_manager/README.md new file mode 100644 index 00000000000..5a8a2978d73 --- /dev/null +++ b/examples/security/key_manager/README.md @@ -0,0 +1,294 @@ +| Supported Targets | ESP32-C5 | ESP32-P4 | +| ----------------- | -------- | -------- | + +# Key Manager Signing Example + +## Overview + +This example demonstrates how to use the Key Manager peripheral for cryptographic signing operations on Key Manager supported chips. The Key Manager provides secure key deployment and management, allowing keys to be used for cryptographic operations without exposing the raw key material. + +The example showcases two signing use cases: + +1. **ECDSA Signing**: Deploy an ECDSA private key via Key Manager and use it for ECDSA-P256 signature generation through the PSA Crypto API. + +2. **RSA-DS Signing**: Deploy a Digital Signature (DS) key via Key Manager and use it for RSA-3072 signature generation through the PSA Crypto API. + +## Key Manager Concepts + +The Key Manager peripheral provides: + +- **Secure Key Deployment**: Keys can be deployed in different modes (AES, ECDH0, Random) without exposing the raw key material. +- **Key Recovery**: Once deployed, keys can be recovered using the key recovery information for subsequent operations. +- **Hardware Protection**: Keys are protected by hardware and cannot be read back in plaintext. + +### Key Deployment Modes + +This example uses the **AES deployment mode** with pre-generated key material: + +- `sw_init_key`: Software initialization key (32 bytes) +- `k2_info`: K2 information for key derivation (64 bytes) +- `k1_encrypted`: Encrypted K1 key material (32 bytes) + +These parameters are used to derive and deploy the actual cryptographic key inside the Key Manager. + +## How to Use the Example + +### Hardware Required + +This example can be executed on any development board with a Espressif SOC chip supporting the Key Manager peripheral (see Supported Targets table above). + +### Configure the Project + +```bash +idf.py set-target +idf.py menuconfig +``` + +In the menuconfig, you can enable/disable the signing examples: + +- `Key Manager Signing Example Configuration` + - `Enable ECDSA signing example` (default: enabled) + - `Enable RSA-DS signing example` (default: enabled) + +### Build and Flash + +```bash +idf.py build +idf.py -p PORT flash monitor +``` + +(Replace `PORT` with your serial port, e.g., `/dev/ttyUSB0` or `COM3`) + +To exit the serial monitor, type `Ctrl-]`. + +### Key Storage in NVS + +The example stores **key recovery info** in the NVS namespace `key_mgr` so that keys persist across reboots: + +- **First boot** (or after `idf.py erase-flash`): No key is found in NVS, so the example deploys a new key via Key Manager and saves the recovery info to NVS. You will see logs like `No ECDSA key in NVS, deploying new key via Key Manager...`. +- **Later boots** (reset or `idf.py flash monitor` without erase): The example finds the key in NVS and reuses it. You will see `Using existing ECDSA key from NVS` (or DS). + +To force **new keys** to be deployed (e.g. for testing), run erase before flashing: + +```bash +idf.py erase-flash +idf.py -p PORT flash monitor +``` + +After `erase-flash`, the first boot will always deploy and store new keys; subsequent runs without erase will use the stored keys. + +### Verify the flow with idf.py + +From the example directory: + +```bash +cd path/to/esp-idf/examples/security/key_manager + +# Build +idf.py build + +idf.py -p PORT flash + +# Erase the NVS partition to force fresh key deployment on first run +esptool -p PORT --after no-reset erase-region 0x9000 0x6000 + +idf.py -p PORT monitor +# Expect: "No ECDSA key in NVS, deploying new key..." and "No DS key in NVS, deploying new key..." +# Exit monitor with Ctrl+] + +# Second run (reuse path): flash and monitor only (no erase) +idf.py -p PORT monitor +# Expect: "Using existing ECDSA key from NVS" and "Using existing DS key from NVS" +``` + +### Example Output + +#### First Boot + +``` +I (283) key_mgr_sign: ECDSA Signing with Key Manager +I (283) key_mgr_sign: Step 1: No ECDSA key in NVS, deploying new key via Key Manager... +I (293) key_mgr_sign: Key deployed successfully in Key Manager +I (303) key_mgr_sign: Stored key_recovery_info in NVS for key_type "ecdsa" +I (303) key_mgr_sign: Step 2: Creating PSA opaque key reference... +I (313) key_mgr_sign: Step 3: Signing hash using Key Manager key... +I (333) key_mgr_sign: Signature generated successfully (64 bytes) +I (333) key_mgr_sign: Step 4: Verifying signature with known public key... +I (353) key_mgr_sign: ECDSA signature verification PASSED! +I (353) key_mgr_sign: ECDSA Signing Example Complete + +I (353) key_mgr_sign: RSA-DS Signing with Key Manager +I (353) key_mgr_sign: Step 1: No DS key in NVS, deploying new key via Key Manager... +I (373) key_mgr_sign: Key deployed successfully in Key Manager +I (383) key_mgr_sign: Stored key_recovery_info in NVS for key_type "ds" +I (383) key_mgr_sign: Step 2: Preparing DS data context... +I (393) key_mgr_sign: Step 3: Creating PSA opaque key reference for RSA-DS... +I (393) key_mgr_sign: Step 4: Signing hash using RSA-DS with Key Manager key... +I (1563) key_mgr_sign: RSA-DS signature generated successfully (384 bytes) +I (1563) key_mgr_sign: Step 5: Verifying RSA-DS signature with known public key... +I (1573) key_mgr_sign: RSA-DS signature verification PASSED! +I (1573) key_mgr_sign: RSA-DS Signing Example Complete + +I (1573) key_mgr_sign: Key Manager Signing Example finished. +``` + +#### Second Boot + +``` +I (273) key_mgr_sign: Key Manager Signing Example +I (283) key_mgr_sign: ECDSA Signing with Key Manager +I (283) key_mgr_sign: Step 1: Using existing ECDSA key from NVS +I (293) key_mgr_sign: Step 2: Creating PSA opaque key reference... +I (293) key_mgr_sign: Step 3: Signing hash using Key Manager key... +I (313) key_mgr_sign: Signature generated successfully (64 bytes) +I (313) key_mgr_sign: Step 4: Verifying signature with known public key... +I (333) key_mgr_sign: ECDSA signature verification PASSED! +I (333) key_mgr_sign: ECDSA Signing Example Complete + +I (343) key_mgr_sign: RSA-DS Signing with Key Manager +I (353) key_mgr_sign: Step 1: Using existing DS key from NVS +I (353) key_mgr_sign: Step 2: Preparing DS data context... +I (363) key_mgr_sign: Step 3: Creating PSA opaque key reference for RSA-DS... +I (363) key_mgr_sign: Step 4: Signing hash using RSA-DS with Key Manager key... +I (1543) key_mgr_sign: RSA-DS signature generated successfully (384 bytes) +I (1543) key_mgr_sign: Step 5: Verifying RSA-DS signature with known public key... +I (1553) key_mgr_sign: RSA-DS signature verification PASSED! +I (1553) key_mgr_sign: RSA-DS Signing Example Complete + +I (1553) key_mgr_sign: Key Manager Signing Example finished. +``` + +## Code Walkthrough + +### ECDSA Signing Flow + +1. **Deploy Key**: Use `esp_key_mgr_deploy_key_in_aes_mode()` to deploy an ECDSA key. +2. **Create Opaque Key**: Create an `esp_ecdsa_opaque_key_t` structure with the key recovery info. +3. **Import to PSA**: Use `psa_import_key()` with `PSA_KEY_LIFETIME_ESP_ECDSA_VOLATILE` lifetime. +4. **Sign**: Use `psa_sign_hash()` to generate the signature. +5. **Verify**: Import the known ECDSA public key (from `test_data.h`) and use `psa_verify_hash()` to verify the signature. + +### RSA-DS Signing Flow + +1. **Deploy Key**: Use `esp_key_mgr_deploy_key_in_aes_mode()` to deploy a DS (HMAC) key. +2. **Prepare DS Context**: Create `esp_ds_data_t` with IV and encrypted parameters. +3. **Create Opaque Key**: Create an `esp_rsa_ds_opaque_key_t` structure. +4. **Import to PSA**: Use `psa_import_key()` with `PSA_KEY_LIFETIME_ESP_RSA_DS` lifetime. +5. **Sign**: Use `psa_sign_hash()` to generate the RSA signature. +6. **Verify**: Import the known RSA public key (from `test_data.h`) and use `psa_verify_hash()` to verify the signature. + +## Test Data + +The example uses test data generated by `generate_test_data.py` and stored in `main/test_data.h`. + +The included test data was generated with **seed 12345** for ESP32-C5 (default target): + +```bash +python generate_test_data.py --seed 12345 --output-header main/test_data.h +``` + +### Target-Specific RSA Key Sizes + +Different ESP32 chips support different maximum RSA key sizes for the Digital Signature (DS) peripheral: + +| Target | SOC_RSA_MAX_BIT_LEN | RSA Key Size | +|--------|---------------------|--------------| +| ESP32-C5 | 3072 | 3072-bit | +| ESP32-P4 | 4096 | 4096-bit | + +The `--target` option allows generating test data with the correct RSA key size for your target chip. + +### Generating Custom Test Data + +A Python script is provided to generate new test data. When keys are generated (not loaded from files), they are automatically saved to PEM files in the same directory as the output header: +- `ecdsa_private_key.pem`: ECDSA P-256 private key +- `rsa_private_key.pem`: RSA private key (size depends on target) + +#### Basic Usage (Random Keys) + +```bash +# Print test data to stdout (default: ESP32-C5, 3072-bit RSA) +python generate_test_data.py + +# Generate for ESP32-C5 (3072-bit RSA, default) +python generate_test_data.py --seed 12345 --output-header main/test_data.h + +# Generate for ESP32-P4 (4096-bit RSA) +python generate_test_data.py --target esp32p4 --seed 12345 --output-header main/test_data.h + +# Use a different seed for new random keys +python generate_test_data.py --seed 54321 --output-header main/test_data.h +``` + +#### Using Your Own Keys from PEM Files + +You can provide your own ECDSA and/or RSA private keys in PEM format. When a key is loaded from a file, it won't be saved again: + +```bash +# Use your own ECDSA key (only RSA key will be generated and saved) +python generate_test_data.py --ecdsa-key my_ecdsa_key.pem --output-header main/test_data.h + +# Use your own RSA key (only ECDSA key will be generated and saved) +python generate_test_data.py --rsa-key my_rsa_key.pem --output-header main/test_data.h + +# Use both your own keys (no keys will be generated or saved) +python generate_test_data.py --ecdsa-key ecdsa.pem --rsa-key rsa.pem --output-header main/test_data.h + +# Combine with seed for reproducible Key Manager parameters +python generate_test_data.py --seed 12345 --ecdsa-key test/ecdsa_private_key.pem --rsa-key test/rsa_private_key.pem --output-header main/test_data.h +``` + +**Key Requirements:** +- **ECDSA key**: Must be a P-256 (secp256r1) curve private key +- **RSA key**: Must match the target's RSA key size (3072-bit for ESP32-C5, 4096-bit for ESP32-P4) + +**Generating PEM Keys Manually (using OpenSSL):** + +```bash +# Generate ECDSA P-256 key +openssl ecparam -name prime256v1 -genkey -noout -out ecdsa_key.pem + +# Generate RSA 3072-bit key (for ESP32-C5) +openssl genrsa -out rsa_key.pem 3072 + +# Generate RSA 4096-bit key (for ESP32-P4) +openssl genrsa -out rsa_key.pem 4096 +``` + +The script generates: +- **Key Manager parameters**: `init_key`, `k2_info` for AES mode deployment +- **ECDSA key material**: `k1_ecdsa256_encrypt` (encrypted ECDSA private key) +- **DS key material**: `k1_ds_aes_key_encrypt`, `ds_iv`, `ds_c` (encrypted DS parameters) + +> **Note:** The example verifies signatures against known public keys stored in `test_data.h`. When generating custom test data with new keys, you must also export the corresponding public keys and update `main/test_data.h`: +> ```bash +> # Export ECDSA public key (uncompressed point format for ecdsa_public_key[]) +> openssl ec -in ecdsa_private_key.pem -pubout -outform DER -conv_form uncompressed | tail -c 65 | xxd -i +> +> # Export RSA public key (PKCS#1 DER format for rsa_public_key_der[]) +> openssl rsa -in rsa_private_key.pem -RSAPublicKey_out -outform DER | xxd -i +> ``` + +#### How Key Manager Test Data is Generated + +1. **Base Keys**: Random `init_key`, `k2`, and `rand_num` are generated. When `--seed` is provided, all three values are derived from the seeded RNG, making the entire output deterministic and reproducible across runs. Without `--seed`, `os.urandom` is used and every run produces different data. +2. **K2 Info**: Computed as `AES_ECB(init_key, AES_ECB(rand_num, k2) || rand_num)` +3. **K1 Encrypted**: The actual key (ECDSA or DS) is reversed and encrypted with K2 using AES-ECB +4. **DS Parameters**: RSA key parameters are encrypted using AES-CBC with the DS AES key derived from HMAC + +> **Note:** The test data included in the example (`main/test_data.h`) was generated using `--seed 12345` together with the PEM keys stored in the `test/` directory (`test/ecdsa_private_key.pem` and `test/rsa_private_key.pem`). Using the same seed and key files will always produce identical output. + +## Running the Test + +This example includes a pytest that can be run with the ESP-IDF pytest framework: + +```bash +# Run the test on the target +pytest --target +``` + +The test verifies: +- ECDSA key deployment and signing flow +- ECDSA signature verification using the known public key +- RSA-DS key deployment and signing flow +- RSA-DS signature verification using the known public key diff --git a/examples/security/key_manager/generate_test_data.py b/examples/security/key_manager/generate_test_data.py new file mode 100644 index 00000000000..4cd29fb47a2 --- /dev/null +++ b/examples/security/key_manager/generate_test_data.py @@ -0,0 +1,607 @@ +#!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +""" +Generate test data for the Key Manager Signing Example. + +This script generates all the cryptographic test data needed for the example: +1. Key Manager AES mode deployment parameters (init_key, k2_info) +2. ECDSA key material (k1_ecdsa256_encrypt) +3. DS key material and encrypted parameters (k1_ds_aes_key_encrypt, ds_iv, ds_c) + +The generated data can be used to replace the hardcoded values in key_mgr_sign_main.c + +When keys are generated (not loaded from files), they are automatically saved to PEM files +in the same directory as the output header file: +- ecdsa_private_key.pem: ECDSA P-256 private key +- rsa_private_key.pem: RSA private key (size depends on target) + +Target-specific RSA key sizes: +- ESP32-C5: 3072-bit (SOC_RSA_MAX_BIT_LEN = 3072) +- ESP32-P4: 4096-bit (SOC_RSA_MAX_BIT_LEN = 4096) + +Usage: + python generate_test_data.py [--output-header FILENAME] [--target TARGET] + +Options: + --output-header FILENAME Generate a C header file instead of printing to stdout + --seed SEED Random seed for reproducible output (default: random) + --target TARGET Target chip (esp32c5, esp32p4). Determines RSA key size. + Default: esp32c5 (3072-bit RSA) + --ecdsa-key FILE Path to ECDSA private key PEM file to load (P-256 curve) + --rsa-key FILE Path to RSA private key PEM file to load (must match target) + +Examples: + # Generate for ESP32-C5 (3072-bit RSA, default) + python generate_test_data.py --seed 12345 --output-header main/test_data.h + + # Generate for ESP32-P4 (4096-bit RSA) + python generate_test_data.py --target esp32p4 --seed 12345 --output-header main/test_data.h + + # Use existing ECDSA key from PEM file (only RSA key will be generated and saved) + python generate_test_data.py --ecdsa-key my_ecdsa_key.pem --output-header main/test_data.h + + # Use existing RSA key from PEM file (only ECDSA key will be generated and saved) + python generate_test_data.py --rsa-key my_rsa_key.pem --output-header main/test_data.h + + # Use both keys from PEM files (no keys will be generated or saved) + python generate_test_data.py --ecdsa-key ecdsa.pem --rsa-key rsa.pem --output-header main/test_data.h +""" + +import argparse +import hashlib +import hmac +import os +import struct +from collections.abc import Callable + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.asymmetric.rsa import _modinv as modinv # type: ignore +from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers import algorithms +from cryptography.hazmat.primitives.ciphers import modes +from cryptography.utils import int_to_bytes + +# Constants matching ESP-IDF Key Manager +KEY_MGR_K1_ENCRYPTED_SIZE = 32 +KEY_MGR_K2_INFO_SIZE = 64 +KEY_MGR_SW_INIT_KEY_SIZE = 32 + +# DS peripheral constants +ESP_DS_IV_LEN = 16 + +# Target-specific RSA key sizes (SOC_RSA_MAX_BIT_LEN) +# These values match the SOC capabilities defined in soc_caps.h +TARGET_RSA_MAX_BIT_LEN: dict[str, int] = { + 'esp32c5': 3072, + 'esp32p4': 4096, +} + +# Default target and RSA key size +DEFAULT_TARGET = 'esp32c5' +DEFAULT_RSA_KEY_SIZE = TARGET_RSA_MAX_BIT_LEN[DEFAULT_TARGET] + + +def get_rsa_key_size_for_target(target: str) -> int: + """Get the maximum RSA key size for a given target.""" + target_lower = target.lower() + if target_lower not in TARGET_RSA_MAX_BIT_LEN: + raise ValueError(f"Unknown target '{target}'. Supported targets: {', '.join(TARGET_RSA_MAX_BIT_LEN.keys())}") + return TARGET_RSA_MAX_BIT_LEN[target_lower] + + +# ESP_DS_C_LEN calculation: +# (max_key_size * 3 + 256 (MD) + 32 (M_prime) + 32 (length) + 64 (padding)) / 8 +def calculate_ds_c_len(max_key_size: int) -> int: + return (max_key_size * 3 + 256 + 32 + 32 + 64) // 8 + + +def bytes_to_c_array(data: bytes, name: str = '', indent: int = 4) -> str: + """Convert bytes to C array format.""" + indent_str = ' ' * indent + + # Format with line breaks for readability + values = [f'0x{b:02x}' for b in data] + lines = [] + for i in range(0, len(values), 8): + lines.append(indent_str + ', '.join(values[i : i + 8]) + ',') + + if name: + return f'static const uint8_t {name}[] = {{\n' + '\n'.join(lines) + '\n};' + return '{\n' + '\n'.join(lines) + '\n}' + + +def bytes_to_c_array_oneline(data: bytes) -> str: + """Convert bytes to single-line C array format.""" + return '{ ' + ', '.join(f'0x{b:02x}' for b in data) + ' }' + + +def calculate_aes_ecb_encrypt(data: bytes, key: bytes) -> bytes: + """Encrypt data using AES-ECB mode.""" + cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend()) + encryptor = cipher.encryptor() + result: bytes = encryptor.update(data) + encryptor.finalize() + return result + + +def calculate_aes_cbc_encrypt(data: bytes, key: bytes, iv: bytes) -> bytes: + """Encrypt data using AES-CBC mode.""" + cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) + encryptor = cipher.encryptor() + result: bytes = encryptor.update(data) + encryptor.finalize() + return result + + +def number_as_bytes_le(number: int, pad_bits: int = 0) -> bytes: + """Convert number to little-endian bytes with optional padding.""" + result: bytes = int_to_bytes(number)[::-1] # Convert to little endian + while pad_bits != 0 and len(result) < (pad_bits // 8): + result += b'\x00' + return result + + +def load_ecdsa_private_key(pem_file: str) -> bytes: + """ + Load ECDSA private key from PEM file and return the raw private key bytes. + + Args: + pem_file: Path to the PEM file containing an ECDSA P-256 private key + + Returns: + 32-byte raw private key value (big-endian) + + Raises: + ValueError: If the key is not a P-256 ECDSA key + """ + with open(pem_file, 'rb') as f: + pem_data = f.read() + + private_key = serialization.load_pem_private_key(pem_data, password=None, backend=default_backend()) + + if not isinstance(private_key, ec.EllipticCurvePrivateKey): + raise ValueError(f'Expected ECDSA private key, got {type(private_key).__name__}') + + if not isinstance(private_key.curve, ec.SECP256R1): + raise ValueError(f'Expected P-256 (secp256r1) curve, got {private_key.curve.name}') + + # Extract the raw private key value (32 bytes for P-256) + private_numbers = private_key.private_numbers() + private_value = private_numbers.private_value + + # Convert to 32-byte big-endian representation + result: bytes = int_to_bytes(private_value).rjust(32, b'\x00') + return result + + +def load_rsa_private_key(pem_file: str, expected_key_size: int) -> rsa.RSAPrivateKey: + """ + Load RSA private key from PEM file. + + Args: + pem_file: Path to the PEM file containing an RSA private key + expected_key_size: Expected RSA key size in bits (e.g., 3072, 4096) + + Returns: + RSA private key object + + Raises: + ValueError: If the key is not an RSA key or has wrong size + """ + with open(pem_file, 'rb') as f: + pem_data = f.read() + + private_key = serialization.load_pem_private_key(pem_data, password=None, backend=default_backend()) + + if not isinstance(private_key, rsa.RSAPrivateKey): + raise ValueError(f'Expected RSA private key, got {type(private_key).__name__}') + + if private_key.key_size != expected_key_size: + raise ValueError(f'Expected {expected_key_size}-bit RSA key, got {private_key.key_size}-bit') + + return private_key + + +def save_ecdsa_private_key(private_value: bytes, pem_file: str) -> None: + """ + Save ECDSA private key to PEM file. + + Args: + private_value: 32-byte raw private key value (big-endian) + pem_file: Path to save the PEM file + """ + # Convert raw bytes to integer + private_int = int.from_bytes(private_value, byteorder='big') + + # Derive the public key from the private key + private_key = ec.derive_private_key(private_int, ec.SECP256R1(), default_backend()) + + # Serialize to PEM format + pem_data = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ) + + with open(pem_file, 'wb') as f: + f.write(pem_data) + + print(f'Saved ECDSA key to: {pem_file}') + + +def save_rsa_private_key(private_key: rsa.RSAPrivateKey, pem_file: str) -> None: + """ + Save RSA private key to PEM file. + + Args: + private_key: RSA private key object + pem_file: Path to save the PEM file + """ + pem_data = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ) + + with open(pem_file, 'wb') as f: + f.write(pem_data) + + print(f'Saved RSA key to: {pem_file}') + + +def generate_key_manager_params(init_key: bytes, k2: bytes, rand_num: bytes) -> bytes: + """ + Generate K2 info for Key Manager AES mode deployment. + + The K2 info is computed as: + k2_info = AES_ECB(init_key, AES_ECB(rand_num, k2) || rand_num) + """ + temp_result_inner = calculate_aes_ecb_encrypt(k2, rand_num) + k2_info = calculate_aes_ecb_encrypt(temp_result_inner + rand_num, init_key) + return k2_info + + +def generate_k1_encrypted(k1: bytes, k2: bytes) -> bytes: + """ + Generate encrypted K1 for Key Manager. + + K1 is reversed and then encrypted with K2 using AES-ECB. + """ + k1_reversed = k1[::-1] + return calculate_aes_ecb_encrypt(k1_reversed, k2) + + +def generate_ds_aes_key(hmac_key: bytes) -> bytes: + """ + Generate the AES key used for DS parameter encryption. + + The DS AES key is derived from HMAC key: HMAC-SHA256(hmac_key, 0xFF * 32) + """ + return hmac.HMAC(hmac_key, b'\xff' * 32, hashlib.sha256).digest() + + +def generate_ds_encrypted_params(private_key: rsa.RSAPrivateKey, aes_key: bytes, iv: bytes, max_key_size: int) -> bytes: + """ + Generate encrypted DS parameters (the 'C' blob). + + This follows the ESP-IDF DS parameter encryption format. + """ + priv_numbers = private_key.private_numbers() + pub_numbers = private_key.public_key().public_numbers() + + Y = priv_numbers.d # Private exponent + M = pub_numbers.n # Modulus + key_size = private_key.key_size + + # Calculate RSA helper values + rr = 1 << (key_size * 2) + rinv = rr % M + mprime = -modinv(M, 1 << 32) & 0xFFFFFFFF + length = key_size // 32 - 1 + + # Calculate MD (message digest) from parameters and IV + md_in = ( + number_as_bytes_le(Y, max_key_size) + + number_as_bytes_le(M, max_key_size) + + number_as_bytes_le(rinv, max_key_size) + + struct.pack(' dict: + """ + Generate all test data for the Key Manager signing example. + + Args: + seed: Random seed for reproducible output (ignored for keys loaded from files) + target: Target chip name (e.g., 'esp32c5', 'esp32p4'). Determines RSA key size. + ecdsa_key_file: Path to ECDSA private key PEM file to load (P-256 curve) + rsa_key_file: Path to RSA private key PEM file to load (must match target's max RSA size) + save_ecdsa_key_file: Path to save generated ECDSA key as PEM file + save_rsa_key_file: Path to save generated RSA key as PEM file + + Returns: + Dictionary containing all test data arrays + """ + # Get target-specific RSA key size + rsa_key_size = get_rsa_key_size_for_target(target) + print(f'Target: {target} (RSA key size: {rsa_key_size}-bit)') + + urandom: Callable[[int], bytes] + if seed is not None: + import random + + random.seed(seed) + + # Use seeded random for reproducible output + def seeded_urandom(n: int) -> bytes: + return bytes(random.randint(0, 255) for _ in range(n)) + + urandom = seeded_urandom + else: + urandom = os.urandom + + # Generate base keys for Key Manager AES mode + init_key = urandom(KEY_MGR_SW_INIT_KEY_SIZE) + k2 = urandom(32) + rand_num = urandom(32) + + # Generate K2 info + k2_info = generate_key_manager_params(init_key, k2, rand_num) + + # ECDSA key: load from PEM file or generate randomly + ecdsa_key_generated = False + if ecdsa_key_file: + print(f'Loading ECDSA key from: {ecdsa_key_file}') + k1_ecdsa = load_ecdsa_private_key(ecdsa_key_file) + else: + # Generate random ECDSA key (P-256, 32 bytes) + k1_ecdsa = urandom(32) + ecdsa_key_generated = True + k1_ecdsa256_encrypt = generate_k1_encrypted(k1_ecdsa, k2) + + # Save ECDSA key if generated (not loaded from file) + if save_ecdsa_key_file and ecdsa_key_generated: + save_ecdsa_private_key(k1_ecdsa, save_ecdsa_key_file) + + # Generate DS HMAC key and derive AES key + hmac_key_for_ds = urandom(32) + ds_aes_key = generate_ds_aes_key(hmac_key_for_ds) + + # Generate K1 for DS (derived from HMAC key) + k1_ds = generate_ds_aes_key(hmac_key_for_ds) + k1_ds_encrypt = generate_k1_encrypted(k1_ds, k2) + + # RSA key for DS: load from PEM file or generate randomly + rsa_key_generated = False + if rsa_key_file: + print(f'Loading RSA key from: {rsa_key_file}') + rsa_private_key = load_rsa_private_key(rsa_key_file, rsa_key_size) + else: + # Generate random RSA key with target-specific size + rsa_private_key = rsa.generate_private_key( + public_exponent=65537, key_size=rsa_key_size, backend=default_backend() + ) + rsa_key_generated = True + + # Save RSA key if generated (not loaded from file) + if save_rsa_key_file and rsa_key_generated: + save_rsa_private_key(rsa_private_key, save_rsa_key_file) + + # Generate DS IV and encrypted parameters using target's max key size + ds_iv = urandom(ESP_DS_IV_LEN) + ds_c = generate_ds_encrypted_params(rsa_private_key, ds_aes_key, ds_iv, rsa_key_size) + + # Generate a sample SHA-256 hash to sign + sha256_hash = urandom(32) + + return { + 'init_key': init_key, + 'k2_info': k2_info, + 'k1_ecdsa256_encrypt': k1_ecdsa256_encrypt, + 'k1_ds_aes_key_encrypt': k1_ds_encrypt, + 'ds_iv': ds_iv, + 'ds_c': ds_c, + 'sha256_hash': sha256_hash, + # Keep these for reference/debugging + '_target': target, + '_rsa_key_size': rsa_key_size, + '_k2': k2, + '_rand_num': rand_num, + '_k1_ecdsa': k1_ecdsa, + '_hmac_key_for_ds': hmac_key_for_ds, + '_ecdsa_key_file': ecdsa_key_file, + '_rsa_key_file': rsa_key_file, + '_save_ecdsa_key_file': save_ecdsa_key_file if ecdsa_key_generated else None, + '_save_rsa_key_file': save_rsa_key_file if rsa_key_generated else None, + } + + +def print_test_data(data: dict) -> None: + """Print test data in a format suitable for copying into C code.""" + target = data.get('_target', DEFAULT_TARGET) + rsa_key_size = data.get('_rsa_key_size', DEFAULT_RSA_KEY_SIZE) + + print('/*') + print(' * Auto-generated test data for Key Manager Signing Example') + print(' * Generated by generate_test_data.py') + print(f' * Target: {target} (RSA key size: {rsa_key_size}-bit)') + print(' */') + print() + + print('/* SHA-256 hash to sign */') + print(bytes_to_c_array(data['sha256_hash'], 'sha256_hash')) + print() + + print('/* Software init key for Key Manager AES mode deployment */') + print(bytes_to_c_array(data['init_key'], 'init_key')) + print() + + print('/* K2 info for Key Manager AES mode deployment */') + print(bytes_to_c_array(data['k2_info'], 'k2_info')) + print() + + print('#if CONFIG_EXAMPLE_KEY_MGR_ECDSA_SIGN') + print('/* K1 encrypted for ECDSA P-256 key */') + print(bytes_to_c_array(data['k1_ecdsa256_encrypt'], 'k1_ecdsa256_encrypt')) + print('#endif /* CONFIG_EXAMPLE_KEY_MGR_ECDSA_SIGN */') + print() + + print('#if CONFIG_EXAMPLE_KEY_MGR_RSA_DS_SIGN') + print(f'/* K1 encrypted for DS (AES) key - RSA {rsa_key_size}-bit */') + print(bytes_to_c_array(data['k1_ds_aes_key_encrypt'], 'k1_ds_aes_key_encrypt')) + print() + + print(f'static const uint8_t ds_iv[{ESP_DS_IV_LEN}] = {bytes_to_c_array_oneline(data["ds_iv"])};') + print(f'static const uint8_t ds_c[{len(data["ds_c"])}] = {bytes_to_c_array_oneline(data["ds_c"])};') + print('#endif /* CONFIG_EXAMPLE_KEY_MGR_RSA_DS_SIGN */') + + +def generate_header_file(data: dict, filename: str, seed: int | None = None) -> None: + """Generate a C header file with the test data.""" + target = data.get('_target', DEFAULT_TARGET) + rsa_key_size = data.get('_rsa_key_size', DEFAULT_RSA_KEY_SIZE) + + with open(filename, 'w') as f: + f.write('/*\n') + f.write(' * Auto-generated test data for Key Manager Signing Example\n') + f.write(' * Generated by generate_test_data.py\n') + f.write(' *\n') + # Add generation parameters info + gen_info = [] + gen_info.append(f'target: {target}') + gen_info.append(f'RSA key size: {rsa_key_size}-bit') + if seed is not None: + gen_info.append(f'seed: {seed}') + if data.get('_ecdsa_key_file'): + gen_info.append(f'ECDSA key loaded from: {data["_ecdsa_key_file"]}') + elif data.get('_save_ecdsa_key_file'): + gen_info.append(f'ECDSA key saved to: {data["_save_ecdsa_key_file"]}') + if data.get('_rsa_key_file'): + gen_info.append(f'RSA key loaded from: {data["_rsa_key_file"]}') + elif data.get('_save_rsa_key_file'): + gen_info.append(f'RSA key saved to: {data["_save_rsa_key_file"]}') + if gen_info: + f.write(' * Generation parameters:\n') + for info in gen_info: + f.write(f' * {info}\n') + f.write(' *\n') + f.write(' * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n') + f.write(' * SPDX-License-Identifier: Unlicense OR CC0-1.0\n') + f.write(' */\n\n') + f.write('#pragma once\n\n') + f.write('#include \n') + f.write('#include "sdkconfig.h"\n') + f.write('#include "esp_ds.h"\n\n') + + f.write('/* SHA-256 hash to sign */\n') + f.write(bytes_to_c_array(data['sha256_hash'], 'sha256_hash') + '\n\n') + + f.write('/* Software init key for Key Manager AES mode deployment */\n') + f.write(bytes_to_c_array(data['init_key'], 'init_key') + '\n\n') + + f.write('/* K2 info for Key Manager AES mode deployment */\n') + f.write(bytes_to_c_array(data['k2_info'], 'k2_info') + '\n\n') + + f.write('#if CONFIG_EXAMPLE_KEY_MGR_ECDSA_SIGN\n') + f.write('/* K1 encrypted for ECDSA P-256 key */\n') + f.write(bytes_to_c_array(data['k1_ecdsa256_encrypt'], 'k1_ecdsa256_encrypt') + '\n') + f.write('#endif /* CONFIG_EXAMPLE_KEY_MGR_ECDSA_SIGN */\n\n') + + f.write('#if CONFIG_EXAMPLE_KEY_MGR_RSA_DS_SIGN\n') + f.write(f'/* K1 encrypted for DS (AES) key - RSA {rsa_key_size}-bit */\n') + f.write(bytes_to_c_array(data['k1_ds_aes_key_encrypt'], 'k1_ds_aes_key_encrypt') + '\n\n') + + f.write(f'static const uint8_t ds_iv[ESP_DS_IV_LEN] = {bytes_to_c_array_oneline(data["ds_iv"])};\n') + f.write(f'static const uint8_t ds_c[ESP_DS_C_LEN] = {bytes_to_c_array_oneline(data["ds_c"])};\n') + f.write('#endif /* CONFIG_EXAMPLE_KEY_MGR_RSA_DS_SIGN */\n') + + print(f'Generated header file: {filename}') + + +def main() -> None: + parser = argparse.ArgumentParser( + description='Generate test data for the Key Manager Signing Example', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=__doc__, + ) + parser.add_argument( + '--output-header', type=str, metavar='FILENAME', help='Generate a C header file with the test data' + ) + parser.add_argument('--seed', type=int, default=None, help='Random seed for reproducible output') + parser.add_argument( + '--target', + type=str, + default=DEFAULT_TARGET, + choices=list(TARGET_RSA_MAX_BIT_LEN.keys()), + help=f'Target chip (determines RSA key size). Default: {DEFAULT_TARGET}', + ) + parser.add_argument( + '--ecdsa-key', + type=str, + metavar='FILE', + help='Path to ECDSA private key PEM file to load (P-256/secp256r1 curve)', + ) + parser.add_argument( + '--rsa-key', + type=str, + metavar='FILE', + help='Path to RSA private key PEM file to load (must match target RSA size)', + ) + + args = parser.parse_args() + + # Determine output directory for generated key files + if args.output_header: + output_dir = os.path.dirname(args.output_header) + if not output_dir: + output_dir = '.' + else: + output_dir = '.' + + # Set default paths for saving generated keys + save_ecdsa_key = None if args.ecdsa_key else os.path.join(output_dir, 'ecdsa_private_key.pem') + save_rsa_key = None if args.rsa_key else os.path.join(output_dir, 'rsa_private_key.pem') + + data = generate_test_data( + seed=args.seed, + target=args.target, + ecdsa_key_file=args.ecdsa_key, + rsa_key_file=args.rsa_key, + save_ecdsa_key_file=save_ecdsa_key, + save_rsa_key_file=save_rsa_key, + ) + + if args.output_header: + generate_header_file(data, args.output_header, seed=args.seed) + else: + print_test_data(data) + + +if __name__ == '__main__': + main() diff --git a/examples/security/key_manager/main/CMakeLists.txt b/examples/security/key_manager/main/CMakeLists.txt new file mode 100644 index 00000000000..a1f4204944e --- /dev/null +++ b/examples/security/key_manager/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "key_mgr_sign_main.c" + PRIV_REQUIRES esp_security mbedtls nvs_flash + INCLUDE_DIRS ".") diff --git a/examples/security/key_manager/main/Kconfig.projbuild b/examples/security/key_manager/main/Kconfig.projbuild new file mode 100644 index 00000000000..998847b239b --- /dev/null +++ b/examples/security/key_manager/main/Kconfig.projbuild @@ -0,0 +1,22 @@ +menu "Key Manager Signing Example Configuration" + + config EXAMPLE_KEY_MGR_ECDSA_SIGN + bool "Enable ECDSA signing example" + default y + depends on SOC_KEY_MANAGER_SUPPORTED && SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY + help + Enable the ECDSA signing example using Key Manager deployed key. + This demonstrates deploying an ECDSA private key via Key Manager + and using it for signing operations through the PSA Crypto API. + + config EXAMPLE_KEY_MGR_RSA_DS_SIGN + bool "Enable RSA-DS signing example" + default y + depends on SOC_KEY_MANAGER_SUPPORTED && SOC_KEY_MANAGER_DS_KEY_DEPLOY + help + Enable the RSA Digital Signature (DS) signing example using + Key Manager deployed key. This demonstrates deploying a DS key + via Key Manager and using it for RSA signing operations through + the PSA Crypto API. + +endmenu diff --git a/examples/security/key_manager/main/key_mgr_sign_main.c b/examples/security/key_manager/main/key_mgr_sign_main.c new file mode 100644 index 00000000000..e684e51fca4 --- /dev/null +++ b/examples/security/key_manager/main/key_mgr_sign_main.c @@ -0,0 +1,543 @@ +/* + * Key Manager Signing Example + * + * Demonstrates ECDSA and RSA-DS signing operations using keys deployed + * via the Key Manager peripheral on Key Manager supported targets + * + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include + +#include "esp_log.h" +#include "esp_err.h" +#include "nvs_flash.h" + +#include "soc/soc_caps.h" +#include "psa/crypto.h" + +#if SOC_KEY_MANAGER_SUPPORTED +#include "esp_key_mgr.h" +#endif + +#if SOC_ECDSA_SUPPORTED +#include "psa_crypto_driver_esp_ecdsa.h" +#endif + +#if SOC_DIG_SIGN_SUPPORTED +#include "psa_crypto_driver_esp_rsa_ds.h" +#endif + +#define HASH_LEN 32 +#define ECDSA_COMPONENT_LEN 32 +#define ECDSA_UNCOMPRESSED_POINT_FORMAT 0x04 + +/* + * Test data generated by generate_test_data.py (seed: 12345) + * See README.md for instructions on regenerating this data. + */ +#include "test_data.h" + +#if CONFIG_EXAMPLE_KEY_MGR_RSA_DS_SIGN +/* Use target-specific RSA key size from SOC capabilities */ +#define RSA_KEY_BITS SOC_RSA_MAX_BIT_LEN +#define RSA_KEY_BYTES (RSA_KEY_BITS / 8) +/* Convert RSA key bits to esp_digital_signature_length_t enum value */ +#define RSA_DS_LENGTH ((RSA_KEY_BITS / 32) - 1) +#endif /* CONFIG_EXAMPLE_KEY_MGR_RSA_DS_SIGN */ + +static const char *TAG = "key_mgr_sign"; + +#define NVS_KEY_MGR_NAMESPACE "key_mgr" + +#if SOC_KEY_MANAGER_SUPPORTED + +/** + * @brief Get NVS key string for a given key type (for "key_type" -> "key_recovery_info" storage) + */ +static const char *key_type_to_nvs_key(esp_key_mgr_key_type_t key_type) +{ + switch (key_type) { + case ESP_KEY_MGR_ECDSA_KEY: + return "ecdsa"; + case ESP_KEY_MGR_DS_KEY: + return "ds"; + default: + return "unknown"; + } +} + +/** + * @brief Load key recovery info from NVS if present + * + * @param key_type Key type (used as NVS key name) + * @param key_recovery_info Output buffer to fill (must be at least sizeof(esp_key_mgr_key_recovery_info_t)) + * @return ESP_OK if loaded, ESP_ERR_NVS_NOT_FOUND if no key stored, or other error + */ +static esp_err_t load_key_recovery_info_from_nvs(esp_key_mgr_key_type_t key_type, + esp_key_mgr_key_recovery_info_t *key_recovery_info) +{ + nvs_handle_t handle; + esp_err_t err = nvs_open(NVS_KEY_MGR_NAMESPACE, NVS_READONLY, &handle); + if (err != ESP_OK) { + /* ESP_ERR_NVS_NOT_FOUND = namespace "key_mgr" does not exist yet (e.g. after erase_flash) */ + if (err != ESP_ERR_NVS_NOT_FOUND) { + ESP_LOGE(TAG, "Failed to open NVS namespace: 0x%x", err); + } + return err; + } + + /* Get the blob size first */ + size_t required_size = 0; + err = nvs_get_blob(handle, key_type_to_nvs_key(key_type), NULL, &required_size); + if (err == ESP_ERR_NVS_NOT_FOUND) { + nvs_close(handle); + return ESP_ERR_NVS_NOT_FOUND; + } + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to get key_recovery_info size from NVS: 0x%x", err); + nvs_close(handle); + return err; + } + if (required_size != sizeof(esp_key_mgr_key_recovery_info_t)) { + ESP_LOGE(TAG, "Invalid key_recovery_info size in NVS (expected %zu, got %zu)", + sizeof(esp_key_mgr_key_recovery_info_t), required_size); + nvs_close(handle); + return ESP_ERR_INVALID_SIZE; + } + + err = nvs_get_blob(handle, key_type_to_nvs_key(key_type), key_recovery_info, &required_size); + nvs_close(handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to read key_recovery_info from NVS: 0x%x", err); + return err; + } + + return ESP_OK; +} + +/** + * @brief Store key recovery info in NVS under key "key_type" -> blob + * + * @param key_type Key type (used as NVS key name) + * @param key_recovery_info Recovery info to store + * @return ESP_OK on success + */ +static esp_err_t save_key_recovery_info_to_nvs(esp_key_mgr_key_type_t key_type, + const esp_key_mgr_key_recovery_info_t *key_recovery_info) +{ + nvs_handle_t handle; + esp_err_t err = nvs_open(NVS_KEY_MGR_NAMESPACE, NVS_READWRITE, &handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to open NVS namespace: 0x%x", err); + return err; + } + + err = nvs_set_blob(handle, key_type_to_nvs_key(key_type), key_recovery_info, + sizeof(esp_key_mgr_key_recovery_info_t)); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to write key_recovery_info to NVS: 0x%x", err); + nvs_close(handle); + return err; + } + + err = nvs_commit(handle); + nvs_close(handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to commit NVS: 0x%x", err); + return err; + } + ESP_LOGI(TAG, "Stored key_recovery_info in NVS for key_type \"%s\"", key_type_to_nvs_key(key_type)); + return ESP_OK; +} + +/** + * @brief Deploy a key using Key Manager in AES mode + * + * @param k1_encrypted Pointer to the encrypted K1 key material + * @param k1_encrypted_len Length of k1_encrypted (must be >= KEY_MGR_K1_ENCRYPTED_SIZE) + * @param key_type Type of key to deploy (ECDSA, DS, etc.) + * @param key_len Length of the key (for ECDSA keys) + * @param key_recovery_info Output: Key recovery information for later use + * @return esp_err_t ESP_OK on success + */ +static esp_err_t deploy_key_in_key_manager(const uint8_t *k1_encrypted, + size_t k1_encrypted_len, + esp_key_mgr_key_type_t key_type, + esp_key_mgr_key_len_t key_len, + esp_key_mgr_key_recovery_info_t *key_recovery_info) +{ + esp_key_mgr_aes_key_config_t *key_config = NULL; + esp_err_t ret = ESP_FAIL; + + /* Verify sizes before memcpy to avoid buffer overflows */ + if (sizeof(k2_info) < KEY_MGR_K2_INFO_SIZE) { + ESP_LOGE(TAG, "k2_info size mismatch (need %d, have %u)", KEY_MGR_K2_INFO_SIZE, sizeof(k2_info)); + return ESP_ERR_INVALID_SIZE; + } + if (k1_encrypted_len < KEY_MGR_K1_ENCRYPTED_SIZE) { + ESP_LOGE(TAG, "k1_encrypted size too small (need %d, have %u)", KEY_MGR_K1_ENCRYPTED_SIZE, k1_encrypted_len); + return ESP_ERR_INVALID_SIZE; + } + if (sizeof(init_key) < KEY_MGR_SW_INIT_KEY_SIZE) { + ESP_LOGE(TAG, "init_key size mismatch (need %d, have %u)", KEY_MGR_SW_INIT_KEY_SIZE, sizeof(init_key)); + return ESP_ERR_INVALID_SIZE; + } + + key_config = calloc(1, sizeof(esp_key_mgr_aes_key_config_t)); + if (key_config == NULL) { + ESP_LOGE(TAG, "Failed to allocate memory for key config"); + return ESP_ERR_NO_MEM; + } + + key_config->key_type = key_type; + key_config->key_len = key_len; + key_config->use_pre_generated_sw_init_key = 1; + memcpy(key_config->k2_info, (uint8_t *)k2_info, KEY_MGR_K2_INFO_SIZE); + memcpy(key_config->k1_encrypted[0], (uint8_t *)k1_encrypted, KEY_MGR_K1_ENCRYPTED_SIZE); + memcpy(key_config->sw_init_key, (uint8_t *)init_key, KEY_MGR_SW_INIT_KEY_SIZE); + + ret = esp_key_mgr_deploy_key_in_aes_mode(key_config, key_recovery_info); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to deploy key in Key Manager: 0x%x", ret); + } else { + ESP_LOGI(TAG, "Key deployed successfully in Key Manager"); + } + + free(key_config); + return ret; +} + +#if CONFIG_EXAMPLE_KEY_MGR_ECDSA_SIGN +/** + * @brief Demonstrate ECDSA signing using Key Manager deployed key + * + * This function: + * 1. Deploys an ECDSA key using Key Manager + * 2. Creates a PSA opaque key reference + * 3. Signs a hash using psa_sign_hash() + * 4. Verifies the signature using the known ECDSA public key + */ +static void example_ecdsa_sign_with_key_manager(void) +{ + ESP_LOGI(TAG, "ECDSA Signing with Key Manager"); + + esp_err_t ret; + psa_status_t status; + + /* Allocate key recovery info */ + esp_key_mgr_key_recovery_info_t *key_recovery_info = NULL; + key_recovery_info = calloc(1, sizeof(esp_key_mgr_key_recovery_info_t)); + if (key_recovery_info == NULL) { + ESP_LOGE(TAG, "Failed to allocate memory for key recovery info"); + return; + } + + /* Step 1: Use existing key from NVS or deploy new ECDSA key and store in NVS */ + ret = load_key_recovery_info_from_nvs(ESP_KEY_MGR_ECDSA_KEY, key_recovery_info); + if (ret == ESP_ERR_NVS_NOT_FOUND) { + ESP_LOGI(TAG, "Step 1: No ECDSA key in NVS, deploying new key via Key Manager..."); + ret = deploy_key_in_key_manager(k1_ecdsa256_encrypt, sizeof(k1_ecdsa256_encrypt), ESP_KEY_MGR_ECDSA_KEY, + ESP_KEY_MGR_ECDSA_LEN_256, key_recovery_info); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to deploy ECDSA key"); + goto cleanup; + } + ret = save_key_recovery_info_to_nvs(ESP_KEY_MGR_ECDSA_KEY, key_recovery_info); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to store key_recovery_info in NVS"); + goto cleanup; + } + } else if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to load key_recovery_info from NVS: 0x%x", ret); + goto cleanup; + } else { + ESP_LOGI(TAG, "Step 1: Using existing ECDSA key from NVS"); + } + + /* Step 2: Create PSA opaque key reference */ + ESP_LOGI(TAG, "Step 2: Creating PSA opaque key reference..."); + + esp_ecdsa_opaque_key_t opaque_key = { + .curve = ESP_ECDSA_CURVE_SECP256R1, + .key_recovery_info = key_recovery_info, + }; + + psa_key_id_t priv_key_id = 0; + psa_key_attributes_t priv_attr = PSA_KEY_ATTRIBUTES_INIT; + + psa_set_key_type(&priv_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&priv_attr, 256); + psa_set_key_usage_flags(&priv_attr, PSA_KEY_USAGE_SIGN_HASH); + psa_set_key_algorithm(&priv_attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_lifetime(&priv_attr, PSA_KEY_LIFETIME_ESP_ECDSA_VOLATILE); + + status = psa_import_key(&priv_attr, (uint8_t *)&opaque_key, sizeof(opaque_key), &priv_key_id); + psa_reset_key_attributes(&priv_attr); + + if (status != PSA_SUCCESS) { + ESP_LOGE(TAG, "Failed to import opaque key: %d", (int)status); + goto cleanup; + } + + /* Step 3: Sign the hash */ + ESP_LOGI(TAG, "Step 3: Signing hash using Key Manager key..."); + + uint8_t signature[2 * ECDSA_COMPONENT_LEN]; + size_t signature_len = 0; + + status = psa_sign_hash(priv_key_id, + PSA_ALG_ECDSA(PSA_ALG_SHA_256), + sha256_hash, HASH_LEN, + signature, sizeof(signature), + &signature_len); + + if (status != PSA_SUCCESS) { + ESP_LOGE(TAG, "Failed to sign hash: %d", (int)status); + psa_destroy_key(priv_key_id); + goto cleanup; + } + + ESP_LOGI(TAG, "Signature generated successfully (%" PRIu32 " bytes)", (uint32_t)signature_len); + ESP_LOG_BUFFER_HEX_LEVEL(TAG, signature, signature_len, ESP_LOG_DEBUG); + + /* Cleanup opaque key */ + psa_destroy_key(priv_key_id); + + /* Step 4: Verify the signature using the known ECDSA public key */ + ESP_LOGI(TAG, "Step 4: Verifying signature with known public key..."); + + psa_key_id_t pub_key_id = 0; + psa_key_attributes_t pub_key_attr = PSA_KEY_ATTRIBUTES_INIT; + + psa_set_key_type(&pub_key_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_usage_flags(&pub_key_attr, PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_algorithm(&pub_key_attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_lifetime(&pub_key_attr, PSA_KEY_LIFETIME_VOLATILE); + + status = psa_import_key(&pub_key_attr, ecdsa_public_key, sizeof(ecdsa_public_key), &pub_key_id); + psa_reset_key_attributes(&pub_key_attr); + if (status != PSA_SUCCESS) { + ESP_LOGE(TAG, "Failed to import ECDSA public key: %d", (int)status); + goto cleanup; + } + + status = psa_verify_hash(pub_key_id, PSA_ALG_ECDSA(PSA_ALG_SHA_256), + sha256_hash, HASH_LEN, signature, signature_len); + + psa_destroy_key(pub_key_id); + + if (status != PSA_SUCCESS) { + ESP_LOGE(TAG, "ECDSA signature verification failed: %d", (int)status); + goto cleanup; + } + + ESP_LOGI(TAG, "ECDSA signature verification PASSED!"); + +cleanup: + free(key_recovery_info); + ESP_LOGI(TAG, "ECDSA Signing Example Complete\n"); +} +#endif /* CONFIG_EXAMPLE_KEY_MGR_ECDSA_SIGN */ + +#if CONFIG_EXAMPLE_KEY_MGR_RSA_DS_SIGN +/** + * @brief Demonstrate RSA-DS signing using Key Manager deployed key + * + * This function: + * 1. Deploys a DS (HMAC) key using Key Manager + * 2. Prepares DS data context + * 3. Creates a PSA opaque key reference for RSA-DS + * 4. Signs a hash using psa_sign_hash() + * 5. Verifies the signature using the known RSA public key + */ +static void example_rsa_ds_sign_with_key_manager(void) +{ + ESP_LOGI(TAG, "RSA-DS Signing with Key Manager"); + + esp_err_t ret; + psa_status_t status; + + /* Allocate key recovery info */ + esp_key_mgr_key_recovery_info_t *key_recovery_info = NULL; + key_recovery_info = calloc(1, sizeof(esp_key_mgr_key_recovery_info_t)); + if (key_recovery_info == NULL) { + ESP_LOGE(TAG, "Failed to allocate memory for key recovery info"); + return; + } + + /* Step 1: Use existing key from NVS or deploy new DS key and store in NVS */ + ret = load_key_recovery_info_from_nvs(ESP_KEY_MGR_DS_KEY, key_recovery_info); + if (ret == ESP_ERR_NVS_NOT_FOUND) { + ESP_LOGI(TAG, "Step 1: No DS key in NVS, deploying new key via Key Manager..."); + ret = deploy_key_in_key_manager(k1_ds_aes_key_encrypt, sizeof(k1_ds_aes_key_encrypt), ESP_KEY_MGR_DS_KEY, 0, key_recovery_info); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to deploy DS key"); + goto cleanup; + } + ret = save_key_recovery_info_to_nvs(ESP_KEY_MGR_DS_KEY, key_recovery_info); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to store key_recovery_info in NVS"); + goto cleanup; + } + } else if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to load key_recovery_info from NVS: 0x%x", ret); + goto cleanup; + } else { + ESP_LOGI(TAG, "Step 1: Using existing DS key from NVS"); + } + + /* Step 2: Prepare DS data context */ + ESP_LOGI(TAG, "Step 2: Preparing DS data context..."); + + esp_ds_data_t *ds_data = calloc(1, sizeof(esp_ds_data_t)); + if (ds_data == NULL) { + ESP_LOGE(TAG, "Failed to allocate memory for DS data"); + goto cleanup; + } + + ds_data->rsa_length = RSA_DS_LENGTH; + memcpy(ds_data->iv, ds_iv, ESP_DS_IV_LEN); + memcpy(ds_data->c, ds_c, ESP_DS_C_LEN); + + esp_ds_data_ctx_t ds_data_ctx = { + .esp_ds_data = ds_data, + .rsa_length_bits = RSA_KEY_BITS, + }; + + esp_rsa_ds_opaque_key_t rsa_ds_opaque_key = { + .ds_data_ctx = &ds_data_ctx, + .key_recovery_info = key_recovery_info, + }; + + /* Step 3: Create PSA opaque key reference for RSA-DS */ + ESP_LOGI(TAG, "Step 3: Creating PSA opaque key reference for RSA-DS..."); + + psa_key_id_t ds_key_id = 0; + psa_key_attributes_t ds_key_attr = PSA_KEY_ATTRIBUTES_INIT; + + psa_set_key_type(&ds_key_attr, PSA_KEY_TYPE_RSA_KEY_PAIR); + psa_set_key_bits(&ds_key_attr, RSA_KEY_BITS); + psa_set_key_usage_flags(&ds_key_attr, PSA_KEY_USAGE_SIGN_HASH); + psa_set_key_algorithm(&ds_key_attr, PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256)); + psa_set_key_lifetime(&ds_key_attr, PSA_KEY_LIFETIME_ESP_RSA_DS_VOLATILE); + + status = psa_import_key(&ds_key_attr, + (const uint8_t *)&rsa_ds_opaque_key, + sizeof(rsa_ds_opaque_key), + &ds_key_id); + if (status != PSA_SUCCESS) { + ESP_LOGE(TAG, "Failed to import RSA-DS opaque key: %d", (int)status); + free(ds_data); + goto cleanup; + } + + /* Step 4: Sign the hash using RSA-DS */ + ESP_LOGI(TAG, "Step 4: Signing hash using RSA-DS with Key Manager key..."); + + uint8_t *rsa_signature = calloc(1, RSA_KEY_BYTES); + if (rsa_signature == NULL) { + ESP_LOGE(TAG, "Failed to allocate memory for RSA signature"); + psa_destroy_key(ds_key_id); + free(ds_data); + goto cleanup; + } + + size_t rsa_signature_len = 0; + + status = psa_sign_hash(ds_key_id, + PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256), + sha256_hash, HASH_LEN, + rsa_signature, RSA_KEY_BYTES, + &rsa_signature_len); + + if (status != PSA_SUCCESS) { + ESP_LOGE(TAG, "Failed to sign hash with RSA-DS: %d", (int)status); + psa_destroy_key(ds_key_id); + psa_reset_key_attributes(&ds_key_attr); + free(rsa_signature); + free(ds_data); + goto cleanup; + } + + ESP_LOGI(TAG, "RSA-DS signature generated successfully (%" PRIu32 " bytes)", (uint32_t)rsa_signature_len); + ESP_LOG_BUFFER_HEX_LEVEL(TAG, rsa_signature, rsa_signature_len, ESP_LOG_DEBUG); + + /* Cleanup DS opaque key */ + psa_destroy_key(ds_key_id); + psa_reset_key_attributes(&ds_key_attr); + free(ds_data); + + /* Step 5: Verify the signature using the known RSA public key */ + ESP_LOGI(TAG, "Step 5: Verifying RSA-DS signature with known public key..."); + + psa_key_id_t rsa_pub_key_id = 0; + psa_key_attributes_t rsa_pub_key_attr = PSA_KEY_ATTRIBUTES_INIT; + + psa_set_key_type(&rsa_pub_key_attr, PSA_KEY_TYPE_RSA_PUBLIC_KEY); + psa_set_key_bits(&rsa_pub_key_attr, RSA_KEY_BITS); + psa_set_key_usage_flags(&rsa_pub_key_attr, PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_algorithm(&rsa_pub_key_attr, PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256)); + psa_set_key_lifetime(&rsa_pub_key_attr, PSA_KEY_LIFETIME_VOLATILE); + + status = psa_import_key(&rsa_pub_key_attr, rsa_public_key_der, sizeof(rsa_public_key_der), &rsa_pub_key_id); + psa_reset_key_attributes(&rsa_pub_key_attr); + + if (status != PSA_SUCCESS) { + ESP_LOGE(TAG, "Failed to import RSA public key: %d", (int)status); + free(rsa_signature); + goto cleanup; + } + + status = psa_verify_hash(rsa_pub_key_id, PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256), + sha256_hash, HASH_LEN, rsa_signature, rsa_signature_len); + + psa_destroy_key(rsa_pub_key_id); + free(rsa_signature); + + if (status != PSA_SUCCESS) { + ESP_LOGE(TAG, "RSA-DS signature verification failed: %d", (int)status); + goto cleanup; + } + + ESP_LOGI(TAG, "RSA-DS signature verification PASSED!"); + +cleanup: + free(key_recovery_info); + ESP_LOGI(TAG, "RSA-DS Signing Example Complete\n"); +} +#endif /* CONFIG_EXAMPLE_KEY_MGR_RSA_DS_SIGN */ + +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + +void app_main(void) +{ + ESP_LOGI(TAG, "Key Manager Signing Example"); + +#if !SOC_KEY_MANAGER_SUPPORTED + ESP_LOGE(TAG, "Key Manager is not supported on this chip!"); + return; +#endif /* SOC_KEY_MANAGER_SUPPORTED */ + + /* Initialize NVS (required for storing key_recovery_info) */ + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + +#if CONFIG_EXAMPLE_KEY_MGR_ECDSA_SIGN + example_ecdsa_sign_with_key_manager(); +#endif + +#if CONFIG_EXAMPLE_KEY_MGR_RSA_DS_SIGN + example_rsa_ds_sign_with_key_manager(); +#endif + + ESP_LOGI(TAG, "Key Manager Signing Example finished."); +} diff --git a/examples/security/key_manager/main/test_data.h b/examples/security/key_manager/main/test_data.h new file mode 100644 index 00000000000..6d344fa4bb2 --- /dev/null +++ b/examples/security/key_manager/main/test_data.h @@ -0,0 +1,138 @@ +/* + * Auto-generated test data for Key Manager Signing Example + * Generated by generate_test_data.py + * + * Generation parameters: + * target: esp32c5 + * RSA key size: 3072-bit + * seed: 12345 + * ECDSA key loaded from: test/ecdsa_private_key.pem + * RSA key loaded from: test/rsa_private_key.pem + * + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#pragma once + +#include +#include "sdkconfig.h" +#include "esp_ds.h" + +/* SHA-256 hash to sign */ +static const uint8_t sha256_hash[] = { + 0x87, 0x9f, 0xfc, 0xf5, 0x19, 0x87, 0xe4, 0x0f, + 0x70, 0xb0, 0x45, 0x01, 0x2a, 0x0f, 0x38, 0x60, + 0xcb, 0xfb, 0x5d, 0x8b, 0xb2, 0x6a, 0x99, 0xa1, + 0xc6, 0x26, 0x9a, 0xbc, 0x14, 0xd6, 0x61, 0x52, +}; + +/* Software init key for Key Manager AES mode deployment */ +static const uint8_t init_key[] = { + 0xd5, 0x05, 0x98, 0xbc, 0x63, 0x8a, 0xdf, 0x52, + 0xbf, 0x3f, 0xdd, 0x85, 0x59, 0x5f, 0xb5, 0x2e, + 0xd3, 0x55, 0x4b, 0x69, 0x27, 0x61, 0xae, 0xa4, + 0x0c, 0xea, 0xad, 0x0d, 0xd4, 0x01, 0x03, 0x53, +}; + +/* K2 info for Key Manager AES mode deployment */ +static const uint8_t k2_info[] = { + 0x2e, 0x1c, 0xda, 0x62, 0x2c, 0x41, 0xc1, 0xb6, + 0x67, 0x92, 0xfd, 0xe1, 0x99, 0xe2, 0x0d, 0x8c, + 0x89, 0x6c, 0x37, 0x79, 0x14, 0xdd, 0x82, 0x16, + 0xbd, 0xed, 0xdf, 0x12, 0xf8, 0xaa, 0x93, 0x28, + 0x1d, 0x8e, 0xc2, 0x7a, 0x6d, 0xd6, 0xaa, 0x85, + 0x75, 0x37, 0x48, 0x30, 0xae, 0xad, 0xe5, 0xf0, + 0xbd, 0x34, 0xa4, 0xc9, 0x33, 0x0b, 0x6b, 0x33, + 0xe2, 0xa9, 0xcc, 0x53, 0xa0, 0xa2, 0x6b, 0x5f, +}; + +#if CONFIG_EXAMPLE_KEY_MGR_ECDSA_SIGN +/* ECDSA P-256 public key in uncompressed point format (0x04 || X || Y) for signature verification */ +static const uint8_t ecdsa_public_key[] = { + 0x04, 0xab, 0x2c, 0x7a, 0x07, 0x2e, 0x4f, 0x8c, + 0xdf, 0xa0, 0xdc, 0x22, 0xfa, 0x99, 0xc2, 0x81, + 0x6e, 0xea, 0x3b, 0x9c, 0x77, 0x0c, 0x01, 0x92, + 0xa0, 0xc0, 0x4b, 0xe8, 0x45, 0xbe, 0xe2, 0xc7, + 0x3e, 0xf6, 0xf7, 0x11, 0x1d, 0xed, 0x47, 0x7e, + 0x22, 0x71, 0x13, 0xad, 0x90, 0x98, 0x63, 0x67, + 0x33, 0x2c, 0xa9, 0xd3, 0xa8, 0x20, 0xff, 0x15, + 0xe9, 0x0f, 0x39, 0xf1, 0x13, 0xd4, 0x3d, 0x30, + 0xb7, +}; + +/* K1 encrypted for ECDSA P-256 key */ +static const uint8_t k1_ecdsa256_encrypt[] = { + 0x8f, 0x8a, 0xdd, 0x7b, 0x9c, 0xca, 0xb8, 0x8e, + 0x73, 0xca, 0xdd, 0x03, 0x11, 0xb5, 0xb1, 0x28, + 0xe0, 0xe6, 0xe1, 0x1a, 0x4d, 0x5b, 0x71, 0xd1, + 0x16, 0x9f, 0x3f, 0x9e, 0x17, 0x4f, 0xc8, 0x5e, +}; +#endif /* CONFIG_EXAMPLE_KEY_MGR_ECDSA_SIGN */ + +#if CONFIG_EXAMPLE_KEY_MGR_RSA_DS_SIGN +/* K1 encrypted for DS (AES) key - RSA 3072-bit */ +static const uint8_t k1_ds_aes_key_encrypt[] = { + 0x64, 0xd8, 0x2b, 0x4e, 0xa9, 0x3b, 0x84, 0x41, + 0xc2, 0xac, 0xed, 0x77, 0x1a, 0x27, 0x39, 0xc3, + 0xd4, 0x49, 0xf3, 0x17, 0x9f, 0x78, 0xd8, 0xdc, + 0x17, 0x7b, 0xba, 0x65, 0x28, 0x4d, 0x1a, 0xf9, +}; + +/* RSA-3072 public key in PKCS#1 RSAPublicKey DER format for signature verification */ +static const uint8_t rsa_public_key_der[] = { + 0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81, + 0x00, 0xe6, 0x58, 0x20, 0x70, 0xbd, 0x0b, 0x45, + 0x1c, 0x47, 0x48, 0x8e, 0x54, 0x6d, 0xeb, 0x21, + 0x2d, 0x87, 0xc6, 0xdd, 0xdb, 0x4c, 0xa5, 0x1c, + 0xc9, 0xd7, 0x60, 0xe8, 0xd7, 0x55, 0xe5, 0x03, + 0x7d, 0x43, 0xf4, 0x0e, 0x2d, 0x45, 0x16, 0x14, + 0xac, 0xc8, 0x01, 0xa9, 0x6a, 0x8e, 0xed, 0xba, + 0x27, 0x72, 0xa9, 0xa3, 0xc9, 0x45, 0x81, 0xb8, + 0xda, 0xc5, 0x6a, 0x4d, 0x93, 0x99, 0x21, 0x61, + 0x24, 0x54, 0x1b, 0x5b, 0x8d, 0x28, 0x6d, 0xca, + 0x7b, 0x03, 0x0a, 0xc6, 0x74, 0x53, 0x94, 0x2c, + 0x49, 0xcd, 0xae, 0xdd, 0xad, 0xf8, 0xf6, 0x2e, + 0xe8, 0xd6, 0xc2, 0x27, 0xa5, 0xfd, 0x13, 0x98, + 0x90, 0x91, 0x1d, 0x9c, 0x04, 0x59, 0xd7, 0xa8, + 0x30, 0xd7, 0xea, 0x53, 0xff, 0xda, 0xb9, 0x99, + 0x14, 0x54, 0x72, 0xaf, 0x36, 0x62, 0x82, 0x21, + 0x1c, 0x5f, 0x85, 0xd4, 0xc4, 0x5d, 0x9b, 0x22, + 0x89, 0x57, 0xef, 0x53, 0x87, 0x44, 0x0c, 0xc6, + 0xbf, 0x4d, 0x0b, 0x5f, 0x87, 0xe1, 0x48, 0xd9, + 0xe1, 0x7d, 0x9f, 0x23, 0xf4, 0x9c, 0x46, 0x40, + 0x5d, 0x70, 0x2d, 0xe2, 0x7a, 0x13, 0xe6, 0x7b, + 0x0b, 0xe7, 0x3d, 0xd9, 0x8b, 0x4b, 0x0e, 0x50, + 0x3b, 0x19, 0x3c, 0xa8, 0x0d, 0x17, 0x89, 0x7b, + 0xae, 0xf7, 0xb1, 0x2c, 0x34, 0x02, 0x87, 0xc2, + 0x83, 0x17, 0x6f, 0x1c, 0xcc, 0x44, 0x56, 0x87, + 0x04, 0xd2, 0x24, 0xff, 0x0a, 0x80, 0x3f, 0x4e, + 0x35, 0xf9, 0x36, 0x9c, 0x44, 0xd3, 0xc6, 0xbf, + 0x48, 0x7f, 0xb7, 0x89, 0xc5, 0xb0, 0x2c, 0x6c, + 0xa7, 0xf6, 0xd0, 0x3f, 0x09, 0x58, 0x9f, 0xfb, + 0x57, 0xd8, 0xcf, 0xb0, 0xb2, 0xa5, 0x53, 0xd5, + 0x73, 0x85, 0xfe, 0x75, 0x5b, 0x0f, 0x79, 0x22, + 0x62, 0x59, 0x17, 0x93, 0x20, 0x9c, 0xc2, 0x4c, + 0xb4, 0xff, 0x77, 0xf2, 0x8c, 0x93, 0x30, 0xda, + 0xd4, 0x78, 0xa8, 0x41, 0xff, 0xc8, 0x20, 0x1b, + 0xd3, 0x49, 0x1f, 0xde, 0xea, 0xff, 0x9c, 0xbc, + 0x83, 0xb9, 0x18, 0x04, 0x4c, 0xee, 0x97, 0x95, + 0x04, 0xb0, 0x57, 0xd5, 0x64, 0x42, 0xc9, 0xa1, + 0x65, 0x38, 0xb2, 0x12, 0xa0, 0xf5, 0xf2, 0xb2, + 0xcf, 0x89, 0xeb, 0x39, 0x60, 0x41, 0x12, 0xfb, + 0xa7, 0x4a, 0x68, 0x4c, 0xe4, 0xb0, 0x19, 0xee, + 0x76, 0xba, 0x8e, 0xd2, 0xd1, 0x19, 0xd1, 0xac, + 0xa5, 0x88, 0xfa, 0xa2, 0xb9, 0xda, 0xbd, 0xcc, + 0x4f, 0x31, 0x9b, 0x3a, 0x13, 0x63, 0xa1, 0x2e, + 0x49, 0x19, 0x25, 0xb4, 0x7a, 0x17, 0x7a, 0x8e, + 0x58, 0x70, 0xd9, 0x17, 0x29, 0xfa, 0x1a, 0xdc, + 0xd2, 0xb8, 0x46, 0x88, 0xb3, 0x00, 0xd8, 0xf9, + 0x27, 0xc1, 0xab, 0x8e, 0x66, 0xa9, 0xfe, 0xbc, + 0x01, 0x92, 0x86, 0x63, 0x23, 0xfa, 0xfc, 0x9f, + 0xe1, 0x77, 0xc8, 0x98, 0x25, 0x88, 0x4b, 0xfb, + 0x2b, 0x02, 0x03, 0x01, 0x00, 0x01, +}; + +static const uint8_t ds_iv[ESP_DS_IV_LEN] = { 0x1e, 0x85, 0xda, 0x16, 0xba, 0x37, 0x22, 0x4f, 0xbe, 0x12, 0x8c, 0xe3, 0xbc, 0xcd, 0x9d, 0xe5 }; +static const uint8_t ds_c[ESP_DS_C_LEN] = { 0xea, 0xfa, 0x7f, 0xba, 0x6b, 0x68, 0x72, 0xd2, 0xdc, 0x9d, 0x40, 0x4e, 0x4e, 0x7d, 0x65, 0x7f, 0x6a, 0xf6, 0x7c, 0x69, 0xaa, 0xb2, 0x60, 0xa7, 0x3a, 0x79, 0x74, 0x99, 0x3f, 0x79, 0xd5, 0x4a, 0x68, 0x5b, 0x7c, 0xf0, 0x3d, 0x1b, 0xd4, 0x66, 0xde, 0xde, 0xd9, 0x03, 0x5d, 0x5d, 0xc6, 0x2b, 0x59, 0x26, 0x17, 0x42, 0x80, 0xbf, 0xd7, 0x95, 0xee, 0xa9, 0x07, 0x0f, 0x5c, 0xcf, 0xf7, 0xe9, 0x17, 0xe5, 0x3d, 0x40, 0x12, 0x09, 0x4d, 0xf0, 0x51, 0x82, 0x81, 0x86, 0xad, 0xa0, 0x6b, 0x4d, 0xe7, 0xf6, 0x78, 0xd9, 0x4b, 0xeb, 0x38, 0x10, 0xad, 0x5b, 0xb8, 0xe0, 0x9d, 0x9e, 0x5f, 0x22, 0xa0, 0x9d, 0xd8, 0xbc, 0xc2, 0x36, 0x2e, 0xcc, 0xb0, 0x95, 0xd1, 0xb7, 0x5f, 0x0f, 0xe4, 0xc7, 0x82, 0x20, 0x73, 0x12, 0x42, 0x31, 0x97, 0xd5, 0x4d, 0x1f, 0x96, 0x39, 0xad, 0x83, 0x4a, 0xca, 0xf4, 0x1b, 0xe5, 0x36, 0xb4, 0xf7, 0x4a, 0xa1, 0xe9, 0xfd, 0xf4, 0xbf, 0xc8, 0x6e, 0x7d, 0xff, 0x96, 0x47, 0xfa, 0x51, 0xe1, 0xc0, 0x3d, 0x98, 0x9b, 0x54, 0x87, 0x3e, 0x2f, 0xe8, 0x47, 0x11, 0xf2, 0x74, 0xe4, 0xea, 0xef, 0xda, 0x4b, 0x27, 0x2b, 0x40, 0x4c, 0x13, 0xc4, 0x3b, 0xe5, 0x7f, 0xcc, 0x55, 0x9a, 0x6e, 0x3e, 0xee, 0x17, 0xbb, 0x52, 0x9e, 0x02, 0x58, 0x46, 0xc5, 0x4d, 0x42, 0xfb, 0x08, 0xfd, 0xa8, 0x79, 0x39, 0x4a, 0xb2, 0x0c, 0xad, 0x4c, 0x10, 0xd0, 0xde, 0x95, 0xdc, 0x0b, 0xc4, 0x52, 0xb7, 0x09, 0x5d, 0x54, 0x8d, 0xb2, 0xcd, 0xa1, 0x6f, 0x26, 0x9c, 0x53, 0x3d, 0xe8, 0x73, 0x9c, 0x24, 0x23, 0xfc, 0xa2, 0x31, 0x63, 0x1f, 0x26, 0x70, 0x7a, 0x6d, 0xa1, 0xe6, 0x9f, 0x0c, 0xae, 0xe6, 0x05, 0x31, 0xaf, 0xf9, 0x93, 0x21, 0x8a, 0x5b, 0x0f, 0x2b, 0xa7, 0xfb, 0x83, 0x8e, 0x04, 0x71, 0xc8, 0xfb, 0xef, 0x31, 0x2b, 0x58, 0xbd, 0x7c, 0x0c, 0x89, 0x29, 0x33, 0xfe, 0xdb, 0x69, 0xf5, 0xa6, 0x21, 0xd9, 0x35, 0xe8, 0xf7, 0x33, 0xc3, 0x68, 0x9b, 0x15, 0xe7, 0x38, 0x53, 0x28, 0x0c, 0x7e, 0x0d, 0x41, 0xd9, 0xa2, 0x23, 0x7c, 0x62, 0xba, 0x57, 0xb4, 0x90, 0x9d, 0xc6, 0x86, 0x59, 0x6e, 0x8e, 0x6f, 0x27, 0x10, 0xf4, 0xdf, 0x33, 0x89, 0x71, 0xdd, 0x5a, 0x00, 0x49, 0xcf, 0x7c, 0x33, 0xc8, 0x69, 0x44, 0x46, 0xba, 0xc8, 0x16, 0x44, 0x37, 0x7d, 0xdd, 0xc6, 0xe4, 0x6d, 0xfd, 0x42, 0x59, 0x43, 0xa5, 0x32, 0x30, 0x8f, 0x72, 0x5f, 0x9f, 0xe1, 0x48, 0x25, 0x83, 0x4a, 0x80, 0x73, 0x94, 0x7e, 0x08, 0x68, 0xd7, 0xfa, 0x1c, 0x2d, 0xf2, 0xf0, 0xf5, 0x27, 0x42, 0x96, 0x17, 0x6b, 0xfe, 0x39, 0x56, 0x8b, 0xe3, 0x04, 0x47, 0x37, 0xfb, 0x29, 0x72, 0xe7, 0x68, 0xd0, 0xba, 0xc8, 0xe8, 0x0a, 0xe4, 0x9d, 0xd7, 0xa0, 0x23, 0x19, 0x09, 0x66, 0x95, 0x34, 0xe3, 0x29, 0xf4, 0x1b, 0x5e, 0xd2, 0x0c, 0x3c, 0xab, 0x8e, 0xc2, 0x9b, 0x6e, 0xc1, 0x7d, 0xc0, 0x72, 0x87, 0x8f, 0x6c, 0x8e, 0x89, 0x97, 0x00, 0x27, 0x13, 0x89, 0x51, 0x53, 0x8f, 0x6a, 0xbd, 0x1a, 0xfa, 0x64, 0xf4, 0x12, 0x55, 0x21, 0x7b, 0x4a, 0x66, 0x54, 0x40, 0x6f, 0xe1, 0x83, 0xa1, 0xb9, 0xfa, 0x61, 0xa3, 0xed, 0x50, 0xba, 0x4b, 0x35, 0xf1, 0x2b, 0xbb, 0xc3, 0x17, 0xac, 0xe2, 0xd8, 0x87, 0xed, 0x6e, 0x27, 0xd0, 0x3c, 0x34, 0x05, 0x88, 0x5f, 0xa3, 0x8c, 0x6c, 0x77, 0xfc, 0xb3, 0xb7, 0xa0, 0x45, 0x18, 0xf1, 0x7d, 0x32, 0x66, 0xe1, 0x3d, 0x3c, 0x96, 0x6c, 0x06, 0x4a, 0x8a, 0xd4, 0x11, 0xd9, 0xbd, 0xa7, 0xa3, 0x74, 0x99, 0x90, 0x3d, 0x2c, 0x5c, 0x1e, 0xfc, 0x9c, 0xc3, 0xf9, 0x00, 0x3b, 0x51, 0x78, 0x42, 0x35, 0xa9, 0x67, 0x2f, 0x27, 0xbd, 0x76, 0xe5, 0x84, 0xdd, 0x23, 0x35, 0xdd, 0x42, 0x3c, 0x0f, 0xd5, 0x16, 0x8f, 0xef, 0x22, 0xb5, 0x47, 0x0b, 0x85, 0xd0, 0x6b, 0x17, 0x30, 0xa0, 0xb3, 0x96, 0x53, 0x78, 0x62, 0x74, 0x5c, 0xaa, 0x5e, 0x82, 0x1d, 0x6a, 0x9f, 0xce, 0x53, 0xcc, 0xbe, 0x2b, 0xa0, 0x78, 0xfe, 0x24, 0x4f, 0x6a, 0xbf, 0xb4, 0x18, 0x2c, 0xa8, 0x7f, 0x57, 0xb3, 0xc3, 0xea, 0xe3, 0x9e, 0x31, 0xd6, 0xd5, 0xd2, 0x25, 0x31, 0x22, 0x54, 0xc2, 0x8c, 0x0c, 0x9b, 0x30, 0xa6, 0x67, 0x29, 0x2b, 0x58, 0xaa, 0x82, 0x0b, 0x1d, 0xfc, 0x1b, 0xa6, 0x90, 0x44, 0xaf, 0xa0, 0x9c, 0x46, 0x81, 0xf5, 0xcc, 0xa2, 0x4d, 0x94, 0x70, 0x80, 0x0b, 0xf6, 0xae, 0x68, 0xaa, 0x91, 0x24, 0x3f, 0x3b, 0x85, 0x9a, 0x58, 0x9b, 0x4b, 0x07, 0x63, 0x7a, 0x77, 0x24, 0x03, 0x30, 0xe9, 0x62, 0xe0, 0xf1, 0xf2, 0x21, 0xd2, 0x1f, 0x0d, 0xa8, 0x77, 0xaa, 0xda, 0xd6, 0x57, 0x38, 0xd6, 0x22, 0x40, 0x0c, 0x2a, 0x70, 0x90, 0xf3, 0x75, 0x6b, 0x56, 0x9b, 0xe1, 0x86, 0x2e, 0x22, 0xa3, 0x7a, 0x16, 0xe4, 0x15, 0xc3, 0x27, 0xa5, 0xe4, 0xa4, 0x15, 0x93, 0x19, 0x20, 0xc8, 0xac, 0xa0, 0xb4, 0x5b, 0x88, 0xa6, 0x1d, 0xa3, 0x17, 0x95, 0x85, 0x88, 0x02, 0x65, 0xe8, 0x96, 0x50, 0x09, 0x01, 0xd9, 0x34, 0xbf, 0x7e, 0x41, 0x9e, 0x8e, 0x77, 0x8c, 0xb7, 0x86, 0xe2, 0x8c, 0x72, 0xd7, 0xe3, 0x67, 0x9b, 0x8b, 0xfc, 0x09, 0x71, 0xba, 0xba, 0xe4, 0x15, 0xd7, 0x26, 0x61, 0xde, 0x0d, 0x55, 0x55, 0x7f, 0x79, 0xcf, 0x06, 0x79, 0x42, 0xf0, 0x63, 0x28, 0x94, 0x17, 0x28, 0xa5, 0xb7, 0x4e, 0x81, 0x77, 0x39, 0x5e, 0xe7, 0xea, 0x48, 0x99, 0x46, 0x8d, 0xd0, 0x85, 0x15, 0x13, 0x1b, 0x82, 0xc8, 0x99, 0xf1, 0x67, 0x4f, 0x94, 0xae, 0x12, 0xa4, 0x07, 0xb6, 0x90, 0x56, 0x67, 0x7f, 0x23, 0xb4, 0xd0, 0x8a, 0x32, 0xdc, 0xeb, 0xdc, 0x32, 0x05, 0x31, 0xf9, 0xdd, 0x6e, 0xd8, 0x0c, 0xe6, 0x3d, 0x85, 0xc6, 0x3c, 0x17, 0xc3, 0xb4, 0x46, 0xe5, 0xb7, 0xe1, 0xd4, 0x1f, 0x84, 0x05, 0x65, 0x54, 0x87, 0xf8, 0x8d, 0x81, 0x99, 0x0b, 0x27, 0x09, 0x19, 0x49, 0x7a, 0x3b, 0xf1, 0x61, 0xb5, 0xc6, 0x87, 0xd4, 0xbe, 0xb4, 0x07, 0x7e, 0x02, 0xee, 0x1c, 0xc7, 0x46, 0x07, 0xc1, 0xec, 0xb4, 0x62, 0xd5, 0x66, 0x3a, 0x23, 0x5f, 0x67, 0x9c, 0xfc, 0x8f, 0xa9, 0x3e, 0x38, 0xbd, 0xbb, 0x66, 0x60, 0xa5, 0x6b, 0xe2, 0x2a, 0xed, 0xaf, 0xfb, 0x3b, 0xac, 0x1f, 0xb0, 0x57, 0x6c, 0xbf, 0xf3, 0xb0, 0x6e, 0x8b, 0x3c, 0x03, 0x87, 0xca, 0xe0, 0xba, 0xfb, 0x62, 0x86, 0x66, 0x7a, 0xcf, 0x69, 0x20, 0x73, 0xe0, 0x43, 0xea, 0xd8, 0x76, 0xf6, 0xc2, 0x6a, 0x7b, 0x37, 0xbe, 0xd2, 0xc0, 0xe6, 0xd0, 0xda, 0x73, 0xa3, 0x9a, 0x18, 0x07, 0x89, 0x67, 0x4d, 0xa4, 0x9c, 0x26, 0x40, 0x65, 0xc7, 0x76, 0xe4, 0x14, 0x51, 0x9b, 0xc4, 0x93, 0xe6, 0x0a, 0x45, 0x35, 0x4f, 0xd8, 0x28, 0xa5, 0xad, 0x29, 0xf1, 0x7b, 0x4f, 0x79, 0xe1, 0x6e, 0xda, 0x50, 0x7d, 0x23, 0xb5, 0x7a, 0xe8, 0x14, 0x6b, 0x07, 0x05, 0x40, 0x2b, 0x29, 0x04, 0xd6, 0x4d, 0xdd, 0x92, 0xab, 0x7f, 0x45, 0x1e, 0xf3, 0x29, 0x19, 0x9b, 0x02, 0xbc, 0xa4, 0xe4, 0x2a, 0x0f, 0x47, 0x68, 0xf0, 0x64, 0x40, 0x33, 0x7d, 0xd4, 0xb0, 0x81, 0xf4, 0xee, 0x92, 0x14, 0x5b, 0xda, 0x26, 0x69, 0xdc, 0x7c, 0xb3, 0xd8, 0x3f, 0xb5, 0xa0, 0x17, 0x90, 0xf5, 0x2b, 0xc9, 0x77, 0x42, 0x43, 0xa7, 0xa0, 0xfc, 0x90, 0x3a, 0xcc, 0x05, 0xb6, 0x3a, 0x5c, 0x8a, 0x75, 0x4d, 0x41, 0x00, 0x01, 0xe0, 0xfb, 0x66, 0x9e, 0xfb, 0xf3, 0x4f, 0xad, 0x44, 0xaf, 0x7a, 0x80, 0x41, 0x04, 0x2a, 0x73, 0xd4, 0xb3, 0x50, 0xa3, 0x77, 0xc1, 0xa3, 0x1f, 0xdf, 0xbb, 0x7a, 0x60, 0x5f, 0xce, 0x66, 0x3f, 0x22, 0x29, 0x22, 0x76, 0x37, 0x16, 0xde, 0x83, 0xef, 0x2d, 0xb6, 0xf6, 0x65, 0xff, 0xd6, 0x2c, 0x8e, 0xe1, 0x84, 0x96, 0x3e, 0x19, 0xd1, 0x04, 0xfb, 0x6f, 0x2e, 0x61, 0x0c, 0x84, 0x78, 0x8f, 0x0c, 0x77, 0x60, 0x73, 0xdb, 0x04, 0x2a, 0x23, 0xb1, 0x74, 0x0a, 0xfa, 0x22, 0x48, 0x71, 0xa6, 0xe4, 0x49, 0x71, 0xb4, 0x5e, 0xda, 0xf4, 0x9d, 0xee, 0x12, 0x3b, 0x3e, 0x09, 0x59, 0x62, 0xc4, 0xf1, 0x42, 0x30, 0x25, 0xb4, 0x4c, 0x3a, 0x4d, 0x91, 0xed, 0x04, 0xb1, 0xac, 0xb6, 0x79, 0x05, 0x95, 0xe2, 0xa2, 0x9e, 0xa5, 0x20, 0x57, 0x5c, 0xec, 0x5f, 0xc8, 0xd5, 0xb4, 0x3d, 0x39, 0x3b, 0x63, 0x9a, 0xb5, 0x9a, 0xe5, 0x43, 0xec, 0x11, 0xd2, 0xca, 0x30, 0x35, 0x59, 0x5f, 0x1c, 0x29, 0x52, 0x53, 0xac, 0xb0, 0xdb, 0x36, 0x6a, 0xe0, 0xd4, 0xee, 0xa7, 0xec, 0x4e, 0x7f, 0x15 }; +#endif /* CONFIG_EXAMPLE_KEY_MGR_RSA_DS_SIGN */ diff --git a/examples/security/key_manager/pytest_key_manager_sign.py b/examples/security/key_manager/pytest_key_manager_sign.py new file mode 100644 index 00000000000..69d71dd9928 --- /dev/null +++ b/examples/security/key_manager/pytest_key_manager_sign.py @@ -0,0 +1,57 @@ +# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +""" +Pytest for Key Manager Signing Example + +This test verifies ECDSA and RSA-DS signing operations using keys deployed +via the Key Manager peripheral. +""" + +import logging +import os + +import pytest +from pytest_embedded import Dut +from pytest_embedded_idf.utils import idf_parametrize + + +@pytest.mark.generic +@idf_parametrize('target', ['esp32c5'], indirect=['target']) +def test_key_manager(dut: Dut) -> None: + # Log binary size + binary_file = os.path.join(dut.app.binary_path, 'key_manager.bin') + bin_size = os.path.getsize(binary_file) + logging.info(f'key_manager_bin_size: {bin_size // 1024}KB') + + # Verify example starts + dut.expect('Key Manager Signing Example', timeout=30) + + # Test ECDSA signing flow + dut.expect('ECDSA Signing with Key Manager', timeout=30) + match = dut.expect( + r'No ECDSA key in NVS, deploying new key via Key Manager|Using existing ECDSA key from NVS', timeout=30 + ) + if b'No ECDSA key' in match.group(0): + dut.expect('Key deployed successfully in Key Manager', timeout=30) + dut.expect('Step 2: Creating PSA opaque key reference', timeout=30) + dut.expect('Step 3: Signing hash using Key Manager key', timeout=30) + dut.expect(r'Signature generated successfully \(\d+ bytes\)', timeout=30) + dut.expect('Step 4: Verifying signature with known public key', timeout=30) + dut.expect('ECDSA signature verification PASSED!', timeout=30) + dut.expect('ECDSA Signing Example Complete', timeout=30) + + # Test RSA-DS signing flow + dut.expect('RSA-DS Signing with Key Manager', timeout=30) + match = dut.expect( + r'No DS key in NVS, deploying new key via Key Manager|Using existing DS key from NVS', timeout=30 + ) + if b'No DS key' in match.group(0): + dut.expect('Key deployed successfully in Key Manager', timeout=30) + dut.expect('Step 2: Preparing DS data context', timeout=30) + dut.expect('Step 3: Creating PSA opaque key reference for RSA-DS', timeout=30) + dut.expect('Step 4: Signing hash using RSA-DS with Key Manager key', timeout=30) + dut.expect(r'RSA-DS signature generated successfully \(\d+ bytes\)', timeout=30) + dut.expect('RSA-DS Signing Example Complete', timeout=30) + + # Verify example completes + dut.expect('Key Manager Signing Example finished.', timeout=30) diff --git a/examples/security/key_manager/sdkconfig.defaults b/examples/security/key_manager/sdkconfig.defaults new file mode 100644 index 00000000000..35712b1884c --- /dev/null +++ b/examples/security/key_manager/sdkconfig.defaults @@ -0,0 +1,10 @@ +# Enable hardware ECDSA signing +CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN=y +CONFIG_MBEDTLS_HARDWARE_ECDSA_VERIFY=y + +# Enable DS peripheral support +CONFIG_MBEDTLS_HARDWARE_RSA_DS_PERIPHERAL=y + +# Enable Key Manager signing examples +CONFIG_EXAMPLE_KEY_MGR_ECDSA_SIGN=y +CONFIG_EXAMPLE_KEY_MGR_RSA_DS_SIGN=y diff --git a/examples/security/key_manager/test/ecdsa_private_key.pem b/examples/security/key_manager/test/ecdsa_private_key.pem new file mode 100644 index 00000000000..b4532061777 --- /dev/null +++ b/examples/security/key_manager/test/ecdsa_private_key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIP1eMYfPIevVXXxeDb6pWspbW3/T1aY9IutjZ0V3qZVAoAoGCCqGSM49 +AwEHoUQDQgAEqyx6By5PjN+g3CL6mcKBbuo7nHcMAZKgwEvoRb7ixz729xEd7Ud+ +InETrZCYY2czLKnTqCD/FekPOfET1D0wtw== +-----END EC PRIVATE KEY----- diff --git a/examples/security/key_manager/test/rsa_private_key.pem b/examples/security/key_manager/test/rsa_private_key.pem new file mode 100644 index 00000000000..f86ba16227e --- /dev/null +++ b/examples/security/key_manager/test/rsa_private_key.pem @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIG4wIBAAKCAYEA5lggcL0LRRxHSI5UbeshLYfG3dtMpRzJ12Do11XlA31D9A4t +RRYUrMgBqWqO7boncqmjyUWBuNrFak2TmSFhJFQbW40obcp7AwrGdFOULEnNrt2t ++PYu6NbCJ6X9E5iQkR2cBFnXqDDX6lP/2rmZFFRyrzZigiEcX4XUxF2bIolX71OH +RAzGv00LX4fhSNnhfZ8j9JxGQF1wLeJ6E+Z7C+c92YtLDlA7GTyoDReJe673sSw0 +AofCgxdvHMxEVocE0iT/CoA/TjX5NpxE08a/SH+3icWwLGyn9tA/CVif+1fYz7Cy +pVPVc4X+dVsPeSJiWReTIJzCTLT/d/KMkzDa1HioQf/IIBvTSR/e6v+cvIO5GARM +7peVBLBX1WRCyaFlOLISoPXyss+J6zlgQRL7p0poTOSwGe52uo7S0RnRrKWI+qK5 +2r3MTzGbOhNjoS5JGSW0ehd6jlhw2Rcp+hrc0rhGiLMA2PknwauOZqn+vAGShmMj ++vyf4XfImCWIS/srAgMBAAECggGAIyuIhH4w1tQLBEaLGJ9imPeWwzAlQz6iiOqo +kpxwU7iQJBb4DYjiDkGZk1sMSLr4I/dH5UbiGC37H5CJvUNN+ESJStDCQAU/BAdk +psVOJfb82zrIwe8g2XdU/MXI3vGX/ThGpplrJqiShxpdQfG9sE92lU8Z+mGA2gru +oi7irYLH9OhNinPi8rmaR3NRUBTIa6xdSo+D4HcD1lWyqxAxcG9Vz74Hbz+Lzn4m +8JzL5qEf+6LSrCI7blWpJv3/XzDNHukXK+VGsBg+5mcTQOl0n/Crd22/OVucO6wa +/hos1vud13NVVdy4KnQ0kYYOJdXhikQ9BQorOdtHZlGA2e47LZ9wxYk+DVLx6i3r +pTv4h+WnIcCyWRKjfsYJwQOQfcxE9hKd63SZrfMqquyXeXHAgYoLsHGawRto8pti +SF2tOHXpfLnv1xfG9W/RHE1W4NnXYA19rarZFOtEs4E/P02TOl/TNLaZ+xgtte90 +fWLN1B0Qn5XerlvlJTWBMSN6jUiJAoHBAP2zO1l8uoH3HSv4amChJijUa96NjgkV +9IWgOWxWy8B/lyweqJZ71Uj7z2BXn/WjDB16/h02Q8BQuN4TwJ3relV52XLJ+tLs +nb+4xPj6Z+JUyWkN9xgLy8MpaSRQQPkbpyuhPApXFH94zi/MqJi63kbCBPryhA+2 +SPay4rmHLvwz4ZHJA85IWZ7CoAqF7XaC5o8SjLBr81ZHWntvgv9ZJXV2GsbrJx8F +hqEjCNRahT+fnXGT/1Y4WxCkWEYpj4+q6QKBwQDobrE7wPLcXWFxN5soKBq4DIcO +37NVcqyNkEz8UE64EE0fyTpki/DJP+Bedcn0I+eyNYMcUFHNbKxhy0WywIuYUeE3 +nZQiPigQW/balT8w+6dWCfFAChbqod74KovANNQOiOn6jHhWzSFSRTgi6Ii+N75L +eooD2FEEviyngYFWegVi9JWynqlXtA4aAz4o6VEEeBa08mNEfcZ2RHWGjH1AwdsA +h2AcXehftQnrGlHSKpoGtn/hf+jxdCSqo5oOwPMCgcAMW0ZwvVp4KgkJsze7LR4m +rvHyDQL1/lPCjmM9m5yg65X5WCTt72ob++fF0X7BAAf/B5aI5bO3Ejdu2ZdwGaAD +ucOVi7DjxRKJ2/38AnY819RXgY6fZTOvdbzhP+dqOqaRwXCjMEqXStMAEP/FMJTS +7XBAqL815LL5EQ1p6+Ol9QDvkNLWoT98NA6HdK50Lzv7i/O+RAO+GAuYJ35B4Z2p +cu8q8Rkesa40+vfbH+2Ng8CvX334PRZyYQ7LnAqZ/MECgcBQRRIOKcd1lQY23FZI +GvmHQERQPa8oPk8bII+Fv5I//Nk1tf/lg3KnfdjVpmYVW2UD5XkfCRoHEJXDvDiY +z+gltXlLBK+I1+BsLeZlfI9zMiWLECnxzMo3Q6nGGKNkwJnPXzc24NYaXAM6707A +t3+p+YRNesc5JrZsJeU0AASTwdYkY4VjR2oCMNuB3kbUSCdDnNlyqhbgK3Ojmmbg +DZqgB5LDbv0hLsk2bEY9nDxPkYjZ8qLdVJg08sBK8e8dU0MCgcEA6MWXns1BWOyT +29GkD0MWCb/8+XmtaPFLSf3szIUD82XINfx4PBVoPJy22mRU2GkyUOOBBHVwXKOw +ddGWxitW0W6m/7MBuuEztbnvoLNXb8KqA5BdB8/Y9kQg0HmXBh780jWKXqYEh9B7 +3Fm4hbwejC0FQdTrETku6Jl1RdziybpV2D4PEujxdgA+0oPYSrTLWV8/HSLjM5tZ +UkbGlHxDZHq89BeCjpH5uCJXKlT2PHAR3Lzvo4M2SHlFit5oTPj7 +-----END RSA PRIVATE KEY-----