Merge branch 'docs/translate_secure_boot_v2' into 'master'

docs: Provide translation for secure-boot-v2.rst

Closes DOC-6190

See merge request espressif/esp-idf!30865
This commit is contained in:
Shen Meng Jing 2024-06-06 13:15:03 +08:00
commit d84b58ffb5
2 changed files with 924 additions and 148 deletions

View File

@ -1,73 +1,77 @@
:orphan:
Secure Boot V2
Secure Boot v2
==============
:link_to_translation:`zh_CN:[中文]`
{IDF_TARGET_SBV2_SCHEME:default="RSA-PSS", esp32c2="ECDSA", esp32c6="RSA-PSS or ECDSA", esp32h2="RSA-PSS or ECDSA", esp32p4="RSA-PSS or ECDSA", esp32c5="RSA-PSS or ECDSA"}
{IDF_TARGET_SBV2_KEY:default="RSA-3072", esp32c2="ECDSA-256 or ECDSA-192", esp32c6="RSA-3072, ECDSA-256, or ECDSA-192", esp32h2="RSA-3072, ECDSA-256, or ECDSA-192", esp32p4="RSA-3072, ECDSA-256, or ECDSA-192", esp32c5="RSA-3072, ECDSA-256, or ECDSA-192"}
{IDF_TARGET_SECURE_BOOT_OPTION_TEXT:default="", esp32c6="RSA is recommended because of faster verification time. You can choose between RSA and ECDSA scheme from the menu.", esp32h2="RSA is recommended because of faster verification time. You can choose between RSA and ECDSA scheme from the menu.", esp32p4="RSA is recommended because of faster verification time. You can choose between RSA and ECDSA scheme from the menu.", esp32c5="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="(v3.0 onwards)", esp32c3="(v3.0 onwards)"}
{IDF_TARGET_RSA_TIME:default="", esp32c6="~2.7 ms", esp32h2="~4.5 ms"}
{IDF_TARGET_RSA_TIME:default="", esp32c6="about 2.7 ms", esp32h2="about 4.5 ms"}
{IDF_TARGET_ECDSA_TIME:default="", esp32c6="~21.5 ms", esp32h2="~36 ms"}
{IDF_TARGET_ECDSA_TIME:default="", esp32c6="about 21.5 ms", esp32h2="about 36 ms"}
{IDF_TARGET_CPU_FREQ:default="", esp32c6="160 MHz", esp32h2="96 MHz"}
{IDF_TARGET_SBV2_DEFAULT_SCHEME:default="RSA", esp32c2="ECDSA (V2)"}
{IDF_TARGET_SBV2_DEFAULT_SCHEME:default="RSA", esp32c2="ECDSA (v2)"}
.. important::
This document is about Secure Boot V2, supported on {IDF_TARGET_NAME} {IDF_TARGET_ECO_VERSION}
This document is about Secure Boot v2, supported on {IDF_TARGET_NAME} {IDF_TARGET_ECO_VERSION}.
.. only:: esp32
For ESP32 before ECO3, refer to :doc:`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.
For ESP32 before chip revision v3.0, refer to :doc:`secure-boot-v1`. It is recommended to use Secure Boot v2 if you have a chip revision that supports it. Secure Boot v2 is safer and more flexible than Secure Boot V1.
Secure Boot V2 uses {IDF_TARGET_SBV2_SCHEME} based app and bootloader (:ref:`second-stage-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.
Secure Boot v2 uses {IDF_TARGET_SBV2_SCHEME} based app and bootloader :ref:`second-stage-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
``Secure Boot V2`` and RSA scheme (``App Signing Scheme``) options are available for ESP32 from ECO3 onwards. To use these options in menuconfig, set :ref:`CONFIG_ESP32_REV_MIN` greater than or equal to `Rev 3`.
``Secure Boot v2`` and ``RSA App Signing Scheme`` options are available for ESP32 from chip revision v3.0 onwards. To use these options in menuconfig, set :ref:`CONFIG_ESP32_REV_MIN` greater than or equal to `v3.0`.
.. only:: esp32c3
``Secure Boot V2`` is available for ESP32-C3 from ECO3 onwards. To use these options in menuconfig, set :ref:`CONFIG_ESP32C3_REV_MIN` greater than or equal to `Rev 3`.
``Secure Boot v2`` is available for ESP32-C3 from chip revision v3.0 onwards. To use these options in menuconfig, set :ref:`CONFIG_ESP32C3_REV_MIN` greater than or equal to `v3.0`.
.. note::
In this guide, most used commands are in the form of ``idf.py secure-<command>``, which is a wrapper around corresponding ``espsecure.py <command>``. The idf.py-based commands provides more user-friendly experience, although may lack some of the advanced functionality of their espsecure.py-based counterparts.
In this guide, most used commands are in the form of ``idf.py secure-<command>``, which is a wrapper around corresponding ``espsecure.py <command>``. The ``idf.py`` based commands provides more user-friendly experience, although may lack some of the advanced functionality of their ``espsecure.py`` based counterparts.
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.
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 and thus cannot be changed.
.. only:: esp32 or (SOC_SECURE_BOOT_V2_RSA and not SOC_SECURE_BOOT_V2_ECC)
A RSA based Secure Boot verification scheme (Secure Boot V2) is implemented on {IDF_TARGET_NAME} {IDF_TARGET_ECO_VERSION}.
An RSA-based Secure Boot verification scheme, i.e., Secure Boot v2, is implemented on {IDF_TARGET_NAME} {IDF_TARGET_ECO_VERSION}.
.. only:: SOC_SECURE_BOOT_V2_ECC and not SOC_SECURE_BOOT_V2_RSA
A ECC based Secure Boot verification scheme (Secure Boot V2) has been introduce on {IDF_TARGET_NAME}
An ECC-based Secure Boot verification scheme i.e., Secure Boot v2, has been introduced on {IDF_TARGET_NAME}.
.. only:: SOC_SECURE_BOOT_V2_RSA and SOC_SECURE_BOOT_V2_ECC
{IDF_TARGET_NAME} has provision to choose between a {IDF_TARGET_SBV2_SCHEME} based secure boot verification scheme.
{IDF_TARGET_NAME} has provision to choose a {IDF_TARGET_SBV2_SCHEME} based Secure Boot verification scheme.
The Secure Boot process on the {IDF_TARGET_NAME} involves the following steps:
The Secure Boot process on {IDF_TARGET_NAME} involves the following steps:
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.
1. The first stage bootloader (i.e. ROM boot), which is residing in ROM, loads the second stage bootloader, and the second stage bootloader's {IDF_TARGET_SBV2_SCHEME} signature is verified. Only 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 {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.
- The {IDF_TARGET_SBV2_SCHEME}'s 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 or esp32c2
@ -79,23 +83,24 @@ Advantages
- {IDF_TARGET_NAME} provides the facility to permanently revoke individual public keys. This can be configured conservatively or aggressively.
- Conservatively - The old key is revoked after the bootloader and application have successfully migrated to a new key. Aggressively - The key is revoked as soon as verification with this key fails.
- Conservatively: The old key is revoked after the bootloader and application have successfully migrated to a new key.
- Aggressively: The key is revoked as soon as verification with this key fails.
- Same image format and signature verification method is applied for applications and software bootloader.
- The same image format and signature verification method is applied for applications and the software bootloader.
- No secrets are stored on the device. Therefore, it is immune to passive side-channel attacks (timing or power analysis, etc.)
- No secrets are stored on the device. Therefore, it is immune to passive side-channel attacks, e.g., timing or power analysis.
Secure Boot V2 Process
Secure Boot v2 Process
----------------------
This is an overview of the Secure Boot V2 Process. Instructions how to enable Secure Boot are supplied in section :ref:`secure-boot-v2-howto`.
This is an overview of the Secure Boot v2 Process. Instructions on how to enable Secure Boot are supplied in section :ref:`secure-boot-v2-howto`.
Secure Boot V2 verifies the bootloader image and application binary images using a dedicated *signature block*. Each image has a separately generated signature block which is appended to the end of the image.
Secure Boot v2 verifies the bootloader image and application binary images using a dedicated *signature block*. Each image has a separately generated signature block which is appended to the end of the image.
.. only:: esp32
Only one signature block can be appended to the bootloader or application image in ESP32 ECO3.
Only one signature block can be appended to the bootloader or application image in ESP32 chip revision v3.0.
.. only:: esp32c2
@ -103,44 +108,45 @@ Secure Boot V2 verifies the bootloader image and application binary images using
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
Up to 3 signature blocks can be appended to the bootloader or application image in {IDF_TARGET_NAME}.
Up to three 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 {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.
The Secure Boot V2 process follows these steps:
The Secure Boot v2 process follows these steps:
1. On startup, the ROM code checks the Secure Boot V2 bit in the eFuse. If Secure Boot is disabled, a normal boot will be executed. If Secure Boot is enabled, the boot will proceed according to the following steps.
1. On startup, the ROM code checks the Secure Boot v2 bit in the eFuse. If Secure Boot is disabled, a normal boot will be executed; if Secure Boot is enabled, the boot will proceed according to the following steps.
2. The ROM code verifies the bootloader's signature block (:ref:`verify_signature-block`). If this fails, the boot process will be aborted.
2. The ROM code verifies the bootloader's signature block, see :ref:`verify_signature-block`. If this fails, the boot process will be aborted.
3. The ROM code verifies the bootloader image using the raw image data, its corresponding signature block(s), and the eFuse (:ref:`verify_image`). If this fails, the boot process will be aborted.
3. The ROM code verifies the bootloader image using the raw image data, its corresponding signature block(s), and the eFuse, see :ref:`verify_image`. If this fails, the boot process will be aborted.
4. The ROM code executes the bootloader.
5. The bootloader verifies the application image's signature block (:ref:`verify_signature-block`). If this fails, the boot process will be aborted.
5. The bootloader verifies the application image's signature block, see :ref:`verify_signature-block`. If this fails, the boot process will be aborted.
6. The bootloader verifies the application image using the raw image data, its corresponding signature blocks and the eFuse (:ref:`verify_image`). If this fails, the boot process will be aborted. If the verification fails but another application image is found, the bootloader will then try to verify that other image using steps 5 to 7. This repeats until a valid image is found or no other images are found.
6. The bootloader verifies the application image using the raw image data, its corresponding signature blocks, and the eFuse, see :ref:`verify_image`. If this fails, the boot process will be aborted. If the verification fails but another application image is found, the bootloader will then try to verify that other image using steps 5 to 7. This repeats until a valid image is found or no other images are found.
7. The bootloader executes the verified application image.
.. _signature-block-format:
Signature Block Format
----------------------
The signature block starts on a 4 KB aligned boundary and has a flash sector of its own. The signature is calculated over all bytes in the image including the padding bytes (:ref:`secure_padding`).
The signature block starts on a 4 KB aligned boundary and has a flash sector of its own. The signature is calculated over all bytes in the image including the padding bytes, see :ref:`secure_padding`.
.. only:: SOC_SECURE_BOOT_V2_RSA and SOC_SECURE_BOOT_V2_ECC
.. note::
{IDF_TARGET_NAME} has a provision to choose between RSA scheme and ECDSA scheme. Only one scheme can be used per device.
{IDF_TARGET_NAME} has a provision to choose between the RSA scheme and the ECDSA scheme. Only one scheme can be used per device.
ECDSA provides similar security strength, compared to RSA, with shorter key lengths. Current estimates are that ECDSA with curve P-256 has an approximate equivalent strength to RSA with 3072-bit keys. However, ECDSA signature verification takes considerably more amount of time as compared to RSA signature verification.
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 boot-up time is required whereas ECDSA is recommended for use cases where shorter key length is required.
.. only:: not esp32p4 or not esp32c5
@ -158,7 +164,7 @@ The signature block starts on a 4 KB aligned boundary and has a flash sector of
- {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 above table compares the time taken to verify a signature in a particular scheme. It does not indicate the boot-up time.
The content of each signature block is shown in the following table:
@ -173,31 +179,31 @@ The content of each signature block is shown in the following table:
- **Description**
* - 0
- 1
- Magic byte
- Magic byte.
* - 1
- 1
- Version number byte (currently 0x02), 0x01 is for Secure Boot V1.
- Version number byte, currently 0x02, and 0x01 is for Secure Boot V1.
* - 2
- 2
- Padding bytes, Reserved. Should be zero.
- 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).
- RSA Public Modulus used for signature verification, value 'n' in RFC8017.
* - 420
- 4
- RSA Public Exponent used for signature verification (value e in RFC8017).
- RSA Public Exponent used for signature verification, value 'e' in RFC8017.
* - 424
- 384
- Pre-calculated R, derived from n.
- Pre-calculated R, derived from 'n'.
* - 808
- 4
- Pre-calculated M, derived from n
- 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, MGF1 function, salt length 32 bytes, default trailer field (0xBC).
- RSA-PSS Signature result (section 8.1.1 of RFC8017) of image content, computed using the following PSS parameters: SHA256 hash, MGF1 function, salt length 32 bytes, default trailer field 0xBC.
* - 1196
- 4
- CRC32 of the preceding 1196 bytes.
@ -212,7 +218,7 @@ The content of each signature block is shown in the following table:
.. only:: SOC_SECURE_BOOT_V2_ECC
.. list-table:: Content of a ECDSA Signature Block
.. list-table:: Content of an ECDSA Signature Block
:widths: 10 10 40
:header-rows: 1
@ -224,22 +230,22 @@ The content of each signature block is shown in the following table:
- Magic byte.
* - 1
- 1
- Version number byte (currently 0x03).
- Version number byte, currently 0x03.
* - 2
- 2
- Padding bytes, Reserved. Should be zero.
- 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).
- 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.
- 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.
- 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.
@ -250,22 +256,23 @@ The content of each signature block is shown in the following table:
- 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.
The remainder of the signature sector is erased flash (0xFF) which allows writing other signature blocks after the previous signature block.
.. _secure_padding:
Secure Padding
--------------
In Secure Boot V2 scheme, the application image is padded to the flash MMU page size boundary to ensure that only verified contents are mapped in the internal address space. This is known as secure padding. Signature of the image is calculated after padding and then signature block (4KB) gets appended to the image.
In the Secure Boot v2 scheme, the application image is padded to the flash MMU page size boundary to ensure that only verified contents are mapped in the internal address space, which is known as secure padding. The signature of the image is calculated after padding and then the signature block (4 KB) gets appended to the image.
.. list::
- Default flash MMU page size is 64 KB
:SOC_MMU_PAGE_SIZE_CONFIGURABLE: - {IDF_TARGET_NAME} supports configurable flash MMU page size, it (``CONFIG_MMU_PAGE_SIZE``) gets set based on the :ref:`CONFIG_ESPTOOLPY_FLASHSIZE`
:SOC_MMU_PAGE_SIZE_CONFIGURABLE: - {IDF_TARGET_NAME} supports configurable flash MMU page size, and ``CONFIG_MMU_PAGE_SIZE`` gets set based on the :ref:`CONFIG_ESPTOOLPY_FLASHSIZE`
- Secure padding is applied through the option ``--secure-pad-v2`` in the ``elf2image`` conversion using ``esptool.py``
Following table explains the Secure Boot V2 signed image with secure padding and signature block appended:
The following table explains the Secure Boot v2 signed image with secure padding and signature block appended:
.. list-table:: Contents of a signed application
:widths: 20 20 20
@ -276,33 +283,35 @@ Following table explains the Secure Boot V2 signed image with secure padding and
- **Description**
* - 0
- 580
- Unsigned application size (as an example)
- Unsigned application size, as an example
* - 580
- 60
- Secure padding (aligned to next 64KB boundary)
- Secure padding, aligned to the next 64 KB boundary
* - 640
- 4
- Signature block
.. note::
Please note that the application image always starts on the next flash MMU page size boundary (default 64KB) and hence the space left over after the signature block shown above can be utilized to store any other data partitions (e.g., ``nvs``).
Please note that the application image always starts on the next flash MMU page size boundary, default 64 KB, and hence the space left over after the signature block shown above can be utilized to store any other data partitions, e.g., ``nvs``.
.. _verify_signature-block:
Verifying a Signature Block
-----------------------------
---------------------------
A signature block is valid if the first byte is ``0xe7`` and a valid CRC32 is stored at offset 1196. Otherwise, it is invalid.
A signature block is "valid" if the first byte is 0xe7 and a valid CRC32 is stored at offset 1196. Otherwise it is invalid.
.. _verify_image:
Verifying an Image
-----------------------------
------------------
An image is "verified" if the public key stored in any signature block is valid for this device, and if the stored signature is valid for the image data read from flash.
An image is verified if the public key stored in any signature block is valid for this device, and if the signature stored in that signature block matches with the signature calculated for the image data read from flash.
1. Compare the SHA-256 hash digest of the public key embedded in the bootloader's signature block with the digest(s) saved in the eFuses. If public key's hash does not match any of the hashes from the eFuses, the verification fails.
1. Compare the SHA-256 hash digest of the public key embedded in the bootloader's signature block with the digest(s) saved in the eFuses. If the public key's hash does not match any of the hashes from the eFuses, the verification fails.
2. Generate the application image digest and match it with the image digest in the signature block. If the digests do not match, the verification fails.
@ -322,9 +331,10 @@ An image is "verified" if the public key stored in any signature block is valid
Bootloader Size
---------------
Enabling Secure boot and/or flash encryption will increase the size of bootloader, which might require updating partition table offset. See :ref:`bootloader-size`.
Enabling Secure Boot and/or flash encryption will increase the size of the bootloader, which might require updating the partition table offset. See :ref:`bootloader-size`.
When :ref:`CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES` is disabled, the bootloader will use the ``--pad-to-size`` option in ``elf2image`` command of ``esptool`` for sector padding, with a size of 4 KB per sector.
In the case when :ref:`CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES` is disabled, the bootloader is sector padded (4KB) using the ``--pad-to-size`` option in ``elf2image`` command of ``esptool``.
.. _efuse-usage:
@ -333,11 +343,11 @@ eFuse Usage
.. only:: esp32
ESP32-ECO3:
ESP32 chip revision v3.0:
- ABS_DONE_1 - Enables Secure Boot protection on boot.
- BLK2 - Stores the SHA-256 digest of the public key. SHA-256 hash of public key modulus, exponent, pre-calculated R & M' values (represented as 776 bytes offsets 36 to 812 - as per the :ref:`signature-block-format`) is written to an eFuse key block. The write-protection bit must be set, but the read-protection bit must not.
- BLK2 - Stores the SHA-256 digest of the public key. SHA-256 hash of public key modulus, exponent, pre-calculated R & M' values is written to an eFuse key block. This digest is represented as 776 bytes, with offsets of 36 to 812, as per the :ref:`signature-block-format`. The write-protection bit must be set, but the read-protection bit must not.
.. only:: not esp32
@ -345,54 +355,57 @@ eFuse Usage
.. only:: SOC_EFUSE_KEY_PURPOSE_FIELD
- KEY_PURPOSE_X - Set the purpose of the key block on {IDF_TARGET_NAME} by programming SECURE_BOOT_DIGESTX (X = 0, 1, 2) into KEY_PURPOSE_X (X = 0, 1, 2, 3, 4, 5). Example: If KEY_PURPOSE_2 is set to SECURE_BOOT_DIGEST1, then BLOCK_KEY2 will have the Secure Boot V2 public key digest. The write-protection bit must be set (this field does not have a read-protection bit).
- KEY_PURPOSE_X - Set the purpose of the key block on {IDF_TARGET_NAME} by programming SECURE_BOOT_DIGESTX (X = 0, 1, 2) into KEY_PURPOSE_X (X = 0, 1, 2, 3, 4, 5). Example: If KEY_PURPOSE_2 is set to SECURE_BOOT_DIGEST1, then BLOCK_KEY2 will have the Secure Boot v2 public key digest. The write-protection bit must be set, and this field does not have a read-protection bit.
- BLOCK_KEYX - The block contains the data corresponding to its purpose programmed in KEY_PURPOSE_X. Stores the SHA-256 digest of the public key. SHA-256 hash of public key modulus, exponent, pre-calculated R & M' values (represented as 776 bytes offsets 36 to 812 - as per the :ref:`signature-block-format`) is written to an eFuse key block. The write-protection bit must be set, but the read-protection bit must not.
- BLOCK_KEYX - The block contains the data corresponding to its purpose programmed in KEY_PURPOSE_X. Stores the SHA-256 digest of the public key is written to an eFuse key block. This digest is represented as 776 bytes, with offsets of 36 to 812, as per the :ref:`signature-block-format`. The write-protection bit must be set, but the read-protection bit must not.
- KEY_REVOKEX - The revocation bits corresponding to each of the 3 key block. Ex. Setting KEY_REVOKE2 revokes the key block whose key purpose is SECURE_BOOT_DIGEST2.
- KEY_REVOKEX - The revocation bits corresponding to each of the 3 key blocks. E.g., setting KEY_REVOKE2 revokes the key block whose key purpose is SECURE_BOOT_DIGEST2.
- SECURE_BOOT_AGGRESSIVE_REVOKE - Enables aggressive revocation of keys. The key is revoked as soon as verification with this key fails.
To ensure no trusted keys can be added later by an attacker, each unused key digest slot should be revoked (KEY_REVOKEX). It will be checked during app startup in :cpp:func:`esp_secure_boot_init_checks` and fixed unless :ref:`CONFIG_SECURE_BOOT_ALLOW_UNUSED_DIGEST_SLOTS` is enabled.
To ensure no trusted keys can be added later by an attacker, each unused key digest slot should be revoked with KEY_REVOKEX. It will be checked during app startup in :cpp:func:`esp_secure_boot_init_checks` and fixed unless :ref:`CONFIG_SECURE_BOOT_ALLOW_UNUSED_DIGEST_SLOTS` is enabled.
The key(s) must be readable in order to give software access to it. If the key(s) is read-protected then the software reads the key(s) as all zeros and the signature verification process will fail, and the boot process will be aborted.
.. _secure-boot-v2-howto:
How To Enable Secure Boot V2
How To Enable Secure Boot v2
----------------------------
1. Open the :ref:`project-configuration-menu`, in "Security features" set "Enable hardware Secure Boot in bootloader" to enable Secure Boot.
1. Open the :ref:`project-configuration-menu`, in ``Security features`` set ``Enable hardware Secure Boot in bootloader`` to enable Secure Boot.
.. only:: esp32
2. For ESP32, Secure Boot V2 is available only ESP32 ECO3 onwards. To view the "Secure Boot V2" option the chip revision should be changed to revision 3 (ESP32- ECO3). To change the chip revision, set "Minimum Supported ESP32 Revision" to Rev 3 in "Component Config" -> "ESP32- Specific".
2. For ESP32, Secure Boot v2 is available only ESP32 chip revision v3.0 onwards. To view the ``Secure Boot v2`` option, the chip revision should be changed to ESP32 chip revision v3.0. To change the chip revision, set ``Minimum Supported ESP32 Revision`` to v3.0 in ``Component Config`` > ``ESP32- Specific``.
3. Specify the path to Secure Boot signing key, relative to the project directory.
3. Specify the path to the Secure Boot signing key, relative to the project directory.
4. Select the desired UART ROM download mode in "UART ROM download mode". By default the UART ROM download mode has been kept enabled in order to prevent permanently disabling it in the development phase, this option is a potentially insecure option. It is recommended to disable the UART download mode for better security.
4. Select the desired UART ROM download mode in ``UART ROM download mode``. By default the UART ROM download mode has been kept enabled in order to prevent permanently disabling it in the development phase, this option is a potentially insecure option. It is recommended to disable the UART download mode for better security.
.. only:: SOC_SECURE_BOOT_V2_RSA or SOC_SECURE_BOOT_V2_ECC
2. The "Secure Boot V2" option will be selected and the "App Signing Scheme" would be set to {IDF_TARGET_SBV2_DEFAULT_SCHEME} by default. {IDF_TARGET_SECURE_BOOT_OPTION_TEXT}
2. The ``Secure Boot v2`` option will be selected and the ``App Signing Scheme`` will be set to {IDF_TARGET_SBV2_DEFAULT_SCHEME} by default. {IDF_TARGET_SECURE_BOOT_OPTION_TEXT}
3. Specify the path to Secure Boot signing key, relative to the project directory.
3. Specify the path to the Secure Boot signing key, relative to the project directory.
4. Select the desired UART ROM download mode in "UART ROM download mode". By default, it is set to "Permanently switch to Secure mode" which is generally recommended. For production devices, the most secure option is to set it to "Permanently disabled".
4. Select the desired UART ROM download mode in ``UART ROM download mode``. By default, it is set to ``Permanently switch to Secure mode`` which is generally recommended. For production devices, the most secure option is to set it to ``Permanently disabled``.
5. Set other menuconfig options (as desired). Then exit menuconfig and save your configuration.
5. Set other menuconfig options as desired. Then exit menuconfig and save your configuration.
6. The first time you run ``idf.py build``, if the signing key is not found then an error message will be printed with a command to generate a signing key via ``idf.py secure-generate-signing-key``.
.. important::
A signing key generated this way will use the best random number source available to the OS and its Python installation (`/dev/urandom` on OSX/Linux and `CryptGenRandom()` on Windows). If this random number source is weak, then the private key will be weak.
A signing key generated this way will use the best random number source available to the OS and its Python installation, which is `/dev/urandom` on OSX/Linux and `CryptGenRandom()` on Windows. If this random number source is weak, then the private key will be weak.
.. important::
For production environments, we recommend generating the key pair using openssl or another industry standard encryption program. See :ref:`secure-boot-v2-generate-key` for more details.
7. Run ``idf.py bootloader`` to build a Secure Boot enabled bootloader. The build output will include a prompt for a flashing command, using ``esptool.py write_flash``.
For production environments, we recommend generating the key pair using OpenSSL or another industry-standard encryption program. See :ref:`secure-boot-v2-generate-key` for more details.
8. When you are ready to flash the bootloader, run the specified command (you have to enter it yourself, this step is not performed by the build system) and then wait for flashing to complete.
7. Run ``idf.py bootloader`` to build a Secure Boot-enabled bootloader. The build output will include a prompt for a flashing command, using ``esptool.py write_flash``.
8. When you are ready to flash the bootloader, run the specified command and then wait for flashing to complete. You have to enter it yourself, this step is not performed by the build system.
9. Run ``idf.py flash`` to build and flash the partition table and the just-built app image. The app image will be signed using the signing key you generated in step 6.
@ -404,23 +417,25 @@ How To Enable Secure Boot V2
.. note::
Secure boot will not be enabled until after a valid partition table and app image have been flashed. This is to prevent accidents before the system is fully configured.
Secure Boot will not be enabled until after a valid partition table and app image have been flashed. This is to prevent accidents before the system is fully configured.
.. note::
If the {IDF_TARGET_NAME} is reset or powered down during the first boot, it will start the process again on the next boot.
11. On subsequent boots, the Secure Boot hardware will verify the software bootloader has not changed and the software bootloader will verify the signed app image (using the validated public key portion of its appended signature block).
11. On subsequent boots, the Secure Boot hardware will verify the software bootloader has not changed and the software bootloader will verify the signed app image using the validated public key portion of its appended signature block.
Restrictions After Secure Boot Is Enabled
-----------------------------------------
- Any updated bootloader or app will need to be signed with a key matching the digest already stored in eFuse.
- After Secure Boot is enabled, no further eFuses can be read protected. (If :doc:`/security/flash-encryption` is enabled then the bootloader will ensure that any flash encryption key generated on first boot will already be read protected.) If :ref:`CONFIG_SECURE_BOOT_INSECURE` is enabled then this behavior can be disabled, but this is not recommended.
- After Secure Boot is enabled, no further eFuses can be read-protected. If :doc:`/security/flash-encryption` is enabled then the bootloader will ensure that any flash encryption key generated on the first boot will already be read-protected. If :ref:`CONFIG_SECURE_BOOT_INSECURE` is enabled, then this behavior can be disabled, but this is not recommended.
- Please note that enabling Secure Boot or flash encryption disables the USB-OTG USB stack in the ROM, disallowing updates via the serial emulation or Device Firmware Update (DFU) on that port.
.. _secure-boot-v2-generate-key:
Generating Secure Boot Signing Key
@ -430,40 +445,41 @@ The build system will prompt you with a command to generate a new signing key vi
.. only:: esp32 or SOC_SECURE_BOOT_V2_RSA
The ``--version 2`` parameter will generate the RSA 3072 private key for Secure Boot V2. Additionally ``--scheme rsa3072`` can be passed as well to generate RSA 3072 private key
The ``--version 2`` parameter will generate the RSA 3072 private key for Secure Boot v2. Additionally ``--scheme rsa3072`` can be passed as well to generate RSA 3072 private key.
.. only:: SOC_SECURE_BOOT_V2_ECC
Select the ECDSA scheme by passing ``--version 2 --scheme ecdsa256`` or ``--version 2 --scheme ecdsa192`` to generate corresponding ECDSA private key
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.
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:
For example, to generate a signing key using the OpenSSL command line:
.. only:: esp32 or SOC_SECURE_BOOT_V2_RSA
For RSA 3072
```
.. code-block::
openssl genrsa -out my_secure_boot_signing_key.pem 3072
```
.. only:: SOC_SECURE_BOOT_V2_ECC
For ECC NIST192p curve
For the ECC NIST192p curve
.. code-block::
```
openssl ecparam -name prime192v1 -genkey -noout -out my_secure_boot_signing_key.pem
```
For ECC NIST256p curve
For the ECC NIST256p curve
.. code-block::
```
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.
.. _remote-sign-v2-image:
Remote Signing of Images
@ -472,28 +488,35 @@ Remote Signing of Images
Signing Using ``idf.py``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For production builds, it can be good practice to use a remote signing server rather than have the signing key on the build machine (which is the default esp-idf Secure Boot configuration). The espsecure.py command line program can be used to sign app images & partition table data for Secure Boot, on a remote system.
For production builds, it can be good practice to use a remote signing server rather than have the signing key on the build machine (which is the default ESP-IDF Secure Boot configuration). The ``espsecure.py`` command line program can be used to sign app images and partition table data for Secure Boot, on a remote system.
To use remote signing, disable the option :ref:`CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES` and build the firmware. The private signing key does not need to be present on the build system.
After the app image and partition table are built, the build system will print signing steps using idf.py::
After the app image and partition table are built, the build system will print signing steps using ``idf.py``:
.. code-block::
idf.py secure-sign-data BINARY_FILE --keyfile PRIVATE_SIGNING_KEY
The above command appends the image signature to the existing binary. You can use the `--output` argument to write the signed binary to a separate file::
The above command appends the image signature to the existing binary. You can use the `--output` argument to write the signed binary to a separate file:
.. code-block::
idf.py secure-sign-data --keyfile PRIVATE_SIGNING_KEY --output SIGNED_BINARY_FILE BINARY_FILE
Signing Using Pre-calculated Signatures
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you have valid pre-calculated signatures generated for an image and their corresponding public keys, you can use these signatures to generate a signature sector and append it to the image. Note that the pre-calculated signature should be calculated over all bytes in the image including the secure-padding bytes.
In such cases, the firmware image should be built by disabling the option :ref:`CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES`. This image will be secure-padded and to generate a signed binary use the following command::
In such cases, the firmware image should be built by disabling the option :ref:`CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES`. This image will be secure-padded and to generate a signed binary use the following command:
.. code-block::
idf.py secure-sign-data --pub-key PUBLIC_SIGNING_KEY --signature SIGNATURE_FILE --output SIGNED_BINARY_FILE BINARY_FILE
The above command verifies the signature, generates a signature block (refer to :ref:`signature-block-format`) and appends it to the binary file.
The above command verifies the signature, generates a signature block (refer to :ref:`signature-block-format`), and appends it to the binary file.
Signing Using an External Hardware Security Module (HSM)
@ -505,12 +528,15 @@ In such cases, disable the option :ref:`CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
.. note:: For all the above three remote signing workflows, the signed binary is written to the filename provided to the ``--output`` argument and the option ``--append_signatures`` allows us to append multiple signatures (up to 3) the image.
.. note::
For all the above three remote signing workflows, the signed binary is written to the filename provided to the ``--output`` argument, and the option ``--append_signatures`` allows us to append multiple signatures (up to 3) to the image.
.. only:: not SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
.. note:: For all the above three remote signing workflows, the signed binary is written to the filename provided to the ``--output`` argument.
.. note::
For all the above three remote signing workflows, the signed binary is written to the filename provided to the ``--output`` argument.
Secure Boot Best Practices
@ -528,12 +554,13 @@ Secure Boot Best Practices
--------------
* Between 1 and 3 {IDF_TARGET_SBV2_KEY} public key pairs (Keys #0, #1, #2) should be computed independently and stored separately.
* The KEY_DIGEST eFuses should be write protected after being programmed.
* The KEY_DIGEST eFuses should be write-protected after being programmed.
* The unused KEY_DIGEST slots must have their corresponding KEY_REVOKE eFuse burned to permanently disable them. This must happen before the device leaves the factory.
* The eFuses can either be written by the software bootloader during during first boot after enabling "Secure Boot V2" from menuconfig or can be done using `espefuse.py` which communicates with the serial bootloader program in ROM.
* The KEY_DIGESTs should be numbered sequentially beginning at key digest #0. (i.e., if key digest #1 is used, key digest #0 should be used. If key digest #2 is used, key digest #0 & #1 must be used.)
* The software bootloader (non OTA upgradeable) is signed using at least one, possibly all three, private keys and flashed in the factory.
* Apps should only be signed with a single private key (the others being stored securely elsewhere), however they may be signed with multiple private keys if some are being revoked (see Key Revocation, below).
* The eFuses can either be written by the software bootloader during first boot after enabling ``Secure Boot v2`` from menuconfig or can be done using ``espefuse.py`` which communicates with the serial bootloader program in ROM.
* The KEY_DIGESTs should be numbered sequentially beginning at key digest #0. If key digest #1 is used, key digest #0 should be used. If key digest #2 is used, key digest #0 & #1 must be used.
* The software bootloader is non-OTA upgradeable, and is signed using at least one, possibly all three, private keys and flashed in the factory.
* Apps should only be signed with a single private key, with the others being stored securely elsewhere. However, they may be signed with multiple private keys if some are being revoked, see :ref:`secure-boot-v2-key-revocation` below.
Multiple Keys
-------------
@ -541,51 +568,62 @@ Secure Boot Best Practices
* The bootloader should be signed with all the private key(s) that are needed for the life of the device, before it is flashed.
* The build system can sign with at most one private key, user has to run manual commands to append more signatures if necessary.
* You can use the append functionality of ``idf.py secure-sign-data``, this command would also printed at the end of the Secure Boot V2 enabled bootloader compilation.
.. code-block::
idf.py secure-sign-data -k secure_boot_signing_key2.pem --append_signatures -o signed_bootloader.bin build/bootloader/bootloader.bin
* While signing with multiple private keys, it is recommended that the private keys be signed independently, if possible on different servers and stored separately.
* You can check the signatures attached to a binary using -
* You can check the signatures attached to a binary using:
.. code-block::
espsecure.py signature_info_v2 datafile.bin
.. _secure-boot-v2-key-revocation:
Key Revocation
--------------
* Keys are processed in a linear order. (key #0, key #1, key #2).
* Keys are processed in a linear order, i.e., key #0, key #1, key #2.
* Applications should be signed with only one key at a time, to minimize the exposure of unused private keys.
* The bootloader can be signed with multiple keys from the factory.
.. note::
Note that enabling the config :ref:`CONFIG_SECURE_BOOT_ALLOW_UNUSED_DIGEST_SLOTS` only makes sure that the **app** does not revoke the unused digest slots.
But if you plan to enable secure boot during the fist boot up, the bootloader will intentionally revoke the unused digest slots while enabling secure boot, even if the above config is enabled because keeping the unused key slots un-revoked would a security hazard.
In case for any development workflow if you need to avoid this revocation, you should enable secure boot externally (:ref:`enable-secure-boot-v2-externally`) rather than enabling it during the boot up, so that the bootloader would not need to enable secure boot and thus you could avoid its revocation strategy.
But if you plan to enable secure boot during the fist boot up, the bootloader will intentionally revoke the unused digest slots while enabling secure boot, even if the above config is enabled. Because keeping the unused key slots unrevoked would be a security hazard.
In case for any development workflow if you need to avoid this revocation, you should :ref:`enable-secure-boot-v2-externally`, rather than enabling it during the boot up, so that the bootloader would not need to enable secure boot, and thus you could avoid its revocation strategy.
Conservative Approach:
Conservative Approach
~~~~~~~~~~~~~~~~~~~~~~
Assuming a trusted private key (N-1) has been compromised, to update to new key pair (N).
1. Server sends an OTA update with an application signed with the new private key (#N).
1. The server sends an OTA update with an application signed with the new private key (#N).
2. The new OTA update is written to an unused OTA app partition.
3. The new application's signature block is validated. The public keys are checked against the digests programmed in the eFuse & the application is verified using the verified public key.
3. The new application's signature block is validated. The public keys are checked against the digests programmed in the eFuse and the application is verified using the verified public key.
4. The active partition is set to the new OTA application's partition.
5. Device resets, loads the bootloader (verified with key #N-1 and #N) which then boots new app (verified with key #N).
6. The new app verifies bootloader and application with key #N (as a final check) and then runs code to revoke key #N-1 (sets KEY_REVOKE eFuse bit).
5. The device resets and loads the bootloader that is verified with key #N-1, which then boots the new app verified with key #N.
6. The new app verifies the bootloader with key #N as a final check, and then runs code to revoke key #N-1, i.e., sets KEY_REVOKE eFuse bit.
7. The API `esp_ota_revoke_secure_boot_public_key()` can be used to revoke the key #N-1.
* A similar approach can also be used to physically re-flash with a new key. For physical re-flashing, the bootloader content can also be changed at the same time.
.. _secure-boot-v2-aggressive-key-revocation:
Aggressive Approach:
~~~~~~~~~~~~~~~~~~~~
Aggressive Approach
~~~~~~~~~~~~~~~~~~~
ROM code has an additional feature of revoking a public key digest if the signature verification fails.
To enable this feature, you need to burn SECURE_BOOT_AGGRESSIVE_REVOKE efuse or enable :ref:`CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE`
To enable this feature, you need to burn ``SECURE_BOOT_AGGRESSIVE_REVOKE`` eFuse or enable :ref:`CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE`.
Key revocation is not applicable unless secure boot is successfully enabled. Also, a key is not revoked in case of invalid signature block or invalid image digest, it is only revoked in case the signature verification fails, i.e., revoke key only if failure in step 3 of :ref:`verify_image`
Key revocation is not applicable unless Secure Boot is successfully enabled. Also, a key is not revoked in case of an invalid signature block or invalid image digest, it is only revoked in case the signature verification fails, i.e., revoke key only if failure in step 3 of :ref:`verify_image`.
Once a key is revoked, it can never be used for verifying the signature of an image. This feature provides strong resistance against physical attacks on the device. However, this could also brick the device permanently if all the keys are revoked because of signature verification failure.
Once a key is revoked, it can never be used for verifying a signature of an image. This feature provides strong resistance against physical attacks on the device. However, this could also brick the device permanently if all the keys are revoked because of signature verification failure.
.. _secure-boot-v2-technical-details:
@ -594,43 +632,49 @@ Technical Details
The following sections contain low-level reference descriptions of various Secure Boot elements:
Manual Commands
~~~~~~~~~~~~~~~
Secure boot is integrated into the esp-idf build system, so ``idf.py build`` will sign an app image and ``idf.py bootloader`` will produce a signed bootloader if secure signed binaries on build is enabled.
Secure Boot is integrated into the ESP-IDF build system, so ``idf.py build`` will sign an app image, and ``idf.py bootloader`` will produce a signed bootloader if :ref:`CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES` is enabled.
However, it is possible to use the ``idf.py`` tool to make standalone signatures and digests.
To sign a binary image::
To sign a binary image:
.. code-block::
idf.py secure-sign-data --keyfile ./my_signing_key.pem --output ./image_signed.bin image-unsigned.bin
Keyfile is the PEM file containing an {IDF_TARGET_SBV2_KEY} private signing key.
.. _secure-boot-v2-and-flash-encr:
Secure Boot & Flash Encryption
------------------------------
If Secure Boot is used without :doc:`flash-encryption`, it is possible to launch "time-of-check to time-of-use" attack, where flash contents are swapped after the image is verified and running. Therefore, it is recommended to use both the features together.
If Secure Boot is used without :doc:`flash-encryption`, it is possible to launch a ``time-of-check to time-of-use`` attack, where flash contents are swapped after the image is verified and running. Therefore, it is recommended to use both features together.
.. only:: esp32c2
.. important::
{IDF_TARGET_NAME} has only one eFuse key block, which is used for both keys: Secure Boot and Flash Encryption. The eFuse key block can only be burned once. Therefore these keys should be burned together at the same time. Please note that "Secure Boot" and "Flash Encryption" can not be enabled separately as subsequent writes to eFuse key block shall return an error.
{IDF_TARGET_NAME} has only one eFuse key block, which is used for both keys: Secure Boot and Flash Encryption. The eFuse key block can only be burned once. Therefore these keys should be burned together at the same time. Please note that ``Secure Boot`` and ``Flash Encryption`` can not be enabled separately as subsequent writes to the eFuse key block shall return an error.
.. _signed-app-verify-v2:
Signed App Verification Without Hardware Secure Boot
----------------------------------------------------
The Secure Boot V2 signature of apps can be checked on OTA update, without enabling the hardware Secure Boot option. This option uses the same app signature scheme as Secure Boot V2, but unlike hardware Secure Boot it does not prevent an attacker who can write to flash from bypassing the signature protection.
The Secure Boot v2 signature of apps can be verified during an OTA update without the need to enable the hardware Secure Boot option. This approach utilizes the same app signature scheme as Secure Boot v2. However, unlike hardware Secure Boot, Software secure boot does not provide protection against an attacker with write access to flash memory, who could potentially bypass the signature verification.
This may be desirable in cases where the delay of Secure Boot verification on startup is unacceptable, and/or where the threat model does not include physical access or attackers writing to bootloader or app partitions in flash.
This may be desirable in cases where the delay of Secure Boot verification on startup is unacceptable, and/or where the threat model does not include physical access or attackers writing to the bootloader or app partitions in flash.
In this mode, the public key which is present in the signature block of the currently running app will be used to verify the signature of a newly updated app. (The signature on the running app is not verified during the update process, it is assumed to be valid.) In this way the system creates a chain of trust from the running app to the newly updated app.
In this mode, the public key that is present in the signature block of the currently running app will be used to verify the signature of a newly updated app. The signature on the running app is not verified during the update process, it is assumed to be valid. In this way, the system creates a chain of trust from the running app to the newly updated app.
For this reason, it is essential that the initial app flashed to the device is also signed. A check is run on app startup and the app will abort if no signatures are found. This is to try and prevent a situation where no update is possible. The app should have only one valid signature block in the first position. Note again that, unlike hardware Secure Boot V2, the signature of the running app is not verified on boot. The system only verifies a signature block in the first position and ignores any other appended signatures.
For this reason, it is essential that the initial app flashed to the device is also signed. Upon startup, the application checks for signatures. If no valid signatures are found, the app will abort and no updates can be applied. This is done in order to prevent a situation where no further updates are possible and the device shall be bricked. The app should have only one valid signature block in the first position. Note again that, unlike hardware Secure Boot v2, the signature of the running app is not verified on boot. The system only verifies a signature block in the first position and ignores any other appended signatures.
.. only:: not esp32
@ -640,46 +684,48 @@ For this reason, it is essential that the initial app flashed to the device is a
In general, it is recommended to use full hardware Secure Boot unless certain that this option is sufficient for application security needs.
.. _signed-app-verify-v2-howto:
How To Enable Signed App Verification
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Open :ref:`project-configuration-menu` -> Security features
1. Open :ref:`project-configuration-menu` > ``Security features``.
.. only:: esp32
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
2. Ensure ``App Signing Scheme`` is ``RSA``. For the ESP32 chip revision v3.0 chip, select :ref:`CONFIG_ESP32_REV_MIN` to ``v3.0`` to get the ``RSA`` option available.
.. only:: SOC_SECURE_BOOT_V2_RSA and not SOC_SECURE_BOOT_V2_ECC
2. Ensure `App Signing Scheme` is `RSA`
2. Ensure ``App Signing Scheme`` is ``RSA``.
.. only:: SOC_SECURE_BOOT_V2_ECC and not SOC_SECURE_BOOT_V2_RSA
2. Ensure `App Signing Scheme` is `ECDSA (V2)`
2. Ensure ``App Signing Scheme`` is ``ECDSA (v2)``.
.. only:: SOC_SECURE_BOOT_V2_RSA and SOC_SECURE_BOOT_V2_ECC
2. Choose `App Signing Scheme`. Either `RSA` or `ECDSA (V2)`
2. Choose ``App Signing Scheme``. Either ``RSA`` or ``ECDSA (v2)``.
3. Enable :ref:`CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT`
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.
4. By default, ``Sign binaries during build`` will be enabled by selecting the ``Require signed app images`` option, which will sign binary files as a part of the build process. The file named in ``Secure Boot private signing key`` will be used to sign the image.
5. If you disable "Sign binaries during build" option then all app binaries must be manually signed by following instructions in :ref:`remote-sign-v2-image`.
5. If you disable the ``Sign binaries during build`` option then all app binaries must be manually signed by following instructions in :ref:`remote-sign-v2-image`.
.. warning::
It is very important that all apps flashed have been signed, either during the build or after the build.
Advanced Features
-----------------
JTAG Debugging
~~~~~~~~~~~~~~
By default, when Secure Boot is enabled then JTAG debugging is disabled via eFuse. The bootloader does this on first boot, at the same time it enables Secure Boot.
By default, when Secure Boot is enabled, JTAG debugging is disabled via eFuse. The bootloader does this on the first boot, at the same time it enables Secure Boot.
See :ref:`jtag-debugging-security-features` for more information about using JTAG Debugging with either Secure Boot or signed app verification enabled.

View File

@ -1 +1,731 @@
.. include:: ../../en/security/secure-boot-v2.rst
:orphan:
安全启动 (secure boot) v2
============================
:link_to_translation:`en:[English]`
{IDF_TARGET_SBV2_SCHEME:default="RSA-PSS", esp32c2="ECDSA", esp32c6="RSA-PSS 或 ECDSA", esp32h2="RSA-PSS 或 ECDSA", esp32p4="RSA-PSS 或 ECDSA", esp32c5="RSA-PSS 或 ECDSA"}
{IDF_TARGET_SBV2_KEY:default="RSA-3072", esp32c2="ECDSA-256 或 ECDSA-192", esp32c6="RSA-3072、ECDSA-256 或 ECDSA-192", esp32h2="RSA-3072、ECDSA-256 或 ECDSA-192", esp32p4="RSA-3072、ECDSA-256 或 ECDSA-192"}
{IDF_TARGET_SECURE_BOOT_OPTION_TEXT:default="", esp32c6="推荐使用 RSA其验证时间更短。可以在菜单中选择 RSA 和 ECDSA 方案。", esp32h2="推荐使用 RSA其验证时间更短。可以在菜单中选择 RSA 和 ECDSA 方案。", esp32p4="推荐使用 RSA其验证时间更短。可以在菜单中选择 RSA 和 ECDSA 方案。"}
{IDF_TARGET_ECO_VERSION:default="", esp32="v3.0 及以上版本)", esp32c3="v3.0 及以上版本)"}
{IDF_TARGET_RSA_TIME:default="", esp32c6="约 2.7 ms", esp32h2="约 4.5 ms"}
{IDF_TARGET_ECDSA_TIME:default="", esp32c6="约 21.5 ms", esp32h2="约 36 ms"}
{IDF_TARGET_CPU_FREQ:default="", esp32c6="160 MHz", esp32h2="96 MHz"}
{IDF_TARGET_SBV2_DEFAULT_SCHEME:default="RSA", esp32c2="ECDSA (v2)"}
.. important::
本文档介绍了安全启动 v2{IDF_TARGET_NAME} {IDF_TARGET_ECO_VERSION} 支持该启动模式。
.. only:: esp32
芯片版本低于 v3.0 的 ESP32 安全启动请参阅 :doc:`secure-boot-v1`。如果你的芯片版本支持安全启动 v2推荐使用此模式相比安全启动 v1 更安全且灵活。
安全启动 v2 使用基于 {IDF_TARGET_SBV2_SCHEME} 的应用程序和引导加载程序 :ref:`second-stage-bootloader` 验证。若需要使用 {IDF_TARGET_SBV2_SCHEME} 方案对应用程序签名,且无需对引导加载程序签名,同样可以参考本文档。
.. only:: esp32
ESP32 v3.0 及以上芯片版本支持 ``Secure Boot v2````RSA App Signing Scheme`` 选项,可通过 :ref:`CONFIG_ESP32_REV_MIN` 设置芯片版本为 `v3.0` 及以上启用这两个选项。
.. only:: esp32c3
自 ESP32-C3 芯片版本 v3.0 起,提供了 ``Secure Boot v2`` 选项。请设置 :ref:`CONFIG_ESP32C3_REV_MIN` 为高于或等于 `v3.0`,以在 menuconfig 中使用上述选项。
.. note::
在本指南中,最常用的命令形式为 ``idf.py secure-<command>``,这是对应 ``espsecure.py <command>`` 的封装。基于 ``idf.py`` 的命令能提供更好的用户体验,但与基于 ``espsecure.py`` 的命令相比,可能会损失一部分高级功能。
背景
----------
安全启动通过检查每个启动的软件是否已签名来确保设备不会运行任何未经授权(即未签名)的代码。在 {IDF_TARGET_NAME} 上,这些软件包括第二阶段的引导加载程序和每个应用程序的二进制文件。注意,第一阶段的引导加载程序是无法更改的 ROM 代码,因此不需要签名。
.. only:: esp32 or (SOC_SECURE_BOOT_V2_RSA and not SOC_SECURE_BOOT_V2_ECC)
{IDF_TARGET_NAME} {IDF_TARGET_ECO_VERSION} 使用基于 RAS 的安全启动验证方案,即安全启动 v2。
.. only:: SOC_SECURE_BOOT_V2_ECC and not SOC_SECURE_BOOT_V2_RSA
{IDF_TARGET_NAME} 引入了基于 ECC 的安全启动验证方案,即安全启动 v2。
.. only:: SOC_SECURE_BOOT_V2_RSA and SOC_SECURE_BOOT_V2_ECC
{IDF_TARGET_NAME} 可以选择基于 {IDF_TARGET_SBV2_SCHEME} 的安全启动验证方案。
{IDF_TARGET_NAME} 的安全启动包括以下步骤:
1. 第一阶段引导加载程序 (ROM boot) 仍处于 ROM 中,加载第二阶段引导加载程序 (bootloader),并验证第二阶段引导加载程序的 {IDF_TARGET_SBV2_SCHEME} 签名。验证通过后方可进入第二阶段。
2. 二级引导程序加载特定应用程序镜像时,会验证应用程序的 {IDF_TARGET_SBV2_SCHEME} 签名。若验证通过,则执行应用程序镜像。
优势
----------
- {IDF_TARGET_SBV2_SCHEME} 的公钥存储在设备上,而相应的 {IDF_TARGET_SBV2_SCHEME} 私钥存储在私密位置,设备无法访问。
.. only:: esp32 or esp32c2
- 芯片在量产时只能生成并存储一个公钥。
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
- 芯片在量产时最多能生成并存储三个公钥。
- {IDF_TARGET_NAME} 支持永久注销个别公钥,对此可以选择保守或激进的配置。
- 保守配置:在此情况下,只有在引导加载程序和应用程序成功迁移到新密钥后才会注销旧密钥。
- 激进配置:在此情况下,只要使用此密钥验证失败,就会立即注销该密钥。
- 应用程序和软件引导加载程序采用相同的镜像格式和签名验证方法。
- 设备不存储任何机密信息,因此可以免受被动侧通道攻击的影响,如时序分析或功耗分析。
使用安全启动 v2
----------------------
以下为使用安全启动 v2 流程的概述。有关如何启用安全启动,请参阅 :ref:`secure-boot-v2-howto`
安全启动 v2 使用专用的 *签名块* 验证引导加载程序镜像和应用程序二进制镜像,每个镜像末尾都附加了一个单独生成的签名块。
.. only:: esp32
在 ESP32 芯片版本 v3.0 中,引导加载程序或应用程序镜像只能附加一个签名块。
.. only:: esp32c2
在 {IDF_TARGET_NAME} 中,引导加载程序或应用程序镜像只能附加一个签名块。
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
在 {IDF_TARGET_NAME} 中,引导加载程序或应用程序镜像至多可以附加三个签名块。
每个签名块包含前一个镜像的签名和相应的 {IDF_TARGET_SBV2_KEY} 公钥。有关格式详情,请参阅 :ref:`signature-block-format`。{IDF_TARGET_SBV2_KEY} 公钥的摘要存储在 eFuse 中。
应用程序镜像不仅在每次启动时验证,也会在每次空中升级 (OTA) 时验证。如果当前所选 OTA 应用程序镜像无法验证,引导加载程序将回退,并寻找其他正确签名的应用程序镜像。
安全启动 v2 流程遵循以下步骤:
1. 启动时ROM 代码检查 eFuse 中的安全启动 v2 位。如果禁用了安全启动,则执行普通启动;如果启用了安全启动,将继续以下步骤。
2. ROM 代码验证引导加载程序的签名块,请参阅 :ref:`verify_signature-block`。如果验证失败,启动过程将中止。
3. ROM 代码使用原始镜像数据、相应的签名块以及 eFuse 验证引导加载程序镜像,请参阅 :ref:`verify_image`。如果验证失败,启动过程将中止。
4. ROM 代码执行引导加载程序。
5. 引导加载程序验证应用程序镜像的签名块,请参阅 :ref:`verify_signature-block`。如果验证失败,启动过程将中止。
6. 引导加载程序使用原始镜像数据、相应的签名块以及 eFuse 验证引导加载程序镜像,请参阅 :ref:`verify_image`。如果验证失败,启动过程将中止。如果验证失败,但发现了其他应用程序镜像,引导加载程序将使用步骤 5 到 7 验证另一个镜像。该过程将重复,直至找到有效镜像,或所有镜像验证完毕。
7. 引导加载程序执行经验证的应用程序镜像。
.. _signature-block-format:
签名块格式
----------------------
签名块以 4 KB 的整数倍为起始位置,拥有独立 flash 扇区。签名计算覆盖了镜像中的所有字节,包括填充字节,请参阅 :ref:`secure_padding`
.. only:: SOC_SECURE_BOOT_V2_RSA and SOC_SECURE_BOOT_V2_ECC
.. note::
{IDF_TARGET_NAME} 可以选择 RSA 或 ECDSA 方案,每个设备只能选择一种方案。
与 RSA 相比ECDSA 拥有类似的安全性,但密钥长度更短。据估计,使用 P-256 曲线的 ECDSA 签名安全性大致相当于具有 3072 位密钥的 RSA。然而ECDSA 签名验证耗时明显长于 RSA 签名验证。
如果需要快速启动,建议使用 RSA如果需要较短的密钥建议使用 ECDSA。
.. only:: not esp32p4
.. list-table:: 签名验证耗时比较
:widths: 10 10 20
:header-rows: 1
* - **验证方案**
- **耗时**
- **CPU 频率**
* - RSA-3072
- {IDF_TARGET_RSA_TIME}
- {IDF_TARGET_CPU_FREQ}
* - ECDSA-P256
- {IDF_TARGET_ECDSA_TIME}
- {IDF_TARGET_CPU_FREQ}
上表比较了特定方案中验证签名所需的时间,不代表启动时间。
各签名块内容如下表所示:
.. only:: esp32 or SOC_SECURE_BOOT_V2_RSA
.. list-table:: RSA 签名块的内容
:widths: 10 10 40
:header-rows: 1
* - **偏移量**
- **大小(字节)**
- **描述**
* - 0
- 1
- 魔法字节。
* - 1
- 1
- 版本号字节,当前为 0x02安全启动 v1 的版本号字节为 0x01。
* - 2
- 2
- 填充字节。保留,应设置为 0。
* - 4
- 32
- 仅针对镜像内容的 SHA-256 哈希值,不包括签名块。
* - 36
- 384
- 用于验证签名的 RSA 公模数,在 RFC8017 中为 'n' 值。
* - 420
- 4
- 用于验证签名的 RSA 公指数,在 RFC8017 中为 'e' 值。
* - 424
- 384
- 预先计算的 R派生自 'n'。
* - 808
- 4
- 预先计算的 M',派生自 'n'。
* - 812
- 384
- 对镜像内容的 RSA-PSS 签名结果RFC8017 中的 8.1.1 节),使用以下 PSS 参数计算SHA256 哈希值、MGF1 函数、32 字节盐长度、默认尾部字段 0xBC。
* - 1196
- 4
- CRC32 的前 1196 字节。
* - 1200
- 16
- 长度填充为 1216 字节的零填充。
.. note::
R 和 M' 用于硬件辅助的蒙哥马利乘法 (Montgomery Multiplication)。
.. only:: SOC_SECURE_BOOT_V2_ECC
.. list-table:: ECDSA 签名块的内容
:widths: 10 10 40
:header-rows: 1
* - **偏移量**
- **大小(字节)**
- **描述**
* - 0
- 1
- 魔法字节。
* - 1
- 1
- 版本号字节,当前为 0x03。
* - 2
- 2
- 填充字节。保留,应设置为 0。
* - 4
- 32
- 仅针对镜像内容的 SHA-256 哈希值,不包括签名块。
* - 36
- 1
- 曲线 ID。1 代表 NIST192p 曲线2 代表 NIST256p 曲线。
* - 37
- 64
- ECDSA 公钥32 字节的 X 坐标,后跟 32 字节的 Y 坐标。
* - 101
- 64
- 对镜像内容的 ECDSA 签名结果RFC6090 中的 5.3.2 节32 字节的 R 组件,后跟 32 字节的 S 组件。
* - 165
- 1031
- 保留。
* - 1196
- 4
- 前面 1196 字节的 CRC32。
* - 1200
- 16
- 长度填充为 1216 字节的零填充。
签名扇区的其余部分是已擦除的 flash (0xFF),支持在前一个签名块之后写入其他签名块。
.. _secure_padding:
安全填充
--------------
在安全启动 v2 方案中,应用程序镜像经过处理,会填充到与 flash MMU 页面大小边界对齐,确保只有经过验证的内容会映射到内部地址空间,这称为安全填充。填充后会进行镜像签名计算,随后将签名块 (4 KB) 附加到镜像上。
.. list::
- 默认 flash MMU 页面大小为 64 KB
:SOC_MMU_PAGE_SIZE_CONFIGURABLE: - {IDF_TARGET_NAME} 支持配置 flash MMU 页面大小,``CONFIG_MMU_PAGE_SIZE`` 根据 :ref:`CONFIG_ESPTOOLPY_FLASHSIZE` 设置
- 在进行由 ``esptool.py`` 执行的 ``elf2image`` 转换时,可以通过使用选项 ``--secure-pad-v2`` 应用安全填充
带有安全填充和签名块的安全启动 v2 签名镜像的内容如下表所示:
.. list-table:: 已签名应用程序的内容
:widths: 20 20 20
:header-rows: 1
* - **偏移量**
- **大小 (KB)**
- **描述**
* - 0
- 580
- 未签名的应用程序大小,作为示例
* - 580
- 60
- 安全填充,与下一个 64 KB 边界对齐
* - 640
- 4
- 签名块
.. note::
注意,应用程序镜像始终从下一个 flash MMU 页面大小的边界开始,默认为 64 KB。因此使用上述签名块之后剩余的空间可以存储其他数据分区``nvs``
.. _verify_signature-block:
验证签名块
-----------------------------
如果签名块的第一个字节是 ``0xe7``,并且偏移量 1196 处存储了有效的 CRC32则签名块有效否则无效。
.. _verify_image:
验证镜像
-----------------------------
如果存储在某个签名块中的公钥是适用于当前设备的有效公钥,且该签名块中存储的签名与从 flash 中读取的镜像数据计算出的签名匹配,则该镜像通过验证。
1. 将嵌入在引导加载程序签名块中的公钥生成的 SHA-256 哈希摘要与存储在 eFuse 中的摘要进行比较,如果公钥的哈希摘要无法与 eFuse 中的任何哈希摘要匹配,则验证失败。
2. 生成应用程序镜像摘要,将其与签名块中的镜像摘要进行匹配,如果无法匹配,则验证失败。
.. only:: esp32 or (SOC_SECURE_BOOT_V2_RSA and not SOC_SECURE_BOOT_V2_ECC)
3. 使用公钥,采用 RSA-PSSRFC8017 的第 8.1.2 节)算法,验证引导加载程序镜像的签名,并与步骤 (2) 中计算的镜像摘要比较。
.. only:: SOC_SECURE_BOOT_V2_ECC and not SOC_SECURE_BOOT_V2_RSA
3. 使用公钥,采用 ECDSARFC6090 的第 5.3.3 节)算法,验证引导加载程序镜像的签名,并与步骤 (2) 中计算的镜像摘要比较。
.. only:: SOC_SECURE_BOOT_V2_ECC and SOC_SECURE_BOOT_V2_RSA
1. 使用公钥,采用 RSA-PSSRFC8017 的第 8.1.2 节)算法或 ECDSARFC6090 的第 5.3.3 节)算法,验证引导加载程序镜像的签名,并与步骤 (2) 中计算的镜像摘要比较。
引导加载程序大小
------------------
启用安全启动和/或 flash 加密都会增加引导加载程序的大小,因此可能需要更新分区表偏移量,请参阅 :ref:`bootloader-size`
禁用 :ref:`CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES` 时,引导加载程序将使用 ``esptool````elf2image`` 命令中的 ``--pad-to-size`` 选项进行扇区填充,每个扇区大小为 4 KB。
.. _efuse-usage:
使用 eFuse
-----------
.. only:: esp32
ESP32 芯片版本 v3.0
- ABS_DONE_1 - 在启动时启用安全启动保护。
- BLK2 - 存储公钥的 SHA-256 摘要。公钥模数、指数、预先计算的 R 和 M' 值的 SHA-256 哈希摘要都将写入 eFuse 密钥块。这个摘要大小为 776 字节,偏移量从 36 到 812:ref:`signature-block-format` 所示。注意,必须设置写保护位,但切勿设置读保护位。
.. only:: not esp32
- SECURE_BOOT_EN - 在启动时启用安全启动保护。
.. only:: SOC_EFUSE_KEY_PURPOSE_FIELD
- KEY_PURPOSE_X - 将 SECURE_BOOT_DIGESTX (X = 0, 1, 2) 烧录到 KEY_PURPOSE_X (X = 0, 1, 2, 3, 4, 5),设置密钥块功能。例如:若设置 KEY_PURPOSE_2 为 SECURE_BOOT_DIGEST1则 BLOCK_KEY2 将具有安全启动 v2 公钥摘要。注意,必须设置写保护位,该字段无读保护位。
- BLOCK_KEYX - 该块包含其在 KEY_PURPOSE_X 中烧录的功能的对应数据,并存储公钥的 SHA-256 哈希摘要。公钥模数、指数、预先计算的 R 和 M' 值的 SHA-256 哈希摘要都将写入 eFuse 密钥块。这个摘要大小为 776 字节,偏移量从 36 到 812:ref:`signature-block-format` 所示。注意,必须设置写保护位,但切勿设置读保护位。
- KEY_REVOKEX - 与 3 个密钥块中的每一个相对应的注销标记。例如,设置 KEY_REVOKE2 将注销密钥功能为 SECURE_BOOT_DIGEST2 的密钥块。
- SECURE_BOOT_AGGRESSIVE_REVOKE - 启用激进的密钥注销。只要与此密钥的验证失败,密钥就会立即注销。
为确保后续不会有攻击者添加受信任的密钥,应使用 KEY_REVOKEX 注销所有未使用的密钥摘要槽。若未启用 :ref:`CONFIG_SECURE_BOOT_ALLOW_UNUSED_DIGEST_SLOTS`,应用程序启动时,将在 :cpp:func:`esp_secure_boot_init_checks` 中检查和修复注销操作。
密钥必须为可读密钥,以便软件访问。如果密钥设置了读保护,软件只能读取到全为零的数据,导致签名验证失败,启动中止。
.. _secure-boot-v2-howto:
启用安全启动 v2
----------------------------
1. 打开 :ref:`project-configuration-menu`,在 ``Security features`` 下设置 ``Enable hardware Secure Boot in bootloader`` 以启用安全启动模式。
.. only:: esp32
2. 对于 ESP32安全启动 v2 仅适用于 ESP32 芯片版本 v3.0 及以上版本。请将芯片版本更改至 ESP32 芯片版本 v3.0 以查看 ``Secure Boot v2`` 选项。更改芯片版本时,请将 ``Component Config`` > ``ESP32- Specific`` 中的 ``Minimum Supported ESP32 Revision`` 设置为 v3.0。
3. 在项目目录的基础上,明确指定安全启动签名密钥的路径。
4. 在 ``UART ROM download mode`` 中选择所需的 UART ROM 下载模式。为避免在开发阶段该模式一直处于禁用状态UART ROM 模式默认启用,但这是一个潜在的不安全选项。为获得更好的安全性,建议禁用 UART 下载模式。
.. only:: SOC_SECURE_BOOT_V2_RSA or SOC_SECURE_BOOT_V2_ECC
2. 选择 ``Secure Boot v2`` 选项,并默认将 ``App Signing Scheme`` 设置为 {IDF_TARGET_SBV2_DEFAULT_SCHEME}。{IDF_TARGET_SECURE_BOOT_OPTION_TEXT}
3. 在项目目录的基础上,明确指定安全启动签名密钥的路径。
4. 在 ``UART ROM download mode`` 中选择所需 UART ROM 选项。默认情况下,通常建议将其设置为 ``Permanently switch to Secure mode``。对于生产设备,最安全的选项是将其设置为 ``Permanently disabled``
5. 按需设置其他 menuconfig 选项,随后退出 menuconfig 并保存配置。
6. 初次运行 ``idf.py build`` 时,如果未找到签名密钥,将打印错误消息,并提供通过 ``idf.py secure-generate-signing-key`` 生成签名密钥的命令。
.. important::
通过此方法生成的签名密钥将使用操作系统和其 Python 安装中提供的最佳随机数源,在 OSX/Linux 上为 `/dev/urandom`,在 Windows 上为 `CryptGenRandom()`。如果此随机数源不足以提供足够的安全性,那么生成的私钥也不足以提供足够的安全性。
.. important::
在生产环境下,建议使用 OpenSSL 或其他行业标准的加密程序生成密钥对,详情请参阅 :ref:`secure-boot-v2-generate-key`
7. 运行 ``idf.py bootloader`` 构建启用了安全启动的引导加载程序,构建输出中会包含一个烧录命令的提示,使用 ``esptool.py write_flash`` 烧录。
8. 当你准备好烧录引导加载程序时,请运行指定命令并等待烧录完成。注意,此处的指定命令需要手动输入,构建系统不会执行此过程。
9. 运行 ``idf.py flash`` 构建并烧录分区表以及刚刚构建的应用程序镜像,该镜像使用步骤 6 中生成的签名密钥进行签名。
.. note::
如果启用了安全启动,``idf.py flash`` 不会烧录引导加载程序。
10. 重置 {IDF_TARGET_NAME},它将启动你烧录的软件引导加载程序。该软件引导加载程序会在芯片上启用安全启动,然后验证应用程序镜像签名,并启动应用程序。请查看 {IDF_TARGET_NAME} 的串行控制器输出,确保已启用安全启动,且没有因构建配置发生错误。
.. note::
在烧录了有效的分区表和应用程序镜像之前,安全启动不会启用,避免在系统完全配置前发生意外情况。
.. note::
如果在初次启动过程中重置或关闭了 {IDF_TARGET_NAME},它会在下次启动时重新开始上述步骤。
11. 在后续启动过程中,安全启动硬件会验证软件引导加载程序是否更改,软件引导加载程序会使用其附加的签名块中经验证的公钥部分,验证已签名的应用程序镜像。
启用安全启动后的限制
-----------------------------------------
- 任何更新过的引导加载程序或应用程序都需要使用与已存储在 eFuse 中的摘要相匹配的密钥来签名。
- 启用安全启动后,将不再对任何 eFuse 进行读保护。如果启用了 :doc:`/security/flash-encryption`,引导加载程序将确保在初次启动时生成的任何 flash 加密密钥已进行读保护。如果启用了 :ref:`CONFIG_SECURE_BOOT_INSECURE`,则可以禁用对设置读保护的限制,但不建议这样做。
- 注意,启用安全启动或 flash 加密会禁用 ROM 中的 USB-OTG USB 栈,阻止通过该端口进行串行仿真或设备固件更新 (DFU)。
.. _secure-boot-v2-generate-key:
生成安全启动签名密钥
----------------------------------
构建系统会提示你,使用 ``idf.py secure-generate-signing-key`` 命令生成新签名密钥。
.. only:: esp32 or SOC_SECURE_BOOT_V2_RSA
参数 ``--version 2`` 会为安全启动 v2 生成 RSA 3072 私钥。此外,也可以传递 ``--scheme rsa3072`` 生成 RSA 3072 私钥。
.. only:: SOC_SECURE_BOOT_V2_ECC
传递 ``--version 2 --scheme ecdsa256````--version 2 --scheme ecdsa192`` 选择 ECDSA 方案,生成相应的 ECDSA 私钥。
签名密钥的强度取决于 (a) 系统的随机数源和 (b) 所用算法的正确性。对于生产设备,建议从具有高质量熵源的系统生成签名密钥,并使用最佳的可用 {IDF_TARGET_SBV2_SCHEME} 密钥生成工具。
例如,使用 OpenSSL 命令行生成签名密钥时:
.. only:: esp32 or SOC_SECURE_BOOT_V2_RSA
生成 RSA 3072 密钥
.. code-block::
openssl genrsa -out my_secure_boot_signing_key.pem 3072
.. only:: SOC_SECURE_BOOT_V2_ECC
生成 ECC NIST192p 曲线密钥
.. code-block::
openssl ecparam -name prime192v1 -genkey -noout -out my_secure_boot_signing_key.pem
生成 ECC NIST256p 曲线密钥
.. code-block::
openssl ecparam -name prime256v1 -genkey -noout -out my_secure_boot_signing_key.pem
注意,安全启动系统的强度取决于能否保持签名密钥的私密性。
.. _remote-sign-v2-image:
远程镜像签名
------------------------
使用 ``idf.py`` 进行签名
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
对于生产构建,将签名密钥存储在远程签名服务器上,而不是本地构建机器上,是一种比较好的方案,这也是默认的 ESP-IDF 安全启动配置。可以使用命令行工具 ``espsecure.py`` 在远程系统上为应用程序镜像和分区表数据签名,供安全启动使用。
使用远程签名时,请禁用选项 :ref:`CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES`,并构建固件。此时,私钥无需存在于构建系统中。
构建完应用程序镜像和分区表后,构建系统会使用 ``idf.py`` 打印签名步骤:
.. code-block::
idf.py secure-sign-data BINARY_FILE --keyfile PRIVATE_SIGNING_KEY
上述命令将镜像签名附加到现有的二进制文件中,你可以使用 `--output` 参数将签名后的二进制文件写入单独的文件:
.. code-block::
idf.py secure-sign-data --keyfile PRIVATE_SIGNING_KEY --output SIGNED_BINARY_FILE BINARY_FILE
使用预计算的签名进行签名
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
如果你拥有为镜像生成的有效预计算签名及相应公钥,你可以使用这些签名生成一个签名扇区,并将其附加到镜像中。注意,预计算的签名应计算在镜像中的所有字节,包括安全填充字节。
在此情况下,应禁用选项 :ref:`CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES` 来构建固件镜像。该镜像将进行安全填充,并使用以下命令,生成带签名的二进制文件:
.. code-block::
idf.py secure-sign-data --pub-key PUBLIC_SIGNING_KEY --signature SIGNATURE_FILE --output SIGNED_BINARY_FILE BINARY_FILE
上述命令会验证签名,生成签名块(请参阅 :ref:`signature-block-format`),并将其附加到二进制文件中。
使用外部硬件安全模块 (HSM) 进行签名
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
为了提高安全性,你可能会使用外部硬件安全模块 (HSM) 存储私钥,该私钥无法直接访问,但具备一个接口,可以生成二进制文件及其相应公钥的签名。
在此情况下,请禁用选项 :ref:`CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES` 并构建固件。随后,可以将已进行安全填充的镜像提供给外部硬件安全模块来生成签名。请参阅 `使用外部 HSM 签名 <https://docs.espressif.com/projects/esptool/en/latest/{IDF_TARGET_PATH_NAME}/espsecure/index.html#remote-signing-using-an-external-hsm>`_ 生成已签名镜像。
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
.. note::
在上述三种远程签名工作流程中,已签名的二进制文件将写入提供给 ``--output`` 参数的文件名中。选项 ``--append_signatures`` 支持将多个签名(最多 3 个)附加到镜像中。
.. only:: not SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
.. note::
在上述三种远程签名工作流程中,已签名的二进制文件将写入提供给 ``--output`` 参数的文件名中。
使用安全启动的建议
--------------------------
* 在具备高质量熵源的系统上生成签名密钥。
* 时刻对签名密钥保密,泄漏此密钥将危及安全启动系统。
* 不允许第三方使用 ``idf.py secure-`` 命令来观察密钥生成或签名过程的任何细节,这两个过程都容易受到定时攻击或其他侧信道攻击的威胁。
* 在安全启动配置中启用所有安全启动选项,包括 flash 加密、禁用 JTAG、禁用 BASIC ROM 解释器和禁用 UART 引导加载程序的加密 flash 访问。
* 结合 :doc:`flash-encryption` 使用安全启动,防止本地读取 flash 内容。
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
密钥管理
--------------
* 应独立计算并分别存储 1 到 3 个 {IDF_TARGET_SBV2_KEY} 公钥对(密钥 #0, #1, #2
* 完成烧录后,应设置 KEY_DIGEST eFuse 为写保护位。
* 未使用的 KEY_DIGEST 槽必须烧录其相应的 KEY_REVOKE eFuse以永久禁用。请在设备离开工厂前完成此操作。
* 烧录 eFuse 可以由软件引导加载程序在首次从 menuconfig 启用 ``Secure Boot v2`` 后进行,也可以使用 ``espefuse.py``,后者与 ROM 中的串行引导加载程序通信。
* KEY_DIGEST 应从密钥摘要 #0 开始,按顺序编号。如果使用了密钥摘要 #1则必须使用密钥摘要 #0。如果使用了密钥摘要 #2则必须使用密钥摘要 #0 和 #1。
* 软件引导加载程序不支持 OTA 升级,它将至少由一个私钥签名,也可能使用全部三个私钥,并在工厂内烧录。
* 应用程序应仅由单个私钥签名,其他私钥应妥善保管。但如果需要注销某些私钥,也可以使用多个签名私钥,请参阅下文的 :ref:`secure-boot-v2-key-revocation`
多个密钥管理
-------------
* 在烧录引导程序之前,应使用设备整个生命周期所需的所有私钥对引导程序签名。
* 构建系统每次只能使用一个私钥签名,如果需要,你必须手动运行命令以附加更多签名。
* 你可以使用 ``idf.py secure-sign-data`` 的附加功能,此命令也将在启用安全启动 v2 的引导加载程序编译的末尾显示。
.. code-block::
idf.py secure-sign-data -k secure_boot_signing_key2.pem --append_signatures -o signed_bootloader.bin build/bootloader/bootloader.bin
* 使用多个私钥签名时,建议独立签名这些私钥,可以的话请在不同服务器上进行签名,并将它们分开存储。
* 可以使用以下命令查看附加到二进制文件的签名:
.. code-block::
espsecure.py signature_info_v2 datafile.bin
.. _secure-boot-v2-key-revocation:
注销密钥管理
--------------
* 密钥按线性顺序处理,即密钥 #0、密钥 #1、密钥 #2。
* 应用程序每次应只使用一个密钥签名,尽量避免暴露未使用的私钥。
* 引导加载程序可以使用来自工厂的多个函数签名。
.. note::
请注意,启用配置 :ref:`CONFIG_SECURE_BOOT_ALLOW_UNUSED_DIGEST_SLOTS` 只能确保 **应用程序** 不会撤销未使用的摘要槽。
若想在设备首次启动时启用安全启动,那么即使启用了上述配置,引导加载程序也会在启用安全启动时撤销未使用的摘要槽,因为保留未使用的密钥槽会构成安全隐患。
如果在开发流程中需要保留未使用摘要槽,则应从外部启用安全启动 (:ref:`enable-secure-boot-v2-externally`),而不是在启动设备时启用安全启动,这样引导加载程序就无需启用安全启动,从而避免安全隐患。
保守方法
~~~~~~~~~~~~
假设一个受信任的私钥 (N-1) 受到威胁,需要升级到新的密钥对 (N)。
1. 服务器发送一次 OTA 更新,包含使用新的私钥 (#N) 签名的应用程序。
2. 新的 OTA 更新写入未使用的 OTA 应用程序分区。
3. 验证新应用程序的签名块。对比公钥与 eFuse 中烧录的摘要,并使用已验证的公钥验证应用程序。
4. 将活动分区设置为新的 OTA 应用程序分区。
5. 设备重置并加载使用密钥 #N-1 验证的引导加载程序,随后启动使用密钥 #N 验证的新应用程序。
6. 新应用程序使用密钥 #N 验证引导程序,这是最后的检查,然后运行代码注销密钥 #N-1即设置 KEY_REVOKE eFuse 位。
7. 可以使用 API `esp_ota_revoke_secure_boot_public_key()` 注销密钥 #N-1。
* 类似的方法也可以用于物理重新烧录,以使用新的密钥,还可以同时更改引导加载程序的内容。
.. _secure-boot-v2-aggressive-key-revocation:
激进方法
~~~~~~~~~~~~~~
ROM 代码具备一项额外功能,即在签名验证失败时可以注销公钥摘要。
请烧录 ``SECURE_BOOT_AGGRESSIVE_REVOKE`` eFuse 或启用 :ref:`CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE` 以启用此功能。
注销密钥仅适用于成功启用了安全启动的情况。此外,在签名块无效或镜像摘要无效的情况下不会注销密钥,仅在签名验证失败时,即在 :ref:`verify_image` 的第 3 步中验证失败时,才会执行注销操作。
一旦注销了密钥,它将无法再用于验证镜像签名。该功能提供了强大的物理攻击防护,但如果由于签名验证失败而注销了所有密钥,可能会导致设备再也无法使用。
.. _secure-boot-v2-technical-details:
技术细节
-----------------
以下章节包含安全启动元件的详细参考描述:
手动命令
~~~~~~~~~~~~~~~
安全启动已集成到 ESP-IDF 构建系统中,因此 ``idf.py build`` 将进行应用程序镜像签名。启用 :ref:`CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES` 后,``idf.py bootloader`` 将生成一个已签名的引导加载程序。
然而,也可以使用 ``idf.py`` 工具生成独立的签名和摘要。
二进制镜像签名:
.. code-block::
idf.py secure-sign-data --keyfile ./my_signing_key.pem --output ./image_signed.bin image-unsigned.bin
Keyfile 是包含 {IDF_TARGET_SBV2_KEY} 签名私钥的 PEM 文件。
.. _secure-boot-v2-and-flash-encr:
安全启动 & flash 加密
------------------------------
如果使用安全启动时没有启用 :doc:`flash-encryption`,可能会发生 ``time-of-check to time-of-use`` 攻击,即在验证并运行镜像后交换 flash 内容。因此,建议同时使用这两个功能。
.. only:: esp32c2
.. important::
{IDF_TARGET_NAME} 只有一个 eFuse 密钥块,用于存储两种密钥:安全启动和 flash 加密,但 eFuse 密钥块只能烧录一次,因此建议同时烧录这两种密钥。注意,``Secure Boot````Flash Encryption`` 无法分别启用,否则后续写入 eFuse 密钥块将返回错误。
.. _signed-app-verify-v2:
在未启用硬件安全启动时对应用程序进行签名校验
--------------------------------------------
无需启用硬件安全启动选项,即可在 OTA 更新时验证应用程序的安全启动 v2 签名。这种方法采用了与安全启动 v2 相同的应用程序签名方案,但不同于硬件安全启动,软件安全启动无法阻止能够写入 flash 的攻击者绕过签名验证。
如果在启动时无法接受安全启动验证的延迟,和/或威胁模型不包括物理访问或攻击者在 flash 中写入引导加载程序或应用程序分区,则适合使用未启用硬件安全启动的验证。
在此模式下,当前运行的应用程序签名块中的公钥将用于验证新更新的应用程序签名。更新时,不会验证运行中的应用程序签名,而是假定它有效。通过这种方式,系统建立了从当前运行的应用程序到新更新的应用程序之间的信任链。
因此,请务必确保烧录到设备的初始应用程序已签名。应用程序启动时会进行检查,如果没有找到签名,应用程序将中止,并且将无法再进行任何更新。若应用程序在未找到签名时仍继续更新,则可能导致设备损坏,后续任何更新都无法得到应用。应用程序应只包含一个位于第一位置的有效签名块。注意,不同于安全启动 v2系统在启动时不会验证运行中的应用程序的签名只会验证位于第一位置的签名块并忽略其他附加的签名块。
.. only:: not esp32
虽然使用硬件安全启动时支持多个受信任的密钥,但如果配置了无需安全启动的签名检查,则仅使用签名块中的第一个公钥验证更新。如果需要多个受信任的公钥,必须启用完整的安全启动功能。
.. note::
若非确信未启用硬件安全启动的验证已满足应用程序的安全需要,建议使用完整的硬件安全启动。
.. _signed-app-verify-v2-howto:
启用已签名的应用程序验证
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. 打开 :ref:`project-configuration-menu` > ``Security features``
.. only:: esp32
2. 确保 ``App Signing Scheme`` 设置为 ``RSA``。对于 ESP32 芯片版本 v3.0 的芯片,请将 :ref:`CONFIG_ESP32_REV_MIN` 设置为 ``v3.0``,启用 ``RSA`` 选项
.. only:: SOC_SECURE_BOOT_V2_RSA and not SOC_SECURE_BOOT_V2_ECC
2. 确保 ``App Signing Scheme`` 设置为 ``RSA``
.. only:: SOC_SECURE_BOOT_V2_ECC and not SOC_SECURE_BOOT_V2_RSA
1. 确保 ``App Signing Scheme`` 设置为 ``ECDSA (v2)``
.. only:: SOC_SECURE_BOOT_V2_RSA and SOC_SECURE_BOOT_V2_ECC
2. 设置 ``App Signing Scheme````RSA````ECDSA (v2)``
3. 启用 :ref:`CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT`
4. 默认情况下,选择 ``Sign binaries during build`` 选项将启用 ``Require signed app images`` 功能,该功能会在构建过程中自动对二进制文件签名,在 ``Secure Boot private signing key`` 中指定的文件将用于镜像签名。
5. 如果禁用了 ``Sign binaries during build`` 选项,则必须按照 :ref:`remote-sign-v2-image` 中的说明,手动签名所有应用程序二进制文件。
.. warning::
注意,所有烧录的应用程序都必须经过签名,可以在构建过程中签名,也可以在构建后签名。
进阶功能
-----------------
JTAG 调试
~~~~~~~~~~~~~~
启用安全启动模式时eFuse 会默认禁用 JTAG。初次启动时引导加载程序即禁用 JTAG 调试功能,并启用安全启动模式。
有关在启用安全启动或已签名应用程序验证的情况下使用 JTAG 调试的更多信息,请参阅 :ref:`jtag-debugging-security-features`