소스 검색

Merge branch 'bugfix/fix_secure_boot_support' into 'master'

Fixes to secure boot support in CMake

See merge request idf/esp-idf!4977
Angus Gratton 6 년 전
부모
커밋
265d7dc4e5

+ 1 - 1
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)
 

+ 11 - 3
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)
+                            ${flash_bootloader}
+                            FLASH_FILE_TEMPLATE flash_bootloader_args.in)
+
+esptool_py_custom_target(bootloader-flash bootloader "bootloader")
+add_dependencies(bootloader partition_table)

+ 99 - 58
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
-if(BOOTLOADER_BUILD)
-    return()
-endif()
+set(BOOTLOADER_OFFSET 0x1000)
 
-idf_build_get_property(project_dir PROJECT_DIR)
-
-# This is for tracking the top level project path
+# Do not generate flash file when building bootloader
 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)
+    return()
 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

+ 5 - 8
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

+ 30 - 36
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}")
+                    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()

+ 1 - 1
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()

+ 60 - 38
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 "")
-endif()
+    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)
+    # 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)
+    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)
 
-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()
 
-    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")
 
-configure_file(${COMPONENT_DIR}/flasher_args.json.in
-               ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in)
+    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)
 
-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)
+    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()
 
-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")

+ 44 - 44
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)
-
-    # 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()
-
-if(NOT BOOTLOADER_BUILD)
-    add_custom_target(app ALL DEPENDS gen_project_binary)
-else()
-    add_custom_target(bootloader ALL DEPENDS gen_project_binary)
-endif()
-
+set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+    APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
+    "${build_dir}/${unsigned_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)
+add_custom_target(app ALL DEPENDS gen_project_binary)
+
+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)
+
+        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")

+ 21 - 44
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()
-
-# 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 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}")
+
+        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()
-

+ 0 - 2
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.
 

+ 11 - 0
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:"

+ 7 - 1
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()