diff --git a/components/app_update/CMakeLists.txt b/components/app_update/CMakeLists.txt index af07c2404..a683b1c39 100644 --- a/components/app_update/CMakeLists.txt +++ b/components/app_update/CMakeLists.txt @@ -34,7 +34,7 @@ if(NOT BOOTLOADER_BUILD) ${otadata_size} ${blank_otadata_file}) add_custom_target(blank_ota_data ALL DEPENDS ${blank_otadata_file}) - add_dependencies(app blank_ota_data) + add_dependencies(flash blank_ota_data) set(otatool_py ${python} ${COMPONENT_DIR}/otatool.py) diff --git a/components/bootloader/CMakeLists.txt b/components/bootloader/CMakeLists.txt index 6d50ca58f..afe1ad639 100644 --- a/components/bootloader/CMakeLists.txt +++ b/components/bootloader/CMakeLists.txt @@ -1,13 +1,21 @@ -idf_component_register() +idf_component_register(PRIV_REQUIRES partition_table) # Do not generate flash file when building bootloader or is in early expansion of the build if(BOOTLOADER_BUILD) return() endif() +# When secure boot is enabled, do not flash bootloader along with invocation of `idf.py flash` +if(NOT CONFIG_SECURE_BOOT_ENABLED) + set(flash_bootloader FLASH_IN_PROJECT) +endif() + # Set values used in flash_bootloader_args.in and generate flash file # for bootloader esptool_py_flash_project_args(bootloader 0x1000 ${BOOTLOADER_BUILD_DIR}/bootloader.bin - FLASH_IN_PROJECT - FLASH_FILE_TEMPLATE flash_bootloader_args.in) \ No newline at end of file + ${flash_bootloader} + FLASH_FILE_TEMPLATE flash_bootloader_args.in) + +esptool_py_custom_target(bootloader-flash bootloader "bootloader") +add_dependencies(bootloader partition_table) diff --git a/components/bootloader/project_include.cmake b/components/bootloader/project_include.cmake index 49e51b9cb..019d1df71 100644 --- a/components/bootloader/project_include.cmake +++ b/components/bootloader/project_include.cmake @@ -1,32 +1,10 @@ -# Do not generate flash file when building bootloader or is in early expansion of the build +set(BOOTLOADER_OFFSET 0x1000) + +# Do not generate flash file when building bootloader if(BOOTLOADER_BUILD) return() endif() -idf_build_get_property(project_dir PROJECT_DIR) - -# This is for tracking the top level project path -if(BOOTLOADER_BUILD) - set(main_project_path "${CMAKE_BINARY_DIR}/../..") -else() - set(main_project_path "${project_dir}") -endif() - -get_filename_component(secure_boot_signing_key - "${CONFIG_SECURE_BOOT_SIGNING_KEY}" - ABSOLUTE BASE_DIR "${main_project_path}") -if(NOT EXISTS ${secure_boot_signing_key}) - # If the signing key is not found, create a phony gen_secure_boot_signing_key target that - # fails the build. fail_at_build_time also touches CMakeCache.txt to cause a cmake run next time - # (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}") -else() - add_custom_target(gen_secure_boot_signing_key) -endif() - - # Glue to build the bootloader subproject binary as an external # cmake project under this one # @@ -39,41 +17,104 @@ set(bootloader_binary_files "${BOOTLOADER_BUILD_DIR}/bootloader.map" ) -# These additional files may get generated -if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) - set(bootloader_binary_files - ${bootloader_binary_files} - "${BOOTLOADER_BUILD_DIR}/bootloader-reflash-digest.bin" - "${BOOTLOADER_BUILD_DIR}/secure-bootloader-key-192.bin" - "${BOOTLOADER_BUILD_DIR}/secure-bootloader-key-256.bin" - ) +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. +# For both cases, the user either sets binaries to be signed during build or not +# using CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES. +# +# Regardless, pass the main project's keys (signing/verification) to the bootloader subproject +# via config. +if(CONFIG_SECURE_SIGNED_APPS) + add_custom_target(gen_secure_boot_keys) + + if(CONFIG_SECURE_BOOT_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)) + fail_at_build_time(bootloader "Invalid bootloader target: bad sdkconfig?") + endif() + + if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) + set(bootloader_binary_files + ${bootloader_binary_files} + "${BOOTLOADER_BUILD_DIR}/bootloader-reflash-digest.bin" + "${BOOTLOADER_BUILD_DIR}/secure-bootloader-key-192.bin" + "${BOOTLOADER_BUILD_DIR}/secure-bootloader-key-256.bin" + ) + endif() + endif() + + # Since keys are usually given relative to main project dir, get the absolute paths to the keys + # for use by the bootloader subproject. Replace the values in config with these absolute paths, + # so that bootloader subproject does not need to assume main project dir to obtain path to the keys. + if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) + get_filename_component(secure_boot_signing_key + "${CONFIG_SECURE_BOOT_SIGNING_KEY}" + ABSOLUTE BASE_DIR "${project_dir}") + + if(NOT EXISTS ${secure_boot_signing_key}) + # If the signing key is not found, create a phony gen_secure_boot_signing_key target that + # fails the build. fail_at_build_time causes a cmake run next time + # (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}") + else() + add_custom_target(gen_secure_boot_signing_key) + endif() + + set(SECURE_BOOT_SIGNING_KEY ${secure_boot_signing_key}) # needed by some other components + set(sign_key_arg "-DSECURE_BOOT_SIGNING_KEY=${secure_boot_signing_key}") + + add_dependencies(gen_secure_boot_keys gen_secure_boot_signing_key) + else() + + get_filename_component(secure_boot_verification_key + ${CONFIG_SECURE_BOOT_VERIFICATION_KEY} + ABSOLUTE BASE_DIR "${project_dir}") + + if(NOT EXISTS ${secure_boot_verification_key}) + # If the verification key is not found, create a phony gen_secure_boot_verification_key target that + # fails the build. fail_at_build_time causes a cmake run next time + # (to pick up a new verification key if one exists, etc.) + 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.") + else() + add_custom_target(gen_secure_boot_verification_key) + endif() + + set(ver_key_arg "-DSECURE_BOOT_VERIFICATION_KEY=${secure_boot_verification_key}") + + add_dependencies(gen_secure_boot_keys gen_secure_boot_verification_key) + endif() endif() -if((NOT CONFIG_SECURE_BOOT_ENABLED) OR - CONFIG_SECURE_BOOTLOADER_REFLASHABLE OR - CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH) - idf_build_get_property(idf_path IDF_PATH) - idf_build_get_property(sdkconfig SDKCONFIG) - idf_build_get_property(idf_target IDF_TARGET) - externalproject_add(bootloader - # TODO: support overriding the bootloader in COMPONENT_PATHS - SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/subproject" - BINARY_DIR "${BOOTLOADER_BUILD_DIR}" - CMAKE_ARGS -DSDKCONFIG=${sdkconfig} -DIDF_PATH=${idf_path} -DIDF_TARGET=${idf_target} - -DSECURE_BOOT_SIGNING_KEY=${secure_boot_signing_key} - -DPYTHON_DEPS_CHECKED=1 - -DEXTRA_COMPONENT_DIRS=${CMAKE_CURRENT_LIST_DIR} - # LEGACY_INCLUDE_COMMON_HEADERS has to be passed in via cache variable since - # the bootloader common component requirements depends on this and - # config variables are not available before project() call. - -DLEGACY_INCLUDE_COMMON_HEADERS=${CONFIG_LEGACY_INCLUDE_COMMON_HEADERS} - INSTALL_COMMAND "" - BUILD_ALWAYS 1 # no easy way around this... - BUILD_BYPRODUCTS ${bootloader_binary_files} - DEPENDS gen_secure_boot_signing_key - ) -else() - fail_at_build_time(bootloader "Invalid bootloader target: bad sdkconfig?") +idf_build_get_property(idf_path IDF_PATH) +idf_build_get_property(idf_target IDF_TARGET) +idf_build_get_property(sdkconfig SDKCONFIG) + +externalproject_add(bootloader + SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/subproject" + BINARY_DIR "${BOOTLOADER_BUILD_DIR}" + CMAKE_ARGS -DSDKCONFIG=${sdkconfig} -DIDF_PATH=${idf_path} -DIDF_TARGET=${idf_target} + -DPYTHON_DEPS_CHECKED=1 + -DEXTRA_COMPONENT_DIRS=${CMAKE_CURRENT_LIST_DIR} + ${sign_key_arg} ${ver_key_arg} + # LEGACY_INCLUDE_COMMON_HEADERS has to be passed in via cache variable since + # the bootloader common component requirements depends on this and + # config variables are not available before project() call. + -DLEGACY_INCLUDE_COMMON_HEADERS=${CONFIG_LEGACY_INCLUDE_COMMON_HEADERS} + INSTALL_COMMAND "" + BUILD_ALWAYS 1 # no easy way around this... + BUILD_BYPRODUCTS ${bootloader_binary_files} + ) + +if(CONFIG_SECURE_SIGNED_APPS) + add_dependencies(bootloader gen_secure_boot_keys) endif() # this is a hack due to an (annoying) shortcoming in cmake, it can't diff --git a/components/bootloader/subproject/CMakeLists.txt b/components/bootloader/subproject/CMakeLists.txt index d6334ae15..c125cc558 100644 --- a/components/bootloader/subproject/CMakeLists.txt +++ b/components/bootloader/subproject/CMakeLists.txt @@ -29,8 +29,6 @@ project(bootloader) idf_build_set_property(COMPILE_DEFINITIONS "-DBOOTLOADER_BUILD=1" APPEND) idf_build_set_property(COMPILE_OPTIONS "-fno-stack-protector" APPEND) -set(secure_boot_signing_key ${SECURE_BOOT_SIGNING_KEY}) - string(REPLACE ";" " " espsecurepy "${ESPSECUREPY}") string(REPLACE ";" " " espefusepy "${ESPEFUSEPY}") set(esptoolpy_write_flash "${ESPTOOLPY_WRITE_FLASH_STR}") @@ -53,7 +51,7 @@ if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) add_custom_command(OUTPUT "${secure_bootloader_key}" COMMAND ${ESPSECUREPY} digest_private_key --keylen "${key_digest_len}" - --keyfile "${secure_boot_signing_key}" + --keyfile "${SECURE_BOOT_SIGNING_KEY}" "${secure_bootloader_key}" VERBATIM) @@ -67,7 +65,7 @@ if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) "\nTo generate one, you can use this command:" "\n\t${espsecurepy} generate_flash_encryption_key ${secure_bootloader_key}" "\nIf a signing key is present, then instead use:" - "\n\t${ESPSECUREPY} digest_private_key " + "\n\t${espsecurepy} digest_private_key " "--keylen (192/256) --keyfile KEYFILE " "${secure_bootloader_key}") endif() @@ -78,14 +76,14 @@ if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) COMMAND ${CMAKE_COMMAND} -E echo "DIGEST ${bootloader_digest_bin}" COMMAND ${ESPSECUREPY} digest_secure_bootloader --keyfile "${secure_bootloader_key}" -o "${bootloader_digest_bin}" "${CMAKE_BINARY_DIR}/bootloader.bin" - DEPENDS gen_secure_bootloader_key "${CMAKE_BINARY_DIR}/bootloader.bin" + DEPENDS gen_secure_bootloader_key gen_project_binary VERBATIM) add_custom_target (gen_bootloader_digest_bin ALL DEPENDS "${bootloader_digest_bin}") endif() if(CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH) - add_custom_command(TARGET bootloader POST_BUILD + add_custom_command(TARGET bootloader.elf POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "==============================================================================" COMMAND ${CMAKE_COMMAND} -E echo @@ -97,9 +95,8 @@ if(CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH) COMMAND ${CMAKE_COMMAND} -E echo "* IMPORTANT: After first boot, BOOTLOADER CANNOT BE RE-FLASHED on same device" VERBATIM) - elseif(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) - add_custom_command(TARGET bootloader POST_BUILD + add_custom_command(TARGET bootloader.elf POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "==============================================================================" COMMAND ${CMAKE_COMMAND} -E echo diff --git a/components/bootloader_support/CMakeLists.txt b/components/bootloader_support/CMakeLists.txt index b25df75b0..a49f2699c 100644 --- a/components/bootloader_support/CMakeLists.txt +++ b/components/bootloader_support/CMakeLists.txt @@ -19,40 +19,6 @@ if(BOOTLOADER_BUILD) "src/${IDF_TARGET}/flash_encrypt.c" "src/${IDF_TARGET}/secure_boot_signatures.c" "src/${IDF_TARGET}/secure_boot.c") - - if(CONFIG_SECURE_SIGNED_APPS) - get_filename_component(secure_boot_verification_key - "signature_verification_key.bin" - ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}") - if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) - add_custom_command(OUTPUT "${secure_boot_verification_key}" - COMMAND ${ESPSECUREPY} - extract_public_key --keyfile "${secure_boot_signing_key}" - "${secure_boot_verification_key}" - DEPENDS gen_secure_boot_signing_key - VERBATIM) - else() - get_filename_component(orig_secure_boot_verification_key - "${CONFIG_SECURE_BOOT_VERIFICATION_KEY}" - ABSOLUTE BASE_DIR "${main_project_path}") - if(NOT EXISTS ${orig_secure_boot_verification_key}) - message(FATAL_ERROR - "Secure Boot Verification Public Key ${CONFIG_SECURE_BOOT_VERIFICATION_KEY} does not exist." - "\nThis can be extracted from the private signing key." - "\nSee docs/security/secure-boot.rst for details.") - endif() - - add_custom_command(OUTPUT "${secure_boot_verification_key}" - COMMAND ${CMAKE_COMMAND} -E copy "${orig_secure_boot_verification_key}" - "${secure_boot_verification_key}" - DEPENDS "${orig_secure_boot_verification_key}" - VERBATIM) - endif() - set(embed_files "${secure_boot_verification_key}") - set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES - "${secure_boot_verification_key}") - endif() else() list(APPEND srcs "src/idf/bootloader_sha.c" @@ -67,5 +33,33 @@ idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${include_dirs}" PRIV_INCLUDE_DIRS "${priv_include_dirs}" REQUIRES "${requires}" - PRIV_REQUIRES "${priv_requires}" - EMBED_FILES "${embed_files}") \ No newline at end of file + PRIV_REQUIRES "${priv_requires}") + +if(BOOTLOADER_BUILD AND CONFIG_SECURE_SIGNED_APPS) + # Whether CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES or not, we need verification key to embed + # in the library. + if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) + # We generate the key from the signing key. The signing key is passed from the main project. + get_filename_component(secure_boot_signing_key + "${SECURE_BOOT_SIGNING_KEY}" + ABSOLUTE BASE_DIR "${project_dir}") + get_filename_component(secure_boot_verification_key + "signature_verification_key.bin" + ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") + add_custom_command(OUTPUT "${secure_boot_verification_key}" + COMMAND ${ESPSECUREPY} + extract_public_key --keyfile "${secure_boot_signing_key}" + "${secure_boot_verification_key}" + VERBATIM) + else() + # We expect to 'inherit' the verification key passed from main project. + get_filename_component(secure_boot_verification_key + ${SECURE_BOOT_VERIFICATION_KEY} + ABSOLUTE BASE_DIR "${project_dir}") + endif() + + target_add_binary_data(${COMPONENT_LIB} "${secure_boot_verification_key}" "BINARY") + set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES + "${secure_boot_verification_key}") +endif() diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index 9c7f29759..a5823fb61 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -53,7 +53,7 @@ if(CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION) COMMAND ${CMAKE_OBJCOPY} -O binary phy_init_data.obj ${phy_init_data_bin} ) add_custom_target(phy_init_data ALL DEPENDS ${phy_init_data_bin}) - add_dependencies(app phy_init_data) + add_dependencies(flash phy_init_data) esptool_py_flash_project_args(phy ${phy_partition_offset} ${phy_init_data_bin} FLASH_IN_PROJECT) endif() diff --git a/components/esptool_py/CMakeLists.txt b/components/esptool_py/CMakeLists.txt index be1cdbf77..c83cd5286 100644 --- a/components/esptool_py/CMakeLists.txt +++ b/components/esptool_py/CMakeLists.txt @@ -1,50 +1,72 @@ idf_component_register(REQUIRES bootloader) -string(REPLACE ";" " " ESPTOOLPY_FLASH_PROJECT_OPTIONS "${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS}") -set(ESPTOOLPY_FLASH_PROJECT_OPTIONS - "${ESPTOOLPY_FLASH_PROJECT_OPTIONS}" - ) +if(NOT BOOTLOADER_BUILD) + string(REPLACE ";" " " ESPTOOLPY_FLASH_PROJECT_OPTIONS "${ESPTOOLPY_FLASH_OPTIONS}") + set(ESPTOOLPY_FLASH_PROJECT_OPTIONS + "${ESPTOOLPY_FLASH_PROJECT_OPTIONS}" + ) -if(CONFIG_SECURE_BOOT_ENABLED) - set(ESPTOOLPY_FLASH_PROJECT_OPTIONS "") + if(CONFIG_SECURE_BOOT_ENABLED) + set(ESPTOOLPY_FLASH_PROJECT_OPTIONS "") + endif() + + # Generate the flash project args and the flasher args json file using the accumulated values + # from esptool_py_flash_project_args calls. The file is first configured using configure_file() for all variable values, + # and then generated using file(GENERATE... for generator expressions. + configure_file(${COMPONENT_DIR}/flash_project_args.in + ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in) + + file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in2 + INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in) + file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/flash_project_args + INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in2) + + if(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT) + configure_file(${COMPONENT_DIR}/flash_encrypted_project_args.in + ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_project_args.in) + + file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_project_args.in2 + INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_project_args.in) + file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/flash_encrypted_project_args + INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_project_args.in2) + endif() + + configure_file(${COMPONENT_DIR}/flasher_args.json.in + ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in) + + file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in2 + INPUT ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in) + file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/flasher_args.json + INPUT ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in2) + + set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES + "${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in" + "${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in2" + "${CMAKE_BINARY_DIR}/flash_project_args" + "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in" + "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in2" + "${CMAKE_BINARY_DIR}/flasher_args.json") + + idf_build_get_property(build_dir BUILD_DIR) + partition_table_get_partition_info(app_partition_offset "--partition-boot-default" "offset") + esptool_py_flash_project_args(app ${app_partition_offset} ${build_dir}/${PROJECT_BIN} FLASH_IN_PROJECT) + + if(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT) + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_app_args.in "--encrypt ${app_partition_offset} ${PROJECT_BIN}") + esptool_py_flash_project_args(encrypted_app ${app_partition_offset} ${build_dir}/${PROJECT_BIN} + FLASH_FILE_TEMPLATE ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_app_args.in) + endif() + + add_dependencies(flash partition_table) + + # If anti-rollback option is set then factory partition should not be in Partition Table. + # In this case, should be used the partition table with two ota app without the factory. + partition_table_get_partition_info(factory_offset "--partition-type app --partition-subtype factory" "offset") + if(CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK AND factory_offset) + fail_at_build_time(check_table_contents + "ERROR: Anti-rollback option is enabled. Partition table should consist of two ota app without factory partition.") + add_dependencies(app check_table_contents) + endif() endif() -# Generate the flash project args and the flasher args json file using the accumulated values -# from esptool_py_flash_project_args calls. The file is first configured using configure_file() for all variable values, -# and then generated using file(GENERATE... for generator expressions. -configure_file(${COMPONENT_DIR}/flash_project_args.in - ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in) - -file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in2 - INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in) -file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/flash_project_args - INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in2) - - -if(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT) - configure_file(${COMPONENT_DIR}/flash_encrypted_project_args.in - ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_project_args.in) - - file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_project_args.in2 - INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_project_args.in) - file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/flash_encrypted_project_args - INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_project_args.in2) -endif() - - -configure_file(${COMPONENT_DIR}/flasher_args.json.in - ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in) - -file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in2 - INPUT ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in) -file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/flasher_args.json - INPUT ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in2) - -set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES - "${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in" - "${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in2" - "${CMAKE_BINARY_DIR}/flash_project_args" - "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in" - "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in2" - "${CMAKE_BINARY_DIR}/flasher_args.json") diff --git a/components/esptool_py/project_include.cmake b/components/esptool_py/project_include.cmake index 7d064f9c2..d4f8c3f93 100644 --- a/components/esptool_py/project_include.cmake +++ b/components/esptool_py/project_include.cmake @@ -31,7 +31,7 @@ else() set(ESPTOOLPY_COMPRESSED_OPT -u) endif() -set(ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS +set(ESPTOOLPY_FLASH_OPTIONS --flash_mode ${ESPFLASHMODE} --flash_freq ${ESPFLASHFREQ} --flash_size ${ESPFLASHSIZE} @@ -40,19 +40,18 @@ set(ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS # String for printing flash command string(REPLACE ";" " " ESPTOOLPY_WRITE_FLASH_STR "${ESPTOOLPY} --port (PORT) --baud (BAUD) --before ${ESPTOOLPY_BEFORE} --after ${ESPTOOLPY_AFTER} " - "write_flash ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} ${ESPTOOLPY_EXTRA_FLASH_OPTIONS} ${ESPTOOLPY_COMPRESSED_OPT}") - -if(CONFIG_SECURE_BOOT_ENABLED AND - NOT CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION AND - NOT BOOTLOADER_BUILD) - set(ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS - ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} --secure-pad) -endif() + "write_flash ${ESPTOOLPY_FLASH_OPTIONS} ${ESPTOOLPY_EXTRA_FLASH_OPTIONS} ${ESPTOOLPY_COMPRESSED_OPT}") if(NOT BOOTLOADER_BUILD) set(ESPTOOLPY_ELF2IMAGE_OPTIONS --elf-sha256-offset 0xb0) endif() +if(CONFIG_SECURE_BOOT_ENABLED AND + NOT CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION + AND NOT BOOTLOADER_BUILD) + set(ESPTOOLPY_ELF2IMAGE_OPTIONS ${ESPTOOLPY_ELF2IMAGE_OPTIONS} --secure-pad) +endif() + if(CONFIG_ESPTOOLPY_FLASHSIZE_DETECT) # Set ESPFLASHSIZE to 'detect' *after* elf2image options are generated, # as elf2image can't have 'detect' as an option... @@ -76,7 +75,7 @@ set(PROJECT_BIN "${elf_name}.bin") # Add 'app.bin' target - generates with elf2image # add_custom_command(OUTPUT "${build_dir}/.bin_timestamp" - COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS} + COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS} -o "${build_dir}/${unsigned_project_binary}" "${elf}" COMMAND ${CMAKE_COMMAND} -E echo "Generated ${build_dir}/${unsigned_project_binary}" COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${unsigned_project_binary}" > "${build_dir}/.bin_timestamp" @@ -87,40 +86,42 @@ add_custom_command(OUTPUT "${build_dir}/.bin_timestamp" ) add_custom_target(gen_project_binary DEPENDS "${build_dir}/.bin_timestamp") -if(NOT BOOTLOADER_BUILD AND - CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) +set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES + "${build_dir}/${unsigned_project_binary}" + ) - # 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} - -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}" - COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${PROJECT_BIN}" > "${build_dir}/.signed_bin_timestamp" - DEPENDS "${build_dir}/.bin_timestamp" - VERBATIM - COMMENT "Generating signed binary image" - ) - add_custom_target(gen_signed_project_binary DEPENDS "${build_dir}/.signed_bin_timestamp") - add_dependencies(gen_project_binary gen_signed_project_binary) -endif() +add_custom_target(app ALL DEPENDS gen_project_binary) -if(NOT BOOTLOADER_BUILD) - add_custom_target(app ALL DEPENDS gen_project_binary) -else() - add_custom_target(bootloader ALL DEPENDS gen_project_binary) -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} + -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}" + COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${PROJECT_BIN}" > "${build_dir}/.signed_bin_timestamp" + DEPENDS "${build_dir}/.bin_timestamp" + VERBATIM + COMMENT "Generating signed binary image" + ) + add_custom_target(gen_signed_project_binary DEPENDS "${build_dir}/.signed_bin_timestamp") + add_dependencies(gen_project_binary gen_signed_project_binary) - -if(NOT BOOTLOADER_BUILD AND - CONFIG_SECURE_BOOT_ENABLED AND - NOT CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) - add_custom_command(TARGET app POST_BUILD - 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}/${elf_bin}" - VERBATIM) + set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES + "${build_dir}/${PROJECT_BIN}" + ) + else() + string(REPLACE ";" " " espsecurepy "${ESPSECUREPY}") + add_custom_command(TARGET app POST_BUILD + 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}" + VERBATIM) + endif() endif() # @@ -142,7 +143,6 @@ endfunction() esptool_py_custom_target(flash project "app;partition_table;bootloader") esptool_py_custom_target(app-flash app "app") -esptool_py_custom_target(bootloader-flash bootloader "bootloader") if(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT) esptool_py_custom_target(encrypted-flash encrypted_project "app;partition_table;bootloader") diff --git a/components/partition_table/CMakeLists.txt b/components/partition_table/CMakeLists.txt index c64b2500d..233e03d77 100644 --- a/components/partition_table/CMakeLists.txt +++ b/components/partition_table/CMakeLists.txt @@ -40,19 +40,6 @@ add_custom_command(OUTPUT "${build_dir}/partition_table/${unsigned_partition_bin DEPENDS ${partition_csv} "${CMAKE_CURRENT_SOURCE_DIR}/gen_esp32part.py" VERBATIM) -# Add signing steps -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}" - -o "${build_dir}/partition_table/${final_partition_bin}" - "${build_dir}/partition_table/${unsigned_partition_bin}" - DEPENDS "${build_dir}/partition_table/${unsigned_partition_bin}" - VERBATIM) -endif() - if(EXISTS ${partition_csv}) add_custom_target(partition_table ALL DEPENDS "${build_dir}/partition_table/${final_partition_bin}") else() @@ -64,29 +51,29 @@ else() "Either change partition table in menuconfig or create this input file.") endif() -if(CONFIG_SECURE_BOOT_ENABLED AND - NOT CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) - add_custom_command(TARGET partition_table POST_BUILD - COMMAND ${CMAKE_COMMAND} -E echo - "Partition table built but not signed. Sign partition data before flashing:" - COMMAND ${CMAKE_COMMAND} -E echo - "\t${ESPSECUREPY} sign_data --keyfile KEYFILE ${CMAKE_CURRENT_BINARY_DIR}/${final_partition_bin}" - VERBATIM) -endif() +# Add signing steps +if(CONFIG_SECURE_SIGNED_APPS) + if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) + add_custom_target(gen_unsigned_partition_bin ALL DEPENDS + "${build_dir}/partition_table/${unsigned_partition_bin}") -# If anti-rollback option is set then factory partition should not be in Partition Table. -# In this case, should be used the partition table with two ota app without the factory. -partition_table_get_partition_info(factory_offset "--partition-type app --partition-subtype factory" "offset") -if(CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK AND factory_offset) - fail_at_build_time(check_table_contents - "ERROR: Anti-rollback option is enabled. Partition table should consist of two ota app without factory partition.") -add_dependencies(bootloader check_table_contents) -add_dependencies(app check_table_contents) + add_custom_command(OUTPUT "${build_dir}/partition_table/${final_partition_bin}" + COMMAND ${ESPSECUREPY} sign_data --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}" + VERBATIM) + else() + string(REPLACE ";" " " espsecurepy "${ESPSECUREPY}") + add_custom_command(TARGET partition_table POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo + "Partition table built but not signed. Sign partition data before flashing:" + COMMAND ${CMAKE_COMMAND} -E echo + "\t${espsecurepy} sign_data --keyfile KEYFILE ${build_dir}/partition_table/${final_partition_bin}" + VERBATIM) + endif() endif() -add_dependencies(bootloader partition_table) -add_dependencies(app partition_table) - # Use global properties ESPTOOL_WRITE_FLASH_ARGS to pass this info to build # the list of esptool write arguments for flashing set_property(GLOBAL APPEND_STRING PROPERTY @@ -95,13 +82,3 @@ set_property(GLOBAL APPEND_STRING PROPERTY esptool_py_flash_project_args(partition_table ${PARTITION_TABLE_OFFSET} ${build_dir}/partition_table/partition-table.bin FLASH_IN_PROJECT) - -partition_table_get_partition_info(app_partition_offset "--partition-boot-default" "offset") -esptool_py_flash_project_args(app ${app_partition_offset} ${build_dir}/${PROJECT_BIN} FLASH_IN_PROJECT) - -if(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT) - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_app_args.in "--encrypt ${app_partition_offset} ${PROJECT_BIN}") - esptool_py_flash_project_args(encrypted_app ${app_partition_offset} ${build_dir}/${PROJECT_BIN} - FLASH_FILE_TEMPLATE ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_app_args.in) -endif() - diff --git a/docs/en/cmake-pending-features.rst b/docs/en/cmake-pending-features.rst index 548fd7e25..2223f5d4b 100644 --- a/docs/en/cmake-pending-features.rst +++ b/docs/en/cmake-pending-features.rst @@ -2,8 +2,6 @@ The following features are not yet supported with the CMake-based build system: - Eclipse IDE Documentation - - Secure Boot - - Flash Encryption Support for these features will be available before CMake becomes the default build system. diff --git a/tools/ci/test_build_system_cmake.sh b/tools/ci/test_build_system_cmake.sh index 9d033cd01..faac26def 100755 --- a/tools/ci/test_build_system_cmake.sh +++ b/tools/ci/test_build_system_cmake.sh @@ -488,6 +488,17 @@ endmenu\n" >> ${IDF_PATH}/Kconfig; print_status "Can set -D twice: globally and for subcommand, only if values are the same" idf.py -DAAA=BBB -DCCC=EEE build -DAAA=BBB -DCCC=EEE || failure "It should be allowed to set -D twice (globally and for subcommand) if values are the same" + print_status "Fail on build time works" + clean_build_dir + cp CMakeLists.txt CMakeLists.txt.bak + printf "\nif(NOT EXISTS \"\${CMAKE_CURRENT_LIST_DIR}/hello.txt\") \nfail_at_build_time(test_file \"hello.txt does not exists\") \nendif()" >> CMakeLists.txt + ! idf.py build || failure "Build should fail if requirements are not satisfied" + touch hello.txt + idf.py build || failure "Build succeeds once requirements are satisfied" + rm -rf hello.txt CMakeLists.txt + mv CMakeLists.txt.bak CMakeLists.txt + rm -rf CMakeLists.txt.bak + print_status "All tests completed" if [ -n "${FAILURES}" ]; then echo "Some failures were detected:" diff --git a/tools/cmake/utilities.cmake b/tools/cmake/utilities.cmake index 83403d9ce..758061307 100644 --- a/tools/cmake/utilities.cmake +++ b/tools/cmake/utilities.cmake @@ -201,9 +201,15 @@ function(fail_at_build_time target_name message_line0) foreach(message_line ${ARGN}) set(message_lines ${message_lines} COMMAND ${CMAKE_COMMAND} -E echo "${message_line}") endforeach() + # Generate a timestamp file that gets included. When deleted on build, this forces CMake + # to rerun. + string(RANDOM filename) + set(filename "${CMAKE_CURRENT_BINARY_DIR}/${filename}.cmake") + file(WRITE "${filename}" "") + include("${filename}") add_custom_target(${target_name} ALL ${message_lines} - COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/CMakeCache.txt" + COMMAND ${CMAKE_COMMAND} -E remove "${filename}" COMMAND ${CMAKE_COMMAND} -P ${idf_path}/tools/cmake/scripts/fail.cmake VERBATIM) endfunction()