mirror of
https://github.com/espressif/esp-idf.git
synced 2026-08-18 06:35:35 +03:00
feat: migrates bootloader_support to PSA APIs
This commit is contained in:
committed by
Mahavir Jain
parent
dbd198a97e
commit
eb95eafac1
@@ -179,81 +179,117 @@ 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) {
|
||||
psa_hash_operation_t *op = (psa_hash_operation_t *)malloc(sizeof(psa_hash_operation_t));
|
||||
if (!op) {
|
||||
return NULL;
|
||||
}
|
||||
mbedtls_sha256_init(ctx);
|
||||
int ret = mbedtls_sha256_starts(ctx, false);
|
||||
if (ret != 0) {
|
||||
|
||||
*op = psa_hash_operation_init();
|
||||
psa_status_t status = psa_hash_setup(op, PSA_ALG_SHA_256);
|
||||
if (status != PSA_SUCCESS) {
|
||||
free(op);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
|
||||
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));
|
||||
(void)status; // Suppress unused variable warning in release builds
|
||||
(void)hash_len; // Suppress unused variable warning in release builds
|
||||
} else {
|
||||
psa_hash_abort(op);
|
||||
}
|
||||
mbedtls_sha256_free(ctx);
|
||||
|
||||
free(handle);
|
||||
handle = NULL;
|
||||
}
|
||||
|
||||
#if SOC_SHA_SUPPORT_SHA512
|
||||
|
||||
typedef struct {
|
||||
psa_hash_operation_t *hash_op;
|
||||
int psa_alg;
|
||||
} bootloader_psa_sha_handle_t;
|
||||
|
||||
bootloader_sha_handle_t bootloader_sha512_start(bool is384)
|
||||
{
|
||||
mbedtls_sha512_context *ctx = (mbedtls_sha512_context *)malloc(sizeof(mbedtls_sha512_context));
|
||||
if (!ctx) {
|
||||
psa_status_t status;
|
||||
bootloader_psa_sha_handle_t *op = (bootloader_psa_sha_handle_t *)malloc(sizeof(bootloader_psa_sha_handle_t));
|
||||
if (!op) {
|
||||
return NULL;
|
||||
}
|
||||
mbedtls_sha512_init(ctx);
|
||||
int ret = mbedtls_sha512_starts(ctx, is384);
|
||||
if (ret != 0) {
|
||||
|
||||
op->hash_op = (psa_hash_operation_t *)malloc(sizeof(psa_hash_operation_t));
|
||||
if (!op->hash_op) {
|
||||
free(op);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
|
||||
op->psa_alg = is384 ? PSA_ALG_SHA_384 : PSA_ALG_SHA_512;
|
||||
|
||||
*op->hash_op = psa_hash_operation_init();
|
||||
status = psa_hash_setup(op->hash_op, op->psa_alg);
|
||||
if (status != PSA_SUCCESS) {
|
||||
free(op->hash_op);
|
||||
free(op);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (bootloader_psa_sha_handle_t *)op;
|
||||
}
|
||||
|
||||
void bootloader_sha512_data(bootloader_sha_handle_t handle, const void *data, size_t data_len)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
mbedtls_sha512_context *ctx = (mbedtls_sha512_context *)handle;
|
||||
int ret = mbedtls_sha512_update(ctx, data, data_len);
|
||||
assert(ret == 0);
|
||||
(void)ret;
|
||||
bootloader_psa_sha_handle_t *op = (bootloader_psa_sha_handle_t *)handle;
|
||||
|
||||
psa_status_t status = psa_hash_update(op->hash_op, data, data_len);
|
||||
assert(status == PSA_SUCCESS);
|
||||
(void)status; // Suppress unused variable warning in release builds
|
||||
}
|
||||
|
||||
void bootloader_sha512_finish(bootloader_sha_handle_t handle, uint8_t *digest)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
mbedtls_sha512_context *ctx = (mbedtls_sha512_context *)handle;
|
||||
bootloader_psa_sha_handle_t *op = (bootloader_psa_sha_handle_t *)handle;
|
||||
|
||||
if (digest != NULL) {
|
||||
int ret = mbedtls_sha512_finish(ctx, digest);
|
||||
assert(ret == 0);
|
||||
(void)ret;
|
||||
size_t hash_len;
|
||||
psa_status_t status = psa_hash_finish(op->hash_op, digest, PSA_HASH_LENGTH(op->psa_alg), &hash_len);
|
||||
assert(status == PSA_SUCCESS);
|
||||
assert(hash_len == PSA_HASH_LENGTH(op->psa_alg));
|
||||
(void)status; // Suppress unused variable warning in release builds
|
||||
(void)hash_len; // Suppress unused variable warning in release builds
|
||||
} else {
|
||||
psa_hash_abort(op->hash_op);
|
||||
}
|
||||
mbedtls_sha512_free(ctx);
|
||||
free(handle);
|
||||
|
||||
free(op->hash_op);
|
||||
free(op);
|
||||
handle = NULL;
|
||||
}
|
||||
#endif /* SOC_SHA_SUPPORT_SHA512 */
|
||||
|
||||
@@ -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,14 +11,11 @@
|
||||
#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>
|
||||
#include "mbedtls/pk.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot_v1");
|
||||
@@ -27,7 +24,9 @@ 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
|
||||
#define UNCOMPRESSED_SECP256R1_KEY_SIZE 65 // Size for uncompressed SECP256R1 (1 + 32 + 32)
|
||||
#define ECC_UNCOMPRESSED_POINT_FORMAT_INDICATOR 0x04
|
||||
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 +75,47 @@ 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;
|
||||
// Format the public key for PSA import
|
||||
uint8_t formatted_key[UNCOMPRESSED_SECP256R1_KEY_SIZE];
|
||||
formatted_key[0] = ECC_UNCOMPRESSED_POINT_FORMAT_INDICATOR;
|
||||
|
||||
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);
|
||||
// Copy X and Y coordinates
|
||||
if (keylen == 64) { // Raw coordinates without format byte
|
||||
memcpy(&formatted_key[1], signature_verification_key_start, 64);
|
||||
} else if (keylen == UNCOMPRESSED_SECP256R1_KEY_SIZE && signature_verification_key_start[0] == ECC_UNCOMPRESSED_POINT_FORMAT_INDICATOR) {
|
||||
// Key is already in correct format
|
||||
memcpy(formatted_key, signature_verification_key_start, UNCOMPRESSED_SECP256R1_KEY_SIZE);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid key format or length");
|
||||
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);
|
||||
// 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);
|
||||
|
||||
// Import the properly formatted public key
|
||||
status = psa_import_key(&key_attributes, formatted_key, sizeof(formatted_key), &key_handle);
|
||||
if (status != PSA_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Failed to import key, status:%d", status);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Initialise ECDSA context */
|
||||
mbedtls_ecdsa_context ecdsa_context;
|
||||
mbedtls_ecdsa_init(&ecdsa_context);
|
||||
// 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_LOGI(TAG, "Verification result %d", status);
|
||||
|
||||
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;
|
||||
}
|
||||
// Destroy the key handle
|
||||
psa_destroy_key(key_handle);
|
||||
psa_reset_key_attributes(&key_attributes);
|
||||
|
||||
/* 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
|
||||
|
||||
@@ -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,32 +25,35 @@ 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:
|
||||
key_size = 48;
|
||||
mbedtls_ecp_group_load(&ecdsa_context.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP384R1);
|
||||
curve_family = PSA_ECC_FAMILY_SECP_R1;
|
||||
psa_set_key_bits(&key_attributes, PSA_BYTES_TO_BITS(key_size));
|
||||
break;
|
||||
#endif /* CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS */
|
||||
default:
|
||||
@@ -64,50 +61,58 @@ 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) + 1];
|
||||
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;
|
||||
public_key[0] = 0x04; /* Uncompressed point format */
|
||||
|
||||
/* Combine X and Y into a single public key buffer */
|
||||
memcpy(public_key + 1, x_point, key_size);
|
||||
memcpy(public_key + 1 + key_size, y_point, key_size);
|
||||
|
||||
/* Import the public key */
|
||||
status = psa_import_key(&key_attributes, public_key, (2 * key_size) + 1, &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;
|
||||
}
|
||||
|
||||
@@ -1,76 +1,166 @@
|
||||
/*
|
||||
* 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 "psa/crypto.h"
|
||||
#include "mbedtls/asn1.h"
|
||||
#include "mbedtls/asn1write.h"
|
||||
#include "mbedtls/x509.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
|
||||
#include "secure_boot_signature_priv.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "secure_boot_v2_rsa");
|
||||
|
||||
/*
|
||||
* Helper function to encode RSA public key (N, e) into DER format manually
|
||||
* This creates a PKCS#1 RSAPublicKey structure:
|
||||
*
|
||||
* RSAPublicKey ::= SEQUENCE {
|
||||
* modulus INTEGER, -- n
|
||||
* publicExponent INTEGER -- e
|
||||
* }
|
||||
*/
|
||||
static int encode_rsa_pubkey_der(const uint8_t *modulus, size_t modulus_len,
|
||||
const uint8_t *exponent, size_t exponent_len,
|
||||
uint8_t *der_buf, size_t der_buf_size,
|
||||
uint8_t **der_start, size_t *der_len)
|
||||
{
|
||||
if (!der_buf || !der_start || !der_len || der_buf_size == 0) {
|
||||
return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
|
||||
}
|
||||
|
||||
int ret;
|
||||
unsigned char *c = der_buf + der_buf_size;
|
||||
size_t len = 0;
|
||||
|
||||
/* Write the exponent (e) as an INTEGER */
|
||||
/* Skip leading zeros in exponent */
|
||||
while (exponent_len > 0 && *exponent == 0) {
|
||||
exponent++;
|
||||
exponent_len--;
|
||||
}
|
||||
|
||||
/* Write exponent */
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(&c, der_buf, exponent, exponent_len));
|
||||
|
||||
/* Add padding byte if MSB is set (to keep it positive) */
|
||||
if (exponent_len > 0 && (exponent[0] & 0x80)) {
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(&c, der_buf, (const unsigned char *)"\x00", 1));
|
||||
}
|
||||
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, der_buf, exponent_len + ((exponent[0] & 0x80) ? 1 : 0)));
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, der_buf, MBEDTLS_ASN1_INTEGER));
|
||||
|
||||
/* Write the modulus (N) as an INTEGER */
|
||||
/* Skip leading zeros in modulus */
|
||||
const uint8_t *mod_ptr = modulus;
|
||||
size_t mod_len = modulus_len;
|
||||
while (mod_len > 0 && *mod_ptr == 0) {
|
||||
mod_ptr++;
|
||||
mod_len--;
|
||||
}
|
||||
|
||||
/* Write modulus */
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(&c, der_buf, mod_ptr, mod_len));
|
||||
|
||||
/* Add padding byte if MSB is set */
|
||||
if (mod_len > 0 && (mod_ptr[0] & 0x80)) {
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(&c, der_buf, (const unsigned char *)"\x00", 1));
|
||||
}
|
||||
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, der_buf, mod_len + ((mod_ptr[0] & 0x80) ? 1 : 0)));
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, der_buf, MBEDTLS_ASN1_INTEGER));
|
||||
|
||||
/* Write SEQUENCE header */
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, der_buf, len));
|
||||
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, der_buf,
|
||||
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
|
||||
|
||||
*der_start = c;
|
||||
*der_len = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
esp_err_t verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, const ets_secure_boot_sig_block_t *trusted_block)
|
||||
{
|
||||
if (!sig_block || !image_digest || !trusted_block) {
|
||||
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);
|
||||
unsigned char *sig_be = NULL;
|
||||
unsigned char *pubkey_der_buf = NULL;
|
||||
|
||||
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;
|
||||
|
||||
/* Allocate buffer for DER-encoded public key */
|
||||
size_t pubkey_der_buf_size = PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(3072);
|
||||
pubkey_der_buf = calloc(1, pubkey_der_buf_size);
|
||||
if (pubkey_der_buf == 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;
|
||||
/* Convert raw N and e to DER format manually */
|
||||
uint8_t *der_start = NULL;
|
||||
size_t der_len = 0;
|
||||
|
||||
/* Convert modulus from little-endian to big-endian */
|
||||
uint8_t *n_be = calloc(1, rsa_key_size);
|
||||
if (n_be == NULL) {
|
||||
free(sig_be);
|
||||
free(pubkey_der_buf);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
for (size_t i = 0; i < rsa_key_size; i++) {
|
||||
n_be[i] = trusted_block->key.n[rsa_key_size - 1 - i];
|
||||
}
|
||||
|
||||
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);
|
||||
/* Convert e from uint32_t to byte array (big-endian) */
|
||||
uint8_t e_bytes[4];
|
||||
e_bytes[0] = (trusted_block->key.e >> 24) & 0xFF;
|
||||
e_bytes[1] = (trusted_block->key.e >> 16) & 0xFF;
|
||||
e_bytes[2] = (trusted_block->key.e >> 8) & 0xFF;
|
||||
e_bytes[3] = trusted_block->key.e & 0xFF;
|
||||
|
||||
ret = encode_rsa_pubkey_der(
|
||||
n_be, rsa_key_size,
|
||||
e_bytes, sizeof(e_bytes),
|
||||
pubkey_der_buf, pubkey_der_buf_size,
|
||||
&der_start, &der_len
|
||||
);
|
||||
|
||||
free(n_be);
|
||||
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_import, err: %d", ret);
|
||||
goto exit_inner;
|
||||
ESP_LOGE(TAG, "Failed to encode RSA public key to DER, err: %d", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_complete(&pk);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_complete, err: %d", ret);
|
||||
goto exit_inner;
|
||||
}
|
||||
/* 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);
|
||||
|
||||
ret = mbedtls_rsa_check_pubkey(&pk);
|
||||
if (ret != 0) {
|
||||
ESP_LOGI(TAG, "Key is not an RSA key -%0x", -ret);
|
||||
goto exit_inner;
|
||||
/* Import DER-encoded public key into PSA */
|
||||
status = psa_import_key(&key_attributes, der_start, der_len, &key_id);
|
||||
if (status != PSA_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Failed to import key into PSA, err: %d", status);
|
||||
ret = ESP_FAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Signature needs to be byte swapped into BE representation */
|
||||
@@ -78,24 +168,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(sig_be);
|
||||
free(buf);
|
||||
free(pubkey_der_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user