mirror of
https://github.com/HDFGroup/hdf5.git
synced 2026-09-25 04:09:44 +03:00
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>
104 lines
3.7 KiB
CMake
104 lines
3.7 KiB
CMake
#
|
|
# Copyright by The HDF Group.
|
|
# All rights reserved.
|
|
#
|
|
# This file is part of HDF5. The full HDF5 copyright notice, including
|
|
# terms governing use, modification, and redistribution, is contained in
|
|
# the LICENSE file, which can be found at the root of the source code
|
|
# distribution tree, or in https://www.hdfgroup.org/licenses.
|
|
# If you do not have access to either file, you may request a copy from
|
|
# help@hdfgroup.org.
|
|
#
|
|
# runTest.cmake executes a command and captures the output in a file. File is then compared
|
|
# against a reference file. Exit status of command can also be compared.
|
|
cmake_policy(SET CMP0007 NEW)
|
|
cmake_policy(SET CMP0053 NEW)
|
|
|
|
# arguments checking
|
|
if (NOT TEST_PROGRAM) #the program to be run
|
|
message (FATAL_ERROR "Require TEST_PROGRAM to be defined")
|
|
endif ()
|
|
if (NOT TEST_FOLDER) # this is the folder where the test program is run
|
|
message (FATAL_ERROR "Require TEST_FOLDER to be defined")
|
|
endif ()
|
|
if (NOT TEST_OUTPUT) # the output file to capture the test program output
|
|
message (FATAL_ERROR "Require TEST_OUTPUT to be defined")
|
|
endif ()
|
|
if (NOT DEFINED TEST_EXPECT)
|
|
message (VERBOSE "Optional TEST_EXPECT is not defined")
|
|
endif ()
|
|
|
|
message (STATUS "ARGS: ${TEST_EMULATOR}/'${TEST_JAVA}' ${TEST_PROGRAM} ${TEST_ARGS}")
|
|
|
|
include (${CMAKE_CURRENT_LIST_DIR}/runExecute.cmake)
|
|
|
|
EXECUTE_TEST (TEST_FOLDER ${TEST_FOLDER}
|
|
TEST_JAVA ${TEST_JAVA}
|
|
TEST_PROGRAM ${TEST_PROGRAM}
|
|
TEST_ARGS ${TEST_ARGS}
|
|
TEST_EMULATOR ${TEST_EMULATOR}
|
|
TEST_OUTPUT ${TEST_OUTPUT}
|
|
TEST_EXPECT ${TEST_EXPECT}
|
|
TEST_LIBRARY_DIRECTORY ${TEST_LIBRARY_DIRECTORY}
|
|
TEST_ENV_VAR ${TEST_ENV_VAR}
|
|
TEST_ENV_VALUE ${TEST_ENV_VALUE}
|
|
TEST_KEYSTORE_DIR ${TEST_KEYSTORE_DIR}
|
|
TEST_INPUT ${TEST_INPUT}
|
|
TEST_CLASSPATH ${TEST_CLASSPATH}
|
|
TEST_NOERRDISPLAY ${TEST_NOERRDISPLAY}
|
|
)
|
|
|
|
FILTER_TEST (TEST_OUTPUT ${TEST_OUTPUT}
|
|
TEST_FOLDER ${TEST_FOLDER}
|
|
TEST_NO_DISPLAY ${TEST_NO_DISPLAY}
|
|
TEST_REGEX ${TEST_REGEX}
|
|
TEST_ERRREF ${TEST_ERRREF}
|
|
TEST_REFERENCE ${TEST_REFERENCE}
|
|
TEST_MATCH ${TEST_MATCH}
|
|
TEST_MASK_ERROR ${TEST_MASK_ERROR}
|
|
TEST_FILTER ${TEST_FILTER}
|
|
TEST_FILTER_REPLACE ${TEST_FILTER_REPLACE}
|
|
TEST_REF_FILTER ${TEST_REF_FILTER}
|
|
)
|
|
|
|
COMPARE_TEST (TEST_OUTPUT ${TEST_OUTPUT}
|
|
TEST_FOLDER ${TEST_FOLDER}
|
|
TEST_GREP_EXPECT ${TEST_GREP_EXPECT}
|
|
TEST_REFERENCE ${TEST_REFERENCE}
|
|
TEST_ERRREF ${TEST_ERRREF}
|
|
TEST_SKIP_COMPARE ${TEST_SKIP_COMPARE}
|
|
TEST_SORT_COMPARE ${TEST_SORT_COMPARE}
|
|
TEST_GREP_COMPARE ${TEST_GREP_COMPARE}
|
|
TEST_GREP_FILTER ${TEST_GREP_FILTER}
|
|
)
|
|
|
|
# dump the output unless nodisplay option is set
|
|
if (TEST_SKIP_COMPARE AND NOT TEST_NO_DISPLAY AND EXISTS "${TEST_FOLDER}/${TEST_OUTPUT}")
|
|
file (READ ${TEST_FOLDER}/${TEST_OUTPUT} TEST_STREAM)
|
|
execute_process (
|
|
COMMAND ${CMAKE_COMMAND} -E echo ${TEST_STREAM}
|
|
RESULT_VARIABLE TEST_RESULT
|
|
)
|
|
endif ()
|
|
|
|
# Check if the output files should not be removed
|
|
if (NOT DEFINED ENV{HDF5_NOCLEANUP})
|
|
if (EXISTS "${TEST_FOLDER}/${TEST_OUTPUT}" AND NOT TEST_SAVE)
|
|
file (REMOVE ${TEST_FOLDER}/${TEST_OUTPUT})
|
|
endif ()
|
|
|
|
if (EXISTS "${TEST_FOLDER}/${TEST_OUTPUT}.err")
|
|
file (REMOVE ${TEST_FOLDER}/${TEST_OUTPUT}.err)
|
|
endif ()
|
|
|
|
if (TEST_DELETE_LIST)
|
|
foreach (dfile in ${TEST_DELETE_LIST})
|
|
file (REMOVE ${dfile})
|
|
endforeach ()
|
|
endif ()
|
|
endif ()
|
|
|
|
# everything went fine...
|
|
message (STATUS "${TEST_PROGRAM} Passed")
|
|
|