Files
ESP32_Serial_Swiss_Army_Knife/cmake/security_overrides.cmake
T
Commander1024 bea33e1c95 Add restricted wolfSSH ordering fix
Apply hash-pinned generated edits for CVE-2025-14942 while keeping
wolfSSH 1.4.20 managed sources unchanged. Add the ABI header overlay,
provenance records, and real state-machine interoperability contracts.
2026-09-16 14:04:34 +02:00

151 lines
7.6 KiB
CMake

# 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()