diff --git a/docs/en/security/secure-boot-v1.rst b/docs/en/security/secure-boot-v1.rst index c7afbc7020..598e861431 100644 --- a/docs/en/security/secure-boot-v1.rst +++ b/docs/en/security/secure-boot-v1.rst @@ -1,104 +1,112 @@ Secure Boot =========== -.. important:: - - All references in this document are related to Secure Boot V1 (The AES based Secure Boot Scheme). ESP32 Revision 3 onwards, the preferred secure boot scheme is :doc:`secure-boot-v2`. - Please refer to Secure Boot V2 document for ESP32 Revision 3 or ESP32-S2. - -Secure Boot is a feature for ensuring only your code can run on the chip. Data loaded from flash is verified on each reset. - -Secure Boot is separate from the :doc:`flash-encryption` feature, and you can use secure boot without encrypting the flash contents. However, for a secure environment both should be used simultaneously. See :ref:`secure-boot-and-flash-encr` for more details. +:link_to_translation:`zh_CN:[中文]` .. important:: - Enabling secure boot limits your options for further updates of your {IDF_TARGET_NAME}. Make sure to read this document throughly and understand the implications of enabling secure boot. + All references in this document are related to Secure Boot V1, i.e., the AES-based Secure Boot Scheme. For ESP32 v3.0 onwards, the preferred secure boot scheme is :doc:`secure-boot-v2`. + + Please refer to :doc:`secure-boot-v2` for ESP32 v3.0 or ESP32-S2. + +Secure boot is a feature for ensuring only your code can run on the chip. Data loaded from flash is verified on each reset. + +Secure boot is separate from the :doc:`flash-encryption` feature, and you can use secure boot without encrypting the flash contents. However, for a secure environment, both should be used simultaneously. See :ref:`secure-boot-and-flash-encr` for more details. + +.. important:: + + Enabling secure boot limits your options for further updates of your {IDF_TARGET_NAME}. Make sure to read this document thoroughly and understand the implications of enabling secure boot. + Background ---------- -- Most data is stored in flash. Flash access does not need to be protected from physical access in order for secure boot to function, because critical data is stored (non-software-accessible) in Efuses internal to the chip. +- Most data is stored in flash. Flash access does not need to be protected from physical access for secure boot to function, because critical data is stored in eFuses internal to the chip and is non-software-accessible. -- Efuses are used to store the secure bootloader key (in efuse BLOCK2), and also a single Efuse bit (ABS_DONE_0) is burned (written to 1) to permanently enable secure boot on the chip. For more details on eFuses, see *{IDF_TARGET_NAME} Technical Reference Manual* > *eFuse Controller (eFuse)* [`PDF <{IDF_TARGET_TRM_EN_URL}#efuse>`__]. +- eFuses are used to store the secure boot information permanently. The secure boot key is stored in eFuse BLOCK2, and also, a single eFuse bit ABS_DONE_0 is burned, or written to 1, to permanently enable secure boot on the chip. For more details on eFuses, see *{IDF_TARGET_NAME} Technical Reference Manual* > *eFuse Controller (EFUSE)* [`PDF <{IDF_TARGET_TRM_EN_URL}#efuse>`__]. -- To understand the secure boot process, first familiarise yourself with the standard :doc:`../api-guides/startup`. +- To understand the secure boot process, please familiarize yourself with the standard :doc:`../api-guides/startup`. + +- Both stages of the boot process, including initial software bootloader load and subsequent partition & app loading, are verified by the secure boot process, in a chain of trust relationship. -- Both stages of the boot process (initial software bootloader load, and subsequent partition & app loading) are verified by the secure boot process, in a "chain of trust" relationship. Secure Boot Process Overview ---------------------------- -This is a high level overview of the secure boot process. Step by step instructions are supplied under :ref:`secure-boot-howto`. Further in-depth details are supplied under :ref:`secure-boot-technical-details`: +This is a high-level overview of the secure boot process. Step-by-step instructions are supplied under :ref:`secure-boot-how-to`. Further in-depth details are supplied under :ref:`secure-boot-technical-details`: -1. The options to enable secure boot are provided in the :ref:`project-configuration-menu`, under "Secure Boot Configuration". +1. The options to enable secure boot are provided in the :ref:`project-configuration-menu`, under ``Secure Boot Configuration``. -2. Secure Boot defaults to signing images and partition table data during the build process. The "Secure boot private signing key" config item is a file path to a ECDSA public/private key pair in a PEM format file. +2. Secure boot defaults to signing images and partition table data during the build process. The ``Secure boot private signing key`` config item is a file path to an ECDSA public/private key pair in a PEM format file. -3. The software bootloader image is built by esp-idf with secure boot support enabled and the public key (signature verification) portion of the secure boot signing key compiled in. This software bootloader image is flashed at offset 0x1000. +3. The software bootloader image is built by ESP-IDF with secure boot support enabled, and the public key for signature verification is integrated into the bootloader image. This software bootloader image is flashed at offset 0x1000. -4. On first boot, the software bootloader follows the following process to enable secure boot: +4. On the first boot, the software bootloader follows the following process to enable a secure boot: - - Hardware secure boot support generates a device secure bootloader key (generated via hardware RNG, then stored read/write protected in efuse), and a secure digest. The digest is derived from the key, an IV, and the bootloader image contents. + - Hardware secure boot support generates a device-secure bootloader key and a secure digest. The secure bootloader key is generated with the help of the hardware RNG, and then stored in eFuse with read and write protection enabled. The digest is derived from the key, an initialization vector (IV), and the bootloader image contents. - The secure digest is flashed at offset 0x0 in the flash. - - Depending on Secure Boot Configuration, efuses are burned to disable JTAG and the ROM BASIC interpreter (it is strongly recommended these options are turned on.) - - Bootloader permanently enables secure boot by burning the ABS_DONE_0 efuse. The software bootloader then becomes protected (the chip will only boot a bootloader image if the digest matches.) + - Depending on Secure Boot Configuration, eFuses are burned to disable JTAG and the ROM BASIC interpreter. It is **strongly recommended** that these options are turned on. + - Bootloader permanently enables secure boot by burning the ABS_DONE_0 eFuse. The software bootloader then becomes protected. After this point, the chip will only boot a bootloader image if the digest matches. -5. On subsequent boots the ROM bootloader sees that the secure boot efuse is burned, reads the saved digest at 0x0 and uses hardware secure boot support to compare it with a newly calculated digest. If the digest does not match then booting will not continue. The digest and comparison are performed entirely by hardware, and the calculated digest is not readable by software. For technical details see :ref:`secure-boot-hardware-support`. +5. On subsequent boots, the ROM bootloader sees that the secure boot eFuse is burned, reads the saved digest at 0x0, and uses hardware secure boot support to compare it with a newly calculated digest. If the digest does not match then booting will not continue. The digest and comparison are performed entirely by hardware, and the calculated digest is not readable by software. For technical details see :ref:`secure-boot-hardware-support`. + +6. When running in secure boot mode, the software bootloader uses the secure boot signing key, the public key of which is embedded in the bootloader itself and therefore validated as part of the bootloader, to verify the signature appended to all subsequent partition tables and app images before they are booted. -6. When running in secure boot mode, the software bootloader uses the secure boot signing key (the public key of which is embedded in the bootloader itself, and therefore validated as part of the bootloader) to verify the signature appended to all subsequent partition tables and app images before they are booted. Keys ---- The following keys are used by the secure boot process: -- "secure bootloader key" is a 256-bit AES key that is stored in Efuse block 2. The bootloader can generate this key itself from the internal hardware random number generator, the user does not need to supply it (it is optionally possible to supply this key, see :ref:`secure-boot-reflashable`). The Efuse holding this key is read & write protected (preventing software access) before secure boot is enabled. +- The secure bootloader key is a 256-bit AES key that is stored in eFuse block 2. The bootloader can generate this key itself from the internal hardware random number generator, and you do not need to supply it. It is optionally possible to supply this key, see :ref:`secure-boot-reflashable`. The eFuse holding this key is read and write protected before the secure boot is enabled to prevent further software access of the key. - - By default, the Efuse Block 2 Coding Scheme is "None" and a 256 bit key is stored in this block. On some {IDF_TARGET_NAME}s, the Coding Scheme is set to 3/4 Encoding (CODING_SCHEME efuse has value 1) and a 192 bit key must be stored in this block. + - By default, the eFuse Block 2 Coding Scheme is ``None`` and a 256-bit key is stored in this block. On some versions of {IDF_TARGET_NAME}s, the Coding Scheme is set to ``3/4 Encoding`` with CODING_SCHEME eFuse has value 1, and a 192-bit key must be stored in this block. .. only:: esp32 - For more details, see *{IDF_TARGET_NAME} Technical Reference Manual* > *eFuse Controller (eFuse)* > *System Parameter coding_scheme* [`PDF <{IDF_TARGET_TRM_EN_URL}#efuse>`__]. + For more details, see *{IDF_TARGET_NAME} Technical Reference Manual* > *eFuse Controller (EFUSE)* > *System Parameter coding_scheme* [`PDF <{IDF_TARGET_TRM_EN_URL}#efuse>`__]. - The algorithm operates on a 256 bit key in all cases, 192 bit keys are extended by repeating some bits (:ref:`secure-bootloader-digest-algorithm`). + The algorithm operates on a 256-bit key in all cases. 192-bit keys are extended by repeating some bits, see :ref:`secure-bootloader-digest-algorithm`. -- "secure boot signing key" is a standard ECDSA public/private key pair (see :ref:`secure-boot-image-signing-algorithm`) in PEM format. +- ``secure boot signing key`` is a standard ECDSA public/private key pair in PEM format, see :ref:`secure-boot-image-signing-algorithm`. - - The public key from this key pair (for signature verification but not signature creation) is compiled into the software bootloader and used to verify the second stage of booting (partition table, app image) before booting continues. The public key can be freely distributed, it does not need to be kept secret. + - The public key from this key pair is compiled into the software bootloader. It is only used for signature verification purposes and not signature creation. This public key is used to verify the second stage of booting, including the partition table and app image, before booting continues. The public key can be freely distributed; it does not need to be kept secret. + + - The private key from this key pair **must be securely kept private**, as anyone who has this key can authenticate to any bootloader that is configured with a secure boot and the matching public key. - - The private key from this key pair *must be securely kept private*, as anyone who has this key can authenticate to any bootloader that is configured with secure boot and the matching public key. 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`. -.. _secure-boot-howto: -How To Enable Secure Boot +.. _secure-boot-how-to: + +How to Enable Secure Boot ------------------------- -1. Open the :ref:`project-configuration-menu`, navigate to "Secure Boot Configuration" and select the option "One-time Flash". (To understand the alternative "Reflashable" choice, see :ref:`secure-boot-reflashable`.) +1. Open the :ref:`project-configuration-menu`, navigate to ``Secure Boot Configuration`` and select the option ``One-time Flash``. To understand the alternative ``Reflashable`` option, see :ref:`secure-boot-reflashable`. -2. Select a name for the secure boot signing key. This option will appear after secure boot is enabled. The file can be anywhere on your system. A relative path will be evaluated from the project directory. The file does not need to exist yet. +2. Select a name for the secure boot signing key. This option will appear after secure boot is enabled, and the key file can be anywhere on your system. If you opt for a relative path, it will be evaluated based on the project directory. Importantly, there's no need for the file to exist when making this selection. -3. Set other menuconfig options (as desired). Pay particular attention to the "Bootloader Config" options, as you can only flash the bootloader once. Then exit menuconfig and save your configuration +3. Set other menuconfig options as desired. Pay particular attention to the ``Bootloader Config`` options, as you can only flash the bootloader once. Then exit menuconfig and save your configuration. -4. The first time you run ``make``, if the signing key is not found then an error message will be printed with a command to generate a signing key via ``espsecure.py generate_signing_key``. +4. When you run ``idf.py build`` for the first time, if the signing key is not found, then an error message will be printed with a command to generate a signing key via ``espsecure.py 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, i.e., `/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 keypair using openssl or another industry standard encryption program. See :ref:`secure-boot-generate-key` for more details. + For production environments, we recommend generating the key pair using OpenSSL or another industry-standard encryption program. See :ref:`secure-boot-generate-key` for more details. -5. 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``. +5. 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``. .. _secure-boot-resume-normal-flashing: -6. When you are ready to flash the bootloader, run the specified command (you have to enter it yourself, this step is not performed by make) and then wait for flashing to complete. **Remember this is a one time flash, you can not change the bootloader after this!**. +6. When you are ready to flash the bootloader, run the specified command. You have to enter it yourself, this step is not performed by make. And then wait for flashing to complete. **Remember this is a one-time flash, you can not change the bootloader after this!** 7. 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 4. @@ -110,90 +118,101 @@ How To Enable Secure Boot .. 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. + The 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. + If {IDF_TARGET_NAME} is reset or powered down during the first boot, it will start the process again on the next boot. + +9. On subsequent boots, the secure boot hardware will verify the software bootloader has not changed using the secure bootloader key, and then the software bootloader will verify the signed partition table and app image using the public key portion of the secure boot signing key. -9. On subsequent boots, the secure boot hardware will verify the software bootloader has not changed (using the secure bootloader key) and then the software bootloader will verify the signed partition table and app image (using the public key portion of the secure boot signing key). .. _secure-boot-reflashable: -Re-Flashable Software Bootloader --------------------------------- +Reflashable Software Bootloader +------------------------------- -Configuration "Secure Boot: One-Time Flash" is the recommended configuration for production devices. In this mode, each device gets a unique key that is never stored outside the device. +Configuration ``Secure Boot: One-Time Flash`` is the recommended configuration for production devices. In this mode, each device gets a unique key that is never stored outside the device. However, an alternative mode :ref:`CONFIG_SECURE_BOOTLOADER_MODE` is also available. This mode allows you to supply a binary key file that is used for the secure bootloader key. As you have the key file, you can generate new bootloader images and secure boot digests for them. -In the esp-idf build process, this 256-bit key file is derived from the ECDSA app signing key generated by the user (see the :ref:`secure-boot-generate-key` step below). This private key's SHA-256 digest is used as the secure bootloader key in efuse (as-is for Coding Scheme None, or truncate to 192 bytes for 3/4 Encoding). This is a convenience so you only need to generate/protect a single private key. +In the ESP-IDF build process, this 256-bit key file is derived from the ECDSA app signing key generated by the user, see the :ref:`secure-boot-generate-key` step below. This private key's SHA-256 digest is used as the secure bootloader key in eFuse, as-is for Coding Scheme ``None``, or truncated to 192 bytes for ``3/4 Encoding``. This is a convenience so you only need to generate or protect a single private key. .. note:: - Although it is possible, we strongly recommend not generating one secure boot key and flashing it to every device in a production environment. The "One-Time Flash" option is recommended for production environments. + Although it is possible, we strongly recommend not generating one secure boot key and flashing it to every device in a production environment. The ``One-Time Flash`` option is recommended for production environments. To enable a reflashable bootloader: -1. In the :ref:`project-configuration-menu`, select "Bootloader Config" > :ref:`CONFIG_SECURE_BOOT` > CONFIG_SECURE_BOOT_V1_ENABLED > :ref:`CONFIG_SECURE_BOOTLOADER_MODE` > Reflashable. +1. In the :ref:`project-configuration-menu`, select ``Bootloader Config`` > :ref:`CONFIG_SECURE_BOOT` > ``CONFIG_SECURE_BOOT_V1_ENABLED`` > :ref:`CONFIG_SECURE_BOOTLOADER_MODE` > ``Reflashable``. 2. If necessary, set the :ref:`CONFIG_SECURE_BOOTLOADER_KEY_ENCODING` based on the coding scheme used by the device. The coding scheme is shown in the ``Features`` line when ``esptool.py`` connects to the chip, or in the ``espefuse.py summary`` output. -3. Please follow the steps shown in :ref:`secure-boot-generate-key` to generate signing key. Path of the generated key file must be specified in "Secure Boot Configuration" menu. +3. Please follow the steps shown in :ref:`secure-boot-generate-key` to generate the signing key. The path of the generated key file must be specified in the ``Secure Boot Configuration`` menu. -4. Run ``idf.py bootloader``. A binary key file will be created, derived from the private key that is used for signing. Two sets of flashing steps will be printed - the first set of steps includes an ``espefuse.py burn_key secure_boot_v1 path_to/secure-bootloader-key-xxx.bin`` command which is used to write the bootloader key to efuse. (Flashing this key is a one-time-only process.) The second set of steps can be used to reflash the bootloader with a pre-calculated digest (generated during the build process). +4. Run ``idf.py bootloader``. A binary key file will be created, derived from the private key that is used for signing. Two sets of flashing steps will be printed. The first set of steps includes an ``espefuse.py burn_key secure_boot_v1 path_to/secure-bootloader-key-xxx.bin`` command which is used to write the bootloader key to eFuse. Flashing this key is a one-time-only process. The second set of steps can be used to reflash the bootloader with a pre-calculated digest, which is generated during the build process. 5. Resume from :ref:`Step 6 of the one-time flashing process `, to flash the bootloader and enable secure boot. Watch the console log output closely to ensure there were no errors in the secure boot configuration. + .. _secure-boot-generate-key: Generating Secure Boot Signing Key ---------------------------------- -The build system will prompt you with a command to generate a new signing key via ``espsecure.py generate_signing_key``. This uses the python-ecdsa library, which in turn uses Python's os.urandom() as a random number source. +The build system will prompt you with a command to generate a new signing key via ``espsecure.py generate_signing_key``. This uses the python-ecdsa library, which in turn uses Python's ``os.urandom()`` as a random number source. -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 EC key generation utilities. +The strength of the signing key is proportional to the random number source of the system, and 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 EC 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: -``` -openssl ecparam -name prime256v1 -genkey -noout -out my_secure_boot_signing_key.pem -``` +.. 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-image: Remote Signing of Images ------------------------ -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 & partition table data for secure boot, on a remote system. -To use remote signing, disable the option "Sign binaries during build". The private signing key does not need to be present on the build system. However, the public (signature verification) key is required because it is compiled into the bootloader (and can be used to verify image signatures during OTA updates. +To use remote signing, disable the option ``Sign binaries during build``. The private signing key does not need to be present on the build system. However, the public signature verification key is required because it is compiled into the bootloader, and can be used to verify image signatures during OTA updates. -To extract the public key from the private key:: +To extract the public key from the private key: + +.. code-block:: espsecure.py extract_public_key --keyfile PRIVATE_SIGNING_KEY PUBLIC_VERIFICATION_KEY -The path to the public signature verification key needs to be specified in the menuconfig under "Secure boot public signature verification key" in order to build the secure bootloader. +The path to the public signature verification key needs to be specified in the menuconfig under ``Secure boot public signature verification key`` in order to build the secure bootloader. -After the app image and partition table are built, the build system will print signing steps using espsecure.py:: +After the app image and partition table are built, the build system will print signing steps using ``espsecure.py``: + +.. code-block:: espsecure.py sign_data --keyfile PRIVATE_SIGNING_KEY BINARY_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:: +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:: espsecure.py sign_data --keyfile PRIVATE_SIGNING_KEY --output SIGNED_BINARY_FILE BINARY_FILE + Secure Boot Best Practices -------------------------- * Generate the signing key on a system with a quality source of entropy. * Keep the signing key private at all times. A leak of this key will compromise the secure boot system. -* Do not allow any third party to observe any aspects of the key generation or signing process using espsecure.py. Both processes are vulnerable to timing or other side-channel attacks. -* Enable all secure boot options in the Secure Boot Configuration. These include flash encryption, disabling of JTAG, disabling BASIC ROM interpeter, and disabling the UART bootloader encrypted flash access. +* Do not allow any third party to observe any aspects of the key generation or signing process using ``espsecure.py``. Both processes are vulnerable to timing or other side-channel attacks. +* Enable all secure boot options in Secure Boot Configuration. These include flash encryption, disabling of JTAG, disabling BASIC ROM interpreter, and disabling the UART bootloader encrypted flash access. * Use secure boot in combination with :doc:`flash-encryption` to prevent local readout of the flash contents. + .. _secure-boot-technical-details: Technical Details @@ -201,18 +220,20 @@ Technical Details The following sections contain low-level reference descriptions of various secure boot elements: + .. _secure-boot-hardware-support: Secure Boot Hardware Support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The first stage of secure boot verification (checking the software bootloader) is done via hardware. The {IDF_TARGET_NAME}'s Secure Boot support hardware can perform three basic operations: +The first stage of secure boot verification, i.e., checking the software bootloader, is done via hardware. The {IDF_TARGET_NAME}'s secure boot support hardware can perform three basic operations: 1. Generate a random sequence of bytes from a hardware random number generator. -2. Generate a digest from data (usually the bootloader image from flash) using a key stored in Efuse block 2. The key in Efuse can (& should) be read/write protected, which prevents software access. For full details of this algorithm see `Secure Bootloader Digest Algorithm`_. The digest can only be read back by software if Efuse ABS_DONE_0 is *not* burned (ie still 0). +2. Generate a digest from data, usually the bootloader image from flash, using a key stored in eFuse block 2. The key in eFuse can and should be read/write protected, which prevents software access. For full details of this algorithm see `Secure Bootloader Digest Algorithm`_. The digest can only be read back by software if eFuse ABS_DONE_0 is **not** burned, i.e., still 0. + +3. Generate a digest from data, usually the bootloader image from flash, using the same algorithm as step 2 and compare it to a pre-calculated digest supplied in a buffer, usually read from flash offset 0x0. The hardware returns a true/false comparison without making the digest available to the software. This function is available even when eFuse ABS_DONE_0 is burned. -3. Generate a digest from data (usually the bootloader image from flash) using the same algorithm as step 2 and compare it to a pre-calculated digest supplied in a buffer (usually read from flash offset 0x0). The hardware returns a true/false comparison without making the digest available to software. This function is available even when Efuse ABS_DONE_0 is burned. .. _secure-bootloader-digest-algorithm: @@ -221,23 +242,26 @@ Secure Bootloader Digest Algorithm Starting with an "image" of binary data as input, this algorithm generates a digest as output. The digest is sometimes referred to as an "abstract" in hardware documentation. -For a Python version of this algorithm, see the ``espsecure.py`` tool in the components/esptool_py directory (specifically, the ``digest_secure_bootloader`` command). +For a Python version of this algorithm, see the ``espsecure.py`` tool in the :component:`/esptool_py` directory. Specifically, the ``digest_secure_bootloader`` command. Items marked with (^) are to fulfill hardware restrictions, as opposed to cryptographic restrictions. -1. Read the AES key from efuse block 2, in reversed byte order. If Coding Scheme is set to 3/4 Encoding, extend the 192 bit key to 256 bits using the same algorithm described in :ref:`flash-encryption-algorithm`. -2. Prefix the image with a 128 byte randomly generated IV. -3. If the image length is not modulo 128, pad the image to a 128 byte boundary with 0xFF. (^) -4. For each 16 byte plaintext block of the input image: - - Reverse the byte order of the plaintext input block (^) +1. Read the AES key from eFuse block 2, in reversed byte order. If the Coding Scheme is set to ``3/4 Encoding``, extend the 192-bit key to 256 bits using the same algorithm described in :ref:`flash-encryption-algorithm`. +2. Prefix the image with a 128-byte randomly generated IV. +3. If the image length is not modulo 128, pad the image to a 128-byte boundary with 0xFF. (^) +4. For each 16-byte plaintext block of the input image: + + - Reverse the byte order of the plaintext input block. (^) - Apply AES256 in ECB mode to the plaintext block. - Reverse the byte order of the ciphertext output block. (^) - Append to the overall ciphertext output. -5. Byte-swap each 4 byte word of the ciphertext (^) -6. Calculate SHA-512 of the ciphertext. -7. Byte-swap each 4 byte word of the above calculated digest. (^) -Output digest is 192 bytes of data: The 128 byte IV, followed by the 64 byte SHA-512 digest. +5. Byte-swap each 4-byte word of the ciphertext. (^) +6. Calculate SHA-512 of the ciphertext. +7. Byte-swap each 4-byte word of the above-calculated digest. (^) + +Output digest is 192 bytes of data: the 128-byte IV, followed by the 64-byte SHA-512 digest. + .. _secure-boot-image-signing-algorithm: @@ -246,72 +270,82 @@ Image Signing Algorithm Deterministic ECDSA as specified by `RFC 6979 `_. -- Curve is NIST256p (openssl calls this curve "prime256v1", it is also sometimes called secp256r1). -- Hash function is SHA256. -- Key format used for storage is PEM. +- Curve is NIST256p. OpenSSL calls this curve prime256v1, and it is also sometimes called secp256r1. +- The hash function is SHA256. +- The key format used for storage is PEM. - - In the bootloader, the public key (for signature verification) is flashed as 64 raw bytes. + - In the bootloader, the public key for signature verification is flashed as 64 raw bytes. + +- Image signature is 68 bytes: a 4-byte version word (currently zero), followed by 64 bytes of signature data. These 68 bytes are appended to an app image or partition table data. -- Image signature is 68 bytes - a 4 byte version word (currently zero), followed by a 64 bytes of signature data. These 68 bytes are appended to an app image or partition table data. Manual Commands ~~~~~~~~~~~~~~~ -Secure boot is integrated into the esp-idf build system, so ``make`` will automatically sign an app image if secure boot is enabled. ``idf.py bootloader`` will produce a bootloader digest if menuconfig is configured for it. +Secure boot is integrated into the ESP-IDF build system, so ``idf.py build`` will automatically sign an app image if secure boot is enabled. ``idf.py bootloader`` will produce a bootloader digest if menuconfig is configured for it. However, it is possible to use the ``espsecure.py`` tool to make standalone signatures and digests. -To sign a binary image:: +To sign a binary image: + +.. code-block:: espsecure.py sign_data --keyfile ./my_signing_key.pem --output ./image_signed.bin image-unsigned.bin -Keyfile is the PEM file containing an ECDSA private signing key. +The keyfile is the PEM file containing an ECDSA private signing key. -To generate a bootloader digest:: +To generate a bootloader digest: + +.. code-block:: espsecure.py digest_secure_bootloader --keyfile ./securebootkey.bin --output ./bootloader-digest.bin build/bootloader/bootloader.bin -Keyfile is the 32 byte raw secure boot key for the device. +The keyfile is the 32-byte raw secure boot key for the device. -The output of the ``espsecure.py digest_secure_bootloader`` command is a single file which contains both the digest and the bootloader appended to it. To flash the combined digest plus bootloader to the device:: +The output of the ``espsecure.py digest_secure_bootloader`` command is a single file that contains both the digest and the bootloader appended to it. To flash the combined digest plus bootloader to the device: + +.. code-block:: esptool.py write_flash 0x0 bootloader-digest.bin + .. _secure-boot-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. + .. _signed-app-verify: Signed App Verification Without Hardware Secure Boot ---------------------------------------------------- -The integrity of apps can be checked even without enabling the hardware secure boot option. This option uses the same app signature scheme as hardware secure -boot, but unlike hardware secure boot it does not prevent the bootloader from being physically updated. This means that the device can be secured -against remote network access, but not physical access. Compared to using hardware Secure Boot this option is much simpler to implement. See :ref:`signed-app-verify-howto` for step by step instructions. +The integrity of apps can be checked even without enabling the hardware secure boot option. This option uses the same app signature scheme as hardware secure boot, but unlike hardware secure boot, it does not prevent the bootloader from being physically updated. This means that the device can be secured against remote network access, but not physical access. Compared to using hardware secure boot, this option is much simpler to implement. See :ref:`signed-app-verify-how-to` for step-by-step instructions. An app can be verified on update and, optionally, be verified on boot. -- Verification on update: When enabled, the signature is automatically checked whenever the esp_ota_ops.h APIs are used for OTA updates. If hardware secure boot is enabled, this option is always enabled and cannot be disabled. If hardware secure boot is not enabled, this option still adds significant security against network-based attackers by preventing spoofing of OTA updates. +- Verification on update: When enabled, the signature is automatically checked whenever the ``esp_ota_ops.h`` APIs are used for OTA updates. If hardware secure boot is enabled, this option is always enabled and cannot be disabled. If hardware secure boot is not enabled, this option still adds significant security against network-based attackers by preventing spoofing of OTA updates. - Verification on boot: When enabled, the bootloader will be compiled with code to verify that an app is signed before booting it. If hardware secure boot is enabled, this option is always enabled and cannot be disabled. If hardware secure boot is not enabled, this option does not add significant security by itself so most users will want to leave it disabled. -.. _signed-app-verify-howto: + +.. _signed-app-verify-how-to: How To Enable Signed App Verification ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -1. Open :ref:`project-configuration-menu` > Security features > Enable :ref:`CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT` +1. Open :ref:`project-configuration-menu` > ``Security features`` > enable :ref:`CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT` -2. "Bootloader verifies app signatures" can be enabled, which verifies app on boot. +2. ``Bootloader verifies app signatures`` can be enabled, which verifies app on boot. -3. 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. +3. 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 ``Secure boot private signing key`` will be used to sign the image. + +4. If you disable the ``Sign binaries during build`` option then you will have to enter the path of a public key file used to verify signed images in the ``Secure boot public signature verification key``. + + In this case, the private signing key should be generated by following instructions in :ref:`secure-boot-generate-key`; the public verification key and signed image should be generated by following instructions in :ref:`remote-sign-image`. -4. If you disable "Sign binaries during build" option then you will have to enter path of a public key file used to verify signed images in "Secure boot public signature verification key". - In this case, private signing key should be generated by following instructions in :ref:`secure-boot-generate-key`; public verification key and signed image should be generated by following instructions in :ref:`remote-sign-image`. Advanced Features ----------------- @@ -319,6 +353,6 @@ 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. +See :ref:`jtag-debugging-security-features` for more information about using JTAG Debugging with either secure boot or signed app verification enabled. diff --git a/docs/zh_CN/security/secure-boot-v1.rst b/docs/zh_CN/security/secure-boot-v1.rst index fd3d07baf6..5bf1e444ba 100644 --- a/docs/zh_CN/security/secure-boot-v1.rst +++ b/docs/zh_CN/security/secure-boot-v1.rst @@ -1 +1,358 @@ -.. include:: ../../en/security/secure-boot-v1.rst \ No newline at end of file +安全启动 +=========== + +:link_to_translation:`en:[English]` + +.. important:: + + 本文档中的参考均与安全启动 V1,即基于 AES 的安全启动方案有关。版本高于 ESP32 v3.0 的芯片推荐选用 :doc:`secure-boot-v2`。 + + ESP32 v3.0 和 ESP32-S2 的安全启动请参阅 :doc:`secure-boot-v2`。 + +安全启动功能用于确保芯片上仅运行签名后的代码,每次系统重置都会验证从 flash 加载的数据。 + +安全启动功能独立于 :doc:`flash-encryption` 功能,可以在不加密 flash 内容的情况下使用。然而,为确保使用环境安全,建议同时启用安全启动和 flash 加密功能。详情请参阅 :ref:`secure-boot-and-flash-encr`。 + +.. important:: + + 启用安全启动将限制进一步更新 {IDF_TARGET_NAME}。请仔细阅读本文档,了解启用安全启动的影响。 + + +背景信息 +---------- + +- 大部分数据存储在 flash 中,关键数据存储在芯片内部的 eFuse 中,无法通过软件访问。因此,为确保安全启动正常运行,无需额外对 flash 访问进行物理保护。 + +- eFuse 用于永久存储安全引导信息,安全引导密钥存放在 eFuse BLOCK2 中。单个 eFuse 位 ABS_DONE_0 也会进行烧录或写入 1,保持芯片上的安全启动始终启用。有关 eFuse 的更多内容,请参阅 *{IDF_TARGET_NAME} 技术参考手册* > *eFuse 控制器 (EFUSE)* [`PDF <{IDF_TARGET_TRM_CN_URL}#efuse>`__]。 + +- 为理解安全启动过程,请熟悉标准 :doc:`../api-guides/startup`。 + +- 安全启动过程会验证启动过程的两个阶段,包括初始软件引导加载程序和随后的分区与应用加载,形成一条信任链。 + + +安全启动过程概述 +---------------------------- + +以下是对安全启动过程的宏观概述,操作指南请参阅 :ref:`secure-boot-how-to`,进一步的技术细节请参阅 :ref:`secure-boot-technical-details`: + +1. 启用安全启动的选项可以在 ``Secure Boot Configuration`` 下的 :ref:`project-configuration-menu` 中找到。 + +2. 安全启动默认在构建过程中签名镜像和分区表数据。配置项 ``Secure boot private signing key`` 是指向 PEM 格式文件中 ECDSA 公钥/私钥对的文件路径。 + +3. 启用安全启动支持的 ESP-IDF 负责构建软件引导加载程序镜像,签名验证所需公钥已集成到引导加载程序镜像中。此软件引导加载程序镜像将刷写到 0x1000 偏移地址。 + +4. 初次启动时,软件引导加载程序按以下方式启用安全启动: + + - 硬件安全启动支持生成设备安全引导加载程序密钥以及安全摘要。密钥借助硬件随机数生成,随后存储在 eFuse 中,受读写保护。硬件安全启动还支持生成安全摘要,摘要源自密钥、初始向量 (IV) 和引导加载程序镜像内容。 + - 安全摘要将刷写到 flash 中的 0x0 偏移地址。 + - 根据安全启动配置,烧录 eFuse 以禁用 JTAG 和 ROM 基本解释器。**强烈建议** 禁用 JTAG 和 ROM 基本解释器。 + - 烧录 ABS_DONE_0 eFuse 后,引导加载程序将始终启用安全启动,软件引导加载程序也随之受到保护。此后,芯片只有在摘要匹配时才会启动引导加载程序镜像。 + +5. 在后续启动过程中,ROM 引导加载程序检测到安全启动 eFuse 已烧录,读取 0x0 处保存的摘要,然后使用硬件安全启动支持来将其与新计算的摘要进行对比。如果摘要不匹配,启动过程终止。摘要读取和对比完全由硬件完成,软件无法读取计算的摘要。更多技术详情,请参阅 :ref:`secure-boot-hardware-support`。 + +6. 在安全启动模式下运行时,软件引导加载程序使用安全启动签名密钥,该密钥的公钥已嵌入引导加载程序本身,并作为引导加载程序的一部分进行验证,以在启动前验证附加到所有后续分区表和应用程序镜像的签名。 + + +密钥 +---- + +安全启动过程中使用以下密钥: + +- 安全引导加载程序密钥是一个 256 位 AES 密钥,存储在 eFuse 块 2 中。引导加载程序可以使用内部硬件随机数生成器自行生成该密钥,无需手动提供。也可以选择提供该密钥,请参阅 :ref:`secure-boot-reflashable`。在启用安全启动之前,存储该密钥的 eFuse 受到读取和写入保护,防止软件访问。 + + - eFuse 块 2 默认编码方案为 ``None``,块中存储了一个 256 位密钥。在某些版本的 {IDF_TARGET_NAME} 上,编码方案设置为 ``3/4 Encoding``,CODING_SCHEME eFuse 值为 1,且块中必须存储一个 192 位密钥。 + + .. only:: esp32 + + 详情请参阅 *{IDF_TARGET_NAME} 技术参考手册* > *eFuse 控制器 (EFUSE)* > *系统参数 coding_scheme* [`PDF <{IDF_TARGET_TRM_CN_URL}#efuse>`__]. + + 算法始终使用 256 位密钥进行操作。对于 192 位密钥,则通过重复某些位来将其扩展至 256 位,请参阅 :ref:`secure-bootloader-digest-algorithm`。 + +- ``secure boot signing key`` 是标准的 ECDSA 公钥/私钥对,以 PEM 格式存储,请参阅 :ref:`secure-boot-image-signing-algorithm`。 + + - 该密钥对的公钥用于验证签名,但不用于创建签名。它编译到软件引导加载程序中,并在启动继续前验证启动过程的第二阶段,包括分区表和应用程序镜像。该公钥可以自由分发,无需保密。 + + - 该密钥对的私钥必须严格保密。一旦持有该私钥,即可用它对配置了安全启动和匹配公钥的引导加载程序进行身份验证。 + + +引导加载程序大小 +------------------- + +启用安全启动和/或 flash 加密都会增加引导加载程序的大小,因此可能需要更新分区表偏移量,请参阅 :ref:`bootloader-size`。 + + +.. _secure-boot-how-to: + +启用安全启动 +------------------------- + +1. 打开 :ref:`project-configuration-menu`,在 ``Secure Boot Configuration`` 中选择 ``One-time Flash`` 选项。如果要了解备选的 ``Reflashable`` 选项,请参阅 :ref:`secure-boot-reflashable`。 + +2. 为安全启动签名密钥选择名称。此选项将在启用安全启动后出现,密钥文件可以存放在系统的任何位置。如果使用相对路径,系统将基于项目目录确认该路径指向的实际位置。注意,无需在命名前准备好密钥文件。 + +3. 根据需要设置其他 menuconfig 选项。需注意,``Bootloader Config`` 选项对应的引导加载程序仅支持烧录一次。随后,退出 menuconfig 并保存配置。 + +4. 初次运行 ``idf.py build`` 时,如果找不到签名密钥,将打印错误信息,并提供一个通过 ``espsecure.py generate_signing_key`` 生成签名密钥的命令。 + +.. important:: + + 由此方法生成的签名密钥将使用操作系统及其 Python 安装中提供的最佳随机数源,在 OSX/Linux 上为 `/dev/urandom`,在 Windows 上为 `CryptGenRandom()`。此随机数源的安全性将会直接影响私钥的强度。 + +.. important:: + + 在生产环境下,建议使用 OpenSSL 或其他行业标准的加密程序生成密钥对,详情请参阅 :ref:`secure-boot-generate-key`。 + +5. 运行 ``idf.py bootloader`` 构建启用了安全启动的引导加载程序,构建输出中包含一个使用 ``esptool.py write_flash`` 烧录命令的提示。 + +.. _secure-boot-resume-normal-flashing: + +6. 准备就绪后,运行上述命令并等待烧录完成。注意,此处的指定命令需要手动输入,构建系统不会执行此过程。**注意,完成该一次性烧录后,不支持再对引导加载程序进行任何修改**。 + +7. 运行 ``idf.py flash`` 构建并烧录分区表和刚刚构建的应用程序镜像。应用程序镜像将使用在步骤 4 中生成的签名密钥签名。 + +.. note:: + + 如果启用了安全启动,``idf.py flash`` 不会烧录引导加载程序。 + +8. 重置 {IDF_TARGET_NAME} 以启动烧录的软件引导加载程序。该软件引导加载程序会在芯片上启用安全启动,验证应用程序镜像签名,并启动应用程序。请查看 {IDF_TARGET_NAME} 的串行控制器输出,确保已启用安全启动,且没有因构建配置发生错误。 + +.. note:: + + 为避免在系统配置完成前发生意外情况,仅当有效的分区表和应用程序镜像烧录成功后,才会启用安全启动。 + +.. note:: + + 如果在初次启动过程中重置或关闭了 {IDF_TARGET_NAME},它会在下次启动时重新开始上述步骤。 + +9. 在后续启动过程中,安全启动硬件将使用安全引导加载程序密钥验证软件引导加载程序是否更改,随后,软件引导加载程序将使用安全启动签名密钥的公钥部分来验证已签名的分区表和应用程序镜像。 + + +.. _secure-boot-reflashable: + +可重复烧录的软件引导加载程序 +------------------------------- + +对于生产设备,推荐使用 ``Secure Boot: One-Time Flash`` 配置。该模式下,每个设备都对应拥有始终存储在设备内部的唯一密钥。 + +除上述配置外,也可选择 :ref:`CONFIG_SECURE_BOOTLOADER_MODE` 模式。在该备选模式下,可以提供一个二进制密钥文件作为安全引导加载程序密钥。此时,可以生成新的引导加载程序镜像,并为这些镜像生成安全启动摘要。 + +在 ESP-IDF 构建过程中,该 256 位密钥文件派生自用户生成的 ECDSA 应用程序签名密钥,请参阅下文的 :ref:`secure-boot-generate-key` 步骤。该私钥的 SHA-256 摘要用作 eFuse 中的安全引导加载程序密钥,如果编码方案为 ``None``,则使用完整的 256 位密钥;如果编码方案为 ``3/4 Encoding``,则将密钥截断为 192 字节。这样一来,只需要生成或保护单个密钥文件。 + +.. note:: + + 尽管该方案可行,但在生产环境中,强烈建议不要仅生成一个安全引导加载程序密钥并将其烧录到每个设备上。推荐使用 ``One-Time Flash`` 选项。 + +请按以下步骤启用可重复烧录的引导加载程序: + +1. 在 :ref:`project-configuration-menu` 中,选择 ``Bootloader Config`` > :ref:`CONFIG_SECURE_BOOT` > ``CONFIG_SECURE_BOOT_V1_ENABLED`` > :ref:`CONFIG_SECURE_BOOTLOADER_MODE` > ``Reflashable``。 + +2. 如有需要,按照设备使用的编码方案设置 :ref:`CONFIG_SECURE_BOOTLOADER_KEY_ENCODING`。编码方案将在 ``esptool.py`` 连接到芯片时显示在 ``Features`` 行中,或在 ``espefuse.py summary`` 输出中显示。 + +3. 请按 :ref:`secure-boot-generate-key` 中的步骤生成签名密钥。生成的密钥文件路径必须在 ``Secure Boot Configuration`` 菜单中指定。 + +4. 运行 ``idf.py bootloader`` 将创建一个二进制密钥文件,该文件派生自用于签名的私钥。同时将打印两组烧录步骤。第一组步骤包括一个 ``espefuse.py burn_key secure_boot_v1 path_to/secure-bootloader-key-xxx.bin`` 命令,用于将引导加载程序密钥写入 eFuse,此密钥仅可烧录一次。第二组步骤可使用预计算的摘要重新烧录引导加载程序,该摘要在构建过程中生成。 + +5. 从 :ref:`一次性烧录步骤 6 ` 继续,烧录引导加载程序并启用安全启动。请密切监视控制器日志输出,确保安全启动配置正确无误。 + + +.. _secure-boot-generate-key: + +生成安全启动签名密钥 +---------------------------------- + +构建系统将提供一个命令,用于通过 ``espsecure.py generate_signing_key`` 生成新的签名密钥。这个命令使用 python-ecdsa 库,而该库则使用 Python 的 ``os.urandom()`` 作为随机数源。 + +签名密钥的强度取决于系统的随机数源和所用算法的正确性。对于生产设备,建议从具有高质量熵源的系统生成签名密钥,并使用最佳的可用 EC 密钥生成工具。 + +例如,可以采用以下 OpenSSL 命令行生成签名密钥: + +.. code-block:: + + openssl ecparam -name prime256v1 -genkey -noout -out my_secure_boot_signing_key.pem + +注意,安全启动系统的强度取决于能否保持签名密钥的私密性。 + + +.. _remote-sign-image: + +远程镜像签名 +------------------------ + +生产构建中,建议使用远程签名服务器,而非将签名密钥存储在构建机器上,这也是默认的 ESP-IDF 安全启动配置。可以使用命令行工具 ``espsecure.py`` 在远程系统上为应用程序镜像和分区表数据签名,供安全启动使用。 + +使用远程签名时,请禁用选项 ``Sign binaries during build``。此时,签名私钥无需存在于构建系统,但签名公钥必须存在,它会编译到引导加载程序中,并在 OTA 更新期间验证镜像签名。 + +可以采用以下命令从私钥中提取公钥: + +.. code-block:: + + espsecure.py extract_public_key --keyfile PRIVATE_SIGNING_KEY PUBLIC_VERIFICATION_KEY + +请在 ``Secure boot public signature verification key`` 下的 menuconfig 中指定公共签名验证密钥的路径,构建安全引导加载程序。 + +构建完应用程序镜像和分区表后,构建系统会使用 ``espsecure.py`` 打印签名步骤: + +.. code-block:: + + espsecure.py sign_data --keyfile PRIVATE_SIGNING_KEY BINARY_FILE + +上述命令将镜像签名附加到现有的二进制文件中,可以使用 `--output` 参数将签名后的二进制文件写入单独的文件: + +.. code-block:: + + espsecure.py sign_data --keyfile PRIVATE_SIGNING_KEY --output SIGNED_BINARY_FILE BINARY_FILE + + +使用安全启动的建议 +-------------------------- + +* 在具备高质量熵源的系统上生成签名密钥。 +* 时刻对签名密钥保密,泄漏此密钥将危及安全启动系统。 +* 不允许第三方查看 ``espsecure.py`` 进行密钥生成或签名过程的任何细节,因为这样容易受到定时或其他侧信道攻击的威胁。 +* 在安全启动配置中启用所有安全启动选项,包括 flash 加密、禁用 JTAG、禁用 BASIC ROM 解释器和禁用 UART 引导加载程序的加密 flash 访问。 +* 结合 :doc:`flash-encryption` 使用安全启动,防止本地读取 flash 内容。 + + +.. _secure-boot-technical-details: + +技术细节 +----------------- + +以下小节包含安全启动元件的详细参考描述: + + +.. _secure-boot-hardware-support: + +安全启动硬件支持 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +安全启动验证的第一阶段为检查软件引导加载程序,该检查通过硬件完成。{IDF_TARGET_NAME} 的安全启动支持硬件提供以下三种基本操作: + +1. 通过硬件随机数生成器生成一系列随机字节。 + +2. 使用存储在 eFuse 块 2 中的密钥生成数据摘要,通常是从 flash 中提取的引导加载程序镜像。eFuse 中的密钥可以且应设置为读取和写入保护,防止软件访问。有关此算法的完整详细信息,请参阅 `安全引导加载程序摘要算法`_。只有在 eFuse ABS_DONE_0 **未** 烧录,即仍为 0 时,才能通过软件读取摘要。 + +3. 使用与步骤 2 相同的算法从数据中生成摘要,该数据通常是从 flash 中提取的引导加载程序镜像,然后比较生成的摘要与 buffer 中提供的预计算摘要,预计算摘要通常从 flash 偏移 0x0 处读取。硬件返回一个 true/false 的比较结果,无需向软件提供摘要。即使 eFuse ABS_DONE_0 已经烧录,此功能依旧可用。 + + +.. _secure-bootloader-digest-algorithm: + +安全引导加载程序摘要算法 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +输入二进制数据镜像,该算法会生成并输出摘要 (digest),此摘要在硬件文档中有时也称摘要 (abstract)。 + +请前往 :component:`/esptool_py` 目录,查看 ``espsecure.py`` 工具,了解算法使用的 Python 版本。具体而言,请查看 ``digest_secure_bootloader`` 命令。 + +以下带有 (^) 标记的项目用于满足硬件限制,而非密码学限制。 + +1. 以反向字节顺序从 eFuse 块 2 中读取 AES 密钥。如果编码方案设置为 ``3/4 Encoding``,请使用与 :ref:`flash-encryption-algorithm` 中描述的算法相同的算法,将 192 位密钥扩展到 256 位。 +2. 给镜像添加 128 位随机生成的 IV 前缀。 +3. 如果镜像长度不是 128 的倍数,则使用 0xFF 将镜像填充至恰为 128 字节的倍数。(^) +4. 对于输入镜像的每个 16 字节明文块: + + - 反转明文输入块的字节顺序。(^) + - 将 AES256 以 ECB 模式应用于明文块。 + - 反转密文输出块的字节顺序。(^) + - 将其追加到总体密文输出。 + +5. 对密文中的每个 4 字节字进行字节交换。(^) +6. 计算密文的 SHA-512 摘要。 +7. 对上述计算得到的摘要中的每个 4 字节字进行字节交换。(^) + +输出摘要为 192 字节的数据:128 字节的 IV,后跟 64 字节的 SHA-512 摘要。 + + +.. _secure-boot-image-signing-algorithm: + +镜像签名算法 +~~~~~~~~~~~~~~~~~~~~~~~ + +按照 `RFC 6979 `_ 中的规定,指定确定性的 ECDSA。 + +- 使用 NIST256p 曲线。OpenSSL 将此曲线称为 prime256v1,有时也称 secp256r1。 +- 哈希函数采用 SHA256。 +- 用于存储的密钥格式为 PEM。 + + - 在引导加载程序中,用于签名签证的公钥作为 64 个原始字节烧录。 + +- 镜像签名为 68 字节:4 字节的版本号(当前为 0),后跟 64 字节的签名数据。这 68 字节会添加到应用程序镜像或分区表数据末尾。 + + +手动命令 +~~~~~~~~~~~~~~~ + +安全启动已集成到 ESP-IDF 构建系统中,因此若启用了安全启动,``idf.py build`` 将自动签名应用程序镜像。如果 menuconfig 配置了相应选项,``idf.py bootloader`` 将生成引导加载程序摘要。 + +然而,也可以使用 ``espsecure.py`` 工具生成独立的签名和摘要。 + +可以使用以下命令进行二进制镜像签名: + +.. code-block:: + + espsecure.py sign_data --keyfile ./my_signing_key.pem --output ./image_signed.bin image-unsigned.bin + +keyfile 是包含 ECDSA 签名私钥的 PEM 文件。 + +可以使用以下命令生成引导加载程序摘要: + +.. code-block:: + + espsecure.py digest_secure_bootloader --keyfile ./securebootkey.bin --output ./bootloader-digest.bin build/bootloader/bootloader.bin + +keyfile 是设备的 32 字节原始安全启动密钥。 + +``espsecure.py digest_secure_bootloader`` 命令的输出是一个包含摘要和附加的引导加载程序的独立文件。可以使用以下命令将合并的摘要和引导加载程序烧录到设备上: + +.. code-block:: + + esptool.py write_flash 0x0 bootloader-digest.bin + + +.. _secure-boot-and-flash-encr: + +安全启动 & flash 加密 +------------------------------ + +如果使用安全启动时没有启用 :doc:`flash-encryption`,可能会发生 ``time-of-check to time-of-use`` 攻击,即在验证并运行镜像后交换 flash 内容。因此,建议同时使用这两个功能。 + + +.. _signed-app-verify: + +在未启用硬件安全启动时验证已签名的应用程序 +---------------------------------------------------- + +即使没有启用硬件安全启动选项,也可以检查应用程序的完整性。这种方法使用与硬件安全启动相同的应用程序签名方案,但与硬件安全启动不同的是,它不会阻止引导加载程序的物理更新。这意味着设备可以防止远程网络访问,但无法阻止物理访问。与使用硬件安全启动相比,不使用硬件安全启动更加简单。具体操作请参阅 :ref:`signed-app-verify-how-to`。 + +应用程序可以在更新时验证,也可以在启动时验证。 + +- 更新时验证:启用此选项后,每当使用 ``esp_ota_ops.h`` API 执行 OTA 更新,系统都会自动检查签名。如果启用硬件安全启动,则此选项保持启用且无法禁用。如果未启用硬件安全启动,仍然可以通过启用此选项更好地防护网络攻击,防止伪造 OTA 更新。 + +- 启动时验证:启用此选项后,引导加载程序会编译代码,验证应用程序在启动前是否已签名。如果启用硬件安全启动,则此选项保持启用且无法禁用。如果未启用安全启动,该选项本身无法更好地防护网络攻击,因此多数用户会保持禁用该选项。 + + +.. _signed-app-verify-how-to: + +启用已签名的应用程序验证 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1. 打开 :ref:`project-configuration-menu` > ``Security features`` > 启用 :ref:`CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT`。 + +2. 启用 ``Bootloader verifies app signatures``,在启动时验证应用程序。 + +3. 默认情况下,选择 ``Require signed app images`` 选项将启用 ``Sign binaries during build`` 功能,该功能会在构建过程中对二进制文件签名。在 ``Secure boot private signing key`` 中指定的文件将用于镜像签名。 + +4. 如果禁用了 ``Sign binaries during build`` 选项,则需要在 ``Secure boot public signature verification key`` 中输入用于验证已签名图像的公钥文件路径。 + + 此时,私钥应按照 :ref:`secure-boot-generate-key` 中的说明生成;公钥验证密钥和已签名镜像应按照 :ref:`remote-sign-image` 中的说明生成。 + + +进阶功能 +----------------- + +JTAG 调试 +~~~~~~~~~~~~~~ + +启用安全启动模式时,eFuse 会默认禁用 JTAG。初次启动时,引导加载程序即禁用 JTAG 调试功能,并启用安全启动模式。 + +有关在启用安全启动或已签名应用程序验证的情况下使用 JTAG 调试的更多信息,请参阅 :ref:`jtag-debugging-security-features`。