mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
test(examples/security): Add an example to demonstrate signing using Key Manager keys
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "key_mgr_sign_main.c"
|
||||
PRIV_REQUIRES esp_security mbedtls nvs_flash
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -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
|
||||
@@ -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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#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.");
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user