Repository navigation
Add an option to link a static wolfSSL into libwolfpkcs11 - #258
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
🔵 Needs a closer look
Cryptographic symbol isolation and cross-build packaging require human validation of linker compatibility and interoperability results.
No open issues 🎉
What changed in this PR
Adds optional static wolfSSL embedding so libwolfpkcs11 can operate without a runtime libwolfssl dependency.
Changes:
- Adds Autotools and CMake options with symbol isolation and dependency-free package metadata.
- Corrects public symbol visibility and interoperability test initialization.
- Adds CI coverage for static embedding and installed-package consumers.
| File | Description |
|---|---|
| wolfpkcs11/pkcs11.h | Exports v3.0 and v3.2 functions. |
| tests/wolfssl-interoperability/pkcs11_interop.c | Initializes wolfCrypt and preserves the module handle. |
| tests/wolfssl-interoperability/Makefile | Supports external modules and checks dependencies. |
| tests/include.am | Excludes allocator-sensitive tests in embedded mode. |
| src/include.am | Adds isolation flags and archive dependency. |
| README.md | Documents static embedding requirements and usage. |
| configure.ac | Adds static embedding configuration and fixes install paths. |
| CMakeLists.txt | Adds embedding, hidden visibility, and debug-test skipping. |
| cmake/wolfpkcs11Targets.cmake.in | Omits the embedded wolfSSL link dependency. |
| cmake/wolfpkcs11Config.cmake.in | Skips wolfSSL discovery for embedded builds. |
| cmake/consumer/main.c | Checks installed API access. |
| cmake/consumer/CMakeLists.txt | Builds an installed-package consumer. |
| .github/workflows/static-wolfssl.yml | Tests both build systems, isolation, and packaging. |
Review effort: Balanced
The autotools build compiles with -fvisibility=hidden and gets HAVE_VISIBILITY from gl_VISIBILITY, so WP11_LOCAL functions stay out of the dynamic symbol table. The CMake build set neither, so libwolfpkcs11.so exported about 200 internal functions next to the PKCS#11 API. Build the library with hidden visibility on GCC and Clang and define HAVE_VISIBILITY. The PKCS#11 v3.0 and v3.2 functions were declared without WP11_API, so hidden visibility would drop them, and the autotools build did not export them either. Declare them with WP11_API so both builds export the whole C_* API and nothing else. Also register debug_test with skip code 77. It exits 77 when DEBUG_WOLFPKCS11 is not defined, and CTest counted that as a failure, so ctest failed on every non-debug CMake build.
The test never called wolfCrypt_Init() itself. It only worked because the module, linked against the same libwolfcrypt, called wolfCrypt_Init() in C_Initialize and so set up the crypto callback table on the test's behalf. Against a module with its own wolfSSL, wc_CryptoCb_RegisterDevice() fails with BUFFER_E. Initialize and clean up wolfCrypt in main(). The test binary no longer links the module, which it only loads through wc_Pkcs11_Initialize(), and WOLFPKCS11_MODULE selects the module to test, defaulting to the one the Makefile builds. The debug probe now keeps its handle open until cleanup. Closing it right away unloaded the module whenever nothing else held it, which reset the debug flag before wc_Pkcs11_Initialize() loaded the module again, so the debug build of the module never logged. The test and debug targets refuse a module that depends on libwolfssl. Its wolfSSL calls would bind to the test's own wolfCrypt build, which has a different configuration, and crash.
--with-static-wolfssl=FILE (autotools) and WOLFPKCS11_STATIC_WOLFSSL (CMake) link a static, position independent libwolfssl into the shared library, so it has no run time dependency on libwolfssl. Both need an ELF linker, accept only a static wolfSSL and build only the shared library. The wolfSSL symbols are hidden with --exclude-libs,ALL. Without that the embedded wolfSSL exports its whole API, and in a process that already has a libwolfssl.so, such as a wolfSSL application loading the module through wc_Pkcs11_Initialize(), the module's calls bind to the application's copy even though it is loaded with RTLD_LOCAL. With a different wolfSSL configuration that crashes. -Bsymbolic also binds the module's own C_* functions to itself, and -z text turns text relocations from an archive built without PIC into a link error. -z defs does the same for a wolfSSL function missing from the archive, which the loader would otherwise resolve against the application's libwolfssl. It also rules out sanitizer builds whose runtime is not linked into shared objects, such as clang's AddressSanitizer. The archive comes first in LIBS, so libraries it needs can follow it, and the library is relinked when the archive changes. The installed CMake package and the wolfpkcs11-config script no longer refer to wolfssl in this mode. wolfTPM support is rejected in this mode, because libwolftpm links its own wolfSSL and the TPM crypto callback would be registered there rather than in the copy the module uses. Eleven tests set allocators with wolfSSL_SetAllocators() to inject allocation failures, track allocations or inspect freed memory. In this mode that call configures the test's own wolfSSL rather than the module's, so these tests are not run. The default build still runs them. A new workflow builds both variants against a static wolfSSL, checks that the library has no libwolfssl dependency or text relocations and exports only C_* functions, including the v3.0 ones, then runs the tests and the wolfSSL interop test against it.
configure expands libdir and includedir into WOLFPKCS11_LIBDIR_ABS and WOLFPKCS11_INCLUDEDIR_ABS for the installed wolfpkcs11Targets.cmake. It did so while prefix and exec_prefix still held NONE, because autoconf only applies the default prefix when it writes config.status. Without --prefix the package therefore pointed at NONE/lib and NONE/include, and find_package(wolfpkcs11) failed on the missing include directory. Expand them with the default prefix in place and restore both variables afterwards.
Nothing in CI installed wolfPKCS11 or used the installed package, so the static-mode changes to the CMake package files and wolfpkcs11-config, and the expanded install paths, were never exercised. Both jobs now install the library and build a small find_package(wolfpkcs11) project from cmake/consumer with no wolfSSL on the search path, then run it. The autotools job installs to the default prefix, which covers the install paths written into the package, and checks that wolfpkcs11-config --libs no longer names wolfssl.
Frauschi
force-pushed
the
static-wolfssl
branch
from
October 19, 2026 12:47
63ddcae to
3bff88c
Compare
LinuxJedi
approved these changes
Oct 19, 2026
LinuxJedi
left a comment
Member
There was a problem hiding this comment.
Good call on the pkcs11.h fixes too!
LinuxJedi
added a commit
that referenced
this pull request
Oct 21, 2026
* Set the version to 2.2.0 in configure.ac, CMakeLists.txt, the Doxyfiles and version.h, and add a Debian changelog entry. * Bump the shared library version to 4.1.0, as the autotools build now exports the PKCS#11 v3.0 and v3.2 functions (PR #258). * Add the 2.2 release notes to README.md, covering PR #203 through PR #259.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a build option that links a static wolfSSL into
libwolfpkcs11.so, so the module ships as one library with no run-time dependency onlibwolfssl. The embedded wolfSSL is hidden, so an application that uses its own wolfSSL, even one built with a different configuration, can still load the module throughdlopen()orwc_Pkcs11_Initialize().--with-static-wolfssl=/path/to/libwolfssl.a-DWOLFPKCS11_STATIC_WOLFSSL=yesagainst a wolfSSL built with-DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ONThe default build is unchanged.
How it works
--exclude-libs,ALL, so none of the wolfSSL symbols are exported. Without it, the module's wolfSSL calls bind to the application'slibwolfssl.sodespiteRTLD_LOCAL, which crashes when the two configurations differ.-Bsymbolicbinds the module's ownC_*calls to itself.-z textand-z defsturn a non-PIC archive or a function missing from the archive into a link error, instead of a module that quietly resolves against the host's wolfSSL.libwolftpmlinks its own wolfSSL and the TPM crypto callback would be registered in the wrong copy.wolfpkcs11-configno longer refer to wolfSSL.Fixes found along the way
HAVE_VISIBILITY.C_LoginUser,C_Message*,C_EncapsulateKey, ...), because their prototypes lackedWP11_API. Both builds now export the same 92C_*functions and nothing else.debug_testexits 77 in non-debug builds, and CTest counted that as a failure. It is now registered with skip code 77.NONE/includewhen configure ran without--prefix, sofind_package(wolfpkcs11)failed. The install paths are now expanded with the default prefix.wolfCrypt_Init()and only worked because the module did it on the shared libwolfcrypt. It now initializes wolfCrypt itself, loads the module only throughwc_Pkcs11_Initialize(), and takes the module to test fromWOLFPKCS11_MODULE. The debug probe also no longer unloads the module before the test loads it, so a debug module logs again.Tests
static-wolfssl.ymlworkflow with an autotools job and a CMake job. Each builds against a static wolfSSL and checks that the library has nolibwolfssldependency and no text relocations, and that it exports onlyC_*(including the v3.0 entry points). It then runs the test suite and the wolfSSL interop test against the library, installs it, and builds and runs a smallfind_package(wolfpkcs11)consumer with no wolfSSL on the search path.wolfSSL_SetAllocators(). In static mode that call reaches the test's wolfSSL, not the module's, so these tests are built but not run there. The default build still runs them.testtarget refuses an externalWOLFPKCS11_MODULEthat depends onlibwolfssl. The check usesreadelfand is skipped for the default in-tree module, so the default interop test still runs without binutils.