}
#ifdef CONFIG_SECURE_BOOT_ENABLED
- ret = esp_secure_boot_verify_signature(it->part->address, data.image_length);
+ ret = esp_secure_boot_verify_signature(it->part->address, data.image_len);
if (ret != ESP_OK) {
ret = ESP_ERR_OTA_VALIDATE_FAILED;
goto cleanup;
}
#ifdef CONFIG_SECURE_BOOT_ENABLED
- esp_err_t ret = esp_secure_boot_verify_signature(partition->address, data.image_length);
+ esp_err_t ret = esp_secure_boot_verify_signature(partition->address, data.image_len);
if (ret != ESP_OK) {
return ESP_ERR_OTA_VALIDATE_FAILED;
}
cpu_configure_region_protection();
/* Sanity check that static RAM is after the stack */
- int *sp = get_sp();
- assert(&_bss_start <= &_bss_end);
- assert(&_data_start <= &_data_end);
- assert(sp < &_bss_start);
- assert(sp < &_data_start);
+#ifndef NDEBUG
+ {
+ int *sp = get_sp();
+ assert(&_bss_start <= &_bss_end);
+ assert(&_data_start <= &_data_end);
+ assert(sp < &_bss_start);
+ assert(sp < &_data_start);
+ }
+#endif
//Clear bss
memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
esp_image_metadata_t data;
/* TODO: load the app image as part of OTA boot decision, so can fallback if loading fails */
+ /* Loading the image here also includes secure boot verification */
err = esp_image_load(ESP_IMAGE_LOAD, partition, &data);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to verify app image @ 0x%x (%d)", partition->offset, err);
return;
}
-#ifdef CONFIG_SECURE_BOOT_ENABLED
- if (esp_secure_boot_enabled()) {
- ESP_LOGI(TAG, "Verifying app signature @ 0x%x (length 0x%x)", partition->offset, data.image_length);
- err = esp_secure_boot_verify_signature(partition->offset, data.image_length);
- if (err != ESP_OK) {
- ESP_LOGE(TAG, "App image @ 0x%x failed signature verification (%d)", partition->offset, err);
- return;
- }
- ESP_LOGD(TAG, "App signature is valid");
- }
-#endif
-
uint32_t drom_addr = 0;
uint32_t drom_load_addr = 0;
uint32_t drom_size = 0;
ESP_LOGD(TAG, "configure drom and irom and start");
Cache_Read_Disable( 0 );
Cache_Flush( 0 );
+
+ /* Clear the MMU entries that are already set up,
+ so the new app only has the mappings it creates.
+ */
+ for (int i = 0; i < DPORT_FLASH_MMU_TABLE_SIZE; i++) {
+ DPORT_PRO_FLASH_MMU_TABLE[i] = DPORT_FLASH_MMU_TABLE_INVALID_VAL;
+ }
+
uint32_t drom_page_count = (drom_size + 64*1024 - 1) / (64*1024); // round up to 64k
ESP_LOGV(TAG, "d mmu set paddr=%08x vaddr=%08x size=%d n=%d", drom_addr & 0xffff0000, drom_load_addr & 0xffff0000, drom_size, drom_page_count );
int rc = cache_flash_mmu_set( 0, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count );
typedef struct {
uint8_t magic;
uint8_t segment_count;
- uint8_t spi_mode; /* flash read mode (esp_image_spi_mode_t as uint8_t) */
- uint8_t spi_speed: 4; /* flash frequency (esp_image_spi_freq_t as uint8_t) */
- uint8_t spi_size: 4; /* flash chip size (esp_image_flash_size_t as uint8_t) */
+ /* flash read mode (esp_image_spi_mode_t as uint8_t) */
+ uint8_t spi_mode;
+ /* flash frequency (esp_image_spi_freq_t as uint8_t) */
+ uint8_t spi_speed: 4;
+ /* flash chip size (esp_image_flash_size_t as uint8_t) */
+ uint8_t spi_size: 4;
uint32_t entry_addr;
- uint8_t extra_header[16]; /* ESP32 additional header, unused by second bootloader */
-} esp_image_header_t;
+ /* WP pin when SPI pins set via efuse (read by ROM bootloader, the IDF bootloader uses software to configure the WP
+ * pin and sets this field to 0xEE=disabled) */
+ uint8_t wp_pin;
+ /* Drive settings for the SPI flash pins (read by ROM bootloader) */
+ uint8_t spi_pin_drv[3];
+ /* Reserved bytes in ESP32 additional header space, currently unused */
+ uint8_t reserved[11];
+ /* If 1, a SHA256 digest "simple hash" (of the entire image) is appended after the checksum. Included in image length. This digest
+ * is separate to secure boot and only used for detecting corruption. For secure boot signed images, the signature
+ * is appended after this (and the simple hash is included in the signed data). */
+ uint8_t hash_appended;
+} __attribute__((packed)) esp_image_header_t;
+
+_Static_assert(sizeof(esp_image_header_t) == 24, "binary image header should be 24 bytes");
/* Header of binary image segment */
typedef struct {
*
* 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[out] data Pointer to the metadata structure to 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.
- * @param log_errors Log errors reading the image.
+ * @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
- * - (Signature) if signature verification is enabled
+ * - 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 image metadata was loaded successfully, 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 data pointer is invalid.
+ * @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_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data);
*/
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length);
+/** @brief Verify the secure boot signature block (deterministic ECDSA w/ SHA256) based on the SHA256 hash of some data.
+ *
+ * Similar to esp_secure_boot_verify_signature(), but can be used when the digest is precalculated.
+ * @param sig_block Pointer to signature block data
+ * @param image_digest Pointer to 32 byte buffer holding SHA-256 hash.
+ *
+ */
+
/** @brief Secure boot verification block, on-flash data format. */
typedef struct {
uint32_t version;
uint8_t signature[64];
} esp_secure_boot_sig_block_t;
+esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest);
+
#define FLASH_OFFS_SECURE_BOOT_IV_DIGEST 0
/** @brief Secure boot IV+digest header */
-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+// Copyright 2017 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.
-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+// Copyright 2017 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.
{
assert(handle != NULL);
mbedtls_sha256_context *ctx = (mbedtls_sha256_context *)handle;
- mbedtls_sha256_finish(ctx, digest);
+ if (digest != NULL) {
+ mbedtls_sha256_finish(ctx, digest);
+ }
+ mbedtls_sha256_free(ctx);
+ free(handle);
}
#else // Bootloader version
// Words per SHA256 block
static const size_t BLOCK_WORDS = (64/sizeof(uint32_t));
+// Words in final SHA256 digest
+static const size_t DIGEST_WORDS = (32/sizeof(uint32_t));
bootloader_sha256_handle_t bootloader_sha256_start()
{
{
assert(handle != NULL);
+ if (digest == NULL) {
+ return; // We'd free resources here, but there are none to free
+ }
+
uint32_t data_words = words_hashed;
- ets_printf("Padding from %d bytes\n", data_words * 4);
- // Pad to a 60 byte long block loaded in the engine
- // (normally end of block is a 64-bit length, but we know
- // the upper 32 bits will be zeroes.)
+ // Pad to a 55 byte long block loaded in the engine
+ // (leaving 1 byte 0x80 plus variable padding plus 8 bytes of length,
+ // to fill a 64 byte block.)
int block_bytes = (words_hashed % BLOCK_WORDS) * 4;
- int pad_bytes = 60 - block_bytes;
+ int pad_bytes = 55 - block_bytes;
if (pad_bytes < 0) {
pad_bytes += 64;
}
static const uint8_t padding[64] = { 0x80, 0, };
+ pad_bytes += 5; // 1 byte for 0x80 plus first 4 bytes of the 64-bit length
+ assert(pad_bytes % 4 == 0); // should be, as (block_bytes % 4 == 0)
+
bootloader_sha256_data(handle, padding, pad_bytes);
- assert(words_hashed % BLOCK_WORDS == 56/4);
+ assert(words_hashed % BLOCK_WORDS == 60/4); // 32-bits left in block
// Calculate 32-bit length for final 32 bits of data
uint32_t bit_count = __builtin_bswap32( data_words * 32 );
assert(words_hashed % BLOCK_WORDS == 0);
- ets_printf("Padded to %d bytes\n", words_hashed * 4);
-
while(REG_READ(SHA_256_BUSY_REG) == 1) { }
REG_WRITE(SHA_256_LOAD_REG, 1);
while(REG_READ(SHA_256_BUSY_REG) == 1) { }
uint32_t *digest_words = (uint32_t *)digest;
uint32_t *sha_text_reg = (uint32_t *)(SHA_TEXT_BASE);
- for (int i = 0; i < BLOCK_WORDS; i++) {
+ for (int i = 0; i < DIGEST_WORDS; i++) {
digest_words[i] = __builtin_bswap32(sha_text_reg[i]);
}
asm volatile ("memw");
#include <rom/rtc.h>
#include <soc/cpu.h>
#include <esp_image_format.h>
+#include <esp_secure_boot.h>
#include <esp_log.h>
#include <bootloader_flash.h>
#include <bootloader_random.h>
static const char *TAG = "esp_image";
+#define HASH_LEN 32 /* SHA-256 digest length */
+
#define SIXTEEN_MB 0x1000000
#define ESP_ROM_CHECKSUM_INITIAL 0xEF
/* Headroom to ensure between stack SP (at time of checking) and data loaded from flash */
-#define STACK_LOAD_HEADROOM 4096
+#define STACK_LOAD_HEADROOM 32768
#ifdef BOOTLOADER_BUILD
/* 64 bits of random data to obfuscate loaded RAM with, until verification is complete
} \
while(0)
+static esp_err_t verify_checksum(bootloader_sha256_handle_t sha_handle, uint32_t checksum_word, esp_image_metadata_t *data);
+
+static esp_err_t __attribute__((unused)) verify_secure_boot(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)
{
#ifdef BOOTLOADER_BUILD
// checksum the image a word at a time. This shaves 30-40ms per MB of image size
uint32_t checksum_word = ESP_ROM_CHECKSUM_INITIAL;
bootloader_sha256_handle_t sha_handle = NULL;
- uint8_t image_digest[32] = { 0 };
if (data == NULL || part == NULL) {
return ESP_ERR_INVALID_ARG;
bzero(data, sizeof(esp_image_metadata_t));
data->start_addr = part->offset;
- sha_handle = bootloader_sha256_start();
- if (sha_handle == NULL) {
- return ESP_ERR_NO_MEM;
- }
-
ESP_LOGD(TAG, "reading image header @ 0x%x", data->start_addr);
err = bootloader_flash_read(data->start_addr, &data->image, sizeof(esp_image_header_t), true);
if (err != ESP_OK) {
goto err;
}
- bootloader_sha256_data(sha_handle, &data->image, sizeof(esp_image_header_t));
+
+ // Calculate SHA-256 of image if secure boot is on, or if image has a hash appended
+#ifdef CONFIG_SECURE_BOOT_ENABLED
+ if (1) {
+#else
+ if (data->image.hash_appended) {
+#endif
+ sha_handle = bootloader_sha256_start();
+ if (sha_handle == NULL) {
+ return ESP_ERR_NO_MEM;
+ }
+ bootloader_sha256_data(sha_handle, &data->image, sizeof(esp_image_header_t));
+ }
ESP_LOGD(TAG, "image header: 0x%02x 0x%02x 0x%02x 0x%02x %08x",
data->image.magic,
FAIL_LOAD("image offset has wrapped");
}
- uint32_t unpadded_length = end_addr - data->start_addr;
- uint32_t length = unpadded_length + 1; // Add a byte for the checksum
- length = (length + 15) & ~15; // Pad to next full 16 byte block
- if (length > part->size) {
- FAIL_LOAD("Image length %d doesn't fit in partition length %d", length, part->size);
+ data->image_len = end_addr - data->start_addr;
+ ESP_LOGV(TAG, "image start 0x%08x end of last section 0x%08x", data->start_addr, end_addr);
+ err = verify_checksum(sha_handle, checksum_word, data);
+ if (err != ESP_OK) {
+ goto err;
}
- // Verify checksum
- uint32_t buf[16/sizeof(uint32_t)];
- err = bootloader_flash_read(end_addr, buf, length - unpadded_length, true);
- uint8_t calc = ((uint8_t *)buf)[length - unpadded_length - 1];
- uint8_t checksum = (checksum_word >> 24)
- ^ (checksum_word >> 16)
- ^ (checksum_word >> 8)
- ^ (checksum_word >> 0);
- if (err != ESP_OK || checksum != calc) {
- FAIL_LOAD("Checksum failed. Calculated 0x%x read 0x%x",
- checksum, calc);
+ if (data->image_len > part->size) {
+ FAIL_LOAD("Image length %d doesn't fit in partition length %d", data->image_len, part->size);
}
- bootloader_sha256_data(sha_handle, buf, length - unpadded_length);
- bootloader_sha256_finish(sha_handle, image_digest);
-
-#if BOOT_LOG_LEVEL >= LOG_LEVEL_DEBUG
- char digest_print[sizeof(image_digest)*2 + 1];
- digest_print[sizeof(image_digest)*2] = 0;
- for (int i = 0; i < sizeof(image_digest); i++) {
- for (int shift = 0; shift < 2; shift++) {
- uint8_t nibble = (image_digest[i] >> (shift ? 0 : 4)) & 0x0F;
- if (nibble < 10) {
- digest_print[i*2+shift] = '0' + nibble;
- } else {
- digest_print[i*2+shift] = 'a' + nibble - 10;
- }
+#ifdef CONFIG_SECURE_BOOT_ENABLED
+ err = verify_secure_boot(sha_handle, data);
+ sha_handle = NULL;
+ if (err != ESP_OK) {
+ goto err;
+ }
+#else // No secure boot, but SHA-256 can be appended for basic corruption detection
+ if (sha_handle != NULL) {
+ err = verify_simple_hash(sha_handle, data);
+ sha_handle = NULL;
+ if (err != ESP_OK) {
+ goto err;
}
}
- ESP_LOGD(TAG, "Total image length %d bytes (unpagged %d)", length, unpadded_length);
- ESP_LOGD(TAG, "Image SHA256 digest: %s", digest_print);
#endif
- // Verify digest here
-
- data->image_length = length;
#ifdef BOOTLOADER_BUILD
if (do_load) { // Need to deobfuscate RAM
err = ESP_ERR_IMAGE_INVALID;
}
if (sha_handle != NULL) {
- // Need to finish the digest process to free the handle
- bootloader_sha256_finish(sha_handle, image_digest);
+ // Need to finish the hash process to free the handle
+ bootloader_sha256_finish(sha_handle, NULL);
}
// Prevent invalid/incomplete data leaking out
bzero(data, sizeof(esp_image_metadata_t));
/* read segment header */
err = bootloader_flash_read(flash_addr, header, sizeof(esp_image_segment_header_t), true);
if (err != ESP_OK) {
+ ESP_LOGE(TAG, "bootloader_flash_read failed at 0x%08x", flash_addr);
return err;
}
- bootloader_sha256_data(sha_handle, header, sizeof(esp_image_segment_header_t));
+ if (sha_handle != NULL) {
+ bootloader_sha256_data(sha_handle, header, sizeof(esp_image_segment_header_t));
+ }
intptr_t load_addr = header->load_addr;
uint32_t data_len = header->data_len;
// counter-intuitive, but it's ~3ms better than using the
// SHA256 block size.
const size_t SHA_CHUNK = 1024;
- if (i % SHA_CHUNK == 0) {
+ if (sha_handle != NULL && i % SHA_CHUNK == 0) {
bootloader_sha256_data(sha_handle, &src[w_i],
MIN(SHA_CHUNK, data_len - i));
}
if (map_segment
&& ((segment_data_offs % SPI_FLASH_MMU_PAGE_SIZE) != (load_addr % SPI_FLASH_MMU_PAGE_SIZE))) {
if (!silent) {
- ESP_LOGE(TAG, "Segment %d has load address 0x%08x, doesn't match segment data at 0x%08x",
+ ESP_LOGE(TAG, "Segment %d load address 0x%08x, doesn't match data 0x%08x",
index, load_addr, segment_data_offs);
}
return ESP_ERR_IMAGE_INVALID;
}
return err;
}
+
+static esp_err_t verify_checksum(bootloader_sha256_handle_t sha_handle, uint32_t checksum_word, esp_image_metadata_t *data)
+{
+ uint32_t unpadded_length = data->image_len;
+ uint32_t length = unpadded_length + 1; // Add a byte for the checksum
+ length = (length + 15) & ~15; // Pad to next full 16 byte block
+
+ // Verify checksum
+ uint8_t buf[16];
+ esp_err_t err = bootloader_flash_read(data->start_addr + unpadded_length, buf, length - unpadded_length, true);
+ uint8_t calc = buf[length - unpadded_length - 1];
+ uint8_t checksum = (checksum_word >> 24)
+ ^ (checksum_word >> 16)
+ ^ (checksum_word >> 8)
+ ^ (checksum_word >> 0);
+ if (err != ESP_OK || checksum != calc) {
+ ESP_LOGE(TAG, "Checksum failed. Calculated 0x%x read 0x%x", checksum, calc);
+ return ESP_ERR_IMAGE_INVALID;
+ }
+ if (sha_handle != NULL) {
+ bootloader_sha256_data(sha_handle, buf, length - unpadded_length);
+ }
+
+ if (data->image.hash_appended) {
+ // Account for the hash in the total image length
+ length += HASH_LEN;
+ }
+ data->image_len = length;
+
+ return ESP_OK;
+}
+
+static void debug_log_hash(const uint8_t *image_hash, const char *caption);
+
+static esp_err_t verify_secure_boot(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data)
+{
+ uint8_t image_hash[HASH_LEN] = { 0 };
+
+ // For secure boot, we calculate the signature hash over the whole file, which includes any "simple" hash
+ // appended to the image for corruption detection
+ if (data->image.hash_appended) {
+ const void *simple_hash = bootloader_mmap(data->start_addr + data->image_len - HASH_LEN, HASH_LEN);
+ bootloader_sha256_data(sha_handle, simple_hash, HASH_LEN);
+ bootloader_munmap(simple_hash);
+ }
+
+ bootloader_sha256_finish(sha_handle, image_hash);
+
+ // Log the hash for debugging
+ debug_log_hash(image_hash, "Calculated secure boot hash");
+
+ // Use hash to verify signature block
+ const esp_secure_boot_sig_block_t *sig_block = bootloader_mmap(data->start_addr + data->image_len, sizeof(esp_secure_boot_sig_block_t));
+ esp_err_t err = esp_secure_boot_verify_signature_block(sig_block, image_hash);
+ bootloader_munmap(sig_block);
+ if (err != ESP_OK) {
+ ESP_LOGE(TAG, "Secure boot signature verification failed");
+
+ // Go back and check if the simple hash matches or not (we're off the fast path so we can re-hash the whole image now)
+ ESP_LOGI(TAG, "Calculating simple hash to check for corruption...");
+ const void *whole_image = bootloader_mmap(data->start_addr, data->image_len - HASH_LEN);
+ if (whole_image != NULL) {
+ sha_handle = bootloader_sha256_start();
+ bootloader_sha256_data(sha_handle, whole_image, data->image_len - HASH_LEN);
+ bootloader_munmap(whole_image);
+ if (verify_simple_hash(sha_handle, data) != ESP_OK) {
+ ESP_LOGW(TAG, "image corrupted on flash");
+ } else {
+ ESP_LOGW(TAG, "image valid, signature bad");
+ }
+ }
+ return ESP_ERR_IMAGE_INVALID;
+ }
+
+ return ESP_OK;
+}
+
+static esp_err_t verify_simple_hash(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data)
+{
+ uint8_t image_hash[HASH_LEN] = { 0 };
+ bootloader_sha256_finish(sha_handle, image_hash);
+
+ // Log the hash for debugging
+ debug_log_hash(image_hash, "Calculated hash");
+
+ // Simple hash for verification only
+ const void *hash = bootloader_mmap(data->start_addr + data->image_len - HASH_LEN, HASH_LEN);
+ if (memcmp(hash, image_hash, HASH_LEN) != 0) {
+ ESP_LOGE(TAG, "Image hash failed - image is corrupt");
+ debug_log_hash(hash, "Expected hash");
+ bootloader_munmap(hash);
+ return ESP_ERR_IMAGE_INVALID;
+ }
+
+ bootloader_munmap(hash);
+ return ESP_OK;
+}
+
+// Log a hash as a hex string
+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);
+#endif
+}
#include "sdkconfig.h"
#include "bootloader_flash.h"
+#include "bootloader_sha.h"
#include "esp_log.h"
#include "esp_image_format.h"
#include "esp_secure_boot.h"
#define SIGNATURE_VERIFICATION_KEYLEN 64
+#define DIGEST_LEN 32
+
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
{
-#ifdef BOOTLOADER_BUILD
- SHA_CTX sha;
-#endif
- uint8_t digest[32];
- ptrdiff_t keylen;
+ uint8_t digest[DIGEST_LEN];
const uint8_t *data;
const esp_secure_boot_sig_block_t *sigblock;
- bool is_valid;
-#ifdef BOOTLOADER_BUILD
- const uint8_t *digest_data;
- uint32_t digest_len;
-#endif
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
return ESP_FAIL;
}
- sigblock = (const esp_secure_boot_sig_block_t *)(data + length);
-
- if (sigblock->version != 0) {
- ESP_LOGE(TAG, "src 0x%x has invalid signature version field 0x%08x", src_addr, sigblock->version);
- goto unmap_and_fail;
- }
-
+ // Calculate digest of main image
#ifdef BOOTLOADER_BUILD
- /* Use ROM SHA functions directly */
- ets_sha_enable();
- ets_sha_init(&sha);
- digest_len = length * 8;
- digest_data = data;
- while (digest_len > 0) {
- uint32_t chunk_len = (digest_len > 64) ? 64 : digest_len;
- ets_sha_update(&sha, SHA2_256, digest_data, chunk_len);
- digest_len -= chunk_len;
- digest_data += chunk_len / 8;
- }
- ets_sha_finish(&sha, SHA2_256, digest);
- ets_sha_disable();
+ bootloader_sha256_handle_t handle = bootloader_sha256_start();
+ bootloader_sha256_data(handle, data, length);
+ bootloader_sha256_finish(handle, digest);
#else
/* Use thread-safe esp-idf SHA function */
esp_sha(SHA2_256, data, length, digest);
#endif
+ // Map the signature block and verify the signature
+ sigblock = (const esp_secure_boot_sig_block_t *)(data + length);
+ esp_err_t err = esp_secure_boot_verify_signature_block(sigblock, digest);
+ bootloader_munmap(data);
+ return err;
+}
+
+esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest)
+{
+ ptrdiff_t keylen;
+ bool is_valid;
+
keylen = signature_verification_key_end - signature_verification_key_start;
if(keylen != SIGNATURE_VERIFICATION_KEYLEN) {
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
- goto unmap_and_fail;
+ return ESP_FAIL;
}
- is_valid = uECC_verify(signature_verification_key_start,
- digest, sizeof(digest), sigblock->signature,
- uECC_secp256r1());
+ if (sig_block->version != 0) {
+ ESP_LOGE(TAG, "image has invalid signature version field 0x%08x", sig_block->version);
+ return ESP_FAIL;
+ }
- bootloader_munmap(data);
+ is_valid = uECC_verify(signature_verification_key_start,
+ image_digest,
+ DIGEST_LEN,
+ sig_block->signature,
+ uECC_secp256r1());
return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID;
-
- unmap_and_fail:
- bootloader_munmap(data);
- return ESP_FAIL;
}
-Subproject commit 325f01637b667af02cc6390965b09d50e6a31dac
+Subproject commit a4207741eca1fb8e5e3670e498ed058320bbcb5a
/* Flash MMU table for APP CPU */
#define DPORT_APP_FLASH_MMU_TABLE ((volatile uint32_t*) 0x3FF12000)
+#define DPORT_FLASH_MMU_TABLE_SIZE 0x100
+#define DPORT_FLASH_MMU_TABLE_INVALID_VAL 0x100
#endif /*_SOC_DPORT_REG_H_ */
uint32_t entry_app = DPORT_APP_FLASH_MMU_TABLE[i];
if (entry_pro != entry_app) {
// clean up entries used by boot loader
- entry_pro = INVALID_ENTRY_VAL;
- DPORT_PRO_FLASH_MMU_TABLE[i] = INVALID_ENTRY_VAL;
+ entry_pro = DPORT_FLASH_MMU_TABLE_INVALID_VAL;
+ DPORT_PRO_FLASH_MMU_TABLE[i] = DPORT_FLASH_MMU_TABLE_INVALID_VAL;
}
if ((entry_pro & INVALID_ENTRY_VAL) == 0 && (i == 0 || i == PRO_IRAM0_FIRST_USABLE_PAGE || entry_pro != 0)) {
s_mmap_page_refcnt[i] = 1;
} else {
- DPORT_PRO_FLASH_MMU_TABLE[i] = INVALID_ENTRY_VAL;
- DPORT_APP_FLASH_MMU_TABLE[i] = INVALID_ENTRY_VAL;
+ DPORT_PRO_FLASH_MMU_TABLE[i] = DPORT_FLASH_MMU_TABLE_INVALID_VAL;
+ DPORT_APP_FLASH_MMU_TABLE[i] = DPORT_FLASH_MMU_TABLE_INVALID_VAL;
}
}
}
# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set
# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set
CONFIG_LOG_BOOTLOADER_LEVEL=2
+# CONFIG_BOOTLOADER_LTO is not set
#
# Security features