From 7fd2d5ea03822d65a3f98b2b8e8b44f1c87bc9ae Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Fri, 28 Jan 2022 16:40:06 +0530 Subject: [PATCH] esp_https_ota: add support for decryption callback - Decryption callback is additional feature, default disabled - This callback can help to plug in external components managing additional encapsulation layers on firmware image format --- components/esp_https_ota/Kconfig | 11 ++- .../esp_https_ota/include/esp_https_ota.h | 14 ++++ components/esp_https_ota/src/esp_https_ota.c | 69 ++++++++++++++++++- 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/components/esp_https_ota/Kconfig b/components/esp_https_ota/Kconfig index c38dd49020..ea675828b4 100644 --- a/components/esp_https_ota/Kconfig +++ b/components/esp_https_ota/Kconfig @@ -1,6 +1,15 @@ menu "ESP HTTPS OTA" - config OTA_ALLOW_HTTP + config ESP_HTTPS_OTA_DECRYPT_CB + bool "Provide decryption callback" + default n + help + Exposes an additional callback whereby firmware data could be decrypted + before being processed by OTA update component. This can help to integrate + external encryption related format and removal of such encapsulation layer + from firmware image. + + config ESP_HTTPS_OTA_ALLOW_HTTP bool "Allow HTTP for OTA (WARNING: ONLY FOR TESTING PURPOSE, READ HELP)" default n help diff --git a/components/esp_https_ota/include/esp_https_ota.h b/components/esp_https_ota/include/esp_https_ota.h index 6dd5017499..b8103eda6d 100644 --- a/components/esp_https_ota/include/esp_https_ota.h +++ b/components/esp_https_ota/include/esp_https_ota.h @@ -17,6 +17,17 @@ extern "C" { typedef void *esp_https_ota_handle_t; typedef esp_err_t(*http_client_init_cb_t)(esp_http_client_handle_t); +#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB +typedef struct { + const char *data_in; /*!< Pointer to data to be decrypted */ + size_t data_in_len; /*!< Input data length */ + char *data_out; /*!< Pointer to data decrypted using callback, this will be freed after data is written to flash */ + size_t data_out_len; /*!< Output data length */ +} decrypt_cb_arg_t; + +typedef esp_err_t(*decrypt_cb_t)(decrypt_cb_arg_t *args); +#endif // CONFIG_ESP_HTTPS_OTA_DECRYPT_CB + /** * @brief ESP HTTPS OTA configuration */ @@ -26,6 +37,9 @@ typedef struct { bool bulk_flash_erase; /*!< Erase entire flash partition during initialization. By default flash partition is erased during write operation and in chunk of 4K sector size */ bool partial_http_download; /*!< Enable Firmware image to be downloaded over multiple HTTP requests */ int max_http_request_size; /*!< Maximum request size for partial HTTP download */ +#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB + decrypt_cb_t decrypt_cb; /*!< Callback for external decryption layer */ +#endif } esp_https_ota_config_t; #define ESP_ERR_HTTPS_OTA_BASE (0x9000) diff --git a/components/esp_https_ota/src/esp_https_ota.c b/components/esp_https_ota/src/esp_https_ota.c index 68c3efc4ef..68123ce20f 100644 --- a/components/esp_https_ota/src/esp_https_ota.c +++ b/components/esp_https_ota/src/esp_https_ota.c @@ -43,6 +43,9 @@ struct esp_https_ota_handle { esp_https_ota_state state; bool bulk_flash_erase; bool partial_http_download; +#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB + decrypt_cb_t decrypt_cb; +#endif }; typedef struct esp_https_ota_handle esp_https_ota_t; @@ -147,6 +150,27 @@ static void _http_cleanup(esp_http_client_handle_t client) esp_http_client_cleanup(client); } +#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB +static esp_err_t esp_https_ota_decrypt_cb(esp_https_ota_t *handle, decrypt_cb_arg_t *args) +{ + esp_err_t ret = handle->decrypt_cb(args); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Decrypt callback failed %d", ret); + return ret; + } + if (args->data_out_len > 0) { + return ESP_OK; + } else { + return ESP_HTTPS_OTA_IN_PROGRESS; + } +} + +static void esp_https_ota_decrypt_cb_free_buf(void *buffer) +{ + free(buffer); +} +#endif // CONFIG_ESP_HTTPS_OTA_DECRYPT_CB + static esp_err_t _ota_write(esp_https_ota_t *https_ota_handle, const void *buffer, size_t buf_len) { if (buffer == NULL || https_ota_handle == NULL) { @@ -160,6 +184,9 @@ static esp_err_t _ota_write(esp_https_ota_t *https_ota_handle, const void *buffe ESP_LOGD(TAG, "Written image length %d", https_ota_handle->binary_file_len); err = ESP_ERR_HTTPS_OTA_IN_PROGRESS; } +#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB + esp_https_ota_decrypt_cb_free_buf((void *) buffer); +#endif return err; } @@ -277,6 +304,13 @@ esp_err_t esp_https_ota_begin(esp_https_ota_config_t *ota_config, esp_https_ota_ err = ESP_ERR_NO_MEM; goto http_cleanup; } +#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB + if (ota_config->decrypt_cb == NULL) { + err = ESP_ERR_INVALID_ARG; + goto http_cleanup; + } + https_ota_handle->decrypt_cb = ota_config->decrypt_cb; +#endif https_ota_handle->ota_upgrade_buf_size = alloc_size; https_ota_handle->bulk_flash_erase = ota_config->bulk_flash_erase; https_ota_handle->binary_file_len = 0; @@ -403,11 +437,26 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle) } binary_file_len = IMAGE_HEADER_SIZE; } - err = esp_ota_verify_chip_id(handle->ota_upgrade_buf); + + const void *data_buf = (const void *) handle->ota_upgrade_buf; +#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB + decrypt_cb_arg_t args = {}; + args.data_in = handle->ota_upgrade_buf; + args.data_in_len = binary_file_len; + err = esp_https_ota_decrypt_cb(handle, &args); + if (err == ESP_OK) { + data_buf = args.data_out; + binary_file_len = args.data_out_len; + } else { + ESP_LOGE(TAG, "Decryption of image header failed"); + return ESP_FAIL; + } +#endif // CONFIG_ESP_HTTPS_OTA_DECRYPT_CB + err = esp_ota_verify_chip_id(data_buf); if (err != ESP_OK) { return err; } - return _ota_write(handle, (const void *)handle->ota_upgrade_buf, binary_file_len); + return _ota_write(handle, data_buf, binary_file_len); case ESP_HTTPS_OTA_IN_PROGRESS: data_read = esp_http_client_read(handle->http_client, handle->ota_upgrade_buf, @@ -433,7 +482,21 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle) } ESP_LOGD(TAG, "Connection closed"); } else if (data_read > 0) { - return _ota_write(handle, (const void *)handle->ota_upgrade_buf, data_read); + const void *data_buf = (const void *) handle->ota_upgrade_buf; + int data_len = data_read; +#if CONFIG_ESP_HTTPS_OTA_DECRYPT_CB + decrypt_cb_arg_t args = {}; + args.data_in = handle->ota_upgrade_buf; + args.data_in_len = data_read; + err = esp_https_ota_decrypt_cb(handle, &args); + if (err == ESP_OK) { + data_buf = args.data_out; + data_len = args.data_out_len; + } else { + return err; + } +#endif // CONFIG_ESP_HTTPS_OTA_DECRYPT_CB + return _ota_write(handle, data_buf, data_len); } else { ESP_LOGE(TAG, "data read %d, errno %d", data_read, errno); return ESP_FAIL;