Merge branch 'docs/translate_host-based-security-workflows' into 'master'

docs: Provide translation for host-based-security-workflows

Closes DOC-6018

See merge request espressif/esp-idf!31459
This commit is contained in:
Aditya Patwardhan 2024-08-09 19:52:40 +08:00
commit efe62d4a7f
7 changed files with 1453 additions and 731 deletions

View File

@ -9,7 +9,7 @@ Overview of Available Resources
Data privacy is achieved by using the :doc:`../../security/flash-encryption` feature. This mechanism is currently used by FATFS and LittleFS and is recommended for new storage type implementations based on the Partitions API.
NVS storage uses a proprietary :doc:`NVS encryption <nvs_encryption>` implementation.
Workflows focused on overall system security are described in the :doc:`Host Based Workflows <../../security/host-based-security-workflows>`.
Workflows focused on overall system security are described in the :doc:`Security Features Enablement Workflows <../../security/security-features-enablement-workflows>`.
Workflows related to the combination of multiple secured storage components in one project are presented in the :example:`Flash Encryption Example <security/flash_encryption>`.
.. list-table:: Relevant storage security examples

View File

@ -1,727 +0,0 @@
..
WARNING: The steps of each section in the document are referenced at multiple places. If you are changing the step number by adding/deleting a step then make sure to update the references respectively.
Host-Based Security Workflows
=============================
{IDF_TARGET_CRYPT_CNT:default="SPI_BOOT_CRYPT_CNT",esp32="FLASH_CRYPT_CNT"}
{IDF_TARGET_CRYPT_CNT_MAX_VAL:default="7",esp32="127"}
{IDF_TARGET_SBV2_DEFAULT_SCHEME:default="RSA", esp32c2="ECDSA (V2)"}
{IDF_TARGET_FLASH_ENC_ARGS:default="--aes_xts", esp32=""}
Introduction
------------
It is recommended to have an uninterrupted power supply while enabling security features on ESP32 SoCs. Power failures during the secure manufacturing process could cause issues that are hard to debug and, in some cases, may cause permanent boot-up failures.
This guide highlights an approach where security features are enabled with the assistance of an external host machine. Security workflows are broken down into various stages and key material is generated on the host machine; thus, allowing greater recovery chances in case of power or other failures. It also offers better timings for secure manufacturing, e.g., in the case of encryption of firmware on the host machine vs. on the device.
Goals
-----
#. Simplify the traditional workflow with stepwise instructions.
#. Design a more flexible workflow as compared to the traditional firmware-based workflow.
#. Improve reliability by dividing the workflow into small operations.
#. Eliminate dependency on :ref:`second-stage-bootloader` (firmware bootloader).
Pre-requisite
-------------
* ``esptool``: Please make sure the ``esptool`` has been installed. It can be installed by running:
.. code:: bash
pip install esptool
Scope
-----
* :ref:`enable-flash-encryption-and-secure-boot-v2-externally`
* :ref:`enable-flash-encryption-externally`
* :ref:`enable-secure-boot-v2-externally`
* :ref:`enable-nvs-encryption-externally`
Security Workflows
------------------
.. _enable-flash-encryption-and-secure-boot-v2-externally:
Enable Flash Encryption and Secure Boot V2 Externally
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. important::
It is recommended to enable both Flash Encryption and Secure Boot V2 for a production use case.
When enabling the Flash Encryption and Secure Boot V2 together we need to enable them in the following order:
#. Enable the Flash Encryption feature by following the steps listed in :ref:`enable-flash-encryption-externally`.
#. Enable the Secure Boot V2 feature by following the steps listed in :ref:`enable-secure-boot-v2-externally`.
The reason for this order is as follows:
.. note::
To enable the Secure Boot (SB) V2, it is necessary to keep the SB V2 key readable. To protect the key's readability, the write protection for ``RD_DIS`` (``ESP_EFUSE_WR_DIS_RD_DIS``) is applied. However, this action poses a challenge when attempting to enable Flash Encryption, as the Flash Encryption (FE) key needs to remain unreadable. This conflict arises because the ``RD_DIS`` is already write-protected, making it impossible to read protect the FE key.
.. _enable-flash-encryption-externally:
Enable Flash Encryption Externally
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In this case, all the eFuses related to Flash Encryption are written with help of the espefuse tool. More details about flash encryption can be found in the :doc:`Flash Encryption Guide </security/flash-encryption>`
1. Check device status
Ensure that you have an {IDF_TARGET_NAME} device with default Flash Encryption eFuse settings as shown in :ref:`flash-encryption-efuse`.
See how to check :ref:`flash-encryption-status`.
At this point, the Flash Encryption must not be already enabled on the chip. Additionally, the flash on the chip needs to be erased, which can be done by running:
.. code:: bash
esptool.py --port PORT erase_flash
2. Generate a Flash Encryption key
A random Flash Encryption key can be generated by running:
.. only:: not SOC_FLASH_ENCRYPTION_XTS_AES
.. code-block:: bash
espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256
If :ref:`Size of generated AES-XTS key <CONFIG_SECURE_FLASH_ENCRYPTION_KEYSIZE>` is AES-128 (256-bit key):
.. code-block:: bash
espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin
else if :ref:`Size of generated AES-XTS key <CONFIG_SECURE_FLASH_ENCRYPTION_KEYSIZE>` is AES-256 (512-bit key):
.. code-block:: bash
espsecure.py generate_flash_encryption_key --keylen 512 my_flash_encryption_key.bin
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
.. code-block:: bash
espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
If :ref:`Size of generated AES-XTS key <CONFIG_SECURE_FLASH_ENCRYPTION_KEYSIZE>` is AES-128 (256-bit key):
.. code-block:: bash
espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin
else if :ref:`Size of generated AES-XTS key <CONFIG_SECURE_FLASH_ENCRYPTION_KEYSIZE>` is AES-128 key derived from 128 bits (SHA256(128 bits)):
.. code-block:: bash
espsecure.py generate_flash_encryption_key --keylen 128 my_flash_encryption_key.bin
3. Burn the Flash Encryption key into eFuse
This action **cannot be reverted**. It can be done by running:
.. only:: not SOC_FLASH_ENCRYPTION_XTS_AES
.. code-block:: bash
espefuse.py --port PORT burn_key flash_encryption my_flash_encryption_key.bin
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK my_flash_encryption_key.bin KEYPURPOSE
where ``BLOCK`` is a free keyblock between ``BLOCK_KEY0`` and ``BLOCK_KEY5``. And ``KEYPURPOSE`` is either ``XTS_AES_256_KEY_1``, ``XTS_AES_256_KEY_2``, ``XTS_AES_128_KEY``. See `{IDF_TARGET_NAME} Technical Reference Manual <{IDF_TARGET_TRM_EN_URL}>`_ for a description of the key purposes.
For AES-128 (256-bit key) - ``XTS_AES_128_KEY``:
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK my_flash_encryption_key.bin XTS_AES_128_KEY
For AES-256 (512-bit key) - ``XTS_AES_256_KEY_1`` and ``XTS_AES_256_KEY_2``. ``espefuse.py`` supports burning both these two key purposes together with a 512-bit key to two separate key blocks via the virtual key purpose ``XTS_AES_256_KEY``. When this is used ``espefuse.py`` will burn the first 256 bits of the key to the specified ``BLOCK`` and burn the corresponding block key purpose to ``XTS_AES_256_KEY_1``. The last 256 bits of the key will be burned to the first free key block after ``BLOCK`` and the corresponding block key purpose to ``XTS_AES_256_KEY_2``
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK my_flash_encryption_key.bin XTS_AES_256_KEY
If you wish to specify exactly which two blocks are used then it is possible to divide the key into two 256-bit keys, and manually burn each half with ``XTS_AES_256_KEY_1`` and ``XTS_AES_256_KEY_2`` as key purposes:
.. code-block:: bash
split -b 32 my_flash_encryption_key.bin my_flash_encryption_key.bin
espefuse.py --port PORT burn_key BLOCK my_flash_encryption_key.bin.aa XTS_AES_256_KEY_1
espefuse.py --port PORT burn_key BLOCK+1 my_flash_encryption_key.bin.ab XTS_AES_256_KEY_2
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK my_flash_encryption_key.bin XTS_AES_128_KEY
where ``BLOCK`` is a free keyblock between ``BLOCK_KEY0`` and ``BLOCK_KEY5``.
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
For AES-128 (256-bit key) - ``XTS_AES_128_KEY`` (the ``XTS_KEY_LENGTH_256`` eFuse will be burn to 1):
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK_KEY0 flash_encryption_key256.bin XTS_AES_128_KEY
For AES-128 key derived from 128 bits (SHA256(128 bits)) - ``XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS``. The FE key will be written in the lower part of eFuse BLOCK_KEY0. The upper 128 bits are not used and will remain available for reading by software. Using the special mode of the espefuse tool, shown in the ``For burning both keys together`` section below, the user can write their data to it using any espefuse commands.
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK_KEY0 flash_encryption_key128.bin XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS
For burning both keys together (Secure Boot and Flash Encryption):
.. code-block:: bash
espefuse.py --port PORT --chip esp32c2 burn_key_digest secure_boot_signing_key.pem \
burn_key BLOCK_KEY0 flash_encryption_key128.bin XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS
.. only:: SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK
.. warning::
For the {IDF_TARGET_NAME} BLOCK9 (BLOCK_KEY5) can not be used by XTS_AES keys.
4. Burn the ``{IDF_TARGET_CRYPT_CNT}`` eFuse
If you only want to enable Flash Encryption in **Development** mode and want to keep the ability to disable it in the future, Update the {IDF_TARGET_CRYPT_CNT} value in the below command from {IDF_TARGET_CRYPT_CNT_MAX_VAL} to 0x1 (not recommended for production).
.. code-block:: bash
espefuse.py --port PORT --chip {IDF_TARGET_PATH_NAME} burn_efuse {IDF_TARGET_CRYPT_CNT} {IDF_TARGET_CRYPT_CNT_MAX_VAL}
.. only:: esp32
In the case of {IDF_TARGET_NAME}, you also need to burn the ``FLASH_CRYPT_CONFIG``. It can be done by running:
.. code-block:: bash
espefuse.py --port PORT --chip {IDF_TARGET_PATH_NAME} burn_efuse FLASH_CRYPT_CONFIG 0xF
5. Burn Flash Encryption-related security eFuses as listed below
A) Burn security eFuses
.. important::
For production use cases, it is highly recommended to burn all the eFuses listed below.
.. list::
:esp32: - ``DISABLE_DL_ENCRYPT``: Disable the UART bootloader encryption access
:esp32: - ``DISABLE_DL_DECRYPT``: Disable the UART bootloader decryption access
:esp32: - ``DISABLE_DL_CACHE``: Disable the UART bootloader flash cache access
:esp32: - ``JTAG_DISABLE``: Disable the JTAG
:SOC_EFUSE_DIS_BOOT_REMAP: - ``DIS_BOOT_REMAP``: Disable capability to Remap ROM to RAM address space
:SOC_EFUSE_DIS_DOWNLOAD_ICACHE: - ``DIS_DOWNLOAD_ICACHE``: Disable UART cache
:SOC_EFUSE_DIS_DOWNLOAD_DCACHE: - ``DIS_DOWNLOAD_DCACHE``: Disable UART cache
:SOC_EFUSE_HARD_DIS_JTAG: - ``HARD_DIS_JTAG``: Hard disable JTAG peripheral
:SOC_EFUSE_DIS_DIRECT_BOOT:- ``DIS_DIRECT_BOOT``: Disable direct boot (legacy SPI boot mode)
:SOC_EFUSE_DIS_LEGACY_SPI_BOOT: - ``DIS_LEGACY_SPI_BOOT``: Disable legacy SPI boot mode
:SOC_EFUSE_DIS_USB_JTAG: - ``DIS_USB_JTAG``: Disable USB switch to JTAG
:SOC_EFUSE_DIS_PAD_JTAG: - ``DIS_PAD_JTAG``: Disable JTAG permanently
:not esp32: - ``DIS_DOWNLOAD_MANUAL_ENCRYPT``: Disable UART bootloader encryption access
:SOC_EFUSE_DIS_DOWNLOAD_MSPI: - ``DIS_DOWNLOAD_MSPI``: Disable the MSPI access in download mode
The respective eFuses can be burned by running:
.. code:: bash
espefuse.py burn_efuse --port PORT EFUSE_NAME 0x1
.. note::
Please update the EFUSE_NAME with the eFuse that you need to burn. Multiple eFuses can be burned at the same time by appending them to the above command (e.g., EFUSE_NAME VAL EFUSE_NAME2 VAL2). More documentation about `espefuse.py` can be found `here <https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/index.html>`_.
.. only:: esp32
B) Write protect security eFuses
After burning the respective eFuses we need to write_protect the security configurations. It can be done by burning following eFuse
.. code:: bash
espefuse.py --port PORT write_protect_efuse DIS_CACHE
.. note::
The write protection of above eFuse also write protects multiple other eFuses, Please refer to the {IDF_TARGET_NAME} eFuse table for more details.
.. only:: SOC_EFUSE_DIS_ICACHE
B) Write protect security eFuses
After burning the respective eFuses we need to write_protect the security configurations. It can be done by burning following eFuse
.. code:: bash
espefuse.py --port PORT write_protect_efuse DIS_ICACHE
.. note::
The write protection of above eFuse also write protects multiple other eFuses, Please refer to the {IDF_TARGET_NAME} eFuse table for more details.
6. Configure the project
The bootloader and the application binaries for the project must be built with Flash Encryption Release mode with default configurations.
Flash encryption Release mode can be set in the menuconfig as follows:
.. list::
- :ref:`Enable Flash Encryption on boot <CONFIG_SECURE_FLASH_ENC_ENABLED>`
:esp32: - :ref:`Select Release mode <CONFIG_SECURE_FLASH_ENCRYPTION_MODE>` (Note that once Release mode is selected, the ``DISABLE_DL_ENCRYPT`` and ``DISABLE_DL_DECRYPT`` eFuse bits will be burned to disable Flash Encryption hardware in ROM Download Mode)
:esp32: - :ref:`Select UART ROM download mode (Permanently disabled (recommended)) <CONFIG_SECURE_UART_ROM_DL_MODE>` (Note that this option is only available when :ref:`CONFIG_ESP32_REV_MIN` is set to 3 (ESP32 V3).) The default choice is to keep UART ROM download mode enabled, however it is recommended to permanently disable this mode to reduce the options available to an attacker
:not esp32: - :ref:`Select Release mode <CONFIG_SECURE_FLASH_ENCRYPTION_MODE>` (Note that once Release mode is selected, the ``EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT`` eFuse bit will be burned to disable Flash Encryption hardware in ROM Download Mode)
:not esp32: - :ref:`Select UART ROM download mode (Permanently switch to Secure mode (recommended)) <CONFIG_SECURE_UART_ROM_DL_MODE>`. This is the default option and is recommended. It is also possible to change this configuration setting to permanently disable UART ROM download mode, if this mode is not needed
- :ref:`Select the appropriate bootloader log verbosity <CONFIG_BOOTLOADER_LOG_LEVEL>`
- Save the configuration and exit
7. Build, Encrypt and Flash the binaries
The binaries can be encrypted on the host machine by running:
.. code-block:: bash
espsecure.py encrypt_flash_data {IDF_TARGET_FLASH_ENC_ARGS} --keyfile my_flash_encryption_key.bin --address {IDF_TARGET_CONFIG_BOOTLOADER_OFFSET_IN_FLASH} --output bootloader-enc.bin build/bootloader/bootloader.bin
espsecure.py encrypt_flash_data {IDF_TARGET_FLASH_ENC_ARGS} --keyfile my_flash_encryption_key.bin --address 0x8000 --output partition-table-enc.bin build/partition_table/partition-table.bin
espsecure.py encrypt_flash_data {IDF_TARGET_FLASH_ENC_ARGS} --keyfile my_flash_encryption_key.bin --address 0x10000 --output my-app-enc.bin build/my-app.bin
In the above command the offsets are used for a sample firmware, the actual offset for your firmware can be obtained by checking the partition table entry or by running `idf.py partition-table`. Please note that not all the binaries need to be encrypted, the encryption applies only to those generated from the partitions which are marked as ``encrypted`` in the partition table definition file. Other binaries are flashed unencrypted, i.e., as a plain output of the build process.
The above files can then be flashed to their respective offset using ``esptool.py``. To see all of the command line options recommended for ``esptool.py``, see the output printed when ``idf.py build`` succeeds.
When the application contains the following partition: ``otadata``, ``nvs_encryption_keys`` they need to be encrypted as well. Please refer to :ref:`encrypted-partitions` for more details about encrypted partitions.
.. note::
If the flashed ciphertext file is not recognized by the {IDF_TARGET_NAME} when it boots, check that the keys match and that the command line arguments match exactly, including the correct offset. It is important to provide the correct offset as the ciphertext changes when the offset changes.
.. only:: esp32
If your ESP32 uses non-default :ref:`FLASH_CRYPT_CONFIG value in eFuse <setting-flash-crypt-config>` then you will need to pass the ``--flash_crypt_conf`` argument to ``espsecure.py`` to set the matching value. This will not happen when the Flash Encryption is enabled by the firmware bootloader but may happen when burning eFuses manually to enable flash encryption.
The command ``espsecure.py decrypt_flash_data`` can be used with the same options (and different input/output files), to decrypt ciphertext flash contents or a previously encrypted file.
8. Secure the ROM Download mode
.. warning::
Please perform the following step at the very end. After this eFuse is burned, the espefuse tool can no longer be used to burn additional eFuses.
.. only: esp32
Disable UART ROM DL mode:
.. list::
- ``UART_DOWNLOAD_DIS`` : Disable the UART ROM Download mode
The eFuse can be burned by running:
.. code:: bash
espefuse.py --port PORT burn_efuse UART_DOWNLOAD_DIS
.. only:: not esp32
Enable Security Download mode:
.. list::
- ``ENABLE_SECURITY_DOWNLOAD``: Enable Secure ROM download mode
The eFuse can be burned by running:
.. code:: bash
espefuse.py --port PORT burn_efuse ENABLE_SECURITY_DOWNLOAD
.. important::
9. Delete Flash Encryption key on host
Once the Flash Encryption has been enabled for the device, the key **must be deleted immediately**. This ensures that the host cannot produce encrypted binaries for the same device going forward. This step is important to reduce the vulnerability of the flash encryption key.
Flash Encryption Guidelines
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* It is recommended to generate a unique Flash Encryption key for each device for production use-cases.
* It is recommended to ensure that the RNG used by host machine to generate the Flash Encryption key has good entropy.
* See :ref:`flash-encryption-limitations` for more details.
.. _enable-secure-boot-v2-externally:
Enable Secure Boot V2 Externally
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In this workflow, we shall use ``espsecure`` tool to generate signing keys and use the ``espefuse`` tool to burn the relevant eFuses. The details about the Secure Boot V2 process can be found at :doc:`Secure Boot V2 Guide </security/secure-boot-v2>`
1. Generate Secure Boot V2 Signing Private Key
.. only:: esp32 or SOC_SECURE_BOOT_V2_RSA
The Secure Boot V2 signing key for the RSA3072 scheme can be generated by running:
.. code:: bash
espsecure.py generate_signing_key --version 2 --scheme rsa3072 secure_boot_signing_key.pem
.. only:: SOC_SECURE_BOOT_V2_ECC
The Secure Boot V2 signing key for ECDSA scheme can be generated by running:
.. code:: bash
espsecure.py generate_signing_key --version 2 --scheme ecdsa256 secure_boot_signing_key.pem
The scheme in the above command can be changed to ``ecdsa192`` to generate ecdsa192 private key.
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
A total of 3 keys can be used for Secure Boot V2 at once. These should be computed independently and stored separately. The same command with different key file names can be used to generate multiple Secure Boot V2 signing keys. It is recommended to use multiple keys in order to reduce dependency on a single key.
2. Generate Public Key Digest
The public key digest for the private key generated in the previous step can be generated by running:
.. code:: bash
espsecure.py digest_sbv2_public_key --keyfile secure_boot_signing_key.pem --output digest.bin
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
In case of multiple digests, each digest should be kept in a separate file.
3. Burn the key digest in eFuse
The public key digest can be burned in the eFuse by running:
.. only:: esp32
.. code:: bash
espefuse.py --port PORT --chip esp32 burn_key secure_boot_v2 digest.bin
.. only:: esp32c2
.. code:: bash
espefuse.py --port PORT --chip esp32c2 burn_key KEY_BLOCK0 digest.bin SECURE_BOOT_DIGEST
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
.. code:: bash
espefuse.py --port PORT --chip {IDF_TARGET_PATH_NAME} burn_key BLOCK digest.bin SECURE_BOOT_DIGEST0
where ``BLOCK`` is a free keyblock between ``BLOCK_KEY0`` and ``BLOCK_KEY5``.
In case of multiple digests, the other digests can be burned sequentially by changing the key purpose to ``SECURE_BOOT_DIGEST1`` and ``SECURE_BOOT_DIGEST2`` respectively.
4. Enable Secure Boot V2
Secure Boot V2 eFuse can be enabled by running:
.. only:: esp32
.. code:: bash
espefuse.py --port PORT --chip esp32 burn_efuse ABS_DONE_1
.. only:: not esp32
.. code:: bash
espefuse.py --port PORT --chip {IDF_TARGET_PATH_NAME} burn_efuse SECURE_BOOT_EN
5. Burn relevant eFuses
A) Burn security eFuses
.. important::
For production use cases, it is highly recommended to burn all the eFuses listed below.
.. list::
:esp32: - ``JTAG_DISABLE``: Disable the JTAG
:SOC_EFUSE_DIS_BOOT_REMAP: - ``DIS_BOOT_REMAP``: Disable capability to Remap ROM to RAM address space
:SOC_EFUSE_HARD_DIS_JTAG: - ``HARD_DIS_JTAG``: Hard disable JTAG peripheral
:SOC_EFUSE_SOFT_DIS_JTAG: - ``SOFT_DIS_JTAG``: Disable software access to JTAG peripheral
:SOC_EFUSE_DIS_DIRECT_BOOT:- ``DIS_DIRECT_BOOT``: Disable direct boot (legacy SPI boot mode)
:SOC_EFUSE_DIS_LEGACY_SPI_BOOT: - ``DIS_LEGACY_SPI_BOOT``: Disable legacy SPI boot mode
:SOC_EFUSE_DIS_USB_JTAG: - ``DIS_USB_JTAG``: Disable USB switch to JTAG
:SOC_EFUSE_DIS_PAD_JTAG: - ``DIS_PAD_JTAG``: Disable JTAG permanently
:SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS: - ``SECURE_BOOT_AGGRESSIVE_REVOKE``: Aggressive revocation of key digests, see :ref:`secure-boot-v2-aggressive-key-revocation` for more details.
The respective eFuses can be burned by running:
.. code:: bash
espefuse.py burn_efuse --port PORT EFUSE_NAME 0x1
.. note::
Please update the EFUSE_NAME with the eFuse that you need to burn. Multiple eFuses can be burned at the same time by appending them to the above command (e.g., EFUSE_NAME VAL EFUSE_NAME2 VAL2). More documentation about `espefuse.py` can be found `here <https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/index.html>`_
B) Secure Boot V2-related eFuses
i) Disable the read-protection option:
The Secure Boot digest burned in the eFuse must be kept readable otherwise the Secure Boot operation would result in a failure. To prevent the accidental enabling of read protection for this key block, the following eFuse needs to be burned:
.. important::
After burning above-mentioned eFuse, the read protection cannot be enabled for any key. E.g., if Flash Encryption which requires read protection for its key is not enabled at this point, then it cannot be enabled afterwards. Please ensure that no eFuse keys are going to need read protection after completing this step.
.. code:: bash
espefuse.py -p $ESPPORT write_protect_efuse RD_DIS
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
ii) Revoke key digests:
The unused digest slots need to be revoked when we are burning the Secure Boot key. The respective slots can be revoked by running
.. code:: bash
espefuse.py --port PORT --chip {IDF_TARGET_PATH_NAME} burn_efuse EFUSE_REVOKE_BIT
The ``EFUSE_REVOKE_BIT`` in the above command can be ``SECURE_BOOT_KEY_REVOKE0`` or ``SECURE_BOOT_KEY_REVOKE1`` or ``SECURE_BOOT_KEY_REVOKE2``. Please note that only the unused key digests must be revoked. Once revoked, the respective digest cannot be used again.
6. Configure the project
By default, the ROM bootloader would only verify the :ref:`second-stage-bootloader` (firmware bootloader). The firmware bootloader would verify the app partition only when the :ref:`CONFIG_SECURE_BOOT` option is enabled (and :ref:`CONFIG_SECURE_BOOT_VERSION` is set to ``SECURE_BOOT_V2_ENABLED``) while building the bootloader.
a) Open the :ref:`project-configuration-menu`, in "Security features" set "Enable hardware Secure Boot in bootloader" to enable Secure Boot.
.. only:: esp32
For ESP32, Secure Boot V2 is available only for ESP32 ECO3 onwards. To view the "Secure Boot V2" option the chip revision should be changed to revision v3.0 (ECO3). To change the chip revision, set "Minimum Supported ESP32 Revision" to "Rev 3.0 (ECO3)" in "Component Config" -> "Hardware Settings" -> "Chip Revision".
.. only:: SOC_SECURE_BOOT_V2_RSA or SOC_SECURE_BOOT_V2_ECC
The "Secure Boot V2" option will be selected and the "App Signing Scheme" will be set to {IDF_TARGET_SBV2_DEFAULT_SCHEME} by default.
b) Disable the option :ref:`CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES` for the project in the :ref:`project-configuration-menu`. This shall make sure that all the generated binaries are secure padded and unsigned. This step is done to avoid generating signed binaries as we are going to manually sign the binaries using ``espsecure`` tool.
7. Build, Sign and Flash the binaries
After the above configurations, the bootloader and application binaries can be built with ``idf.py build`` command.
The Secure Boot V2 workflow only verifies the ``bootloader`` and ``application`` binaries, hence only those binaries need to be signed. The other binaries (e.g., ``partition-table.bin``) can be flashed as they are generated in the build stage.
The ``bootloader.bin`` and ``app.bin`` binaries can be signed by running:
.. code:: bash
espsecure.py sign_data --version 2 --keyfile secure_boot_signing_key.pem --output bootloader-signed.bin build/bootloader/bootloader.bin
espsecure.py sign_data --version 2 --keyfile secure_boot_signing_key.pem --output my-app-signed.bin build/my-app.bin
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
If multiple keys Secure Boot keys are to be used then the same signed binary can be appended with a signature block signed with the new key as follows:
.. code:: bash
espsecure.py sign_data --keyfile secure_boot_signing_key2.pem --version 2 --append_signatures -o bootloader-signed2.bin bootloader-signed.bin
espsecure.py sign_data --keyfile secure_boot_signing_key2.pem --version 2 --append_signatures -o my-app-signed2.bin my-app-signed.bin
The same process can be repeated for the third key. Note that the names of the input and output files must not be the same.
The signatures attached to a binary can be checked by running:
.. code:: bash
espsecure.py signature_info_v2 bootloader-signed.bin
The above files along with other binaries (e.g., partition table) can then be flashed to their respective offset using ``esptool.py``. To see all of the command line options recommended for ``esptool.py``, see the output printed when ``idf.py build`` succeeds. The flash offset for your firmware can be obtained by checking the partition table entry or by running ``idf.py partition-table``.
8. Secure the ROM Download mode:
.. warning::
Please perform the following step at the very end. After this eFuse is burned, the espefuse tool can no longer be used to burn additional eFuses.
.. only: esp32
Disable UART ROM DL mode:
.. list::
- ``UART_DOWNLOAD_DIS`` : Disable the UART ROM Download mode
The eFuse can be burned by running:
.. code:: bash
espefuse.py --port PORT burn_efuse UART_DOWNLOAD_DIS
.. only:: not esp32
Enable Security Download mode:
.. list::
- ``ENABLE_SECURITY_DOWNLOAD``: Enable Secure ROM download mode
The eFuse can be burned by running:
.. code:: bash
espefuse.py --port PORT burn_efuse ENABLE_SECURITY_DOWNLOAD
Secure Boot V2 Guidelines
~~~~~~~~~~~~~~~~~~~~~~~~~
* It is recommended to store the Secure Boot key in a highly secure place. A physical or a cloud HSM may be used for secure storage of the Secure Boot private key. Please take a look at :ref:`remote-sign-v2-image` for more details.
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
* It is recommended to use all the available digest slots to reduce dependency on a single private key.
.. _enable-nvs-encryption-externally:
Enable NVS Encryption Externally
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The details about NVS Encryption and related schemes can be found at :doc:`NVS Encryption </api-reference/storage/nvs_encryption>`.
.. only:: SOC_HMAC_SUPPORTED
.. _enable-nvs-encryption-based-on-hmac:
Enable NVS Encryption based on HMAC
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Generate the HMAC key and NVS Encryption key
In the HMAC based NVS scheme, there are two keys:
* HMAC key - this is a 256 bit HMAC key that shall be stored in the eFuse
* NVS Encryption key - This is the NVS Encryption key that is used to encrypt the NVS partition. This key is derived at run-time using the HMAC key.
The above keys can be generated with the :component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py` script with help of the following command:
.. code:: bash
python3 nvs_partition_gen.py generate-key --key_protect_hmac --kp_hmac_keygen --kp_hmac_keyfile hmac_key.bin --keyfile nvs_encr_key.bin
This shall generate the respective keys in the ``keys`` folder.
2. Burn the HMAC key in the eFuse
The NVS key can be burned in the eFuse of {IDF_TARGET_NAME} with help of following command:
.. code:: bash
espefuse.py --port PORT burn_key BLOCK hmac_key.bin HMAC_UP
where ``BLOCK`` is a free keyblock between ``BLOCK_KEY0`` and ``BLOCK_KEY5``.
3. Generate the encrypted NVS partition
We shall generate the actual encrypted NVS partition on host. More details about generating the encryption NVS partition can be found at :ref:`generate-encrypted-nvs-partition`.
For this purpose, the contents of the NVS file shall be available in a CSV file. Please check out :ref:`nvs-csv-file-format` for more details.
The encrypted NVS partition can be generated with following command:
.. code:: bash
python3 nvs_partition_gen.py encrypt sample_singlepage_blob.csv nvs_encr_partition.bin 0x3000 --inputkey keys/nvs_encr_key.bin
Some command arguments are explained below:
* CSV file name - In this case `sample_singlepage_blob.csv` is the CSV file which contains the NVS data, Replace this with the file you wish to choose.
* NVS partition offset - This is the offset at which that NVS partition shall be stored in the flash of {IDF_TARGET_NAME}. The offset of your nvs-partition can be found be executing `idf.py partition-table` in the projtect directory. Please update the sample value of `0x3000` in the above-provided command to the correct offset.
4. Configure the project
* Enable `NVS Encryption` by enabling :ref:`CONFIG_NVS_ENCRYPTION`.
* Enable the HMAC based NVS Encryption by setting :ref:`CONFIG_NVS_SEC_KEY_PROTECTION_SCHEME` to ``CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC``
* Set the HMAC efuse key id at :ref:`CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID` to the one in which the eFuse key was burned in Step 2.
5. Flash NVS partition
The NVS partition (``nvs_encr_partition.bin``) generated in Step 3 can then be flashed to its respective offset using ``esptool.py``. To see all of the command line options recommended for ``esptool.py``, check the output printed when ``idf.py build`` succeeds.
If Flash encryption is enabled for the chip then please encrypt the partition first before flashing. You may refer the flashing related steps of `Flash Encryption workflow <enable-flash-encryption-externally_>`_.
.. _enable-flash-enc-based-nvs-encryption:
Enable NVS Encryption based on Flash Encryption
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In this case we generate NVS Encryption keys on a host. This key is then flashed on the chip and protected with help of the :doc:`Flash Encryption </security/flash-encryption>` feature.
1. Generate the NVS Encryption key
For generation of respective keys, we shall use :doc:`NVS partition generator utility </api-reference/storage/nvs_partition_gen>`. We shall generate the encryption key on host and this key key shall be stored on the flash of {IDF_TARGET_NAME} in encrypted state.
The key can be generated with the :component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py` script with help of the following command:
.. code:: bash
python3 nvs_partition_gen.py generate-key --keyfile nvs_encr_key.bin
This shall generate the respective key in the ``keys`` folder.
2. Generate the encrypted NVS partition
We shall generate the actual encrypted NVS partition on host. More details about generating the encryption NVS partition can be found at :ref:`generate-encrypted-nvs-partition`.
For this, the contents of the NVS file shall be available in a CSV file. Please refer :ref:`nvs-csv-file-format` for more details.
The encrypted NVS partition can be generated with following command:
.. code:: bash
python3 nvs_partition_gen.py encrypt sample_singlepage_blob.csv nvs_encr_partition.bin 0x3000 --inputkey keys/nvs_encr_key.bin
Some command arguments are explained below:
* CSV file name - In this case `sample_singlepage_blob.csv` is the CSV file which contains the NVS data, Replace this with the file you wish to choose.
* NVS partition offset - This is the offset at which that NVS partition shall be stored in the flash of {IDF_TARGET_NAME}. The offset of your nvs-partition can be found be executing `idf.py partition-table` in the projtect directory. Please update the sample value of `0x3000` in the above-provided command to the correct offset.
3. Configure the project
* Enable `NVS Encryption` by enabling :ref:`CONFIG_NVS_ENCRYPTION`.
* Set NVS to use Flash Encryption based scheme by setting :ref:`CONFIG_NVS_SEC_KEY_PROTECTION_SCHEME` to ``CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC``.
4. Flash NVS partition and NVS Encryption keys
The NVS partition (``nvs_encr_partition.bin``) and NVS Encryption key (``nvs_encr_key.bin``) can then be flashed to their respective offset using ``esptool.py``. To see all of the command line options recommended for ``esptool.py``, check the output printed when ``idf.py build`` succeeds.
If Flash encryption is enabled for the chip then please encrypt the partition first before flashing. You may refer the flashing related steps of `Flash Encryption workflow <enable-flash-encryption-externally_>`_.

View File

@ -24,7 +24,7 @@ Workflows
.. toctree::
:maxdepth: 1
host-based-security-workflows
security-features-enablement-workflows
Vulnerabilities
---------------

View File

@ -0,0 +1,725 @@
..
WARNING: The steps of each section in the document are referenced at multiple places. If you are changing the step number by adding/deleting a step then make sure to update the references respectively.
Security Features Enablement Workflows
======================================
:link_to_translation:`zh_CN:[中文]`
{IDF_TARGET_CRYPT_CNT:default="SPI_BOOT_CRYPT_CNT",esp32="FLASH_CRYPT_CNT"}
{IDF_TARGET_CRYPT_CNT_MAX_VAL:default="7",esp32="127"}
{IDF_TARGET_SBV2_DEFAULT_SCHEME:default="RSA", esp32c2="ECDSA (V2)"}
{IDF_TARGET_FLASH_ENC_ARGS:default="--aes_xts", esp32=""}
Introduction
------------
When enabling security features on ESP32 SoCs, it is recommended that power supply be uninterrupted. Power failures during this process could cause issues that are hard to debug and, in some cases, may cause permanent boot-up failures.
This guide describes a set of workflows to enable security features on the device with the assistance of an external host machine. These workflows are broken down into various stages, with each stage generating signing/encryption keys on the host machine. This allows for greater chances of recovery in case of power or other failures. Furthermore, these workflows expedites the overall provisioning process via the use of the host machine (e.g., encrypting firmware on the host is quicker than on the device).
Goals
-----
#. Simplify the traditional workflow for enabling security features with stepwise instructions.
#. Design a more flexible workflow when compared to the traditional firmware-based workflow.
#. Improve reliability by dividing the workflow into small operations.
#. Eliminate dependency on :ref:`second-stage-bootloader` (firmware bootloader).
Prerequisites
-------------
* ``esptool``: Please make sure the ``esptool`` has been installed. It can be installed by running:
.. code:: bash
pip install esptool
Scope
-----
* :ref:`enable-flash-encryption-and-secure-boot-v2-externally`
* :ref:`enable-flash-encryption-externally`
* :ref:`enable-secure-boot-v2-externally`
* :ref:`enable-nvs-encryption-externally`
Security Features Enablement
----------------------------
.. _enable-flash-encryption-and-secure-boot-v2-externally:
Enable Flash Encryption and Secure Boot v2 Externally
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. important::
It is recommended to enable both Flash Encryption and Secure Boot v2 for a production use case.
When enabling the Flash Encryption and Secure Boot v2 together, they need to enable them in the following order:
#. Enable the Flash Encryption feature by following the steps listed in :ref:`enable-flash-encryption-externally`.
#. Enable the Secure Boot v2 feature by following the steps listed in :ref:`enable-secure-boot-v2-externally`.
The reason this particular ordering is that when enabling Secure Boot (SB) v2, it is necessary to keep the SB v2 key readable. To protect the key's readability, the write protection for ``RD_DIS`` (``ESP_EFUSE_WR_DIS_RD_DIS``) is applied. However, this action poses a challenge when attempting to enable Flash Encryption, as the Flash Encryption (FE) key needs to remain unreadable. This conflict arises because the ``RD_DIS`` is already write-protected, making it impossible to read protect the FE key.
.. _enable-flash-encryption-externally:
Enable Flash Encryption Externally
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In this case all the eFuses related to Flash Encryption are written with help of the espefuse tool. More details about Flash Encryption can process can be found in :doc:`/security/flash-encryption`.
1. Ensure that you have an {IDF_TARGET_NAME} device with default Flash Encryption eFuse settings as shown in :ref:`flash-encryption-efuse`
See how to check :ref:`flash-encryption-status`.
At this point, the Flash Encryption must not be already enabled on the chip. Additionally, the flash on the chip needs to be erased, which can be done by running:
.. code:: bash
esptool.py --port PORT erase_flash
2. Generate a Flash Encryption key
A random Flash Encryption key can be generated by running:
.. only:: not SOC_FLASH_ENCRYPTION_XTS_AES
.. code-block:: bash
espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256
If :ref:`Size of generated AES-XTS key <CONFIG_SECURE_FLASH_ENCRYPTION_KEYSIZE>` is AES-128 (256-bit key):
.. code-block:: bash
espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin
else if :ref:`Size of generated AES-XTS key <CONFIG_SECURE_FLASH_ENCRYPTION_KEYSIZE>` is AES-256 (512-bit key):
.. code-block:: bash
espsecure.py generate_flash_encryption_key --keylen 512 my_flash_encryption_key.bin
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
.. code-block:: bash
espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
If :ref:`Size of generated AES-XTS key <CONFIG_SECURE_FLASH_ENCRYPTION_KEYSIZE>` is AES-128 (256-bit key):
.. code-block:: bash
espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin
else if :ref:`Size of generated AES-XTS key <CONFIG_SECURE_FLASH_ENCRYPTION_KEYSIZE>` is AES-128 key derived from 128 bits (SHA256(128 bits)):
.. code-block:: bash
espsecure.py generate_flash_encryption_key --keylen 128 my_flash_encryption_key.bin
3. Burn the Flash Encryption key into eFuse
.. warning::
This action **cannot be reverted**.
It can be done by running:
.. only:: not SOC_FLASH_ENCRYPTION_XTS_AES
.. code-block:: bash
espefuse.py --port PORT burn_key flash_encryption my_flash_encryption_key.bin
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK my_flash_encryption_key.bin KEYPURPOSE
where ``BLOCK`` is a free keyblock between ``BLOCK_KEY0`` and ``BLOCK_KEY5``. And ``KEYPURPOSE`` is either ``XTS_AES_256_KEY_1``, ``XTS_AES_256_KEY_2``, ``XTS_AES_128_KEY``. See `{IDF_TARGET_NAME} Technical Reference Manual <{IDF_TARGET_TRM_EN_URL}>`_ for a description of the key purposes.
For AES-128 (256-bit key) - ``XTS_AES_128_KEY``:
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK my_flash_encryption_key.bin XTS_AES_128_KEY
For AES-256 (512-bit key) - ``XTS_AES_256_KEY_1`` and ``XTS_AES_256_KEY_2``. ``espefuse.py`` supports burning both these two key purposes together with a 512-bit key to two separate key blocks via the virtual key purpose ``XTS_AES_256_KEY``. When this is used ``espefuse.py`` will burn the first 256 bits of the key to the specified ``BLOCK`` and burn the corresponding block key purpose to ``XTS_AES_256_KEY_1``. The last 256 bits of the key will be burned to the first free key block after ``BLOCK`` and the corresponding block key purpose to ``XTS_AES_256_KEY_2``
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK my_flash_encryption_key.bin XTS_AES_256_KEY
If you wish to specify exactly which two blocks are used then it is possible to divide the key into two 256-bit keys, and manually burn each half with ``XTS_AES_256_KEY_1`` and ``XTS_AES_256_KEY_2`` as key purposes:
.. code-block:: bash
split -b 32 my_flash_encryption_key.bin my_flash_encryption_key.bin
espefuse.py --port PORT burn_key BLOCK my_flash_encryption_key.bin.aa XTS_AES_256_KEY_1
espefuse.py --port PORT burn_key BLOCK+1 my_flash_encryption_key.bin.ab XTS_AES_256_KEY_2
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK my_flash_encryption_key.bin XTS_AES_128_KEY
where ``BLOCK`` is a free keyblock between ``BLOCK_KEY0`` and ``BLOCK_KEY5``.
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
For AES-128 (256-bit key) - ``XTS_AES_128_KEY`` (the ``XTS_KEY_LENGTH_256`` eFuse will be burn to 1):
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK_KEY0 flash_encryption_key256.bin XTS_AES_128_KEY
For AES-128 key derived from SHA256(128 eFuse bits) - ``XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS``. The FE key will be written in the lower part of eFuse BLOCK_KEY0. The upper 128 bits are not used and will remain available for reading by software. Using the special mode of the espefuse tool, shown in the ``For burning both keys together`` section below, the user can write their data to it using any espefuse commands.
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK_KEY0 flash_encryption_key128.bin XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS
For burning both keys together (Secure Boot and Flash Encryption):
.. code-block:: bash
espefuse.py --port PORT --chip esp32c2 burn_key_digest secure_boot_signing_key.pem \
burn_key BLOCK_KEY0 flash_encryption_key128.bin XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS
.. only:: SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK
.. warning::
For the {IDF_TARGET_NAME} BLOCK9 (BLOCK_KEY5) can not be used by XTS_AES keys.
4. Burn the ``{IDF_TARGET_CRYPT_CNT}`` eFuse
If you only want to enable Flash Encryption in **Development** mode and want to keep the ability to disable it in the future, Update the {IDF_TARGET_CRYPT_CNT} value in the below command from {IDF_TARGET_CRYPT_CNT_MAX_VAL} to 0x1 (not recommended for production).
.. code-block:: bash
espefuse.py --port PORT --chip {IDF_TARGET_PATH_NAME} burn_efuse {IDF_TARGET_CRYPT_CNT} {IDF_TARGET_CRYPT_CNT_MAX_VAL}
.. only:: esp32
In the case of {IDF_TARGET_NAME}, you also need to burn the ``FLASH_CRYPT_CONFIG``. It can be done by running:
.. code-block:: bash
espefuse.py --port PORT --chip {IDF_TARGET_PATH_NAME} burn_efuse FLASH_CRYPT_CONFIG 0xF
5. Burn Flash Encryption-related security eFuses as listed below
A) Burn security eFuses
.. important::
For production use cases, it is highly recommended to burn all the eFuses listed below.
.. list::
:esp32: - ``DISABLE_DL_ENCRYPT``: Disable the UART bootloader encryption access
:esp32: - ``DISABLE_DL_DECRYPT``: Disable the UART bootloader decryption access
:esp32: - ``DISABLE_DL_CACHE``: Disable the UART bootloader flash cache access
:esp32: - ``JTAG_DISABLE``: Disable the JTAG
:SOC_EFUSE_DIS_BOOT_REMAP: - ``DIS_BOOT_REMAP``: Disable capability to Remap ROM to RAM address space
:SOC_EFUSE_DIS_DOWNLOAD_ICACHE: - ``DIS_DOWNLOAD_ICACHE``: Disable UART cache
:SOC_EFUSE_DIS_DOWNLOAD_DCACHE: - ``DIS_DOWNLOAD_DCACHE``: Disable UART cache
:SOC_EFUSE_HARD_DIS_JTAG: - ``HARD_DIS_JTAG``: Hard disable JTAG peripheral
:SOC_EFUSE_DIS_DIRECT_BOOT:- ``DIS_DIRECT_BOOT``: Disable direct boot (legacy SPI boot mode)
:SOC_EFUSE_DIS_LEGACY_SPI_BOOT: - ``DIS_LEGACY_SPI_BOOT``: Disable legacy SPI boot mode
:SOC_EFUSE_DIS_USB_JTAG: - ``DIS_USB_JTAG``: Disable USB switch to JTAG
:SOC_EFUSE_DIS_PAD_JTAG: - ``DIS_PAD_JTAG``: Disable JTAG permanently
:not esp32: - ``DIS_DOWNLOAD_MANUAL_ENCRYPT``: Disable UART bootloader encryption access
:SOC_EFUSE_DIS_DOWNLOAD_MSPI: - ``DIS_DOWNLOAD_MSPI``: Disable the MSPI access in download mode
The respective eFuses can be burned by running:
.. code:: bash
espefuse.py burn_efuse --port PORT EFUSE_NAME 0x1
.. note::
Please update the ``EFUSE_NAME`` with the eFuse that you need to burn. Multiple eFuses can be burned at the same time by appending them to the above command (e.g., ``EFUSE_NAME VAL EFUSE_NAME2 VAL2``). More documentation about `espefuse.py` can be found `here <https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/index.html>`_.
.. only:: esp32
B) Write protect security eFuses
After burning the respective eFuses we need to write_protect the security configurations. It can be done by burning following eFuse:
.. code:: bash
espefuse.py --port PORT write_protect_efuse DIS_CACHE
.. note::
The write protection of above eFuse also write protects multiple other eFuses. Please refer to the {IDF_TARGET_NAME} eFuse table for more details.
.. only:: SOC_EFUSE_DIS_ICACHE
B) Write protect security eFuses
After burning the respective eFuses we need to write_protect the security configurations. It can be done by burning following eFuse
.. code:: bash
espefuse.py --port PORT write_protect_efuse DIS_ICACHE
.. note::
The write protection of above eFuse also write protects multiple other eFuses, Please refer to the {IDF_TARGET_NAME} eFuse table for more details.
6. Configure the project
The bootloader and the application binaries for the project must be built with Flash Encryption release mode with default configurations.
Flash Encryption release mode can be set in the menuconfig as follows:
.. list::
- :ref:`Enable Flash Encryption on boot <CONFIG_SECURE_FLASH_ENC_ENABLED>`.
:esp32: - :ref:`Select release mode <CONFIG_SECURE_FLASH_ENCRYPTION_MODE>` (Note that once release mode is selected, the ``DISABLE_DL_ENCRYPT`` and ``DISABLE_DL_DECRYPT`` eFuse bits will be burned to disable Flash Encryption hardware in ROM download mode).
:esp32: - :ref:`Select UART ROM download mode (permanently disabled (recommended)) <CONFIG_SECURE_UART_ROM_DL_MODE>` (Note that this option is only available when :ref:`CONFIG_ESP32_REV_MIN` is set to 3 (ESP32 V3)). The default choice is to keep UART ROM download mode enabled, however it is recommended to permanently disable this mode to reduce the options available to an attacker.
:not esp32: - :ref:`Select release mode <CONFIG_SECURE_FLASH_ENCRYPTION_MODE>` (Note that once release mode is selected, the ``EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT`` eFuse bit will be burned to disable Flash Encryption hardware in ROM download mode).
:not esp32: - :ref:`Select UART ROM download mode (permanently switch to Secure mode (recommended)) <CONFIG_SECURE_UART_ROM_DL_MODE>`. This is the default option, and is recommended. It is also possible to change this configuration setting to permanently disable UART ROM download mode, if this mode is not needed.
- :ref:`Select the appropriate bootloader log verbosity <CONFIG_BOOTLOADER_LOG_LEVEL>`.
- Save the configuration and exit.
7. Build, Encrypt and Flash the binaries
The binaries can be encrypted on the host machine by running:
.. code-block:: bash
espsecure.py encrypt_flash_data {IDF_TARGET_FLASH_ENC_ARGS} --keyfile my_flash_encryption_key.bin --address {IDF_TARGET_CONFIG_BOOTLOADER_OFFSET_IN_FLASH} --output bootloader-enc.bin build/bootloader/bootloader.bin
espsecure.py encrypt_flash_data {IDF_TARGET_FLASH_ENC_ARGS} --keyfile my_flash_encryption_key.bin --address 0x8000 --output partition-table-enc.bin build/partition_table/partition-table.bin
espsecure.py encrypt_flash_data {IDF_TARGET_FLASH_ENC_ARGS} --keyfile my_flash_encryption_key.bin --address 0x10000 --output my-app-enc.bin build/my-app.bin
In the above command, the offsets are used for a sample firmware, and the actual offset for your firmware can be obtained by checking the partition table entry or by running `idf.py partition-table`. Please note that not all the binaries need to be encrypted, the encryption applies only to those generated from the partitions which are marked as ``encrypted`` in the partition table definition file. Other binaries are flashed unencrypted, i.e., as a plain output of the build process.
The above files can then be flashed to their respective offset using ``esptool.py``. To see all of the command line options recommended for ``esptool.py``, see the output printed when ``idf.py build`` succeeds.
When the application contains the following partition: ``otadata`` and ``nvs_encryption_keys``, they need to be encrypted as well. Please refer to :ref:`encrypted-partitions` for more details about encrypted partitions.
.. note::
If the flashed ciphertext file is not recognized by the {IDF_TARGET_NAME} when it boots, check that the keys match and that the command line arguments match exactly, including the correct offset. It is important to provide the correct offset as the ciphertext changes when the offset changes.
.. only:: esp32
If your ESP32 uses non-default :ref:`FLASH_CRYPT_CONFIG value in eFuse <setting-flash-crypt-config>` then you will need to pass the ``--flash_crypt_conf`` argument to ``espsecure.py`` to set the matching value. This will not happen when the Flash Encryption is enabled by the firmware bootloader but may happen when burning eFuses manually to enable Flash Encryption.
The command ``espsecure.py decrypt_flash_data`` can be used with the same options (and different input or output files), to decrypt ciphertext flash contents or a previously encrypted file.
8. Secure the ROM download mode
.. warning::
Please perform the following step at the very end. After this eFuse is burned, the espefuse tool can no longer be used to burn additional eFuses.
.. only:: esp32
Disable UART ROM DL mode:
.. list::
- ``UART_DOWNLOAD_DIS`` : Disable the UART ROM download mode
The eFuse can be burned by running:
.. code:: bash
espefuse.py --port PORT burn_efuse UART_DOWNLOAD_DIS
.. only:: not esp32
Enable security download mode:
.. list::
- ``ENABLE_SECURITY_DOWNLOAD``: Enable secure ROM download mode
The eFuse can be burned by running:
.. code:: bash
espefuse.py --port PORT burn_efuse ENABLE_SECURITY_DOWNLOAD
.. important::
9. Delete Flash Encryption key on host
Once the Flash Encryption has been enabled for the device, the key **must be deleted immediately**. This ensures that the host can't produce encrypted binaries for the same device going forward. This step is important to reduce the vulnerability of the Flash Encryption key.
Flash Encryption Guidelines
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* It is recommended to generate a unique Flash Encryption key for each device for production use-cases.
* It is recommended to ensure that the RNG used by host machine to generate the Flash Encryption key has good entropy.
* See :ref:`flash-encryption-limitations` for more details.
.. _enable-secure-boot-v2-externally:
Enable Secure Boot v2 Externally
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In this workflow we shall use ``espsecure`` tool to generate signing keys and use the ``espefuse`` tool to burn the relevant eFuses. The details about the Secure Boot v2 process can be found at :doc:`/security/secure-boot-v2`.
1. Generate Secure Boot v2 Signing Private Key
.. only:: esp32 or SOC_SECURE_BOOT_V2_RSA
The Secure Boot v2 signing key for the RSA3072 scheme can be generated by running:
.. code:: bash
espsecure.py generate_signing_key --version 2 --scheme rsa3072 secure_boot_signing_key.pem
.. only:: SOC_SECURE_BOOT_V2_ECC
The Secure Boot v2 signing key for ECDSA scheme can be generated by running:
.. code:: bash
espsecure.py generate_signing_key --version 2 --scheme ecdsa256 secure_boot_signing_key.pem
The scheme in the above command can be changed to ``ecdsa192`` to generate ecdsa192 private key.
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
A total of 3 keys can be used for Secure Boot v2 at once. These should be computed independently and stored separately. The same command with different key file names can be used to generate multiple Secure Boot v2 signing keys. It is recommended to use multiple keys in order to reduce dependency on a single key.
2. Generate Public Key Digest
The public key digest for the private key generated in the previous step can be generated by running:
.. code:: bash
espsecure.py digest_sbv2_public_key --keyfile secure_boot_signing_key.pem --output digest.bin
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
In case of multiple digests, each digest should be kept in a separate file.
3. Burn the key digest in eFuse
The public key digest can be burned in the eFuse by running:
.. only:: esp32
.. code:: bash
espefuse.py --port PORT --chip esp32 burn_key secure_boot_v2 digest.bin
.. only:: esp32c2
.. code:: bash
espefuse.py --port PORT --chip esp32c2 burn_key KEY_BLOCK0 digest.bin SECURE_BOOT_DIGEST
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
.. code:: bash
espefuse.py --port PORT --chip {IDF_TARGET_PATH_NAME} burn_key BLOCK digest.bin SECURE_BOOT_DIGEST0
where ``BLOCK`` is a free keyblock between ``BLOCK_KEY0`` and ``BLOCK_KEY5``.
In case of multiple digests, the other digests can be burned sequentially by changing the key purpose to ``SECURE_BOOT_DIGEST1`` and ``SECURE_BOOT_DIGEST2`` respectively.
4. Enable Secure Boot v2
Secure Boot v2 eFuse can be enabled by running:
.. only:: esp32
.. code:: bash
espefuse.py --port PORT --chip esp32 burn_efuse ABS_DONE_1
.. only:: not esp32
.. code:: bash
espefuse.py --port PORT --chip {IDF_TARGET_PATH_NAME} burn_efuse SECURE_BOOT_EN
5. Burn relevant eFuses
A) Burn security eFuses
.. important::
For production use cases, it is highly recommended to burn all the eFuses listed below.
.. list::
:esp32: - ``JTAG_DISABLE``: Disable the JTAG.
:SOC_EFUSE_DIS_BOOT_REMAP: - ``DIS_BOOT_REMAP``: Disable capability to remap ROM to RAM address space.
:SOC_EFUSE_HARD_DIS_JTAG: - ``HARD_DIS_JTAG``: Hard disable JTAG peripheral.
:SOC_EFUSE_SOFT_DIS_JTAG: - ``SOFT_DIS_JTAG``: Disable software access to JTAG peripheral.
:SOC_EFUSE_DIS_DIRECT_BOOT:- ``DIS_DIRECT_BOOT``: Disable direct boot (legacy SPI boot mode).
:SOC_EFUSE_DIS_LEGACY_SPI_BOOT: - ``DIS_LEGACY_SPI_BOOT``: Disable legacy SPI boot mode.
:SOC_EFUSE_DIS_USB_JTAG: - ``DIS_USB_JTAG``: Disable USB switch to JTAG.
:SOC_EFUSE_DIS_PAD_JTAG: - ``DIS_PAD_JTAG``: Disable JTAG permanently.
:SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS: - ``SECURE_BOOT_AGGRESSIVE_REVOKE``: Aggressive revocation of key digests, see :ref:`secure-boot-v2-aggressive-key-revocation` for more details.
The respective eFuses can be burned by running:
.. code:: bash
espefuse.py burn_efuse --port PORT EFUSE_NAME 0x1
.. note::
Please update the EFUSE_NAME with the eFuse that you need to burn. Multiple eFuses can be burned at the same time by appending them to the above command (e.g., EFUSE_NAME VAL EFUSE_NAME2 VAL2). More documentation about `espefuse.py` can be found `here <https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/index.html>`_
B) Secure Boot v2-related eFuses
i) Disable the read-protection option:
The Secure Boot digest burned in the eFuse must be kept readable otherwise the Secure Boot operation would result in a failure. To prevent the accidental enabling of read protection for this key block, the following eFuse needs to be burned:
.. code:: bash
espefuse.py -p $ESPPORT write_protect_efuse RD_DIS
.. important::
After burning above-mentioned eFuse, the read protection can't be enabled for any key. For example, if Flash Encryption which requires read protection for its key is not enabled at this point, then it can't be enabled afterwards. Please ensure that no eFuse keys are going to need read protection after completing this step.
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
ii) Revoke key digests:
The unused digest slots need to be revoked when we are burning the Secure Boot key. The respective slots can be revoked by running
.. code:: bash
espefuse.py --port PORT --chip {IDF_TARGET_PATH_NAME} burn_efuse EFUSE_REVOKE_BIT
The ``EFUSE_REVOKE_BIT`` in the above command can be ``SECURE_BOOT_KEY_REVOKE0`` or ``SECURE_BOOT_KEY_REVOKE1`` or ``SECURE_BOOT_KEY_REVOKE2``. Please note that only the unused key digests must be revoked. Once revoked, the respective digest cannot be used again.
6. Configure the project
By default, the ROM bootloader would only verify the :ref:`second-stage-bootloader` (firmware bootloader). The firmware bootloader would verify the app partition only when the :ref:`CONFIG_SECURE_BOOT` option is enabled (and :ref:`CONFIG_SECURE_BOOT_VERSION` is set to ``SECURE_BOOT_V2_ENABLED``) while building the bootloader.
A) Open the :ref:`project-configuration-menu`, in ``Security features`` set ``Enable hardware Secure Boot in bootloader`` to enable Secure Boot.
.. only:: esp32
For ESP32, Secure Boot v2 is available only for ESP32 ECO3 onwards. To view the ``Secure Boot v2`` option the chip revision should be changed to revision v3.0 (ECO3). To change the chip revision, set ``Minimum Supported ESP32 Revision`` to ``Rev 3.0 (ECO3)`` in ``Component Config -> Hardware Settings -> Chip Revision``.
.. only:: SOC_SECURE_BOOT_V2_RSA or SOC_SECURE_BOOT_V2_ECC
The ``Secure Boot v2`` option will be selected and the ``App Signing Scheme`` will be set to {IDF_TARGET_SBV2_DEFAULT_SCHEME} by default.
B) Disable the option :ref:`CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES` for the project in the :ref:`project-configuration-menu`. This shall make sure that all the generated binaries are secure padded and unsigned. This step is done to avoid generating signed binaries as we are going to manually sign the binaries using ``espsecure`` tool.
7. Build, Sign and Flash the binaries
After the above configurations, the bootloader and application binaries can be built with ``idf.py build`` command.
The Secure Boot v2 workflow only verifies the ``bootloader`` and ``application`` binaries, hence only those binaries need to be signed. The other binaries (e.g., ``partition-table.bin``) can be flashed as they are generated in the build stage.
The ``bootloader.bin`` and ``app.bin`` binaries can be signed by running:
.. code:: bash
espsecure.py sign_data --version 2 --keyfile secure_boot_signing_key.pem --output bootloader-signed.bin build/bootloader/bootloader.bin
espsecure.py sign_data --version 2 --keyfile secure_boot_signing_key.pem --output my-app-signed.bin build/my-app.bin
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
If multiple keys Secure Boot keys are to be used then the same signed binary can be appended with a signature block signed with the new key as follows:
.. code:: bash
espsecure.py sign_data --keyfile secure_boot_signing_key2.pem --version 2 --append_signatures -o bootloader-signed2.bin bootloader-signed.bin
espsecure.py sign_data --keyfile secure_boot_signing_key2.pem --version 2 --append_signatures -o my-app-signed2.bin my-app-signed.bin
The same process can be repeated for the third key. Note that the names of the input and output files must not be the same.
The signatures attached to a binary can be checked by running:
.. code:: bash
espsecure.py signature_info_v2 bootloader-signed.bin
The above files along with other binaries (e.g., partition table) can then be flashed to their respective offset using ``esptool.py``. To see all of the command line options recommended for ``esptool.py``, see the output printed when ``idf.py build`` succeeds. The flash offset for your firmware can be obtained by checking the partition table entry or by running ``idf.py partition-table``.
8. Secure the ROM download mode
.. warning::
Please perform the following step at the very end. After this eFuse is burned, the espefuse tool can no longer be used to burn additional eFuses.
.. only:: esp32
Disable UART ROM DL mode:
.. list::
- ``UART_DOWNLOAD_DIS`` : Disable the UART ROM download mode
The eFuse can be burned by running:
.. code:: bash
espefuse.py --port PORT burn_efuse UART_DOWNLOAD_DIS
.. only:: not esp32
Enable security download mode:
.. list::
- ``ENABLE_SECURITY_DOWNLOAD``: Enable secure ROM download mode
The eFuse can be burned by running:
.. code:: bash
espefuse.py --port PORT burn_efuse ENABLE_SECURITY_DOWNLOAD
Secure Boot v2 Guidelines
~~~~~~~~~~~~~~~~~~~~~~~~~
* It is recommended to store the Secure Boot key in a highly secure place. A physical or a cloud HSM may be used for secure storage of the Secure Boot private key. Please take a look at :ref:`remote-sign-v2-image` for more details.
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
* It is recommended to use all the available digest slots to reduce dependency on a single private key.
.. _enable-nvs-encryption-externally:
Enable NVS Encryption Externally
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The details about NVS encryption and related schemes can be found at :doc:`NVS Encryption </api-reference/storage/nvs_encryption>`.
.. only:: SOC_HMAC_SUPPORTED
.. _enable-nvs-encryption-based-on-hmac:
Enable NVS Encryption Based on HMAC
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Generate the HMAC key and NVS encryption key
In the HMAC based NVS scheme, there are two keys:
* HMAC key - this is a 256-bit HMAC key that shall be stored in the eFuse.
* NVS Encryption key - This is the NVS encryption key that is used to encrypt the NVS partition. This key is derived at run-time using the HMAC key.
The above keys can be generated with the :component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py` script with help of the following command:
.. code:: bash
python3 nvs_partition_gen.py generate-key --key_protect_hmac --kp_hmac_keygen --kp_hmac_keyfile hmac_key.bin --keyfile nvs_encr_key.bin
This shall generate the respective keys in the ``keys`` folder.
2. Burn the HMAC key in the eFuse
The NVS key can be burned in the eFuse of {IDF_TARGET_NAME} with help of following command:
.. code:: bash
espefuse.py --port PORT burn_key BLOCK hmac_key.bin HMAC_UP
Here, ``BLOCK`` is a free keyblock between ``BLOCK_KEY0`` and ``BLOCK_KEY5``.
3. Generate the encrypted NVS partition
We shall generate the actual encrypted NVS partition on the host. More details about generating the encryption NVS partition can be found at :ref:`generate-encrypted-nvs-partition`.For this purpose, the contents of the NVS file shall be available in a CSV file. Please check out :ref:`nvs-csv-file-format` for more details.
The encrypted NVS partition can be generated with following command:
.. code:: bash
python3 nvs_partition_gen.py encrypt sample_singlepage_blob.csv nvs_encr_partition.bin 0x3000 --inputkey keys/nvs_encr_key.bin
Some command arguments are explained below:
* CSV file name - In this case, ``sample_singlepage_blob.csv`` is the CSV file which contains the NVS data. Please replace this with the file you wish to choose.
* NVS partition offset - This is the offset at which that NVS partition shall be stored in the flash of {IDF_TARGET_NAME}. The offset of your NVS partition can be found by executing ``idf.py partition-table`` in the projtect directory. Please update the sample value of ``0x3000`` in the above-provided command to the correct offset.
4. Configure the project
* Enable `NVS Encryption` by enabling :ref:`CONFIG_NVS_ENCRYPTION`.
* Enable the HMAC based NVS encryption by setting :ref:`CONFIG_NVS_SEC_KEY_PROTECTION_SCHEME` to ``CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC``.
* Set the HMAC efuse key ID at :ref:`CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID` to the one in which the eFuse key was burned in Step 2.
5. Flash NVS partition
The NVS partition (``nvs_encr_partition.bin``) generated in Step 3 can then be flashed to its respective offset using ``esptool.py``. To see all of the command line options recommended for ``esptool.py``, check the output printed when ``idf.py build`` succeeds.
If Flash Encryption is enabled for the chip, please encrypt the partition first before flashing. More details please refer to the flashing related steps of `Flash Encryption workflow <enable-flash-encryption-externally_>`_.
.. _enable-flash-enc-based-nvs-encryption:
Enable NVS Encryption Based on Flash Encryption
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In this case we generate NVS Encryption keys on a host. This key is then flashed on the chip and protected with the help of :doc:`Flash Encryption </security/flash-encryption>` features.
1. Generate the NVS encryption key
For generation of respective keys, we shall use :doc:`NVS partition generator utility </api-reference/storage/nvs_partition_gen>`. We shall generate the encryption key on host and this key shall be stored on the flash of {IDF_TARGET_NAME} in encrypted state.
The key can be generated with the :component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py` script with the help of the following command:
.. code:: bash
python3 nvs_partition_gen.py generate-key --keyfile nvs_encr_key.bin
This shall generate the respective key in the ``keys`` folder.
2. Generate the encrypted NVS partition
We shall generate the actual encrypted NVS partition on host. More details about generating the encrypted NVS partition can be found at :ref:`generate-encrypted-nvs-partition`.For this, the contents of the NVS file shall be available in a CSV file. Please refer to :ref:`nvs-csv-file-format` for more details.
The encrypted NVS partition can be generated with following command:
.. code:: bash
python3 nvs_partition_gen.py encrypt sample_singlepage_blob.csv nvs_encr_partition.bin 0x3000 --inputkey keys/nvs_encr_key.bin
Some command arguments are explained below:
* CSV file name - In this case `sample_singlepage_blob.csv` is the CSV file which contains the NVS data. Please replace it with the file you wish to choose.
* NVS partition offset - This is the offset at which the NVS partition shall be stored in the flash of {IDF_TARGET_NAME}. The offset of your NVS partition can be found by executing ``idf.py partition-table`` in the projtect directory. Please update the sample value of ``0x3000`` in the above-provided command to the correct offset.
3. Configure the project
* Enable `NVS Encryption` by enabling :ref:`CONFIG_NVS_ENCRYPTION`.
* Set NVS to use Flash Encryption based scheme by setting :ref:`CONFIG_NVS_SEC_KEY_PROTECTION_SCHEME` to ``CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC``.
4. Flash NVS partition and NVS encryption keys
The NVS partition (``nvs_encr_partition.bin``) and NVS encryption key (``nvs_encr_key.bin``) can then be flashed to their respective offset using ``esptool.py``. To see all of the command line options recommended for ``esptool.py``, check the output print when ``idf.py build`` succeeds.
If Flash Encryption is enabled for the chip, then please encrypt the partition first before flashing. You may refer the flashing related steps of `Flash Encryption workflow <enable-flash-encryption-externally_>`_.

View File

@ -1 +0,0 @@
.. include:: ../../en/security/host-based-security-workflows.rst

View File

@ -24,7 +24,7 @@
.. toctree::
:maxdepth: 1
host-based-security-workflows
security-features-enablement-workflows
漏洞
---------

View File

@ -0,0 +1,725 @@
..
WARNING: The steps of each section in the document are referenced at multiple places. If you are changing the step number by adding/deleting a step then make sure to update the references respectively.
启用安全功能的工作流程
======================
:link_to_translation:`en:[English]`
{IDF_TARGET_CRYPT_CNT:default="SPI_BOOT_CRYPT_CNT",esp32="FLASH_CRYPT_CNT"}
{IDF_TARGET_CRYPT_CNT_MAX_VAL:default="7",esp32="127"}
{IDF_TARGET_SBV2_DEFAULT_SCHEME:default="RSA", esp32c2="ECDSA (V2)"}
{IDF_TARGET_FLASH_ENC_ARGS:default="--aes_xts", esp32=""}
概述
----
启用 ESP32 SoC 的安全功能时,建议保证不间断的电源供应。在此过程中,如果发生电力故障,可能会引起难以调试的问题,甚至在某些情况下可能导致永久性启动故障。
这份指南介绍了一系列工作流程,从而在外部主机的协助下启用设备的安全功能。这些工作流程分为多个阶段,每个阶段都会在主机上生成签名/加密密钥,从而在发生电力或其他故障时,提高恢复几率。此外,在主机的协助下,这些流程将加快整体配置过程(例如,在主机上加密固件要比在设备上加密更快)。
目标
----
#. 用逐步指令简化启用安全功能的传统工作流程。
#. 设计比基于固件的传统工作流更加灵活的工作流。
#. 将工作流划分为多个小操作,从而提高可靠性。
#. 消除对 :ref:`second-stage-bootloader` (固件引导加载程序)的依赖。
准备工作
--------
* ``esptool``:确保已安装 ``esptool``。可运行以下命令安装:
.. code:: bash
pip install esptool
目录
----
* :ref:`enable-flash-encryption-and-secure-boot-v2-externally`
* :ref:`enable-flash-encryption-externally`
* :ref:`enable-secure-boot-v2-externally`
* :ref:`enable-nvs-encryption-externally`
启用安全功能
------------
.. _enable-flash-encryption-and-secure-boot-v2-externally:
外部启用 flash 加密和 Secure Boot v2
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. important::
建议在生产用例中同时启用 flash 加密和 Secure Boot v2。
外部启用 flash 加密和 Secure Boot v2 时,须遵循以下启用顺序:
#. 按照 :ref:`enable-flash-encryption-externally` 中列出的步骤启用 flash 加密功能。
#. 按照 :ref:`enable-secure-boot-v2-externally` 中列出的步骤启用 Secure Boot v2 功能。
须严格遵循以上顺序,因为启用 Secure Boot (SB) v2 时,要确保 SB v2 密钥可读。通过启用 ``RD_DIS`` (``ESP_EFUSE_WR_DIS_RD_DIS``) 的写保护,确保了密钥的可读性。但是,这也为启用 flash 加密带来了困难,因为 flash 加密 (FE) 密钥须保持不可读状态。产生这种冲突的原因是 ``RD_DIS`` 已受到写保护,因此无法对 FE 密钥进行读保护。
.. _enable-flash-encryption-externally:
外部启用 flash 加密
^^^^^^^^^^^^^^^^^^^
在这种情况下,所有与 flash 加密相关的 eFuse 都是借助 espefuse 工具写入的。关于 flash 加密过程的详细信息,请参阅 :doc:`/security/flash-encryption`
1. 确保有一块 {IDF_TARGET_NAME},其默认 flash 加密 eFuse 设置如 :ref:`flash-encryption-efuse` 所示
参考 :ref:`flash-encryption-status`,查看 flash 加密状态。
此时需要擦除芯片上的 flash且 flash 加密必须尚未启用。请运行以下命令进行擦除:
.. code:: bash
esptool.py --port PORT erase_flash
2. 生成一个 flash 加密密钥
运行以下命令可以生成一个随机的 flash 加密密钥:
.. only:: not SOC_FLASH_ENCRYPTION_XTS_AES
.. code-block:: bash
espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256
如果 :ref:`生成的 AES-XTS 密钥大小 <CONFIG_SECURE_FLASH_ENCRYPTION_KEYSIZE>` 为 AES-128256 位密钥):
.. code-block:: bash
espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin
如果 :ref:`生成的 AES-XTS 密钥的大小 <CONFIG_SECURE_FLASH_ENCRYPTION_KEYSIZE>` 为 AES-256512 位密钥):
.. code-block:: bash
espsecure.py generate_flash_encryption_key --keylen 512 my_flash_encryption_key.bin
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
.. code-block:: bash
espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
如果 :ref:` 生成的 AES-XTS 密钥的大小 <CONFIG_SECURE_FLASH_ENCRYPTION_KEYSIZE>` 为 AES-128256 位密钥):
.. code-block:: bash
espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin
如果 :ref:`生成的 AES-XTS 密钥的大小 <CONFIG_SECURE_FLASH_ENCRYPTION_KEYSIZE>` 是从 128 位SHA256128 位))派生的 AES-128 密钥:
.. code-block:: bash
espsecure.py generate_flash_encryption_key --keylen 128 my_flash_encryption_key.bin
3. 将 flash 加密密钥烧录到 eFuse 中
.. warning::
这个操作 **无法回退**
运行以下命令进行烧录:
.. only:: not SOC_FLASH_ENCRYPTION_XTS_AES
.. code-block:: bash
espefuse.py --port PORT burn_key flash_encryption my_flash_encryption_key.bin
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_256
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK my_flash_encryption_key.bin KEYPURPOSE
其中, ``BLOCK`` 是位于 ``BLOCK_KEY0````BLOCK_KEY5`` 之间的空闲密钥块, ``KEYPURPOSE````XTS_AES_256_KEY_1`` ``XTS_AES_256_KEY_2````XTS_AES_128_KEY``。有关密钥用途的说明,请参阅 `{IDF_TARGET_NAME} 技术参考手册 <{IDF_TARGET_TRM_EN_URL}>`__。
对于 AES-128256 位密钥)- ``XTS_AES_128_KEY``
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK my_flash_encryption_key.bin XTS_AES_128_KEY
对于 AES-256512 位密钥)- ``XTS_AES_256_KEY_1````XTS_AES_256_KEY_2````espefuse.py`` 支持通过虚拟密钥用途 ``XTS_AES_256_KEY`` 将这两个密钥用途和一个 512 位密钥一起烧录到两个单独的密钥块中。使用时, ``espefuse.py`` 会把密钥的前 256 位烧录到指定的 ``BLOCK``,并把相应块的密钥用途烧录为 ``XTS_AES_256_KEY_1``。密钥的后 256 位会被烧录到 ``BLOCK`` 后的第一个空闲密钥块,相应块的密钥用途会烧录为 ``XTS_AES_256_KEY_2``
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK my_flash_encryption_key.bin XTS_AES_256_KEY
如果要指定使用两个块,那么可以将密钥分成两个 256 位密钥并手动烧录,以 ``XTS_AES_256_KEY_1````XTS_AES_256_KEY_2`` 作为密钥用途:
.. code-block:: bash
split -b 32 my_flash_encryption_key.bin my_flash_encryption_key.bin
espefuse.py --port PORT burn_key BLOCK my_flash_encryption_key.bin.aa XTS_AES_256_KEY_1
espefuse.py --port PORT burn_key BLOCK+1 my_flash_encryption_key.bin.ab XTS_AES_256_KEY_2
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and not SOC_FLASH_ENCRYPTION_XTS_AES_256 and not SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK my_flash_encryption_key.bin XTS_AES_128_KEY
其中, ``BLOCK````BLOCK_KEY0````BLOCK_KEY5`` 之间的空闲密钥块。
.. only:: SOC_FLASH_ENCRYPTION_XTS_AES_128 and SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK
对于 AES-128 (256 位密钥) - ``XTS_AES_128_KEY`` (``XTS_KEY_LENGTH_256`` eFuse 会被烧录为 1)
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK_KEY0 flash_encryption_key256.bin XTS_AES_128_KEY
对于从 SHA256128 eFuse 位)派生的 AES-128 密钥 - ``XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS``。FE 密钥会被写入 eFuse BLOCK_KEY0 的后半部分。前 128 位不会被使用,并保持可供软件读取状态。使用 espefuse 工具的特殊模式,可以用任何 espefuse 命令将数据写入其中,可参考下文 ``同时烧录两个密钥``
.. code-block:: bash
espefuse.py --port PORT burn_key BLOCK_KEY0 flash_encryption_key128.bin XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS
同时烧录两个密钥Secure Boot 和 flash 加密):
.. code-block:: bash
espefuse.py --port PORT --chip esp32c2 burn_key_digest secure_boot_signing_key.pem \
burn_key BLOCK_KEY0 flash_encryption_key128.bin XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS
.. only:: SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK
.. warning::
对于 {IDF_TARGET_NAME}XTS_AES 密钥不能使用 BLOCK9 (BLOCK_KEY5)。
4. 烧录 ``{IDF_TARGET_CRYPT_CNT}`` eFuse
如果你只想在 **开发** 模式下启用 flash 加密,并在将来可能会禁用 flash 加密,可将下面命令中的 {IDF_TARGET_CRYPT_CNT} 值从 {IDF_TARGET_CRYPT_CNT_MAX_VAL} 更新为 0x1。不推荐在生产中使用
.. code-block:: bash
espefuse.py --port PORT --chip {IDF_TARGET_PATH_NAME} burn_efuse {IDF_TARGET_CRYPT_CNT} {IDF_TARGET_CRYPT_CNT_MAX_VAL}
.. only:: esp32
在使用 {IDF_TARGET_NAME} 时,还要烧录 ``FLASH_CRYPT_CONFIG``。通过运行以下命令进行烧录:
.. code-block:: bash
espefuse.py --port PORT --chip {IDF_TARGET_PATH_NAME} burn_efuse FLASH_CRYPT_CONFIG 0xF
5. 烧录下列与 flash 加密相关的安全 eFuse
A) 烧录安全 eFuse
.. important::
对于生产用例,强烈建议烧录下列所有的 eFuse。
.. list::
:esp32: - ``DISABLE_DL_ENCRYPT``:禁用 UART 引导加载程序加密访问。
:esp32: - ``DISABLE_DL_DECRYPT``:禁用 UART 引导加载程序解密访问。
:esp32: - ``DISABLE_DL_CACHE``:禁用 UART 引导加载程序 flash cache 访问
:esp32: - ``JTAG_DISABLE``:禁用 JTAG
:SOC_EFUSE_DIS_BOOT_REMAP: - ``DIS_BOOT_REMAP``:禁用将 ROM 映射到 RAM 地址空间的功能
:SOC_EFUSE_DIS_DOWNLOAD_ICACHE: - ``DIS_DOWNLOAD_ICACHE``:禁用 UART cache
:SOC_EFUSE_DIS_DOWNLOAD_DCACHE: - ``DIS_DOWNLOAD_DCACHE``:禁用 UART cache
:SOC_EFUSE_HARD_DIS_JTAG: - ``HARD_DIS_JTAG``:硬禁用 JTAG 外设
:SOC_EFUSE_DIS_DIRECT_BOOT: - ``DIS_DIRECT_BOOT``:禁用直接引导(旧版 SPI 引导模式)
:SOC_EFUSE_DIS_LEGACY_SPI_BOOT: - ``DIS_LEGACY_SPI_BOOT``:禁用旧版 SPI 引导模式
:SOC_EFUSE_DIS_USB_JTAG: - ``DIS_USB_JTAG``:禁止从 USB 切换到 JTAG
:SOC_EFUSE_DIS_PAD_JTAG: - ``DIS_PAD_JTAG``:永久禁用 JTAG
:not esp32: - ``DIS_DOWNLOAD_MANUAL_ENCRYPT``:禁用 UART 引导加载程序加密访问
:SOC_EFUSE_DIS_DOWNLOAD_MSPI: - ``DIS_DOWNLOAD_MSPI``:禁用下载模式下的 MSPI 访问
可运行以下命令烧录相应的 eFuse
.. code:: bash
espefuse.py burn_efuse --port PORT EFUSE_NAME 0x1
.. note::
请将 ``EFUSE_NAME`` 更新为需要烧录的 eFuse。可以在上述命令中添加多个 efuse 同时进行烧录(例如:``EFUSE_NAME VAL EFUSE_NAME2 VAL2``)。有关 `espefuse.py` 的更多信息,请参阅 `此文档 <https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/index.html>`__。
.. only:: esp32
B) 对安全 eFuse 采用写保护
在烧录相应 eFuse 后,需要对安全配置进行 write_protect。请烧录下列 eFuse
.. code:: bash
espefuse.py --port PORT write_protect_efuse DIS_CACHE
.. note::
以上 eFuse 的写保护还对其他多个 eFuse 起效。详情请参阅 {IDF_TARGET_NAME} eFuse 表。
.. only:: SOC_EFUSE_DIS_ICACHE
B) 对安全 eFuse 采用写保护
在烧录相应 eFuse 后,需要对安全配置进行 write_protect。请烧录下列 eFuse
.. code:: bash
espefuse.py --port PORT write_protect_efuse DIS_ICACHE
.. note::
以上 eFuse 的写保护还对其他多个 eFuse 起效。详情请参阅 {IDF_TARGET_NAME} eFuse 表。
6. 配置项目
项目的引导加载程序和应用程序二进制文件必须使用默认配置的 flash 加密发布模式进行构建。
如下所示,可以在 menuconfig 中设置 flash 加密发布模式:
.. list::
- :ref:`启动时启用 flash 加密 <CONFIG_SECURE_FLASH_ENC_ENABLED>`
:esp32: - :ref:`选择发布模式 <CONFIG_SECURE_FLASH_ENCRYPTION_MODE>` (注意,若选择发布模式,则将烧录 ``DISABLE_DL_ENCRYPT`` 和 ``DISABLE_DL_DECRYPT`` eFuse 位ROM 下载模式下 flash 加密硬件将被禁用)。
:esp32: - :ref:`选择 UART ROM 下载模式(永久禁用(推荐))<CONFIG_SECURE_UART_ROM_DL_MODE>` (注意,此选项仅在 :ref:`CONFIG_ESP32_REV_MIN` 设为 3 (ESP32 V3) 时可用。UART ROM 下载模式在默认设置中自动启用,但建议永久禁用此模式以减少攻击者可用的选项。
:not esp32: - :ref:`选择发布模式 <CONFIG_SECURE_FLASH_ENCRYPTION_MODE>` (注意,若选择发布模式,则将烧录 ``EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT`` eFuse 位ROM 下载模式下 flash 加密硬件将被禁用)。
:not esp32: - :ref:`选择 UART ROM 下载模式(永久切换到安全模式(推荐))<CONFIG_SECURE_UART_ROM_DL_MODE>`。这是推荐的默认选项,如果不需要,也可将其更改为永久禁用 UART ROM 下载模式。
- :ref:`选择适当的引导程序日志级别 <CONFIG_BOOTLOADER_LOG_LEVEL>`
- 保存配置并退出。
7. 构建、加密并烧录二进制文件
可以在主机上运行下列命令来加密二进制文件:
.. code-block:: bash
espsecure.py encrypt_flash_data {IDF_TARGET_FLASH_ENC_ARGS} --keyfile my_flash_encryption_key.bin --address {IDF_TARGET_CONFIG_BOOTLOADER_OFFSET_IN_FLASH} --output bootloader-enc.bin build/bootloader/bootloader.bin
espsecure.py encrypt_flash_data {IDF_TARGET_FLASH_ENC_ARGS} --keyfile my_flash_encryption_key.bin --address 0x8000 --output partition-table-enc.bin build/partition_table/partition-table.bin
espsecure.py encrypt_flash_data {IDF_TARGET_FLASH_ENC_ARGS} --keyfile my_flash_encryption_key.bin --address 0x10000 --output my-app-enc.bin build/my-app.bin
上述命令中的偏移量仅适用于示例固件,请通过检查分区表条目或运行 `idf.py partition-table` 来获取你固件的实际偏移量。请注意,不需要加密所有二进制文件,只需加密在分区表定义文件中带有 ``encrypted`` 标记的文件,其他二进制文件只作为构建过程的普通输出进行烧录。
使用 ``esptool.py`` 可以将上述文件烧写到各自的偏移地址。要查看所有推荐的 ``esptool.py`` 命令行选项,请查阅 ``idf.py build`` 构建成功后打印的输出。
若应用程序包含分区 ``otadata````nvs_encryption_keys``,则该分区也需加密。详情请参阅 :ref:`encrypted-partitions`
.. note::
如果 {IDF_TARGET_NAME} 启动时无法识别烧录的密文,请检查密钥是否匹配、命令行参数是否精确匹配及偏移量的正确性。偏移量必须正确,因为当偏移量改变时,密文也会改变。
.. only:: esp32
如果 ESP32 在 eFuse 中使用非默认的 :ref:`FLASH_CRYPT_CONFIG 值 <setting-flash-crypt-config>`,需要将 ``--flash_crypt_conf`` 参数传递给 ``espsecure.py`` 以设置匹配值。如果设备自行配置 flash 加密,则不会发生这种情况,但是如果手动烧录了 eFuses 启用 flash 加密,就有可能发生。
使用 ``espsecure.py decrypt_flash_data`` 命令时,可以用相同的选项(和不同的输入或输出文件)来解密密文 flash 或之前加密的文件。
8. 确保 ROM 下载模式安全
.. warning::
请在最后烧录以下位。烧录后espefuse 工具将无法再用于烧录其他 eFuse。
.. only:: esp32
禁用 UART ROM DL 模式:
.. list::
- ``UART_DOWNLOAD_DIS``:禁用 UART ROM 下载模式
运行以下指令,烧录 eFuse
.. code:: bash
espefuse.py --port PORT burn_efuse UART_DOWNLOAD_DIS
.. only:: not esp32
启用安全下载模式:
.. list::
- ``ENABLE_SECURITY_DOWNLOAD``:启用安全 ROM 下载模式
运行以下指令,烧录 eFuse
.. code:: bash
espefuse.py --port PORT burn_efuse ENABLE_SECURITY_DOWNLOAD
.. important::
9. 从主机上删除 flash 加密密钥
一旦为设备启用了 flash 加密,密钥 **必须立即删除**。这能确保主机以后不为同一设备生成加密二进制文件,从而减少 flash 加密密钥漏洞。
flash 加密指南
~~~~~~~~~~~~~~
* 建议为每个设备生成唯一的 flash 加密密钥用于生产用例。
* 确保主机用于生成 flash 加密密钥的 RNG 具有良好的熵。
* 更多详细信息请参阅 :ref:`flash-encryption-limitations`
.. _enable-secure-boot-v2-externally:
外部启用 Secure Boot v2
^^^^^^^^^^^^^^^^^^^^^^^
在此工作流中,我们会使用 ``espsecure`` 工具生成签名密钥,并使用 ``espefuse`` 工具烧录相关 eFuse。关于 Secure Boot v2 流程的详细信息,请参阅 :doc:`/security/secure-boot-v2`
1. 生成 Secure Boot v2 签名私钥
.. only:: esp32 or SOC_SECURE_BOOT_V2_RSA
运行以下命令可以生成 RSA3072 方案的 Secure Boot v2 签名密钥:
.. code:: bash
espsecure.py generate_signing_key --version 2 --scheme rsa3072 secure_boot_signinig_key.pem
.. only:: SOC_SECURE_BOOT_V2_ECC
运行以下命令可以生成 ECDSA 方案的 Secure Boot v2 签名密钥:
.. code:: bash
bashespsecure.py generate_signing_key --version 2 --scheme ecdsa256 secure_boot_signing_key.pem
将上述命令中的方案更改为 ``ecdsa192``,可生成 ecdsa192 私钥。
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
每次可以在 Secure Boot v2 中使用 3 个密钥。这些密钥应独立计算,分开存储。同一个命令也可以使用不同的密钥文件名,生成多个 Secure Boot v2 签名密钥。建议使用多个密钥,以降低对单个密钥的依赖。
2. 生成公钥摘要
运行以下命令可以为上一步生成的私钥生成公钥摘要:
.. code:: bash
espsecure.py digest_sbv2_public_key --keyfile secure_boot_signing_key.pem --output digest.bin
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
如果有多个摘要,应将每个摘要保存在一个单独的文件中。
3. 在 eFuse 中烧录密钥摘要
运行以下命令可以在 eFuse 中烧录公钥摘要:
.. only:: esp32
.. code:: bash
espefuse.py --port PORT --chip esp32 burn_key secure_boot_v2 digest.bin
.. only:: esp32c2
.. code:: bash
espefuse.py --port PORT --chip esp32c2 burn_key KEY_BLOCK0 digest.bin SECURE_BOOT_DIGEST
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
.. code:: bash
espefuse.py --port PORT --chip {IDF_TARGET_PATH_NAME} burn_key BLOCK digest.bin SECURE_BOOT_DIGEST0
其中,``BLOCK````BLOCK_KEY0````BLOCK_KEY5`` 之间的一个空闲密钥块。
如果有多个摘要,可以将密钥用途分别更改为 ``SECURE_BOOT_DIGEST1````SECURE_BOOT_DIGEST2``,从而依次烧录其他摘要。
4. 启用 Secure Boot v2
运行以下命令启用 Secure Boot v2 eFuse
.. only:: esp32
.. code:: bash
espefuse.py --port PORT --chip esp32 burn_efuse ABS_DONE_1
.. only:: not esp32
.. code:: bash
espefuse.py --port PORT --chip {IDF_TARGET_PATH_NAME} burn_efuse SECURE_BOOT_EN
5. 烧录相关 eFuse
A) 烧录安全 eFuse
.. important::
对于生产用例,强烈建议烧录下列所有 eFuse。
.. list::
:esp32: - ``JTAG_DISABLE``:禁用 JTAG。
:SOC_EFUSE_DIS_BOOT_REMAP: - ``DIS_BOOT_REMAP``:禁用将 ROM 重新映射到 RAM 地址空间的功能。
:SOC_EFUSE_HARD_DIS_JTAG: - ``HARD_DIS_JTAG``:硬禁用 JTAG 外设。
:SOC_EFUSE_SOFT_DIS_JTAG: - ``SOFT_DIS_JTAG``:禁止软件对 JTAG 外设的访问。
:SOC_EFUSE_DIS_DIRECT_BOOT:- ``DIS_DIRECT_BOOT``: 禁用直接引导(旧版 SPI 引导模式)。
:SOC_EFUSE_DIS_LEGACY_SPI_BOOT: - ``DIS_LEGACY_SPI_BOOT``:禁用旧版 SPI 引导模式。
:SOC_EFUSE_DIS_USB_JTAG: - ``DIS_USB_JTAG``:禁止从 USB 切换到 JTAG
:SOC_EFUSE_DIS_PAD_JTAG: - ``DIS_PAD_JTAG``:永久禁用 JTAG。
:SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS: - ``SECURE_BOOT_AGGRESSIVE_REVOKE``:主动吊销密钥摘要。详请请参阅 :ref:`secure-boot-v2-aggressive-key-revocation`。
运行以下命令烧录相应的 eFuse
.. code:: bash
espefuse.py burn_efuse --port PORT EFUSE_NAME 0x1
.. note::
请将 EFUSE_NAME 更新为需烧录的 eFuse。在上述命令中添加多个 eFuse 可以同时烧录例如EFUSE_NAME VAL EFUSE_NAME2 VAL2。有关 `espefuse.py` 的更多信息,请参阅 `此文档 <https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/index.html>`__
B) 与 Secure Boot v2 相关的 eFuse
i) 禁用读保护选项:
在 eFuse 中烧录的 Secure Boot 摘要必须保持可读,否则会导致安全启动失败。烧录以下 eFuse 可防止意外启用此密钥块的读保护:
.. code:: bash
espefuse.py -p $ESPPORT write_protect_efuse RD_DIS
.. important::
烧录此 eFuse 后,不能为任何密钥启用读保护。例如,如果此时需要对密钥进行读保护的 flash 加密尚未启用,则之后也无法启用。请确保在此之后没有其他 efuse 密钥需要读保护。
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
ii) 吊销密钥摘要:
在我们烧录 Secure Boot 密钥时,需要吊销未使用的摘要槽。可以通过运行以下命令吊销相应的槽:
.. code:: bash
espefuse.py --port PORT --chip {IDF_TARGET_PATH_NAME} burn_efuse EFUSE_REVOKE_BIT
上述命令中的 ``EFUSE_REVOKE_BIT`` 可以是 ``SECURE_BOOT_KEY_REVOKE0````SECURE_BOOT_KEY_REVOKE1````SECURE_BOOT_KEY_REVOKE2``。注意,只有未使用的密钥摘要必须吊销。一旦吊销,相应的摘要就不能再次使用。
6. 构建二进制文件
默认情况下ROM 引导加载程序只会验证 :ref:`second-stage-bootloader` (固件引导加载程序)。只有在启用 :ref:`CONFIG_SECURE_BOOT` 选项(并将 :ref:`CONFIG_SECURE_BOOT_VERSION` 设置为 ``SECURE_BOOT_V2_ENABLED``)时,固件引导加载程序才会在构建引导加载程序时验证应用程序分区。
A) 打开 :ref:`project-configuration-menu`,在 ``Security features`` 中设置 ``Enable hardware Secure Boot in bootloader`` 启用 Secure Boot。
.. only:: esp32
对于 ESP32Secure Boot v2 仅适用于 ESP32 ECO3 及以上版本。要查看 ``Secure Boot v2`` 选项,芯片版本应更改为 v3.0 (ECO3)。要更改芯片版本,请在 ``Component Config -> Hardware Settings -> Chip Revision`` 中将 ``Minimum Supported ESP32 Revision`` 设置为 ``Rev 3.0 (ECO3)``
.. only:: SOC_SECURE_BOOT_V2_RSA or SOC_SECURE_BOOT_V2_ECC
选中 ``Secure Boot v2`` 选项, ``App Signing Scheme`` 将被默认设置为 {IDF_TARGET_SBV2_DEFAULT_SCHEME}。
B) 在 :ref:`project-configuration-menu` 中为项目禁用 :ref:`CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES` 选项,以确保所有生成的二进制文件都受到安全保护且未签名,避免生成签名的二进制文件,因为需要使用 ``espsecure`` 工具手动签名二进制文件。
7. 构建、签名并烧录二进制文件
完成上述配置后,可以用 ``idf.py build`` 命令构建引导加载程序和应用程序二进制文件。
Secure Boot v2 工作流程只验证 ``bootloader````application`` 二进制文件,因此只需要对这些二进制文件进行签名。其他二进制文件(例如 ``partition-table.bin``)可以在构建后直接进行烧录。
运行以下命令对 ``bootloader.bin````app.bin`` 二进制文件进行签名:
.. code:: bash
espsecure.py sign_data --version 2 --keyfile secure_boot_signing_key.pem --output bootloader-signed.bin build/bootloader/bootloader.bin
espsecure.py sign_data --version 2 --keyfile secure_boot_signing_key.pem --output my-app-signed.bin build/my-app.bin
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
如要使用多个安全引导密钥,可在同一个已签名二进制文件中添加用新密钥签名的块,如下所示:
.. code:: bash
espsecure.py sign_data --keyfile secure_boot_signing_key2.pem --version 2 --amend_signatures -o bootloader-signed.bin bootloader-signed.bin
espsecure.py sign_data --keyfile secure_boot_signing_key2.pem --version 2 --apend_signatures -o my-app-signed.bin my-app-signed.bin
如果有第三个密钥,则可以重复以上过程。注意:输入和输出文件不能用相同名字来命名。
运行以下命令来检查附加到二进制文件的签名:
.. code:: bash
espsecure.py signature_info_v2 bootloader-signed.bin
然后使用 ``esptool.py`` 将上述文件和其他二进制文件(如分区表)烧录到各自的偏移地址。要查看所有推荐的 ``esptool.py`` 命令行选项,请参阅 ``idf.py build`` 的输出结果。要获得固件的 flash 偏移地址,可查找分区表条目或运行 ``idf.py partition-table`` 查看。
8. 确保 ROM 下载模式安全
.. warning::
请在最后烧录以下位。烧录后espefuse 工具将无法再用于烧录其他 eFuse。
.. only:: esp32
禁用 UART ROM DL 模式:
.. list::
- ``UART_DOWNLOAD_DIS``:禁用 UART ROM 下载模式
运行以下指令,烧录 eFuse
.. code:: bash
espefuse.py --port PORT burn_efuse UART_DOWNLOAD_DIS
.. only:: not esp32
启用安全下载模式:
.. list::
- ``ENABLE_SECURITY_DOWNLOAD``:启用安全 ROM 下载模式
运行以下指令,烧录 eFuse
.. code:: bash
espefuse.py --port PORT burn_efuse ENABLE_SECURITY_DOWNLOAD
Secure Boot v2 指南
~~~~~~~~~~~~~~~~~~~
* 建议将 Secure Boot 密钥存储在高度安全的地方,如可以使用物理或云 HSM 来存储 Secure Boot 私钥。请参阅 :ref:`remote-sign-v2-image` 获取更多详细信息。
.. only:: SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
* 建议使用所有可用的摘要槽,降低对单个私钥的依赖。
.. _enable-nvs-encryption-externally:
启用外部 NVS 加密
^^^^^^^^^^^^^^^^^
有关 NVS 加密及相关方案的详细信息,请参阅 :doc:`NVS 加密 </api-reference/storage/nvs_encryption>`
.. only:: SOC_HMAC_SUPPORTED
.. _enable-nvs-encryption-based-on-hmac:
基于 HMAC 启用 NVS 加密
~~~~~~~~~~~~~~~~~~~~~~~
1. 生成 HMAC 密钥和 NVS 加密密钥
在基于 HMAC 的 NVS 加密方案中,有两个密钥:
* HMAC 密钥 - 256 位的 HMAC 密钥,应存储在 eFuse 中。
* NVS 加密密钥 - 用于加密 NVS 分区,在命令运行时通过 HMAC 密钥派生。
使用以下命令,通过 :component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py` 脚本可以生成上述密钥:
.. code:: bash
python3 nvs_partition_gen.py generate-key --key_protect_hmac --kp_hmac_keygen --kp_hmac_keyfile hmac_key.bin --keyfile nvs_encr_key.bin
运行上述命令后,``keys`` 文件夹下会生成相应的密钥。
2. 在 eFuse 中烧录 HMAC 密钥
使用以下命令在 {IDF_TARGET_NAME} 的 eFuse 中烧录 NVS 密钥:
.. code:: bash
espefuse.py --port PORT burn_key BLOCK hmac_key.bin HMAC_UP
其中,``BLOCK````BLOCK_KEY0````BLOCK_KEY5`` 之间的一个空闲密钥块。
3. 生成加密的 NVS 分区
主机上将会生成加密 NVS 分区。有关生成加密 NVS 分区的详细信息,请参阅读 :ref:`generate-encrypted-nvs-partition`。为此CSV 文件中应该包含 NVS 文件的全部内容。详情请参阅 :ref:`nvs-csv-file-format`
使用以下命令,可以生成加密的 NVS 分区:
.. code:: bash
python3 nvs_partition_gen.py encrypt sample_singlepage_blob.csv nvs_encr_partition.bin 0x3000 --inputkey keys/nvs_encr_key.bin
下面解释一些命令参数:
* CSV 文件名 - 此命令中,``sample_singlepage_blob.csv`` 是指包含 NVS 数据的 CSV 文件,请将其替换为所选择的文件。
* NVS 分区偏移量 - 这是 {IDF_TARGET_NAME} flash 中存储 NVS 分区的偏移地址。通过在项目目录下执行 ``idf.py partition-table`` 命令,可以找到 NVS 分区偏移地址。请将上述命令中的示例值 ``0x3000`` 调整为正确的偏移量。
4. 配置项目
* 通过设置 :ref:`CONFIG_NVS_ENCRYPTION`,启用 `NVS 加密`
* 将 :ref:`CONFIG_NVS_SEC_KEY_PROTECTION_SCHEME` 设置为 ``CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC``,启用基于 HMAC 的 NVS 加密。
* 通过设置 :ref:`CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID`,将 HMAC eFuse 密钥 ID 设为步骤 2 中烧录 eFuse 密钥的 ID。
5. 烧录 NVS 分区
使用 ``esptool.py`` 命令,将步骤 3 中生成的 NVS 分区 (``nvs_encr_partition.bin``) 烧录到相应的偏移地址。要查看所有推荐的 ``esptool.py`` 命令行选项,请查阅 ``idf.py build`` 构建成功后打印的输出。
如果芯片启用了 flash 加密,请先加密分区再进行烧录。详情请参阅 `flash 加密工作流程 <enable-flash-encryption-externally_>`_ 的相关烧录步骤。
.. _enable-flash-enc-based-nvs-encryption:
基于 flash 加密启用 NVS 加密
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
在这种情况下,主机上生成 NVS 加密密钥,并将其烧录到芯片上,借助 :doc:`flash 加密 </security/flash-encryption>` 功能进行保护。
1. 生成 NVS 加密密钥
使用 :doc:`NVS 分区生成工具 </api-reference/storage/nvs_partition_gen>`,可以生成相应的密钥。在主机上生成加密密钥,并将该密钥以加密状态存储在 {IDF_TARGET_NAME} 的 flash 中。
使用以下命令,通过 :component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py` 脚本生成密钥:
.. code:: bash
python3 nvs_partition_gen.py generate-key --keyfile nvs_encr_key.bin
``keys`` 文件夹中将生成相应的密钥。
2. 生成加密的 NVS 分区
在主机上生成实际的加密 NVS 分区,详情请参阅 :ref:`generate-encrypted-nvs-partition`。为此CSV 文件应包含 NVS 文件数据,详情请参阅 :ref:`nvs-csv-file-format`
使用以下命令,可以生成加密的 NVS 分区:
.. code:: bash
python3 nvs_partition_gen.py encrypt sample_singlepage_blob.csv nvs_encr_partition.bin 0x3000 --inputkey keys/nvs_encr_key.bin
下文解释了上述命令中的一些参数:
* CSV 文件名 - 上述命名中的 `sample_singlepage_blob.csv` 是指包含 NVS 数据的 CSV 文件,请将其替换为所选文件。
* NVS 分区偏移量 - 这是 NVS 分区在 {IDF_TARGET_NAME} 的 flash 中存储时的偏移地址。在项目目录中执行 ``idf.py partition-table`` 命令,可以找到 NVS 分区的偏移量。请将上述命令中的示例值 ``0x3000`` 替换为正确的偏移量。
3. 配置项目
* 通过启用 :ref:`CONFIG_NVS_ENCRYPTION` 来启用 `NVS 加密`
* 通过将 :ref:`CONFIG_NVS_SEC_KEY_PROTECTION_SCHEME` 设置为 ``CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC``,配置 NVS 使用基于 flash 加密的方案。
4. 烧录 NVS 分区和 NVS 加密密钥
使用 ``esptool.py`` 命令,将 NVS 分区 (``nvs_encr_partition.bin``) 和 NVS 加密密钥 (``nvs_encr_key.bin``) 烧录到各自的偏移地址。通过 ``idf.py build`` 成功后打印的输出,可查看所有推荐的 ``esptool.py`` 命令行选项。
若芯片启用了 flash 加密,请在烧录之前先加密分区。详情请参阅 `flash 加密工作流程 <enable-flash-encryption-externally_>`_ 中与烧录相关的步骤。