Просмотр исходного кода

Secure boot v2 support for ESP32-S2

Supreet Deshpande 5 лет назад
Родитель
Сommit
e640e148cf

+ 27 - 0
components/app_update/esp_ota_ops.c

@@ -40,6 +40,12 @@
 #include "esp_system.h"
 #include "esp_efuse.h"
 
+#ifdef CONFIG_IDF_TARGET_ESP32
+#include "esp32/rom/crc.h"
+#elif CONFIG_IDF_TARGET_ESP32S2
+#include "esp32s2/rom/crc.h"
+#include "esp32s2/rom/secure_boot.h"
+#endif
 
 #define SUB_TYPE_ID(i) (i & 0x0F)
 
@@ -857,3 +863,24 @@ esp_err_t esp_ota_erase_last_boot_app_partition(void)
 
     return ESP_OK;
 }
+
+#if CONFIG_IDF_TARGET_ESP32S2 && CONFIG_SECURE_BOOT_V2_ENABLED
+esp_err_t esp_ota_revoke_secure_boot_public_key(esp_ota_secure_boot_public_key_index_t index) {
+
+    if (!esp_secure_boot_enabled()) {
+        ESP_LOGE(TAG, "Secure boot v2 has not been enabled.");
+        return ESP_FAIL;
+    }
+
+    if (index != SECURE_BOOT_PUBLIC_KEY_INDEX_0 &&
+         index != SECURE_BOOT_PUBLIC_KEY_INDEX_1 &&
+         index != SECURE_BOOT_PUBLIC_KEY_INDEX_2) {
+        ESP_LOGE(TAG, "Invalid Index found for public key revocation %d.", index);
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    ets_secure_boot_revoke_public_key_digest(index);
+    ESP_LOGI(TAG, "Revoked signature block %d.", index);
+    return ESP_OK;
+}
+#endif

+ 28 - 0
components/app_update/include/esp_ota_ops.h

@@ -299,6 +299,34 @@ esp_err_t esp_ota_erase_last_boot_app_partition(void);
  */
 bool esp_ota_check_rollback_is_possible(void);
 
+#if CONFIG_IDF_TARGET_ESP32S2 && (CONFIG_SECURE_BOOT_V2_ENABLED || __DOXYGEN__)
+
+/**
+ * Secure Boot V2 public key indexes.
+ */
+typedef enum {
+    SECURE_BOOT_PUBLIC_KEY_INDEX_0,     /*!< Points to the 0th index of the Secure Boot v2 public key */
+    SECURE_BOOT_PUBLIC_KEY_INDEX_1,     /*!< Points to the 1st index of the Secure Boot v2 public key */
+    SECURE_BOOT_PUBLIC_KEY_INDEX_2      /*!< Points to the 2nd index of the Secure Boot v2 public key */
+} esp_ota_secure_boot_public_key_index_t;
+
+/**
+ * @brief Revokes the old signature digest. To be called in the application after the rollback logic.
+ *
+ * Relevant for Secure boot v2 on ESP32-S2 where upto 3 key digests can be stored (Key #N-1, Key #N, Key #N+1).
+ * When key #N-1 used to sign an app is invalidated, an OTA update is to be sent with an app signed with key #N-1 & Key #N.
+ * After successfully booting the OTA app should call this function to revoke Key #N-1.
+ *
+ * @param index - The index of the signature block to be revoked
+ *
+ * @return
+ *        - ESP_OK: If revocation is successful.
+ *        - ESP_ERR_INVALID_ARG: If the index of the public key to be revoked is incorrect.
+ *        - ESP_FAIL: If secure boot v2 has not been enabled.
+ */
+esp_err_t esp_ota_revoke_secure_boot_public_key(esp_ota_secure_boot_public_key_index_t index);
+#endif /* CONFIG_IDF_TARGET_ESP32S2 */
+
 #ifdef __cplusplus
 }
 #endif

+ 17 - 2
components/bootloader/Kconfig.projbuild

@@ -383,7 +383,7 @@ menu "Security features"
 
         config SECURE_SIGNED_APPS_RSA_SCHEME
             bool "RSA"
-            depends on ESP32_REV_MIN_3 && SECURE_BOOT_V2_ENABLED
+            depends on (ESP32_REV_MIN_3 || IDF_TARGET_ESP32S2) && SECURE_BOOT_V2_ENABLED
             help
                 Appends the RSA-3072 based Signature block to the application.
                 Refer to <Secure Boot Version 2 documentation link> before enabling.
@@ -447,7 +447,9 @@ menu "Security features"
 
         config SECURE_BOOT_V2_ENABLED
             bool "Enable Secure Boot version 2"
-            depends on ESP32_REV_MIN_3
+            depends on ESP32_REV_MIN_3 || IDF_TARGET_ESP32S2
+            select SECURE_ENABLE_SECURE_ROM_DL_MODE if IDF_TARGET_ESP32S2 && !SECURE_INSECURE_ALLOW_DL_MODE
+            select SECURE_DISABLE_ROM_DL_MODE if ESP32_REV_MIN_3 && !SECURE_INSECURE_ALLOW_DL_MODE
             help
                 Build a bootloader which enables Secure Boot version 2 on first boot.
                 Refer to Secure Boot V2 section of the ESP-IDF Programmer's Guide for this version before enabling.
@@ -681,6 +683,19 @@ menu "Security features"
                 key digest, causing an immediate denial of service and possibly allowing an additional fault
                 injection attack to bypass the signature protection.
 
+        config SECURE_INSECURE_ALLOW_DL_MODE
+            bool "Don't automatically restrict UART download mode"
+            depends on SECURE_BOOT_INSECURE && SECURE_BOOT_V2_ENABLED
+            default N
+            help
+                By default, enabling either flash encryption in release mode or secure boot will automatically
+                disable UART download mode on ESP32 ECO3, or enable secure download mode on newer chips.
+                This is recommended to reduce the attack surface of the chip.
+
+                To allow the full UART download mode to stay enabled, enable this option and ensure
+                the options SECURE_DISABLE_ROM_DL_MODE and SECURE_ENABLE_SECURE_ROM_DL_MODE are disabled as applicable.
+                This is not recommended.
+
         config SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
             bool "Leave UART bootloader encryption enabled"
             depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT

+ 25 - 7
components/bootloader/subproject/CMakeLists.txt

@@ -92,15 +92,15 @@ endif()
 
 if(CONFIG_SECURE_BOOT_V2_ENABLED)
     if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
-        get_filename_component(secure_boot_signing_key 
+        get_filename_component(secure_boot_signing_key
             "${SECURE_BOOT_SIGNING_KEY}" ABSOLUTE BASE_DIR "${project_dir}")
 
         if(NOT EXISTS "${secure_boot_signing_key}")
-            message(FATAL_ERROR
-                "Secure Boot Signing Key Not found."
-                "\nGenerate the Secure Boot V2 RSA-PSS 3072 Key."
-                "\nTo generate one, you can use this command:"
-                "\n\t${espsecurepy} generate_signing_key --version 2 ${SECURE_BOOT_SIGNING_KEY}")
+        message(FATAL_ERROR
+            "Secure Boot Signing Key Not found."
+            "\nGenerate the Secure Boot V2 RSA-PSS 3072 Key."
+            "\nTo generate one, you can use this command:"
+            "\n\t${espsecurepy} generate_signing_key --version 2 ${SECURE_BOOT_SIGNING_KEY}")
         endif()
 
         set(bootloader_unsigned_bin "bootloader-unsigned.bin")
@@ -117,7 +117,7 @@ if(CONFIG_SECURE_BOOT_V2_ENABLED)
     else()
         add_custom_command(OUTPUT ".signed_bin_timestamp"
         VERBATIM
-        COMMENT "Bootloader generated but not signed")    
+        COMMENT "Bootloader generated but not signed")
     endif()
 
     add_custom_target (gen_signed_bootloader ALL DEPENDS "${build_dir}/.signed_bin_timestamp")
@@ -166,6 +166,24 @@ elseif(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
             "* Not recommended to re-use the same secure boot keyfile on multiple production devices."
         DEPENDS gen_secure_bootloader_key gen_bootloader_digest_bin
         VERBATIM)
+elseif(CONFIG_SECURE_BOOT_V2_ENABLED AND CONFIG_IDF_TARGET_ESP32S2)
+    add_custom_command(TARGET bootloader.elf POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E echo
+        "=============================================================================="
+    COMMAND ${CMAKE_COMMAND} -E echo
+        "Bootloader built. Secure boot enabled, so bootloader not flashed automatically."
+    COMMAND ${CMAKE_COMMAND} -E echo
+        "To sign the bootloader with additional private keys."
+    COMMAND ${CMAKE_COMMAND} -E echo
+        "\t${espsecurepy} sign_data -k secure_boot_signing_key2.pem -v 2 --append_signatures -o signed_bootloader.bin build/bootloader/bootloader.bin"
+    COMMAND ${CMAKE_COMMAND} -E echo
+        "Secure boot enabled, so bootloader not flashed automatically."
+    COMMAND ${CMAKE_COMMAND} -E echo
+        "\t${esptoolpy_write_flash} ${BOOTLOADER_OFFSET} ${CMAKE_BINARY_DIR}/bootloader.bin"
+    COMMAND ${CMAKE_COMMAND} -E echo
+        "=============================================================================="
+    DEPENDS gen_signed_bootloader
+    VERBATIM)
 elseif(CONFIG_SECURE_BOOT_V2_ENABLED)
     add_custom_command(TARGET bootloader.elf POST_BUILD
     COMMAND ${CMAKE_COMMAND} -E echo

+ 2 - 1
components/bootloader_support/src/bootloader_utility.c

@@ -820,6 +820,7 @@ void bootloader_debug_buffer(const void *buffer, size_t length, const char *labe
 
 esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len, uint8_t *digest)
 {
+
     if (digest == NULL) {
         return ESP_ERR_INVALID_ARG;
     }
@@ -836,7 +837,7 @@ esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len,
     while (len > 0) {
         uint32_t mmu_page_offset = ((flash_offset & MMAP_ALIGNED_MASK) != 0) ? 1 : 0; /* Skip 1st MMU Page if it is already populated */
         uint32_t partial_image_len = MIN(len, ((mmu_free_pages_count - mmu_page_offset) * SPI_FLASH_MMU_PAGE_SIZE)); /* Read the image that fits in the free MMU pages */
-        
+
         const void * image = bootloader_mmap(flash_offset, partial_image_len);
         if (image == NULL) {
             bootloader_sha256_finish(sha_handle, NULL);

+ 11 - 0
components/bootloader_support/src/esp32/secure_boot.c

@@ -392,6 +392,17 @@ esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *imag
     ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
 #endif
 
+#ifdef CONFIG_SECURE_DISABLE_ROM_DL_MODE
+    ESP_LOGI(TAG, "Disable ROM Download mode...");
+    esp_err_t err = esp_efuse_disable_rom_download_mode();
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Could not disable ROM Download mode...");
+        return ESP_FAIL;
+    }
+#else
+    ESP_LOGW(TAG, "Not disabling ROM Download mode - SECURITY COMPROMISED");
+#endif
+
 #ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
     bool rd_dis_now = true;
 #ifdef CONFIG_SECURE_FLASH_ENC_ENABLED

+ 287 - 19
components/bootloader_support/src/esp32s2/secure_boot.c

@@ -11,43 +11,311 @@
 // 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_secure_boot.h"
+#include <string.h>
+
 #include "esp_log.h"
+#include "esp_secure_boot.h"
+#include "soc/efuse_reg.h"
+
+#include "bootloader_flash.h"
+#include "bootloader_sha.h"
+#include "bootloader_utility.h"
+
+#include "esp_rom_crc.h"
+#include "esp_efuse.h"
+#include "esp_efuse_table.h"
+
 #include "esp32s2/rom/secure_boot.h"
 
-static const char *TAG = "secure_boot";
+static const char *TAG = "secure_boot_v2";
+#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
+
+#define SIG_BLOCK_MAGIC_BYTE 0xe7
+#define CRC_SIGN_BLOCK_LEN 1196
+#define SIG_BLOCK_PADDING 4096
+
+#define DIGEST_LEN 32
+
+/* A signature block is valid when it has correct magic byte, crc and image digest. */
+static esp_err_t validate_signature_block(int block_num, const ets_secure_boot_signature_t *sig_block, uint8_t *digest)
+{
+    uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)&sig_block->block[block_num], CRC_SIGN_BLOCK_LEN);
+    if (sig_block->block[block_num].magic_byte != SIG_BLOCK_MAGIC_BYTE) {
+        // All signature blocks have been parsed, no new signature block present.
+        ESP_LOGD(TAG, "Signature block(%d) invalid/absent.", block_num);
+        return ESP_FAIL;
+    }
+    if (sig_block->block[block_num].block_crc != crc) {
+        ESP_LOGE(TAG, "Magic byte correct but incorrect crc.");
+        return ESP_FAIL;
+    }
+    if (memcmp(digest, sig_block->block[block_num].image_digest, DIGEST_LEN)) {
+        ESP_LOGE(TAG, "Magic byte & CRC correct but incorrect image digest.");
+        return ESP_FAIL;
+    } else {
+        ESP_LOGD(TAG, "valid signature block(%d) found", block_num);
+        return ESP_OK;
+    }
+
+    return ESP_FAIL;
+}
+
+// Inputs the flash_offset and length of an image(app or bootloader), validates & verifies its secure boot v2 signature.
+// Generates the public key digests of the valid public keys in a signature block and writes it into trusted_keys.
+// The key_digests in trusted keys whose signature blocks are invalid will be set to NULL.
+static esp_err_t secure_boot_v2_digest_generate(uint32_t flash_offset, uint32_t flash_size, ets_secure_boot_key_digests_t * const trusted_keys)
+{
+    int i = 0;
+    esp_err_t ret = ESP_FAIL;
+
+    uint8_t image_digest[DIGEST_LEN] = {0};
+    uint8_t public_key_digests[SECURE_BOOT_NUM_BLOCKS][DIGEST_LEN];
+    size_t sig_block_addr = flash_offset + ALIGN_UP(flash_size, FLASH_SECTOR_SIZE);
+    ret = bootloader_sha256_flash_contents(flash_offset, sig_block_addr - flash_offset, image_digest);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "error generating image digest, %d", ret);
+        return ret;
+    }
+
+    ESP_LOGD(TAG, "reading signature block");
+    const ets_secure_boot_signature_t *sig_block = bootloader_mmap(sig_block_addr, sizeof(ets_secure_boot_signature_t));
+    if (sig_block == NULL) {
+        ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", sig_block_addr, sizeof(ets_secure_boot_signature_t));
+        return ESP_FAIL;
+    }
+
+    for (i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
+        ret = validate_signature_block(i, sig_block, image_digest);
+        if (ret != ESP_OK) {
+            break;
+        }
+
+        /* Generating the SHA of the public key components in the signature block */
+        bootloader_sha256_handle_t sig_block_sha;
+        sig_block_sha = bootloader_sha256_start();
+        bootloader_sha256_data(sig_block_sha, &sig_block->block[i].key, sizeof(sig_block->block[i].key));
+        bootloader_sha256_finish(sig_block_sha, public_key_digests[i]);
+
+        memcpy((uint8_t *)trusted_keys->key_digests[0], public_key_digests[i], DIGEST_LEN); // Overwriting 0th index to verify each valid signature block
+        /* A signature block is verified when it is valid and the signature in its signature block can be verified with a valid public key */
+        uint8_t verified_digest[DIGEST_LEN] = {0};
+        ets_secure_boot_status_t r = ets_secure_boot_verify_signature(sig_block, image_digest, trusted_keys, verified_digest);
+        if (r != SB_SUCCESS) {
+            ESP_LOGE(TAG, "Secure boot key (%d) verification failed.", i);
+            ret = ESP_FAIL;
+            goto exit;
+        }
+    }
+
+    // At least 1 verified signature block found.
+    if (i > 0) {
+        // validate_signature_block returns ESP_FAIL when a sig block is absent, which isn't an error.
+        while (--i) {
+            trusted_keys->key_digests[i] = public_key_digests[i];
+        }
+        ret = ESP_OK;
+    }
+
+exit:
+    /* Set the pointer to an invalid/absent block to NULL */
+    while (i < SECURE_BOOT_NUM_BLOCKS) {
+        trusted_keys->key_digests[i] = NULL;
+        i++;
+    }
+    ESP_LOGI(TAG, "Secure boot verification success.");
+    bootloader_munmap(sig_block);
+    return ret;
+}
+
+/* Traverses ets_secure_boot_key_digests_t to find the number of non-null key_digests */
+static uint8_t get_signature_block_count(ets_secure_boot_key_digests_t * const trusted_keys) {
+    uint8_t bootloader_sig_block_count = 0;
+    for (uint8_t i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
+        if (trusted_keys->key_digests[i] != NULL) {
+            bootloader_sig_block_count++;
 
-esp_err_t esp_secure_boot_permanently_enable(void)
+            for (uint8_t j = 0; j < DIGEST_LEN ; j++) {
+                ESP_LOGD(TAG, "Secure Boot Digest %d: 0x%x", i, *(((uint8_t *)trusted_keys->key_digests[i]) + j));
+            }
+        }
+    }
+    return bootloader_sig_block_count;
+}
+
+esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *image_data)
 {
-    uint8_t hash[32];
+    ESP_LOGI(TAG, "enabling secure boot v2 - ESP32-S2...");
 
-    if (esp_rom_efuse_is_secure_boot_enabled())
-    {
-        ESP_LOGI(TAG, "secure boot is already enabled, continuing..");
+    if (esp_secure_boot_enabled()) {
+        ESP_LOGI(TAG, "secure boot v2 is already enabled, continuing..");
         return ESP_OK;
     }
 
-    ESP_LOGI(TAG, "Verifying bootloader signature...\n");
-    int r = ets_secure_boot_verify_bootloader(hash, false);
-    if (r != ESP_OK) {
-        ESP_LOGE(TAG, "Failed to verify bootloader signature");
-        return r;
+    esp_err_t ret;
+    /* Verify the bootloader */
+    esp_image_metadata_t bootloader_data = { 0 };
+    ret = esp_image_verify_bootloader_data(&bootloader_data);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "bootloader image appears invalid! error %d", ret);
+        return ret;
     }
 
-    esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */
+    /* Check if secure boot digests are present */
+    bool has_secure_boot_digest = ets_efuse_find_purpose(ETS_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0, NULL);
+    has_secure_boot_digest |= ets_efuse_find_purpose(ETS_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1, NULL);
+    has_secure_boot_digest |= ets_efuse_find_purpose(ETS_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2, NULL);
+    ESP_LOGI(TAG, "Secure boot digests %s", has_secure_boot_digest ? "already present":"absent, generating..");
+
+
+    ets_efuse_clear_program_registers();
+    uint8_t i, j, bootloader_sig_block_count = 0;
+    if (!has_secure_boot_digest) {
+        ets_secure_boot_key_digests_t boot_trusted_keys, app_trusted_keys;
+        uint8_t boot_trusted_key_data[SECURE_BOOT_NUM_BLOCKS][DIGEST_LEN] = {0}, app_trusted_key_data[SECURE_BOOT_NUM_BLOCKS][DIGEST_LEN] = {0};
+
+        for(i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
+            boot_trusted_keys.key_digests[i] = boot_trusted_key_data[i];
+            app_trusted_keys.key_digests[i] = app_trusted_key_data[i];
+        }
+
+        /* Generate the bootloader public key digests */
+        ret = secure_boot_v2_digest_generate(bootloader_data.start_addr, bootloader_data.image_len - SIG_BLOCK_PADDING, &boot_trusted_keys);
+        if (ret != ESP_OK) {
+            ESP_LOGE(TAG, "Public key digest generation failed.");
+            return ret;
+        }
+
+        bootloader_sig_block_count = get_signature_block_count(&boot_trusted_keys);
+        if (bootloader_sig_block_count <= 0) {
+            ESP_LOGI(TAG, "No valid signature blocks found. %d signature block(s) found.", bootloader_sig_block_count);
+            return ESP_FAIL;
+        }
+        ESP_LOGI(TAG, "%d signature block(s) found appended to the bootloader.", bootloader_sig_block_count);
+
+        int unused_key_slots = ets_efuse_count_unused_key_blocks();
+        if (bootloader_sig_block_count > unused_key_slots) {
+            ESP_LOGE(TAG, "Bootloader signatures(%d) more than available key slots(%d).", bootloader_sig_block_count, unused_key_slots);
+            return ESP_FAIL;
+        }
+
+        for (i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
+            if (boot_trusted_keys.key_digests[i] == NULL)  {
+                break;
+            }
+
+            const uint32_t secure_boot_key_purpose[SECURE_BOOT_NUM_BLOCKS] = { ETS_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0,
+                                ETS_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1, ETS_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2 };
+
+            ets_efuse_block_t block = ets_efuse_find_unused_key_block();
+            if (block == ETS_EFUSE_BLOCK_MAX) {
+                ESP_LOGE(TAG, "Key blocks not available.");
+                return ESP_FAIL;
+            }
+
+            int r = ets_efuse_write_key(block, secure_boot_key_purpose[i], boot_trusted_keys.key_digests[i], DIGEST_LEN);
+            if (r != 0) {
+                ESP_LOGE(TAG, "Failed to write efuse block %d with purpose %d. Can't continue.", block, secure_boot_key_purpose[i]);
+                return ESP_FAIL;
+            }
+
+            r = esp_efuse_set_write_protect(block);
+            if (r != 0) {
+                ESP_LOGE(TAG, "Failed to write protect efuse block %d. Can't continue.", block);
+                return ESP_FAIL;
+            }
+        }
+
+        /* Generate the application public key digests */
+        ret = secure_boot_v2_digest_generate(image_data->start_addr, image_data->image_len - SIG_BLOCK_PADDING, &app_trusted_keys);
+        if (ret != ESP_OK) {
+            ESP_LOGE(TAG, "Application signature block is invalid.");
+            return ret;
+        }
+
+        int app_sig_block_count = get_signature_block_count(&app_trusted_keys);
+        ESP_LOGI(TAG, "%d signature block(s) found appended to the application.", app_sig_block_count);
+
+        /* Confirm if atleast one the public key from the application matches a public key in the bootloader
+        (Also, ensure if that public revoke bit is not set for the matched key) */
+        bool match = false;
+        const uint32_t revoke_bits[SECURE_BOOT_NUM_BLOCKS] = { EFUSE_SECURE_BOOT_KEY_REVOKE0,
+                                EFUSE_SECURE_BOOT_KEY_REVOKE1, EFUSE_SECURE_BOOT_KEY_REVOKE2 };
+
+        for (i = 0; i < SECURE_BOOT_NUM_BLOCKS && match == false; i++) {
+
+            if (REG_GET_BIT(EFUSE_RD_REPEAT_DATA1_REG, revoke_bits[i])) {
+                ESP_LOGI(TAG, "Key block(%d) has been revoked.", i);
+                continue; // skip if the key block is revoked
+            }
+
+            for (j = 0; j < SECURE_BOOT_NUM_BLOCKS; j++) {
+                if (!memcmp(boot_trusted_key_data[i], app_trusted_key_data[j], DIGEST_LEN)) {
+                    ESP_LOGI(TAG, "Application key(%d) matches with bootloader key(%d).", j, i);
+                    match = true;
+                    break;
+                }
+            }
+        }
+
+        if (match == false) {
+            ESP_LOGE(TAG, "No application key digest matches the bootloader key digest.");
+            return ESP_FAIL;
+        }
+
+        /* Revoke the empty signature blocks */
+        if (bootloader_sig_block_count < SECURE_BOOT_NUM_BLOCKS) {
+            /* The revocation index can be 0, 1, 2. Bootloader count can be 1,2,3. */
+            for (uint8_t i = bootloader_sig_block_count; i < SECURE_BOOT_NUM_BLOCKS; i++) {
+                ESP_LOGI(TAG, "Revoking empty key digest slot (%d)...", i);
+                ets_secure_boot_revoke_public_key_digest(i);
+            }
+        }
+    }
+
+    esp_err_t err = esp_efuse_batch_write_begin();
+    if (err != ESP_OK) {
+        ESP_LOGI(TAG, "Error batch programming security eFuses.");
+        return err;
+    }
+
+    __attribute__((unused)) static const uint8_t enable = 1;
 
-    esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
     esp_efuse_write_field_bit(ESP_EFUSE_DIS_BOOT_REMAP);
     esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
 
-    // TODO: also disable JTAG here, etc
+#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE
+    ESP_LOGI(TAG, "Enabling Security download mode...");
+    esp_efuse_write_field_bit(ESP_EFUSE_ENABLE_SECURITY_DOWNLOAD);
+#else
+    ESP_LOGW(TAG, "Not enabling Security download mode - SECURITY COMPROMISED");
+#endif
+
+#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
+    ESP_LOGI(TAG, "Disable hardware & software JTAG...");
+    esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
+    esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
+#else
+    ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
+#endif
 
-    esp_err_t err = esp_efuse_batch_write_commit();
+#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
+    esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE);
+#endif
 
-    if (err == ESP_OK) {
-        assert(esp_rom_efuse_is_secure_boot_enabled());
-        ESP_LOGI(TAG, "Secure boot permanently enabled");
+    esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
+
+    err = esp_efuse_batch_write_commit();
+    if (err != ESP_OK) {
+        ESP_LOGI(TAG, "Error programming security eFuses.");
+        return err;
     }
 
+#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE
+    assert(ets_efuse_secure_boot_aggressive_revoke_enabled());
+#endif
+
+    assert(esp_rom_efuse_is_secure_boot_enabled());
+    ESP_LOGI(TAG, "Secure boot permanently enabled");
+
     return ESP_OK;
 }

+ 39 - 29
components/bootloader_support/src/esp32s2/secure_boot_signatures.c

@@ -13,29 +13,32 @@
 // limitations under the License.
 #include "sdkconfig.h"
 
+#include <string.h>
+#include "esp_fault.h"
 #include "bootloader_flash.h"
 #include "bootloader_sha.h"
+#include "bootloader_utility.h"
 #include "esp_log.h"
 #include "esp_image_format.h"
+#include "esp_secure_boot.h"
 #include "esp32s2/rom/secure_boot.h"
 
 static const char* TAG = "secure_boot";
 
 #define DIGEST_LEN 32
+#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
 
 esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
 {
-    ets_secure_boot_key_digests_t trusted_keys = { 0 };
     uint8_t digest[DIGEST_LEN];
     uint8_t verified_digest[DIGEST_LEN] = { 0 }; /* Note: this function doesn't do any anti-FI checks on this buffer */
     const uint8_t *data;
 
     ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
 
-    if ((src_addr + length) % 4096 != 0) {
-        ESP_LOGE(TAG, "addr 0x%x length 0x%x doesn't end on a sector boundary", src_addr, length);
-        return ESP_ERR_INVALID_ARG;
-    }
+    /* Padding to round off the input to the nearest 4k boundary */
+    int padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
+    ESP_LOGD(TAG, "verifying src_addr 0x%x length", src_addr, padded_length);
 
     data = bootloader_mmap(src_addr, length + sizeof(struct ets_secure_boot_sig_block));
     if (data == NULL) {
@@ -43,23 +46,16 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
         return ESP_FAIL;
     }
 
-    // Calculate digest of main image
-#ifdef BOOTLOADER_BUILD
-    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
-
-    int r = ets_secure_boot_read_key_digests(&trusted_keys);
-
-    if (r == ETS_OK) {
-        const ets_secure_boot_signature_t *sig = (const ets_secure_boot_signature_t *)(data + length);
-        // TODO: calling this function in IDF app context is unsafe
-        r = ets_secure_boot_verify_signature(sig, digest, &trusted_keys, verified_digest);
+    /* Calculate digest of main image */
+    esp_err_t err = bootloader_sha256_flash_contents(src_addr, padded_length, digest);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, padded_length);
+        bootloader_munmap(data);
+        return err;
     }
+
+    const ets_secure_boot_signature_t *sig = (const ets_secure_boot_signature_t *)(data + length);
+    int r = esp_secure_boot_verify_rsa_signature_block(sig, digest, verified_digest);
     bootloader_munmap(data);
 
     return (r == ETS_OK) ? ESP_OK : ESP_FAIL;
@@ -68,15 +64,29 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
 esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
 {
     ets_secure_boot_key_digests_t trusted_keys;
+    ets_secure_boot_key_digests_t trusted_key_copies[2];
+    ETS_STATUS r;
+
+    memset(&trusted_keys, 0, sizeof(ets_secure_boot_key_digests_t));
+    memset(trusted_key_copies, 0, 2 * sizeof(ets_secure_boot_key_digests_t));
+
+    if (!esp_secure_boot_enabled()) {
+        return ESP_OK;
+    }
 
-    int r = ets_secure_boot_read_key_digests(&trusted_keys);
-    if (r != 0) {
-        ESP_LOGE(TAG, "No trusted key digests were found in efuse!");
-    } else {
-        ESP_LOGD(TAG, "Verifying with RSA-PSS...");
-        // TODO: calling this function in IDF app context is unsafe
-        r = ets_secure_boot_verify_signature(sig_block, image_digest, &trusted_keys, verified_digest);
+    r = ets_secure_boot_read_key_digests(&trusted_keys);
+    if (r != ETS_OK) {
+        ESP_LOGI(TAG, "Could not read secure boot digests!");
+        return ESP_FAIL;
     }
 
-    return (r == 0) ? ESP_OK : ESP_ERR_IMAGE_INVALID;
+    // Create the copies for FI checks (assuming result is ETS_OK, if it's not then it'll fail the fault check anyhow)
+    ets_secure_boot_read_key_digests(&trusted_key_copies[0]);
+    ets_secure_boot_read_key_digests(&trusted_key_copies[1]);
+    ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[0], sizeof(ets_secure_boot_key_digests_t)) == 0);
+    ESP_FAULT_ASSERT(memcmp(&trusted_keys, &trusted_key_copies[1], sizeof(ets_secure_boot_key_digests_t)) == 0);
+
+    ESP_LOGI(TAG, "Verifying with RSA-PSS boot...");
+    r = ets_secure_boot_verify_signature(sig_block, image_digest, &trusted_keys, verified_digest);
+    return (r == ETS_OK) ? ESP_OK : ESP_FAIL;
 }

+ 2 - 2
components/bootloader_support/src/esp_image_format.c

@@ -275,7 +275,7 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
        "only verify signature in bootloader" into the macro so it's tested multiple times.
      */
 #if CONFIG_SECURE_BOOT_V2_ENABLED
-    ESP_FAULT_ASSERT(memcmp(image_digest, verified_digest, HASH_LEN) == 0);
+    ESP_FAULT_ASSERT(!esp_secure_boot_enabled() || memcmp(image_digest, verified_digest, HASH_LEN) == 0);
 #else // Secure Boot V1 on ESP32, only verify signatures for apps not bootloaders
     ESP_FAULT_ASSERT(data->start_addr == ESP_BOOTLOADER_OFFSET || memcmp(image_digest, verified_digest, HASH_LEN) == 0);
 #endif
@@ -310,7 +310,7 @@ err:
     // Prevent invalid/incomplete data leaking out
     bzero(data, sizeof(esp_image_metadata_t));
     return err;
-    }
+}
 
 esp_err_t bootloader_load_image(const esp_partition_pos_t *part, esp_image_metadata_t *data)
 {

+ 1 - 0
components/bootloader_support/src/idf/bootloader_sha.c

@@ -51,4 +51,5 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest
     }
     mbedtls_sha256_free(ctx);
     free(handle);
+    handle = NULL;
 }

+ 69 - 13
components/bootloader_support/src/idf/secure_boot_signatures.c

@@ -27,6 +27,11 @@
 #include "mbedtls/ctr_drbg.h"
 #include <string.h>
 #include <sys/param.h>
+#include "esp_secure_boot.h"
+
+#ifdef CONFIG_IDF_TARGET_ESP32S2
+#include <esp32s2/rom/secure_boot.h>
+#endif
 
 #define DIGEST_LEN 32
 
@@ -142,6 +147,26 @@ static const char *TAG = "secure_boot_v2";
 #define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
 #define RSA_KEY_SIZE 384 /* RSA 3072 Bits */
 
+#if CONFIG_IDF_TARGET_ESP32S2
+inline static bool digest_matches(const void *trusted, const void *computed)
+{
+    if (trusted == NULL) {
+        return false;
+    }
+
+    // 'trusted' is probably a pointer to read-only efuse registers,
+    // which only support word reads. memcmp() cannot be guaranteed
+    // to do word reads, so we make a local copy here (we know that
+    // memcpy() will do word operations if it can).
+    uint8_t __attribute__((aligned(4))) trusted_local[ETS_DIGEST_LEN];
+    uint8_t __attribute__((aligned(4))) computed_local[ETS_DIGEST_LEN];
+
+    memcpy(trusted_local, trusted, ETS_DIGEST_LEN);
+    memcpy(computed_local, computed, ETS_DIGEST_LEN);
+    return memcmp(trusted_local, computed_local, ETS_DIGEST_LEN) == 0;
+}
+#endif /* CONFIG_IDF_TARGET_ESP32S2 */
+
 esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
 {
     uint8_t digest[DIGEST_LEN] = {0};
@@ -173,23 +198,19 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
 
 esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
 {
-    int i = 0;
-
+    uint8_t i = 0;
 #if CONFIG_SECURE_BOOT_V2_ENABLED /* Verify key against efuse block */
-    uint8_t efuse_trusted_digest[DIGEST_LEN] = {0}, sig_block_trusted_digest[DIGEST_LEN] = {0};
-    memcpy(efuse_trusted_digest, (uint8_t *) EFUSE_BLK2_RDATA0_REG, sizeof(efuse_trusted_digest));
+    uint8_t sig_block_key_digest[SECURE_BOOT_NUM_BLOCKS][DIGEST_LEN] = {0};
 
     /* Note: in IDF verification we don't add any fault injection resistance, as we don't expect this to be called
        during boot-time verification. */
     memset(verified_digest, 0, DIGEST_LEN);
 
-    /* Generating the SHA of the public key components in the signature block */
-    bootloader_sha256_handle_t sig_block_sha;
-    sig_block_sha = bootloader_sha256_start();
-    bootloader_sha256_data(sig_block_sha, &sig_block->block[0].key, sizeof(sig_block->block[0].key));
-    bootloader_sha256_finish(sig_block_sha, (unsigned char *)sig_block_trusted_digest);
+#if CONFIG_IDF_TARGET_ESP32
+    uint8_t efuse_trusted_digest[DIGEST_LEN] = {0};
+    memcpy(efuse_trusted_digest, (uint8_t *) EFUSE_BLK2_RDATA0_REG, sizeof(efuse_trusted_digest));
 
-    if (memcmp(efuse_trusted_digest, sig_block_trusted_digest, DIGEST_LEN) != 0) {
+    if (memcmp(efuse_trusted_digest, sig_block_key_digest, DIGEST_LEN) != 0) {
         const uint8_t zeroes[DIGEST_LEN] = {0};
         /* Can't continue if secure boot is enabled, OR if a different digest is already written in efuse BLK2
 
@@ -200,7 +221,25 @@ esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signa
             return ESP_FAIL;
         }
     }
-#endif
+#elif CONFIG_IDF_TARGET_ESP32S2
+    bool match = false;
+    ets_secure_boot_key_digests_t efuse_trusted_digest;
+    ETS_STATUS r;
+    r = ets_secure_boot_read_key_digests(&efuse_trusted_digest);
+    if (r != 0) {
+        ESP_LOGI(TAG, "Could not read secure boot digests!");
+        return ESP_FAIL;
+    }
+#endif /* CONFIG_IDF_TARGET_ESP32 */
+
+    /* Generating the SHA of the public key components in the signature block */
+    for (i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
+        bootloader_sha256_handle_t sig_block_sha;
+        sig_block_sha = bootloader_sha256_start();
+        bootloader_sha256_data(sig_block_sha, &sig_block->block[i].key, sizeof(sig_block->block[i].key));
+        bootloader_sha256_finish(sig_block_sha, (unsigned char *)sig_block_key_digest[i]);
+    }
+#endif /* CONFIG_SECURE_BOOT_V2_ENABLED */
 
     ESP_LOGI(TAG, "Verifying with RSA-PSS...");
     int ret = 0;
@@ -222,6 +261,19 @@ esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signa
     }
 
     for (i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
+#if CONFIG_IDF_TARGET_ESP32S2
+        for (uint8_t j = 0; j < SECURE_BOOT_NUM_BLOCKS; j++) {
+            if (digest_matches(efuse_trusted_digest.key_digests[j], sig_block_key_digest[i])) {
+                ESP_LOGI(TAG, "eFuse key matches(%d) matches the application key(%d).", j, i);
+                match = true;
+                break;
+            }
+        }
+        if (match == false) {
+            continue; // Skip the public keys whose digests don't match.
+        }
+# endif
+
         const mbedtls_mpi N = { .s = 1,
                                 .n = sizeof(sig_block->block[i].key.n)/sizeof(mbedtls_mpi_uint),
                                 .p = (void *)sig_block->block[i].key.n,
@@ -260,7 +312,7 @@ esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signa
             goto exit;
         }
 
-        ret = mbedtls_rsa_rsassa_pss_verify( &pk, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, 32, 
+        ret = mbedtls_rsa_rsassa_pss_verify( &pk, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, DIGEST_LEN, 
                                             sig_block->block[i].image_digest, sig_be);
         if (ret != 0) {
             ESP_LOGE(TAG, "Failed mbedtls_rsa_rsassa_pss_verify, err: %d", ret);
@@ -276,6 +328,10 @@ esp_err_t esp_secure_boot_verify_rsa_signature_block(const ets_secure_boot_signa
     
     free(sig_be);
     free(buf);
-    return (!ret) ? ESP_OK : ESP_ERR_IMAGE_INVALID;
+#if CONFIG_IDF_TARGET_ESP32
+    return (ret != 0) ? ESP_ERR_IMAGE_INVALID: ESP_OK;
+#elif CONFIG_IDF_TARGET_ESP32S2
+    return (ret != 0 || match == false) ? ESP_ERR_IMAGE_INVALID: ESP_OK;
+#endif /* CONFIG_IDF_TARGET_ESP32 */
 }
 #endif