]> granicus.if.org Git - esp-idf/commitdiff
app_update: Add API for getting sha256_of_partition
authorKonstantin Kondrashov <konstantin@espressif.com>
Wed, 30 May 2018 09:08:00 +0000 (14:08 +0500)
committerKonstantin Kondrashov <konstantin@espressif.com>
Mon, 13 Aug 2018 08:59:07 +0000 (13:59 +0500)
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

17 files changed:
components/app_update/esp_ota_ops.c
components/app_update/include/esp_ota_ops.h
components/bootloader_support/include/bootloader_common.h
components/bootloader_support/include/esp_image_format.h
components/bootloader_support/include_bootloader/bootloader_sha.h
components/bootloader_support/src/bootloader_common.c
components/bootloader_support/src/bootloader_sha.c
components/bootloader_support/src/bootloader_utility.c
components/bootloader_support/src/esp_image_format.c
components/bootloader_support/src/flash_encrypt.c
components/bootloader_support/test/test_verify_image.c
components/spi_flash/include/esp_partition.h
components/spi_flash/partition.c
components/spi_flash/sim/stubs/Makefile.files
components/spi_flash/sim/stubs/bootloader_support/include/bootloader_common.h [new file with mode: 0644]
components/spi_flash/sim/stubs/bootloader_support/src/bootloader_common.c [new file with mode: 0644]
examples/system/ota/native_ota_example/main/native_ota_example.c

index 48542c23f66cf14ab706f898a421eaa4d42bb773..c7ac0bc6a2b1a5969faee0e63250f5583fa5f5ef 100644 (file)
@@ -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;
     }
 
index a089a92be0519a6d3d8cdff68640e22bb4257848..291d6375e4ede988f9ed4540b6e7dcdefbe114e4 100644 (file)
@@ -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.
index 07fc9341c503e093504399bd4a2ad7705eee384b..d5a92cc79b6563068699b730b3c5810132a24bf4 100644 (file)
@@ -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);
index 6d332d810f3545a91d4f25b1095ebecdc1b7ceef..6d92a35b0061e7ee50423e8175e5e9661e6a52ea 100644 (file)
@@ -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.
index 38bd080485dccd21433959cd0254e94220ac387d..079a457917f905840aaf29da70c769f4578d0fda 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <stdint.h>
 #include <stdlib.h>
+#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);
index 30a9dac441dbe924c615be29945bb5c6290f0b8c..a1749260129883823b2dc40da88e218a85dce7a4 100644 (file)
 #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;
+}
index a8d537e04e2ba9cb414bb283f4d0fb58dd936d54..1f7c1b4934bddd9e189c0be5af25555c2884b976 100644 (file)
@@ -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;
+}
index e68f8d0d837e5391bb8ec93061d7d05e8c297eb0..5550945bb6f585edf5fdc3dd2b092b8ad6ead51d 100644 (file)
@@ -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;
index 92acf3b025de522b9a3063cd36ef3e8b9730b516..fea89e6a3722e403f569814cdb56bbad2fb5c137 100644 (file)
@@ -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
 }
index a9e8f8f9bacd57fce8c6fec2deae89e7c7e85757..2b229c00b7a9fe610700cd73ad2e171a9c143d38 100644 (file)
@@ -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);
index 7994667f33480525782da3be7008dd056c282bf5..153a859c29d2c2fa0bb2bfea4ff6f3b860ae3acd 100644 (file)
@@ -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);
 }
index f3d5a424af21f0398e85f741de78a3206b0d701a..5345fa97d164a2dc4ca8ca069f82c7e99a4c5bc0 100644 (file)
@@ -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
 }
index 7f63d4c343242b7198df21c8734312403f382ded..045c140de54e7d4729e489b156229b2e55dd8fc8 100644 (file)
@@ -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;
+}
index 7b37db7342fde2b1e5c43e5ffe234cd1f6ca4fa5..c3d004ae396c65426f56cd40f2ee0a935457d4f0 100644 (file)
@@ -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 (file)
index 0000000..856eecd
--- /dev/null
@@ -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 <stdint.h>
+#include <stdio.h>
+#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 (file)
index 0000000..c940fb4
--- /dev/null
@@ -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;
+}
index 1478cbd4e10d48d66702fe00f19a9a8c5edb1363..0f83ca7ab64351b704524f33158ddec19e8b5246 100644 (file)
@@ -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) {