# SPDX-License-Identifier: GPL-3.0-only # Include after project(): IDF component targets and their final source lists exist. if(CMAKE_VERSION VERSION_LESS 3.18) message(FATAL_ERROR "Security overrides need CMake 3.18 source-property directory support") endif() set(_sak_security_script "${CMAKE_CURRENT_LIST_DIR}/../tools/security_overrides.py") get_filename_component(_sak_security_script "${_sak_security_script}" REALPATH) if(NOT PYTHON) find_package(Python3 REQUIRED COMPONENTS Interpreter) set(_sak_security_python "${Python3_EXECUTABLE}") else() set(_sak_security_python "${PYTHON}") endif() idf_build_get_property(_sak_security_idf IDF_PATH) execute_process( COMMAND "${_sak_security_python}" "${_sak_security_script}" --idf-path "${_sak_security_idf}" --project-dir "${PROJECT_SOURCE_DIR}" --binary-dir "${CMAKE_BINARY_DIR}" RESULT_VARIABLE _sak_security_result OUTPUT_VARIABLE _sak_security_stdout ERROR_VARIABLE _sak_security_stderr ) if(NOT _sak_security_result EQUAL 0) message(FATAL_ERROR "SDK security override generation failed:\n${_sak_security_stdout}${_sak_security_stderr}") endif() include("${CMAKE_BINARY_DIR}/security_overrides/manifest.cmake") set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${_sak_security_script}" "${SAK_SECURITY_VERSION_HEADER}") if(SAK_SECURITY_HEADER_IDS) get_filename_component(_sak_security_tools "${_sak_security_script}" DIRECTORY) set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${_sak_security_tools}/wolfssh_order/delta.json") endif() # Public extension point: the Python Entry registry supplies the mapping. This # function is backend-agnostic; a later pinned project/vendor source uses it too. function(sak_security_replace_source component original generated nested_target) idf_component_get_property(_target "${component}" COMPONENT_LIB) if(NOT TARGET "${_target}") message(FATAL_ERROR "Security override: missing component target ${component}") endif() if(NOT "${nested_target}" STREQUAL "") if(NOT component STREQUAL "mbedtls" OR NOT nested_target MATCHES "^(mbedtls|mbedx509|mbedcrypto)$") message(FATAL_ERROR "Security override: invalid nested target ${component}/${nested_target}") endif() if(NOT TARGET "${nested_target}") message(FATAL_ERROR "Security override: missing nested target ${nested_target}") endif() set(_target "${nested_target}") get_target_property(_imported "${_target}" IMPORTED) get_target_property(_alias "${_target}" ALIASED_TARGET) get_target_property(_owner_dir "${_target}" SOURCE_DIR) get_filename_component(_owner_dir "${_owner_dir}" REALPATH) get_filename_component(_expected_owner "${_sak_security_idf}/components/mbedtls/mbedtls/library" REALPATH) if(_imported OR _alias OR NOT _owner_dir STREQUAL _expected_owner) message(FATAL_ERROR "Security override: unexpected nested target owner ${_target}: ${_owner_dir}") endif() endif() get_target_property(_source_dir "${_target}" SOURCE_DIR) get_target_property(_sources "${_target}" SOURCES) get_filename_component(_expected "${original}" REALPATH) set(_matches 0) set(_replaced) foreach(_source IN LISTS _sources) if(_source MATCHES "\\$<") # An expression could hide an additional copy of the protected source. message(FATAL_ERROR "Security override: unaudited source expression in ${component}: ${_source}") endif() get_filename_component(_absolute "${_source}" ABSOLUTE BASE_DIR "${_source_dir}") get_filename_component(_absolute "${_absolute}" REALPATH) if(_absolute STREQUAL _expected) math(EXPR _matches "${_matches} + 1") list(APPEND _replaced "${generated}") else() list(APPEND _replaced "${_source}") endif() endforeach() if(NOT _matches EQUAL 1) message(FATAL_ERROR "Security override: ${component} needs exactly one ${original}; found ${_matches}") endif() # Target flags/includes/definitions are retained because the target is not # replaced. Preserve source-specific properties in the owning directory too. set(_properties COMPILE_FLAGS COMPILE_OPTIONS COMPILE_DEFINITIONS INCLUDE_DIRECTORIES OBJECT_DEPENDS OBJECT_OUTPUTS LANGUAGE SKIP_PRECOMPILE_HEADERS SKIP_UNITY_BUILD_INCLUSION SKIP_LINTING HEADER_FILE_ONLY) set(_configs DEBUG RELEASE RELWITHDEBINFO MINSIZEREL ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE}) foreach(_config IN LISTS _configs) string(TOUPPER "${_config}" _config) list(APPEND _properties "COMPILE_DEFINITIONS_${_config}") endforeach() foreach(_property IN LISTS _properties) get_property(_is_set SOURCE "${_expected}" DIRECTORY "${_source_dir}" PROPERTY "${_property}" SET) if(_is_set) get_property(_value SOURCE "${_expected}" DIRECTORY "${_source_dir}" PROPERTY "${_property}") set_property(SOURCE "${generated}" DIRECTORY "${_source_dir}" PROPERTY "${_property}" "${_value}") endif() endforeach() get_filename_component(_original_dir "${original}" DIRECTORY) get_property(_includes SOURCE "${generated}" DIRECTORY "${_source_dir}" PROPERTY INCLUDE_DIRECTORIES) # Restore the implicit quoted-include search directory lost by relocating C. set_property(SOURCE "${generated}" DIRECTORY "${_source_dir}" PROPERTY INCLUDE_DIRECTORIES "${_original_dir};${_includes}") set_property(TARGET "${_target}" PROPERTY SOURCES "${_replaced}") set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${original}" "${generated}") message(STATUS "Security override: ${component}: ${original} -> ${generated}") endfunction() # HandshakeInfo and WOLFSSH are ABI-sensitive. Force the same generated header # into the library AND every transitive consumer, even if a consumer adds a # vendor include directory ahead of the overlay. The original include guard # then prevents a second, stale definition. This also creates compiler deps. foreach(_sak_security_id IN LISTS SAK_SECURITY_HEADER_IDS) if(NOT _sak_security_id STREQUAL "wolfssh_internal_header" OR NOT SAK_SECURITY_${_sak_security_id}_COMPONENT STREQUAL "wolfssl__wolfssh") message(FATAL_ERROR "Security override: unaudited header overlay") endif() idf_component_get_property(_sak_security_wolfssh wolfssl__wolfssh COMPONENT_LIB) if(NOT TARGET "${_sak_security_wolfssh}") message(FATAL_ERROR "Security override: missing wolfSSH overlay target") endif() target_include_directories("${_sak_security_wolfssh}" BEFORE PUBLIC "${SAK_SECURITY_WOLFSSH_INCLUDE}") # PlatformIO's ESP-IDF adapter sorts app flags and deduplicates component # flags. Keep option+operand atomic, as with wolf_crypto_policy.h. target_compile_options("${_sak_security_wolfssh}" PUBLIC "-include${SAK_SECURITY_${_sak_security_id}_GENERATED}") set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${SAK_SECURITY_${_sak_security_id}_ORIGINAL}" "${SAK_SECURITY_${_sak_security_id}_GENERATED}") endforeach() foreach(_sak_security_id IN LISTS SAK_SECURITY_OVERRIDE_IDS) sak_security_replace_source( "${SAK_SECURITY_${_sak_security_id}_COMPONENT}" "${SAK_SECURITY_${_sak_security_id}_ORIGINAL}" "${SAK_SECURITY_${_sak_security_id}_GENERATED}" "${SAK_SECURITY_${_sak_security_id}_TARGET}") endforeach()