feat(bootloader_support): Support Secure Boot using ECDSA-P384 curve

This commit is contained in:
harshal.patil
2025-04-29 01:53:24 +05:30
parent 03ea07155a
commit 130e72f82b
21 changed files with 331 additions and 86 deletions

View File

@@ -559,12 +559,13 @@ menu "Security features"
depends on SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
default SECURE_BOOT_ECDSA_KEY_LEN_256_BITS
help
Select the ECDSA key size. Two key sizes are supported
Select the ECDSA key size. Three key sizes are supported depending upon on the target:
- 192 bit key using NISTP192 curve
- 256 bit key using NISTP256 curve (Recommended)
- 384 bit key using NISTP384 curve (Recommended)
The advantage of using 256 bit key is the extra randomness which makes it difficult to be
The advantage of using 384 and 256 bit keys is the extra randomness which makes it difficult to be
bruteforced compared to 192 bit key.
At present, both key sizes are practically implausible to bruteforce.
@@ -576,6 +577,10 @@ menu "Security features"
bool "Using ECC curve NISTP256 (Recommended)"
depends on SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
config SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
bool "Using ECC curve NISTP384 (Recommended)"
depends on SECURE_SIGNED_APPS_ECDSA_V2_SCHEME && SOC_ECDSA_SUPPORT_CURVE_P384
endchoice
config SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT

View File

@@ -70,6 +70,8 @@ if(CONFIG_SECURE_SIGNED_APPS)
set(scheme "ecdsa192")
elseif(CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_256_BITS)
set(scheme "ecdsa256")
elseif(CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS)
set(scheme "ecdsa384")
endif()
fail_at_build_time(gen_secure_boot_signing_key
"Secure Boot Signing Key ${CONFIG_SECURE_BOOT_SIGNING_KEY} does not exist. Generate using:"

View File

@@ -17,7 +17,6 @@
#if !CONFIG_IDF_TARGET_LINUX
#include "rom/secure_boot.h"
#endif
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
#if !defined(CONFIG_SECURE_SIGNED_ON_BOOT) || !defined(CONFIG_SECURE_SIGNED_ON_UPDATE) || !defined(CONFIG_SECURE_SIGNED_APPS)
#error "internal sdkconfig error, secure boot should always enable all signature options"
@@ -33,7 +32,11 @@ extern "C" {
Can be compiled as part of app or bootloader code.
*/
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
#define ESP_SECURE_BOOT_DIGEST_LEN 48
#else /* !CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS */
#define ESP_SECURE_BOOT_DIGEST_LEN 32
#endif /* CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS */
/* SHA-256 length of the public key digest */
#define ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN 32
@@ -197,7 +200,8 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
/** @brief Verify the secure boot signature appended to some binary data in flash.
*
* For ECDSA Scheme (Secure Boot V1) - deterministic ECDSA w/ SHA256 image
* For RSA Scheme (Secure Boot V2) - RSA-PSS Verification of the SHA-256 image
* For RSA Scheme (Secure Boot V2) - RSA-PSS Verification of the SHA-256 image digest
* For ECDSA Scheme (Secure Boot V2) - ECDSA Verification of the SHA-256 / SHA-384 (in case of ECDSA-P384 secure boot key) image digest
*
* Public key is compiled into the calling program in the ECDSA Scheme.
* See the apt docs/security/secure-boot-v1.rst or docs/security/secure-boot-v2.rst for details.
@@ -240,13 +244,13 @@ esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig
/** @brief Verify the secure boot signature block for Secure Boot V2.
*
* Performs RSA-PSS or ECDSA verification of the SHA-256 image based on the public key
* Performs RSA-PSS or ECDSA verification of the SHA-256 / SHA-384 image based on the public key
* in the signature block, compared against the public key digest stored in efuse.
*
* Similar to esp_secure_boot_verify_signature(), but can be used when the digest is precalculated.
* @param[in] sig_block Pointer to signature block data
* @param[in] image_digest Pointer to 32 byte buffer holding SHA-256 hash.
* @param[out] verified_digest Pointer to 32 byte buffer that will receive verified digest if verification completes. (Used during bootloader implementation only, result is invalid otherwise.)
* @param[in] image_digest Pointer to 32/48 byte buffer holding SHA-256/SHA-384 hash.
* @param[out] verified_digest Pointer to 32/48 byte buffer that will receive verified digest if verification completes. (Used during bootloader implementation only, result is invalid otherwise.)
*
*/
esp_err_t esp_secure_boot_verify_sbv2_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest);

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -12,15 +12,18 @@
Use mbedTLS APIs or include esp32/sha.h to calculate SHA256 in IDF apps.
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "esp_err.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void *bootloader_sha256_handle_t;
typedef bootloader_sha256_handle_t bootloader_sha_handle_t;
bootloader_sha256_handle_t bootloader_sha256_start(void);
@@ -28,6 +31,14 @@ void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data,
void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest);
#if SOC_SHA_SUPPORT_SHA512
bootloader_sha_handle_t bootloader_sha512_start(bool is384);
void bootloader_sha512_data(bootloader_sha_handle_t handle, const void *data, size_t data_len);
void bootloader_sha512_finish(bootloader_sha_handle_t handle, uint8_t *digest);
#endif /* SOC_SHA_SUPPORT_SHA512 */
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -138,6 +138,20 @@ void bootloader_debug_buffer(const void *buffer, size_t length, const char *labe
*/
esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len, uint8_t *digest);
/** @brief Generates the digest of the data between offset & offset+length.
*
* This function should be used when the size of the data is larger than 3.2MB.
* The MMU capacity is 3.2MB (50 pages - 64KB each). This function generates the SHA-384
* of the data in chunks of 3.2MB, considering the MMU capacity.
*
* @param[in] flash_offset Offset of the data in flash.
* @param[in] len Length of data in bytes.
* @param[out] digest Pointer to buffer where the digest is written, if ESP_OK is returned.
*
* @return ESP_OK if secure boot digest is generated successfully.
*/
esp_err_t bootloader_sha384_flash_contents(uint32_t flash_offset, uint32_t len, uint8_t *digest);
#ifdef __cplusplus
}
#endif

View File

@@ -29,15 +29,6 @@ bootloader_sha256_handle_t bootloader_sha256_start()
void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data, size_t data_len)
{
assert(handle != NULL);
#if !SOC_SECURE_BOOT_V2_ECC
/* For secure boot, the key field consists of 1 byte of curve identifier and 64 bytes of ECDSA public key.
* While verifying the signature block, we need to calculate the SHA of this key field which is of 65 bytes.
* ets_sha_update handles it cleanly so we can safely remove the check:
*/
assert(data_len % 4 == 0);
#endif /* SOC_SECURE_BOOT_V2_ECC */
ets_sha_update(&ctx, data, data_len, false);
}
@@ -51,6 +42,33 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest
}
ets_sha_finish(&ctx, digest);
}
#if SOC_SHA_SUPPORT_SHA512
bootloader_sha_handle_t bootloader_sha512_start(bool is384)
{
// Enable SHA hardware
ets_sha_enable();
ets_sha_init(&ctx, is384 ? SHA2_384 : SHA2_512);
return &ctx; // Meaningless non-NULL value
}
void bootloader_sha512_data(bootloader_sha_handle_t handle, const void *data, size_t data_len)
{
assert(handle != NULL);
ets_sha_update(&ctx, data, data_len, false);
}
void bootloader_sha512_finish(bootloader_sha_handle_t handle, uint8_t *digest)
{
assert(handle != NULL);
if (digest == NULL) {
bzero(&ctx, sizeof(ctx));
return;
}
ets_sha_finish(&ctx, digest);
}
#endif /* SOC_SHA_SUPPORT_SHA512 */
#else /* !CONFIG_IDF_TARGET_ESP32 */
#include "soc/dport_reg.h"
@@ -162,6 +180,7 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest
#include "bootloader_flash_priv.h"
#include <mbedtls/sha256.h>
#include <mbedtls/sha512.h>
bootloader_sha256_handle_t bootloader_sha256_start(void)
{
@@ -199,4 +218,43 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest
free(handle);
handle = NULL;
}
#if SOC_SHA_SUPPORT_SHA512
bootloader_sha_handle_t bootloader_sha512_start(bool is384)
{
mbedtls_sha512_context *ctx = (mbedtls_sha512_context *)malloc(sizeof(mbedtls_sha512_context));
if (!ctx) {
return NULL;
}
mbedtls_sha512_init(ctx);
int ret = mbedtls_sha512_starts(ctx, is384);
if (ret != 0) {
return NULL;
}
return ctx;
}
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;
}
void bootloader_sha512_finish(bootloader_sha_handle_t handle, uint8_t *digest)
{
assert(handle != NULL);
mbedtls_sha512_context *ctx = (mbedtls_sha512_context *)handle;
if (digest != NULL) {
int ret = mbedtls_sha512_finish(ctx, digest);
assert(ret == 0);
(void)ret;
}
mbedtls_sha512_free(ctx);
free(handle);
handle = NULL;
}
#endif /* SOC_SHA_SUPPORT_SHA512 */
#endif /* !(NON_OS_BUILD || CONFIG_APP_BUILD_TYPE_RAM) */

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -30,6 +30,7 @@
#include "hal/cache_types.h"
#include "hal/cache_ll.h"
#include "hal/cache_hal.h"
#include "hal/sha_types.h"
#include "esp_cpu.h"
#include "esp_image_format.h"
@@ -1213,18 +1214,29 @@ void bootloader_debug_buffer(const void *buffer, size_t length, const char *labe
#endif
}
esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len, uint8_t *digest)
static esp_err_t bootloader_sha_flash_contents(esp_sha_type type, uint32_t flash_offset, uint32_t len, uint8_t *digest)
{
if (digest == NULL) {
return ESP_ERR_INVALID_ARG;
}
/* Handling firmware images larger than MMU capacity */
uint32_t mmu_free_pages_count = bootloader_mmap_get_free_pages();
bootloader_sha256_handle_t sha_handle = NULL;
bootloader_sha_handle_t sha_handle = NULL;
if (type == SHA2_256) {
sha_handle = bootloader_sha256_start();
} else
// Using SOC_ECDSA_SUPPORT_CURVE_P384 here so that there is no flash size impact in the case of existing targets like ESP32.
#if SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384
if (type == SHA2_384) {
sha_handle = bootloader_sha512_start(true);
} else
#endif /* SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384 */
{
return ESP_ERR_INVALID_ARG;
}
if (sha_handle == NULL) {
return ESP_ERR_NO_MEM;
}
@@ -1234,7 +1246,14 @@ esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len,
uint32_t max_pages = (mmu_free_pages_count > mmu_page_offset) ? (mmu_free_pages_count - mmu_page_offset) : 0;
if (max_pages == 0) {
ESP_LOGE(TAG, "No free MMU pages are available");
if (type == SHA2_256) {
bootloader_sha256_finish(sha_handle, NULL);
}
#if SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384
else if (type == SHA2_384) {
bootloader_sha512_finish(sha_handle, NULL);
}
#endif /* SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384 */
return ESP_ERR_NO_MEM;
}
uint32_t max_image_len;
@@ -1245,15 +1264,51 @@ esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len,
const void * image = bootloader_mmap(flash_offset, partial_image_len);
if (image == NULL) {
if (type == SHA2_256) {
bootloader_sha256_finish(sha_handle, NULL);
}
#if SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384
else if (type == SHA2_384) {
bootloader_sha512_finish(sha_handle, NULL);
}
#endif /* SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384 */
return ESP_FAIL;
}
if (type == SHA2_256) {
bootloader_sha256_data(sha_handle, image, partial_image_len);
}
#if SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384
else if (type == SHA2_384) {
bootloader_sha512_data(sha_handle, image, partial_image_len);
}
#endif /* SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384 */
bootloader_munmap(image);
flash_offset += partial_image_len;
len -= partial_image_len;
}
if (type == SHA2_256) {
bootloader_sha256_finish(sha_handle, digest);
}
#if SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384
else if (type == SHA2_384) {
bootloader_sha512_finish(sha_handle, digest);
}
#endif /* SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384 */
return ESP_OK;
}
esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len, uint8_t *digest)
{
return bootloader_sha_flash_contents(SHA2_256, flash_offset, len, digest);
}
#if SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384
esp_err_t bootloader_sha384_flash_contents(uint32_t flash_offset, uint32_t len, uint8_t *digest)
{
return bootloader_sha_flash_contents(SHA2_384, flash_offset, len, digest);
}
#endif /* SOC_SHA_SUPPORT_SHA384 && SOC_ECDSA_SUPPORT_CURVE_P384 */

View File

@@ -49,6 +49,12 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
#endif
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_SHA384_EN);
#endif
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_SECURE_BOOT_SHA384_EN);
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS

View File

@@ -105,7 +105,6 @@ static esp_err_t verify_segment_header(int index, const esp_image_segment_header
static esp_err_t process_image_header(esp_image_metadata_t *data, uint32_t part_offset, bootloader_sha256_handle_t *sha_handle, bool do_verify, bool silent);
static esp_err_t process_appended_hash_and_sig(esp_image_metadata_t *data, uint32_t part_offset, uint32_t part_len, bool do_verify, bool silent);
static esp_err_t process_checksum(bootloader_sha256_handle_t sha_handle, uint32_t checksum_word, esp_image_metadata_t *data, bool silent, bool skip_check_checksum);
static esp_err_t __attribute__((unused)) verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data, uint8_t *image_digest, uint8_t *verified_digest);
static esp_err_t __attribute__((unused)) verify_simple_hash(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data);
@@ -160,8 +159,8 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
bool verify_sha;
#if (SECURE_BOOT_CHECK_SIGNATURE == 1)
/* used for anti-FI checks */
uint8_t image_digest[HASH_LEN] = { [ 0 ... 31] = 0xEE };
uint8_t verified_digest[HASH_LEN] = { [ 0 ... 31 ] = 0x01 };
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { [ 0 ... ESP_SECURE_BOOT_DIGEST_LEN - 1 ] = 0xEE };
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { [ 0 ... ESP_SECURE_BOOT_DIGEST_LEN - 1 ] = 0x01 };
#endif
if (data == NULL || part == NULL) {
@@ -237,7 +236,7 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
"only verify signature in bootloader" into the macro so it's tested multiple times.
*/
#if CONFIG_SECURE_BOOT_V2_ENABLED
ESP_FAULT_ASSERT(!esp_secure_boot_enabled() || memcmp(image_digest, verified_digest, HASH_LEN) == 0);
ESP_FAULT_ASSERT(!esp_secure_boot_enabled() || memcmp(image_digest, verified_digest, ESP_SECURE_BOOT_DIGEST_LEN) == 0);
#else // Secure Boot V1 on ESP32, only verify signatures for apps not bootloaders
ESP_FAULT_ASSERT(is_bootloader(data->start_addr) || memcmp(image_digest, verified_digest, HASH_LEN) == 0);
#endif
@@ -1028,43 +1027,14 @@ err:
return err;
}
static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data, uint8_t *image_digest, uint8_t *verified_digest)
{
#if (SECURE_BOOT_CHECK_SIGNATURE == 1)
uint32_t end = data->start_addr + data->image_len;
ESP_LOGI(TAG, "Verifying image signature...");
// For secure boot, we calculate the signature hash over the whole file, which includes any "simple" hash
// appended to the image for corruption detection
if (data->image.hash_appended) {
const void *simple_hash = bootloader_mmap(end - HASH_LEN, HASH_LEN);
bootloader_sha256_data(sha_handle, simple_hash, HASH_LEN);
bootloader_munmap(simple_hash);
}
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
// End of the image needs to be padded all the way to a 4KB boundary, after the simple hash
// (for apps they are usually already padded due to --secure-pad-v2, only a problem if this option was not used.)
uint32_t padded_end = ALIGN_UP(end, FLASH_SECTOR_SIZE);
if (padded_end > end) {
const void *padding = bootloader_mmap(end, padded_end - end);
bootloader_sha256_data(sha_handle, padding, padded_end - end);
bootloader_munmap(padding);
end = padded_end;
}
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
bootloader_sha256_finish(sha_handle, image_digest);
// Log the hash for debugging
bootloader_debug_buffer(image_digest, HASH_LEN, "Calculated secure boot hash");
static esp_err_t verify_signature_and_adjust_image_len(esp_image_metadata_t *data, uint32_t end, uint8_t *image_digest, uint8_t *verified_digest)
{
// Use hash to verify signature block
esp_err_t err = ESP_ERR_IMAGE_INVALID;
#if CONFIG_SECURE_BOOT || CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT
const void *sig_block;
ESP_FAULT_ASSERT(memcmp(image_digest, verified_digest, HASH_LEN) != 0); /* sanity check that these values start differently */
ESP_FAULT_ASSERT(memcmp(image_digest, verified_digest, ESP_SECURE_BOOT_DIGEST_LEN) != 0); /* sanity check that these values start differently */
#if defined(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
sig_block = bootloader_mmap(data->start_addr + data->image_len, sizeof(esp_secure_boot_sig_block_t));
err = esp_secure_boot_verify_ecdsa_signature_block(sig_block, image_digest, verified_digest);
@@ -1081,7 +1051,7 @@ static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_han
ESP_LOGI(TAG, "Calculating simple hash to check for corruption...");
const void *whole_image = bootloader_mmap(data->start_addr, data->image_len - HASH_LEN);
if (whole_image != NULL) {
sha_handle = bootloader_sha256_start();
bootloader_sha256_handle_t sha_handle = bootloader_sha256_start();
bootloader_sha256_data(sha_handle, whole_image, data->image_len - HASH_LEN);
bootloader_munmap(whole_image);
if (verify_simple_hash(sha_handle, data) != ESP_OK) {
@@ -1102,6 +1072,64 @@ static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_han
}
#endif
return ESP_OK;
}
#endif /* SECURE_BOOT_CHECK_SIGNATURE */
static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data, uint8_t *image_digest, uint8_t *verified_digest)
{
#if (SECURE_BOOT_CHECK_SIGNATURE == 1)
uint32_t end = data->start_addr + data->image_len;
ESP_LOGI(TAG, "Verifying image signature...");
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
(void) sha_handle;
/* Re-calculating image digest using SHA384 */
const void *image_data = bootloader_mmap(data->start_addr, data->image_len - HASH_LEN);
bootloader_sha_handle_t sha384_handle = bootloader_sha512_start(true);
bootloader_sha512_data(sha384_handle, image_data, data->image_len - HASH_LEN);
bootloader_munmap(image_data);
#endif
// For secure boot, we calculate the signature hash over the whole file, which includes any "simple" hash
// appended to the image for corruption detection
if (data->image.hash_appended) {
const void *simple_hash = bootloader_mmap(end - HASH_LEN, HASH_LEN);
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
bootloader_sha512_data(sha384_handle, simple_hash, HASH_LEN);
#else
bootloader_sha256_data(sha_handle, simple_hash, HASH_LEN);
#endif
bootloader_munmap(simple_hash);
}
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
// End of the image needs to be padded all the way to a 4KB boundary, after the simple hash
// (for apps they are usually already padded due to --secure-pad-v2, only a problem if this option was not used.)
uint32_t padded_end = ALIGN_UP(end, FLASH_SECTOR_SIZE);
if (padded_end > end) {
const void *padding = bootloader_mmap(end, padded_end - end);
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
bootloader_sha512_data(sha384_handle, padding, padded_end - end);
#else
bootloader_sha256_data(sha_handle, padding, padded_end - end);
#endif
bootloader_munmap(padding);
end = padded_end;
}
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
bootloader_sha512_finish(sha384_handle, image_digest);
#else
bootloader_sha256_finish(sha_handle, image_digest);
#endif
// Log the hash for debugging
bootloader_debug_buffer(image_digest, ESP_SECURE_BOOT_DIGEST_LEN, "Calculated secure boot hash");
return verify_signature_and_adjust_image_len(data, end, image_digest, verified_digest);
#endif // SECURE_BOOT_CHECK_SIGNATURE
return ESP_OK;
}

View File

@@ -427,7 +427,19 @@ bool esp_secure_boot_cfg_verify_release_mode(void)
#endif
}
}
#if SOC_ECDSA_SUPPORT_CURVE_P384
/* When using Secure Boot with SHA-384, the efuse bit representing Secure Boot with SHA-384 would already be programmed.
* But in the case of the existing Secure Boot V2 schemes using SHA-256, the efuse bit representing
* Secure Boot with SHA-384 needs to be write-protected, so that an attacker cannot perform a denial-of-service
* attack by changing the existing secure boot mode using SHA-256 to SHA-384.
*/
secure = esp_efuse_read_field_bit(ESP_EFUSE_WR_DIS_SECURE_BOOT_SHA384_EN);
result &= secure;
if (!secure) {
ESP_LOGW(TAG, "Not write-protected secure boot using SHA-384 mode (set WR_DIS_SECURE_BOOT_SHA384_EN->1)");
}
#endif
secure = (num_keys != 0);
result &= secure;

View File

@@ -69,7 +69,7 @@ static esp_err_t validate_signature_block(const ets_secure_boot_sig_block_t *blo
*/
static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uint32_t flash_size, esp_image_sig_public_key_digests_t *public_key_digests)
{
esp_err_t ret;
esp_err_t ret = ESP_FAIL;
uint8_t image_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
uint8_t __attribute__((aligned(4))) key_digest[ESP_SECURE_BOOT_KEY_DIGEST_SHA_256_LEN] = {0};
size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
@@ -78,7 +78,12 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
bzero(public_key_digests, sizeof(esp_image_sig_public_key_digests_t));
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
ret = bootloader_sha384_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
#else
ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
#endif
if (ret != ESP_OK) {
ESP_LOGE(TAG, "error generating image digest, %d", ret);
return ret;

View File

@@ -81,7 +81,11 @@ static esp_err_t calculate_image_public_key_digests(bool verify_image_digest, bo
bzero(public_key_digests, sizeof(esp_image_sig_public_key_digests_t));
if (verify_image_digest) {
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
ret = bootloader_sha384_flash_contents(img_metadata.start_addr, sig_block_addr - img_metadata.start_addr, image_digest);
#else
ret = bootloader_sha256_flash_contents(img_metadata.start_addr, sig_block_addr - img_metadata.start_addr, image_digest);
#endif
if (ret != ESP_OK) {
ESP_LOGE(TAG, "error generating image digest, %d", ret);
return ret;
@@ -184,13 +188,19 @@ static esp_err_t get_secure_boot_key_digests(esp_image_sig_public_key_digests_t
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
{
esp_err_t err = ESP_FAIL;
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
/* Rounding off length to the upper 4k boundary */
uint32_t padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
ESP_LOGD(TAG, "verifying signature src_addr 0x%"PRIx32" length 0x%"PRIx32, src_addr, length);
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
err = bootloader_sha384_flash_contents(src_addr, padded_length, digest);
#else
err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
#endif
if (err != ESP_OK) {
ESP_LOGE(TAG, "Digest calculation failed 0x%"PRIx32", 0x%"PRIx32, src_addr, padded_length);
return err;

View File

@@ -26,6 +26,7 @@ static const char* TAG = "secure_boot_v2";
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
{
esp_err_t err = ESP_FAIL;
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = { 0 }; /* Note: this function doesn't do any anti-FI checks on this buffer */
@@ -34,7 +35,12 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
ESP_LOGD(TAG, "verifying signature src_addr 0x%" PRIx32 " length 0x%" PRIx32, src_addr, length);
/* Calculate digest of main image */
esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
err = bootloader_sha384_flash_contents(src_addr, padded_length, digest);
#else
err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
#endif
if (err != ESP_OK) {
ESP_LOGE(TAG, "Digest calculation failed 0x%" PRIx32 ", 0x%" PRIx32, src_addr, padded_length);
return err;

View File

@@ -16,7 +16,8 @@ extern "C" {
typedef enum {
ECDSA_CURVE_P192 = 1,
ECDSA_CURVE_P256 = 2
ECDSA_CURVE_P256 = 2,
ECDSA_CURVE_P384 = 3
} ECDSA_CURVE;
int ets_ecdsa_verify(const uint8_t *key, const uint8_t *sig, ECDSA_CURVE curve_id, const uint8_t *digest, uint8_t *verified_digest);

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -88,6 +88,25 @@ struct ets_secure_boot_sig_block {
#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS
struct __attribute((packed)) ets_secure_boot_sig_block {
uint8_t magic_byte;
uint8_t version;
uint8_t sha_version;
uint8_t _reserved2;
uint8_t image_digest[48];
struct {
struct {
uint8_t curve_id; /* ETS_ECDSA_CURVE_P192 / ETS_ECDSA_CURVE_P256 */
uint8_t point[96]; /* X followed by Y (both little-endian), plus zero bytes if P192 */
} key;
uint8_t signature[96]; /* r followed by s (both little-endian) */
uint8_t padding[951];
} ecdsa;
uint32_t block_crc; /* note: crc covers all bytes in the structure before it, regardless of version field */
uint8_t _padding[16];
};
#else
struct __attribute((packed)) ets_secure_boot_sig_block {
uint8_t magic_byte;
uint8_t version;
@@ -105,6 +124,7 @@ struct __attribute((packed)) ets_secure_boot_sig_block {
uint32_t block_crc; /* note: crc covers all bytes in the structure before it, regardless of version field */
uint8_t _padding[16];
};
#endif /* CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS */
#endif
ESP_STATIC_ASSERT(sizeof(ets_secure_boot_sig_block_t) == 1216, "invalid sig block size");

View File

@@ -1119,6 +1119,10 @@ config SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP
bool
default y
config SOC_ECDSA_SUPPORT_CURVE_P384
bool
default y
config SOC_SDM_GROUPS
int
default 1

View File

@@ -442,6 +442,7 @@
#define SOC_ECDSA_SUPPORT_EXPORT_PUBKEY (1)
#define SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE (1)
#define SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP (1)
#define SOC_ECDSA_SUPPORT_CURVE_P384 (1)
/*-------------------------- Sigma Delta Modulator CAPS -----------------*/
#define SOC_SDM_GROUPS 1U

View File

@@ -2430,13 +2430,13 @@ extern "C" {
#define EFUSE_XTS_DPA_CLK_ENABLE_ERR_M (EFUSE_XTS_DPA_CLK_ENABLE_ERR_V << EFUSE_XTS_DPA_CLK_ENABLE_ERR_S)
#define EFUSE_XTS_DPA_CLK_ENABLE_ERR_V 0x00000001U
#define EFUSE_XTS_DPA_CLK_ENABLE_ERR_S 29
/** EFUSE_ECDSA_P384_ENABLE_ERR : RO; bitpos: [31]; default: 0;
* Represents the programming error of EFUSE_ECDSA_P384_ENABLE
/** EFUSE_SECURE_BOOT_SHA384_EN_ERR : RO; bitpos: [31]; default: 0;
* Represents the programming error of EFUSE_SECURE_BOOT_SHA384_EN
*/
#define EFUSE_ECDSA_P384_ENABLE_ERR (BIT(31))
#define EFUSE_ECDSA_P384_ENABLE_ERR_M (EFUSE_ECDSA_P384_ENABLE_ERR_V << EFUSE_ECDSA_P384_ENABLE_ERR_S)
#define EFUSE_ECDSA_P384_ENABLE_ERR_V 0x00000001U
#define EFUSE_ECDSA_P384_ENABLE_ERR_S 31
#define EFUSE_SECURE_BOOT_SHA384_EN_ERR (BIT(31))
#define EFUSE_SECURE_BOOT_SHA384_EN_ERR_M (EFUSE_SECURE_BOOT_SHA384_EN_ERR_V << EFUSE_SECURE_BOOT_SHA384_EN_ERR_S)
#define EFUSE_SECURE_BOOT_SHA384_EN_ERR_V 0x00000001U
#define EFUSE_SECURE_BOOT_SHA384_EN_ERR_S 31
/** EFUSE_RD_REPEAT_DATA_ERR4_REG register
* Represents rd_repeat_data_err

View File

@@ -1345,10 +1345,10 @@ typedef union {
*/
uint32_t xts_dpa_clk_enable_err:1;
uint32_t reserved_30:1;
/** ecdsa_p384_enable_err : RO; bitpos: [31]; default: 0;
* Represents the programming error of EFUSE_ECDSA_P384_ENABLE
/** secure_boot_sha384_en_err : RO; bitpos: [31]; default: 0;
* Represents the programming error of EFUSE_SECURE_BOOT_SHA384_EN
*/
uint32_t ecdsa_p384_enable_err:1;
uint32_t secure_boot_sha384_en_err:1;
};
uint32_t val;
} efuse_rd_repeat_data_err3_reg_t;

View File

@@ -485,7 +485,8 @@ In this workflow we shall use ``espsecure`` tool to generate signing keys and us
: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 ECDSA curve mode.
:SOC_ECDSA_P192_CURVE_DEFAULT_DISABLED: - ``WR_DIS_ECDSA_CURVE_MODE``: Write disable ECDSA curve mode.
:SOC_ECDSA_SUPPORT_CURVE_P384: - ``WR_DIS_SECURE_BOOT_SHA384_EN``: Disallow writing to the secure boot using SHA-384 efuse bit.
The respective eFuses can be burned by running:

View File

@@ -813,9 +813,9 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
'secure-generate-signing-key': {
'callback': secure_generate_signing_key,
'help': (
'Generate a private key for signing secure boot images as per the secure boot version. Key file is '
'generated in PEM format, Secure Boot V1 - ECDSA NIST256p private key. Secure Boot V2 - RSA 3072, '
'ECDSA NIST256p, ECDSA NIST192p private key.'
'Generate a private key for signing secure boot images as per the secure boot version.'
' Key file is generated in PEM format, Secure Boot V1 - ECDSA NIST256p private key.'
' Secure Boot V2 - RSA 3072, ECDSA NIST384p, ECDSA NIST256p, ECDSA NIST192p private key.'
),
'options': [
{
@@ -827,7 +827,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
{
'names': ['--scheme', '-s'],
'help': ('Scheme of secure boot signing.'),
'type': click.Choice(['rsa3072', 'ecdsa192', 'ecdsa256']),
'type': click.Choice(['rsa3072', 'ecdsa192', 'ecdsa256', 'ecdsa384']),
},
],
'arguments': [
@@ -854,8 +854,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
'secure-sign-data': {
'callback': secure_sign_data,
'help': (
'Sign a data file for use with secure boot. Signing algorithm is deterministic ECDSA w/ SHA-512 '
'(V1) or either RSA-PSS or ECDSA w/ SHA-256 (V2).'
'Sign a data file for use with secure boot. Signing algorithm is deterministic'
' ECDSA w/ SHA-512 (V1) or either RSA-PSS or ECDSA w/ SHA-256 (V2) or ECDSA w/ SHA-384 (V2).'
),
'options': [
{
@@ -871,7 +871,9 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
{
'names': ['--append-signatures', '-a'],
'is_flag': True,
'help': ('Append signature block(s) to already signed image. Valid only for ESP32-S2.'),
'help': (
'Append signature block(s) to already signed image. Not valid for ESP32 and ESP32-C2.'
),
},
{
'names': ['--pub-key'],