Skip to content

Add an option to link a static wolfSSL into libwolfpkcs11 - #5

Closed
Frauschi wants to merge 5 commits into
masterfrom
claude/wolfpkcs11-static-wolfssl-cqcov3
Closed

Frauschi wants to merge 5 commits into
masterfrom
claude/wolfpkcs11-static-wolfssl-cqcov3

Conversation

@Frauschi

Copy link
Copy Markdown
Owner

Adds an opt-in build of libwolfpkcs11.so with a static, hidden wolfSSL inside. The module then has no run time dependency on libwolfssl and can be loaded by an application that uses its own, differently configured wolfSSL.

  • --with-static-wolfssl=FILE (autotools) and WOLFPKCS11_STATIC_WOLFSSL (CMake) link a PIC libwolfssl.a with --exclude-libs,ALL -Bsymbolic -z text -z defs, so only the C_* API is exported.
  • CMake builds with hidden visibility, and the PKCS#11 v3.0/v3.2 functions are declared WP11_API, so both build systems export the full C_* API and nothing else.
  • The wolfSSL interop test initializes wolfCrypt itself and runs against any module given in WOLFPKCS11_MODULE.
  • configure no longer writes NONE/lib and NONE/include into the installed CMake package when run without --prefix.
  • debug_test counts as skipped in non-debug CMake builds.

Testing

  • New static-wolfssl.yml workflow. Its autotools and CMake jobs each build against a static wolfSSL and check that the library has no libwolfssl dependency or text relocations and exports only C_*. They then run make check/ctest and the interop test, install the library, and build a find_package(wolfpkcs11) consumer with no wolfSSL present.

Generated by Claude Code

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 Frauschi closed this Oct 19, 2026
@Frauschi
Frauschi deleted the claude/wolfpkcs11-static-wolfssl-cqcov3 branch October 19, 2026 09:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant