Skip to content

✨[Feature] Digital Signature Verification for HDF5 Plugins#6198

Open
brtnfld wants to merge 167 commits intodevelopfrom
feature/dig_sig_ver
Open

✨[Feature] Digital Signature Verification for HDF5 Plugins#6198
brtnfld wants to merge 167 commits intodevelopfrom
feature/dig_sig_ver

Conversation

@brtnfld
Copy link
Copy Markdown
Collaborator

@brtnfld brtnfld commented Feb 4, 2026

Description

This PR introduces a robust security framework for digitally signing and verifying HDF5 dynamic plugins (filters). This feature ensures that the HDF5 library loads only trusted, unmodified plugins, significantly enhancing security in environments where plugins are distributed dynamically.

Key Features

1. Plugin Signature Verification

  • Mechanism: Implements an append-style signature verification where RSA signatures are attached to the plugin binary footer. This allows signed plugins to remain compatible with standard system loaders while enabling cryptographic verification by HDF5.
  • Crypto: Utilizes OpenSSL (1.1.0+) for RSA signature verification (SHA-256, SHA-384, SHA-512 supported).
  • Key Management: Introduces a "KeyStore" concept. Public keys can be loaded from:
    • A configured directory (HDF5_PLUGIN_KEYSTORE_DIR).
    • An environment variable (HDF5_PLUGIN_KEYSTORE).
    • A compile-time embedded key (fallback).
  • Performance: Implements an internal signature cache to prevent redundant verification of the same plugin file, ensuring minimal performance impact after the first load.
  • Revocation: Adds support for a revocation list (blocklist) to reject specific known-bad signatures.

2. New Tool: h5sign

  • Added a new command-line tool, h5sign, located in tools/src/h5sign.
  • Allows plugin developers to sign their binaries using a private key.
  • Supports verification mode to check existing signatures.

3. Build & Configuration Changes

  • New CMake Option: HDF5_REQUIRE_SIGNED_PLUGINS (Default: OFF). When enabled, HDF5 enforces signature verification and refuses to load unsigned or invalid plugins.
  • Dependencies: Adds OpenSSL as a required dependency when signed plugins are enabled.

4. CI/CD & Infrastructure Updates

  • New Workflow: Added .github/workflows/signed-plugins.yml to specifically test the new signature verification logic in serial and parallel configurations.

Technical Details

New Files

  • src/H5PLsig.c / .h: Core logic for reading signatures, managing the KeyStore, and performing OpenSSL verification.
  • tools/src/h5sign/: Source code for the signing utility.
  • release_docs/PLUGIN_SIGNATURE_README.md: Comprehensive documentation for developers and users regarding key generation, signing, and air-gapped environment handling.
  • test/test_plugin_signature.c: New test suite covering valid signatures, tampered binaries, and invalid keys.

Modified Files

  • src/H5PLint.c: Hooked into the plugin loading process to trigger verification before dlopen/LoadLibrary.
  • CMakeLists.txt & src/CMakeLists.txt: build logic for OpenSSL linking and new source files.
  • .github/workflows/*: CI updates

Testing

  • Added h5signverifytest and test_plugin_signature to the test suite.
  • Verified that unsigned plugins are rejected when the feature is enabled.
  • Verified that tampered plugins (bit-flipped) are rejected.
  • Verified support for multiple trusted keys in a single KeyStore.
  • Validated caching mechanisms to ensure performance.

Documentation

  • Added release_docs/PLUGIN_SIGNATURE_README.md detailing the security model, usage instructions, and best practices.

Fixes #5116

glennsong09 and others added 20 commits January 9, 2026 17:52
* Add working code to verify signed plugins.

* Committing clang-format changes

* Adding changes to test branch

* Committing clang-format changes

* Moving to repo

* Committing clang-format changes

* Make fixes

* Committing clang-format changes

* Add

* Committing clang-format changes

* Finish up security changes

* Committing clang-format changes

* Fix bad conflict

* Add last 2 snprintfs

* Add changes to code

* Committing clang-format changes

* Remove bad file validation check

* Committing clang-format changes

---------

Co-authored-by: Glenn Song <gsong@hdfgroup.org>
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Implements a signature verification cache to avoid redundant cryptographic
operations when loading the same plugin multiple times. The cache stores
verification results (success/failure) indexed by plugin path and file
modification time, enabling instant verification on cache hits while
maintaining security through mtime-based invalidation.

Implementation Details:

1. Cache Structure (H5PLsig.c):
   - H5PL_signature_cache_entry_t: path, mtime, verified status
   - Dynamic array with doubling growth strategy (initial capacity: 8)
   - Stores both positive and negative verification results

2. Cache Operations:
   - H5PL__check_signature_cache(): Check cache, validate mtime
   - H5PL__update_signature_cache(): Add/update cache entries
   - Integrated into H5PL__verify_signature_appended()
   - Cache invalidation on file modification (mtime check)

3. Code Cleanup:
   - Removed commented GPG/GPGME configuration from H5pubconf.h.in
   - Eliminated dead code since implementation uses OpenSSL

4. Test Infrastructure:
   - New test executable: h5signverifytest
   - 6 comprehensive test cases:
     * Verify signed plugin (positive test)
     * Verify unsigned plugin (negative test)
     * Verify tampered plugin (security test)
     * Cache basic functionality (performance test)
     * Cache invalidation on modification (security test)
     * Cache negative results (DoS prevention)
   - CMake integration with dependency management
   - CreateTamperedPlugin.cmake: Generate tampered plugins for testing

Files Modified:
- src/H5PLsig.c: Cache implementation and integration
- src/H5pubconf.h.in: Removed GPG comments
- tools/test/h5sign/CMakeLists.txt: Added h5signverifytest build
- tools/test/h5sign/CMakeTests.cmake: Added verification tests

Files Added:
- tools/test/h5sign/h5signverifytest.c: Comprehensive test suite
- tools/test/h5sign/CreateTamperedPlugin.cmake: Tamper test helper

Performance: Eliminates cryptographic overhead on repeated plugin loads
(cache hit returns instantly vs. full RSA signature verification).

Security: mtime-based invalidation ensures modified plugins are re-verified,
preventing cache from masking tampering. Negative result caching prevents
retry attacks on invalid plugins.

Backward Compatibility: Fully backward compatible, cache is transparent
optimization with no API changes.
Resolved conflicts by keeping HEAD implementations:
- CMakeLists.txt: Retained comprehensive KeyStore configuration with OpenSSL validation
- src/H5PLint.c: Kept refactored H5PL__verify_plugin_signature() implementation

The HEAD versions contain the latest KeyStore implementation with:
- Support for multiple trusted keys via directory
- Backward compatibility with single embedded key
- Proper OpenSSL target-based linking
- Windows support with Advapi32
- Comprehensive validation and error messages
Phase 1: Code Cleanup (Completed)
✅ Moved H5PL_MAX_PLUGIN_SIZE to file scope - The constant is now properly defined at file scope in src/H5PLsig.c:110-111 instead of inside a function with #define/#undef.

✅ Fixed misleading error message - Changed the error message at src/H5PLsig.c:1491 from referencing non-existent "h5sign --verify" to a more accurate message about signature compatibility.

Phase 2: Algorithm Agility in h5sign (Completed)
✅ Added command-line option - New -a/--algorithm option allows users to select hash algorithms: sha256, sha384, sha512, sha256-pss, sha384-pss, sha512-pss

✅ Created algorithm parser - New parse_algorithm_name() function (tools/src/h5sign/h5sign.c:283-329) validates and maps algorithm names to OpenSSL EVP functions and algorithm IDs

✅ Updated signing function - Modified sign_plugin_file() to accept hash algorithm and algorithm ID parameters, with PSS padding support

✅ Updated help text - Enhanced usage documentation with algorithm options and examples

✅ Backward compatible - SHA-256 remains the default algorithm, so existing workflows continue to work unchanged

Phase 3: Chunked I/O for Verification (Completed)
✅ Added constants - Defined H5PL_VERIFY_CHUNK_SIZE (64KB) and H5PL_MEMORY_THRESHOLD (16MB) in src/H5PLsig.c:113-117

✅ Created chunked verification helper - New H5PL__verify_with_chunked_io() function (src/H5PLsig.c:1139-1224) performs signature verification using 64KB chunks, including PSS padding support

✅ Implemented hybrid approach - Smart verification strategy:

Small files (≤16MB) + multiple keys: Reads file once into memory, verifies with all keys (optimized for speed)
Large files (>16MB) OR single key: Uses chunked I/O, reducing memory from 1GB to 64KB (optimized for memory)
Key Benefits
Algorithm Flexibility: Users can now sign plugins with SHA-384 or SHA-512 for enhanced security, or use PSS padding variants
Memory Efficiency: Large plugin verification now uses only 64KB of memory instead of up to 1GB
Performance Optimized: Small files with multiple keys still use the fast memory-optimized path
Backward Compatible: All changes are additive; existing signed plugins and workflows continue to work
PSS Padding Support: Both signing and verification now properly handle RSA-PSS padding mode
- Fix private key path in test environment: use CMAKE_BINARY_DIR
  instead of HDF5_TEST_BINARY_DIR since keys are generated in the
  top-level build directory
- Fix h5sign.c to use algorithm_id parameter instead of undefined
  HASH_ALGORITHM_ID macro in output messages
- Remove invalid DEPENDS from post-build signing command in
  SignPlugin.cmake
@brtnfld brtnfld added this to the HDF5 2.x.x milestone Feb 4, 2026
@brtnfld brtnfld added the Component - C Library Core C library issues (usually in the src directory) label Feb 4, 2026
fortnern
fortnern previously approved these changes Apr 16, 2026
bmribler
bmribler previously approved these changes Apr 17, 2026
Comment thread release_docs/CHANGELOG.md Outdated
Comment thread test/test_plugin_signature.c Outdated
jhendersonHDF
jhendersonHDF previously approved these changes Apr 21, 2026
Copy link
Copy Markdown
Collaborator

@jhendersonHDF jhendersonHDF left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor changes but otherwise I think it looks good

Co-authored-by: jhendersonHDF <jhenderson@hdfgroup.org>
@lrknox lrknox dismissed stale reviews from jhendersonHDF, bmribler, and fortnern via 3859d4f April 22, 2026 12:28
brtnfld added 2 commits April 22, 2026 08:57
The icacls block was only needed to satisfy the world-writable keystore
permission check, which has since been removed from H5PLsig.c.
Copy link
Copy Markdown
Member

@hyoklee hyoklee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add --version option that matches -V.

brtnfld and others added 3 commits April 22, 2026 10:42
… tests

Running the full test suite caused unrelated flaky tests (e.g.
MPI_TEST_t_2Gio) to fail. Scope ctest to only the signature-relevant
tests via -R "H5SIGN|H5PLUGIN-signature".
@hyoklee
Copy link
Copy Markdown
Member

hyoklee commented Apr 23, 2026

Did anyone succeed signing ZFP plugin on OpenBSD?

Copy link
Copy Markdown
Member

@hyoklee hyoklee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix ZFP plugin first and run h5sign test on ZFP later again:

[ 78%] Building C object ZFP/example/CMakeFiles/h5ex_d_zfp.dir/h5ex_d_zfp.c.o
/home/runner/work/actions/actions/hdf5_plugins/ZFP/example/h5ex_d_zfp.c:179:73: warning: format specifies type 'int' but the argument has type 'size_t' (aka 'unsigned long') [-Wformat]
  179 |             printf("   Number of parameters is %d with the value %u\n", nelmts, values_out[0]);
      |                                                ~~                       ^~~~~~
      |                                                %zu
1 warning generated.
[ 79%] Linking C executable ../../bin/h5ex_d_zfp
ld: error: unable to find library -ldl
cc: error: linker command failed with exit code 1 (use -v to see invocation)
*** Error 1 in . (ZFP/example/CMakeFiles/h5ex_d_zfp.dir/build.make:102 'bin/h5ex_d_zfp')
*** Error 2 in . (CMakeFiles/Makefile2:2538 'ZFP/example/CMakeFiles/h5ex_d_zfp.dir/all')
*** Error 2 in /home/runner/work/actions/actions/plugins-build (Makefile:166 'all': /usr/bin/make -s -f CMakeFiles/Makefile2 all)

@lrknox
Copy link
Copy Markdown
Collaborator

lrknox commented Apr 23, 2026

I don't think the OpenBSD test configuration for push/pull request enables plugins, sp it's probably not tested there. I'll take a closer look later on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Component - C Library Core C library issues (usually in the src directory) HDFG-internal Internally coded for use by the HDF Group

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

Allow only digitally signed plugins to be loaded