Enabling Secure Boot V2 on ESP32 Platforms in Development

In this post we talk about how to enable Secure Boot V2 on ESP32* platforms and provide links to Thistle’s developer tools to make secure boot enablement and firmware signing in development a “one-click” process. This is the first of a series of two blog posts about ESP32* secure boot enablement. For a guide on how to enable Secure Boot V2 in production, click here.

Introduction to Secure Boot

Secure boot is a boot sequence on a hardware device in which each software (aka firmware) image loaded is authorized to execute using software previously authorized by this system.

The sequence is designed to prevent unauthorized or modified code from being run by ensuring that all code is checked before it's executed, during device boot-up time.

The authorization is normally done through attestation of one or more valid digital signatures associated with the firmware image.

The first piece of software in the boot sequence that performs such image attestation is called a root of trust (RoT). Usually, when people talk about "secure boot", the RoT is part of a chipset's hardware, e.g., in read-only memory (ROM). As a corollary, secure boot (with hardware-based RoT) needs hardware support.

For a secure boot mechanism to be effective, once enabled on a device, it shall not be possible to turn it off. For this reason, secure boot enablement is usually done by configuring one-time programmable (OTP) memory, e.g., eFuse.

A secure boot enabled device runs only signed firmware images, which makes secure boot a fundamental hardware security countermeasure against malware persistence. This countermeasure is strong if and only if the firmware signing keys are secure.

Secure Boot Enablement: As mentioned above, secure boot requires hardware support. On hardware supporting secure boot, the process to enable secure boot is normally as follows.

  • Create and manage firmware signing keys or a public-key infrastructure (PKI)

  • Program (aka, "blow") eFuse to configure the RoT and device security parameters

  • Properly sign firmware images to run on fuse-blown devices, using a signing infrastructure

ESP32: Secure Boot V2 (SBV2)

ESP32 platforms (e.g., ESP32, ESP32-S, ESP32-C, ESP32-H2 series) support secure boot with a hardware-based root-of-trust: The first stage bootloader is in ROM, which uses a verification key anchored in eFuse to authorize the second-stage, firmware bootloader. The preferred secure boot scheme is Secure Boot V2 (SBV2).

Secure Boot V2 is largely available on ESP32 series, ESP32-S series, ESP32-C series and ESP32-H series - on certain chipsets, SBV2 is only available in newer revisions (e.g., ESP32 ECO3 onward, ESP32-C3 ECO3 onward). SBV2 employs digital signatures (RSA-PSS- or ECDSA-based) for bootloader and app firmware authorization. As of today (July 2023), RSA-PSS is more widely supported for SBV2 among ESP32 chipsets, and is the SBV2 digital signature algorithm available on chipsets Thistle currently provides support for: ESP32, ESP32-S2, and ESP32-S3. In the rest of this blog post, we will only talk about RSA-PSS as the SBV2 digital signature.

ESP32 SBV2 supports at least the following two boot flows, with different bootloader and app firmware bundle types:

1. ESP-IDF

ESP32 secure boot flow: ESP-IDF

ESP32 Secure Boot Flow: ESP-IDF

  • This firmware bundle type consists of an IDF bootloader image as the 2nd-stage bootloader, and FreeRTOS-based IDF application images

  • The (first-stage) ROM bootloader authorizes the (second-stage) IDF bootloader using an RSA-3072-PSS public-key hash (PK_HASH) burned in eFuse

  • Once authorized to execute, the IDF bootloader authorizes a FreeRTOS-based application image using the fused PK_HASH, with RSA-3072-PSS

2. MCUboot/ZephyrOS

ESP32 secure boot flow: ZephyrOS+MCUboot

ESP32 Secure Boot Flow: ZephyrOS/MCUboot

  • This firmware bundle type consists of an MCUboot image as the 2nd-stage bootloader, and ZephyrOS-based application images. Note that MCUboot supports a number of RTOSes, and a similar secure boot workflow can be enabled for other firmware bundle types with MCUboot. Currently, Thistle’s solution only supports the MCUboot/ZephyrOS firmware bundle type.

  • The (first-stage) ROM bootloader authorizes the (second-stage) MCUboot bootloader using the RSA-3072-PSS public-key hash (PK_HASH) burned in eFuse

  • Once authorized to execute, the MCUboot bootloader verifies a ZephyrOS-based application image using an ECDSA-P256 public key embedded in the already authorized MCUboot bootloader image

How to Enable SBV2

Generally speaking, the steps to enable Secure Boot V2 on an ESP32 platform and maintain this state are as follows.

  1. Generate firmware signing key(s). This is usually a one-time effort during the lifecycle of a type of devices.

    • The two digital signature schemes Thistle's solution supports are RSA-3072-PSS and ECDSA-P256, which have good ecosystem support, and thus maximize interoperability while ensuring cryptography strength. Therefore, one can use software tools, e.g., OpenSSL and espsecure.py, and a key management system (KMS), e.g., AWS KMS, GCP KMS, and hardware security modules (HSMs).

  2. Determine eFuse configuration and get eFuse bits blown. This is usually a one-time effort.

    • One can turn on SBV2 and other hardware security features by manually computing and blowing eFuse bit using the espefuse.py tool. While it provides more flexibility and allows for more advanced eFuse configurations, we found this approach more error-prone, and more cumbersome to setup during manufacturing testing. Therefore, we don't recommend it.

    • Our preferred method to blow eFuse for SBV2 enablement is to sign a bootloader and app image bundle with the desired private key, and flash the signing images (together with a valid partition table) to the unfused unit. On first successful boot, eFuse bits will be blown by the IDF bootloader to enable SBV2. This way, eFuse blowing and image flashing can also be combined into one step during manufacturing. With this method, SBV2 eFuse configuration is reduced to the problem of firmware signing.

  3. Sign firmware using the firmware signing key(s). This is an on-going effort that is required for each new firmware release.

In all the above three steps, the firmware signing keys plays an important role. Firmware signing keys need to be appropriately managed, depending on the security requirements. In this regard, Thistle recommends to distinguish two scenarios: key management in development and in production.

If one would like to have SBV2 enabled on production devices, it's a good idea to perform firmware development and testing on SBV2-enabled development units. Ideally, production firmware should be a nearly faithful mirror of development firmware, where the two differ only in bits associated with public keys and signatures.

Production and development firmware should be similar, so that after development testing is completed, a minimum level of additional testing would be needed on production firmware. Production and development firmware should be signed with different keys, because the security and operational requirements on them are different.

  • Development signing: Development firmware is typically flashed onto only a handful devices during earlier phases of hardware development. Signing key confidentiality in this case is usually not crucial, because development hardware is supposed to be physically more tightly controlled, and not not plugged into production systems. The development signing process should be easy to allow fast feedback loops.

  • Production signing: Production firmware runs on production devices, which usually ship in large volumes, and are used in the real world by end users. For this reason, production signing keys are typically highly confidential, and shall not be exposed to software or human operators. The production signing process in many cases should be easy to allow fast firmware releases.

In the rest of this blog post, we will talk about the practices to sign ESP32 SBV2 firmware images in development, and how to make the development signing process effortless.

Firmware Signing in Development

The void app: The void app is an IDF application provided by Thistle that does not do anything useful by itself - it simply prints out a self-introductory message to the console. However "useless", it generates firmware images that can be flashed on an ESP32 chip to blow security related eFuse bits. Being a minimum application, the void app eliminates attack surfaces to the device, which is a particularly useful property in production scenarios.

The void app source code

Because development signing keys are not security critical, file-based private keys can be used. For the "ESP-IDF" secure boot flow, the "fuseblower" firmware images can be created in the following steps.

  • Key generation. With OpenSSL

# Generate private key
openssl genrsa -out sbv2_private_dev.pem 3072
# Extract public key
openssl rsa -in sbv2_private_dev.pem -pubout > sbv2_public_dev.pem

The private key file sbv2_private_dev.pem will be inserted into the build system to sign firmware images during builds.

  • Build configuration. Invoke idf.py menuconfig in the project directory of the "void app", and select the options to enable SBV2, configure the private signing key file path as well as other hardware security features - most notably, disabling JTAG, and enabling secure ROM download mode (this option is only available for ESP32-S2 and ESP32-S3 among Thistle currently supported platforms).

idf.py menuconfig
  • Because a signed bootloader image is larger compared to an unsigned one, one may also need to adjust (increase) the offset of the partition table in flash for the signed bootloader to fit.

Partition table offset
  • Once we are done with menuconfig, save the "sdkconfig" file for building and signing firmware in iterations.

  • Sign firmware in build system. Invoke idf.py build from the project directory of the void app, with the saved "sdkconfig" in the last step, It builds a bootloader image and an app image, and signs them using the configured private key file. The IDF bootloader and app images created in this way are called "fuseblower" images, because they can be flashed to an unfused ESP32 unit to get eFuse blown to enable SBV2.

One-click SBV2 Signing

After the private signing key and "sdkconfig" files are generated and saved, they can be used as inputs to an automated build system to build and sign ESP-IDF firmware images for SBV2, for each software iteration during development and in CI. Because the development key and "sdkconfig" files are not security critical, they often can be checked into a version control system for easy access and backup.

Thistle has released developer tools on GitHub including Dockerfiles, utility apps and pre-built Docker images to allow 1-click firmware signing in development. For example, the following command can be used to build and sign ESP32 bootloader and app images for secure boot eFuse blowing. Overridable build arguments make it possible to use custom "sdkconfig" and private key files to generate signed firmware.

cd esp32/ && docker build -f Dockerfile.esp32_fuseblower -t esp32fb:dev \
--build-arg IDF_SDKCONFIG=sdkconfig.sbv2_nojtag \
--build-arg SBV2_PRIVATE_KEY=sbv2_private_dev.pem \
.

In addition to signing an ESP-IDF firmware bundle, Thistle also implemented a similar 1-click approach for signing a MCUboot/ZephyrOS firmware bundle. Interested readers may want to peruse the thistletech/esp32-devenvs repository for instructions to use the tool.

Although a few ESP32 chipsets (e.g., ESP32-S2 and ESP32-S3) support multiple SBV2 signing keys as well as a couple of key revocation flavors, our SBV2 setup doesn't use these features. This is a design choice that strives for simplicity - because development signing keys are not security critical, it's rarely necessary to revoke them.

In the next blog post, we will discuss how to enable SBV2 on ESP32 platforms in production, where highly confidential signing keys are managed in a key management system.

Previous
Previous

Enabling Secure Boot V2 on ESP32 Platforms in Production

Next
Next

Thistle-Infineon Technology Partnership Brings More Security Capabilities to Developers