mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
544 lines
19 KiB
C
544 lines
19 KiB
C
/*
|
|
* 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.");
|
|
}
|