Merge branch 'feat/secure_boot_v2_v41' into 'master'

feat/secure_boot_v2: Adding secure boot v2 support to ESP32-ECO3

Closes IDF-799

See merge request espressif/esp-idf!6778
This commit is contained in:
Mahavir Jain 2020-02-27 18:54:08 +08:00
commit 5f897fd33c
80 changed files with 2266 additions and 310 deletions

View file

@ -10,15 +10,31 @@ unset(link_options)
# Add the following build specifications here, since these seem to be dependent
# on config values on the root Kconfig.
if(CONFIG_COMPILER_OPTIMIZATION_SIZE)
list(APPEND compile_options "-Os")
list(APPEND compile_options "-freorder-blocks")
elseif(CONFIG_COMPILER_OPTIMIZATION_DEFAULT)
list(APPEND compile_options "-Og")
elseif(CONFIG_COMPILER_OPTIMIZATION_NONE)
list(APPEND compile_options "-O0")
elseif(CONFIG_COMPILER_OPTIMIZATION_PERF)
list(APPEND compile_options "-O2")
if(NOT BOOTLOADER_BUILD)
if(CONFIG_COMPILER_OPTIMIZATION_SIZE)
list(APPEND compile_options "-Os")
list(APPEND compile_options "-freorder-blocks")
elseif(CONFIG_COMPILER_OPTIMIZATION_DEFAULT)
list(APPEND compile_options "-Og")
elseif(CONFIG_COMPILER_OPTIMIZATION_NONE)
list(APPEND compile_options "-O0")
elseif(CONFIG_COMPILER_OPTIMIZATION_PERF)
list(APPEND compile_options "-O2")
endif()
else() # BOOTLOADER_BUILD
if(CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE)
list(APPEND compile_options "-Os")
list(APPEND compile_options "-freorder-blocks")
elseif(CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG)
list(APPEND compile_options "-Og")
elseif(CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE)
list(APPEND compile_options "-O0")
elseif(CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF)
list(APPEND compile_options "-O2")
endif()
endif()

View file

@ -170,7 +170,7 @@ mainmenu "Espressif IoT Development Framework Configuration"
prompt "Optimization Level"
default COMPILER_OPTIMIZATION_DEFAULT
help
This option sets compiler optimization level (gcc -O argument).
This option sets compiler optimization level (gcc -O argument) for the app.
- The "Default" setting will add the -0g flag to CFLAGS.
- The "Size" setting will add the -0s flag to CFLAGS.
@ -188,6 +188,9 @@ mainmenu "Espressif IoT Development Framework Configuration"
Note that custom optimization levels may be unsupported.
Compiler optimization for the IDF bootloader is set separately,
see the BOOTLOADER_COMPILER_OPTIMIZATION setting.
config COMPILER_OPTIMIZATION_DEFAULT
bool "Debug (-Og)"
config COMPILER_OPTIMIZATION_SIZE

View file

@ -6,11 +6,15 @@ if(BOOTLOADER_BUILD OR NOT CONFIG_APP_BUILD_BOOTLOADER)
endif()
add_dependencies(bootloader partition_table)
# When secure boot is enabled, do not flash bootloader along with invocation of `idf.py flash`
if(NOT CONFIG_SECURE_BOOT)
set(flash_bootloader FLASH_IN_PROJECT)
endif()
esptool_py_custom_target(bootloader-flash bootloader "bootloader")
esptool_py_flash_target_image(bootloader-flash bootloader "0x1000" "${BOOTLOADER_BUILD_DIR}/bootloader.bin")
# Also attach an image to the project flash target
if(NOT CONFIG_SECURE_BOOT_ENABLED)
if(NOT CONFIG_SECURE_BOOT)
esptool_py_flash_target_image(flash bootloader "0x1000" "${BOOTLOADER_BUILD_DIR}/bootloader.bin")
endif()

View file

@ -1,4 +1,29 @@
menu "Bootloader config"
choice BOOTLOADER_COMPILER_OPTIMIZATION
prompt "Bootloader optimization Level"
default BOOTLOADER_COMPILER_OPTIMIZATION_SIZE
help
This option sets compiler optimization level (gcc -O argument)
for the bootloader.
- The default "Size" setting will add the -0s flag to CFLAGS.
- The "Debug" setting will add the -Og flag to CFLAGS.
- The "Performance" setting will add the -O2 flag to CFLAGS.
- The "None" setting will add the -O0 flag to CFLAGS.
Note that custom optimization levels may be unsupported.
config BOOTLOADER_COMPILER_OPTIMIZATION_SIZE
bool "Size (-Os)"
config BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG
bool "Debug (-Og)"
config BOOTLOADER_COMPILER_OPTIMIZATION_PERF
bool "Optimize for performance (-O2)"
config BOOTLOADER_COMPILER_OPTIMIZATION_NONE
bool "Debug without optimization (-O0)"
endchoice
choice BOOTLOADER_LOG_LEVEL
bool "Bootloader log verbosity"
default BOOTLOADER_LOG_LEVEL_INFO
@ -224,7 +249,7 @@ menu "Bootloader config"
config BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP
bool "Skip image validation when exiting deep sleep"
depends on (SECURE_BOOT_ENABLED && SECURE_BOOT_INSECURE) || !SECURE_BOOT_ENABLED
depends on (SECURE_BOOT && SECURE_BOOT_INSECURE) || !SECURE_BOOT
default n
help
This option disables the normal validation of an image coming out of
@ -279,12 +304,12 @@ menu "Security features"
config SECURE_SIGNED_ON_BOOT
bool
default y
depends on SECURE_BOOT_ENABLED || SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT
depends on SECURE_BOOT || SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT
config SECURE_SIGNED_ON_UPDATE
bool
default y
depends on SECURE_BOOT_ENABLED || SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
depends on SECURE_BOOT || SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
config SECURE_SIGNED_APPS
bool
@ -298,8 +323,7 @@ menu "Security features"
config SECURE_SIGNED_APPS_NO_SECURE_BOOT
bool "Require signed app images"
default n
depends on !SECURE_BOOT_ENABLED
depends on !SECURE_BOOT
help
Require apps to be signed to verify their integrity.
@ -308,6 +332,35 @@ menu "Security features"
against remote network access, but not physical access. Compared to using hardware Secure Boot this option
is much simpler to implement.
choice SECURE_SIGNED_APPS_SCHEME
bool "App Signing Scheme"
depends on SECURE_BOOT || SECURE_SIGNED_APPS_NO_SECURE_BOOT
default SECURE_SIGNED_APPS_ECDSA_SCHEME if SECURE_BOOT_V1_ENABLED
default SECURE_SIGNED_APPS_RSA_SCHEME if SECURE_BOOT_V2_ENABLED
help
Select the Secure App signing scheme. Depends on the Chip Revision.
There are two options:
1. ECDSA based secure boot scheme. (Only choice for Secure Boot V1)
Supported in ESP32 and ESP32-ECO3.
2. The RSA based secure boot scheme. (Only choice for Secure Boot V2)
Supported in ESP32-ECO3. (ESP32 Chip Revision 3 onwards)
config SECURE_SIGNED_APPS_ECDSA_SCHEME
bool "ECDSA"
depends on IDF_TARGET_ESP32 && (SECURE_SIGNED_APPS_NO_SECURE_BOOT || SECURE_BOOT_V1_ENABLED)
help
Embeds the ECDSA public key in the bootloader and signs the application with an ECDSA key.
Refer to the documentation before enabling.
config SECURE_SIGNED_APPS_RSA_SCHEME
bool "RSA"
depends on ESP32_REV_MIN_3 && 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.
endchoice
config SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT
bool "Bootloader verifies app signatures"
default n
@ -334,23 +387,48 @@ menu "Security features"
If hardware secure boot is not enabled, this option still adds significant security against network-based
attackers by preventing spoofing of OTA updates.
config SECURE_BOOT_ENABLED
bool "Enable hardware secure boot in bootloader (READ DOCS FIRST)"
config SECURE_BOOT
bool "Enable hardware Secure Boot in bootloader (READ DOCS FIRST)"
default n
help
Build a bootloader which enables secure boot on first boot.
Build a bootloader which enables Secure Boot on first boot.
Once enabled, secure boot will not boot a modified bootloader. The bootloader will only load a partition
Once enabled, Secure Boot will not boot a modified bootloader. The bootloader will only load a partition
table or boot an app if the data has a verified digital signature. There are implications for reflashing
updated apps once secure boot is enabled.
When enabling secure boot, JTAG and ROM BASIC Interpreter are permanently disabled by default.
Refer to https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html before enabling.
choice SECURE_BOOT_VERSION
bool "Select secure boot version"
default SECURE_BOOT_V2_ENABLED if ESP32_REV_MIN_3
depends on SECURE_BOOT
help
Select the Secure Boot Version. Depends on the Chip Revision.
Secure Boot V2 is the new RSA based secure boot scheme.
Supported in ESP32-ECO3. (ESP32 Chip Revision 3 onwards)
Secure Boot V1 is the AES based secure boot scheme.
Supported in ESP32 and ESP32-ECO3.
config SECURE_BOOT_V1_ENABLED
bool "Enable Secure Boot version 1"
depends on IDF_TARGET_ESP32
help
Build a bootloader which enables secure boot version 1 on first boot.
Refer to the Secure Boot section of the ESP-IDF Programmer's Guide for this version before enabling.
config SECURE_BOOT_V2_ENABLED
bool "Enable Secure Boot version 2"
depends on ESP32_REV_MIN_3
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.
endchoice
choice SECURE_BOOTLOADER_MODE
bool "Secure bootloader mode"
depends on SECURE_BOOT_ENABLED
depends on SECURE_BOOT_V1_ENABLED
default SECURE_BOOTLOADER_ONE_TIME_FLASH
config SECURE_BOOTLOADER_ONE_TIME_FLASH
@ -385,7 +463,8 @@ menu "Security features"
If enabled (default), these binary files are signed as part of the build process. The file named in
"Secure boot private signing key" will be used to sign the image.
If disabled, unsigned app/partition data will be built. They must be signed manually using espsecure.py
If disabled, unsigned app/partition data will be built. They must be signed manually using espsecure.py.
Version 1 to enable ECDSA Based Secure Boot and Version 2 to enable RSA based Secure Boot.
(for example, on a remote signing server.)
config SECURE_BOOT_SIGNING_KEY
@ -395,28 +474,32 @@ menu "Security features"
help
Path to the key file used to sign app images.
Key file is an ECDSA private key (NIST256p curve) in PEM format.
Key file is an ECDSA private key (NIST256p curve) in PEM format for Secure Boot V1.
Key file is an RSA private key in PEM format for Secure Boot V2.
Path is evaluated relative to the project directory.
You can generate a new signing key by running the following command:
espsecure.py generate_signing_key secure_boot_signing_key.pem
See https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html for details.
See the Secure Boot section of the ESP-IDF Programmer's Guide for this version for details.
config SECURE_BOOT_VERIFICATION_KEY
string "Secure boot public signature verification key"
depends on SECURE_SIGNED_APPS && !SECURE_BOOT_BUILD_SIGNED_BINARIES
depends on SECURE_SIGNED_APPS && !SECURE_BOOT_BUILD_SIGNED_BINARIES && !SECURE_SIGNED_APPS_RSA_SCHEME
default "signature_verification_key.bin"
help
Path to a public key file used to verify signed images. This key is compiled into the bootloader and/or
Path to a public key file used to verify signed images.
Secure Boot V1: This ECDSA public key is compiled into the bootloader and/or
app, to verify app images.
Secure Boot V2: This RSA public key is compiled into the signature block at
the end of the bootloader/app.
Key file is in raw binary format, and can be extracted from a
PEM formatted private key using the espsecure.py
extract_public_key command.
Refer to https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html before enabling.
Refer to the Secure Boot section of the ESP-IDF Programmer's Guide for this version before enabling.
choice SECURE_BOOTLOADER_KEY_ENCODING
bool "Hardware Key Encoding"
@ -443,7 +526,7 @@ menu "Security features"
config SECURE_BOOT_INSECURE
bool "Allow potentially insecure options"
depends on SECURE_BOOT_ENABLED
depends on SECURE_BOOT
default N
help
You can disable some of the default protections offered by secure boot, in order to enable testing or a
@ -451,7 +534,7 @@ menu "Security features"
Only enable these options if you are very sure.
Refer to https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html before enabling.
Refer to the Secure Boot section of the ESP-IDF Programmer's Guide for this version before enabling.
config SECURE_FLASH_ENC_ENABLED
bool "Enable flash encryption on boot (READ DOCS FIRST)"
@ -495,7 +578,7 @@ menu "Security features"
Select Release mode only for production or manufacturing. Once enabled you can not reflash using UART
bootloader
Refer to https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html and
Refer to the Secure Boot section of the ESP-IDF Programmer's Guide for this version and
https://docs.espressif.com/projects/esp-idf/en/latest/security/flash-encryption.html for details.
config SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT

View file

@ -45,7 +45,7 @@ clean: bootloader-clean
bootloader-list-components:
$(BOOTLOADER_MAKE) list-components
ifndef CONFIG_SECURE_BOOT_ENABLED
ifndef CONFIG_SECURE_BOOT
# If secure boot disabled, bootloader flashing is integrated
# with 'make flash' and no warnings are printed.
@ -115,13 +115,35 @@ $(BOOTLOADER_DIGEST_BIN): $(BOOTLOADER_BIN) $(SECURE_BOOTLOADER_KEY) | check_pyt
@echo "DIGEST $(notdir $@)"
$(ESPSECUREPY) digest_secure_bootloader -k $(SECURE_BOOTLOADER_KEY) -o $@ $<
else # CONFIG_SECURE_BOOT_ENABLED && !CONFIG_SECURE_BOOTLOADER_REFLASHABLE && !CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH
else ifdef CONFIG_SECURE_BOOT_V2_ENABLED
BOOTLOADER_SIGNED_BIN := $(BOOTLOADER_BUILD_DIR)/bootloader-signed.bin
ifdef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
bootloader: $(BOOTLOADER_BIN) $(SDKCONFIG_MAKEFILE) | check_python_dependencies
$(ESPSECUREPY) sign_data --keyfile $(SECURE_BOOT_SIGNING_KEY) --version 2 \
-o $(BOOTLOADER_SIGNED_BIN) $(BOOTLOADER_BIN)
else
bootloader: $(BOOTLOADER_BIN) $(SDKCONFIG_MAKEFILE) | check_python_dependencies
@echo "Bootloader not signed. Sign the bootloader before flashing."
@echo "To sign the bootloader, you can use this command:"
@echo "espsecure.py sign_data --keyfile SECURE_BOOT_SIGNING_KEY --version 2 $(BOOTLOADER_BIN)"
endif
@echo $(SEPARATOR)
@echo "Use the following command to flash the bootloader:"
ifdef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
@echo "$(ESPTOOLPY_WRITE_FLASH) $(BOOTLOADER_OFFSET) $(BOOTLOADER_SIGNED_BIN)"
else
@echo "$(ESPTOOLPY_WRITE_FLASH) $(BOOTLOADER_OFFSET) $(BOOTLOADER_BIN)"
endif
@echo $(SEPARATOR)
else # CONFIG_SECURE_BOOT && !CONFIG_SECURE_BOOTLOADER_REFLASHABLE \
&& !CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH && !CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
bootloader:
@echo "Invalid bootloader target: bad sdkconfig?"
@exit 1
endif
ifndef CONFIG_SECURE_BOOT_ENABLED
ifndef CONFIG_SECURE_BOOT
# don't build bootloader by default if secure boot is enabled
all_binaries: $(BOOTLOADER_BIN)
endif
@ -131,3 +153,8 @@ bootloader-clean: $(SDKCONFIG_MAKEFILE)
ifdef CONFIG_SECURE_BOOTLOADER_REFLASHABLE
rm -f $(SECURE_BOOTLOADER_KEY) $(BOOTLOADER_DIGEST_BIN)
endif
ifdef CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
ifdef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
rm -f $(BOOTLOADER_SIGNED_BIN)
endif
endif

View file

@ -19,8 +19,8 @@ set(bootloader_binary_files
idf_build_get_property(project_dir PROJECT_DIR)
# There are some additional processing when CONFIG_CONFIG_SECURE_SIGNED_APPS. This happens
# when either CONFIG_SECURE_BOOT_ENABLED or SECURE_BOOT_BUILD_SIGNED_BINARIES.
# There are some additional processing when CONFIG_SECURE_SIGNED_APPS. This happens
# when either CONFIG_SECURE_BOOT_V1_ENABLED or CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES.
# For both cases, the user either sets binaries to be signed during build or not
# using CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES.
#
@ -29,7 +29,13 @@ idf_build_get_property(project_dir PROJECT_DIR)
if(CONFIG_SECURE_SIGNED_APPS)
add_custom_target(gen_secure_boot_keys)
if(CONFIG_SECURE_BOOT_ENABLED)
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
set(secure_apps_signing_scheme "1")
elseif(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
set(secure_apps_signing_scheme "2")
endif()
if(CONFIG_SECURE_BOOT_V1_ENABLED)
# Check that the configuration is sane
if((CONFIG_SECURE_BOOTLOADER_REFLASHABLE AND CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH) OR
(NOT CONFIG_SECURE_BOOTLOADER_REFLASHABLE AND NOT CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH))
@ -60,7 +66,8 @@ if(CONFIG_SECURE_SIGNED_APPS)
# (to pick up a new signing key if one exists, etc.)
fail_at_build_time(gen_secure_boot_signing_key
"Secure Boot Signing Key ${CONFIG_SECURE_BOOT_SIGNING_KEY} does not exist. Generate using:"
"\tespsecure.py generate_signing_key ${CONFIG_SECURE_BOOT_SIGNING_KEY}")
"\tespsecure.py generate_signing_key --version ${secure_apps_signing_scheme} \
${CONFIG_SECURE_BOOT_SIGNING_KEY}")
else()
add_custom_target(gen_secure_boot_signing_key)
endif()
@ -70,7 +77,7 @@ if(CONFIG_SECURE_SIGNED_APPS)
set(ver_key_arg)
add_dependencies(gen_secure_boot_keys gen_secure_boot_signing_key)
else()
elseif(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
get_filename_component(secure_boot_verification_key
${CONFIG_SECURE_BOOT_VERIFICATION_KEY}
@ -83,7 +90,7 @@ if(CONFIG_SECURE_SIGNED_APPS)
fail_at_build_time(gen_secure_boot_verification_key
"Secure Boot Verification Public Key ${CONFIG_SECURE_BOOT_VERIFICATION_KEY} does not exist."
"\tThis can be extracted from the private signing key."
"\tSee docs/security/secure-boot.rst for details.")
"\tSee docs/security/secure-boot-v1.rst for details.")
else()
add_custom_target(gen_secure_boot_verification_key)
endif()

View file

@ -20,3 +20,6 @@ CONFIG_FLASH_ENCRYPTION_INSECURE CONFIG_SECURE_FLASH_
CONFIG_FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_ENCRYPT CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
CONFIG_FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_DECRYPT CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC
CONFIG_FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_CACHE CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
# Secure Boot Scheme
CONFIG_SECURE_BOOT_ENABLED CONFIG_SECURE_BOOT_V1_ENABLED

View file

@ -90,6 +90,39 @@ if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
add_custom_target (gen_bootloader_digest_bin ALL DEPENDS "${bootloader_digest_bin}")
endif()
if(CONFIG_SECURE_BOOT_V2_ENABLED)
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
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}")
endif()
set(bootloader_unsigned_bin "bootloader-unsigned.bin")
add_custom_command(OUTPUT ".signed_bin_timestamp"
COMMAND cp "${CMAKE_BINARY_DIR}/${PROJECT_BIN}" "${CMAKE_BINARY_DIR}/${bootloader_unsigned_bin}"
COMMAND ${ESPSECUREPY} sign_data --version 2 --keyfile "${secure_boot_signing_key}"
-o "${CMAKE_BINARY_DIR}/${PROJECT_BIN}" "${CMAKE_BINARY_DIR}/${bootloader_unsigned_bin}"
COMMAND ${CMAKE_COMMAND} -E echo "Generated signed binary image ${build_dir}/${PROJECT_BIN}"
"from ${CMAKE_BINARY_DIR}/${bootloader_unsigned_bin}"
COMMAND ${CMAKE_COMMAND} -E md5sum "${CMAKE_BINARY_DIR}/${PROJECT_BIN}" > "${CMAKE_BINARY_DIR}/.signed_bin_timestamp"
DEPENDS "${build_dir}/.bin_timestamp"
VERBATIM
COMMENT "Generated the signed Bootloader")
else()
add_custom_command(OUTPUT ".signed_bin_timestamp"
VERBATIM
COMMENT "Bootloader generated but not signed")
endif()
add_custom_target (gen_signed_bootloader ALL DEPENDS "${build_dir}/.signed_bin_timestamp")
endif()
if(CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH)
add_custom_command(TARGET bootloader.elf POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo
@ -133,4 +166,18 @@ 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)
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
"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)
endif()

View file

@ -1,3 +1,3 @@
# only compile the "micro-ecc/uECC.c" source file
idf_component_register(SRCS "micro-ecc/uECC.c"
INCLUDE_DIRS micro-ecc)
# only compile the "uECC_verify_antifault.c" file which includes the "micro-ecc/uECC.c" source file
idf_component_register(SRCS "uECC_verify_antifault.c"
INCLUDE_DIRS . micro-ecc)

View file

@ -1,8 +1,6 @@
# only compile the micro-ecc/uECC.c source file
# (SRCDIRS is needed so build system can find the source file)
COMPONENT_SRCDIRS := micro-ecc
COMPONENT_OBJS := micro-ecc/uECC.o
# only compile the "uECC_verify_antifault.c" file which includes the "micro-ecc/uECC.c" source file
COMPONENT_SRCDIRS := .
COMPONENT_ADD_INCLUDEDIRS := micro-ecc
COMPONENT_ADD_INCLUDEDIRS := . micro-ecc
COMPONENT_SUBMODULES := micro-ecc

View file

@ -0,0 +1,141 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license.
Modifications Copyright 2020, Espressif Systems (Shanghai) PTE LTD. Licensed under the BSD
2-clause license.
*/
/* uECC_verify() calls a number of static functions form here and
uses other definitions, so we just build that whole source file here and then append
our modified version uECC_verify_antifault(). */
#include "micro-ecc/uECC.c"
/* Version of uECC_verify() which also copies message_hash into verified_hash,
but only if the signature is valid. Does this in an FI resistant way.
*/
int uECC_verify_antifault(const uint8_t *public_key,
const uint8_t *message_hash,
unsigned hash_size,
const uint8_t *signature,
uECC_Curve curve,
uint8_t *verified_hash) {
uECC_word_t u1[uECC_MAX_WORDS], u2[uECC_MAX_WORDS];
uECC_word_t z[uECC_MAX_WORDS];
uECC_word_t sum[uECC_MAX_WORDS * 2];
uECC_word_t rx[uECC_MAX_WORDS];
uECC_word_t ry[uECC_MAX_WORDS];
uECC_word_t tx[uECC_MAX_WORDS];
uECC_word_t ty[uECC_MAX_WORDS];
uECC_word_t tz[uECC_MAX_WORDS];
const uECC_word_t *points[4];
const uECC_word_t *point;
bitcount_t num_bits;
bitcount_t i;
#if uECC_VLI_NATIVE_LITTLE_ENDIAN
uECC_word_t *_public = (uECC_word_t *)public_key;
#else
uECC_word_t _public[uECC_MAX_WORDS * 2];
#endif
uECC_word_t r[uECC_MAX_WORDS], s[uECC_MAX_WORDS];
wordcount_t num_words = curve->num_words;
wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
rx[num_n_words - 1] = 0;
r[num_n_words - 1] = 0;
s[num_n_words - 1] = 0;
#if uECC_VLI_NATIVE_LITTLE_ENDIAN
bcopy((uint8_t *) r, signature, curve->num_bytes);
bcopy((uint8_t *) s, signature + curve->num_bytes, curve->num_bytes);
#else
uECC_vli_bytesToNative(_public, public_key, curve->num_bytes);
uECC_vli_bytesToNative(
_public + num_words, public_key + curve->num_bytes, curve->num_bytes);
uECC_vli_bytesToNative(r, signature, curve->num_bytes);
uECC_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes);
#endif
/* r, s must not be 0. */
if (uECC_vli_isZero(r, num_words) || uECC_vli_isZero(s, num_words)) {
return 0;
}
/* r, s must be < n. */
if (uECC_vli_cmp(curve->n, r, num_n_words) != 1 ||
uECC_vli_cmp(curve->n, s, num_n_words) != 1) {
return 0;
}
/* Calculate u1 and u2. */
uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */
u1[num_n_words - 1] = 0;
bits2int(u1, message_hash, hash_size, curve);
uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */
uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */
/* Calculate sum = G + Q. */
uECC_vli_set(sum, _public, num_words);
uECC_vli_set(sum + num_words, _public + num_words, num_words);
uECC_vli_set(tx, curve->G, num_words);
uECC_vli_set(ty, curve->G + num_words, num_words);
uECC_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */
XYcZ_add(tx, ty, sum, sum + num_words, curve);
uECC_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */
apply_z(sum, sum + num_words, z, curve);
/* Use Shamir's trick to calculate u1*G + u2*Q */
points[0] = 0;
points[1] = curve->G;
points[2] = _public;
points[3] = sum;
num_bits = smax(uECC_vli_numBits(u1, num_n_words),
uECC_vli_numBits(u2, num_n_words));
point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) |
((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)];
uECC_vli_set(rx, point, num_words);
uECC_vli_set(ry, point + num_words, num_words);
uECC_vli_clear(z, num_words);
z[0] = 1;
for (i = num_bits - 2; i >= 0; --i) {
uECC_word_t index;
curve->double_jacobian(rx, ry, z, curve);
index = (!!uECC_vli_testBit(u1, i)) | ((!!uECC_vli_testBit(u2, i)) << 1);
point = points[index];
if (point) {
uECC_vli_set(tx, point, num_words);
uECC_vli_set(ty, point + num_words, num_words);
apply_z(tx, ty, z, curve);
uECC_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */
XYcZ_add(tx, ty, rx, ry, curve);
uECC_vli_modMult_fast(z, z, tz, curve);
}
}
uECC_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */
apply_z(rx, ry, z, curve);
/* v = x1 (mod n) */
if (uECC_vli_cmp(curve->n, rx, num_n_words) != 1) {
uECC_vli_sub(rx, rx, curve->n, num_n_words);
}
/* Anti-FI addition. Copy message_hash into verified_hash, but do it in a
way that it will only happen if v == r (ie, rx == r)
*/
const uECC_word_t *mhash_words = (const uECC_word_t *)message_hash;
uECC_word_t *vhash_words = (uECC_word_t *)verified_hash;
unsigned hash_words = hash_size / sizeof(uECC_word_t);
for (int w = 0; w < hash_words; w++) {
/* note: using curve->num_words here to encourage compiler to re-read this variable */
vhash_words[w] = mhash_words[w] ^ rx[w % curve->num_words] ^ r[w % curve->num_words];
}
/* Curve may be longer than hash, in which case keep reading the rest of the bytes */
for (int w = hash_words; w < curve->num_words; w++) {
vhash_words[w % hash_words] |= rx[w] | r[w];
}
/* Accept only if v == r. */
return (int)(uECC_vli_equal(rx, r, num_words));
}

View file

@ -0,0 +1,18 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license.
Modifications Copyright 2020, Espressif Systems (Shanghai) PTE LTD. Licensed under the BSD
2-clause license.
*/
#pragma once
#include "uECC.h"
/* Version uECC_verify() that also copies message_hash to verified_hash
if the signature is valid, and does it in a way that is harder to attack
with fault injection.
*/
int uECC_verify_antifault(const uint8_t *public_key,
const uint8_t *message_hash,
unsigned hash_size,
const uint8_t *signature,
uECC_Curve curve,
uint8_t *verified_hash);

View file

@ -17,6 +17,9 @@ ifdef CONFIG_IDF_TARGET_ESP32
ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH
LINKER_SCRIPTS += $(IDF_PATH)/components/esp_rom/$(IDF_TARGET)/ld/$(IDF_TARGET).rom.spiflash.ld
endif
ifdef CONFIG_ESP32_REV_MIN_3
LINKER_SCRIPTS += $(IDF_PATH)/components/esp_rom/$(IDF_TARGET)/ld/$(IDF_TARGET).rom.eco3.ld
endif
endif
COMPONENT_ADD_LDFLAGS += -L $(COMPONENT_PATH) $(addprefix -T ,$(LINKER_SCRIPTS))

View file

@ -74,6 +74,7 @@ SECTIONS
.dram0.bss (NOLOAD) :
{
. = ALIGN (8);
_dram_start = ABSOLUTE(.);
_bss_start = ABSOLUTE(.);
*(.dynsbss)
*(.sbss)
@ -150,6 +151,7 @@ SECTIONS
*(.gnu.linkonce.lit4.*)
_lit4_end = ABSOLUTE(.);
. = ALIGN(4);
_dram_end = ABSOLUTE(.);
} >dram_seg
.iram.text :

View file

@ -59,6 +59,7 @@ SECTIONS
.dram0.bss (NOLOAD) :
{
. = ALIGN (8);
_dram_start = ABSOLUTE(.);
_bss_start = ABSOLUTE(.);
*(.dynsbss)
*(.sbss)
@ -135,7 +136,7 @@ SECTIONS
*(.gnu.linkonce.lit4.*)
_lit4_end = ABSOLUTE(.);
. = ALIGN(4);
_heap_start = ABSOLUTE(.);
_dram_end = ABSOLUTE(.);
} >dram_seg
.iram.text :

View file

@ -20,22 +20,34 @@ if(BOOTLOADER_BUILD)
set(include_dirs "include" "include_bootloader")
set(priv_requires micro-ecc spi_flash efuse)
list(APPEND srcs
"src/bootloader_init.c"
"src/${IDF_TARGET}/bootloader_sha.c"
"src/${IDF_TARGET}/flash_encrypt.c"
"src/${IDF_TARGET}/secure_boot_signatures.c"
"src/${IDF_TARGET}/secure_boot.c"
"src/${IDF_TARGET}/bootloader_${IDF_TARGET}.c"
)
"src/bootloader_init.c"
"src/${IDF_TARGET}/bootloader_sha.c"
"src/${IDF_TARGET}/flash_encrypt.c"
"src/${IDF_TARGET}/bootloader_${IDF_TARGET}.c"
)
else()
list(APPEND srcs
"src/idf/bootloader_sha.c"
"src/idf/secure_boot_signatures.c")
"src/idf/bootloader_sha.c")
set(include_dirs "include")
set(priv_include_dirs "include_bootloader")
set(priv_requires spi_flash mbedtls efuse)
endif()
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME OR CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
if(BOOTLOADER_BUILD)
list(APPEND srcs
"src/${IDF_TARGET}/secure_boot_signatures.c")
else()
list(APPEND srcs
"src/idf/secure_boot_signatures.c")
endif()
endif()
if(CONFIG_SECURE_BOOT AND BOOTLOADER_BUILD)
list(APPEND srcs
"src/${IDF_TARGET}/secure_boot.c")
endif()
set(requires soc) #unfortunately the header directly uses SOC registers
idf_component_register(SRCS "${srcs}"
@ -44,7 +56,7 @@ idf_component_register(SRCS "${srcs}"
REQUIRES "${requires}"
PRIV_REQUIRES "${priv_requires}")
if(CONFIG_SECURE_SIGNED_APPS)
if(CONFIG_SECURE_SIGNED_APPS AND (CONFIG_SECURE_BOOT_V1_ENABLED OR CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME))
if(BOOTLOADER_BUILD)
# Whether CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES or not, we need verification key to embed
# in the library.

View file

@ -22,11 +22,23 @@ endif
COMPONENT_OBJEXCLUDE += src/bootloader_flash_config_esp32s2.o \
src/bootloader_efuse_esp32s2.o
ifndef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
ifndef CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
COMPONENT_OBJEXCLUDE += src/$(IDF_TARGET)/secure_boot_signatures.o \
src/idf/secure_boot_signatures.o
endif
endif
ifndef CONFIG_SECURE_BOOT
COMPONENT_OBJEXCLUDE += src/$(IDF_TARGET)/secure_boot.o
endif
#
# Secure boot signing key support
#
ifdef CONFIG_SECURE_SIGNED_APPS
ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
# this path is created relative to the component build directory
SECURE_BOOT_VERIFICATION_KEY := $(abspath signature_verification_key.bin)
@ -41,7 +53,7 @@ ORIG_SECURE_BOOT_VERIFICATION_KEY := $(call resolvepath,$(call dequote,$(CONFIG_
$(ORIG_SECURE_BOOT_VERIFICATION_KEY):
@echo "Secure boot verification public key '$@' missing."
@echo "This can be extracted from the private signing key, see"
@echo "docs/security/secure-boot.rst for details."
@echo "docs/security/secure-boot-v1.rst for details."
exit 1
# copy it into the build dir, so the secure boot verification key has
@ -55,4 +67,5 @@ COMPONENT_EXTRA_CLEAN += $(SECURE_BOOT_VERIFICATION_KEY)
COMPONENT_EMBED_FILES := $(SECURE_BOOT_VERIFICATION_KEY)
endif #CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
endif #CONFIG_SECURE_SIGNED_APPS

View file

@ -16,13 +16,18 @@
#include <stdbool.h>
#include <esp_err.h>
#include "soc/efuse_periph.h"
#include "esp_image_format.h"
#include "sdkconfig.h"
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/efuse.h"
#else
#include "esp32/rom/secure_boot.h"
#endif
#ifdef CONFIG_SECURE_BOOT_ENABLED
typedef struct ets_secure_boot_signature ets_secure_boot_signature_t;
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
#if !defined(CONFIG_SECURE_SIGNED_ON_BOOT) || !defined(CONFIG_SECURE_SIGNED_ON_UPDATE) || !defined(CONFIG_SECURE_SIGNED_APPS)
#error "internal sdkconfig error, secure boot should always enable all signature options"
#endif
@ -47,16 +52,23 @@ extern "C" {
static inline bool esp_secure_boot_enabled(void)
{
#if CONFIG_IDF_TARGET_ESP32
return REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0;
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
return REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0;
#elif CONFIG_SECURE_BOOT_V2_ENABLED
return ets_use_secure_boot_v2();
#endif
#elif CONFIG_IDF_TARGET_ESP32S2
return ets_efuse_secure_boot_enabled();
#endif
return false; /* Secure Boot not enabled in menuconfig */
}
/** @brief Generate secure digest from bootloader image
*
* @important This function is intended to be called from bootloader code only.
*
* This function is only used in the context of the Secure Boot V1 scheme.
*
* If secure boot is not yet enabled for bootloader, this will:
* 1) generate the secure boot key and burn it on EFUSE
* (without enabling R/W protection)
@ -73,18 +85,17 @@ static inline bool esp_secure_boot_enabled(void)
*/
esp_err_t esp_secure_boot_generate_digest(void);
/** @brief Enable secure boot if it is not already enabled.
/** @brief Enable secure boot V1 if it is not already enabled.
*
* @important If this function succeeds, secure boot is permanently
* @important If this function succeeds, secure boot V1 is permanently
* enabled on the chip via efuse.
*
* @important This function is intended to be called from bootloader code only.
*
* @important This will enable r/w protection of secure boot key on EFUSE,
* therefore it is to be ensured that esp_secure_boot_generate_digest()
* is called before this
*
* If secure boot is not yet enabled for bootloader, this will
* @important In case of Secure Boot V1, this will enable r/w protection
* of secure boot key on EFUSE, therefore it is to be ensured that
* esp_secure_boot_generate_digest() is called before this .If secure boot is not
* yet enabled for bootloader, this will
* 1) enable R/W protection of secure boot key on EFUSE
* 2) enable secure boot by blowing the EFUSE_RD_ABS_DONE_0 efuse.
*
@ -100,35 +111,97 @@ esp_err_t esp_secure_boot_generate_digest(void);
*/
esp_err_t esp_secure_boot_permanently_enable(void);
/** @brief Verify the secure boot signature (determinstic ECDSA w/ SHA256) appended to some binary data in flash.
/** @brief Enables secure boot V2 if it is not already enabled.
*
* Public key is compiled into the calling program. See docs/security/secure-boot.rst for details.
* @important If this function succeeds, secure boot V2 is permanently
* enabled on the chip via efuse.
*
* @important This function is intended to be called from bootloader code only.
*
* @important In case of Secure Boot V2, this will enable write protection
* of secure boot key on EFUSE in BLK2. .If secure boot is not
* yet enabled for bootloader, this will
* 1) enable W protection of secure boot key on EFUSE
* 2) enable secure boot by blowing the EFUSE_RD_ABS_DONE_1 efuse.
*
* This function does not verify secure boot of the bootloader (the
* ROM bootloader does this.)
*
* @param image_data Image metadata of the application to be loaded.
*
* Will fail if efuses have been part-burned in a way that indicates
* secure boot should not or could not be correctly enabled.
*
* @return ESP_ERR_INVALID_STATE if efuse state doesn't allow
* secure boot to be enabled cleanly. ESP_OK if secure boot
* is enabled on this chip from now on.
*/
esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *image_data);
/** @brief Verify the secure boot signature appended to some binary data in flash.
*
* For ECDSA Scheme (Secure Boot V1) - deterministic ECDSA w/ SHA256 image
* For RSA Scheme (Secure Boot V2) - RSA-PSS Verification of the SHA-256 image
*
* Public key is compiled into the calling program in the ECDSA Scheme.
* See the apt docs/security/secure-boot-v1.rst or docs/security/secure-boot-v2.rst for details.
*
* @param src_addr Starting offset of the data in flash.
* @param length Length of data in bytes. Signature is appended -after- length bytes.
*
* If flash encryption is enabled, the image will be transparently decrypted while being verified.
*
* @note This function doesn't have any fault injection resistance so should not be called
* during a secure boot itself (but can be called when verifying an update, etc.)
*
* @return ESP_OK if signature is valid, ESP_ERR_INVALID_STATE if
* signature fails, ESP_FAIL for other failures (ie can't read flash).
*/
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);
/** @brief Verify the ECDSA secure boot signature block for Secure Boot V1.
*
* Calculates Deterministic ECDSA w/ SHA256 based on the SHA256 hash of the image. ECDSA signature
* verification must be enabled in project configuration to use this function.
*
* Similar to esp_secure_boot_verify_signature(), but can be used when the digest is precalculated.
* @param sig_block Pointer to ECDSA signature block data
* @param image_digest Pointer to 32 byte buffer holding SHA-256 hash.
* @param verified_digest Pointer to 32 byte buffer that will receive verified digest if verification completes. (Used during bootloader implementation only, result is invalid otherwise.)
*
*/
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest);
/** @brief Verify the RSA secure boot signature block for Secure Boot V2.
*
* Performs RSA-PSS Verification of the SHA-256 image based on the public key
* in the signature block, compared against the public key digest stored in efuse.
*
* Similar to esp_secure_boot_verify_signature(), but can be used when the digest is precalculated.
* @param sig_block Pointer to RSA signature block data
* @param image_digest Pointer to 32 byte buffer holding SHA-256 hash.
* @param verified_digest Pointer to 32 byte buffer that will receive verified digest if verification completes. (Used during bootloader implementation only, result is invalid otherwise.)
*
*/
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);
/** @brief Legacy ECDSA verification function
*
* @note Deprecated, call either esp_secure_boot_verify_ecdsa_signature_block() or esp_secure_boot_verify_rsa_signature_block() instead.
*
* @param sig_block Pointer to ECDSA signature block data
* @param image_digest Pointer to 32 byte buffer holding SHA-256 hash.
*/
esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest)
__attribute__((deprecated("use esp_secure_boot_verify_ecdsa_signature_block instead")));
#define FLASH_OFFS_SECURE_BOOT_IV_DIGEST 0

View file

@ -18,9 +18,11 @@
#include <stdbool.h>
#include <stdint.h>
#include <esp_err.h>
#include <esp_spi_flash.h> /* including in bootloader for error values */
#define FLASH_SECTOR_SIZE 0x1000
#define FLASH_BLOCK_SIZE 0x10000
#define MMAP_ALIGNED_MASK 0x0000FFFF
/* Provide a Flash API for bootloader_support code,
that can be used from bootloader or app code.

View file

@ -108,3 +108,17 @@ esp_err_t bootloader_sha256_hex_to_str(char *out_str, const uint8_t *in_array_he
* @param label Label to print at beginning of log line.
*/
void bootloader_debug_buffer(const void *buffer, size_t length, const char *label);
/** @brief Generates the digest of the data between offset & offset+length.
*
* This function should be used when the size of the data is larger than 3.2MB.
* The MMU capacity is 3.2MB (50 pages - 64KB each). This function generates the SHA-256
* of the data in chunks of 3.2MB, considering the MMU capacity.
*
* @param[in] flash_offset Offset of the data in flash.
* @param[in] len Length of data in bytes.
* @param[out] digest Pointer to buffer where the digest is written, if ESP_OK is returned.
*
* @return ESP_OK if secure boot digest is generated successfully.
*/
esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len, uint8_t *digest);

View file

@ -15,7 +15,6 @@
#include <bootloader_flash.h>
#include <esp_log.h>
#include <esp_spi_flash.h> /* including in bootloader for error values */
#include <esp_flash_encrypt.h>
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/spi_flash.h"

View file

@ -557,11 +557,19 @@ static void load_image(const esp_image_metadata_t *image_data)
* then Step 6 enables secure boot.
*/
#if defined(CONFIG_SECURE_BOOT_ENABLED) || defined(CONFIG_SECURE_FLASH_ENC_ENABLED)
#if defined(CONFIG_SECURE_BOOT) || defined(CONFIG_SECURE_FLASH_ENC_ENABLED)
esp_err_t err;
#endif
#ifdef CONFIG_SECURE_BOOT_ENABLED
#ifdef CONFIG_SECURE_BOOT_V2_ENABLED
err = esp_secure_boot_v2_permanently_enable(image_data);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Secure Boot v2 failed (%d)", err);
return;
}
#endif
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
/* Steps 1 & 2 (see above for full description):
* 1) Generate secure boot EFUSE key
* 2) Compute digest of plaintext bootloader
@ -588,7 +596,7 @@ static void load_image(const esp_image_metadata_t *image_data)
}
#endif
#ifdef CONFIG_SECURE_BOOT_ENABLED
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
/* Step 6 (see above for full description):
* 6) Burn EFUSE to enable secure boot
*/
@ -810,3 +818,37 @@ void bootloader_debug_buffer(const void *buffer, size_t length, const char *labe
ESP_LOGD(TAG, "%s: %s", label, hexbuf);
#endif
}
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;
}
/* Handling firmware images larger than MMU capacity */
uint32_t mmu_free_pages_count = bootloader_mmap_get_free_pages();
bootloader_sha256_handle_t sha_handle = NULL;
sha_handle = bootloader_sha256_start();
if (sha_handle == NULL) {
return ESP_ERR_NO_MEM;
}
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);
return ESP_FAIL;
}
bootloader_sha256_data(sha_handle, image, partial_image_len);
bootloader_munmap(image);
flash_offset += partial_image_len;
len -= partial_image_len;
}
bootloader_sha256_finish(sha_handle, digest);
return ESP_OK;
}

View file

@ -236,13 +236,24 @@ static esp_err_t encrypt_bootloader(void)
/* Check for plaintext bootloader (verification will fail if it's already encrypted) */
if (esp_image_verify_bootloader(&image_length) == ESP_OK) {
ESP_LOGD(TAG, "bootloader is plaintext. Encrypting...");
#if CONFIG_SECURE_BOOT_V2_ENABLED
// Account for the signature sector after the bootloader
image_length = (image_length + FLASH_SECTOR_SIZE - 1) & ~(FLASH_SECTOR_SIZE - 1);
image_length += FLASH_SECTOR_SIZE;
if (ESP_BOOTLOADER_OFFSET + image_length > ESP_PARTITION_TABLE_OFFSET) {
ESP_LOGE(TAG, "Bootloader is too large to fit Secure Boot V2 signature sector and partition table (configured offset 0x%x)", ESP_PARTITION_TABLE_OFFSET);
return ESP_ERR_INVALID_STATE;
}
#endif // CONFIG_SECURE_BOOT_V2_ENABLED
err = esp_flash_encrypt_region(ESP_BOOTLOADER_OFFSET, image_length);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err);
return err;
}
#ifdef CONFIG_SECURE_BOOT_ENABLED
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
/* If secure boot is enabled and bootloader was plaintext, also
* need to encrypt secure boot IV+digest.
*/
@ -355,4 +366,4 @@ esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length)
flash_failed:
ESP_LOGE(TAG, "flash operation failed: 0x%x", err);
return err;
}
}

View file

@ -20,10 +20,12 @@
#include "esp32/rom/cache.h"
#include "esp32/rom/ets_sys.h"
#include "esp32/rom/secure_boot.h"
#include "esp32/rom/crc.h"
#include "soc/efuse_periph.h"
#include "soc/rtc_periph.h"
#include "bootloader_sha.h"
#include "bootloader_utility.h"
#include "sdkconfig.h"
@ -37,9 +39,14 @@
/* The following API implementations are used only when called
* from the bootloader code.
*/
/* Burn values written to the efuse write registers */
static inline void burn_efuses(void)
{
esp_efuse_burn_new_values();
}
static const char* TAG = "secure_boot";
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
static const char *TAG = "secure_boot_v1";
/**
* @function : secure_boot_generate
* @description: generate boot digest (aka "abstract") & iv
@ -94,12 +101,6 @@ static bool secure_boot_generate(uint32_t image_len){
return true;
}
/* Burn values written to the efuse write registers */
static inline void burn_efuses(void)
{
esp_efuse_burn_new_values();
}
esp_err_t esp_secure_boot_generate_digest(void)
{
esp_err_t err;
@ -219,3 +220,188 @@ esp_err_t esp_secure_boot_permanently_enable(void)
return ESP_ERR_INVALID_STATE;
}
}
#elif CONFIG_SECURE_BOOT_V2_ENABLED
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
static const char *TAG = "secure_boot_v2";
#define SIG_BLOCK_MAGIC_BYTE 0xe7
#define CRC_SIGN_BLOCK_LEN 1196
#define SIG_BLOCK_PADDING 4096
#define DIGEST_LEN 32
static esp_err_t validate_signature_block(const ets_secure_boot_signature_t *sig_block, uint8_t *digest)
{
uint32_t crc = crc32_le(0, (uint8_t *)sig_block, CRC_SIGN_BLOCK_LEN);
if (sig_block->block[0].magic_byte == SIG_BLOCK_MAGIC_BYTE && sig_block->block[0].block_crc == crc && !memcmp(digest, sig_block->block[0].image_digest, DIGEST_LEN)) {
ESP_LOGI(TAG, "valid signature block found");
return ESP_OK;
}
return ESP_FAIL;
}
static esp_err_t secure_boot_v2_digest_generate(uint32_t flash_offset, uint32_t flash_size, uint8_t *public_key_digest)
{
esp_err_t ret = ESP_FAIL;
uint8_t image_digest[DIGEST_LEN] = {0};
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 ret;
}
/* Validating Signature block */
ret = validate_signature_block(sig_block, image_digest);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "signature block (address 0x%x) validation failed %d", sig_block_addr, ret);
goto done;
}
/* Verifying Signature block */
uint8_t verified_digest[DIGEST_LEN] = {0};
/* 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, public_key_digest);
secure_boot_v2_status_t error;
error = ets_secure_boot_verify_signature(sig_block, image_digest, public_key_digest, verified_digest);
if (error != SBV2_SUCCESS) {
ESP_LOGE(TAG, "secure boot v2 verification failed %d", error);
ret = ESP_FAIL;
goto done;
} else {
ret = ESP_OK;
}
done:
bootloader_munmap(sig_block);
return ret;
}
esp_err_t esp_secure_boot_v2_permanently_enable(const esp_image_metadata_t *image_data)
{
ESP_LOGI(TAG, "enabling secure boot v2...");
esp_err_t ret;
if (esp_secure_boot_enabled()) {
ESP_LOGI(TAG, "secure boot v2 is already enabled. Continuing..");
return ESP_OK;
}
uint32_t coding_scheme = REG_GET_FIELD(EFUSE_BLK0_RDATA6_REG, EFUSE_CODING_SCHEME);
if (coding_scheme != EFUSE_CODING_SCHEME_VAL_NONE) {
ESP_LOGE(TAG, "No coding schemes are supported in secure boot v2.(Detected scheme: 0x%x)", coding_scheme);
return ESP_ERR_NOT_SUPPORTED;
}
/* 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;
}
uint8_t boot_pub_key_digest[DIGEST_LEN];
uint32_t dis_reg = REG_READ(EFUSE_BLK0_RDATA0_REG);
bool efuse_key_read_protected = dis_reg & EFUSE_RD_DIS_BLK2;
bool efuse_key_write_protected = dis_reg & EFUSE_WR_DIS_BLK2;
if (efuse_key_write_protected == false
&& efuse_key_read_protected == false
&& REG_READ(EFUSE_BLK2_RDATA0_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA1_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA2_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA3_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA4_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA5_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA6_REG) == 0
&& REG_READ(EFUSE_BLK2_RDATA7_REG) == 0) {
/* Verifies the signature block appended to the image matches with the signature block of the app to be loaded */
ret = secure_boot_v2_digest_generate(bootloader_data.start_addr, bootloader_data.image_len - SIG_BLOCK_PADDING, boot_pub_key_digest);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Public key digest generation failed");
return ret;
}
ESP_LOGI(TAG, "Burning public key hash to efuse.");
uint32_t *boot_public_key_digest_ptr = (uint32_t *) boot_pub_key_digest;
for (int i = 0; i < 8 ; i++) {
REG_WRITE(EFUSE_BLK2_WDATA0_REG + 4 * i, boot_public_key_digest_ptr[i]);
ESP_LOGD(TAG, "EFUSE_BLKx_WDATA%d_REG = 0x%08x", i, boot_public_key_digest_ptr[i]);
}
ESP_LOGI(TAG, "Write protecting public key digest...");
REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_BLK2);
efuse_key_write_protected = true;
efuse_key_read_protected = false;
} else {
ESP_LOGW(TAG, "Using pre-loaded secure boot v2 public key digest in EFUSE block 2");
}
uint8_t app_pub_key_digest[DIGEST_LEN];
ret = secure_boot_v2_digest_generate(image_data->start_addr, image_data->image_len - SIG_BLOCK_PADDING, app_pub_key_digest);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Application signature block is invalid.");
return ret;
}
/* Confirming if the public key in the bootloader's signature block matches with the one in the application's signature block */
if (memcmp(boot_pub_key_digest, app_pub_key_digest, DIGEST_LEN) != 0) {
ESP_LOGE(TAG, "Application not signed with a valid private key.");
return ESP_FAIL;
}
if (efuse_key_read_protected) {
ESP_LOGE(TAG, "Efuse BLK2 (public key digest) is read protected. Refusing to blow secure boot efuse.");
return ESP_ERR_INVALID_STATE;
}
if (!efuse_key_write_protected) {
ESP_LOGE(TAG, "Efuse BLK2 (public key digest) is not write protected. Refusing to blow secure boot efuse.");
return ESP_ERR_INVALID_STATE;
}
ESP_LOGI(TAG, "blowing secure boot efuse...");
ESP_LOGD(TAG, "before updating, EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG));
uint32_t new_wdata6 = EFUSE_RD_ABS_DONE_1;
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable JTAG...");
new_wdata6 |= EFUSE_RD_DISABLE_JTAG;
#else
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
#endif
#ifndef CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC
ESP_LOGI(TAG, "Disable ROM BASIC interpreter fallback...");
new_wdata6 |= EFUSE_RD_CONSOLE_DEBUG_DISABLE;
#else
ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
#endif
REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6);
burn_efuses();
uint32_t after = REG_READ(EFUSE_BLK0_RDATA6_REG);
ESP_LOGD(TAG, "after updating, EFUSE_BLK0_RDATA6 %x", after);
if (after & EFUSE_RD_ABS_DONE_1) {
ESP_LOGI(TAG, "secure boot v2 is now enabled.");
return ESP_OK;
} else {
ESP_LOGE(TAG, " secure boot v2 not enabled, EFUSE_RD_ABS_DONE_1 is probably write protected!");
return ESP_ERR_INVALID_STATE;
}
}
#endif // CONFIG_SECURE_BOOT_V2_ENABLED

View file

@ -15,62 +15,40 @@
#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 "esp_spi_flash.h"
#include "esp_fault.h"
#include "esp32/rom/sha.h"
#include "uECC.h"
#include "uECC_verify_antifault.h"
#include <sys/param.h>
#include <string.h>
static const char *TAG = "secure_boot";
#define DIGEST_LEN 32
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
#define SIGNATURE_VERIFICATION_KEYLEN 64
#define DIGEST_LEN 32
/* Mmap source address mask */
#define MMAP_ALIGNED_MASK 0x0000FFFF
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
{
uint8_t digest[DIGEST_LEN];
const uint8_t *data;
uint8_t verified_digest[DIGEST_LEN] = { 0 }; /* ignored in this function */
const esp_secure_boot_sig_block_t *sigblock;
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
bootloader_sha256_handle_t handle = bootloader_sha256_start();
uint32_t free_page_count = bootloader_mmap_get_free_pages();
ESP_LOGD(TAG, "free data page_count 0x%08x", free_page_count);
int32_t data_len_remain = length;
uint32_t data_addr = src_addr;
while (data_len_remain > 0) {
uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0) ? 1 : 0;
/* Data we could map in case we are not aligned to PAGE boundary is one page size lesser. */
uint32_t data_len = MIN(data_len_remain, ((free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE));
data = (const uint8_t *) bootloader_mmap(data_addr, data_len);
if(!data) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", data_addr, data_len);
bootloader_sha256_finish(handle, NULL);
return ESP_FAIL;
}
bootloader_sha256_data(handle, data, data_len);
bootloader_munmap(data);
data_addr += data_len;
data_len_remain -= data_len;
esp_err_t err = bootloader_sha256_flash_contents(src_addr, length, digest);
if (err != ESP_OK) {
return err;
}
/* Done! Get the digest */
bootloader_sha256_finish(handle, digest);
// Map the signature block
sigblock = (const esp_secure_boot_sig_block_t *) bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t));
if(!sigblock) {
@ -78,7 +56,7 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
return ESP_FAIL;
}
// Verify the signature
esp_err_t err = esp_secure_boot_verify_signature_block(sigblock, digest);
err = esp_secure_boot_verify_ecdsa_signature_block(sigblock, digest, verified_digest);
// Unmap
bootloader_munmap(sigblock);
@ -86,6 +64,12 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
}
esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest)
{
uint8_t verified_digest[DIGEST_LEN] = { 0 };
return esp_secure_boot_verify_ecdsa_signature_block(sig_block, image_digest, verified_digest);
}
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
{
ptrdiff_t keylen;
@ -103,11 +87,83 @@ esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block
ESP_LOGD(TAG, "Verifying secure boot signature");
bool is_valid;
is_valid = uECC_verify(signature_verification_key_start,
is_valid = uECC_verify_antifault(signature_verification_key_start,
image_digest,
DIGEST_LEN,
sig_block->signature,
uECC_secp256r1());
uECC_secp256r1(),
verified_digest);
ESP_LOGD(TAG, "Verification result %d", is_valid);
return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID;
}
#elif CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
#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)
{
uint8_t digest[DIGEST_LEN] = {0};
uint8_t verified_digest[DIGEST_LEN] = {0}; // ignored in this function
const uint8_t *data;
/* 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, padded_length + sizeof(ets_secure_boot_signature_t));
if (data == NULL) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, padded_length);
return ESP_FAIL;
}
/* 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_block = (const ets_secure_boot_signature_t *)(data + padded_length);
err = esp_secure_boot_verify_rsa_signature_block(sig_block, digest, verified_digest);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
}
bootloader_munmap(data);
return err;
}
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)
{
uint8_t efuse_trusted_digest[DIGEST_LEN] = {0}, sig_block_trusted_digest[DIGEST_LEN] = {0};
secure_boot_v2_status_t r;
memcpy(efuse_trusted_digest, (uint8_t *)EFUSE_BLK2_RDATA0_REG, DIGEST_LEN); /* EFUSE_BLK2_RDATA0_REG - Stores the Secure Boot Public Key Digest */
if (!ets_use_secure_boot_v2()) {
ESP_LOGI(TAG, "Secure Boot EFuse bit(ABS_DONE_1) not yet programmed.");
/* 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 (memcmp(efuse_trusted_digest, sig_block_trusted_digest, DIGEST_LEN) != 0) {
ESP_LOGW(TAG, "Public key digest in eFuse BLK2 and the signature block don't match.");
}
memcpy(efuse_trusted_digest, sig_block_trusted_digest, DIGEST_LEN);
}
ESP_LOGI(TAG, "Verifying with RSA-PSS...");
r = ets_secure_boot_verify_signature(sig_block, image_digest, efuse_trusted_digest, verified_digest);
if (r != SBV2_SUCCESS) {
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
}
return (r == SBV2_SUCCESS) ? ESP_OK : ESP_ERR_IMAGE_INVALID;
}
#endif

View file

@ -15,7 +15,7 @@
#include "esp_log.h"
#include "esp32s2/rom/secure_boot.h"
#define TAG "secure_boot"
static const char *TAG = "secure_boot";
esp_err_t esp_secure_boot_permanently_enable(void)
{

View file

@ -27,6 +27,7 @@ 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);
@ -37,7 +38,7 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
}
data = bootloader_mmap(src_addr, length + sizeof(struct ets_secure_boot_sig_block));
if(data == NULL) {
if (data == NULL) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length+sizeof(ets_secure_boot_signature_t));
return ESP_FAIL;
}
@ -57,36 +58,25 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
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);
r = ets_secure_boot_verify_signature(sig, digest, &trusted_keys, verified_digest);
}
bootloader_munmap(data);
return (r == ETS_OK) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_secure_boot_verify_signature_block(uint32_t sig_block_flash_offs, const uint8_t *image_digest)
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;
assert(sig_block_flash_offs % 4096 == 0); // TODO: enforce this in a better way
const ets_secure_boot_signature_t *sig = bootloader_mmap(sig_block_flash_offs, sizeof(ets_secure_boot_signature_t));
if (sig == NULL) {
ESP_LOGE(TAG, "Failed to mmap data at offset 0x%x", sig_block_flash_offs);
return ESP_FAIL;
}
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, image_digest, &trusted_keys);
r = ets_secure_boot_verify_signature(sig_block, image_digest, &trusted_keys, verified_digest);
}
bootloader_munmap(sig);
return (r == 0) ? ESP_OK : ESP_ERR_IMAGE_INVALID;
}

View file

@ -16,6 +16,7 @@
#include <soc/cpu.h>
#include <bootloader_utility.h>
#include <esp_secure_boot.h>
#include <esp_fault.h>
#include <esp_log.h>
#include <esp_spi_flash.h>
#include <bootloader_flash.h>
@ -23,6 +24,7 @@
#include <bootloader_sha.h>
#include "bootloader_util.h"
#include "bootloader_common.h"
#include "soc/soc_memory_layout.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/rtc.h"
#include "esp32/rom/secure_boot.h"
@ -37,11 +39,11 @@
*/
#ifdef BOOTLOADER_BUILD
#ifdef CONFIG_SECURE_SIGNED_ON_BOOT
#define SECURE_BOOT_CHECK_SIGNATURE
#define SECURE_BOOT_CHECK_SIGNATURE 1
#endif
#else /* !BOOTLOADER_BUILD */
#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE
#define SECURE_BOOT_CHECK_SIGNATURE
#define SECURE_BOOT_CHECK_SIGNATURE 1
#endif
#endif
@ -55,18 +57,12 @@ static const char *TAG = "esp_image";
/* Headroom to ensure between stack SP (at time of checking) and data loaded from flash */
#define STACK_LOAD_HEADROOM 32768
/* Mmap source address mask */
#define MMAP_ALIGNED_MASK 0x0000FFFF
#ifdef BOOTLOADER_BUILD
/* 64 bits of random data to obfuscate loaded RAM with, until verification is complete
(Means loaded code isn't executable until after the secure boot check.)
*/
static uint32_t ram_obfs_value[2];
/* Range of IRAM used by the loader, defined in ld script */
extern int _loader_text_start;
extern int _loader_text_end;
#endif
/* Return true if load_addr is an address the bootloader should load into */
@ -97,7 +93,7 @@ static esp_err_t verify_segment_header(int index, const esp_image_segment_header
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_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data);
static esp_err_t __attribute__((unused)) verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data, uint8_t *image_digest, uint8_t *verified_digest);
static esp_err_t __attribute__((unused)) verify_simple_hash(bootloader_sha256_handle_t sha_handle, 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)
@ -115,6 +111,11 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
uint32_t checksum_word = ESP_ROM_CHECKSUM_INITIAL;
uint32_t *checksum = NULL;
bootloader_sha256_handle_t sha_handle = NULL;
#if SECURE_BOOT_CHECK_SIGNATURE
/* used for anti-FI checks */
uint8_t image_digest[HASH_LEN] = { [ 0 ... 31] = 0xEE };
uint8_t verified_digest[HASH_LEN] = { [ 0 ... 31 ] = 0x01 };
#endif
if (data == NULL || part == NULL) {
return ESP_ERR_INVALID_ARG;
@ -172,6 +173,7 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
for (int i = 0; i < data->image.segment_count; i++) {
esp_image_segment_header_t *header = &data->segments[i];
ESP_LOGV(TAG, "loading segment header %d at offset 0x%x", i, next_addr);
err = process_segment(i, next_addr, header, silent, do_load, sha_handle, checksum);
if (err != ESP_OK) {
goto err;
@ -197,14 +199,14 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
}
}
/* For secure boot on ESP32, we don't calculate SHA or verify signautre on bootloaders.
For ESP32S2, we do verify signature on bootloader which includes the SHA calculation.
/* For secure boot V1 on ESP32, we don't calculate SHA or verify signature on bootloaders.
For Secure Boot V2, we do verify signature on bootloader which includes the SHA calculation.
(For non-secure boot, we don't verify any SHA-256 hash appended to the bootloader because
esptool.py may have rewritten the header - rely on esptool.py having verified the bootloader at flashing time, instead.)
*/
bool verify_sha;
#if CONFIG_SECURE_BOOT_ENABLED && CONFIG_IDF_TARGET_ESP32S2
#if CONFIG_SECURE_BOOT_V2_ENABLED
verify_sha = true;
#else // ESP32, or ESP32S2 without secure boot enabled
verify_sha = (data->start_addr != ESP_BOOTLOADER_OFFSET);
@ -217,7 +219,7 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
#ifdef SECURE_BOOT_CHECK_SIGNATURE
// secure boot images have a signature appended
err = verify_secure_boot_signature(sha_handle, data);
err = verify_secure_boot_signature(sha_handle, data, image_digest, verified_digest);
#else
// No secure boot, but SHA-256 can be appended for basic corruption detection
if (sha_handle != NULL && !esp_cpu_in_ocd_debug_mode()) {
@ -250,7 +252,28 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
}
#ifdef BOOTLOADER_BUILD
if (do_load && ram_obfs_value[0] != 0 && ram_obfs_value[1] != 0) { // Need to deobfuscate RAM
#ifdef SECURE_BOOT_CHECK_SIGNATURE
/* If signature was checked in bootloader build, verified_digest should equal image_digest
This is to detect any fault injection that caused signature verification to not complete normally.
Any attack which bypasses this check should be of limited use as the RAM contents are still obfuscated, therefore we do the check
immediately before we deobfuscate.
Note: the conditions for making this check are the same as for setting verify_sha above, but on ESP32 SB V1 we move the test for
"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);
#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
#endif // SECURE_BOOT_CHECK_SIGNATURE
// Deobfuscate RAM
if (do_load && ram_obfs_value[0] != 0 && ram_obfs_value[1] != 0) {
for (int i = 0; i < data->image.segment_count; i++) {
uint32_t load_addr = data->segments[i].load_addr;
if (should_load(load_addr)) {
@ -336,6 +359,127 @@ static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t
return err;
}
#ifdef BOOTLOADER_BUILD
/* Check the region load_addr - load_end doesn't overlap any memory used by the bootloader, registers, or other invalid memory
*/
static bool verify_load_addresses(int segment_index, intptr_t load_addr, intptr_t load_end, bool print_error, bool no_recurse)
{
/* Addresses of static data and the "loader" section of bootloader IRAM, all defined in ld script */
const char *reason = NULL;
extern int _dram_start, _dram_end, _loader_text_start, _loader_text_end;
void *load_addr_p = (void *)load_addr;
void *load_end_p = (void *)load_end;
if (load_end == load_addr) {
return true; // zero-length segments are fine
}
assert(load_end > load_addr); // data_len<16MB is checked in verify_segment_header() which is called before this, so this should always be true
if (esp_ptr_in_dram(load_addr_p) && esp_ptr_in_dram(load_end_p)) { /* Writing to DRAM */
/* Check if we're clobbering the stack */
intptr_t sp = (intptr_t)get_sp();
if (bootloader_util_regions_overlap(sp - STACK_LOAD_HEADROOM, SOC_ROM_STACK_START,
load_addr, load_end)) {
reason = "overlaps bootloader stack";
goto invalid;
}
/* Check if we're clobbering static data
(_dram_start.._dram_end includes bss, data, rodata sections in DRAM)
*/
if (bootloader_util_regions_overlap((intptr_t)&_dram_start, (intptr_t)&_dram_end, load_addr, load_end)) {
reason = "overlaps bootloader data";
goto invalid;
}
/* LAST DRAM CHECK (recursive): for D/IRAM, check the equivalent IRAM addresses if needed
Allow for the possibility that even though both pointers are IRAM, only part of the region is in a D/IRAM
section. In which case we recurse to check the part which falls in D/IRAM.
Note: We start with SOC_DIRAM_DRAM_LOW/HIGH and convert that address to IRAM to account for any reversing of word order
(chip-specific).
*/
if (!no_recurse && bootloader_util_regions_overlap(SOC_DIRAM_DRAM_LOW, SOC_DIRAM_DRAM_HIGH, load_addr, load_end)) {
intptr_t iram_load_addr, iram_load_end;
if (esp_ptr_in_diram_dram(load_addr_p)) {
iram_load_addr = (intptr_t)esp_ptr_diram_dram_to_iram(load_addr_p);
} else {
iram_load_addr = (intptr_t)esp_ptr_diram_dram_to_iram((void *)SOC_DIRAM_DRAM_LOW);
}
if (esp_ptr_in_diram_dram(load_end_p)) {
iram_load_end = (intptr_t)esp_ptr_diram_dram_to_iram(load_end_p);
} else {
iram_load_end = (intptr_t)esp_ptr_diram_dram_to_iram((void *)SOC_DIRAM_DRAM_HIGH);
}
if (iram_load_end < iram_load_addr) {
return verify_load_addresses(segment_index, iram_load_end, iram_load_addr, print_error, true);
} else {
return verify_load_addresses(segment_index, iram_load_addr, iram_load_end, print_error, true);
}
}
}
else if (esp_ptr_in_iram(load_addr_p) && esp_ptr_in_iram(load_end_p)) { /* Writing to IRAM */
/* Check for overlap of 'loader' section of IRAM */
if (bootloader_util_regions_overlap((intptr_t)&_loader_text_start, (intptr_t)&_loader_text_end,
load_addr, load_end)) {
reason = "overlaps loader IRAM";
goto invalid;
}
/* LAST IRAM CHECK (recursive): for D/IRAM, check the equivalent DRAM address if needed
Allow for the possibility that even though both pointers are IRAM, only part of the region is in a D/IRAM
section. In which case we recurse to check the part which falls in D/IRAM.
Note: We start with SOC_DIRAM_IRAM_LOW/HIGH and convert that address to DRAM to account for any reversing of word order
(chip-specific).
*/
if (!no_recurse && bootloader_util_regions_overlap(SOC_DIRAM_IRAM_LOW, SOC_DIRAM_IRAM_HIGH, load_addr, load_end)) {
intptr_t dram_load_addr, dram_load_end;
if (esp_ptr_in_diram_iram(load_addr_p)) {
dram_load_addr = (intptr_t)esp_ptr_diram_iram_to_dram(load_addr_p);
} else {
dram_load_addr = (intptr_t)esp_ptr_diram_iram_to_dram((void *)SOC_DIRAM_IRAM_LOW);
}
if (esp_ptr_in_diram_iram(load_end_p)) {
dram_load_end = (intptr_t)esp_ptr_diram_iram_to_dram(load_end_p);
} else {
dram_load_end = (intptr_t)esp_ptr_diram_iram_to_dram((void *)SOC_DIRAM_IRAM_HIGH);
}
if (dram_load_end < dram_load_addr) {
return verify_load_addresses(segment_index, dram_load_end, dram_load_addr, print_error, true);
} else {
return verify_load_addresses(segment_index, dram_load_addr, dram_load_end, print_error, true);
}
}
/* Sections entirely in RTC memory won't overlap with a vanilla bootloader but are valid load addresses, thus skipping them from the check */
} else if (esp_ptr_in_rtc_iram_fast(load_addr_p) && esp_ptr_in_rtc_iram_fast(load_end_p)){
return true;
} else if (esp_ptr_in_rtc_dram_fast(load_addr_p) && esp_ptr_in_rtc_dram_fast(load_end_p)){
return true;
} else if (esp_ptr_in_rtc_slow(load_addr_p) && esp_ptr_in_rtc_slow(load_end_p)) {
return true;
} else { /* Not a DRAM or an IRAM or RTC Fast IRAM, RTC Fast DRAM or RTC Slow address */
reason = "bad load address range";
goto invalid;
}
return true;
invalid:
if (print_error) {
ESP_LOGE(TAG, "Segment %d 0x%08x-0x%08x invalid: %s", segment_index, load_addr, load_end, reason);
}
return false;
}
#endif // BOOTLOADER_BUILD
static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segment_header_t *header, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum)
{
esp_err_t err;
@ -379,33 +523,8 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
#ifdef BOOTLOADER_BUILD
/* Before loading segment, check it doesn't clobber bootloader RAM. */
if (do_load && data_len > 0) {
const intptr_t load_end = load_addr + data_len;
if (load_end < (intptr_t) SOC_DRAM_HIGH) {
/* Writing to DRAM */
intptr_t sp = (intptr_t)get_sp();
if (load_end > sp - STACK_LOAD_HEADROOM) {
/* Bootloader .data/.rodata/.bss is above the stack, so this
* also checks that we aren't overwriting these segments.
*
* TODO: This assumes specific arrangement of sections we have
* in the ESP32. Rewrite this in a generic way to support other
* layouts.
*/
ESP_LOGE(TAG, "Segment %d end address 0x%08x too high (bootloader stack 0x%08x limit 0x%08x)",
index, load_end, sp, sp - STACK_LOAD_HEADROOM);
return ESP_ERR_IMAGE_INVALID;
}
} else {
/* Writing to IRAM */
const intptr_t loader_iram_start = (intptr_t) &_loader_text_start;
const intptr_t loader_iram_end = (intptr_t) &_loader_text_end;
if (bootloader_util_regions_overlap(loader_iram_start, loader_iram_end,
load_addr, load_end)) {
ESP_LOGE(TAG, "Segment %d (0x%08x-0x%08x) overlaps bootloader IRAM (0x%08x-0x%08x)",
index, load_addr, load_end, loader_iram_start, loader_iram_end);
return ESP_ERR_IMAGE_INVALID;
}
if (!verify_load_addresses(index, load_addr, load_addr + data_len, true, false)) {
return ESP_ERR_IMAGE_INVALID;
}
}
#endif // BOOTLOADER_BUILD
@ -415,6 +534,10 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
int32_t data_len_remain = data_len;
while (data_len_remain > 0) {
#if SECURE_BOOT_CHECK_SIGNATURE && defined(BOOTLOADER_BUILD)
/* Double check the address verification done above */
ESP_FAULT_ASSERT(!do_load || verify_load_addresses(0, load_addr, load_addr + data_len_remain, false, false));
#endif
uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0) ? 1 : 0;
/* Data we could map in case we are not aligned to PAGE boundary is one page size lesser. */
data_len = MIN(data_len_remain, ((free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE));
@ -440,7 +563,7 @@ static esp_err_t process_segment_data(intptr_t load_addr, uint32_t data_addr, ui
{
// If we are not loading, and the checksum is empty, skip processing this
// segment for data
if(!do_load && checksum == NULL) {
if (!do_load && checksum == NULL) {
ESP_LOGD(TAG, "skipping checksum for segment");
return ESP_OK;
}
@ -623,9 +746,9 @@ static esp_err_t verify_checksum(bootloader_sha256_handle_t sha_handle, uint32_t
return ESP_OK;
}
static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data)
static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data, uint8_t *image_digest, uint8_t *verified_digest)
{
uint8_t image_hash[HASH_LEN] = { 0 };
#ifdef SECURE_BOOT_CHECK_SIGNATURE
uint32_t end = data->start_addr + data->image_len;
ESP_LOGI(TAG, "Verifying image signature...");
@ -638,25 +761,36 @@ static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_han
bootloader_munmap(simple_hash);
}
#if CONFIG_IDF_TARGET_ESP32S2
// Pad to 4096 byte sector boundary
if (end % FLASH_SECTOR_SIZE != 0) {
uint32_t pad_len = FLASH_SECTOR_SIZE - (end % FLASH_SECTOR_SIZE);
const void *padding = bootloader_mmap(end, pad_len);
bootloader_sha256_data(sha_handle, padding, pad_len);
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
// End of the image needs to be padded all the way to a 4KB boundary, after the simple hash
// (for apps they are usually already padded due to --secure-pad-v2, only a problem if this option was not used.)
uint32_t padded_end = (end + FLASH_SECTOR_SIZE - 1) & ~(FLASH_SECTOR_SIZE-1);
if (padded_end > end) {
const void *padding = bootloader_mmap(end, padded_end - end);
bootloader_sha256_data(sha_handle, padding, padded_end - end);
bootloader_munmap(padding);
end += pad_len;
end = padded_end;
}
#endif
bootloader_sha256_finish(sha_handle, image_hash);
bootloader_sha256_finish(sha_handle, image_digest);
// Log the hash for debugging
bootloader_debug_buffer(image_hash, HASH_LEN, "Calculated secure boot hash");
bootloader_debug_buffer(image_digest, HASH_LEN, "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);
esp_err_t err = ESP_ERR_IMAGE_INVALID;
const void *sig_block;
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
ESP_FAULT_ASSERT(memcmp(image_digest, verified_digest, HASH_LEN) != 0); /* sanity check that these values start differently */
sig_block = bootloader_mmap(data->start_addr + data->image_len, sizeof(esp_secure_boot_sig_block_t));
err = esp_secure_boot_verify_ecdsa_signature_block(sig_block, image_digest, verified_digest);
#elif CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
ESP_FAULT_ASSERT(memcmp(image_digest, verified_digest, HASH_LEN) != 0); /* sanity check that these values start differently */
sig_block = bootloader_mmap(end, sizeof(ets_secure_boot_signature_t));
err = esp_secure_boot_verify_rsa_signature_block(sig_block, image_digest, verified_digest);
#endif
bootloader_munmap(sig_block);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Secure boot signature verification failed");
@ -677,11 +811,12 @@ static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_han
return ESP_ERR_IMAGE_INVALID;
}
#if CONFIG_IDF_TARGET_ESP32S2
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
// Adjust image length result to include the appended signature
data->image_len = end - data->start_addr + sizeof(ets_secure_boot_signature_t);
#endif
#endif // SECURE_BOOT_CHECK_SIGNATURE
return ESP_OK;
}

View file

@ -31,7 +31,7 @@ void esp_flash_encryption_init_checks()
// FLASH_CRYPT_CNT *must* be write protected. This will have happened automatically
// if bootloader is IDF V4.0 or newer but may not have happened for previous ESP-IDF bootloaders.
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
#ifdef CONFIG_SECURE_BOOT_ENABLED
#ifdef CONFIG_SECURE_BOOT
if (esp_secure_boot_enabled() && esp_flash_encryption_enabled()) {
uint8_t flash_crypt_cnt_wr_dis = 0;
esp_efuse_read_field_blob(ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT, &flash_crypt_cnt_wr_dis, 1);
@ -40,7 +40,7 @@ void esp_flash_encryption_init_checks()
esp_flash_write_protect_crypt_cnt();
}
}
#endif // CONFIG_SECURE_BOOT_ENABLED
#endif // CONFIG_SECURE_BOOT
#endif // CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
// Second check is to print a warning or error if the current running flash encryption mode

View file

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "bootloader_sha.h"
#include "bootloader_flash.h"
#include <stdbool.h>
#include <string.h>
#include <assert.h>

View file

@ -15,46 +15,55 @@
#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 "mbedtls/sha256.h"
#include "mbedtls/x509.h"
#include "mbedtls/md.h"
#include "mbedtls/platform.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include <string.h>
#include <sys/param.h>
static const char *TAG = "secure_boot";
#define DIGEST_LEN 32
#ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
static const char *TAG = "secure_boot_v1";
extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
#define SIGNATURE_VERIFICATION_KEYLEN 64
#define DIGEST_LEN 32
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
{
uint8_t digest[DIGEST_LEN];
const uint8_t *data;
uint8_t verified_digest[DIGEST_LEN];
const esp_secure_boot_sig_block_t *sigblock;
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
data = bootloader_mmap(src_addr, length + sizeof(esp_secure_boot_sig_block_t));
if (data == NULL) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length + sizeof(esp_secure_boot_sig_block_t));
return ESP_FAIL;
esp_err_t err = bootloader_sha256_flash_contents(src_addr, length, digest);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Digest calculation failed 0x%x, 0x%x", src_addr, length);
return err;
}
// Calculate digest of main image
mbedtls_sha256_ret(data, length, digest, 0);
// 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);
sigblock = (const esp_secure_boot_sig_block_t *)bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t));
if (sigblock == NULL) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t));
return ESP_FAIL;
}
err = esp_secure_boot_verify_ecdsa_signature_block(sigblock, digest, verified_digest);
bootloader_munmap(sigblock);
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)
esp_err_t esp_secure_boot_verify_ecdsa_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest, uint8_t *verified_digest)
{
#if !(defined(CONFIG_MBEDTLS_ECDSA_C) && defined(CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED))
ESP_LOGE(TAG, "Signature verification requires ECDSA & SECP256R1 curve enabled");
@ -62,6 +71,9 @@ esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block
#else
ptrdiff_t keylen;
/* Note: in IDF app image verification we don't add any fault injection resistance, boot-time checks only */
memset(verified_digest, 0, DIGEST_LEN);
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);
@ -123,3 +135,139 @@ cleanup:
return ret == 0 ? ESP_OK : ESP_ERR_IMAGE_INVALID;
#endif // CONFIG_MBEDTLS_ECDSA_C && CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED
}
#elif CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
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 */
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
{
uint8_t digest[DIGEST_LEN] = {0};
uint8_t verified_digest[DIGEST_LEN] = {0};
/* Rounding off length to the upper 4k boundary */
uint32_t padded_length = ALIGN_UP(length, FLASH_SECTOR_SIZE);
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
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);
return err;
}
const ets_secure_boot_signature_t *sig_block = bootloader_mmap(src_addr + padded_length, sizeof(ets_secure_boot_signature_t));
if (sig_block == NULL) {
ESP_LOGE(TAG, "Failed to mmap data at offset 0x%x", src_addr + padded_length);
return ESP_FAIL;
}
err = esp_secure_boot_verify_rsa_signature_block(sig_block, digest, verified_digest);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Secure Boot V2 verification failed.");
}
bootloader_munmap(sig_block);
return err;
}
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)
{
uint8_t i = 0, 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));
/* 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 (memcmp(efuse_trusted_digest, sig_block_trusted_digest, DIGEST_LEN) != 0) {
if (esp_secure_boot_enabled()) {
ESP_LOGE(TAG, "Public key digest in eFuse BLK2 and the signature block don't match.");
return ESP_FAIL;
} else {
ESP_LOGW(TAG, "Public key digest in eFuse BLK2 and the signature block don't match.");
}
}
ESP_LOGI(TAG, "Verifying with RSA-PSS...");
int ret = 0;
mbedtls_rsa_context pk;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
unsigned char *sig_be = calloc(1, RSA_KEY_SIZE);
unsigned char *buf = calloc(1, RSA_KEY_SIZE);
if (sig_be == NULL || buf == NULL) {
return ESP_ERR_NO_MEM;
}
mbedtls_entropy_init(&entropy);
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
if (ret != 0) {
ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%04x\n", ret);
goto exit;
}
for (i = 0; i < SECURE_BOOT_NUM_BLOCKS; i++) {
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,
};
const mbedtls_mpi e = { .s = 1,
.n = sizeof(sig_block->block[i].key.e)/sizeof(mbedtls_mpi_uint), // 1
.p = (void *)&sig_block->block[i].key.e,
};
mbedtls_rsa_init(&pk, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
ret = mbedtls_rsa_import(&pk, &N, NULL, NULL, NULL, &e);
if (ret != 0) {
ESP_LOGE(TAG, "Failed mbedtls_rsa_import, err: %d", ret);
goto exit;
}
ret = mbedtls_rsa_complete(&pk);
if (ret != 0) {
ESP_LOGE(TAG, "Failed mbedtls_rsa_complete, err: %d", ret);
goto exit;
}
ret = mbedtls_rsa_check_pubkey(&pk);
if (ret != 0) {
ESP_LOGI(TAG, "Key is not an RSA key -%0x", -ret);
goto exit;
}
/* Signature needs to be byte swapped into BE representation */
for (int j = 0; j < RSA_KEY_SIZE; j++) {
sig_be[RSA_KEY_SIZE- j - 1] = sig_block->block[i].signature[j];
}
ret = mbedtls_rsa_public( &pk, sig_be, buf);
if (ret != 0) {
ESP_LOGE(TAG, "mbedtls_rsa_public failed, err: %d", ret);
goto exit;
}
ret = mbedtls_rsa_rsassa_pss_verify( &pk, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, 32,
sig_block->block[i].image_digest, sig_be);
if (ret != 0) {
ESP_LOGE(TAG, "Failed mbedtls_rsa_rsassa_pss_verify, err: %d", ret);
} else {
ESP_LOGI(TAG, "Signature verified successfully!");
}
exit:
mbedtls_rsa_free(&pk);
if (ret == 0) {
break;
}
}
free(sig_be);
free(buf);
return (!ret) ? ESP_OK : ESP_ERR_IMAGE_INVALID;
}
#endif

View file

@ -0,0 +1,93 @@
// Copyright 2020 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 "sdkconfig.h"
#include "soc/rtc_cntl_reg.h"
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Assert a condition is true, in a way that should be resistant to fault injection for
* single fault attacks.
*
* - Expands CONDITION multiple times (condition must have no side effects)
* - Compiler is told all registers are invalid before evaluating CONDITION each time, to avoid a fault
* causing a misread of a register used in all three evaluations of CONDITION.
* - If CONDITION is ever false, a system reset is triggered.
*
* @note Place this macro after a "normal" check of CONDITION that will fail with a normal error
* message. This is the fallback in case a fault injection attack skips or corrupts the result of
* that check. (Although ensure that an attacker can't use fault injection to skip past the "normal"
* error message, to avoid this check entirely.)
*
* @note This macro increases binary size and is slow and should be used sparingly.
*
* @note This macro does not guarantee fault injection resistance. In particular CONDITION must be
* chosen carefully - a fault injection attack which sets CONDITION to true will not be detected by
* this macro. Care must also be taken that an attacker can't use a fault to completely bypass calling
* whatever function tests ESP_FAULT_ASSERT.
*
* @note This is difficult to debug as a failure triggers an instant software reset, and UART output
* is often truncated (as FIFO is not flushed). Define the ESP_FAULT_ASSERT_DEBUG macro to debug any
* failures of this macro due to software bugs.
*
* @param CONDITION A condition which will evaluate true unless an attacker used fault injection to skip or corrupt some other critical system calculation.
*
*/
#define ESP_FAULT_ASSERT(CONDITION) do { \
asm volatile ("" ::: "memory"); \
if(!(CONDITION)) _ESP_FAULT_RESET(); \
asm volatile ("" ::: "memory"); \
if(!(CONDITION)) _ESP_FAULT_RESET(); \
asm volatile ("" ::: "memory"); \
if(!(CONDITION)) _ESP_FAULT_RESET(); \
} while(0)
// Uncomment this macro to get debug output if ESP_FAULT_ASSERT() fails
//
// Note that uncommenting this macro reduces the anti-FI effectiveness
//
//#define ESP_FAULT_ASSERT_DEBUG
/* Internal macro, purpose is to trigger a system reset if an inconsistency due to fault injection
is detected.
Illegal instruction opcodes are there as a fallback to crash the CPU in case it doesn't
reset as expected.
*/
#ifndef ESP_FAULT_ASSERT_DEBUG
#define _ESP_FAULT_RESET() do { \
REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST); \
asm volatile("ill; ill; ill;"); \
} while(0)
#else // ESP_FAULT_ASSERT_DEBUG
#warning "Enabling ESP_FAULT_ASSERT_DEBUG makes ESP_FAULT_ASSERT() less effective"
#define _ESP_FAULT_RESET() do { \
ets_printf("ESP_FAULT_ASSERT %s:%d\n", __FILE__, __LINE__); \
asm volatile("ill;"); \
} while(0)
#endif // ESP_FAULT_ASSERT_DEBUG
#ifdef __cplusplus
}
#endif

View file

@ -12,6 +12,10 @@ if(BOOTLOADER_BUILD)
list(APPEND scripts "esp32s2/ld/esp32s2.rom.spiflash.ld")
endif()
if(CONFIG_ESP32_REV_MIN_3)
list(APPEND scripts "esp32/ld/esp32.rom.eco3.ld")
endif()
target_linker_script(${COMPONENT_LIB} INTERFACE "${scripts}")
else() # Regular app build
set(scripts
@ -42,8 +46,13 @@ else() # Regular app build
list(APPEND scripts "esp32/ld/esp32.rom.spiflash.ld")
endif()
if(CONFIG_ESP32_REV_MIN_3)
list(APPEND scripts "esp32/ld/esp32.rom.eco3.ld")
endif()
elseif(target STREQUAL "esp32s2")
# no SPIRAM workaround for esp32s2
# no nano formatting function in ROM
list(APPEND scripts "esp32s2/ld/esp32s2.rom.newlib-funcs.ld"
"esp32s2/ld/esp32s2.rom.spiflash.ld")

View file

@ -11,6 +11,10 @@ LINKER_SCRIPTS += esp32.rom.ld \
ifndef CONFIG_SPIRAM_CACHE_WORKAROUND
LINKER_SCRIPTS += esp32.rom.newlib-funcs.ld
ifdef CONFIG_ESP32_REV_MIN_3
LINKER_SCRIPTS += esp32.rom.eco3.ld
endif
# Include in newlib nano from ROM only if SPIRAM cache workaround is disabled
ifdef CONFIG_NEWLIB_NANO_FORMAT
LINKER_SCRIPTS += esp32.rom.newlib-nano.ld

View file

@ -0,0 +1,7 @@
/*
ESP32 ECO3 ROM address table
Secure Boot Version 2 API's imported from the ROM
*/
PROVIDE ( ets_secure_boot_verify_signature = 0x4006543c);
PROVIDE ( ets_secure_boot_verify_boot_bootloader = 0x400655ec);
PROVIDE ( ets_use_secure_boot_v2 = 0x4000f8d4);

View file

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "sdkconfig.h"
#ifndef _ROM_SECURE_BOOT_H_
#define _ROM_SECURE_BOOT_H_
@ -39,8 +41,74 @@ bool ets_secure_boot_check_start(uint8_t abs_index, uint32_t iv_addr);
int ets_secure_boot_check_finish(uint32_t *abstract);
#ifdef __cplusplus
}
#endif
#ifdef CONFIG_ESP32_REV_MIN_3
#define SECURE_BOOT_NUM_BLOCKS 1
#endif /* _ROM_SECURE_BOOT_H_ */
typedef enum {
SBV2_SUCCESS = 0x3A5A5AA5,
SBV2_FAILED = 0xA533885A,
} secure_boot_v2_status_t;
/* Secure Boot Version 2 - Public Key format */
typedef struct {
uint8_t n[384]; /* Public key modulus */
uint32_t e; /* Public key exponent */
uint8_t rinv[384];
uint32_t mdash;
} ets_rsa_pubkey_t;
/* Secure Boot Version 2 signature format for ESP32 ECO3 */
typedef struct {
uint8_t magic_byte;
uint8_t version;
uint8_t _reserved1;
uint8_t _reserved2;
uint8_t image_digest[32];
ets_rsa_pubkey_t key;
uint8_t signature[384];
uint32_t block_crc;
uint8_t _padding[16];
} ets_secure_boot_sig_block_t;
/* Multiple key block support */
struct ets_secure_boot_signature {
ets_secure_boot_sig_block_t block[SECURE_BOOT_NUM_BLOCKS];
uint8_t _padding[4096 - (sizeof(ets_secure_boot_sig_block_t) * SECURE_BOOT_NUM_BLOCKS)];
};
typedef struct ets_secure_boot_signature ets_secure_boot_signature_t;
/** @brief Verifies the signature block appended to a firmware image. Implemented in the ROM.
*
* This function is used to verify the bootloader before burning its public key hash into Efuse.
* Also, it is used to verify the app on loading the image on boot and on OTA.
*
* @param sig The signature block flashed aligned 4096 bytes from the firmware.
* @param image_digest The SHA-256 Digest of the firmware to be verified
* @param trusted_key_digest The SHA-256 Digest of the public key (ets_rsa_pubkey_t) of a single signature block.
* @param verified_digest RSA-PSS signature of image_digest. Pass an uninitialised array.
*
* @return SBV2_SUCCESS if signature is valid
* SBV2_FAILED for failures.
*/
secure_boot_v2_status_t ets_secure_boot_verify_signature(const ets_secure_boot_signature_t *sig, const uint8_t *image_digest, const uint8_t *trusted_key_digest, uint8_t *verified_digest);
/** @brief This function verifies the 1st stage bootloader. Implemented in the ROM.
* Reboots post verification. It reads the Efuse key for verification of the public key.
*
* This function is not used in the current workflow.
*
*/
void ets_secure_boot_verify_boot_bootloader(void);
/** @brief Confirms if the secure boot V2 has been enabled. Implemented in the ROM.
*
* In ESP32-ECO3 - It checks the value of ABS_DONE_1 in EFuse.
*
* @return true if is Secure boot v2 has been enabled
* False if Secure boot v2 has not been enabled.
*/
bool ets_use_secure_boot_v2();
#endif /* CONFIG_ESP32_REV_MIN_3 */
#endif /* _ROM_SECURE_BOOT_H_ */

View file

@ -1,4 +1,4 @@
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
// Copyright 2020 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.
@ -29,45 +29,77 @@ typedef struct ets_secure_boot_sig_block ets_secure_boot_sig_block_t;
typedef struct ets_secure_boot_signature ets_secure_boot_signature_t;
typedef struct ets_secure_boot_key_digests ets_secure_boot_key_digests_t;
/* Verify bootloader image (reconfigures cache to map,
loads trusted key digests from efuse)
/* 64KB 'staging buffer' for loading the verified bootloader
If allow_key_revoke is true and aggressive revoke efuse is set,
any failed signature has its associated key revoked in efuse.
Comes from the "shared buffers" region (see shared_buffers.h)
If result is ETS_OK, the "simple hash" of the bootloader
is copied into verified_hash.
The bootloader can't be safely linked into this address range
(may be possible with some cleverness.)
*/
int ets_secure_boot_verify_bootloader(uint8_t *verified_hash, bool allow_key_revoke);
#define SECURE_BOOT_STAGING_BUFFER_START ((uint32_t)(g_shared_buffers.secure_boot_staging_buf))
#define SECURE_BOOT_STAGING_BUFFER_SZ sizeof(g_shared_buffers.secure_boot_staging_buf)
#define SECURE_BOOT_STAGING_BUFFER_END (SECURE_BOOT_STAGING_BUFFER_START + SECURE_BOOT_STAGING_BUFFER_SZ)
/* Verify bootloader image (reconfigures cache to map), with
key digests provided as parameters.)
/* Anti-FI measure: use full words for success/fail, instead of
0/non-zero
*/
typedef enum {
SB_SUCCESS = 0x3A5A5AA5,
SB_FAILED = 0x7533885E,
} ets_secure_boot_status_t;
/* Verify and stage-load the bootloader image
(reconfigures cache to map, loads trusted key digests from efuse,
copies the bootloader into the staging buffer.)
If allow_key_revoke is true and aggressive revoke efuse is set,
any failed signature has its associated key revoked in efuse.
If result is SB_SUCCESS, the "simple hash" of the bootloader
is copied into verified_hash.
*/
ets_secure_boot_status_t ets_secure_boot_verify_stage_bootloader(uint8_t *verified_hash, bool allow_key_revoke);
/* Verify bootloader image (reconfigures cache to map),
with key digests provided as parameters.)
Can be used to verify secure boot status before enabling
secure boot permanently.
If result is ETS_OK, the "simple hash" of the bootloader is
If stage_load parameter is true, bootloader is copied into staging
buffer in RAM at the same time.
If result is SB_SUCCESS, the "simple hash" of the bootloader is
copied into verified_hash.
*/
int ets_secure_boot_verify_bootloader_with_keys(uint8_t *verified_hash, const ets_secure_boot_key_digests_t *trusted_keys);
ets_secure_boot_status_t ets_secure_boot_verify_bootloader_with_keys(uint8_t *verified_hash, const ets_secure_boot_key_digests_t *trusted_keys, bool stage_load);
/* Read key digests from efuse. Any revoked/missing digests will be
marked as NULL
*/
ETS_STATUS ets_secure_boot_read_key_digests(ets_secure_boot_key_digests_t *trusted_keys);
/* Verify supplied signature against supplied digest, using
supplied trusted key digests.
Doesn't reconfigure cache or any other hardware access.
*/
int ets_secure_boot_verify_signature(const ets_secure_boot_signature_t *sig, const uint8_t *image_digest, const ets_secure_boot_key_digests_t *trusted_keys);
Doesn't reconfigure cache or any other hardware access except for RSA peripheral.
/* Read key digests from efuse. Any revoked/missing digests will be
marked as NULL
Returns 0 if at least one valid digest was found.
If result is SB_SUCCESS, the image_digest value is copied into verified_digest.
*/
int ets_secure_boot_read_key_digests(ets_secure_boot_key_digests_t *trusted_keys);
ets_secure_boot_status_t ets_secure_boot_verify_signature(const ets_secure_boot_signature_t *sig, const uint8_t *image_digest, const ets_secure_boot_key_digests_t *trusted_keys, uint8_t *verified_digest);
/* Revoke a public key digest in efuse.
@param index Digest to revoke. Must be 0, 1 or 2.
*/
void ets_secure_boot_revoke_public_key_digest(int index);
#define ETS_SECURE_BOOT_V2_SIGNATURE_MAGIC 0xE7
/* Secure Boot V2 signature block (up to 3 can be appended) */
/* Secure Boot V2 signature block
(Up to 3 in a signature sector are appended to the image)
*/
struct ets_secure_boot_sig_block {
uint8_t magic_byte;
uint8_t version;
@ -92,8 +124,10 @@ struct ets_secure_boot_signature {
_Static_assert(sizeof(ets_secure_boot_signature_t) == 4096, "invalid sig sector size");
#define MAX_KEY_DIGESTS 3
struct ets_secure_boot_key_digests {
const void *key_digests[3];
const void *key_digests[MAX_KEY_DIGESTS];
bool allow_key_revoke;
};

View file

@ -29,7 +29,7 @@ if(NOT BOOTLOADER_BUILD)
set(ESPTOOLPY_CHIP "${target}")
set(ESPTOOLPY_WITH_STUB TRUE)
if(CONFIG_SECURE_BOOT_ENABLED OR CONFIG_SECURE_FLASH_ENC_ENABLED)
if(CONFIG_SECURE_BOOT OR CONFIG_SECURE_FLASH_ENC_ENABLED)
# If security enabled then override post flash option
set(ESPTOOLPY_AFTER "no_reset")
endif()

View file

@ -29,16 +29,22 @@ else
ESPTOOL_WRITE_FLASH_OPTIONS := $(ESPTOOL_FLASH_OPTIONS)
endif
ifdef CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
ESPTOOL_WRITE_FLASH_OPTIONS := --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) --flash_size keep
endif
ESPTOOL_ELF2IMAGE_OPTIONS :=
ifdef CONFIG_ESP32_REV_MIN
ESPTOOL_ELF2IMAGE_OPTIONS += --min-rev $(CONFIG_ESP32_REV_MIN)
endif
ifdef CONFIG_SECURE_BOOT_ENABLED
ifndef CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION
ifndef IS_BOOTLOADER_BUILD
ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
ESPTOOL_ELF2IMAGE_OPTIONS += --secure-pad
else ifdef CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
ESPTOOL_ELF2IMAGE_OPTIONS += --secure-pad-v2
endif
endif
endif
@ -47,6 +53,12 @@ ifndef IS_BOOTLOADER_BUILD
ESPTOOL_ELF2IMAGE_OPTIONS += --elf-sha256-offset 0xb0
endif
ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
SECURE_APPS_SIGNING_SCHEME = "1"
else ifdef CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
SECURE_APPS_SIGNING_SCHEME = "2"
endif
ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z,-u) $(ESPTOOL_WRITE_FLASH_OPTIONS)
ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
@ -61,7 +73,7 @@ ifndef IS_BOOTLOADER_BUILD
APP_BIN_UNSIGNED := $(APP_BIN:.bin=-unsigned.bin)
$(APP_BIN): $(APP_BIN_UNSIGNED) $(SECURE_BOOT_SIGNING_KEY) $(SDKCONFIG_MAKEFILE)
$(ESPSECUREPY) sign_data --keyfile $(SECURE_BOOT_SIGNING_KEY) -o $@ $<
$(ESPSECUREPY) sign_data --version $(SECURE_APPS_SIGNING_SCHEME) --keyfile $(SECURE_BOOT_SIGNING_KEY) -o $@ $<
endif
endif
# non-secure boot (or bootloader), both these files are the same
@ -77,7 +89,7 @@ endif
ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
encrypted-flash: all_binaries $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info | check_python_dependencies
@echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(APP_OFFSET))..."
ifdef CONFIG_SECURE_BOOT_ENABLED
ifdef CONFIG_SECURE_BOOT
@echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)"
endif
$(ESPTOOLPY_WRITE_FLASH_ENCRYPT) $(ESPTOOL_ALL_FLASH_ARGS)
@ -89,7 +101,7 @@ endif
flash: all_binaries $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info | check_python_dependencies
@echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(APP_OFFSET))..."
ifdef CONFIG_SECURE_BOOT_ENABLED
ifdef CONFIG_SECURE_BOOT
@echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)"
endif
$(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS)

@ -1 +1 @@
Subproject commit 939b3e987ac6efde171add89ee26a34031058760
Subproject commit 91bdc71841d1b4e561e8e896405b58db86d5fd72

View file

@ -22,10 +22,13 @@ if(NOT BOOTLOADER_BUILD)
set(esptool_elf2image_args --elf-sha256-offset 0xb0)
endif()
if(CONFIG_SECURE_BOOT_ENABLED AND
NOT CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION
AND NOT BOOTLOADER_BUILD)
list(APPEND esptool_elf2image_args --secure-pad)
if(NOT CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION AND
NOT BOOTLOADER_BUILD)
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
list(APPEND esptool_elf2image_args --secure-pad)
elseif(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
list(APPEND esptool_elf2image_args --secure-pad-v2)
endif()
endif()
if(CONFIG_ESP32_REV_MIN)
@ -38,6 +41,10 @@ if(CONFIG_ESPTOOLPY_FLASHSIZE_DETECT)
set(ESPFLASHSIZE detect)
endif()
if(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
set(ESPFLASHSIZE keep)
endif()
idf_build_get_property(build_dir BUILD_DIR)
idf_build_get_property(elf_name EXECUTABLE_NAME GENERATOR_EXPRESSION)
@ -77,11 +84,17 @@ if(CONFIG_APP_BUILD_GENERATE_BINARIES)
add_custom_target(app ALL DEPENDS gen_project_binary)
endif()
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
set(secure_boot_version "1")
elseif(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
set(secure_boot_version "2")
endif()
if(NOT BOOTLOADER_BUILD AND CONFIG_SECURE_SIGNED_APPS)
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
# for locally signed secure boot image, add a signing step to get from unsigned app to signed app
add_custom_command(OUTPUT "${build_dir}/.signed_bin_timestamp"
COMMAND ${ESPSECUREPY} sign_data --keyfile ${secure_boot_signing_key}
COMMAND ${ESPSECUREPY} sign_data --version ${secure_boot_version} --keyfile ${secure_boot_signing_key}
-o "${build_dir}/${PROJECT_BIN}" "${build_dir}/${unsigned_project_binary}"
COMMAND ${CMAKE_COMMAND} -E echo "Generated signed binary image ${build_dir}/${PROJECT_BIN}"
"from ${build_dir}/${unsigned_project_binary}"
@ -103,7 +116,8 @@ if(NOT BOOTLOADER_BUILD AND CONFIG_SECURE_SIGNED_APPS)
COMMAND ${CMAKE_COMMAND} -E echo
"App built but not signed. Sign app before flashing"
COMMAND ${CMAKE_COMMAND} -E echo
"\t${espsecurepy} sign_data --keyfile KEYFILE ${build_dir}/${PROJECT_BIN}"
"\t${espsecurepy} sign_data --keyfile KEYFILE --version ${secure_boot_version} \
${build_dir}/${PROJECT_BIN}"
VERBATIM)
endif()
endif()
@ -131,7 +145,7 @@ add_custom_target(monitor
set(esptool_flash_main_args "--before=${CONFIG_ESPTOOLPY_BEFORE}")
if(CONFIG_SECURE_BOOT_ENABLED OR CONFIG_SECURE_FLASH_ENC_ENABLED)
if(CONFIG_SECURE_BOOT OR CONFIG_SECURE_FLASH_ENC_ENABLED)
# If security enabled then override post flash option
list(APPEND esptool_flash_main_args "--after=no_reset")
else()

View file

@ -39,17 +39,16 @@ possible. This should optimize the amount of RAM accessible to the code without
IRAM_ATTR static void *dram_alloc_to_iram_addr(void *addr, size_t len)
{
uintptr_t dstart = (uintptr_t)addr; //First word
uintptr_t dend = dstart + len; //Last word + 4
uintptr_t dend = dstart + len - 4; //Last word
assert(esp_ptr_in_diram_dram((void *)dstart));
assert(esp_ptr_in_diram_dram((void *)dend));
assert((dstart & 3) == 0);
assert((dend & 3) == 0);
#if SOC_DIRAM_INVERTED
uint32_t istart = SOC_DIRAM_IRAM_LOW + (SOC_DIRAM_DRAM_HIGH - dend);
#ifdef SOC_DIRAM_INVERTED // We want the word before the result to hold the DRAM address
uint32_t *iptr = esp_ptr_diram_dram_to_iram((void *)dend);
#else
uint32_t istart = SOC_DIRAM_IRAM_LOW + (dstart - SOC_DIRAM_DRAM_LOW);
uint32_t *iptr = esp_ptr_diram_dram_to_iram((void *)dstart);
#endif
uint32_t *iptr = (uint32_t *)istart;
*iptr = dstart;
return iptr + 1;
}

View file

@ -0,0 +1,74 @@
/*
Tests for D/IRAM support in heap capability allocator
*/
#include <esp_types.h>
#include <stdio.h>
#include "unity.h"
#include "esp_heap_caps.h"
#include "soc/soc_memory_layout.h"
#define ALLOC_SZ 1024
static void *malloc_block_diram(uint32_t caps)
{
void *attempts[256] = { 0 }; // Allocate up to 256 ALLOC_SZ blocks to exhaust all non-D/IRAM memory temporarily
int count = 0;
void *result;
while(count < sizeof(attempts)/sizeof(void *)) {
result = heap_caps_malloc(ALLOC_SZ, caps);
TEST_ASSERT_NOT_NULL_MESSAGE(result, "not enough free heap to perform test");
if (esp_ptr_in_diram_dram(result) || esp_ptr_in_diram_iram(result)) {
break;
}
attempts[count] = result;
result = NULL;
count++;
}
for (int i = 0; i < count; i++) {
free(attempts[i]);
}
TEST_ASSERT_NOT_NULL_MESSAGE(result, "not enough D/IRAM memory is free");
return result;
}
TEST_CASE("Allocate D/IRAM as DRAM", "[heap]")
{
uint32_t *dram = malloc_block_diram(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
for (int i = 0; i < ALLOC_SZ / sizeof(uint32_t); i++) {
uint32_t v = i + 0xAAAA;
dram[i] = v;
volatile uint32_t *iram = esp_ptr_diram_dram_to_iram(dram + i);
TEST_ASSERT_EQUAL(v, dram[i]);
TEST_ASSERT_EQUAL(v, *iram);
*iram = UINT32_MAX;
TEST_ASSERT_EQUAL(UINT32_MAX, *iram);
TEST_ASSERT_EQUAL(UINT32_MAX, dram[i]);
}
free(dram);
}
TEST_CASE("Allocate D/IRAM as IRAM", "[heap]")
{
uint32_t *iram = malloc_block_diram(MALLOC_CAP_EXEC);
for (int i = 0; i < ALLOC_SZ / sizeof(uint32_t); i++) {
uint32_t v = i + 0xEEE;
iram[i] = v;
volatile uint32_t *dram = esp_ptr_diram_iram_to_dram(iram + i);
TEST_ASSERT_EQUAL_HEX32(v, iram[i]);
TEST_ASSERT_EQUAL_HEX32(v, *dram);
*dram = UINT32_MAX;
TEST_ASSERT_EQUAL_HEX32(UINT32_MAX, *dram);
TEST_ASSERT_EQUAL_HEX32(UINT32_MAX, iram[i]);
}
free(iram);
}

View file

@ -6,7 +6,7 @@ endif()
set(partition_csv "${PARTITION_CSV_PATH}")
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES AND CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
set(unsigned_partition_bin "partition-table-unsigned.bin")
set(final_partition_bin "partition-table.bin")
set(final_partition_target "sign_partition_table")
@ -24,7 +24,7 @@ if(CONFIG_ESPTOOLPY_FLASHSIZE)
set(flashsize_opt --flash-size ${CONFIG_ESPTOOLPY_FLASHSIZE})
endif()
if(CONFIG_SECURE_BOOT_ENABLED AND NOT CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION)
if(CONFIG_SECURE_BOOT AND NOT CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION)
set(partition_secure_opt --secure)
else()
set(partition_secure_opt "")
@ -52,13 +52,13 @@ else()
endif()
# Add signing steps
if(CONFIG_SECURE_SIGNED_APPS)
if(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
add_custom_target(gen_unsigned_partition_bin ALL DEPENDS
"${build_dir}/partition_table/${unsigned_partition_bin}")
add_custom_command(OUTPUT "${build_dir}/partition_table/${final_partition_bin}"
COMMAND ${ESPSECUREPY} sign_data --keyfile "${SECURE_BOOT_SIGNING_KEY}"
COMMAND ${ESPSECUREPY} sign_data --version 1 --keyfile "${SECURE_BOOT_SIGNING_KEY}"
-o "${build_dir}/partition_table/${final_partition_bin}"
"${build_dir}/partition_table/${unsigned_partition_bin}"
DEPENDS "${build_dir}/partition_table/${unsigned_partition_bin}"
@ -72,6 +72,10 @@ if(CONFIG_SECURE_SIGNED_APPS)
"\t${espsecurepy} sign_data --keyfile KEYFILE ${build_dir}/partition_table/${final_partition_bin}"
VERBATIM)
endif()
elseif(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME)
add_custom_command(TARGET partition_table POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Partition table built:"
VERBATIM)
endif()
idf_component_get_property(main_args esptool_py FLASH_ARGS)

View file

@ -19,7 +19,7 @@ PARTITION_FLASHSIZE_OPT := --flash-size $(CONFIG_ESPTOOLPY_FLASHSIZE)
endif
PARTITION_SECURE_OPT :=
ifdef CONFIG_SECURE_BOOT_ENABLED
ifdef CONFIG_SECURE_BOOT
ifndef CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION
PARTITION_SECURE_OPT += --secure
endif
@ -46,11 +46,16 @@ PARTITION_TABLE_CSV_NAME := $(notdir $(PARTITION_TABLE_CSV_PATH))
PARTITION_TABLE_BIN := $(BUILD_DIR_BASE)/$(PARTITION_TABLE_CSV_NAME:.csv=.bin)
ifdef CONFIG_SECURE_BOOT_V1_ENABLED
ifdef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
PARTITION_TABLE_BIN_UNSIGNED := $(PARTITION_TABLE_BIN:.bin=-unsigned.bin)
# add an extra signing step for secure partition table
$(PARTITION_TABLE_BIN): $(PARTITION_TABLE_BIN_UNSIGNED) $(SDKCONFIG_MAKEFILE) $(SECURE_BOOT_SIGNING_KEY)
$(ESPSECUREPY) sign_data --keyfile $(SECURE_BOOT_SIGNING_KEY) -o $@ $<
$(ESPSECUREPY) sign_data --version 1 --keyfile $(SECURE_BOOT_SIGNING_KEY) -o $@ $<
else
# secure bootloader disabled, both files are the same
PARTITION_TABLE_BIN_UNSIGNED := $(PARTITION_TABLE_BIN)
endif
else
# secure bootloader disabled, both files are the same
PARTITION_TABLE_BIN_UNSIGNED := $(PARTITION_TABLE_BIN)

View file

@ -213,9 +213,47 @@ inline static bool IRAM_ATTR esp_ptr_in_diram_iram(const void *p) {
return ((intptr_t)p >= SOC_DIRAM_IRAM_LOW && (intptr_t)p < SOC_DIRAM_IRAM_HIGH);
}
inline static bool IRAM_ATTR esp_ptr_in_rtc_iram_fast(const void *p) {
return ((intptr_t)p >= SOC_RTC_IRAM_LOW && (intptr_t)p < SOC_RTC_IRAM_HIGH);
}
inline static bool IRAM_ATTR esp_ptr_in_rtc_dram_fast(const void *p) {
return ((intptr_t)p >= SOC_RTC_DRAM_LOW && (intptr_t)p < SOC_RTC_DRAM_HIGH);
}
inline static bool IRAM_ATTR esp_ptr_in_rtc_slow(const void *p) {
return ((intptr_t)p >= SOC_RTC_DATA_LOW && (intptr_t)p < SOC_RTC_DATA_HIGH);
}
/* Convert a D/IRAM DRAM pointer to equivalent word address in IRAM
- Address must be word aligned
- Address must pass esp_ptr_in_diram_dram() test, or result will be invalid pointer
*/
inline static void * IRAM_ATTR esp_ptr_diram_dram_to_iram(const void *p) {
#if SOC_DIRAM_INVERTED
return (void *) ( SOC_DIRAM_IRAM_LOW + (SOC_DIRAM_DRAM_HIGH - (intptr_t)p) - 4);
#else
return (void *) ( SOC_DIRAM_IRAM_LOW + ((intptr_t)p - SOC_DIRAM_DRAM_LOW) );
#endif
}
/* Convert a D/IRAM IRAM pointer to equivalent word address in DRAM
- Address must be word aligned
- Address must pass esp_ptr_in_diram_iram() test, or result will be invalid pointer
*/
inline static void * IRAM_ATTR esp_ptr_diram_iram_to_dram(const void *p) {
#if SOC_DIRAM_INVERTED
return (void *) ( SOC_DIRAM_DRAM_LOW + (SOC_DIRAM_IRAM_HIGH - (intptr_t)p) - 4);
#else
return (void *) ( SOC_DIRAM_DRAM_LOW + ((intptr_t)p - SOC_DIRAM_IRAM_LOW) );
#endif
}
inline static bool IRAM_ATTR esp_stack_ptr_is_sane(uint32_t sp)
{
//Check if stack ptr is in between SOC_DRAM_LOW and SOC_DRAM_HIGH, and 16 byte aligned.
return !(sp < SOC_DRAM_LOW + 0x10 || sp > SOC_DRAM_HIGH - 0x10 || ((sp & 0xF) != 0));
}

View file

@ -277,6 +277,9 @@
#define SOC_MEM_INTERNAL_LOW 0x3FF90000
#define SOC_MEM_INTERNAL_HIGH 0x400C2000
// Start (highest address) of ROM boot stack, only relevant during early boot
#define SOC_ROM_STACK_START 0x3ffe3f20
//Interrupt hardware source table
//This table is decided by hardware, don't touch this.
#define ETS_WIFI_MAC_INTR_SOURCE 0/**< interrupt of WiFi MAC, level*/

View file

@ -283,6 +283,9 @@
#define SOC_MEM_INTERNAL_LOW 0x3FF9E000
#define SOC_MEM_INTERNAL_HIGH 0x40072000
// Start (highest address) of ROM boot stack, only relevant during early boot
#define SOC_ROM_STACK_START 0x3fffe70c
//interrupt cpu using table, Please see the core-isa.h
/*************************************************************************************************************
* Intr num Level Type PRO CPU usage APP CPU uasge

View file

@ -147,6 +147,8 @@ def update_exclude_patterns(tags):
'api-reference/protocols/esp_serial_slave_link.rst',
'api-reference/system/ipc.rst',
'get-started-legacy/**',
'security/secure-boot-v1.rst',
'security/secure-boot-v2.rst',
'gnu-make-legacy.rst',
'hw-reference/esp32/**',
]:

View file

@ -57,7 +57,7 @@ After the GPIO input is deactivated and the device reboots, the normally configu
Fast boot from Deep Sleep
-------------------------
The bootloader has the :ref:`CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP` option which allows to reduce the wake-up time (useful to reduce consumption). This option is available when the :ref:`CONFIG_SECURE_BOOT_ENABLED` option is disabled. Reduction of time is achieved due to the lack of image verification. During the first boot, the bootloader stores the address of the application being launched in the RTC FAST memory. And during the awakening, this address is used for booting without any checks, thus fast loading is achieved.
The bootloader has the :ref:`CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP` option which allows to reduce the wake-up time (useful to reduce consumption). This option is available when the :ref:`CONFIG_SECURE_BOOT` option is disabled. Reduction of time is achieved due to the lack of image verification. During the first boot, the bootloader stores the address of the application being launched in the RTC FAST memory. And during the awakening, this address is used for booting without any checks, thus fast loading is achieved.
Customer bootloader
---------------------

View file

@ -28,7 +28,8 @@ API Guides
Partition Tables <partition-tables>
:esp32: RF Calibration <RF_calibration>
ROM debug console <romconsole>
Secure Boot <../security/secure-boot>
:esp32: Secure Boot <../security/secure-boot-v1>
:esp32: Secure Boot V2 <../security/secure-boot-v2>
Thread Local Storage <thread-local-storage>
Tools <tools/index>
ULP Coprocessor <ulp>

View file

@ -265,4 +265,4 @@ More information can be obtained by specifying `--help` as argument:
parttool.py [subcommand] --help
.. _secure boot: security/secure-boot.rst
.. _secure boot: security/secure-boot-v1.rst

View file

@ -62,7 +62,7 @@ For more details on the type of memory segments and their address ranges, see th
3. The image has a single checksum byte after the last segment. This byte is written on a sixteen byte padded boundary, so the application image might need padding.
4. If the ``hash_appended`` field from :cpp:type:`esp_image_header_t` is set then a SHA256 checksum will be appended. The value of SHA256 is calculated on the range from first byte and up to this field. The length of this field is 32 bytes.
5. If the options :ref:`CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT` or :ref:`CONFIG_SECURE_BOOT_ENABLED` are enabled then the application image will have additional 68 bytes for an ECDSA signature, which includes:
5. If the options :ref:`CONFIG_SECURE_SIGNED_APPS_SCHEME` is set to ECDSA then the application image will have additional 68 bytes for an ECDSA signature, which includes:
* version word (4 bytes),
* signature data (64 bytes).

View file

@ -29,10 +29,12 @@ Application Example
return ESP_OK;
}
Signature Verification
----------------------
.. only:: esp32
For additional security, signature of OTA firmware images can be verified. For that, refer :ref:`secure-ota-updates`
Signature Verification
----------------------
For additional security, signature of OTA firmware images can be verified. For that, refer :ref:`secure-ota-updates`
API Reference
-------------

View file

@ -194,14 +194,16 @@ Restrictions:
- In ESP32 it is stored in efuse ``EFUSE_BLK3_RDATA4_REG``. (when a eFuse bit is programmed to 1, it can never be reverted to 0). The number of bits set in this register is the ``security_version`` from app.
.. _secure-ota-updates:
.. only:: esp32
Secure OTA Updates Without Secure boot
--------------------------------------
.. _secure-ota-updates:
The verification of signed OTA updates can be performed even without enabling hardware secure boot. For doing so, refer :ref:`signed-app-verify`
Secure OTA Updates Without Secure boot
--------------------------------------
The verification of signed OTA updates can be performed even without enabling hardware secure boot. For doing so, refer :ref:`signed-app-verify`
OTA Tool (otatool.py)
---------------------

View file

@ -25,7 +25,9 @@ With flash encryption enabled, following kinds of flash data are encrypted by de
- Secure boot bootloader digest (if secure boot is enabled)
- Any partition marked with the "encrypted" flag in the partition table
Flash encryption is separate from the :doc:`Secure Boot <secure-boot>` feature, and you can use flash encryption without enabling secure boot. However, for a secure environment both should be used simultaneously.
.. only:: esp32
Flash encryption is separate from the :doc:`Secure Boot <secure-boot-v2>` feature, and you can use flash encryption without enabling secure boot. However, for a secure environment both should be used simultaneously.
.. important::
For production use, flash encryption should be enabled in the "Release" mode only.
@ -130,7 +132,9 @@ As mentioned above :ref:`flash_enc_development_mode` allows user to download as
- Select appropriate Bootloader log verbosity under Bootloader config.
- Update to the partition table offset may be required since after enabling flash encryption the size of bootloader is increased. See :ref:`secure-boot-bootloader-size`
.. only:: esp32
- Update to the partition table offset may be required since after enabling flash encryption the size of bootloader is increased. See :ref:`secure-boot-bootloader-size`
- Save the configuration and exit.
@ -326,7 +330,9 @@ It is possible to pregenerate the flash encryption key on the host computer and
- Select appropriate Bootloader log verbosity under Bootloader config.
- Update to the partition table offset may be required since after enabling flash encryption the size of bootloader is increased. See :ref:`secure-boot-bootloader-size`
.. only:: esp32
- Update to the partition table offset may be required since after enabling flash encryption the size of bootloader is increased. See :ref:`secure-boot-bootloader-size`
- Save the configuration and exit.
@ -364,7 +370,9 @@ In Release mode UART bootloader can not perform flash encryption operations and
- Select appropriate Bootloader log verbosity under Bootloader config.
- Update to the partition table offset may be required since after enabling flash encryption the size of bootloader is increased. See :ref:`secure-boot-bootloader-size`
.. only:: esp32
- Update to the partition table offset may be required since after enabling flash encryption the size of bootloader is increased. See :ref:`secure-boot-bootloader-size`
- Save the configuration and exit.
@ -487,7 +495,9 @@ Key Points About Flash Encryption
- If secure boot is enabled, reflashing the bootloader of an encrypted device requires a "Reflashable" secure boot digest (see :ref:`flash-encryption-and-secure-boot`).
.. note:: The bootloader app binary ``bootloader.bin`` may become too large when both secure boot and flash encryption are enabled. See :ref:`secure-boot-bootloader-size`.
.. only:: esp32
.. note:: The bootloader app binary ``bootloader.bin`` may become too large when both secure boot and flash encryption are enabled. See :ref:`secure-boot-bootloader-size`.
.. important::
Do not interrupt power to the {IDF_TARGET_NAME} while the first boot encryption pass is running. If power is interrupted, the flash contents will be corrupted and require flashing with unencrypted data again. A reflash like this will not count towards the flashing limit.
@ -587,7 +597,9 @@ Flash encryption prevents plaintext readout of the encrypted flash, to protect f
- For the same reason, an attacker can always tell when a pair of adjacent 16 byte blocks (32 byte aligned) contain two identical 16 byte sequences. Keep this in mind if storing sensitive data on the flash, design your flash storage so this doesn't happen (using a counter byte or some other non-identical value every 16 bytes is sufficient). :ref:`NVS Encryption <nvs_encryption>` deals with this and is suitable for many uses.
- Flash encryption alone may not prevent an attacker from modifying the firmware of the device. To prevent unauthorised firmware from running on the device, use flash encryption in combination with :doc:`Secure Boot <secure-boot>`.
.. only:: esp32
- Flash encryption alone may not prevent an attacker from modifying the firmware of the device. To prevent unauthorised firmware from running on the device, use flash encryption in combination with :doc:`Secure Boot <secure-boot-v2>`.
.. _flash-encryption-and-secure-boot:
@ -597,8 +609,12 @@ Flash Encryption and Secure Boot
It is recommended to use flash encryption and secure boot together. However, if Secure Boot is enabled then additional restrictions apply to reflashing the device:
- :ref:`updating-encrypted-flash-ota` are not restricted (provided the new app is signed correctly with the Secure Boot signing key).
- :ref:`Plaintext serial flash updates <updating-encrypted-flash-serial>` are only possible if the :ref:`Reflashable <CONFIG_SECURE_BOOTLOADER_MODE>` Secure Boot mode is selected and a Secure Boot key was pre-generated and burned to the {IDF_TARGET_NAME} (refer to :ref:`Secure Boot <secure-boot-reflashable>` docs.). In this configuration, ``idf.py bootloader`` will produce a pre-digested bootloader and secure boot digest file for flashing at offset 0x0. When following the plaintext serial reflashing steps it is necessary to re-flash this file before flashing other plaintext data.
- :ref:`Reflashing via Pregenerated Flash Encryption Key <pregenerated-flash-encryption-key>` is still possible, provided the bootloader is not reflashed. Reflashing the bootloader requires the same :ref:`Reflashable <CONFIG_SECURE_BOOTLOADER_MODE>` option to be enabled in the Secure Boot config.
.. only:: esp32
- :ref:`Plaintext serial flash updates <updating-encrypted-flash-serial>` are only possible if the :ref:`Reflashable <CONFIG_SECURE_BOOTLOADER_MODE>` Secure Boot mode is selected and a Secure Boot key was pre-generated and burned to the {IDF_TARGET_NAME} (refer to :ref:`Secure Boot <secure-boot-reflashable>` docs.). In this configuration, ``idf.py bootloader`` will produce a pre-digested bootloader and secure boot digest file for flashing at offset 0x0. When following the plaintext serial reflashing steps it is necessary to re-flash this file before flashing other plaintext data.
- :ref:`Reflashing via Pregenerated Flash Encryption Key <pregenerated-flash-encryption-key>` is still possible, provided the bootloader is not reflashed. Reflashing the bootloader requires the same :ref:`Reflashable <CONFIG_SECURE_BOOTLOADER_MODE>` option to be enabled in the Secure Boot config.
.. _flash-encryption-advanced-features:

View file

@ -1,6 +1,11 @@
Secure Boot
===========
.. important::
All references in this document are related to Secure Boot V1 (The AES based Secure Boot Scheme). ESP32 Revision 3 onwards, the preferred secure boot scheme is :doc:`Secure Boot V2 <secure-boot-v2>`.
Please refer to Secure Boot V2 document for ESP32 Revision 3 or ESP32S2.
Secure Boot is a feature for ensuring only your code can run on the chip. Data loaded from flash is verified on each reset.
Secure Boot is separate from the :doc:`Flash Encryption <flash-encryption>` feature, and you can use secure boot without encrypting the flash contents. However, for a secure environment both should be used simultaneously. See :ref:`secure-boot-and-flash-encr` for more details.
@ -133,7 +138,7 @@ In the esp-idf build process, this 256-bit key file is derived from the ECDSA ap
To enable a reflashable bootloader:
1. In the :ref:`project-configuration-menu`, select "Bootloader Config" -> :ref:`CONFIG_SECURE_BOOT_ENABLED` -> :ref:`CONFIG_SECURE_BOOTLOADER_MODE` -> Reflashable.
1. In the :ref:`project-configuration-menu`, select "Bootloader Config" -> :ref:`CONFIG_SECURE_BOOT` -> CONFIG_SECURE_BOOT_V1_ENABLED -> :ref:`CONFIG_SECURE_BOOTLOADER_MODE` -> Reflashable.
2. If necessary, set the :ref:`CONFIG_SECURE_BOOTLOADER_KEY_ENCODING` based on the coding scheme used by the device. The coding scheme is shown in the ``Features`` line when ``esptool.py`` connects to the chip, or in the ``espefuse.py summary`` output.

View file

@ -0,0 +1,239 @@
Secure Boot V2
==============
.. important::
The references in this document are related to Secure Boot v2, the preferred scheme from ESP32-ECO3 onwards and in ESP32S2. (Refer to :doc:`Secure Boot <secure-boot-v1>` for ESP32)
Secure Boot V2 uses RSA based app and bootloader verification. This document can also be referred for signing apps with the RSA scheme without signing the bootloader.
Background
----------
Secure Boot protects a device from running unsigned code (verification at time of load). A new RSA based secure boot
verification scheme (Secure Boot V2) has been introduced for ESP32S2 and ESP32 ECO3 onwards.
- The software bootloaders RSA-PSS signature is verified by the Mask ROM and it is executed post successful verification.
- The verified software bootloader verifies the RSA-PSS signature of the application image before it is executed.
Advantages
----------
- The RSA public key is stored on the device. The corresponding RSA private key is kept secret on a server and is never accessed by the device.
- Upto three public keys can store can be generated and stored in ESP32S2 during manufacturing. (ESP32 ECO3: only one key)
- ESP32S2 also provides the facility to revoke individual public keys.
- Same image format & signature verification is applied for applications & software bootloader.
- No secrets are stored on the device. Therefore immune to passive side-channel attacks (timing or power analysis, etc.)
Secure Boot V2 Process
----------------------
This is an overview of the Secure Boot V2 Process, Step by step instructions are supplied under :ref:`secure-boot-v2-howto`.
1. Secure Boot V2 verifies the signature blocks appended to the bootloader and application binaries. The signature block contains the image binary signed by a RSA-3072 private key and its corresponding public key. More details on the :ref:`signature-block-format`.
2. On startup, ROM code checks the secure boot v2 bit in eFuse.
3. If secure boot is enabled, ROM checks the SHA-256 of the public key in the signature block in the eFuse.
4. The ROM code validates the public key embedded in the software bootloader's signature block by matching the SHA-256 of its public key to the SHA-256 in eFuse as per the earlier step. Boot process will be aborted if a valid hash of the public key isnt found in the eFuse.
5. The ROM code verifies the signature of the bootloader with the pre-validated public key with the RSA-PSS Scheme. In depth information on :ref:`verify_signature-block`.
6. Software bootloader, reads the app partition and performs similar verification on the application. The application is verified on every boot up and OTA update. If selected OTA app partition fails verification, bootloader will fall back and look for another correctly signed partition.
.. _signature-block-format:
Signature Block Format
----------------------
The bootloader and application images are padded to the next 4096 byte boundary, thus the signature has a flash sector of its own. The signature is calculated over all bytes in the image including the padding bytes.
Each signature block contains the following:
* **Offset 0 (1 byte):** Magic byte (0xe7)
* **Offset 1 (1 byte):** Version number byte (currently 0x02), 0x01 is for Secure Boot V1.
* **Offset 2 (2 bytes):** Padding bytes, Reserved. Should be zero.
* **Offset 4 (32 bytes):** SHA-256 hash of only the image content, not including the signature block.
* **Offset 36 (384 bytes):** RSA Public Modulus used for signature verification. (value n in RFC8017).
* **Offset 420 (4 bytes):** RSA Public Exponent used for signature verification (value e in RFC8017).
* **Offset 424 (384 bytes):** Precalculated R, derived from n.
* **Offset 808 (4 bytes):** Precalculated M, derived from n
* **Offset 812 (384 bytes):** RSA-PSS Signature result (section 8.1.1 of RFC8017) of image content, computed using following PSS parameters: SHA256 hash, MFG1 function, 0 length salt, default trailer field (0xBC).
* **Offset 1196:** CRC32 of the preceding 1095 bytes.
* **Offset 1200 (16 bytes):** Zero padding to length 1216 bytes.
.. note::
R and M' are used for hardware-assisted Montgomery Multiplication.
The remainder of the signature sector is erased flash (0xFF) which allows writing other signature blocks after previous signature block.
.. _verify_signature-block:
Verifying the signature Block
-----------------------------
A signature block is “valid” if the first byte is 0xe7 and a valid CRC32 is stored at offset 1196. Upto 3 signature blocks can be appended to the bootloader or application image in ESP32S2. (ESP32 ECO3: only one key)
An image is “verified” if the public key stored in any signature block is valid for this device, and if the stored signature is valid for the image data read from flash.
1. The magic byte, signature block CRC is validated.
2. Public key digests are generated per signature block and compared with the digests from eFuse. If none of the digests match, the verification process is aborted.
3. The application image digest is generated and matched with the image digest in the signature blocks. The verification process is aborted is the digests don't match.
4. The public key is used to verify the signature of the bootloader image, using RSA-PSS (section 8.1.2 of RFC8017) with the image digest calculated in step (3) for comparison.
- The application signing scheme is set to RSA for secure boot V2 and to ECDSA for secure boot V1.
.. important::
It is recommended to use secure boot V2 on the chip versions supporting them.
.. _secure-boot-v2-bootloader-size:
Bootloader Size
---------------
When secure boot is enabled the bootloader app binary ``bootloader.bin`` may exceed the default bootloader size limit. This is especially likely if flash encryption is enabled as well. The default size limit is 0x7000 (28672) bytes (partition table offset 0x8000 - bootloader offset 0x1000).
If the bootloader becomes too large, the ESP32 will fail to boot - errors will be logged about either invalid partition table or invalid bootloader checksum.
Options to work around this are:
- Reduce :ref:`bootloader log level <CONFIG_BOOTLOADER_LOG_LEVEL>`. Setting log level to Warning, Error or None all significantly reduce the final binary size (but may make it harder to debug).
- Set :ref:`partition table offset <CONFIG_PARTITION_TABLE_OFFSET>` to a higher value than 0x8000, to place the partition table later in the flash. This increases the space available for the bootloader. If the :doc:`partition table </api-guides/partition-tables>` CSV file contains explicit partition offsets, they will need changing so no partition has an offset lower than ``CONFIG_PARTITION_TABLE_OFFSET + 0x1000``. (This includes the default partition CSV files supplied with ESP-IDF.)
.. _efuse-usage:
eFuse usage
-----------
ESP32-ECO3:
- ABS_DONE_1 - Enables secure boot protection on boot.
- BLK2 - Stores the SHA-256 digest of the public key. SHA-256 hash of public key modulus, exponent, precalculated R & M values (represented as 776 bytes offsets 36 to 812 - as per the :ref:`signature-block-format`) is written to an eFuse key block.
.. _secure-boot-v2-howto:
How To Enable Secure Boot V2
----------------------------
1. Open the :ref:`project-configuration-menu`, in "Security Features" set "Enable hardware Secure Boot in bootloader" to enable Secure Boot. The chip revision should be changed to revision 3(ESP32- ECO3) to view the Secure Boot V2 option.
2. To change the chip revision, set "Minimum Supported ESP32 Revision" to Rev 3 in "Component Config" -> "ESP32- Specific", the Secure Boot V2 option can be enabled under "Enable hardware Secure Boot in bootloader" -> "Secure Boot Version". Secure Boot V2 is available for ESP32 ECO3 onwards and in ESP32S2.
3. Specify the secure boot signing key path. The file can be anywhere on your system. A relative path will be evaluated from the project directory. The file does not need to exist yet.
4. Set other menuconfig options (as desired). Pay particular attention to the "Bootloader Config" options, as you can only flash the bootloader once. Then exit menuconfig and save your configuration
5. The first time you run ``make`` or ``idf.py build``, if the signing key is not found then an error message will be printed with a command to generate a signing key via ``espsecure.py generate_signing_key``.
.. important::
A signing key generated this way will use the best random number source available to the OS and its Python installation (`/dev/urandom` on OSX/Linux and `CryptGenRandom()` on Windows). If this random number source is weak, then the private key will be weak.
.. important::
For production environments, we recommend generating the keypair using openssl or another industry standard encryption program. See :ref:`secure-boot-v2-generate-key` for more details.
6. Run ``idf.py bootloader`` to build a secure boot enabled bootloader. The build output will include a prompt for a flashing command, using ``esptool.py write_flash``.
7. When you're ready to flash the bootloader, run the specified command (you have to enter it yourself, this step is not performed by the build system) and then wait for flashing to complete.
8. Run ``idf.py flash`` to build and flash the partition table and the just-built app image. The app image will be signed using the signing key you generated in step 4.
.. note:: ``idf.py flash`` doesn't flash the bootloader if secure boot is enabled.
9. Reset the ESP32 and it will boot the software bootloader you flashed. The software bootloader will enable secure boot on the chip, and then it verifies the app image signature and boots the app. You should watch the serial console output from the ESP32 to verify that secure boot is enabled and no errors have occurred due to the build configuration.
.. note:: Secure boot won't be enabled until after a valid partition table and app image have been flashed. This is to prevent accidents before the system is fully configured.
.. note:: If the ESP32 is reset or powered down during the first boot, it will start the process again on the next boot.
10. On subsequent boots, the secure boot hardware will verify the software bootloader has not changed and the software bootloader will verify the signed app image (using the validated public key portion of its appended signature block).
.. _secure-boot-v2-generate-key:
Generating Secure Boot Signing Key
----------------------------------
The build system will prompt you with a command to generate a new signing key via ``espsecure.py generate_signing_key``. The --version 2 parameter will generate the RSA 3072 private key for Secure Boot V2.
The strength of the signing key is proportional to (a) the random number source of the system, and (b) the correctness of the algorithm used. For production devices, we recommend generating signing keys from a system with a quality entropy source, and using the best available RSA key generation utilities.
For example, to generate a signing key using the openssl command line:
```
openssl genrsa -out my_secure_boot_signing_key.pem 3072
```
Remember that the strength of the secure boot system depends on keeping the signing key private.
.. _remote-sign-v2-image:
Remote Signing of Images
------------------------
For production builds, it can be good practice to use a remote signing server rather than have the signing key on the build machine (which is the default esp-idf secure boot configuration). The espsecure.py command line program can be used to sign app images & partition table data for secure boot, on a remote system.
To use remote signing, disable the option "Sign binaries during build". The private signing key does not need to be present on the build system.
After the app image and partition table are built, the build system will print signing steps using espsecure.py::
espsecure.py sign_data --version 2 --keyfile PRIVATE_SIGNING_KEY BINARY_FILE
The above command appends the image signature to the existing binary. You can use the `--output` argument to write the signed binary to a separate file::
espsecure.py sign_data --version 2 --keyfile PRIVATE_SIGNING_KEY --output SIGNED_BINARY_FILE BINARY_FILE
Secure Boot Best Practices
--------------------------
* Generate the signing key on a system with a quality source of entropy.
* Keep the signing key private at all times. A leak of this key will compromise the secure boot system.
* Do not allow any third party to observe any aspects of the key generation or signing process using espsecure.py. Both processes are vulnerable to timing or other side-channel attacks.
* Enable all secure boot options in the Secure Boot Configuration. These include flash encryption, disabling of JTAG, disabling BASIC ROM interpeter, and disabling the UART bootloader encrypted flash access.
* Use secure boot in combination with :doc:`flash encryption<flash-encryption>` to prevent local readout of the flash contents.
.. _secure-boot-v2-technical-details:
Technical Details
-----------------
The following sections contain low-level reference descriptions of various secure boot elements:
Manual Commands
~~~~~~~~~~~~~~~
Secure boot is integrated into the esp-idf build system, so ``make`` or ``idf.py build`` will sign an app image and ``idf.py bootloader`` will produce a signed bootloader if secure signed binaries on build is enabled.
However, it is possible to use the ``espsecure.py`` tool to make standalone signatures and digests.
To sign a binary image::
espsecure.py sign_data --version 2 --keyfile ./my_signing_key.pem --output ./image_signed.bin image-unsigned.bin
Keyfile is the PEM file containing an RSA-3072 private signing key.
.. _secure-boot-v2-and-flash-encr:
Secure Boot & Flash Encryption
------------------------------
If secure boot is used without :doc:`Flash Encryption <flash-encryption>`, it is possible to launch "time-of-check to time-of-use" attack, where flash contents are swapped after the image is verified and running. Therefore, it is recommended to use both the features together.

View file

@ -50,4 +50,7 @@ api-guide/build-system-cmake api-guide/build-system
api-guide/ulp-cmake api-guide/ulp
api-guide/unit-tests-cmake api-guide/unit-tests
api-reference/network/tcpip_adapter api-reference/network/esp_netif
api-reference/network/tcpip_adapter api-reference/network/esp_netif
# The 'secure boot' guides are now 'secure boot v1' guides
security/secure-boot.rst security/secure-boot-v1.rst

View file

@ -20,7 +20,8 @@ API 指南
JTAG 调试 <jtag-debugging/index>
引导加载程序 <bootloader>
分区表 <partition-tables>
Secure Boot <../security/secure-boot>
:esp32: Secure Boot <../security/secure-boot-v1>
:esp32: Secure Boot V2 <../security/secure-boot-v2>
ULP 协处理器 <ulp>
:esp32: ULP (传统 GNU Make) <ulp-legacy>
单元测试 <unit-tests>

View file

@ -7,7 +7,9 @@
每片 {IDF_TARGET_NAME} 的 flash 可以包含多个应用程序,以及多种不同类型的数据(例如校准数据、文件系统数据、参数存储器数据等)。因此,我们需要引入分区表的概念。
具体来说,{IDF_TARGET_NAME} 在 flash 的 :ref:`默认偏移地址 <CONFIG_PARTITION_TABLE_OFFSET>` 0x8000 处烧写一张分区表。该分区表的长度为 0xC00 字节(最多可以保存 95 条分区表条目)。分区表数据后还保存着该表的 MD5 校验和,用于验证分区表的完整性。此外,如果芯片使能了 :doc:`安全启动 </security/secure-boot>` 功能,则该分区表后还会保存签名信息。
.. only:: esp32
具体来说,{IDF_TARGET_NAME} 在 flash 的 :ref:`默认偏移地址 <CONFIG_PARTITION_TABLE_OFFSET>` 0x8000 处烧写一张分区表。该分区表的长度为 0xC00 字节(最多可以保存 95 条分区表条目)。分区表数据后还保存着该表的 MD5 校验和,用于验证分区表的完整性。此外,如果芯片使能了 :doc:`安全启动 </security/secure-boot-v2>` 功能,则该分区表后还会保存签名信息。
分区表中的每个条目都包括以下几个部分Name标签、Typeapp、data 等、SubType 以及在 flash 中的偏移量(分区的加载地址)。
@ -175,4 +177,4 @@ MD5 校验和
分区表的更新并不会擦除根据之前分区表存储的数据。此时,您可以使用 ``idf.py erase_flash`` 命令或者 ``esptool.py erase_flash`` 命令来擦除 flash 中的所有内容。
.. _secure boot: security/secure-boot.rst
.. _secure boot: security/secure-boot-v1.rst

View file

@ -24,7 +24,9 @@ Flash 加密功能用于加密与 {IDF_TARGET_NAME} 搭载使用的 SPI Flash
- 安全启动引导加载程序摘要(如果已启用安全启动)
- 分区表中标有“加密”标记的分区
Flash 加密与 :doc:`安全启动<secure-boot>` 功能各自独立,您可以在关闭安全启动的状态下使用 Flash 加密。但是,为了安全的计算机环境,二者应同时使用。在关闭安全启动的状态下,需运行其他配置来确保 Flash 加密的有效性。详细信息可参见 :ref:`flash-encryption-without-secure-boot`
.. only:: esp32
Flash 加密与 :doc:`安全启动<secure-boot-v2>` 功能各自独立,您可以在关闭安全启动的状态下使用 Flash 加密。但是,为了安全的计算机环境,二者应同时使用。在关闭安全启动的状态下,需运行其他配置来确保 Flash 加密的有效性。详细信息可参见 :ref:`flash-encryption-without-secure-boot`
.. important::
启用 Flash 加密将限制后续 {IDF_TARGET_NAME} 更新。请务必阅读本文档(包括 :ref:`flash-encryption-limitations`)了解启用 Flash 加密的影响。
@ -116,7 +118,9 @@ Flash 的加密过程
- 在引导加载程序 config 下选择适当详细程度的日志。
- 启用 Flash 加密将增大引导加载程序,因而可能需更新分区表偏移。请参见 :ref:`secure-boot-bootloader-size`
.. only:: esp32
- 启用 Flash 加密将增大引导加载程序,因而可能需更新分区表偏移。请参见 :ref:`secure-boot-bootloader-size`
- 保存配置并退出。
@ -310,7 +314,9 @@ Flash 的加密过程
- 在引导加载程序 config 下选择适当详细程度的日志。
- 启用 Flash 加密将增大引导加载程序,因而可能需要更新分区表偏移。可参见 See :ref:`secure-boot-bootloader-size`
.. only:: esp32
- 启用 Flash 加密将增大引导加载程序,因而可能需要更新分区表偏移。可参见 See :ref:`secure-boot-bootloader-size`
- 保存配置并退出。
@ -347,7 +353,9 @@ Flash 的加密过程
- 在引导加载程序 config 下选择适当详细程度的日志。
- 启用 Flash 加密将增大引导加载程序,因而可能需要更新分区表偏移。可参见 See :ref:`secure-boot-bootloader-size`
.. only:: esp32
- 启用 Flash 加密将增大引导加载程序,因而可能需要更新分区表偏移。可参见 See :ref:`secure-boot-bootloader-size`
- 保存配置并退出。
@ -467,7 +475,9 @@ Flash 加密的要点
- 如果已启用安全启动,则重新烧录加密设备的引导加载程序则需要“可重新烧录”的安全启动摘要(可参见 :ref:`flash-encryption-and-secure-boot`)。
.. note:: 同时启用安全启动和 Flash 加密后,引导加载程序 app 二进制文件 ``bootloader.bin`` 可能会过大。参见 :ref:`secure-boot-bootloader-size`
.. only:: esp32
.. note:: 同时启用安全启动和 Flash 加密后,引导加载程序 app 二进制文件 ``bootloader.bin`` 可能会过大。参见 :ref:`secure-boot-bootloader-size`
.. important::
在首次启动加密过程中,请勿中断 {IDF_TARGET_NAME} 的电源。如果电源中断Flash 的内容将受到破坏,并需要重新烧录未加密数据。而这类重新烧录将不计入烧录限制次数。
@ -562,7 +572,9 @@ Flash 加密可防止从加密 Flash 中读取明文,从而保护固件防止
- 出于相同原因,攻击者始终可获知一对相邻的 16 字节块32 字节对齐)何时包含相同内容。因此,在 Flash 上存储敏感数据时应牢记这点,并进行相关设置避免该情况发生(可使用计数器字节或每 16 字节设置不同的值即可)。
- 单独使用 Flash 加密可能无法防止攻击者修改本设备的固件。为防止设备上运行未经授权的固件,可搭配 Flash 加密使用 :doc:`安全启动 <secure-boot>`
.. only:: esp32
- 单独使用 Flash 加密可能无法防止攻击者修改本设备的固件。为防止设备上运行未经授权的固件,可搭配 Flash 加密使用 :doc:`安全启动 <secure-boot-v2>`
.. _flash-encryption-and-secure-boot:
@ -572,8 +584,12 @@ Flash 加密与安全启动
推荐搭配使用 Flash 加密与安全启动。但是,如果已启用安全启动,则重新烧录设备时会受到其他限制:
- :ref:`updating-encrypted-flash-ota` 不受限制(如果新的 app 已使用安全启动签名密钥进行正确签名)。
- 只有当选择 :ref:`可再次烧录 <CONFIG_SECURE_BOOTLOADER_MODE>` 安全启动模式,且安全启动密钥已预生成并烧录至 {IDF_TARGET_NAME}(可参见 :ref:`安全启动 <secure-boot-reflashable>`),则 :ref:`明文串行 flash 更新 <updating-encrypted-flash-serial>` 可实现。在该配置下,``idf.py bootloader`` 将生成简化的引导加载程序和安全启动摘要文件,用于在偏移量 0x0 处进行烧录。当进行明文串行重新烧录步骤时,须在烧录其他明文数据前重新烧录此文件。
- 假设未重新烧录引导加载程序,:ref:`使用预生成的 Flash 加密密钥重新烧录 <pregenerated-flash-encryption-key>` 仍可实现。重新烧录引导加载程序时,需在安全启动配置中启用相同的 :ref:`可重新烧录 <CONFIG_SECURE_BOOTLOADER_MODE>` 选项。
.. only:: esp32
- 只有当选择 :ref:`可再次烧录 <CONFIG_SECURE_BOOTLOADER_MODE>` 安全启动模式,且安全启动密钥已预生成并烧录至 {IDF_TARGET_NAME}(可参见 :ref:`安全启动 <secure-boot-reflashable>`),则 :ref:`明文串行 flash 更新 <updating-encrypted-flash-serial>` 可实现。在该配置下,``idf.py bootloader`` 将生成简化的引导加载程序和安全启动摘要文件,用于在偏移量 0x0 处进行烧录。当进行明文串行重新烧录步骤时,须在烧录其他明文数据前重新烧录此文件。
- 假设未重新烧录引导加载程序,:ref:`使用预生成的 Flash 加密密钥重新烧录 <pregenerated-flash-encryption-key>` 仍可实现。重新烧录引导加载程序时,需在安全启动配置中启用相同的 :ref:`可重新烧录 <CONFIG_SECURE_BOOTLOADER_MODE>` 选项。
.. _flash-encryption-without-secure-boot:

View file

@ -0,0 +1 @@
.. include:: ../../en/security/secure-boot-v1.rst

View file

@ -0,0 +1 @@
.. include:: ../../en/security/secure-boot-v2.rst

View file

@ -1 +0,0 @@
.. include:: ../../en/security/secure-boot.rst

View file

@ -311,12 +311,17 @@ COMPONENT_INCLUDES += $(abspath $(BUILD_DIR_BASE)/include/)
export COMPONENT_INCLUDES
all:
ifdef CONFIG_SECURE_BOOT_ENABLED
ifdef CONFIG_SECURE_BOOT
@echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)"
ifndef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
ifdef SECURE_SIGNED_APPS_ECDSA_SCHEME
@echo "App built but not signed. Sign app & partition data before flashing, via espsecure.py:"
@echo "espsecure.py sign_data --keyfile KEYFILE $(APP_BIN)"
@echo "espsecure.py sign_data --keyfile KEYFILE $(PARTITION_TABLE_BIN)"
@echo "espsecure.py sign_data --version 1 --keyfile KEYFILE $(APP_BIN)"
@echo "espsecure.py sign_data --version 1 --keyfile KEYFILE $(PARTITION_TABLE_BIN)"
else
@echo "App built but not signed. Sign app & partition data before flashing, via espsecure.py:"
@echo "espsecure.py sign_data --version 2 --keyfile KEYFILE $(APP_BIN)"
endif
endif
@echo "To flash app & partition table, run 'make flash' or:"
else
@ -420,7 +425,6 @@ endif
ifdef CONFIG_COMPILER_STACK_CHECK_MODE_ALL
COMMON_FLAGS += -fstack-protector-all
endif
endif
# Optimization flags are set based on menuconfig choice
ifdef CONFIG_COMPILER_OPTIMIZATION_SIZE
@ -443,6 +447,27 @@ ifdef CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE
CPPFLAGS += -DNDEBUG
endif
else # IS_BOOTLOADER_BUILD
ifdef CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE
OPTIMIZATION_FLAGS = -Os -freorder-blocks
endif
ifdef CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG
OPTIMIZATION_FLAGS = -Og
endif
ifdef CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE
OPTIMIZATION_FLAGS = -O0
endif
ifdef CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF
OPTIMIZATION_FLAGS = -O2
endif
endif # IS_BOOTLOADER_BUILD
# IDF uses some GNU extension from libc
CPPFLAGS += -D_GNU_SOURCE
@ -538,11 +563,17 @@ $(APP_ELF): $(foreach libcomp,$(COMPONENT_LIBRARIES),$(BUILD_DIR_BASE)/$(libcomp
$(summary) LD $(patsubst $(PWD)/%,%,$@)
$(CC) $(LDFLAGS) -o $@ -Wl,-Map=$(APP_MAP)
ifdef CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
SECURE_APPS_SIGNING_SCHEME = "1"
else ifdef CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME
SECURE_APPS_SIGNING_SCHEME = "2"
endif
app: $(APP_BIN) partition_table_get_info
ifeq ("$(CONFIG_APP_BUILD_GENERATE_BINARIES)","y")
ifeq ("$(CONFIG_SECURE_BOOT_ENABLED)$(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)","y") # secure boot enabled, but remote sign app image
ifeq ("$(CONFIG_SECURE_BOOT)$(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)","y") # secure boot enabled, but remote sign app image
@echo "App built but not signed. Signing step via espsecure.py:"
@echo "espsecure.py sign_data --keyfile KEYFILE $(APP_BIN)"
@echo "espsecure.py sign_data --version $(SECURE_APPS_SIGNING_SCHEME) --keyfile KEYFILE $(APP_BIN)"
@echo "Then flash app command is:"
@echo $(ESPTOOLPY_WRITE_FLASH) $(APP_OFFSET) $(APP_BIN)
else

View file

@ -336,7 +336,7 @@ example_test_012:
UT_001:
extends: .unit_test_template
parallel: 34
parallel: 36
tags:
- ESP32_IDF
- UT_T1_1

View file

@ -21,7 +21,7 @@ CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y
#
# Security features
#
CONFIG_SECURE_BOOT_ENABLED=
CONFIG_SECURE_BOOT=
CONFIG_SECURE_FLASH_ENC_ENABLED=
#

View file

@ -23,6 +23,7 @@ The test apps should be grouped into subdirectories by category. Categories are:
* `protocols` contains test of protocol interactions.
* `network` contains system network tests
* `system` contains tests on the internal chip features, debugging and development tools.
* `security` contains tests on the chip security features.
# Test Apps local execution

View file

@ -0,0 +1,7 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(SUPPORTED_TARGETS esp32) # Secure Boot not currently supported for ESP32-S2beta
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(secure_boot)

View file

@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := secure_boot
include $(IDF_PATH)/make/project.mk

View file

@ -0,0 +1,53 @@
# Secure Boot
The example checks if the secure boot feature is enabled/disabled and if enabled prints the secure boot version (Version 1 / Version 2) and FLASH_CRYPT_CNT eFuse value.
## How to use example
### Hardware Required
ESP32 (supports Secure Boot V1) or ESP32-ECO3 (supports Secure Boot V2 & Secure Boot V1). It is recommended to use Secure Boot V2 from ESP32-ECO3 onwards.
### Configure the project
```
idf.py menuconfig
```
* Set serial port under Serial Flasher Options.
* Enable the `Enable hardware Secure Boot` under Security Features. Default version for ESP32 is Secure Boot V1. The chip revision should be changed to revision 3(ESP32- ECO3) to view the Secure Boot V2 option.
* To change the chip revision, set "Component Config" -> "ESP32- Specific"->"Minimum Supported ESP32 Revision" to Rev 3. Now, set Secure Boot V2 option can now be enabled under "Enable hardware Secure Boot in bootloader" -> "Secure Boot Version".
* Specify the apt secure boot signing key path. If not present generate one using `python $IDF_PATH/components/esptool_py/esptool/espsecure.py generate_signing_key --version {VERSION} secure_boot_signing_key.pem`
* Ensure Bootloader log verbosity is Info under Bootloader config.
* Select Single factory app, no OTA under Partition Table options. Change the partition table offset to 0xb000 from 0x8000 since after enabling secure boot the size of bootloader is increased.
### Build and Flash
- The below steps can be used in any application to enable secure boot.
- Secure Boot is an irreversible operation, please read the Secure Boot section in ESP-IDF Programming Manual.
- Secure boot will be enabled on building the project after enabling hardware secure boot feature in _Security features_ in menuconfig and flashing it to the board FOR THE FIRST TIME.
- The bootloader will not be automatically flashed when secure boot is enabled. Running `idf.py bootloader` will print a command to flash the bootloader on the ESP32. Run this command manually to flash the bootloader.
Run following command to program the partition table and application on the ESP32 and monitor the output:
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
- On subsequent boots, the secure boot hardware will verify the software bootloader has not changed and the software bootloader will verify the signed app image (using the validated public key portion of its appended signature block).
## Example Output
## Troubleshooting

View file

@ -0,0 +1,4 @@
set(COMPONENT_SRCS "secure_boot_main.c")
set(COMPONENT_ADD_INCLUDEDIRS "")
register_component()

View file

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View file

@ -0,0 +1,96 @@
/* Flash encryption Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "soc/efuse_reg.h"
#include "esp_efuse.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_log.h"
#include "esp_efuse_table.h"
#include <string.h>
static void example_print_chip_info(void);
static void example_secure_boot_status(void);
#define TAG "example_secure_boot"
void app_main(void)
{
printf("\nExample to check Secure Boot status\n");
example_print_chip_info();
example_secure_boot_status();
}
static void example_print_chip_info(void)
{
/* Print chip information */
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
printf("This is ESP32 chip with %d CPU cores, WiFi%s%s, ",
chip_info.cores,
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
printf("silicon revision %d, ", chip_info.revision);
printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
}
#define DIGEST_LEN 32
static void example_secure_boot_status(void)
{
uint32_t efuse_block0 = REG_READ(EFUSE_BLK0_RDATA6_REG);
#ifdef CONFIG_ESP32_REV_MIN_3
uint8_t efuse_trusted_digest[DIGEST_LEN] = {0}, i;
ESP_LOGI(TAG, "Checking for secure boot v2..");
if(efuse_block0 & EFUSE_RD_ABS_DONE_1) {
ESP_LOGI(TAG, "ABS_DONE_1 is set. Secure Boot V2 enabled");
memcpy(efuse_trusted_digest, (uint8_t *)EFUSE_BLK2_RDATA0_REG, DIGEST_LEN);
ESP_LOGI(TAG, "Reading the public key digest from BLK2.");
for (i = 0; i < DIGEST_LEN; i++) {
ESP_LOGI(TAG, "%02x \t", efuse_trusted_digest[i]);
}
return;
} else {
ESP_LOGI(TAG, "Secure boot v2 not enabled. Enable Secure Boot V2 in menuconfig, build & flash again.");
}
#endif
ESP_LOGI(TAG, "Checking for secure boot v1..");
uint32_t dis_reg = REG_READ(EFUSE_BLK0_RDATA0_REG);
if (efuse_block0 & EFUSE_RD_ABS_DONE_0) {
ESP_LOGI(TAG, "ABS_DONE_0 is set. Secure Boot V1 enabled");
#ifdef CONFIG_ESP32_REV_MIN_3
ESP_LOGW(TAG, "This chip version supports Secure Boot V2. It is recommended to use Secure Boot V2.");
#endif
bool efuse_key_read_protected = dis_reg & EFUSE_RD_DIS_BLK2;
bool efuse_key_write_protected = dis_reg & EFUSE_WR_DIS_BLK2;
ESP_LOGI(TAG, "Checking the integrityof the key in BLK2..");
if (!efuse_key_read_protected) {
ESP_LOGE(TAG, "Key is not read protected. Refusing to blow secure boot efuse.");
return;
}
if (!efuse_key_write_protected) {
ESP_LOGE(TAG, "Key is not write protected. Refusing to blow secure boot efuse.");
return;
}
ESP_LOGI(TAG, "Key is read/write protected in eFuse.");
return;
} else {
ESP_LOGI(TAG, "Secure Boot V1 not enabled. Enable Secure Boot in menuconfig, build & flash again.");
}
}

View file

@ -0,0 +1,6 @@
# Secure Boot V2 - ESP-ECO3+
CONFIG_SECURE_BOOT=y
CONFIG_ESP32_REV_MIN_3=y
CONFIG_SECURE_BOOT_V2_ENABLED=y
CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES=y
CONFIG_SECURE_BOOT_SIGNING_KEY="test_rsa_3072_key.pem"

View file

@ -0,0 +1,4 @@
# Secure Boot V1
CONFIG_SECURE_BOOT=y
CONFIG_SECURE_BOOT_V1_ENABLED=y
CONFIG_SECURE_BOOT_SIGNING_KEY="test_ecdsa_key.pem"

View file

@ -0,0 +1,4 @@
# ECDSA App signing without secure boot
CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT=y
CONFIG_SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT=y
CONFIG_SECURE_BOOT_SIGNING_KEY="test_ecdsa_key.pem"

View file

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIJLB2fFAa7istjO0AWfEbvJM8Kn0T+R38GXalwX3oP6GoAoGCCqGSM49
AwEHoUQDQgAEy2N3ohJ1hIjU2AHNyVKGafSrmGhizG1/xOTOtASbJpiVI3ccUVXI
zrDSnrTwg331qOAT7WWkY1p4ixZvP6HWzA==
-----END EC PRIVATE KEY-----

View file

@ -0,0 +1,39 @@
-----BEGIN RSA PRIVATE KEY-----
MIIG4gIBAAKCAYEA0rvS0tvQ4dF/mW62K2QAt13Wnlsd5NDRtZmCB94XaPWzV2D1
JDZw2M0PH+ylXvVsVN4Q4gjULwxHFO1ebnR3Ws61Se/x3KM4MoC0EjCvV21VfjFB
2sB/bark+2yHd5ChvikCfXWrIRYFkBTQLnZOJB7nVXY4XzHoZ+d9MLGfVcZoufDa
Uaj+3WmrgBzYifZ2dWHfAm1KQ+cVhFHiPEw75bX67ZcJyXb95vBRzylubOqWquWp
AML/ygKz/JP6SKCOihUUyIrC/lz9H3eduWnzaqsx6E/8Nv3vVv6A1y5UbzPLCP9a
j2G2I2DoqB4QlQic4GKjBwgMfQQPSka0h5pNYAyyiJKncnvgIweQKH7UY3cRLPWi
B37Q/E3J+bHdZzGHXReiyiSpmLlvRbohgPRnlsawjySqXCFrHicRF7wElnrLrzcc
iFWatWUK2Ky6ODWD/l/hIEtvjbZZaeXa0UTWwfeXDQscES8z+BODRshy2iVhpnGh
/+wa7NabzIOaX8b9AgMBAAECggGAIbRsydDinduWHwI4HMSH4MwfcYB9TYWgpP0C
cSOydtUldApL6xjR/7r8ekytPnzecMx7wstKtKOwEsbMXbo/BMUe9c5szq9EY792
DZq/0KnqDJ7wO36iYvX8XcJEAHmfhPymK07QqiANj7fkfCnr4ZcXxPF9nqwq0cOS
oGEobN2pDmRZZsoyyVMHXRw//gDvfWLD+m1kfWvOYzV9i8tdoSX0FmAb7p8biP5S
92FXChCTPI4y8648nyDDjNhWJZuYJmTFWnovFNK8MI6pz9y3db58iksBATsVpbRr
HZ9bSMOyUMwV0Cg3DSgBOHcEj1/cWY9LNtYd1B4d049JjocRe7IT6KzGDpegdfhK
razu5/UQKriZAQJt1m6UNSbaQ2x2tFo6JS/BQVEQyFc1M27OTlU7AXn3LcU0AUpz
NHoW7047SbfPf/KYLbUeaXlKl1BzEs1OE2hq1kok1uf5JK+wZI7nZ9lUCVIaIUcu
Y7XLouN8BzkJAM6oBi0x5+FAI+W5AoHBAO9KAEyzYKnjhbmWb8D4FUPcbRbVJ6ie
E1WO/6JhmXON/jEXkOE32LPdd1xEX+q70zZ6kDrZvlDrPJqiJyOad+nSsRRR5c01
UGHWqGmjQ0JU4B/GczuyBMhaLjJbLhco/laQb6mL/ipFpDtljJK8500NP+kfoCrW
9OUw2ryGAaw45HmSvPRAs1Yv/AF9k/4TGL/jT3Mz/wUSmsYyXVgWQVjUN+5nXCxD
tGXew/M6DvO3uDBe+33ZrmoThiG7aGUIMwKBwQDhc0+B9VZWlE6IDPwvFxSN7BG7
KyGg+4JORKWk45Fpk0LkJ+hAdJ4+pFr2XVpYbKRPmYK/pNZlo3LC3FsJCJOyakZb
X7Tpkc6Uepj1VH6YXdRAA5IC3OVi4dAl1Dt+LLoL7V9lUxpI7lgrfy+067L2QizV
YFD58H5eH0eG/nB9mKN2PO/42RCXGpSpw9V4b6JoupTh7jU3xrDKXfXQG1xm3A7M
j6DDgZDHqPWSdwJWsnaL+oPhYM0Cai7945jehA8CgcAtrxMfkZ+Cz81YAUCUtshY
jFzHXyqTJprKWuKzPa7uQM2m0bj3RpI4xK9lDijBx9orLHscwTV0fXS0kQCn63W5
TmBAYOJeqy8Nfs3oXSMaJtojNuAJJZOELLNlKcNC6LCmFi07UV7U8zbHoDuWSDpg
m4b4GvGZPDDFEO6xz2PCXZpBG6K3fyK98atLHY6Dk2HGQL+KXwLxFPw3mqX3i0gu
jVWgTltqmAJ48G64oPz5yrl/gqLBBC4oUlHpXr4vi8ECgcBq/gxXgpUM1alHS9JK
jsuEZuorR1bYTUQT3OQ3koAp+GcgXAgOvslytREuJjOAD18TH6k7RgExjxYhf+38
JYPigikNqCf1SOse7+ezVfwWV0EpeAhNL4P1H3Fm4oexY4yPqIFDVuL8hZB2ZA/B
7rGpyNH6GZGUbBusk2+gkxPTpyK8NEM2d901uLmgr32ZgHE0/oc1iZTb+YFhKKJF
txZtAjZLwkXrQovxFTAl6DDF8D/uQl9gEE56vOW8O80KnOUCgcAsolCIngfomSTJ
ZIUomwn7bkO3Npaaxeew01LJT9/0zKkiazrqtNV6lfFBgE4/dbpufccCz16OQ/65
cnCjggxDxPTIoO184AUDxpbM+4XmOmn/dLt6NdK/2jVEdWFN3fdApaDO0OExcU/L
HZ2lfR38+aJrbPp3rZwUFjHcmSZu999XdmhCWLo2qBND0zgb8//bFTWb1coL6ucM
O7EQiOmmlG6QW24JCmbjBuNY3oVs0aDTxeYJ8yGM6WJOUwNtGZM=
-----END RSA PRIVATE KEY-----