mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
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
This commit is contained in:
parent
886bf4b88e
commit
117c79eae5
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
@ -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;
|
||||
}
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user