Merge branch 'feature/enable_secure_boot_esp32p4' into 'master'

feat(secure_boot): add secure boot support for esp32p4

Closes IDF-7544 and IDF-7745

See merge request espressif/esp-idf!26335
This commit is contained in:
Mahavir Jain
2023-10-16 11:07:14 +08:00
11 changed files with 72 additions and 24 deletions

View File

@@ -45,6 +45,8 @@
#include "esp32c6/rom/secure_boot.h" #include "esp32c6/rom/secure_boot.h"
#elif CONFIG_IDF_TARGET_ESP32H2 #elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/secure_boot.h" #include "esp32h2/rom/secure_boot.h"
#elif CONFIG_IDF_TARGET_ESP32P4
#include "esp32p4/rom/secure_boot.h"
#endif #endif
#define SUB_TYPE_ID(i) (i & 0x0F) #define SUB_TYPE_ID(i) (i & 0x0F)

View File

@@ -19,6 +19,8 @@
#include "esp32c6/rom/secure_boot.h" #include "esp32c6/rom/secure_boot.h"
#elif CONFIG_IDF_TARGET_ESP32H2 #elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/secure_boot.h" #include "esp32h2/rom/secure_boot.h"
#elif CONFIG_IDF_TARGET_ESP32P4
#include "esp32p4/rom/secure_boot.h"
#endif #endif
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_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);

View File

@@ -115,6 +115,10 @@ config SOC_FLASH_ENC_SUPPORTED
bool bool
default y default y
config SOC_SECURE_BOOT_SUPPORTED
bool
default y
config SOC_LP_GPIO_MATRIX_SUPPORTED config SOC_LP_GPIO_MATRIX_SUPPORTED
bool bool
default y default y

View File

@@ -66,7 +66,7 @@
#define SOC_ECDSA_SUPPORTED 1 #define SOC_ECDSA_SUPPORTED 1
// #define SOC_KEY_MANAGER_SUPPORTED 1 //TODO: IDF-7925 // #define SOC_KEY_MANAGER_SUPPORTED 1 //TODO: IDF-7925
#define SOC_FLASH_ENC_SUPPORTED 1 #define SOC_FLASH_ENC_SUPPORTED 1
// #define SOC_SECURE_BOOT_SUPPORTED 1 //TODO: IDF-7544 #define SOC_SECURE_BOOT_SUPPORTED 1
// #define SOC_BOD_SUPPORTED 1 //TODO: IDF-7519 // #define SOC_BOD_SUPPORTED 1 //TODO: IDF-7519
// #define SOC_APM_SUPPORTED 1 //TODO: IDF-7542 // #define SOC_APM_SUPPORTED 1 //TODO: IDF-7542
// #define SOC_PMU_SUPPORTED 1 //TODO: IDF-7531 // #define SOC_PMU_SUPPORTED 1 //TODO: IDF-7531

View File

@@ -199,8 +199,6 @@ api-reference/protocols/asio.rst
security/host-based-security-workflows.rst security/host-based-security-workflows.rst
security/flash-encryption.rst security/flash-encryption.rst
security/security.rst security/security.rst
security/secure-boot-v2.rst
security/secure-boot-v1.rst
security/esp32p4_log.inc security/esp32p4_log.inc
security/index.rst security/index.rst
about.rst about.rst

View File

@@ -3,11 +3,11 @@
Secure Boot V2 Secure Boot V2
============== ==============
{IDF_TARGET_SBV2_SCHEME:default="RSA-PSS", esp32c2="ECDSA", esp32c6 or esp32h2="RSA-PSS or ECDSA"} {IDF_TARGET_SBV2_SCHEME:default="RSA-PSS", esp32c2="ECDSA", esp32c6 or esp32h2 or esp32p4="RSA-PSS or ECDSA"}
{IDF_TARGET_SBV2_KEY:default="RSA-3072", esp32c2="ECDSA-256 or ECDSA-192", esp32c6 or esp32h2="RSA-3072, ECDSA-256, or ECDSA-192"} {IDF_TARGET_SBV2_KEY:default="RSA-3072", esp32c2="ECDSA-256 or ECDSA-192", esp32c6 or esp32h2 or esp32p4="RSA-3072, ECDSA-256, or ECDSA-192"}
{IDF_TARGET_SECURE_BOOT_OPTION_TEXT:default="", esp32c6 or esp32h2="RSA is recommended because of faster verification time. You can choose between RSA and ECDSA scheme from the menu."} {IDF_TARGET_SECURE_BOOT_OPTION_TEXT:default="", esp32c6 or esp32h2 or esp32p4="RSA is recommended because of faster verification time. You can choose between RSA and ECDSA scheme from the menu."}
{IDF_TARGET_ECO_VERSION:default="", esp32="(ECO 3 onwards)", esp32c3="(ECO 3 onwards)"} {IDF_TARGET_ECO_VERSION:default="", esp32="(ECO 3 onwards)", esp32c3="(ECO 3 onwards)"}
@@ -138,21 +138,23 @@ The signature block starts on a 4 KB aligned boundary and has a flash sector of
RSA is recommended for use cases where fast bootup time is required whereas ECDSA is recommended for use cases where shorter key length is required. RSA is recommended for use cases where fast bootup time is required whereas ECDSA is recommended for use cases where shorter key length is required.
.. list-table:: Comparison between signature verification time .. only:: not esp32p4
:widths: 10 10 20
:header-rows: 1
* - **Verification scheme** .. list-table:: Comparison between signature verification time
- **Time** :widths: 10 10 20
- **CPU Frequency** :header-rows: 1
* - RSA-3072
- {IDF_TARGET_RSA_TIME}
- {IDF_TARGET_CPU_FREQ}
* - ECDSA-P256
- {IDF_TARGET_ECDSA_TIME}
- {IDF_TARGET_CPU_FREQ}
The above table compares the time taken to verify a signature in a particular scheme. It does not indicate the bootup time. * - **Verification scheme**
- **Time**
- **CPU Frequency**
* - RSA-3072
- {IDF_TARGET_RSA_TIME}
- {IDF_TARGET_CPU_FREQ}
* - ECDSA-P256
- {IDF_TARGET_ECDSA_TIME}
- {IDF_TARGET_CPU_FREQ}
The above table compares the time taken to verify a signature in a particular scheme. It does not indicate the bootup time.
The content of each signature block is shown in the following table: The content of each signature block is shown in the following table:

View File

@@ -554,6 +554,7 @@ def test_examples_efuse_with_virt_secure_boot_v2_pre_loaded(dut: Dut) -> None:
@pytest.mark.esp32c2 @pytest.mark.esp32c2
@pytest.mark.esp32c6 @pytest.mark.esp32c6
@pytest.mark.esp32h2 @pytest.mark.esp32h2
@pytest.mark.esp32p4
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.generic @pytest.mark.generic
@@ -626,6 +627,7 @@ def test_examples_efuse_with_virt_secure_boot_v2_esp32xx(dut: Dut) -> None:
@pytest.mark.esp32c2 @pytest.mark.esp32c2
@pytest.mark.esp32c6 @pytest.mark.esp32c6
@pytest.mark.esp32h2 @pytest.mark.esp32h2
@pytest.mark.esp32p4
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.generic @pytest.mark.generic

View File

@@ -0,0 +1,16 @@
# SECURE_BOOT_V2 with EFUSE_VIRTUAL_KEEP_IN_FLASH
CONFIG_IDF_TARGET="esp32p4"
CONFIG_PARTITION_TABLE_OFFSET=0xC000
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="test/partitions_efuse_emul.csv"
CONFIG_SECURE_BOOT=y
CONFIG_SECURE_BOOT_V2_ENABLED=y
CONFIG_SECURE_BOOT_SIGNING_KEY="test/secure_boot_signing_key.pem"
CONFIG_SECURE_INSECURE_ALLOW_DL_MODE=y
# IMPORTANT: ONLY VIRTUAL eFuse MODE!
CONFIG_EFUSE_VIRTUAL=y
CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=y

View File

@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | | Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | | ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
# Secure Boot # Secure Boot
@@ -15,6 +15,7 @@ Any of the following ESP module:
* ESP32S2 (supports Secure Boot V2) * ESP32S2 (supports Secure Boot V2)
* ESP32C3-ECO3 (supports Secure Boot V2) * ESP32C3-ECO3 (supports Secure Boot V2)
* ESP32S3 (supports Secure Boot V2) * ESP32S3 (supports Secure Boot V2)
* ESP32P4 (supports Secure Boot V2)
It is recommended to use Secure Boot V2 from ESP32-ECO3 onwards. It is recommended to use Secure Boot V2 from ESP32-ECO3 onwards.
@@ -69,7 +70,7 @@ Purpose of the test case (`pytest_secure_boot.py`) is to test the secure boot im
### Hardware required ### Hardware required
* FPGA setup with ESP32C3/ESP32S3 image * FPGA setup with ESP32C3/ESP32S3/ESP32P4 image
* COM port for programming and export it as ESPPORT * COM port for programming and export it as ESPPORT
e.g `export ESPPORT=/dev/ttyUSB0` e.g `export ESPPORT=/dev/ttyUSB0`
@@ -82,7 +83,7 @@ Purpose of the test case (`pytest_secure_boot.py`) is to test the secure boot im
``` ```
export IDF_ENV_FPGA=1 export IDF_ENV_FPGA=1
idf.py set-target esp32c3 #(or esp32s3) idf.py set-target esp32c3 #(or esp32s3 / esp32p4)
idf.py menuconfig idf.py menuconfig
``` ```

View File

@@ -159,6 +159,20 @@ class Esp32s3FpgaDut(FpgaDut):
self.serial.burn_efuse_key_digest(digest, 'SECURE_BOOT_DIGEST%d' % key_index, 'BLOCK_KEY%d' % block) self.serial.burn_efuse_key_digest(digest, 'SECURE_BOOT_DIGEST%d' % key_index, 'BLOCK_KEY%d' % block)
class Esp32p4FpgaDut(FpgaDut):
SECURE_BOOT_EN_KEY = 'SECURE_BOOT_EN'
SECURE_BOOT_EN_VAL = 1
def burn_wafer_version(self) -> None:
pass
def secure_boot_burn_en_bit(self) -> None:
self.serial.burn_efuse(self.SECURE_BOOT_EN_KEY, self.SECURE_BOOT_EN_VAL)
def secure_boot_burn_digest(self, digest: str, key_index: int = 0, block: int = 0) -> None:
self.serial.burn_efuse_key_digest(digest, 'SECURE_BOOT_DIGEST%d' % key_index, 'BLOCK_KEY%d' % block)
@pytest.fixture(scope='module') @pytest.fixture(scope='module')
def monkeypatch_module(request: FixtureRequest) -> MonkeyPatch: def monkeypatch_module(request: FixtureRequest) -> MonkeyPatch:
mp = MonkeyPatch() mp = MonkeyPatch()
@@ -173,5 +187,7 @@ def replace_dut_class(monkeypatch_module: MonkeyPatch, pytestconfig: pytest.Conf
monkeypatch_module.setattr('pytest_embedded_idf.IdfDut', Esp32c3FpgaDut) monkeypatch_module.setattr('pytest_embedded_idf.IdfDut', Esp32c3FpgaDut)
elif target == 'esp32s3': elif target == 'esp32s3':
monkeypatch_module.setattr('pytest_embedded_idf.IdfDut', Esp32s3FpgaDut) monkeypatch_module.setattr('pytest_embedded_idf.IdfDut', Esp32s3FpgaDut)
elif target == 'esp32p4':
monkeypatch_module.setattr('pytest_embedded_idf.IdfDut', Esp32p4FpgaDut)
monkeypatch_module.setattr('pytest_embedded_idf.IdfSerial', FpgaSerial) monkeypatch_module.setattr('pytest_embedded_idf.IdfSerial', FpgaSerial)

View File

@@ -81,6 +81,7 @@ def dut_start_secure_app(dut: Dut) -> None:
# Correctly signed bootloader + correctly signed app should work # Correctly signed bootloader + correctly signed app should work
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.esp32p4
def test_examples_security_secure_boot(dut: Dut) -> None: def test_examples_security_secure_boot(dut: Dut) -> None:
dut_start_secure_app(dut) dut_start_secure_app(dut)
dut.expect('Secure Boot is enabled', timeout=10) dut.expect('Secure Boot is enabled', timeout=10)
@@ -92,6 +93,7 @@ def test_examples_security_secure_boot(dut: Dut) -> None:
# Any key index can be written to any key block and should work # Any key index can be written to any key block and should work
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.esp32p4
# Increasing the test timeout to 1200s as the test runs for 18 iterations # Increasing the test timeout to 1200s as the test runs for 18 iterations
# and thus the default 600s timeout is not sufficient # and thus the default 600s timeout is not sufficient
@pytest.mark.timeout(1200) @pytest.mark.timeout(1200)
@@ -113,6 +115,7 @@ def test_examples_security_secure_boot_key_combo(dut: Dut) -> None:
# If a key is revoked, bootloader signed with that key should fail verification # If a key is revoked, bootloader signed with that key should fail verification
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.esp32p4
def test_examples_security_secure_boot_key_revoke(dut: Dut) -> None: def test_examples_security_secure_boot_key_revoke(dut: Dut) -> None:
dut_start_secure_app(dut) dut_start_secure_app(dut)
dut.expect('Secure Boot is enabled', timeout=10) dut.expect('Secure Boot is enabled', timeout=10)
@@ -131,6 +134,7 @@ def test_examples_security_secure_boot_key_revoke(dut: Dut) -> None:
# Corrupt one byte at a time of bootloader signature and test that the verification fails # Corrupt one byte at a time of bootloader signature and test that the verification fails
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.esp32p4
@pytest.mark.timeout(18000) @pytest.mark.timeout(18000)
# Increasing the test timeout to 18000s as the test runs for 384 iterations # Increasing the test timeout to 18000s as the test runs for 384 iterations
# and thus the default 600s timeout is not sufficient # and thus the default 600s timeout is not sufficient
@@ -167,6 +171,7 @@ def test_examples_security_secure_boot_corrupt_bl_sig(dut: Dut) -> None:
# Corrupt app signature, one byte at a time, and test that the verification fails # Corrupt app signature, one byte at a time, and test that the verification fails
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.esp32p4
@pytest.mark.timeout(18000) @pytest.mark.timeout(18000)
# Increasing the test timeout to 18000s as the test runs for 385 iterations # Increasing the test timeout to 18000s as the test runs for 385 iterations
# and thus the default 600s timeout is not sufficient # and thus the default 600s timeout is not sufficient
@@ -208,6 +213,6 @@ def test_examples_security_secure_boot_corrupt_app_sig(dut: Dut) -> None:
dut.secure_boot_burn_en_bit() dut.secure_boot_burn_en_bit()
dut.secure_boot_burn_digest('test_rsa_3072_key.pem', 0, 0) dut.secure_boot_burn_digest('test_rsa_3072_key.pem', 0, 0)
dut.expect('Sig block 0 invalid: Stored CRC ends', timeout=2) dut.expect('Sig block 0 invalid: {}'.format('CRC mismatch' if dut.target == 'esp32p4' else 'Stored CRC ends'), timeout=2)
dut.expect('Secure boot signature verification failed', timeout=2) dut.expect('Secure boot signature verification failed', timeout=2)
dut.expect('No bootable app partitions in the partition table', timeout=2) dut.expect('No bootable app partitions in the partition table', timeout=2)