ESP32 Secure Boot - Your code only runs on your own hardware?
-
- Posts: 11
- Joined: Sat Oct 14, 2017 6:31 am
ESP32 Secure Boot - Your code only runs on your own hardware?
Hi all,
New to ESP32. I am reading the Secure Boot section on the ESP-IDF docs: https://docs.espressif.com/projects/esp ... -boot.html
The guide begins with the statement "Secure Boot is a feature for ensuring only your code can run on the chip. Data loaded from flash is verified on each reset." Understood. Is it possible to use ESP32's h/w encryption features to also ensure that our firmware only runs on our own h/w? Meaning, if someone counterfeits the hardware, but if they don't have the correct keys programmed into the ESP32 OTP, the firmware would refuse to run on counterfeit hardware.
We have not started building the hardware so we want to explore this area without say using Microchip ATSHA204 or something external.
New to ESP32. I am reading the Secure Boot section on the ESP-IDF docs: https://docs.espressif.com/projects/esp ... -boot.html
The guide begins with the statement "Secure Boot is a feature for ensuring only your code can run on the chip. Data loaded from flash is verified on each reset." Understood. Is it possible to use ESP32's h/w encryption features to also ensure that our firmware only runs on our own h/w? Meaning, if someone counterfeits the hardware, but if they don't have the correct keys programmed into the ESP32 OTP, the firmware would refuse to run on counterfeit hardware.
We have not started building the hardware so we want to explore this area without say using Microchip ATSHA204 or something external.
Re: ESP32 Secure Boot - Your code only runs on your own hardware?
Yes, with secure boot and flash encryption someone can't obtain the raw binary as long as you also distribute your ota updates in encrypted form. Also the recommended configuration is to use unique per device flash encryption keys so a flash dump won't even run on another authentic device.
-
- Posts: 11
- Joined: Sat Oct 14, 2017 6:31 am
Re: ESP32 Secure Boot - Your code only runs on your own hardware?
Thanks for your response. Just wondering if we distribute encrypted firmware for serial flashing (no OTA, Wifi will be off on this device), would that be ok?WiFive wrote:Yes, with secure boot and flash encryption someone can't obtain the raw binary as long as you also distribute your ota updates in encrypted form. Also the recommended configuration is to use unique per device flash encryption keys so a flash dump won't even run on another authentic device.
Re: ESP32 Secure Boot - Your code only runs on your own hardware?
If your app implements a secure serial update process (ota over uart)
Re: ESP32 Secure Boot - Your code only runs on your own hardware?
Do you need to flash in the field updates, or only once in the factory?fermienrico wrote: Thanks for your response. Just wondering if we distribute encrypted firmware for serial flashing (no OTA, Wifi will be off on this device), would that be ok?
If only once, the default Secure Boot & Flash Encryption will be enough.
If you need to be able flash updates over serial, take a look at the "Reflashable" options for flash encryption:
https://docs.espressif.com/projects/esp ... ption.html
To flash an update over serial, you'll need the flash encryption key for the device you're updating in order to pre-encrypt the app which is being flashed on that device. The app will also need to be signed with the secure boot signing key, or the bootloader will refuse to boot it.
Re: ESP32 Secure Boot - Your code only runs on your own hardware?
Hi @ESP_Angus,
I have a quite similar situation. I have implemented OTA from SD card. The BIn file can be downloaded by esp32 or customer can transfer from their pc to an sd card and then my program will do the upgrade with esp_ota_write api. Already tested and it works.
Now i want to encrypt flash to protect the code(no secure boot probably). My question is: in case of upgrade i will send the bin file(i guess encrypted) to customer. Does esp_ota_write work with encrypted bin file? From docs i didn't understand.
Secknd question: i think we cannot use per-device encryption key because we can't know the key of every device when updates are sent to customer, so we will generate a unique key in every device we sell. Does it work with above decription I wrote?
Thanks
I have a quite similar situation. I have implemented OTA from SD card. The BIn file can be downloaded by esp32 or customer can transfer from their pc to an sd card and then my program will do the upgrade with esp_ota_write api. Already tested and it works.
Now i want to encrypt flash to protect the code(no secure boot probably). My question is: in case of upgrade i will send the bin file(i guess encrypted) to customer. Does esp_ota_write work with encrypted bin file? From docs i didn't understand.
Secknd question: i think we cannot use per-device encryption key because we can't know the key of every device when updates are sent to customer, so we will generate a unique key in every device we sell. Does it work with above decription I wrote?
Thanks
Re: ESP32 Secure Boot - Your code only runs on your own hardware?
The ESP-IDF OTA update API assumes that the data it writes is in plaintext. Any protection done to it while it's "in transit" (ie HTTPS, Bluetooth pairing & encryption) is separate from the protection done while it's "at rest" (ie flash encryption).davdav wrote:Hi @ESP_Angus,
I have a quite similar situation. I have implemented OTA from SD card. The BIn file can be downloaded by esp32 or customer can transfer from their pc to an sd card and then my program will do the upgrade with esp_ota_write api. Already tested and it works.
Now i want to encrypt flash to protect the code(no secure boot probably). My question is: in case of upgrade i will send the bin file(i guess encrypted) to customer. Does esp_ota_write work with encrypted bin file? From docs i didn't understand.
This is largely designed this way so that each device can have a unique flash encryption key, without needing to pre-encrypt each firmware image specifically for each device.
There are at least three possible approaches you could take:
- Pre-generate and store the encryption key for each device and use espsecure.py to encrypt per-device binaries. Then make a copy of the app_update component and modify esp_ota_write() to call the "plain" SPI flash write function rather than the "automatically encrypt in place" esp_partition_write() function, so the encrypted bytes are written verbatim to the flash rather than being double-encrypted.
- As above, but use the same encryption key for all devices. This is less secure, because a leak of the encryption key will compromise all devices. You'll have to consider your own circumstances to know if this is OK.
- Compile a separate "OTA update key" into the app (can embed directly) and use this with the mbedTLS APIs to decrypt and verify an encrypted OTA binary from the SD Card. This way the binary can be the same for all devices. Unfortunately I don't know of a good off-the-shelf file encryption format or library, you'll need to research a good encryption scheme for your purposes.
This is a little more secure than sharing the same flash encryption key for all devices, because you can still "revoke" a leaked firmware update key and OTA update (using the old key) with a new app that uses a new firmware update key from then on.
Re: ESP32 Secure Boot - Your code only runs on your own hardware?
Thanks @ESP_Angus.
In our case, distributing the bin file in plaintext means to "donate" the original code and for sure it is not an option. Therefore I'm going to follow your 2nd suggestion.
Is it sufficient to "delete" the last "if (partition->encrypted)", i.e. a function like this?
Thanks
Just to understand better: flash encryption is robust only in case someone reads the physical flash. In case you do the FOTA over WiFI, for example, if someone sniffs the WiFi the plaintext file can be retrieved (unless you use HTTPS I guess): is it right?The ESP-IDF OTA update API assumes that the data it writes is in plaintext. Any protection done to it while it's "in transit" (ie HTTPS, Bluetooth pairing & encryption) is separate from the protection done while it's "at rest" (ie flash encryption).
This is largely designed this way so that each device can have a unique flash encryption key, without needing to pre-encrypt each firmware image specifically for each device.
In our case, distributing the bin file in plaintext means to "donate" the original code and for sure it is not an option. Therefore I'm going to follow your 2nd suggestion.
I have checked the app_update component and esp_partition_write() API in spi_flash/partition.c....Then make a copy of the app_update component and modify esp_ota_write() to call the "plain" SPI flash write function rather than the "automatically encrypt in place" esp_partition_write() function, so the encrypted bytes are written verbatim to the flash rather than being double-encrypted.
Code: Select all
esp_err_t esp_partition_write(const esp_partition_t* partition,
size_t dst_offset, const void* src, size_t size)
{
assert(partition != NULL);
if (dst_offset > partition->size) {
return ESP_ERR_INVALID_ARG;
}
if (dst_offset + size > partition->size) {
return ESP_ERR_INVALID_SIZE;
}
dst_offset = partition->address + dst_offset;
if (partition->encrypted) {
return spi_flash_write_encrypted(dst_offset, src, size);
} else {
return spi_flash_write(dst_offset, src, size);
}
}
Code: Select all
esp_err_t esp_partition_write_NOENCRYPT(const esp_partition_t* partition,
size_t dst_offset, const void* src, size_t size)
{
assert(partition != NULL);
if (dst_offset > partition->size) {
return ESP_ERR_INVALID_ARG;
}
if (dst_offset + size > partition->size) {
return ESP_ERR_INVALID_SIZE;
}
dst_offset = partition->address + dst_offset;
return spi_flash_write(dst_offset, src, size);
}
Yes I'm aware of this.Note that if using flash encryption without secure boot, it's important to write-protect the FLASH_CRYPT_CNT efuse in production. More details here: https://docs.espressif.com/projects/esp ... ecure-boot
Thanks
Re: ESP32 Secure Boot - Your code only runs on your own hardware?
Hello @ESP_Angus,
Sorry to bump this thread.
This is the last tile of the puzzle, before we can start develloping production tools and automation.
Thanks
Sorry to bump this thread.
Can you please confirm that the implementation of esp_partition_write() modified to send pre-generated encrypted binary via OTA (over SD card in our case) is OK?Then make a copy of the app_update component and modify esp_ota_write() to call the "plain" SPI flash write function rather than the "automatically encrypt in place" esp_partition_write() function, so the encrypted bytes are written verbatim to the flash rather than being double-encrypted.
Code: Select all
esp_err_t esp_partition_write_NOENCRYPT(const esp_partition_t* partition,
size_t dst_offset, const void* src, size_t size)
{
assert(partition != NULL);
if (dst_offset > partition->size) {
return ESP_ERR_INVALID_ARG;
}
if (dst_offset + size > partition->size) {
return ESP_ERR_INVALID_SIZE;
}
dst_offset = partition->address + dst_offset;
return spi_flash_write(dst_offset, src, size);
}
This is the last tile of the puzzle, before we can start develloping production tools and automation.
Thanks
Re: ESP32 Secure Boot - Your code only runs on your own hardware?
Yes, this looks correct. We can probably add this (as an option in the app_update component) in a future IDF release, but this approach will work for now.davdav wrote:Then make a copy of the app_update component and modify esp_ota_write() to call the "plain" SPI flash write function rather than the "automatically encrypt in place" esp_partition_write() function, so the encrypted bytes are written verbatim to the flash rather than being double-encrypted.
Who is online
Users browsing this forum: Majestic-12 [Bot] and 64 guests