Просмотр исходного кода

Merge branch 'bugfix/preencrypted_ota_failed_with_partial_download' into 'master'

fix(esp_https_ota): fix preencrypted ota failed with pytest server and partial http enabled

Closes IDF-8112

See merge request espressif/esp-idf!25791
Mahavir Jain 2 лет назад
Родитель
Сommit
ee435132cb

+ 1 - 0
components/esp_https_ota/include/esp_https_ota.h

@@ -62,6 +62,7 @@ typedef struct {
 #if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
     decrypt_cb_t decrypt_cb;                       /*!< Callback for external decryption layer */
     void *decrypt_user_ctx;                        /*!< User context for external decryption layer */
+    uint16_t enc_img_header_size;                  /*!< Header size of pre-encrypted ota image header */
 #endif
 } esp_https_ota_config_t;
 

+ 18 - 2
components/esp_https_ota/src/esp_https_ota.c

@@ -53,6 +53,7 @@ struct esp_https_ota_handle {
 #if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
     decrypt_cb_t decrypt_cb;
     void *decrypt_user_ctx;
+    uint16_t enc_img_header_size;
 #endif
 };
 
@@ -323,6 +324,11 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
         }
 
         https_ota_handle->image_length = esp_http_client_get_content_length(https_ota_handle->http_client);
+#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
+        /* In case of pre ecnrypted OTA, actual image size of OTA binary includes header size
+        which stored in variable enc_img_header_size*/
+        https_ota_handle->image_length -= ota_config->enc_img_header_size;
+#endif
         esp_http_client_close(https_ota_handle->http_client);
 
         if (https_ota_handle->image_length > https_ota_handle->max_http_request_size) {
@@ -349,6 +355,11 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
 
     if (!https_ota_handle->partial_http_download) {
         https_ota_handle->image_length = esp_http_client_get_content_length(https_ota_handle->http_client);
+#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
+        /* In case of pre ecnrypted OTA, actual image size of OTA binary includes header size
+        which stored in variable enc_img_header_size*/
+        https_ota_handle->image_length -= ota_config->enc_img_header_size;
+#endif
     }
 
     https_ota_handle->update_partition = NULL;
@@ -376,6 +387,7 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http
     }
     https_ota_handle->decrypt_cb = ota_config->decrypt_cb;
     https_ota_handle->decrypt_user_ctx = ota_config->decrypt_user_ctx;
+    https_ota_handle->enc_img_header_size = ota_config->enc_img_header_size;
 #endif
     https_ota_handle->ota_upgrade_buf_size = alloc_size;
     https_ota_handle->bulk_flash_erase = ota_config->bulk_flash_erase;
@@ -584,10 +596,14 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)
         if (handle->state == ESP_HTTPS_OTA_IN_PROGRESS && handle->image_length > handle->binary_file_len) {
             esp_http_client_close(handle->http_client);
             char *header_val = NULL;
+            int header_size = 0;
+#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB
+            header_size = handle->enc_img_header_size;
+#endif
             if ((handle->image_length - handle->binary_file_len) > handle->max_http_request_size) {
-                asprintf(&header_val, "bytes=%d-%d", handle->binary_file_len, (handle->binary_file_len + handle->max_http_request_size - 1));
+                asprintf(&header_val, "bytes=%d-%d", handle->binary_file_len + header_size, (handle->binary_file_len + header_size + handle->max_http_request_size - 1));
             } else {
-                asprintf(&header_val, "bytes=%d-", handle->binary_file_len);
+                asprintf(&header_val, "bytes=%d-", handle->binary_file_len + header_size);
             }
             if (header_val == NULL) {
                 ESP_LOGE(TAG, "Failed to allocate memory for HTTP header");

+ 2 - 0
examples/system/ota/pre_encrypted_ota/main/pre_encrypted_ota.c

@@ -74,6 +74,7 @@ static esp_err_t _decrypt_cb(decrypt_cb_arg_t *args, void *user_ctx)
     if (err != ESP_OK && err != ESP_ERR_NOT_FINISHED) {
         return err;
     }
+
     static bool is_image_verified = false;
     if (pargs.data_out_len > 0) {
         args->data_out = pargs.data_out;
@@ -143,6 +144,7 @@ void pre_encrypted_ota_task(void *pvParameter)
 #endif
         .decrypt_cb = _decrypt_cb,
         .decrypt_user_ctx = (void *)decrypt_handle,
+        .enc_img_header_size = esp_encrypted_img_get_header_size(),
     };
 
     esp_https_ota_handle_t https_ota_handle = NULL;

+ 45 - 1
examples/system/ota/pre_encrypted_ota/pytest_pre_encrypted_ota.py

@@ -1,4 +1,4 @@
-# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
 # SPDX-License-Identifier: Unlicense OR CC0-1.0
 import http.server
 import multiprocessing
@@ -82,3 +82,47 @@ def test_examples_protocol_pre_encrypted_ota_example(dut: Dut) -> None:
         dut.expect('Loaded app from partition at offset', timeout=30)
     finally:
         thread1.terminate()
+
+
+@pytest.mark.esp32
+@pytest.mark.ethernet_ota
+@pytest.mark.parametrize('config', ['partial_download',], indirect=True)
+def test_examples_protocol_pre_encrypted_ota_example_partial_request(dut: Dut) -> None:
+    server_port = 8001
+    # Size of partial HTTP request
+    request_size = int(dut.app.sdkconfig.get('EXAMPLE_HTTP_REQUEST_SIZE'))
+    # File to be downloaded. This file is generated after compilation
+    binary_file = os.path.join(dut.app.binary_path, enc_bin_name)
+    bin_size = os.path.getsize(binary_file)
+    http_requests = int((bin_size / request_size) - 1)
+    assert http_requests > 1
+
+    # Start server
+    thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', server_port))
+    thread1.daemon = True
+    thread1.start()
+
+    try:
+        dut.expect('Loaded app from partition at offset', timeout=30)
+        try:
+            ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[1].decode()
+            print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
+        except pexpect.exceptions.TIMEOUT:
+            raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
+        host_ip = get_host_ip4_by_dest_ip(ip_address)
+
+        dut.expect('Starting Pre Encrypted OTA example', timeout=30)
+        print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + enc_bin_name))
+        dut.write('https://' + host_ip + ':' + str(server_port) + '/' + enc_bin_name)
+        dut.expect('Magic Verified', timeout=30)
+        dut.expect('Reading RSA private key', timeout=30)
+
+        for _ in range(http_requests):
+            dut.expect('Connection closed', timeout=60)
+
+        dut.expect('upgrade successful. Rebooting', timeout=60)
+        # after reboot
+        dut.expect('Loaded app from partition at offset', timeout=30)
+
+    finally:
+        thread1.terminate()

+ 19 - 0
examples/system/ota/pre_encrypted_ota/sdkconfig.ci.partial_download

@@ -0,0 +1,19 @@
+CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN"
+CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y
+CONFIG_EXAMPLE_SKIP_VERSION_CHECK=y
+CONFIG_EXAMPLE_OTA_RECV_TIMEOUT=3000
+CONFIG_EXAMPLE_ENABLE_PARTIAL_HTTP_DOWNLOAD=y
+CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
+
+CONFIG_EXAMPLE_CONNECT_ETHERNET=y
+CONFIG_EXAMPLE_CONNECT_WIFI=n
+CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
+CONFIG_EXAMPLE_ETH_PHY_IP101=y
+CONFIG_EXAMPLE_ETH_MDC_GPIO=23
+CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
+CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
+CONFIG_EXAMPLE_ETH_PHY_ADDR=1
+
+CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y
+CONFIG_COMPILER_OPTIMIZATION_SIZE=y
+CONFIG_EXAMPLE_CONNECT_IPV6=n