feat(bootloader_support): Migrated mbedTLS crypto APIs to PSA

This commit is contained in:
Aditya Patwardhan
2025-04-03 19:32:04 +05:30
committed by Ashish Sharma
parent 25814db7b1
commit c39347c00c
8 changed files with 164 additions and 182 deletions

View File

@@ -9,7 +9,7 @@
that can be used from bootloader or app code.
This header is available to source code in the bootloader & bootloader_support components only.
Use mbedTLS APIs or include esp32/sha.h to calculate SHA256 in IDF apps.
Use PSA APIs or include esp32/sha.h to calculate SHA256 in IDF apps.
*/
#include <stdbool.h>

View File

@@ -179,42 +179,55 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest
#else /* NON_OS_BUILD || CONFIG_APP_BUILD_TYPE_RAM */
#include "bootloader_flash_priv.h"
#include <mbedtls/sha256.h>
#include <mbedtls/sha512.h>
#include "psa/crypto.h"
bootloader_sha256_handle_t bootloader_sha256_start(void)
{
mbedtls_sha256_context *ctx = (mbedtls_sha256_context *)malloc(sizeof(mbedtls_sha256_context));
if (!ctx) {
// Initialize PSA Crypto subsystem
psa_status_t status = psa_crypto_init();
if (status != PSA_SUCCESS) {
return NULL;
}
mbedtls_sha256_init(ctx);
int ret = mbedtls_sha256_starts(ctx, false);
if (ret != 0) {
psa_hash_operation_t *op = (psa_hash_operation_t *)malloc(sizeof(psa_hash_operation_t));
if (!op) {
return NULL;
}
return ctx;
*op = psa_hash_operation_init();
status = psa_hash_setup(op, PSA_ALG_SHA_256);
if (status != PSA_SUCCESS) {
free(op);
return NULL;
}
return (bootloader_sha256_handle_t)op;
}
void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data, size_t data_len)
{
assert(handle != NULL);
mbedtls_sha256_context *ctx = (mbedtls_sha256_context *)handle;
int ret = mbedtls_sha256_update(ctx, data, data_len);
assert(ret == 0);
(void)ret;
psa_hash_operation_t *op = (psa_hash_operation_t *)handle;
psa_status_t status = psa_hash_update(op, data, data_len);
assert(status == PSA_SUCCESS);
(void)status; // Suppress unused variable warning in release builds
}
void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest)
{
assert(handle != NULL);
mbedtls_sha256_context *ctx = (mbedtls_sha256_context *)handle;
psa_hash_operation_t *op = (psa_hash_operation_t *)handle;
if (digest != NULL) {
int ret = mbedtls_sha256_finish(ctx, digest);
assert(ret == 0);
(void)ret;
size_t hash_len;
psa_status_t status = psa_hash_finish(op, digest, PSA_HASH_LENGTH(PSA_ALG_SHA_256), &hash_len);
assert(status == PSA_SUCCESS);
assert(hash_len == PSA_HASH_LENGTH(PSA_ALG_SHA_256));
} else {
psa_hash_abort(op);
}
mbedtls_sha256_free(ctx);
free(handle);
handle = NULL;
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -11,12 +11,7 @@
#include "esp_log.h"
#include "esp_image_format.h"
#include "esp_secure_boot.h"
#include "mbedtls/sha256.h"
#include "mbedtls/x509.h"
#include "mbedtls/md.h"
#include "mbedtls/platform.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "psa/crypto.h"
#include <string.h>
#include <sys/param.h>
@@ -27,7 +22,7 @@ extern const uint8_t signature_verification_key_start[] asm("_binary_signature_v
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
#define SIGNATURE_VERIFICATION_KEYLEN 64
#define PSA_ECDSA_PUB_KEY_SIZE_BITS 256
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
{
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN];
@@ -76,53 +71,31 @@ esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig
}
ESP_LOGD(TAG, "Verifying secure boot signature");
psa_status_t status;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t key_handle;
int ret;
mbedtls_mpi r, s;
// Set key attributes
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&key_attributes, PSA_ECDSA_PUB_KEY_SIZE_BITS);
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
/* Extract r and s components from RAW ECDSA signature of 64 bytes */
#define ECDSA_INTEGER_LEN 32
ret = mbedtls_mpi_read_binary(&r, &sig_block->signature[0], ECDSA_INTEGER_LEN);
if (ret != 0) {
ESP_LOGE(TAG, "Failed mbedtls_mpi_read_binary(1), err:%d", ret);
// Import the public key
status = psa_import_key(&key_attributes, signature_verification_key_start, keylen, &key_handle);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed to import key, status:%d", status);
return ESP_FAIL;
}
ret = mbedtls_mpi_read_binary(&s, &sig_block->signature[ECDSA_INTEGER_LEN], ECDSA_INTEGER_LEN);
if (ret != 0) {
ESP_LOGE(TAG, "Failed mbedtls_mpi_read_binary(2), err:%d", ret);
mbedtls_mpi_free(&r);
return ESP_FAIL;
}
// Verify the signature
status = psa_verify_hash(key_handle, PSA_ALG_ECDSA(PSA_ALG_SHA_256), image_digest, ESP_SECURE_BOOT_DIGEST_LEN, sig_block->signature, SIGNATURE_VERIFICATION_KEYLEN);
ESP_LOGD(TAG, "Verification result %d", status);
/* Initialise ECDSA context */
mbedtls_ecdsa_context ecdsa_context;
mbedtls_ecdsa_init(&ecdsa_context);
// Destroy the key handle
psa_destroy_key(key_handle);
mbedtls_ecp_group_load(&ecdsa_context.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1);
size_t plen = mbedtls_mpi_size(&ecdsa_context.MBEDTLS_PRIVATE(grp).P);
if (keylen != 2 * plen) {
ESP_LOGE(TAG, "Incorrect ECDSA key length %d", keylen);
ret = ESP_FAIL;
goto cleanup;
}
/* Extract X and Y components from ECDSA public key */
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ecdsa_context.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), signature_verification_key_start, plen));
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ecdsa_context.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), signature_verification_key_start + plen, plen));
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ecdsa_context.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Z), 1));
ret = mbedtls_ecdsa_verify(&ecdsa_context.MBEDTLS_PRIVATE(grp), image_digest, ESP_SECURE_BOOT_DIGEST_LEN, &ecdsa_context.MBEDTLS_PRIVATE(Q), &r, &s);
ESP_LOGD(TAG, "Verification result %d", ret);
cleanup:
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
mbedtls_ecdsa_free(&ecdsa_context);
return ret == 0 ? ESP_OK : ESP_ERR_IMAGE_INVALID;
return status == PSA_SUCCESS ? ESP_OK : ESP_ERR_IMAGE_INVALID;
#endif // CONFIG_MBEDTLS_ECDSA_C && CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED
}
#endif // CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME

View File

@@ -5,15 +5,9 @@
*/
#include "esp_log.h"
#include "esp_secure_boot.h"
#include "mbedtls/sha256.h"
#include "mbedtls/x509.h"
#include "mbedtls/md.h"
#include "mbedtls/platform.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/ecp.h"
#include "rom/ecdsa.h"
#include "sdkconfig.h"
#include "psa/crypto.h"
#include "secure_boot_signature_priv.h"
@@ -31,27 +25,29 @@ esp_err_t verify_ecdsa_signature_block(const ets_secure_boot_signature_t *sig_bl
return ESP_ERR_INVALID_ARG;
}
esp_err_t ret;
esp_err_t ret = ESP_OK;
psa_status_t status;
mbedtls_mpi r, s;
/* Prepare public key for verification */
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t key_handle = 0;
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
/* Initialise ECDSA context */
mbedtls_ecdsa_context ecdsa_context;
mbedtls_ecdsa_init(&ecdsa_context);
/* Set key attributes according to the curve */
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH);
uint8_t key_size = 0;
psa_ecc_family_t curve_family;
switch(trusted_block->ecdsa.key.curve_id) {
case ECDSA_CURVE_P192:
key_size = 24;
mbedtls_ecp_group_load(&ecdsa_context.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP192R1);
curve_family = PSA_ECC_FAMILY_SECP_R1;
psa_set_key_bits(&key_attributes, PSA_BYTES_TO_BITS(key_size));
break;
case ECDSA_CURVE_P256:
key_size = 32;
mbedtls_ecp_group_load(&ecdsa_context.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1);
curve_family = PSA_ECC_FAMILY_SECP_R1;
psa_set_key_bits(&key_attributes, PSA_BYTES_TO_BITS(key_size));
break;
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
case ECDSA_CURVE_P384:
@@ -64,50 +60,55 @@ esp_err_t verify_ecdsa_signature_block(const ets_secure_boot_signature_t *sig_bl
return ESP_ERR_INVALID_ARG;
}
uint8_t x_point[ECDSA_INTEGER_LEN] = {};
uint8_t y_point[ECDSA_INTEGER_LEN] = {};
uint8_t _r[ECDSA_INTEGER_LEN] = {};
uint8_t _s[ECDSA_INTEGER_LEN] = {};
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve_family));
/* Convert r and s components to big endian format */
/* Prepare the public key data from X and Y coordinates */
uint8_t public_key[2 * ECDSA_INTEGER_LEN];
uint8_t x_point[ECDSA_INTEGER_LEN] = {0};
uint8_t y_point[ECDSA_INTEGER_LEN] = {0};
/* Convert key points from little-endian to big-endian format */
for (int i = 0; i < key_size; i++) {
_r[i] = trusted_block->ecdsa.signature[key_size - i - 1];
_s[i] = trusted_block->ecdsa.signature[2 * key_size - i - 1];
x_point[i] = trusted_block->ecdsa.key.point[key_size - i - 1];
y_point[i] = trusted_block->ecdsa.key.point[2 * key_size - i - 1];
}
/* Extract r and s components from RAW ECDSA signature of 64 bytes */
ret = mbedtls_mpi_read_binary(&r, _r, key_size);
if (ret != 0) {
ESP_LOGE(TAG, "Failed mbedtls_mpi_read_binary(r), err:%d", ret);
mbedtls_ecdsa_free(&ecdsa_context);
return ESP_FAIL;
/* Combine X and Y into a single public key buffer */
memcpy(public_key, x_point, key_size);
memcpy(public_key + key_size, y_point, key_size);
/* Import the public key */
status = psa_import_key(&key_attributes, public_key, 2 * key_size, &key_handle);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed to import key, err:%d", status);
ret = ESP_FAIL;
goto cleanup;
}
ret = mbedtls_mpi_read_binary(&s, _s, key_size);
if (ret != 0) {
ESP_LOGE(TAG, "Failed mbedtls_mpi_read_binary(s), err:%d", ret);
mbedtls_mpi_free(&r);
mbedtls_ecdsa_free(&ecdsa_context);
return ESP_FAIL;
/* Convert signature from little-endian to big-endian format */
uint8_t signature[2 * ECDSA_INTEGER_LEN] = {0};
for (int i = 0; i < key_size; i++) {
signature[i] = trusted_block->ecdsa.signature[key_size - i - 1];
signature[key_size + i] = trusted_block->ecdsa.signature[2 * key_size - i - 1];
}
size_t plen = mbedtls_mpi_size(&ecdsa_context.MBEDTLS_PRIVATE(grp).P);
/* Verify the signature */
status = psa_verify_hash(key_handle, PSA_ALG_ECDSA(PSA_ALG_SHA_256),
image_digest, ESP_SECURE_BOOT_DIGEST_LEN,
signature, 2 * key_size);
for (int i = 0; i < plen; i++) {
x_point[i] = trusted_block->ecdsa.key.point[plen - 1 - i];
y_point[i] = trusted_block->ecdsa.key.point[2 * plen - 1 - i];
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Signature verification failed, err:%d", status);
ret = ESP_FAIL;
}
/* Extract X and Y components from ECDSA public key */
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ecdsa_context.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), x_point, plen));
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&ecdsa_context.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), y_point, plen));
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&ecdsa_context.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Z), 1));
ret = mbedtls_ecdsa_verify(&ecdsa_context.MBEDTLS_PRIVATE(grp), image_digest, ESP_SECURE_BOOT_DIGEST_LEN, &ecdsa_context.MBEDTLS_PRIVATE(Q), &r, &s);
cleanup:
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
mbedtls_ecdsa_free(&ecdsa_context);
/* Clean up resources */
if (key_handle) {
psa_destroy_key(key_handle);
}
psa_reset_key_attributes(&key_attributes);
return ret;
}

View File

@@ -1,16 +1,11 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "esp_secure_boot.h"
#include "mbedtls/sha256.h"
#include "mbedtls/x509.h"
#include "mbedtls/md.h"
#include "mbedtls/platform.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "psa/crypto.h"
#include "secure_boot_signature_priv.h"
@@ -22,55 +17,56 @@ esp_err_t verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_bloc
return ESP_ERR_INVALID_ARG;
}
int ret = 0;
mbedtls_rsa_context pk;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
esp_err_t ret = ESP_OK;
psa_status_t status;
const unsigned rsa_key_size = sizeof(sig_block->block[0].signature);
unsigned char *sig_be = calloc(1, rsa_key_size);
if (sig_be == NULL) {
return ESP_ERR_NO_MEM;
}
unsigned char *buf = calloc(1, rsa_key_size);
if (buf == NULL) {
/* Create key attributes for RSA public key */
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t key_id = 0;
/* Set key attributes */
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_algorithm(&key_attributes, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256));
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_RSA_PUBLIC_KEY);
/* Set the key size in bits (RSA key size is typically 2048 or 3072 bits) */
psa_set_key_bits(&key_attributes, PSA_BYTES_TO_BITS(rsa_key_size));
/* Prepare the RSA public key in the format expected by PSA */
/* PSA expects the key in big-endian format as a sequence of {N, E} */
size_t n_size = rsa_key_size; /* N size in bytes */
size_t e_size = sizeof(trusted_block->key.e); /* E size in bytes */
size_t key_data_size = n_size + e_size + 8; /* Additional bytes for encoding */
uint8_t *key_data = calloc(1, key_data_size);
if (key_data == NULL) {
free(sig_be);
return ESP_ERR_NO_MEM;
}
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
if (ret != 0) {
ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%04x", ret);
goto exit_outer;
}
/* Construct the key data - would normally need proper DER encoding,
but PSA may accept raw concatenated N and E values */
uint8_t *p = key_data;
const mbedtls_mpi N = { .MBEDTLS_PRIVATE(s) = 1,
.MBEDTLS_PRIVATE(n) = sizeof(trusted_block->key.n)/sizeof(mbedtls_mpi_uint),
.MBEDTLS_PRIVATE(p) = (void *)trusted_block->key.n,
};
const mbedtls_mpi e = { .MBEDTLS_PRIVATE(s) = 1,
.MBEDTLS_PRIVATE(n) = sizeof(trusted_block->key.e)/sizeof(mbedtls_mpi_uint), // 1
.MBEDTLS_PRIVATE(p) = (void *)&trusted_block->key.e,
};
mbedtls_rsa_init(&pk);
mbedtls_rsa_set_padding(&pk,MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
ret = mbedtls_rsa_import(&pk, &N, NULL, NULL, NULL, &e);
if (ret != 0) {
ESP_LOGE(TAG, "Failed mbedtls_rsa_import, err: %d", ret);
goto exit_inner;
}
/* Copy N (modulus) */
memcpy(p, trusted_block->key.n, n_size);
p += n_size;
ret = mbedtls_rsa_complete(&pk);
if (ret != 0) {
ESP_LOGE(TAG, "Failed mbedtls_rsa_complete, err: %d", ret);
goto exit_inner;
}
/* Copy E (exponent) */
memcpy(p, &trusted_block->key.e, e_size);
ret = mbedtls_rsa_check_pubkey(&pk);
if (ret != 0) {
ESP_LOGI(TAG, "Key is not an RSA key -%0x", -ret);
goto exit_inner;
/* Import the RSA public key */
status = psa_import_key(&key_attributes, key_data, key_data_size, &key_id);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed to import RSA public key, err: %d", status);
ret = ESP_FAIL;
goto cleanup;
}
/* Signature needs to be byte swapped into BE representation */
@@ -78,24 +74,27 @@ esp_err_t verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_bloc
sig_be[rsa_key_size - j - 1] = trusted_block->signature[j];
}
ret = mbedtls_rsa_public( &pk, sig_be, buf);
if (ret != 0) {
ESP_LOGE(TAG, "mbedtls_rsa_public failed, err: %d", ret);
goto exit_inner;
}
/* Verify the signature using PSA APIs */
status = psa_verify_hash(key_id, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256),
image_digest, ESP_SECURE_BOOT_DIGEST_LEN,
sig_be, rsa_key_size);
ret = mbedtls_rsa_rsassa_pss_verify( &pk, MBEDTLS_MD_SHA256, ESP_SECURE_BOOT_DIGEST_LEN, image_digest, sig_be);
if (ret != 0) {
ESP_LOGE(TAG, "Failed mbedtls_rsa_rsassa_pss_verify, err: %d", ret);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Signature verification failed, err: %d", status);
ret = ESP_FAIL;
} else {
ESP_LOGI(TAG, "Signature verified successfully!");
ret = ESP_OK;
}
exit_inner:
mbedtls_rsa_free(&pk);
exit_outer:
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
cleanup:
/* Clean up resources */
if (key_id != 0) {
psa_destroy_key(key_id);
}
psa_reset_key_attributes(&key_attributes);
free(key_data);
free(sig_be);
free(buf);
return ret;
}

View File

@@ -11,12 +11,6 @@
#include "bootloader_signature.h"
#include "esp_log.h"
#include "esp_image_format.h"
#include "mbedtls/sha256.h"
#include "mbedtls/x509.h"
#include "mbedtls/md.h"
#include "mbedtls/platform.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include <string.h>
#include <sys/param.h>
#include "esp_secure_boot.h"

View File

@@ -1,4 +1,4 @@
idf_component_register(SRCS "test_app_main.c" "test_verify_image.c"
INCLUDE_DIRS "."
REQUIRES unity bootloader_support esp_partition app_update
REQUIRES unity bootloader_support esp_partition app_update mbedtls
WHOLE_ARCHIVE)

View File

@@ -8,7 +8,7 @@
#include "unity_test_runner.h"
#include "esp_heap_caps.h"
#include "esp_ota_ops.h"
#include "psa/crypto.h"
// Some resources are lazy allocated, e.g. newlib locks, GDMA channel lazy installed by crypto driver
// the threshold is left for those cases
@@ -28,8 +28,10 @@ void setUp(void)
{
// load the partition table before measuring the initial free heap size.
TEST_ASSERT_NOT_EQUAL(NULL, esp_ota_get_running_partition());
psa_crypto_init();
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
void tearDown(void)