mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
esp32c2: Support Secure Boot V2 based on ECDSA scheme
This commit is contained in:
parent
dec3db6913
commit
2c725264f7
@ -449,7 +449,12 @@ menu "Security features"
|
||||
bool
|
||||
default y
|
||||
# RSA secure boot is supported in ESP32 revision >= ECO3
|
||||
depends on ESP32_REV_MIN >= 3 || SOC_SECURE_BOOT_V2_RSA
|
||||
depends on (IDF_TARGET_ESP32 && ESP32_REV_MIN >= 3) || SOC_SECURE_BOOT_V2_RSA
|
||||
|
||||
config SECURE_BOOT_V2_ECC_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
depends on SOC_SECURE_BOOT_V2_ECC
|
||||
|
||||
config SECURE_BOOT_V1_SUPPORTED
|
||||
bool
|
||||
@ -461,6 +466,13 @@ menu "Security features"
|
||||
default y
|
||||
depends on ESP32_REV_MIN >= 3
|
||||
|
||||
config SECURE_BOOT_V2_ECDSA_ENABLED
|
||||
bool
|
||||
default y if SECURE_BOOT_V2_ENABLED && SECURE_BOOT_V2_ECC_SUPPORTED
|
||||
|
||||
config SECURE_BOOT_V2_RSA_ENABLED
|
||||
bool
|
||||
default y if SECURE_BOOT_V2_ENABLED && SECURE_BOOT_V2_RSA_SUPPORTED
|
||||
|
||||
config SECURE_SIGNED_APPS_NO_SECURE_BOOT
|
||||
bool "Require signed app images"
|
||||
@ -477,21 +489,26 @@ menu "Security features"
|
||||
bool "App Signing Scheme"
|
||||
depends on SECURE_BOOT || SECURE_SIGNED_APPS_NO_SECURE_BOOT
|
||||
default SECURE_SIGNED_APPS_ECDSA_SCHEME if SECURE_BOOT_V1_ENABLED
|
||||
default SECURE_SIGNED_APPS_RSA_SCHEME if SECURE_BOOT_V2_ENABLED
|
||||
default SECURE_SIGNED_APPS_RSA_SCHEME if SECURE_BOOT_V2_RSA_SUPPORTED
|
||||
default SECURE_SIGNED_APPS_ECDSA_V2_SCHEME if SECURE_BOOT_V2_ECC_SUPPORTED
|
||||
help
|
||||
Select the Secure App signing scheme. Depends on the Chip Revision.
|
||||
There are two options:
|
||||
1. ECDSA based secure boot scheme. (Only choice for Secure Boot V1)
|
||||
Supported in ESP32 and ESP32-ECO3.
|
||||
2. The RSA based secure boot scheme. (Only choice for Secure Boot V2)
|
||||
Supported in ESP32-ECO3 (ESP32 Chip Revision 3 onwards), ESP32-S2, ESP32-C3, ESP32-S3.
|
||||
There are two secure boot versions:
|
||||
|
||||
1. Secure boot V1
|
||||
- Legacy custom secure boot scheme. Supported in ESP32 SoC.
|
||||
|
||||
2. Secure boot V2
|
||||
- RSA based secure boot scheme.
|
||||
Supported in ESP32-ECO3 (ESP32 Chip Revision 3 onwards), ESP32-S2, ESP32-C3, ESP32-S3 SoCs.
|
||||
|
||||
- ECDSA based secure boot scheme. Supported in ESP32-C2 SoC.
|
||||
|
||||
config SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
bool "ECDSA"
|
||||
depends on SECURE_BOOT_V1_SUPPORTED && (SECURE_SIGNED_APPS_NO_SECURE_BOOT || SECURE_BOOT_V1_ENABLED)
|
||||
help
|
||||
Embeds the ECDSA public key in the bootloader and signs the application with an ECDSA key.
|
||||
|
||||
Refer to the documentation before enabling.
|
||||
|
||||
config SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
@ -500,6 +517,38 @@ menu "Security features"
|
||||
help
|
||||
Appends the RSA-3072 based Signature block to the application.
|
||||
Refer to <Secure Boot Version 2 documentation link> before enabling.
|
||||
|
||||
config SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
bool "ECDSA (V2)"
|
||||
depends on SECURE_BOOT_V2_ECC_SUPPORTED && (SECURE_SIGNED_APPS_NO_SECURE_BOOT || SECURE_BOOT_V2_ENABLED)
|
||||
help
|
||||
For Secure boot V2 (e.g., ESP32-C2 SoC), appends ECDSA based signature block to the application.
|
||||
Refer to documentation before enabling.
|
||||
|
||||
endchoice
|
||||
|
||||
choice SECURE_BOOT_ECDSA_KEY_LEN_SIZE
|
||||
bool "ECDSA key size"
|
||||
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
|
||||
|
||||
- 192 bit key using NISTP192 curve
|
||||
- 256 bit key using NISTP256 curve (Recommended)
|
||||
|
||||
The advantage of using 256 bit key 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.
|
||||
|
||||
config SECURE_BOOT_ECDSA_KEY_LEN_192_BITS
|
||||
bool "Using ECC curve NISTP192"
|
||||
depends on SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
|
||||
config SECURE_BOOT_ECDSA_KEY_LEN_256_BITS
|
||||
bool "Using ECC curve NISTP256 (Recommended)"
|
||||
depends on SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
|
||||
endchoice
|
||||
|
||||
config SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT
|
||||
@ -549,10 +598,16 @@ menu "Security features"
|
||||
depends on SECURE_BOOT
|
||||
help
|
||||
Select the Secure Boot Version. Depends on the Chip Revision.
|
||||
Secure Boot V2 is the new RSA based secure boot scheme.
|
||||
Supported in ESP32-ECO3 (ESP32 Chip Revision 3 onwards), ESP32-S2, ESP32-C3 ECO3.
|
||||
Secure Boot V1 is the AES based secure boot scheme.
|
||||
Supported in ESP32 and ESP32-ECO3.
|
||||
Secure Boot V2 is the new RSA / ECDSA based secure boot scheme.
|
||||
|
||||
- RSA based scheme is supported in ESP32 (Revision 3 onwards), ESP32-S2, ESP32-C3 (ECO3), ESP32-S3.
|
||||
- ECDSA based scheme is supported in ESP32-C2 SoC.
|
||||
|
||||
Please note that, RSA or ECDSA secure boot is property of specific SoC based on its HW design, supported
|
||||
crypto accelerators, die-size, cost and similar parameters. Please note that RSA scheme has requirement
|
||||
for bigger key sizes but at the same time it is comparatively faster than ECDSA verification.
|
||||
|
||||
Secure Boot V1 is the AES based (custom) secure boot scheme supported in ESP32 SoC.
|
||||
|
||||
config SECURE_BOOT_V1_ENABLED
|
||||
bool "Enable Secure Boot version 1"
|
||||
@ -563,7 +618,7 @@ menu "Security features"
|
||||
|
||||
config SECURE_BOOT_V2_ENABLED
|
||||
bool "Enable Secure Boot version 2"
|
||||
depends on SECURE_BOOT_V2_RSA_SUPPORTED
|
||||
depends on SECURE_BOOT_V2_RSA_SUPPORTED || SECURE_BOOT_V2_ECC_SUPPORTED
|
||||
help
|
||||
Build a bootloader which enables Secure Boot version 2 on first boot.
|
||||
Refer to Secure Boot V2 section of the ESP-IDF Programmer's Guide for this version before enabling.
|
||||
|
@ -30,9 +30,9 @@ if(CONFIG_SECURE_SIGNED_APPS)
|
||||
add_custom_target(gen_secure_boot_keys)
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
|
||||
set(secure_apps_signing_scheme "1")
|
||||
elseif(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
set(secure_apps_signing_scheme "2")
|
||||
set(secure_apps_signing_version "1")
|
||||
elseif(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME OR CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME)
|
||||
set(secure_apps_signing_version "2")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SECURE_BOOT_V1_ENABLED)
|
||||
@ -64,10 +64,22 @@ if(CONFIG_SECURE_SIGNED_APPS)
|
||||
# If the signing key is not found, create a phony gen_secure_boot_signing_key target that
|
||||
# fails the build. fail_at_build_time causes a cmake run next time
|
||||
# (to pick up a new signing key if one exists, etc.)
|
||||
fail_at_build_time(gen_secure_boot_signing_key
|
||||
"Secure Boot Signing Key ${CONFIG_SECURE_BOOT_SIGNING_KEY} does not exist. Generate using:"
|
||||
"\tespsecure.py generate_signing_key --version ${secure_apps_signing_scheme} \
|
||||
${CONFIG_SECURE_BOOT_SIGNING_KEY}")
|
||||
if(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
fail_at_build_time(gen_secure_boot_signing_key
|
||||
"Secure Boot Signing Key ${CONFIG_SECURE_BOOT_SIGNING_KEY} does not exist. Generate using:"
|
||||
"\tespsecure.py generate_signing_key --version ${secure_apps_signing_version} \
|
||||
${CONFIG_SECURE_BOOT_SIGNING_KEY}")
|
||||
else()
|
||||
if(CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_192_BITS)
|
||||
set(scheme "ecdsa192")
|
||||
elseif(CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_256_BITS)
|
||||
set(scheme "ecdsa256")
|
||||
endif()
|
||||
fail_at_build_time(gen_secure_boot_signing_key
|
||||
"Secure Boot Signing Key ${CONFIG_SECURE_BOOT_SIGNING_KEY} does not exist. Generate using:"
|
||||
"\tespsecure.py generate_signing_key --version ${secure_apps_signing_version} \
|
||||
--scheme ${scheme} ${CONFIG_SECURE_BOOT_SIGNING_KEY}")
|
||||
endif()
|
||||
else()
|
||||
add_custom_target(gen_secure_boot_signing_key)
|
||||
endif()
|
||||
|
@ -55,11 +55,9 @@ if(BOOTLOADER_BUILD)
|
||||
"src/${IDF_TARGET}/secure_boot_secure_features.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
list(APPEND srcs "src/secure_boot_v2/secure_boot_signatures_bootloader.c")
|
||||
endif()
|
||||
if(CONFIG_SECURE_BOOT_V2_ENABLED)
|
||||
list(APPEND srcs "src/secure_boot_v2/secure_boot.c"
|
||||
list(APPEND srcs "src/secure_boot_v2/secure_boot_signatures_bootloader.c"
|
||||
"src/secure_boot_v2/secure_boot.c"
|
||||
"src/${IDF_TARGET}/secure_boot_secure_features.c")
|
||||
endif()
|
||||
endif()
|
||||
@ -71,6 +69,11 @@ else()
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
list(APPEND srcs "src/secure_boot_v2/secure_boot_signatures_app.c")
|
||||
list(APPEND srcs "src/secure_boot_v2/secure_boot_rsa_signature.c")
|
||||
endif()
|
||||
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME)
|
||||
list(APPEND srcs "src/secure_boot_v2/secure_boot_signatures_app.c")
|
||||
list(APPEND srcs "src/secure_boot_v2/secure_boot_ecdsa_signature.c")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
@ -51,6 +51,12 @@ extern "C" {
|
||||
|
||||
#define ESP_SECURE_BOOT_DIGEST_LEN 32
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C2
|
||||
#define ESP_SECURE_BOOT_KEY_DIGEST_LEN 16
|
||||
#else
|
||||
#define ESP_SECURE_BOOT_KEY_DIGEST_LEN 32
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
@ -215,18 +221,30 @@ typedef struct {
|
||||
unsigned num_digests; /* Number of valid digests, starting at index 0 */
|
||||
} esp_image_sig_public_key_digests_t;
|
||||
|
||||
/** @brief Verify the RSA secure boot signature block for Secure Boot V2.
|
||||
/** @brief Verify the secure boot signature block for Secure Boot V2.
|
||||
*
|
||||
* Performs RSA-PSS Verification of the SHA-256 image based on the public key
|
||||
* Performs RSA-PSS or ECDSA verification of the SHA-256 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 sig_block Pointer to signature block data
|
||||
* @param image_digest Pointer to 32 byte buffer holding SHA-256 hash.
|
||||
* @param verified_digest Pointer to 32 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);
|
||||
|
||||
/** @brief Legacy function to verify RSA secure boot signature block for Secure Boot V2.
|
||||
*
|
||||
* @note This is kept for backward compatibility. It internally calls esp_secure_boot_verify_sbv2_signature_block.
|
||||
*
|
||||
* @param sig_block Pointer to RSA signature block data
|
||||
* @param image_digest Pointer to 32 byte buffer holding SHA-256 hash.
|
||||
* @param verified_digest Pointer to 32 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_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest);
|
||||
|
||||
#endif // !CONFIG_IDF_TARGET_ESP32 || CONFIG_ESP32_REV_MIN_3
|
||||
|
||||
/** @brief Legacy ECDSA verification function
|
||||
@ -259,7 +277,7 @@ typedef struct {
|
||||
*/
|
||||
void esp_secure_boot_init_checks(void);
|
||||
|
||||
#if !BOOTLOADER_BUILD && CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
#if !BOOTLOADER_BUILD && (CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME)
|
||||
|
||||
/** @brief Scan the current running app for signature blocks
|
||||
*
|
||||
@ -285,7 +303,7 @@ void esp_secure_boot_init_checks(void);
|
||||
*/
|
||||
esp_err_t esp_secure_boot_get_signature_blocks_for_running_app(bool digest_public_keys, esp_image_sig_public_key_digests_t *public_key_digests);
|
||||
|
||||
#endif // !BOOTLOADER_BUILD && CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
#endif // !BOOTLOADER_BUILD && (CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME)
|
||||
|
||||
/** @brief Set all secure eFuse features related to secure_boot
|
||||
*
|
||||
|
@ -16,7 +16,7 @@ static __attribute__((unused)) const char *TAG = "secure_boot";
|
||||
|
||||
esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
{
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT);
|
||||
|
||||
#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
|
||||
ESP_LOGI(TAG, "Enabling Security download mode...");
|
||||
@ -39,16 +39,10 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
|
||||
#endif
|
||||
|
||||
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
|
||||
return ESP_OK;
|
||||
|
@ -827,7 +827,7 @@ static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_han
|
||||
bootloader_munmap(simple_hash);
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
#if CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
// 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 = (end + FLASH_SECTOR_SIZE - 1) & ~(FLASH_SECTOR_SIZE-1);
|
||||
@ -846,18 +846,18 @@ static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_han
|
||||
|
||||
// Use hash to verify signature block
|
||||
esp_err_t err = ESP_ERR_IMAGE_INVALID;
|
||||
#if defined(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME) || defined(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
#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 */
|
||||
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
|
||||
#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);
|
||||
#else
|
||||
sig_block = bootloader_mmap(end, sizeof(ets_secure_boot_signature_t));
|
||||
err = esp_secure_boot_verify_rsa_signature_block(sig_block, image_digest, verified_digest);
|
||||
err = esp_secure_boot_verify_sbv2_signature_block(sig_block, image_digest, verified_digest);
|
||||
#endif
|
||||
bootloader_munmap(sig_block);
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME or CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
#endif // CONFIG_SECURE_BOOT || CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure boot signature verification failed");
|
||||
|
||||
@ -877,7 +877,7 @@ static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_han
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
// Adjust image length result to include the appended signature
|
||||
data->image_len = end - data->start_addr + sizeof(ets_secure_boot_signature_t);
|
||||
#endif
|
||||
|
@ -98,12 +98,20 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin
|
||||
/* Generating the SHA of the public key components in the signature block */
|
||||
bootloader_sha256_handle_t sig_block_sha;
|
||||
sig_block_sha = bootloader_sha256_start();
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &block->key, sizeof(block->key));
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &block->ecdsa.key, sizeof(block->ecdsa.key));
|
||||
#endif
|
||||
bootloader_sha256_finish(sig_block_sha, key_digest);
|
||||
|
||||
// Check we can verify the image using this signature and this key
|
||||
uint8_t temp_verified_digest[ESP_SECURE_BOOT_DIGEST_LEN];
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
bool verified = ets_rsa_pss_verify(&block->key, block->signature, image_digest, temp_verified_digest);
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
bool verified = ets_ecdsa_verify(&block->ecdsa.key.point[0], block->ecdsa.signature, block->ecdsa.key.curve_id, image_digest, temp_verified_digest);
|
||||
#endif
|
||||
|
||||
if (!verified) {
|
||||
/* We don't expect this: the signature blocks before we enable secure boot should all be verifiable or invalid,
|
||||
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 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 "mbedtls/ecp.h"
|
||||
#include "rom/ecdsa.h"
|
||||
|
||||
static const char *TAG = "secure_boot_v2_ecdsa";
|
||||
|
||||
#define ECDSA_INTEGER_LEN 32
|
||||
|
||||
esp_err_t verify_ecdsa_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;
|
||||
}
|
||||
|
||||
esp_err_t ret;
|
||||
|
||||
mbedtls_mpi r, s;
|
||||
|
||||
mbedtls_mpi_init(&r);
|
||||
mbedtls_mpi_init(&s);
|
||||
|
||||
/* Initialise ECDSA context */
|
||||
mbedtls_ecdsa_context ecdsa_context;
|
||||
mbedtls_ecdsa_init(&ecdsa_context);
|
||||
|
||||
uint8_t key_size = 0;
|
||||
|
||||
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);
|
||||
break;
|
||||
case ECDSA_CURVE_P256:
|
||||
key_size = 32;
|
||||
mbedtls_ecp_group_load(&ecdsa_context.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid curve ID");
|
||||
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] = {};
|
||||
|
||||
/* Convert r and s components 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];
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
size_t plen = mbedtls_mpi_size(&ecdsa_context.MBEDTLS_PRIVATE(grp).P);
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
/* 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);
|
||||
return ret;
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 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"
|
||||
|
||||
static const char *TAG = "secure_boot_v2_rsa";
|
||||
|
||||
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;
|
||||
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) {
|
||||
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\n", ret);
|
||||
goto exit_outer;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_complete(&pk);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_complete, err: %d", ret);
|
||||
goto exit_inner;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_check_pubkey(&pk);
|
||||
if (ret != 0) {
|
||||
ESP_LOGI(TAG, "Key is not an RSA key -%0x", -ret);
|
||||
goto exit_inner;
|
||||
}
|
||||
|
||||
/* Signature needs to be byte swapped into BE representation */
|
||||
for (int j = 0; j < rsa_key_size; j++) {
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Signature verified successfully!");
|
||||
}
|
||||
exit_inner:
|
||||
mbedtls_rsa_free(&pk);
|
||||
exit_outer:
|
||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
||||
mbedtls_entropy_free(&entropy);
|
||||
free(sig_be);
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
esp_err_t verify_ecdsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, const ets_secure_boot_sig_block_t *trusted_block);
|
||||
|
||||
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);
|
@ -22,13 +22,15 @@
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_efuse.h"
|
||||
|
||||
#include "secure_boot_signature_priv.h"
|
||||
|
||||
// Secure boot V2 for app
|
||||
|
||||
_Static_assert(SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS == SECURE_BOOT_NUM_BLOCKS,
|
||||
"Parts of this code rely on the max number of signatures appended to an image"
|
||||
"being the same as the max number of trusted keys.");
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME || CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
static const char *TAG = "secure_boot_v2";
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
@ -76,7 +78,11 @@ esp_err_t esp_secure_boot_get_signature_blocks_for_running_app(bool digest_publi
|
||||
if (validate_signature_block(&block) == ESP_OK) {
|
||||
if (digest_public_keys) {
|
||||
bootloader_sha256_handle_t sig_block_sha = bootloader_sha256_start();
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &block.key, sizeof(block.key));
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &block.ecdsa.key, sizeof(block.ecdsa.key));
|
||||
#endif
|
||||
bootloader_sha256_finish(sig_block_sha, public_key_digests->key_digests[i]);
|
||||
}
|
||||
public_key_digests->num_digests++;
|
||||
@ -106,7 +112,7 @@ static esp_err_t get_secure_boot_key_digests(esp_image_sig_public_key_digests_t
|
||||
if (esp_secure_boot_read_key_digests(&efuse_trusted) == ESP_OK) {
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
if (efuse_trusted.key_digests[i] != NULL) {
|
||||
memcpy(public_key_digests->key_digests[i], (uint8_t *)efuse_trusted.key_digests[i], ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
memcpy(public_key_digests->key_digests[i], (uint8_t *)efuse_trusted.key_digests[i], ESP_SECURE_BOOT_KEY_DIGEST_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
}
|
||||
@ -120,8 +126,8 @@ 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)
|
||||
{
|
||||
uint8_t digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};
|
||||
uint8_t digest[ESP_SECURE_BOOT_KEY_DIGEST_LEN] = {0};
|
||||
uint8_t verified_digest[ESP_SECURE_BOOT_KEY_DIGEST_LEN] = {0};
|
||||
|
||||
/* Rounding off length to the upper 4k boundary */
|
||||
uint32_t padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
|
||||
@ -139,7 +145,7 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = esp_secure_boot_verify_rsa_signature_block(sig_block, digest, verified_digest);
|
||||
err = esp_secure_boot_verify_sbv2_signature_block(sig_block, digest, verified_digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
}
|
||||
@ -150,13 +156,13 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
// This verify function is called only from app, during ota update.
|
||||
// This function is compiled in case when CONFIG_SECURE_BOOT_V2_ENABLED==y or CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT==y.
|
||||
// if CONFIG_SECURE_BOOT_V2_ENABLED==y and key digests from eFuse are missing, then FAIL (eFuse blocks should be set).
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
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)
|
||||
{
|
||||
bool any_trusted_key = false;
|
||||
|
||||
/* Note: in IDF verification we don't add any fault injection resistance, as we don't expect this to be called
|
||||
during boot-time verification. */
|
||||
memset(verified_digest, 0, ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
memset(verified_digest, 0, ESP_SECURE_BOOT_KEY_DIGEST_LEN);
|
||||
|
||||
esp_image_sig_public_key_digests_t trusted = {0};
|
||||
|
||||
@ -165,26 +171,7 @@ esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signa
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
int ret = 0;
|
||||
mbedtls_rsa_context pk;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
const unsigned rsa_key_size = sizeof(sig_block->block[0].signature);
|
||||
unsigned char *sig_be = calloc(1, rsa_key_size);
|
||||
unsigned char *buf = calloc(1, rsa_key_size);
|
||||
if (sig_be == NULL || buf == NULL) {
|
||||
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\n", ret);
|
||||
goto exit_outer;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
const unsigned secure_boot_num_blocks = 1;
|
||||
#else
|
||||
@ -202,12 +189,17 @@ esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signa
|
||||
|
||||
/* Generate the SHA of the public key components in the signature block */
|
||||
bootloader_sha256_handle_t sig_block_sha = bootloader_sha256_start();
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &app_blk->key, sizeof(app_blk->key));
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &app_blk->ecdsa.key, sizeof(app_blk->ecdsa.key));
|
||||
#endif
|
||||
|
||||
bootloader_sha256_finish(sig_block_sha, app_blk_digest);
|
||||
|
||||
/* Check if the key is one we trust */
|
||||
for (unsigned trusted_key_idx = 0; trusted_key_idx < secure_boot_num_blocks; trusted_key_idx++) {
|
||||
if (memcmp(app_blk_digest, trusted.key_digests[trusted_key_idx], ESP_SECURE_BOOT_DIGEST_LEN) == 0) {
|
||||
if (memcmp(app_blk_digest, trusted.key_digests[trusted_key_idx], ESP_SECURE_BOOT_KEY_DIGEST_LEN) == 0) {
|
||||
ESP_LOGI(TAG, "#%d app key digest == #%d trusted key digest", app_blk_idx, trusted_key_idx);
|
||||
trusted_block = app_blk;
|
||||
any_trusted_key = true;
|
||||
@ -220,63 +212,26 @@ esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signa
|
||||
continue; // Skip the signature blocks with no trusted digest
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS...");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_complete(&pk);
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed mbedtls_rsa_complete, err: %d", ret);
|
||||
goto exit_inner;
|
||||
}
|
||||
|
||||
ret = mbedtls_rsa_check_pubkey(&pk);
|
||||
if (ret != 0) {
|
||||
ESP_LOGI(TAG, "Key is not an RSA key -%0x", -ret);
|
||||
goto exit_inner;
|
||||
}
|
||||
|
||||
/* Signature needs to be byte swapped into BE representation */
|
||||
for (int j = 0; j < rsa_key_size; j++) {
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Signature verified successfully!");
|
||||
}
|
||||
exit_inner:
|
||||
mbedtls_rsa_free(&pk);
|
||||
ret = verify_rsa_signature_block(sig_block, image_digest, trusted_block);
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
ESP_LOGI(TAG, "Verifying with ECDSA...");
|
||||
ret = verify_ecdsa_signature_block(sig_block, image_digest, trusted_block);
|
||||
#endif
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit_outer:
|
||||
free(sig_be);
|
||||
free(buf);
|
||||
return (ret != 0 || any_trusted_key == false) ? ESP_ERR_IMAGE_INVALID: ESP_OK;
|
||||
}
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
// To maintain backward compatibility
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
return esp_secure_boot_verify_sbv2_signature_block(sig_block, image_digest, verified_digest);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME || CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
// Secure boot V2 for bootloader.
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME && CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
#if CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
|
||||
static const char* TAG = "secure_boot_v2";
|
||||
|
||||
@ -45,7 +45,7 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = esp_secure_boot_verify_rsa_signature_block(sig_block, digest, verified_digest);
|
||||
err = esp_secure_boot_verify_sbv2_signature_block(sig_block, digest, verified_digest);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
}
|
||||
@ -83,7 +83,7 @@ static esp_err_t get_secure_boot_key_digests(esp_image_sig_public_key_digests_t
|
||||
if (err == ESP_OK) {
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
if (trusted_keys.key_digests[i] != NULL) {
|
||||
memcpy(public_key_digests->key_digests[i], (uint8_t *)trusted_keys.key_digests[i], ESP_SECURE_BOOT_DIGEST_LEN);
|
||||
memcpy(public_key_digests->key_digests[i], (uint8_t *)trusted_keys.key_digests[i], ESP_SECURE_BOOT_KEY_DIGEST_LEN);
|
||||
public_key_digests->num_digests++;
|
||||
}
|
||||
}
|
||||
@ -101,7 +101,7 @@ static esp_err_t get_secure_boot_key_digests(esp_image_sig_public_key_digests_t
|
||||
|
||||
// if CONFIG_SECURE_BOOT_V2_ENABLED==y and key digests from eFuse are missing, then it is the first boot,
|
||||
// trusted.key_digests are filled from app sig_block.
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
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)
|
||||
{
|
||||
esp_image_sig_public_key_digests_t trusted = {0};
|
||||
bool efuse_keys_are_not_set = false;
|
||||
@ -125,7 +125,11 @@ esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signa
|
||||
// if efuse key digests are not in eFuse yet due to it is the first boot
|
||||
// then use digests from app to skip error in ets_secure_boot_verify_signature().
|
||||
bootloader_sha256_handle_t sig_block_sha = bootloader_sha256_start();
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &sig_block->block[i].key, sizeof(sig_block->block[i].key));
|
||||
#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
|
||||
bootloader_sha256_data(sig_block_sha, &sig_block->block[i].ecdsa.key, sizeof(sig_block->block[i].ecdsa.key));
|
||||
#endif
|
||||
bootloader_sha256_finish(sig_block_sha, trusted.key_digests[i]);
|
||||
}
|
||||
}
|
||||
@ -133,19 +137,27 @@ esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signa
|
||||
ESP_FAULT_ASSERT(!esp_secure_boot_enabled());
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
ESP_LOGI(TAG, "Verifying with RSA-PSS...");
|
||||
#if SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS == 1
|
||||
#else
|
||||
ESP_LOGI(TAG, "Verifying with ECDSA...");
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
int sb_result = ets_secure_boot_verify_signature(sig_block, image_digest, trusted.key_digests[0], verified_digest);
|
||||
#else
|
||||
ets_secure_boot_key_digests_t trusted_key_digests = {0};
|
||||
for (unsigned i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
|
||||
trusted_key_digests.key_digests[i] = &trusted.key_digests[i];
|
||||
}
|
||||
|
||||
// Key revocation happens in ROM bootloader.
|
||||
// Do NOT allow key revocation while verifying application
|
||||
trusted_key_digests.allow_key_revoke = false;
|
||||
|
||||
int sb_result = ets_secure_boot_verify_signature(sig_block, image_digest, &trusted_key_digests, verified_digest);
|
||||
#endif
|
||||
#endif // CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
if (sb_result != SB_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
@ -154,4 +166,13 @@ esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signa
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME && CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
|
||||
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
|
||||
// To maintain backward compatibility
|
||||
esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
|
||||
{
|
||||
return esp_secure_boot_verify_sbv2_signature_block(sig_block, image_digest, verified_digest);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
|
@ -24,6 +24,7 @@ typedef enum {
|
||||
|
||||
EFUSE_BLK3 = 3, /**< Number of eFuse BLOCK3. KEY0. whole block */
|
||||
EFUSE_BLK_KEY0 = 3, /**< Number of eFuse BLOCK3. KEY0. whole block */
|
||||
EFUSE_BLK_SECURE_BOOT = 3,
|
||||
EFUSE_BLK_KEY_MAX = 4,
|
||||
|
||||
EFUSE_BLK_MAX = 4, /**< Number of eFuse blocks */
|
||||
|
24
components/esp_rom/include/esp32c2/rom/ecdsa.h
Normal file
24
components/esp_rom/include/esp32c2/rom/ecdsa.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
ECDSA_CURVE_P192 = 1,
|
||||
ECDSA_CURVE_P256 = 2
|
||||
} 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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -10,6 +10,7 @@
|
||||
#include <stdbool.h>
|
||||
#include "ets_sys.h"
|
||||
#include "rsa_pss.h"
|
||||
#include "ecdsa.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -77,19 +78,25 @@ void ets_secure_boot_revoke_public_key_digest(int index);
|
||||
#define SIG_BLOCK_PADDING 4096
|
||||
#define ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC 0xE7
|
||||
|
||||
/* Secure Boot V2 signature block
|
||||
/* Secure Boot V2 signature block (extended to support ECDSA)
|
||||
|
||||
(Up to 3 in a signature sector are appended to the image)
|
||||
*/
|
||||
struct ets_secure_boot_sig_block {
|
||||
struct __attribute((packed)) ets_secure_boot_sig_block {
|
||||
uint8_t magic_byte;
|
||||
uint8_t version;
|
||||
uint8_t _reserved1;
|
||||
uint8_t _reserved2;
|
||||
uint8_t image_digest[32];
|
||||
ets_rsa_pubkey_t key;
|
||||
uint8_t signature[384];
|
||||
uint32_t block_crc;
|
||||
struct {
|
||||
struct {
|
||||
uint8_t curve_id; /* ETS_ECDSA_CURVE_P192 / ETS_ECDSA_CURVE_P256 */
|
||||
uint8_t point[64]; /* X followed by Y (both little-endian), plus zero bytes if P192 */
|
||||
} key;
|
||||
uint8_t signature[64]; /* r followed by s (both little-endian) */
|
||||
uint8_t padding[1031];
|
||||
} ecdsa;
|
||||
uint32_t block_crc; /* note: crc covers all bytes in the structure before it, regardless of version field */
|
||||
uint8_t _padding[16];
|
||||
};
|
||||
|
||||
|
@ -40,7 +40,7 @@ if(NOT CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION AND
|
||||
NOT BOOTLOADER_BUILD)
|
||||
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
|
||||
list(APPEND esptool_elf2image_args --secure-pad)
|
||||
elseif(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
elseif(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME OR CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME)
|
||||
list(APPEND esptool_elf2image_args --secure-pad-v2)
|
||||
endif()
|
||||
endif()
|
||||
@ -110,7 +110,7 @@ endif()
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
|
||||
set(secure_boot_version "1")
|
||||
elseif(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
elseif(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME OR CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME)
|
||||
set(secure_boot_version "2")
|
||||
endif()
|
||||
|
||||
|
@ -95,7 +95,7 @@ if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
|
||||
"\t${espsecurepy} sign_data --keyfile KEYFILE ${build_dir}/partition_table/${final_partition_bin}"
|
||||
VERBATIM)
|
||||
endif()
|
||||
elseif(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
|
||||
elseif(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME OR CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME)
|
||||
add_custom_command(TARGET partition-table POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Partition table built:"
|
||||
VERBATIM)
|
||||
|
@ -3,15 +3,19 @@
|
||||
Secure Boot V2
|
||||
==============
|
||||
|
||||
{IDF_TARGET_SBV2_SCHEME:default="RSA-PSS", esp32c2="ECDSA"}
|
||||
|
||||
{IDF_TARGET_SBV2_KEY:default="RSA-3072", esp32c2="ECDSA-256 or ECDSA-192"}
|
||||
|
||||
.. important::
|
||||
|
||||
This document is about Secure Boot V2, supported on the following chips: ESP32 (ECO3 onwards), ESP32-S2, ESP32-S3 and ESP32-C3 (ECO3 onwards). Except for ESP32, it is the only supported Secure Boot scheme.
|
||||
This document is about Secure Boot V2, supported on the following chips: ESP32 (ECO3 onwards), ESP32-S2, ESP32-S3, ESP32-C3 (ECO3 onwards), and ESP32-C2. Except for ESP32, it is the only supported Secure Boot scheme.
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
For ESP32 before ECO3, refer to :doc:`Secure Boot <secure-boot-v1>`. It is recommended that users use Secure Boot V2 if they have a chip version that supports it. Secure Boot V2 is safer and more flexible than Secure Boot V1.
|
||||
|
||||
Secure Boot V2 uses RSA based app and bootloader verification. This document can also be used as a reference for signing apps using the RSA scheme without signing the bootloader.
|
||||
Secure Boot V2 uses {IDF_TARGET_SBV2_SCHEME} based app and bootloader verification. This document can also be used as a reference for signing apps using the {IDF_TARGET_SBV2_SCHEME} scheme without signing the bootloader.
|
||||
|
||||
|
||||
.. only:: esp32
|
||||
@ -27,18 +31,26 @@ Background
|
||||
|
||||
Secure Boot protects a device from running any unauthorized (i.e., unsigned) code by checking that each piece of software that is being booted is signed. On an {IDF_TARGET_NAME}, these pieces of software include the second stage bootloader and each application binary. Note that the first stage bootloader does not require signing as it is ROM code thus cannot be changed.
|
||||
|
||||
A new RSA based Secure Boot verification scheme (Secure Boot V2) has been introduced on the ESP32 (ECO3 onwards), ESP32-S2, ESP32-S3 and ESP32-C3 (ECO3 onwards).
|
||||
.. only:: not esp32c2
|
||||
|
||||
A new RSA based Secure Boot verification scheme (Secure Boot V2) has been introduced on the ESP32 (ECO3 onwards), ESP32-S2, ESP32-S3 and ESP32-C3 (ECO3 onwards).
|
||||
|
||||
.. only:: esp32c2
|
||||
|
||||
A new ECC based Secure Boot verification scheme (Secure Boot V2) has been introduced on the ESP32-C2.
|
||||
|
||||
The Secure Boot process on the {IDF_TARGET_NAME} involves the following steps:
|
||||
1. When the first stage bootloader loads the second stage bootloader, the second stage bootloader's RSA-PSS signature is verified. If the verification is successful, the second stage bootloader is executed.
|
||||
2. When the second stage bootloader loads a particular application image, the application's RSA-PSS signature is verified. If the verification is successful, the application image is executed.
|
||||
|
||||
1. When the first stage bootloader loads the second stage bootloader, the second stage bootloader's {IDF_TARGET_SBV2_SCHEME} signature is verified. If the verification is successful, the second stage bootloader is executed.
|
||||
|
||||
2. When the second stage bootloader loads a particular application image, the application's {IDF_TARGET_SBV2_SCHEME} signature is verified. If the verification is successful, the application image is executed.
|
||||
|
||||
Advantages
|
||||
----------
|
||||
|
||||
- The RSA public key is stored on the device. The corresponding RSA private key is kept at a secret place and is never accessed by the device.
|
||||
- The {IDF_TARGET_SBV2_SCHEME} public key is stored on the device. The corresponding {IDF_TARGET_SBV2_SCHEME} private key is kept at a secret place and is never accessed by the device.
|
||||
|
||||
.. only:: esp32
|
||||
.. only:: esp32 or esp32c2
|
||||
|
||||
- Only one public key can be generated and stored in the chip during manufacturing.
|
||||
|
||||
@ -66,11 +78,15 @@ Secure Boot V2 verifies the bootloader image and application binary images using
|
||||
|
||||
Only one signature block can be appended to the bootloader or application image in ESP32 ECO3.
|
||||
|
||||
.. only:: esp32c2
|
||||
|
||||
Only one signature block can be appended to the bootloader or application image in {IDF_TARGET_NAME}
|
||||
|
||||
.. only:: esp32s2 or esp32c3 or esp32s3
|
||||
|
||||
Up to 3 signature blocks can be appended to the bootloader or application image in {IDF_TARGET_NAME}.
|
||||
|
||||
Each signature block contains a signature of the preceding image as well as the corresponding RSA-3072 public key. For more details about the format, refer to :ref:`signature-block-format`. A digest of the RSA-3072 public key is stored in the eFuse.
|
||||
Each signature block contains a signature of the preceding image as well as the corresponding {IDF_TARGET_SBV2_KEY} public key. For more details about the format, refer to :ref:`signature-block-format`. A digest of the {IDF_TARGET_SBV2_KEY} public key is stored in the eFuse.
|
||||
|
||||
The application image is not only verified on every boot but also on each over the air (OTA) update. If the currently selected OTA app image cannot be verified, the bootloader will fall back and look for another correctly signed application image.
|
||||
|
||||
@ -99,50 +115,92 @@ The bootloader and application images are padded to the next 4096 byte boundary,
|
||||
|
||||
The content of each signature block is shown in the following table:
|
||||
|
||||
.. list-table:: Content of a Signature Block
|
||||
:widths: 10 10 40
|
||||
:header-rows: 1
|
||||
.. only:: not esp32c2
|
||||
|
||||
* - **Offset**
|
||||
- **Size (bytes)**
|
||||
- **Description**
|
||||
* - 0
|
||||
- 1
|
||||
- Magic byte
|
||||
* - 1
|
||||
- 1
|
||||
- Version number byte (currently 0x02), 0x01 is for Secure Boot V1.
|
||||
* - 2
|
||||
- 2
|
||||
- Padding bytes, Reserved. Should be zero.
|
||||
* - 4
|
||||
- 32
|
||||
- SHA-256 hash of only the image content, not including the signature block.
|
||||
* - 36
|
||||
- 384
|
||||
- RSA Public Modulus used for signature verification. (value ‘n’ in RFC8017).
|
||||
* - 420
|
||||
- 4
|
||||
- RSA Public Exponent used for signature verification (value ‘e’ in RFC8017).
|
||||
* - 424
|
||||
- 384
|
||||
- Pre-calculated R, derived from ‘n’.
|
||||
* - 808
|
||||
- 4
|
||||
- Pre-calculated M’, derived from ‘n’
|
||||
* - 812
|
||||
- 384
|
||||
- RSA-PSS Signature result (section 8.1.1 of RFC8017) of image content, computed using following PSS parameters: SHA256 hash, MFG1 function, salt length 32 bytes, default trailer field (0xBC).
|
||||
* - 1196
|
||||
- 4
|
||||
- CRC32 of the preceding 1095 bytes.
|
||||
* - 1200
|
||||
- 16
|
||||
- Zero padding to length 1216 bytes.
|
||||
.. list-table:: Content of a Signature Block
|
||||
:widths: 10 10 40
|
||||
:header-rows: 1
|
||||
|
||||
* - **Offset**
|
||||
- **Size (bytes)**
|
||||
- **Description**
|
||||
* - 0
|
||||
- 1
|
||||
- Magic byte
|
||||
* - 1
|
||||
- 1
|
||||
- Version number byte (currently 0x02), 0x01 is for Secure Boot V1.
|
||||
* - 2
|
||||
- 2
|
||||
- Padding bytes, Reserved. Should be zero.
|
||||
* - 4
|
||||
- 32
|
||||
- SHA-256 hash of only the image content, not including the signature block.
|
||||
* - 36
|
||||
- 384
|
||||
- RSA Public Modulus used for signature verification. (value ‘n’ in RFC8017).
|
||||
* - 420
|
||||
- 4
|
||||
- RSA Public Exponent used for signature verification (value ‘e’ in RFC8017).
|
||||
* - 424
|
||||
- 384
|
||||
- Pre-calculated R, derived from ‘n’.
|
||||
* - 808
|
||||
- 4
|
||||
- Pre-calculated M’, derived from ‘n’
|
||||
* - 812
|
||||
- 384
|
||||
- RSA-PSS Signature result (section 8.1.1 of RFC8017) of image content, computed using following PSS parameters: SHA256 hash, MFG1 function, salt length 32 bytes, default trailer field (0xBC).
|
||||
* - 1196
|
||||
- 4
|
||||
- CRC32 of the preceding 1095 bytes.
|
||||
* - 1200
|
||||
- 16
|
||||
- Zero padding to length 1216 bytes.
|
||||
|
||||
|
||||
.. note::
|
||||
R and M' are used for hardware-assisted Montgomery Multiplication.
|
||||
.. note::
|
||||
R and M' are used for hardware-assisted Montgomery Multiplication.
|
||||
|
||||
.. only:: esp32c2
|
||||
|
||||
.. list-table:: Content of a Signature Block
|
||||
:widths: 10 10 40
|
||||
:header-rows: 1
|
||||
|
||||
* - **Offset**
|
||||
- **Size (bytes)**
|
||||
- **Description**
|
||||
* - 0
|
||||
- 1
|
||||
- Magic byte.
|
||||
* - 1
|
||||
- 1
|
||||
- Version number byte (currently 0x03).
|
||||
* - 2
|
||||
- 2
|
||||
- Padding bytes, Reserved. Should be zero.
|
||||
* - 4
|
||||
- 32
|
||||
- SHA-256 hash of only the image content, not including the signature block.
|
||||
* - 36
|
||||
- 1
|
||||
- Curve ID (1 for NIST192p curve. 2 for NIST256p curve).
|
||||
* - 37
|
||||
- 64
|
||||
- ECDSA Public key: 32 byte X coordinate followed by 32 byte Y coordinate.
|
||||
* - 101
|
||||
- 64
|
||||
- ECDSA Signature result (section 5.3.2 of RFC6090) of the image content: 32 byte R component followed by 32 byte S component.
|
||||
* - 165
|
||||
- 1031
|
||||
- Reserved.
|
||||
* - 1196
|
||||
- 4
|
||||
- CRC32 of the preceding 1095 bytes.
|
||||
* - 1200
|
||||
- 16
|
||||
- Zero padding to length 1216 bytes.
|
||||
|
||||
The remainder of the signature sector is erased flash (0xFF) which allows writing other signature blocks after previous signature block.
|
||||
|
||||
@ -164,7 +222,15 @@ An image is “verified” if the public key stored in any signature block is va
|
||||
|
||||
2. Generate the application image digest and match it with the image digest in the signature block. If the digests don't match, the verification fails.
|
||||
|
||||
3. Use the public key to verify the signature of the bootloader image, using RSA-PSS (section 8.1.2 of RFC8017) with the image digest calculated in step (2) for comparison.
|
||||
.. only:: not esp32c2
|
||||
|
||||
3. Use the public key to verify the signature of the bootloader image, using RSA-PSS (section 8.1.2 of RFC8017) with the image digest calculated in step (2) for comparison.
|
||||
|
||||
.. only:: esp32c2
|
||||
|
||||
3. Use the public key to verify the signature of the bootloader image, using ECDSA signature verification (section 5.3.3 of RFC6090) with the image digest calculated in step (2) for comparison.
|
||||
|
||||
|
||||
|
||||
Bootloader Size
|
||||
---------------
|
||||
@ -261,15 +327,39 @@ Restrictions after Secure Boot is enabled
|
||||
Generating Secure Boot Signing Key
|
||||
----------------------------------
|
||||
|
||||
The build system will prompt you with a command to generate a new signing key via ``espsecure.py generate_signing_key``. The --version 2 parameter will generate the RSA 3072 private key for Secure Boot V2.
|
||||
The build system will prompt you with a command to generate a new signing key via ``espsecure.py generate_signing_key``.
|
||||
|
||||
The strength of the signing key is proportional to (a) the random number source of the system, and (b) the correctness of the algorithm used. For production devices, we recommend generating signing keys from a system with a quality entropy source, and using the best available RSA key generation utilities.
|
||||
.. only:: not esp32c2
|
||||
|
||||
The ``--version 2`` parameter will generate the RSA 3072 private key for Secure Boot V2.
|
||||
|
||||
.. only:: esp32c2
|
||||
|
||||
Select the ECDSA scheme by passing ``--version 2 --scheme ecdsa256`` or ``--version 2 --scheme ecdsa192`` to generate corresponding ECDSA private key
|
||||
|
||||
The strength of the signing key is proportional to (a) the random number source of the system, and (b) the correctness of the algorithm used. For production devices, we recommend generating signing keys from a system with a quality entropy source, and using the best available {IDF_TARGET_SBV2_SCHEME} key generation utilities.
|
||||
|
||||
For example, to generate a signing key using the openssl command line:
|
||||
|
||||
```
|
||||
openssl genrsa -out my_secure_boot_signing_key.pem 3072
|
||||
```
|
||||
.. only:: not esp32c2
|
||||
|
||||
```
|
||||
openssl genrsa -out my_secure_boot_signing_key.pem 3072
|
||||
```
|
||||
|
||||
.. only:: esp32c2
|
||||
|
||||
For NIST192p curve
|
||||
|
||||
```
|
||||
openssl ecparam -name prime192v1 -genkey -noout -out my_secure_boot_signing_key.pem
|
||||
```
|
||||
|
||||
For NIST256p curve
|
||||
|
||||
```
|
||||
openssl ecparam -name prime256v1 -genkey -noout -out my_secure_boot_signing_key.pem
|
||||
```
|
||||
|
||||
Remember that the strength of the Secure Boot system depends on keeping the signing key private.
|
||||
|
||||
@ -374,7 +464,7 @@ To sign a binary image::
|
||||
|
||||
espsecure.py sign_data --version 2 --keyfile ./my_signing_key.pem --output ./image_signed.bin image-unsigned.bin
|
||||
|
||||
Keyfile is the PEM file containing an RSA-3072 private signing key.
|
||||
Keyfile is the PEM file containing an {IDF_TARGET_SBV2_KEY} private signing key.
|
||||
|
||||
.. _secure-boot-v2-and-flash-encr:
|
||||
|
||||
@ -415,10 +505,15 @@ How To Enable Signed App Verification
|
||||
|
||||
2. Ensure `App Signing Scheme` is `RSA`. For ESP32 ECO3 chip, select :ref:`CONFIG_ESP32_REV_MIN` to `Rev 3` to get `RSA` option available
|
||||
|
||||
.. only:: not esp32
|
||||
.. only:: not esp32 and not esp32c2
|
||||
|
||||
2. Ensure `App Signing Scheme` is `RSA`
|
||||
|
||||
.. only:: esp32c2
|
||||
|
||||
2. Ensure `App Signing Scheme` is `ECDSA (V2)`
|
||||
|
||||
|
||||
3. Enable :ref:`CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT`
|
||||
|
||||
4. By default, "Sign binaries during build" will be enabled on selecting "Require signed app images" option, which will sign binary files as a part of build process. The file named in "Secure boot private signing key" will be used to sign the image.
|
||||
|
Loading…
x
Reference in New Issue
Block a user