From 117c79eae56f6bb59dcd7aebef483002c497d4ec Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Wed, 30 May 2018 14:08:00 +0500 Subject: [PATCH] app_update: Add API for getting sha256_of_partition Added bootloader_common_get_sha256_of_partition() and esp_partition_get_sha256() - get or calculate SHA-256 digest for app and data partitions. Added bootloader_sha256_hex_to_str() - helps to print SHA-256 digest Added esp_partition_check_identity() - compares two partitions by SHA-256 digest Refactoring a function esp_image_load() in bootloader space to esp_image_verify() and bootloader_load_image(). Old name function esp_image_load is deprecated and will remove in V4.0 version. spi_flash/sim: Fix error test_host. Add stub for bootloader_common_get_sha256_of_partition in sim/stubs --- components/app_update/esp_ota_ops.c | 4 +- components/app_update/include/esp_ota_ops.h | 2 +- .../include/bootloader_common.h | 23 +++++++ .../include/esp_image_format.h | 63 ++++++++++++++++++- .../include_bootloader/bootloader_sha.h | 24 +++++++ .../src/bootloader_common.c | 47 ++++++++++++++ .../bootloader_support/src/bootloader_sha.c | 18 ++++++ .../src/bootloader_utility.c | 3 +- .../bootloader_support/src/esp_image_format.c | 50 ++++++++++----- .../bootloader_support/src/flash_encrypt.c | 2 +- .../test/test_verify_image.c | 4 +- components/spi_flash/include/esp_partition.h | 31 +++++++++ components/spi_flash/partition.c | 22 +++++++ components/spi_flash/sim/stubs/Makefile.files | 3 +- .../include/bootloader_common.h | 20 ++++++ .../src/bootloader_common.c | 19 ++++++ .../main/native_ota_example.c | 45 +++++++++++++ 17 files changed, 354 insertions(+), 26 deletions(-) create mode 100644 components/spi_flash/sim/stubs/bootloader_support/include/bootloader_common.h create mode 100644 components/spi_flash/sim/stubs/bootloader_support/src/bootloader_common.c diff --git a/components/app_update/esp_ota_ops.c b/components/app_update/esp_ota_ops.c index 48542c23f..c7ac0bc6a 100644 --- a/components/app_update/esp_ota_ops.c +++ b/components/app_update/esp_ota_ops.c @@ -235,7 +235,7 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle) .size = it->part->size, }; - if (esp_image_load(ESP_IMAGE_VERIFY, &part_pos, &data) != ESP_OK) { + if (esp_image_verify(ESP_IMAGE_VERIFY, &part_pos, &data) != ESP_OK) { ret = ESP_ERR_OTA_VALIDATE_FAILED; goto cleanup; } @@ -372,7 +372,7 @@ esp_err_t esp_ota_set_boot_partition(const esp_partition_t *partition) .offset = partition->address, .size = partition->size, }; - if (esp_image_load(ESP_IMAGE_VERIFY, &part_pos, &data) != ESP_OK) { + if (esp_image_verify(ESP_IMAGE_VERIFY, &part_pos, &data) != ESP_OK) { return ESP_ERR_OTA_VALIDATE_FAILED; } diff --git a/components/app_update/include/esp_ota_ops.h b/components/app_update/include/esp_ota_ops.h index a089a92be..291d6375e 100644 --- a/components/app_update/include/esp_ota_ops.h +++ b/components/app_update/include/esp_ota_ops.h @@ -133,7 +133,7 @@ esp_err_t esp_ota_set_boot_partition(const esp_partition_t* partition); * If the OTA data partition is not present or not valid then the result is the first app partition found in the * partition table. In priority order, this means: the factory app, the first OTA app slot, or the test app partition. * - * Note that there is no guarantee the returned partition is a valid app. Use esp_image_load(ESP_IMAGE_VERIFY, ...) to verify if the + * Note that there is no guarantee the returned partition is a valid app. Use esp_image_verify(ESP_IMAGE_VERIFY, ...) to verify if the * returned partition contains a bootable image. * * @return Pointer to info for partition structure, or NULL if partition table is invalid or a flash read operation failed. Any returned pointer is valid for the lifetime of the application. diff --git a/components/bootloader_support/include/bootloader_common.h b/components/bootloader_support/include/bootloader_common.h index 07fc9341c..d5a92cc79 100644 --- a/components/bootloader_support/include/bootloader_common.h +++ b/components/bootloader_support/include/bootloader_common.h @@ -68,3 +68,26 @@ bool bootloader_common_erase_part_type_data(const char *list_erase, bool ota_dat * @return Returns true if the list contains the label, false otherwise. */ bool bootloader_common_label_search(const char *list, char *label); + +/** + * @brief Calculates a sha-256 for a given partition or returns a appended digest. + * + * This function can be used to return the SHA-256 digest of application, bootloader and data partitions. + * For apps with SHA-256 appended to the app image, the result is the appended SHA-256 value for the app image content. + * The hash is verified before returning, if app content is invalid then the function returns ESP_ERR_IMAGE_INVALID. + * For apps without SHA-256 appended to the image, the result is the SHA-256 of all bytes in the app image. + * For other partition types, the result is the SHA-256 of the entire partition. + * + * @param[in] address Address of partition. + * @param[in] size Size of partition. + * @param[in] type Type of partition. For applications the type is 0, otherwise type is data. + * @param[out] out_sha_256 Returned SHA-256 digest for a given partition. + * + * @return + * - ESP_OK: In case of successful operation. + * - ESP_ERR_INVALID_ARG: The size was 0 or the sha_256 was NULL. + * - ESP_ERR_NO_MEM: Cannot allocate memory for sha256 operation. + * - ESP_ERR_IMAGE_INVALID: App partition doesn't contain a valid app image. + * - ESP_FAIL: An allocation error occurred. + */ +esp_err_t bootloader_common_get_sha256_of_partition(uint32_t address, uint32_t size, int type, uint8_t *out_sha_256); diff --git a/components/bootloader_support/include/esp_image_format.h b/components/bootloader_support/include/esp_image_format.h index 6d332d810..6d92a35b0 100644 --- a/components/bootloader_support/include/esp_image_format.h +++ b/components/bootloader_support/include/esp_image_format.h @@ -96,11 +96,12 @@ typedef struct { esp_image_segment_header_t segments[ESP_IMAGE_MAX_SEGMENTS]; /* Per-segment header data */ uint32_t segment_data[ESP_IMAGE_MAX_SEGMENTS]; /* Data offsets for each segment */ uint32_t image_len; /* Length of image on flash, in bytes */ + uint8_t image_digest[32]; /* appended SHA-256 digest */ } esp_image_metadata_t; /* Mode selection for esp_image_load() */ typedef enum { - ESP_IMAGE_VERIFY, /* Verify image contents, load metadata. Print errorsors. */ + ESP_IMAGE_VERIFY, /* Verify image contents, load metadata. Print errors. */ ESP_IMAGE_VERIFY_SILENT, /* Verify image contents, load metadata. Don't print errors. */ #ifdef BOOTLOADER_BUILD ESP_IMAGE_LOAD, /* Verify image contents, load to memory. Print errors. */ @@ -110,6 +111,11 @@ typedef enum { /** * @brief Verify and (optionally, in bootloader mode) load an app image. * + * This name is deprecated and is included for compatibility with the ESP-IDF v3.x API. + * It will be removed in V4.0 version. + * Function has been renamed to esp_image_verify(). + * Use function esp_image_verify() to verify a image. And use function bootloader_load_image() to load image from a bootloader space. + * * If encryption is enabled, data will be transparently decrypted. * * @param mode Mode of operation (verify, silent verify, or load). @@ -130,7 +136,60 @@ typedef enum { * - ESP_ERR_IMAGE_INVALID if the image appears invalid. * - ESP_ERR_INVALID_ARG if the partition or data pointers are invalid. */ -esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data); +esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data) __attribute__((deprecated)); + +/** + * @brief Verify an app image. + * + * If encryption is enabled, data will be transparently decrypted. + * + * @param mode Mode of operation (verify, silent verify, or load). + * @param part Partition to load the app from. + * @param[inout] data Pointer to the image metadata structure which is be filled in by this function. + * 'start_addr' member should be set (to the start address of the image.) + * Other fields will all be initialised by this function. + * + * Image validation checks: + * - Magic byte. + * - Partition smaller than 16MB. + * - All segments & image fit in partition. + * - 8 bit image checksum is valid. + * - SHA-256 of image is valid (if image has this appended). + * - (Signature) if signature verification is enabled. + * + * @return + * - ESP_OK if verify or load was successful + * - ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs + * - ESP_ERR_IMAGE_INVALID if the image appears invalid. + * - ESP_ERR_INVALID_ARG if the partition or data pointers are invalid. + */ +esp_err_t esp_image_verify(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data); + +/** + * @brief Verify and load an app image (available only in space of bootloader). + * + * If encryption is enabled, data will be transparently decrypted. + * + * @param part Partition to load the app from. + * @param[inout] data Pointer to the image metadata structure which is be filled in by this function. + * 'start_addr' member should be set (to the start address of the image.) + * Other fields will all be initialised by this function. + * + * Image validation checks: + * - Magic byte. + * - Partition smaller than 16MB. + * - All segments & image fit in partition. + * - 8 bit image checksum is valid. + * - SHA-256 of image is valid (if image has this appended). + * - (Signature) if signature verification is enabled. + * + * @return + * - ESP_OK if verify or load was successful + * - ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs + * - ESP_ERR_IMAGE_INVALID if the image appears invalid. + * - ESP_ERR_INVALID_ARG if the partition or data pointers are invalid. + */ +esp_err_t bootloader_load_image(const esp_partition_pos_t *part, esp_image_metadata_t *data); /** * @brief Verify the bootloader image. diff --git a/components/bootloader_support/include_bootloader/bootloader_sha.h b/components/bootloader_support/include_bootloader/bootloader_sha.h index 38bd08048..079a45791 100644 --- a/components/bootloader_support/include_bootloader/bootloader_sha.h +++ b/components/bootloader_support/include_bootloader/bootloader_sha.h @@ -22,6 +22,7 @@ #include #include +#include "esp_err.h" typedef void *bootloader_sha256_handle_t; @@ -30,3 +31,26 @@ bootloader_sha256_handle_t bootloader_sha256_start(); void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data, size_t data_len); void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest); + +/** + * @brief Converts an array to a printable string. + * + * This function is useful for printing SHA-256 digest. + * \code{c} + * // Example of using. image_hash will be printed + * #define HASH_LEN 32 // SHA-256 digest length + * ... + * char hash_print[HASH_LEN * 2 + 1]; + * hash_print[HASH_LEN * 2] = 0; + * bootloader_sha256_hex_to_str(hash_print, image_hash, HASH_LEN); + * ESP_LOGI(TAG, %s", hash_print); + * \endcode + + * @param[out] out_str Output string + * @param[in] in_array_hex Pointer to input array + * @param[in] len Length of input array + * + * @return ESP_OK: Successful + * ESP_ERR_INVALID_ARG: Error in the passed arguments + */ +esp_err_t bootloader_sha256_hex_to_str(char *out_str, const uint8_t *in_array_hex, size_t len); diff --git a/components/bootloader_support/src/bootloader_common.c b/components/bootloader_support/src/bootloader_common.c index 30a9dac44..a17492601 100644 --- a/components/bootloader_support/src/bootloader_common.c +++ b/components/bootloader_support/src/bootloader_common.c @@ -27,6 +27,10 @@ #include "bootloader_flash.h" #include "bootloader_common.h" #include "soc/gpio_periph.h" +#include "esp_image_format.h" +#include "bootloader_sha.h" + +#define ESP_PARTITION_HASH_LEN 32 /* SHA-256 digest length */ static const char* TAG = "boot_comm"; @@ -145,3 +149,46 @@ bool bootloader_common_erase_part_type_data(const char *list_erase, bool ota_dat return ret; } + +esp_err_t bootloader_common_get_sha256_of_partition (uint32_t address, uint32_t size, int type, uint8_t *out_sha_256) +{ + if (out_sha_256 == NULL || size == 0) { + return ESP_ERR_INVALID_ARG; + } + + if (type == PART_TYPE_APP) { + const esp_partition_pos_t partition_pos = { + .offset = address, + .size = size, + }; + esp_image_metadata_t data; + // Function esp_image_verify() verifies and fills the structure data. + // here important to get: image_digest, image_len, hash_appended. + if (esp_image_verify(ESP_IMAGE_VERIFY_SILENT, &partition_pos, &data) != ESP_OK) { + return ESP_ERR_IMAGE_INVALID; + } + if (data.image.hash_appended) { + memcpy(out_sha_256, data.image_digest, ESP_PARTITION_HASH_LEN); + return ESP_OK; + } + // If image doesn't have a appended hash then hash calculates for entire image. + size = data.image_len; + } + // If image is type by data then hash is calculated for entire image. + const void *partition_bin = bootloader_mmap(address, size); + if (partition_bin == NULL) { + ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", address, size); + return ESP_FAIL; + } + bootloader_sha256_handle_t sha_handle = bootloader_sha256_start(); + if (sha_handle == NULL) { + bootloader_munmap(partition_bin); + return ESP_ERR_NO_MEM; + } + bootloader_sha256_data(sha_handle, partition_bin, size); + bootloader_sha256_finish(sha_handle, out_sha_256); + + bootloader_munmap(partition_bin); + + return ESP_OK; +} diff --git a/components/bootloader_support/src/bootloader_sha.c b/components/bootloader_support/src/bootloader_sha.c index a8d537e04..1f7c1b493 100644 --- a/components/bootloader_support/src/bootloader_sha.c +++ b/components/bootloader_support/src/bootloader_sha.c @@ -169,3 +169,21 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest } #endif + +esp_err_t bootloader_sha256_hex_to_str(char *out_str, const uint8_t *in_array_hex, size_t len) +{ + if (out_str == NULL || in_array_hex == NULL || len == 0) { + return ESP_ERR_INVALID_ARG; + } + for (int i = 0; i < len; i++) { + for (int shift = 0; shift < 2; shift++) { + uint8_t nibble = (in_array_hex[i] >> (shift ? 0 : 4)) & 0x0F; + if (nibble < 10) { + out_str[i*2+shift] = '0' + nibble; + } else { + out_str[i*2+shift] = 'a' + nibble - 10; + } + } + } + return ESP_OK; +} diff --git a/components/bootloader_support/src/bootloader_utility.c b/components/bootloader_support/src/bootloader_utility.c index e68f8d0d8..5550945bb 100644 --- a/components/bootloader_support/src/bootloader_utility.c +++ b/components/bootloader_support/src/bootloader_utility.c @@ -50,6 +50,7 @@ #include "bootloader_config.h" #include "bootloader_common.h" #include "bootloader_utility.h" +#include "bootloader_sha.h" static const char* TAG = "boot"; @@ -265,7 +266,7 @@ static bool try_load_partition(const esp_partition_pos_t *partition, esp_image_m return false; } #ifdef BOOTLOADER_BUILD - if (esp_image_load(ESP_IMAGE_LOAD, partition, data) == ESP_OK) { + if (bootloader_load_image(partition, data) == ESP_OK) { ESP_LOGI(TAG, "Loaded app from partition at offset 0x%x", partition->offset); return true; diff --git a/components/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c index 92acf3b02..fea89e6a3 100644 --- a/components/bootloader_support/src/esp_image_format.c +++ b/components/bootloader_support/src/esp_image_format.c @@ -75,7 +75,7 @@ static esp_err_t verify_checksum(bootloader_sha256_handle_t sha_handle, uint32_t static esp_err_t __attribute__((unused)) verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data); static esp_err_t __attribute__((unused)) verify_simple_hash(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data); -esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data) +static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data) { #ifdef BOOTLOADER_BUILD bool do_load = (mode == ESP_IMAGE_LOAD); @@ -128,7 +128,7 @@ esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t * err = verify_image_header(data->start_addr, &data->image, silent); if (err != ESP_OK) { -goto err; + goto err; } if (data->image.segment_count > ESP_IMAGE_MAX_SEGMENTS) { @@ -189,6 +189,17 @@ goto err; bootloader_sha256_finish(sha_handle, NULL); } } + + if (data->image.hash_appended) { + const void *hash = bootloader_mmap(data->start_addr + data->image_len - HASH_LEN, HASH_LEN); + if (hash == NULL) { + err = ESP_FAIL; + goto err; + } + memcpy(data->image_digest, hash, HASH_LEN); + bootloader_munmap(hash); + } + sha_handle = NULL; if (err != ESP_OK) { goto err; @@ -224,6 +235,22 @@ goto err; return err; } +esp_err_t bootloader_load_image(const esp_partition_pos_t *part, esp_image_metadata_t *data) +{ +#ifdef BOOTLOADER_BUILD + return image_load(ESP_IMAGE_LOAD, part, data); +#else + return ESP_FAIL; +#endif +} + +esp_err_t esp_image_verify(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data) +{ + return image_load(mode, part, data); +} + +esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data) __attribute__((alias("esp_image_verify"))); + static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t *image, bool silent) { esp_err_t err = ESP_OK; @@ -446,7 +473,7 @@ esp_err_t esp_image_verify_bootloader(uint32_t *length) .offset = ESP_BOOTLOADER_OFFSET, .size = ESP_PARTITION_TABLE_OFFSET - ESP_BOOTLOADER_OFFSET, }; - esp_err_t err = esp_image_load(ESP_IMAGE_VERIFY, + esp_err_t err = esp_image_verify(ESP_IMAGE_VERIFY, &bootloader_part, &data); if (length != NULL) { @@ -556,18 +583,9 @@ static esp_err_t verify_simple_hash(bootloader_sha256_handle_t sha_handle, esp_i static void debug_log_hash(const uint8_t *image_hash, const char *label) { #if BOOT_LOG_LEVEL >= LOG_LEVEL_DEBUG - char hash_print[sizeof(image_hash)*2 + 1]; - hash_print[sizeof(image_hash)*2] = 0; - for (int i = 0; i < sizeof(image_hash); i++) { - for (int shift = 0; shift < 2; shift++) { - uint8_t nibble = (image_hash[i] >> (shift ? 0 : 4)) & 0x0F; - if (nibble < 10) { - hash_print[i*2+shift] = '0' + nibble; - } else { - hash_print[i*2+shift] = 'a' + nibble - 10; - } - } - } - ESP_LOGD(TAG, "%s: %s", label, hash_print); + char hash_print[HASH_LEN * 2 + 1]; + hash_print[HASH_LEN * 2] = 0; + bootloader_sha256_hex_to_str(hash_print, image_hash, HASH_LEN); + ESP_LOGD(TAG, "%s: %s", label, hash_print); #endif } diff --git a/components/bootloader_support/src/flash_encrypt.c b/components/bootloader_support/src/flash_encrypt.c index a9e8f8f9b..2b229c00b 100644 --- a/components/bootloader_support/src/flash_encrypt.c +++ b/components/bootloader_support/src/flash_encrypt.c @@ -281,7 +281,7 @@ static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partit if (partition->type == PART_TYPE_APP) { /* check if the partition holds a valid unencrypted app */ esp_image_metadata_t data_ignored; - err = esp_image_load(ESP_IMAGE_VERIFY, + err = esp_image_verify(ESP_IMAGE_VERIFY, &partition->pos, &data_ignored); should_encrypt = (err == ESP_OK); diff --git a/components/bootloader_support/test/test_verify_image.c b/components/bootloader_support/test/test_verify_image.c index 7994667f3..153a859c2 100644 --- a/components/bootloader_support/test/test_verify_image.c +++ b/components/bootloader_support/test/test_verify_image.c @@ -25,7 +25,7 @@ TEST_CASE("Verify bootloader image in flash", "[bootloader_support]") .size = ESP_PARTITION_TABLE_OFFSET - ESP_BOOTLOADER_OFFSET, }; esp_image_metadata_t data = { 0 }; - TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_image_load(ESP_IMAGE_VERIFY, &fake_bootloader_partition, &data)); + TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_image_verify(ESP_IMAGE_VERIFY, &fake_bootloader_partition, &data)); TEST_ASSERT_NOT_EQUAL(0, data.image_len); uint32_t bootloader_length = 0; @@ -43,7 +43,7 @@ TEST_CASE("Verify unit test app image", "[bootloader_support]") .size = running->size, }; - TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_image_load(ESP_IMAGE_VERIFY, &running_pos, &data)); + TEST_ASSERT_EQUAL_HEX(ESP_OK, esp_image_verify(ESP_IMAGE_VERIFY, &running_pos, &data)); TEST_ASSERT_NOT_EQUAL(0, data.image_len); TEST_ASSERT_TRUE(data.image_len <= running->size); } diff --git a/components/spi_flash/include/esp_partition.h b/components/spi_flash/include/esp_partition.h index f3d5a424a..5345fa97d 100644 --- a/components/spi_flash/include/esp_partition.h +++ b/components/spi_flash/include/esp_partition.h @@ -286,6 +286,37 @@ esp_err_t esp_partition_mmap(const esp_partition_t* partition, uint32_t offset, spi_flash_mmap_memory_t memory, const void** out_ptr, spi_flash_mmap_handle_t* out_handle); +/** + * @brief Get SHA-256 digest for required partition. + * + * For apps with SHA-256 appended to the app image, the result is the appended SHA-256 value for the app image content. + * The hash is verified before returning, if app content is invalid then the function returns ESP_ERR_IMAGE_INVALID. + * For apps without SHA-256 appended to the image, the result is the SHA-256 of all bytes in the app image. + * For other partition types, the result is the SHA-256 of the entire partition. + * + * @param[in] partition Pointer to info for partition containing app or data. (fields: address, size and type, are required to be filled). + * @param[out] sha_256 Returned SHA-256 digest for a given partition. + * + * @return + * - ESP_OK: In case of successful operation. + * - ESP_ERR_INVALID_ARG: The size was 0 or the sha_256 was NULL. + * - ESP_ERR_NO_MEM: Cannot allocate memory for sha256 operation. + * - ESP_ERR_IMAGE_INVALID: App partition doesn't contain a valid app image. + * - ESP_FAIL: An allocation error occurred. + */ +esp_err_t esp_partition_get_sha256(const esp_partition_t *partition, uint8_t *sha_256); + +/** + * @brief Check for the identity of two partitions by SHA-256 digest. + * + * @param[in] partition_1 Pointer to info for partition 1 containing app or data. (fields: address, size and type, are required to be filled). + * @param[in] partition_2 Pointer to info for partition 2 containing app or data. (fields: address, size and type, are required to be filled). + * + * @return + * - True: In case of the two firmware is equal. + * - False: Otherwise + */ +bool esp_partition_check_identity(const esp_partition_t *partition_1, const esp_partition_t *partition_2); #ifdef __cplusplus } diff --git a/components/spi_flash/partition.c b/components/spi_flash/partition.c index 7f63d4c34..045c140de 100644 --- a/components/spi_flash/partition.c +++ b/components/spi_flash/partition.c @@ -24,7 +24,9 @@ #include "esp_partition.h" #include "esp_flash_encrypt.h" #include "esp_log.h" +#include "bootloader_common.h" +#define HASH_LEN 32 /* SHA-256 digest length */ #ifndef NDEBUG // Enable built-in checks in queue.h in debug builds @@ -322,3 +324,23 @@ esp_err_t esp_partition_mmap(const esp_partition_t* partition, uint32_t offset, } return rc; } + +esp_err_t esp_partition_get_sha256(const esp_partition_t *partition, uint8_t *sha_256) +{ + return bootloader_common_get_sha256_of_partition(partition->address, partition->size, partition->type, sha_256); +} + +bool esp_partition_check_identity(const esp_partition_t *partition_1, const esp_partition_t *partition_2) +{ + uint8_t sha_256[2][HASH_LEN] = { 0 }; + + if (esp_partition_get_sha256(partition_1, sha_256[0]) == ESP_OK && + esp_partition_get_sha256(partition_2, sha_256[1]) == ESP_OK) { + + if (memcmp(sha_256[0], sha_256[1], HASH_LEN) == 0) { + // The partitions are identity + return true; + } + } + return false; +} diff --git a/components/spi_flash/sim/stubs/Makefile.files b/components/spi_flash/sim/stubs/Makefile.files index 7b37db734..c3d004ae3 100644 --- a/components/spi_flash/sim/stubs/Makefile.files +++ b/components/spi_flash/sim/stubs/Makefile.files @@ -3,7 +3,8 @@ SOURCE_FILES := \ log/log.c \ newlib/lock.c \ esp32/crc.cpp \ - esp32/esp_random.c + esp32/esp_random.c \ + bootloader_support/src/bootloader_common.c INCLUDE_DIRS := \ ../include \ diff --git a/components/spi_flash/sim/stubs/bootloader_support/include/bootloader_common.h b/components/spi_flash/sim/stubs/bootloader_support/include/bootloader_common.h new file mode 100644 index 000000000..856eecd7a --- /dev/null +++ b/components/spi_flash/sim/stubs/bootloader_support/include/bootloader_common.h @@ -0,0 +1,20 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include +#include +#include "esp_err.h" + +esp_err_t bootloader_common_get_sha256_of_partition(uint32_t address, uint32_t size, int type, uint8_t *out_sha_256); diff --git a/components/spi_flash/sim/stubs/bootloader_support/src/bootloader_common.c b/components/spi_flash/sim/stubs/bootloader_support/src/bootloader_common.c new file mode 100644 index 000000000..c940fb4e7 --- /dev/null +++ b/components/spi_flash/sim/stubs/bootloader_support/src/bootloader_common.c @@ -0,0 +1,19 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "esp_err.h" + +esp_err_t bootloader_common_get_sha256_of_partition (uint32_t address, uint32_t size, int type, uint8_t *out_sha_256) +{ + return ESP_OK; +} diff --git a/examples/system/ota/native_ota_example/main/native_ota_example.c b/examples/system/ota/native_ota_example/main/native_ota_example.c index 1478cbd4e..0f83ca7ab 100644 --- a/examples/system/ota/native_ota_example/main/native_ota_example.c +++ b/examples/system/ota/native_ota_example/main/native_ota_example.c @@ -16,6 +16,8 @@ #include "esp_log.h" #include "esp_ota_ops.h" #include "esp_http_client.h" +#include "esp_flash_partitions.h" +#include "esp_partition.h" #include "nvs.h" #include "nvs_flash.h" @@ -24,6 +26,7 @@ #define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD #define EXAMPLE_SERVER_URL CONFIG_FIRMWARE_UPG_URL #define BUFFSIZE 1024 +#define HASH_LEN 32 /* SHA-256 digest length */ static const char *TAG = "native_ota_example"; /*an ota data write buffer ready to write to the flash*/ @@ -96,6 +99,16 @@ static void __attribute__((noreturn)) task_fatal_error() } } +void print_sha256 (const uint8_t *image_hash, const char *label) +{ + char hash_print[HASH_LEN * 2 + 1]; + hash_print[HASH_LEN * 2] = 0; + for (int i = 0; i < HASH_LEN; ++i) { + sprintf(&hash_print[i * 2], "%02x", image_hash[i]); + } + ESP_LOGI(TAG, "%s: %s", label, hash_print); +} + static void ota_example_task(void *pvParameter) { esp_err_t err; @@ -181,6 +194,17 @@ static void ota_example_task(void *pvParameter) http_cleanup(client); task_fatal_error(); } + + if (esp_partition_check_identity(esp_ota_get_running_partition(), update_partition) == true) { + ESP_LOGI(TAG, "The current running firmware is same as the firmware just downloaded"); + int i = 0; + ESP_LOGI(TAG, "When a new firmware is available on the server, press the reset button to download it"); + while(1) { + ESP_LOGI(TAG, "Waiting for a new firmware ... %d", ++i); + vTaskDelay(2000 / portTICK_PERIOD_MS); + } + } + err = esp_ota_set_boot_partition(update_partition); if (err != ESP_OK) { ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err)); @@ -194,6 +218,27 @@ static void ota_example_task(void *pvParameter) void app_main() { + uint8_t sha_256[HASH_LEN] = { 0 }; + esp_partition_t partition; + + // get sha256 digest for the partition table + partition.address = ESP_PARTITION_TABLE_OFFSET; + partition.size = ESP_PARTITION_TABLE_MAX_LEN; + partition.type = ESP_PARTITION_TYPE_DATA; + esp_partition_get_sha256(&partition, sha_256); + print_sha256(sha_256, "SHA-256 for the partition table: "); + + // get sha256 digest for bootloader + partition.address = ESP_BOOTLOADER_OFFSET; + partition.size = ESP_PARTITION_TABLE_OFFSET; + partition.type = ESP_PARTITION_TYPE_APP; + esp_partition_get_sha256(&partition, sha_256); + print_sha256(sha_256, "SHA-256 for bootloader: "); + + // get sha256 digest for running partition + esp_partition_get_sha256(esp_ota_get_running_partition(), sha_256); + print_sha256(sha_256, "SHA-256 for current firmware: "); + // Initialize NVS. esp_err_t err = nvs_flash_init(); if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {