Page 1 of 1

ESP32-S3 Secure boot+Flash Encryption - Correct procedure?

Posted: Fri May 17, 2024 9:00 am
by Crinst
Hi guys,

I have tried to enable Secure boot and Flash Encryption on ESP32-S3 for the past few days with limited success.

In the past, we have used ESP32 (ESP32-WROVER-E N16R8) in our product, where we used conbination of secure boot and flash encryption and it worked really well. We have implemented whole procedure per guide: https://docs.espressif.com/projects/esp ... flows.html and it worked as expected. But guide for ESP32-S3 (https://docs.espressif.com/projects/esp ... flows.html seems to be incomplete or faulty, because no matter what I did, it does not work as I was expecting.

For ESP32-S3, we have choosen ESP32-S3-WROOM-1 N16R8. All test were done on WROOM modules in programmer board such as https://www.aliexpress.com/item/1005006825819098.html.

Regarding ESP-IDF, I am using ESP-IDF "release\v4.4" as it's validated and working oka-ish for my use-case. On top of that I have did some fixes so moving to newer version is not priority right now.

My partition table for ESP32-S3 is below. I let partition tool calculate all offsets, I have only set first offset at 0x11000, partition table itself is located at offset 0x10000.

Code: Select all

# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs,		data,	nvs,		0x11000,	128K,
nvs_key,	data,	nvs_keys,	0x31000,	4K,
otadata,	data,	ota,		0x32000,	8K,
phy_init,	data,	phy,		0x34000,	4K,
factory,	app,	factory,	0x40000,	4M,
ota_0,		app,	ota_0,		0x440000,	4M,
ota_1,		app,	ota_1,		0x840000,	4M,
storage,	data,	spiffs,		0xc40000,	2880K,
fw_nvs_data,data,	nvs,		0xf10000,	256K,
Current state:
My workflow is as this:
1) Flash Encryption key
I flash host-generated AES-256 (512 bit) key to "BLOCK_KEY_0" with function "XTS_AES_256_KEY", which flashes to "BLOCK_KEY0" and "BLOCK_KEY1" AES-256 key.
I do this with

Code: Select all

 command = ["espefuse", "--port", COMport, "--chip", "esp32s3", "burn_key", "BLOCK_KEY0", EncryptionKeyPath, "XTS_AES_256_KEY"]
.

2) Flash public key digest for Secure boot.
I flash host-generated RSA3070 key digest to "BLOCK_KEY2" with function "SECURE_BOOT_DIGEST0".
I do this with

Code: Select all

command = ["espefuse", "--port", COMport, "--chip", "esp32s3", "burn_key", "BLOCK_KEY2", SignDigestKeyPath, "SECURE_BOOT_DIGEST0"]
3) I burn eFuses.
I have set of eFuses, which are burned in sequence as written.

Code: Select all

	*** Efuse ***					*** Val ***
	"SPI_BOOT_CRYPT_CNT"    		: "7",
	"DIS_DOWNLOAD_ICACHE"   		: "0x1",
	"DIS_DOWNLOAD_DCACHE"   		: "0x1",
	"DIS_PAD_JTAG"          		: "0x1",
	"SOFT_DIS_JTAG"         		: "0x1",
	"DIS_DIRECT_BOOT"				: "0x1",
	"DIS_USB_JTAG"   				: "0x1",
	"DIS_DOWNLOAD_MANUAL_ENCRYPT"   : "0x1",

command = ["espefuse", "--port", COMport, "--chip", "esp32s3", "burn_efuse", Efuse, Val]
subprocess.run(command, input = str("BURN").encode())
4) After these eFuses are burned, I enable secure boot, secure download mode and disable read for BLOCK4-BLOCK10 (keys).

*** Efuse *** *** Val ***
"SECURE_BOOT_EN" : "True",
"RD_DIS" : "3",
"ENABLE_SECURITY_DOWNLOAD" : "True",

For burning I send these command, in sequence as written from top to buttom.

Code: Select all

if Efuse == "ENABLE_SECURITY_DOWNLOAD":
        command = ["espefuse", "--port", COMport, "--chip", "esp32s3", "burn_efuse", "ENABLE_SECURITY_DOWNLOAD"]
    elif Efuse == "SECURE_BOOT_EN":
        command = ["espefuse", "--port", COMport, "--chip", "esp32s3", "burn_efuse", "SECURE_BOOT_EN"]
    elif Efuse == "RD_DIS":
        command = ["espefuse", "--port", COMport, "write_protect_efuse", "RD_DIS"]
    else:
        continue
        
    subprocess.run(command, input = str("BURN").encode())
NOTE: Once, I have enabled security download, I can no longer read/write any eFuse. Thats allright and expected behaviour.

5) I build binaries.

I use standard command "idf.py build" in Visual Studio code.

6) Erase whole flash memory
As security download is enabled, I was unable to use standard command "idf.py erase_flash" is ROM did not allow it. So I came up with variant that i generated fixed size bin files fulled with 0xFF values (=empty data) and write these to all relevant offsets.
This way whole address block from 0x0 up to end of factory_partition is erased.

Code: Select all

	adress = ["0x0", "0x40000"]
	binaries = ["512k_0xff_file.bin", "4096k_0xff_file.bin"]

	for i in range(0, len(binaries)):
        bins = [addresses[i], folderPath + "\\" + binaries[i]]

        command = ["esptool", "-p", COMport, "-b", "460800", "--no-stub", "--before", "default_reset", "--after", "no_reset"]
        command = command + ["--chip", "esp32s3", "write_flash", "--flash_mode", "dio"]
        command = command + ["--flash_size", "16MB", "--flash_freq", "80m"]
        command = command + bins + ["--force"]
    
        subprocess.run(command)
7) Sign binaries.

I sign all binaries (bootloader, partition table, ota_init, factory fw).

Code: Select all

command = ["espsecure", "sign_data", "--version", "2", "--keyfile", SignKeyPath, "--output", OutputBinPath, InputBinPath]
	subprocess.run(command)
8) Encryption signed binaries.

I enrypt all binaries (bootloader, partition table, ota_init, factory fw).

Code: Select all

command = ["espsecure", "encrypt_flash_data", "--aes_xts", "--keyfile", EncryptKeyPath, "--address", BinAdsress, "--output", OutputBinPath, InputBinPath]
	subprocess.run(command)
9) Flash signed and encrypted binaries.

Code: Select all

	adress = ["0x0", "0x10000", "0x40000", "0x32000"]
	binaries = ["bootloader_signed_encrypted.bin", "partition-table_signed_encrypted.bin", "esp32_evse_signed_encrypted.bin", "ota_data_initial_signed_encrypted.bin"]
	
	for i in range(0, len(binaries)):
        bins = [addresses[i], binaries[i]]

        command = ["esptool", "-p", COMport, "-b", "460800", "--no-stub", "--before", "default_reset", "--after", "no_reset"]
        command = command + ["--chip", "esp32s3", "write_flash", "--flash_mode", "dio"]
        command = command + ["--flash_size", "16MB", "--flash_freq", "80m"]
        command = command + bins + ["--force"]
    
        subprocess.run(command)
10) Controller is in bootloader and waiting for reset.
I open VSCode console and controller runs for the first time and everything works as expected. It boot in bootloader, 2nd stage bootloader and then validates successfully factory partition and runs FW as it should.
But once I reset controller, It's unable to validate factory partition checksum and start to restart in loop.

I have tried to do OTA update for this first run if it will finish and it restart with several critical erros.
I have attached below my sdkconfig and log file, where I captured correct and incorrect run for first and second boot respectively.

I have tried to validate firmware image for chechsum with command

Code: Select all

esptool image_info esp32_evse_signed.bin --version 2
It returned correct value for plaintext and signed firmware binary. For encrypted file it returned error, but this should be correct behaviour. I have tried this validation for old ESP32 flow and it produced same results.
NOTE: checksum values in log and image_info are not same as I have tried to build FW several times and captured only handful of outputs to console.

Here is output to console:

Code: Select all

esptool.py v4.6.2
File size: 1314816 (bytes)
Detected image type: ESP32-S3

ESP32-S3 image header
=====================
Image version: 1
Entry point: 0x40375594
Segments: 8
Flash size: 16MB
Flash freq: 80m
Flash mode: DIO

ESP32-S3 extended image header
==============================
WP pin: 0xee (disabled)
Flash pins drive settings: clk_drv: 0x0, q_drv: 0x0, d_drv: 0x0, cs0_drv: 0x0, hd_drv: 0x0, wp_drv: 0x0
Chip ID: 9 (ESP32-S3)
Minimal chip revision: v0.0, (legacy min_rev = 0)
Maximal chip revision: v0.0

Segments information
====================
Segment   Length   Load addr   File offs  Memory types
-------  -------  ----------  ----------  ------------
      1  0x3e574  0x3c0f0020  0x00000018  DROM
      2  0x01a7c  0x3fc975b0  0x0003e594  BYTE_ACCESSIBLE, MEM_INTERNAL, DRAM
      3  0xe1d80  0x42000020  0x00040018  IROM
      4  0x035b8  0x3fc9902c  0x00121da0  BYTE_ACCESSIBLE, MEM_INTERNAL, DRAM
      5  0x135a4  0x40374000  0x00125360  MEM_INTERNAL, IRAM
      6  0x00010  0x50000000  0x0013890c  RTC_DATA
      7  0x00028  0x600fe000  0x00138924  RTC_DRAM, RTC_IRAM
      8  0x07674  0x00000000  0x00138954  PADDING

ESP32-S3 image footer
=====================
Checksum: 0xaa (valid)
Validation hash: 554343f3cc6ca7eb9e2c6ec0926d67cac7f57ed19de081623cb64367f7d8097f (valid)

Application information
=======================
Project name: esp32_evse
App version: V1.2.2D-Litva-57-g80a89a3-dirty
Compile time: May 16 2024      18:13:31
ELF file SHA256: db3c3ef25804e68ebc8bfcd0be494376bc03e09d5dd5de0f27d6f08c547e5225
ESP-IDF: v4.4-dev-3703-gddc44956bf-dirty
Secure version: 0
Do you have any idea what I'm missing out or what is wrong? I'm slowly going crazy as I have been debugging this issue for the past week. :/ Any help appreciated.

Re: ESP32-S3 Secure boot+Flash Encryption - Correct procedure?

Posted: Thu Apr 24, 2025 12:25 pm
by lalit.shah
Hi all,

Have been doing simple hello world application on ESP32S3 with Secure Boot and Flash Encryption.

When applied only secure boot every thing works as expected.

After that enabled both Secure boot and Flash Encryption and getting compile time errors.

.espressif/tools/xtensa-esp32s3-elf/esp-2022r1-11.2.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/11.2.0/../../../../xtensa-esp32s3-elf/bin/ld.exe: bootloader.elf section `.dram0.rodata' will not fit in region `dram_seg'
.espressif/tools/xtensa-esp32s3-elf/esp-2022r1-11.2.0/xtensa-esp32s3-elf/bin/../lib/gcc/xtensa-esp32s3-elf/11.2.0/../../../../xtensa-esp32s3-elf/bin/ld.exe: region `dram_seg' overflowed by 2688 bytes
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

What configuration needs to be look at from memory perspective when Choosing Flash Encryption.

Doe's it require any changes in linker files to make it compile properly.

Any other optimization option to look at to make it work?

Regards,
Lalit

Re: ESP32-S3 Secure boot+Flash Encryption - Correct procedure?

Posted: Sat Apr 26, 2025 7:07 am
by lalit.shah
Hi All,

Any update on what may be wrong or how both Secure boot and Flash Encryption can be enabled together.

From error it looks like i got stuck at last stage and small help and guidance required to make it work.

Regards,
Lalit

Re: ESP32-S3 Secure boot+Flash Encryption - Correct procedure?

Posted: Tue May 06, 2025 7:46 am
by fanmen1
Were you able to solve this issue? I have had this same issue for a while now and nothing works, seems like nobody has come across this.

Re: ESP32-S3 Secure boot+Flash Encryption - Correct procedure?

Posted: Sat May 10, 2025 9:22 am
by lalit.shah
Hi fanmen1,

No update still struggling to make it working.

Not getting any feedback on the same.

Regards,
Lalit

Re: ESP32-S3 Secure boot+Flash Encryption - Correct procedure?

Posted: Sun May 11, 2025 11:19 pm
by adokitkat
Hello.

Can you try to follow steps I posted here? viewtopic.php?p=147367#p147367

You can then change some menuconfig settings so the build would be production ready. These steps are for debugging purposes / getting secure boot work with flash encryption.

Re: ESP32-S3 Secure boot+Flash Encryption - Correct procedure?

Posted: Wed May 14, 2025 5:15 am
by lalit.shah
Hi @adokitkat ,

Thanks for feedback.

Have gone through link provided by you. Which provide steps for enabling flash encryption and secure boot externally.

What i have followed is below link and try to achieve it internally.

https://docs.espressif.com/projects/esp ... ot-v2.html
https://docs.espressif.com/projects/esp ... ption.html

As per link shared by you that suggested to burn efuse and some digest key for secure boot as well, which is not clear when doing in locally. Would you please help us in getting it done.

Also after following above steps i am not able to read eFuse in boot loader mode as well though we have kept in development mode and UART ROM download enable.

Would you please let us know if there is any way to recover?

Have tried with QEMU emulator as well and it suggested that QEMU emulator does not support fully for Flash Encryption and secure boot.

We have got stuck at this point, your help is much appreciated to get out of this stage.

We have already burned 3 to 4 modules and can't burn more modules without clarity.

Regards,
Lalit

Re: ESP32-S3 Secure boot+Flash Encryption - Correct procedure?

Posted: Wed May 28, 2025 8:43 am
by fanmen1
Hi Lalit,

If you're still struggling, this post got it solved for me
https://github.com/espressif/esp-idf/is ... 2857474678
Turns out it is the order of flashing, do not use the basic flash command and folow the order he has given.
I tried with enabling secure boot alone and then followed it by flash encryption. It is working as expected. However, both enabled together in menuconfig still fails as before.

About burning up the modules, do it in development mode first. Also use the ESP_TX and ESP_RX pin in UART for this.

Re: ESP32-S3 Secure boot+Flash Encryption - Correct procedure?

Posted: Wed May 28, 2025 8:50 am
by fanmen1
QEMU is useless for this. I believe enabling secure boot with burning out the USB_OTG and UART to disable readouts is good enough for most of the production application. We have settled for this now. However both security features works as expected if done as described abovew but this will be extra steps for production assembly when the device is flashed using ESP flash programmer tool.