Files
hdf5/tools/test/CMakeLists.txt
86bdc78365 ✨[Feature] Digital Signature Verification for HDF5 Plugins (#6198)
feat: add optional digital signature verification for HDF5 filter plugins

Introduce an opt-in plugin signing and verification system that allows
HDF5 deployments to require cryptographically signed filter plugins before
loading them. Disabled by default (HDF5_REQUIRE_SIGNED_PLUGINS=OFF).

New tool: h5sign
- Signs plugin shared libraries by appending an RSA signature and a
  14-byte footer (algo_id | sig_len | 8-byte magic | format_ver) to the
  binary without modifying the original content.
- Supports SHA-512 (default), SHA-256, SHA-384, and their PSS variants
  (-a/--algorithm flag).
- Detects already-signed plugins; --force strips the old signature and
  re-signs.
- Security hardened: keeps the file descriptor open through hashing and
  appending (no TOCTOU window), enforces a 2048-bit minimum RSA key size,
  rolls back partial writes on failure, and rejects paths that are not
  regular files.

Verification (H5PLsig.c)
- At plugin load time, reads the footer, validates the magic and format
  version, then checks the RSA signature against all public keys found in
  the KeyStore directory.
- File is hashed once; per-key verification operates on the pre-computed
  digest (no redundant I/O for multi-key keystores).
- Plugins whose signature hash appears in revoked_signatures.txt are
  rejected regardless of key validity.
- Runtime debug output via HDF5_DEBUG=pl.

KeyStore management
- Trusted public keys are PEM files in a directory specified by
  HDF5_PLUGIN_KEYSTORE_DIR (build time) or HDF5_PLUGIN_KEYSTORE (env var).
- HDF5_LOCK_PLUGIN_KEYSTORE cmake option disables the env-var override for
  security-hardened deployments.

Test infrastructure
- h5signverifytest: positive, negative, tamper, re-sign, and revocation
  test cases.
- CTest fixture-based dependency graph (FIXTURES_SETUP/FIXTURES_REQUIRED)
  replaces fragile DEPENDS chains so tests remain correct under -R filtering.
- Dedicated signed-plugins.yml CI workflow; full test suite scoped to
  H5SIGN and H5PLUGIN-signature tests to avoid unrelated flaky failures.
- Cross-platform: Linux, macOS, and Windows (MSVC-compatible, BIO-based
  OpenSSL I/O, HDsleep/HDsetenv portability wrappers).

Documentation: docs/PLUGIN_SIGNATURE_README.md covers usage, footer
format, revocation file format, FAQ, and troubleshooting.

Co-authored-by: Glenn Song <gsong@hdfgroup.org>
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-06 09:35:19 -05:00

130 lines
3.9 KiB
CMake

cmake_minimum_required (VERSION 3.26)
project (HDF5_TOOLS_TEST C)
# Include plugin signing helper function (used by tool test subdirectories)
include(${HDF5_SOURCE_DIR}/config/cmake/SignPlugin.cmake)
set (HDF5_TOOLS
h5copy
h5diff
h5dump
h5format_convert
h5jam
h5repack
h5stat
h5ls
)
set (HDF5_TOOLS_MISC
h5repart
# h5clear gentest requires special exit to leave IDs open, excluded here
# h5perf does not use gentest like other tools, excluded here
)
# Build main gentest
add_executable(h5gentest ${HDF5_TOOLS_TEST_SOURCE_DIR}/h5gentest.c)
target_include_directories (h5gentest PRIVATE
"${HDF5_SRC_INCLUDE_DIRS};${HDF5_SRC_BINARY_DIR};"
"$<$<BOOL:${HDF5_ENABLE_PARALLEL}>:${MPI_C_INCLUDE_DIRS}>")
if (HDF5_BUILD_STATIC_TOOLS)
TARGET_C_PROPERTIES (h5gentest STATIC)
target_link_libraries (h5gentest PRIVATE ${HDF5_LIB_TARGET})
else ()
TARGET_C_PROPERTIES (h5gentest SHARED)
target_link_libraries (h5gentest PRIVATE ${HDF5_LIBSH_TARGET})
endif ()
target_include_directories(h5gentest PRIVATE
"${HDF5_TOOLS_TEST_SOURCE_DIR}/misc"
)
# Build object libraries for gentest
foreach(tool ${HDF5_TOOLS};${HDF5_TOOLS_MISC})
if (${tool} IN_LIST HDF5_TOOLS_MISC)
add_library(${tool}gentest OBJECT ${HDF5_TOOLS_TEST_SOURCE_DIR}/misc/${tool}gentest.c)
target_include_directories (${tool}gentest PRIVATE "${HDF5_SRC_INCLUDE_DIRS};${HDF5_TEST_SRC_DIR};${HDF5_TOOLS_TST_DIR};${HDF5_TOOLS_ROOT_DIR}/misc;${HDF5_TOOLS_ROOT_DIR}/lib;${HDF5_SRC_BINARY_DIR};$<$<BOOL:${HDF5_ENABLE_PARALLEL}>:${MPI_C_INCLUDE_DIRS}>")
else()
add_library(${tool}gentest OBJECT ${HDF5_TOOLS_TEST_SOURCE_DIR}/${tool}/${tool}gentest.c)
target_include_directories (${tool}gentest PRIVATE "${HDF5_SRC_INCLUDE_DIRS};${HDF5_TEST_SRC_DIR};${HDF5_TOOLS_TST_DIR};${HDF5_TOOLS_ROOT_DIR}/lib;${HDF5_SRC_BINARY_DIR};$<$<BOOL:${HDF5_ENABLE_PARALLEL}>:${MPI_C_INCLUDE_DIRS}>")
endif()
if (HDF5_BUILD_STATIC_TOOLS)
TARGET_C_PROPERTIES(${tool}gentest STATIC)
target_link_libraries (${tool}gentest PRIVATE
${HDF5_LIB_TARGET}
${HDF5_TOOLS_LIB_TARGET}
${HDF5_REQUIRED_LIBRARIES} # For math lib
${HDF5_TEST_LIB_TARGET}
)
else ()
TARGET_C_PROPERTIES(${tool}gentest SHARED)
target_link_libraries (${tool}gentest PRIVATE
${HDF5_LIBSH_TARGET}
${HDF5_TOOLS_LIBSH_TARGET}
${HDF5_REQUIRED_LIBRARIES}
${HDF5_TEST_LIBSH_TARGET}
)
endif ()
target_include_directories(h5gentest PRIVATE
"${HDF5_TOOLS_TEST_SOURCE_DIR}/${tool}"
)
target_link_libraries(h5gentest PRIVATE ${tool}gentest)
endforeach ()
set_target_properties (h5gentest PROPERTIES FOLDER generator/tools)
#-----------------------------------------------------------------------------
# Add Targets to clang-format
#-----------------------------------------------------------------------------
if (HDF5_ENABLE_FORMATTERS)
clang_format (HDF5_TOOLS_TEST_H5COPY_FORMAT h5gentest)
foreach(tool ${HDF5_TOOLS})
string(TOUPPER ${tool} tool_upper)
clang_format (HDF5_TOOLS_TEST_${tool_upper}_FORMAT ${tool}gentest)
endforeach()
endif ()
#add_test (NAME H5GEN-h5gentest COMMAND $<TARGET_FILE:h5gentest>)
#-- Add the h5diff tests
add_subdirectory (h5diff)
#-- Add the h5ls tests
add_subdirectory (h5ls)
#-- Misc tests
add_subdirectory (misc)
#-- Add the h5import tests
add_subdirectory (h5import)
#-- h5Repack tests
add_subdirectory (h5repack)
#-- Add the h5jam tests
add_subdirectory (h5jam)
#-- Add the h5copy tests
add_subdirectory (h5copy)
#-- Add the h5stat tests
add_subdirectory (h5stat)
#-- Add the h5dump tests
add_subdirectory (h5dump)
#-- Add the h5format_convert and test executables
add_subdirectory (h5format_convert)
#-- Add the perform tests
add_subdirectory (perform)
#-- Add the h5sign tests
# Only build h5sign tests when signed plugins are required (h5sign tool must be built)
if (HDF5_REQUIRE_SIGNED_PLUGINS)
add_subdirectory (h5sign)
endif ()