[PATCH v3 0/2] binman: add PKCS#11/HSM signing support for X509 certificates

Sergio Prado sergio.prado at e-labworks.com
Thu Apr 23 17:45:34 CEST 2026


Motivation
----------

TI K3 secure boot requires X509 certificates to be signed with a private
key at build time. Until now, binman expected this key to be present as a
plain PEM file on the build host. For production use, however, private keys
should never exist unprotected on a build machine — they belong inside a
Hardware Security Module (HSM) that enforces access control and keeps the
key material unexportable.

This series adds support for signing X509 certificates via any PKCS#11-
capable HSM (YubiKey, TPM, network HSM, SoftHSM2 for development, etc.).

Design
------

Two new make variables are the sole user-visible interface:

  BINMAN_PKCS11_URI    PKCS#11 URI of the signing key on the HSM, e.g.
                       pkcs11:token=mytoken;object=mykey;type=private
  BINMAN_PKCS11_MODULE Path to the PKCS#11 shared library (.so), e.g.
                       /usr/lib/softhsm/libsofthsm2.so (optional when the
                       module is already configured via openssl.cnf or
                       PKCS11_MODULE_PATH)

When BINMAN_PKCS11_URI is set, binman replaces the on-disk keyfile with
the URI at signing time. The PKCS11_PIN environment variable can be used
to supply the token PIN non-interactively; it is appended as a
pin-value=<pin> query parameter to the URI.

The openssl bintool auto-detects which OpenSSL PKCS#11 interface to use:

 - If the pkcs11 provider is loaded (OpenSSL >= 3.1 + pkcs11-provider),
   it uses -provider default -provider pkcs11.
 - Otherwise it falls back to the legacy libp11 engine
   (-engine pkcs11 -keyform engine).

Detection is done once via 'openssl list -providers' and the result is
cached, so there is no per-signing subprocess overhead.

Testing
-------

Tested on a Toradex Verdin AM62 (verdin-am62_a53_defconfig) board with
both legacy engine path and pkcs11 provider path using SoftHSM2 and
YubiKey 5 NFC.

A subtle issue was discovered during testing: binman uses a
ThreadPoolExecutor internally (etype/section.py) and may call multiple
ObtainContents() methods concurrently even under make -j1. SoftHSM2 and
some real HSMs do not support simultaneous logins from different threads,
which caused intermittent "login failed" and "object not found" errors
during multi-certificate builds. To fix it, a module-level threading.Lock
was used to serialise all PKCS#11 signing calls.

Test coverage: btool/openssl.py and etype/x509_cert.py remain at 100%
(verified with 'binman test -T').

Changes in v3:
- Split into two patches: bintool infrastructure (1/2) and x509_cert
  feature (2/2)
- Fix global environment mutation: _run_cmd_pkcs11() no longer writes to
  os.environ directly; it now uses the new extra_env parameter so module
  paths are scoped to the subprocess only, which is both cleaner and safe
  under concurrent execution
- Add module-level threading.Lock to serialise concurrent PKCS#11 signing
  calls and fix intermittent login failures caused by binman's
  ThreadPoolExecutor
- Fix URI query string separator: use '&' when the URI already contains
  '?' (e.g. module-path already present), '?' otherwise
- Test cases updated

Changes in v2:
- Add tests for _build_key_args() (PEM path, PKCS#11 provider, PKCS#11
  engine, PIN appending), _pkcs11_use_provider() (caching),
  _run_cmd_pkcs11() (with and without module path), and end-to-end
  x509_cert signing with a PKCS#11 URI (testX509CertPkcs11), ensuring
  btool/openssl.py and etype/x509_cert.py have 100% test coverage

Sergio Prado (2):
  binman: bintool: add extra_env parameter to run_cmd
  binman: x509_cert: add PKCS#11/HSM signing support

 Makefile                        |   2 +
 tools/binman/binman.rst         |  18 +++++
 tools/binman/bintool.py         |  15 +++-
 tools/binman/btool/openssl.py   | 117 +++++++++++++++++++++++++++-----
 tools/binman/etype/x509_cert.py |  47 +++++++++++--
 tools/binman/ftest.py           | 110 ++++++++++++++++++++++++++++++
 6 files changed, 286 insertions(+), 23 deletions(-)

-- 
2.34.1


More information about the U-Boot mailing list