ESP32 FOTA via WiFi how to check integrity of the .bin file

zazas321
Posts: 231
Joined: Mon Feb 01, 2021 9:41 am

ESP32 FOTA via WiFi how to check integrity of the .bin file

Postby zazas321 » Wed Sep 07, 2022 8:18 am

Hello. I have created a webserver where user can select .bin file and upload to the ESP32.
When user uploads .bin file, the following function will be executed:

Code: Select all

static esp_err_t upload_and_flash_post_handler(httpd_req_t *req){
    printf("upload and flash handler \n");
    char filepath[FILE_PATH_MAX];
    const char *filename = get_path_from_uri(filepath, ((struct file_server_data *)req->user_ctx)->base_path,
                                             req->uri + sizeof("/upload") - 1, sizeof(filepath));

    // File cannot be larger than a limit 
    if (req->content_len > MAX_FILE_SIZE) {
        ESP_LOGE("UPLOAD", "File too large : %d bytes", req->content_len);
        // Respond with 400 Bad Request 
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST,
                            "File size must be less than "
                            MAX_FILE_SIZE_STR "!");
        //Return failure to close underlying connection else the
        // incoming file content will keep the socket busy 
        return ESP_FAIL;
    }



    ESP_LOGI("UPLOAD", "Receiving file : %s...", filename);

    //Retrieve the pointer to scratch buffer for temporary storage 
    
    int received;


    esp_err_t ret;
    
    const esp_partition_t *update_partition;
    const esp_partition_t *configured = esp_ota_get_boot_partition();
    const esp_partition_t *running  = esp_ota_get_running_partition();
    esp_ota_handle_t well_done_handle = 0;  // Handler for OTA update. 
    if (configured != running) {
        ESP_LOGW("UPDATE", "Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x",
                        configured->address, running->address);
        ESP_LOGW("UPDATE", "(This can happen if either the OTA boot data or preferred boot image become corrupted somehow.)"
                        );
    }
    ESP_LOGI("UPDATE", "Running partition type %d subtype %d (offset 0x%08x)",
                    running->type, running->subtype, running->address);

    ESP_LOGI("UPDATE", "Starting OTA example");
    // It finds the partition where it should write the firmware
    update_partition = esp_ota_get_next_update_partition(NULL);
    ESP_LOGI("UPDATE", "Writing to partition subtype %d at offset 0x%x",
                    update_partition->subtype, update_partition->address);
    assert(update_partition != NULL);
    
    // Reset of this partition
    ESP_ERROR_CHECK(esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &well_done_handle));

   
    char buf[SEND_DATA];
    // Init of the buffer
    memset(buf, 0, sizeof(buf));
    // Content length of the request gives
    // the size of the file being uploaded 
    int remaining = req->content_len;
    while (remaining > 0) {
        uint16_t read_chunk_length = MIN(remaining, SEND_DATA);
        vTaskDelay(20/portTICK_PERIOD_MS);
        ESP_LOGI("UPLOAD", "Remaining size : %d", remaining);
        // Receive the file part by part into a buffer 
        if ((received = httpd_req_recv(req, buf, read_chunk_length)) <= 0) {
            if (received == HTTPD_SOCK_ERR_TIMEOUT) {
                continue;
            }
            ESP_LOGE("UPLOAD", "File reception failed!");
            httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to receive file");
            return ESP_FAIL;
        }
        //printf("data actually received received=%u \n",received);
        //printf("read_chunk_length=%u \n",read_chunk_length);
        ret = esp_ota_write(well_done_handle, buf, received);
        if(ret != ESP_OK){
            ESP_LOGE("UPDATE", "Firmware upgrade failed");
            while (1) {
                vTaskDelay(1000 / portTICK_PERIOD_MS);
            }
            return ESP_FAIL;
        }
        
    remaining -= received;
    }


    ESP_LOGI("UPLOAD", "File reception complete");

    // Redirect onto root to see the updated file list
    httpd_resp_set_status(req, "303 See Other");
    httpd_resp_set_hdr(req, "Location", "/");
#ifdef CONFIG_EXAMPLE_HTTPD_CONN_CLOSE_HEADER
    httpd_resp_set_hdr(req, "Connection", "close");
#endif
    httpd_resp_sendstr(req, "File uploaded successfully");

    // If you are here it means there are no problems!
    ESP_ERROR_CHECK(esp_ota_end(well_done_handle));

    // OTA partition configuration
    ESP_ERROR_CHECK(esp_ota_set_boot_partition(update_partition));
    ESP_LOGI("UPDATE", "Restarting...");
    // REBOOT!!!!!
    esp_restart();
    return ESP_OK;
}


The function works okay and I am able to update the firmware without any issues.

The problem is that I do not want to allow user to update any .bin file that he want, I want user to only be able update .bin files that I release and check them so the user does not "brick" the device by uploading wrong binary file. At the moment, there is no one stopping user from uploading "hello_world" program to my device which is not good. What are the best methods to ensure only specific .bin files are allowed to perform firmware update?


Is there any way to detect that the .bin file came out of my project build and not some hello_world project?

ESP_igrr
Posts: 2071
Joined: Tue Dec 01, 2015 8:37 am

Re: ESP32 FOTA via WiFi how to check integrity of the .bin file

Postby ESP_igrr » Wed Sep 07, 2022 1:03 pm

Hi zazas321,
Normally such restriction can be implemented using the Secure Boot feature. It allows you to cryptographically sign the OTA images. The device will verify the signature of the OTA image using a public key.

You can read about this feature here: https://docs.espressif.com/projects/esp ... ot-v2.html

There is also a weaker version of this functionality, where the signature is only verified by the OTA library and by the 2nd stage bootloader. It can be enabled via the CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT option. This option doesn't enable signature checks in the first stage bootloader, and the device can still be flashed with an unauthorized application, for example via UART or by programming the flash chip directly.

chegewara
Posts: 2364
Joined: Wed Jun 14, 2017 9:00 pm

Re: ESP32 FOTA via WiFi how to check integrity of the .bin file

Postby chegewara » Wed Sep 07, 2022 1:51 pm

How about firmware custom descriptor?

Code: Select all

typedef struct {
	// whatever fields you want here; numerical or string or even encoded data
} my_custom_app_desc_t;
const __attribute__((section(".rodata_custom_desc"))) my_custom_app_desc_t custom_app_desc = 
This is stored at the beginning of firmware, so you can download like 1024-4096 bytes and check if new firmware is having this structure. If not then discard binary and do not OTA update.
Yes, it is possible to dump already flashed firmware and then duplicate it in another app.

zazas321
Posts: 231
Joined: Mon Feb 01, 2021 9:41 am

Re: ESP32 FOTA via WiFi how to check integrity of the .bin file

Postby zazas321 » Thu Sep 08, 2022 5:33 am

ESP_igrr wrote:
Wed Sep 07, 2022 1:03 pm
Hi zazas321,
Normally such restriction can be implemented using the Secure Boot feature. It allows you to cryptographically sign the OTA images. The device will verify the signature of the OTA image using a public key.

You can read about this feature here: https://docs.espressif.com/projects/esp ... ot-v2.html

There is also a weaker version of this functionality, where the signature is only verified by the OTA library and by the 2nd stage bootloader. It can be enabled via the CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT option. This option doesn't enable signature checks in the first stage bootloader, and the device can still be flashed with an unauthorized application, for example via UART or by programming the flash chip directly.


Thank you very much for pointing me in the right direction. I read a little bit about secure boot in esp-idf website but it is quite complex and I am not sure if I understand it right. I dont think I need secure boot hardware support, I just need basic protection to prevent user from flashing wrong binary from the website. I dont need to stop user from flashing the device using the hardware usb flasher.

I am reading How To Enable Secure Boot (https://docs.espressif.com/projects/esp ... boot-howto)

How To Enable Secure Boot
Open the Project Configuration Menu, navigate to “Secure Boot Configuration” and select the option “One-time Flash”. (To understand the alternative “Reflashable” choice, see Re-Flashable Software Bootloader.)

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.

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

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.



In menuconfig, I cannot find anything remotely close to "Secure Boot Configuration" or specifically "One-time Flash" , can you help me understand how can I enable these options? (I prefer using VSCODE GUI menuconfig rather than cmd menuconfig)


What I have tried so far:
1. Enable Require signed app images and Verify app signature on update in SDK Configuration editor:
https://imgur.com/bNG8nCR

2. Downloaded openssl and generated key using cmd

Code: Select all

openssl ecparam -name prime256v1 -genkey -noout -out secure_boot_signing_key.pem
3. I am not sure what is the next step? Now in my project folder I have this .pem file. Do I need to manually sign the firmware files before I send him the .bin?

ESP_igrr
Posts: 2071
Joined: Tue Dec 01, 2015 8:37 am

Re: ESP32 FOTA via WiFi how to check integrity of the .bin file

Postby ESP_igrr » Thu Sep 08, 2022 4:31 pm

If you are using ESP32 silicon revision 3 (also known as ECO 3), then I'd recommend using Secure Boot v2.

The documentation for the basic signature verification setup can be found here: https://docs.espressif.com/projects/esp ... ecure-boot

Once you enable "Require signed app images", "Verify app signature on update", and "Sign binaries during build", you can then build the application as usual. The application binary will be signed using the private key. The public key will be embedded into the application and used when verifying an OTA binary.

(You do not need to enable the "Enable hardware Secure Boot in bootloader" option in this case.)

zazas321
Posts: 231
Joined: Mon Feb 01, 2021 9:41 am

Re: ESP32 FOTA via WiFi how to check integrity of the .bin file

Postby zazas321 » Fri Sep 09, 2022 4:45 am

Oh thanks for clarifying.

I assume secure boot V2 requires you to use hardware secure boot ( not only OTA secure boot) ?

Because the first step in the instructions require you to enable Hardware secure boot in the bootloader
Open the Project Configuration Menu, in “Security features” set “Enable hardware Secure Boot in bootloader” to enable Secure Boot.
If that is the case, I dont think I need it. This is actually "too much" security for me. If user have have physical access to the device and he wants to reprogram it, I shall allow it. I am only mainly concerned programming via the OTA (since it will be the only available option that I recommend to update the firmware)

I have managed to confirm that it works (I have tried to flash some random binary file and it was declined)

ESP_igrr
Posts: 2071
Joined: Tue Dec 01, 2015 8:37 am

Re: ESP32 FOTA via WiFi how to check integrity of the .bin file

Postby ESP_igrr » Fri Sep 09, 2022 7:48 am

zazas321 wrote: I assume secure boot V2 requires you to use hardware secure boot ( not only OTA secure boot) ?
It doesn't, you can still use image verification after OTA only. Perhaps you are looking at a different section of the docs? The one you need is titled "Signed App Verification Without Hardware Secure Boot", and the instructions are under "How To Enable Signed App Verification". Here's the link: https://docs.espressif.com/projects/esp ... ecure-boot


If you already made it work with secure boot V1, you can still use that approach, of course. Secure Boot V2's benefits are improved security when the hardware secure boot is used (which doesn't apply to your car) and that you can use the same scheme if you use newer chips from Espressif.

Who is online

Users browsing this forum: No registered users and 92 guests