[PATCH v4] binman: x509_cert: add PKCS#11/HSM signing support

Sergio Prado sergio.prado at e-labworks.com
Mon May 25 12:27:12 CEST 2026


Hi Quentin,

On 5/20/26 08:20 PM, Quentin Schulz wrote:
> > To run signing non-interactively, the PKCS11_PIN environment variable
> > can be set; its value is appended to the URI as ?pin-value=<pin> (or
> > &pin-value=<pin> when the URI already contains '?'), so the PIN does
> > not have to be embedded in BINMAN_X509_KEY_URI.
>
> It'd be nice to specify in the commit log the recommended way is to pass
> the pin via pkcs11-module-token-pin in OPENSS_CONF file.

Will add that to the commit message and call it out as the recommended
path, with PKCS11_PIN as the fallback.

> > +BINMAN_X509_KEY_URI
> > +    URI of a key used to sign x509 certificate entries via an HSM
instead of a
> > +    PEM key file on disk. When set, it is passed as ``-a
x509-key-uri=<uri>``
> > +    to binman, which overrides the ``keyfile`` entry argument for all
x509
> > +    certificate signing operations.
> > +
>
> Can't we reuse keyfile directly? keyfile can then point either at a file
> on disk or be an OpenSSL provider URI? This would limit the required
> changes in logic. It's piggy-backing on keyfile variable whose name
> doesn't indicate it should support provider URI and maybe I'm trying to
> fit something where it shouldn't.

Hmmm, I don't have a strong opinion on this, and indeed reusing the keyfile
argument would simplify even more the implementation. Will move on with
this change.

> > +    This only applies to x509 certificate entries (e.g. TI K3 secure
boot). It
> > +    does not affect FIT image signing, which uses device tree
properties such as
> > +    ``fit,engine`` and ``key-name-hint`` instead.
> > +
> > +    The URI is currently a PKCS#11 URI (RFC 7512). PKCS#11 signing
requires
>
> Rephrase maybe to something like
>
> """
> URIs that are currently supported are:
> - PKCS#11 URI (RFC 7512)
>
> PKCS#11 signing requires...
> """
>
> The wording is a bit odd currently but maybe you have something better
> to suggest?

Right. Will think about a better way to rephrase this.

> > +    OpenSSL 3.x. The provider or engine and the PKCS#11 module must be
> > +    configured externally via an ``openssl.cnf`` file. Either rely on
the
> > +    system default (``/etc/ssl/openssl.cnf``) or point to a custom
file via
> > +    ``OPENSSL_CONF``.
> > +
> > +    Two URI forms are supported on OpenSSL 3.x:
> > +
> > +    1. Provider path (recommended) — requires the pkcs11 provider, e.g.
> > +       ``pkcs11-provider``::
>
> The syntax is confusing here, is pkcs11-provider the provider path, or
> the required pkcs11 provider.
>
> It's the latter, so I can suggest:
>
> """
> e.g. via the ``pkcs11-provider`` package::
> """
>
> What do you think?

Makes sense. Will update.

> > +    To run signing non-interactively, set the ``PKCS11_PIN``
environment
> > +    variable. Its value is appended to the URI as ``?pin-value=<pin>``
so the
> > +    PIN does not have to be embedded in ``BINMAN_X509_KEY_URI``::
> > +
> > +        PKCS11_PIN=1234 make BINMAN_X509_KEY_URI="pkcs11:..." \
> > +                             OPENSSL_CONF=/path/to/openssl.cnf
> > +
> > +    Note: ``PKCS11_PIN`` keeps the PIN out of the ``make`` command
line and
> > +    shell history, but the PIN is still passed to ``openssl`` as part
of the
>
> Not sure to understand how PKCS11_PIN is kept out of shell history?

You are right. I had a different context in mind, such as building inside a
controlled build system, but even in that case the variable could still end
up in log files. I will rephrase that.

> >       def ReadNode(self):
> >           super().ReadNode()
> > @@ -61,6 +80,8 @@ class Entry_x509_cert(Entry_collection):
> >           self.key_fname = self.GetEntryArgsOrProps([
> >               EntryArg('keyfile', str)], required=True)[0]
>
> Well... we'll override this with x509-key-uri if present, so why should
> this be required?

Moot once we unify under keyfile - keyfile stays required, and the URI form
is just a different value for it.

> > +        if pkcs11_provider is None:
> > +            self.skipTest('OpenSSL pkcs11 provider module not found')
> > +
>
> Can you explain why you're trying to find the module path? I don't think
> we need to know it?
>
> If you want to check whether it's present,
>
> openssl list -providers -provider pkcs11
>
> will fail if not present, otherwise succeeds.

Yeah, that makes sense. Will do it.

> > +[pkcs11_sect]
> > +module = {pkcs11_provider}
> > +pkcs11-module-path = {softhsm2_lib}4
>
> Why do you need those two lines? It doesn't seem to be required for me
> with my local work on supporting signing FIT images in binman with
> PKCS11 provider. I have the following:
>
> """
> openssl_conf = openssl_init
>
> [openssl_init]
> providers = providers_section
>
> [providers_section]
> default = default_provider
> pkcs11 = pkcs11_provider
>
> [default_provider]
> activate=1
>
> [pkcs11_provider]
> activate = 1
> """
>
> This would also allow you to simply have this config file in-tree
> instead of generating it like for
> tools/binman/test/fit/openssl_provider.conf, this is not a requirement
> though, it's just what I've done for signing FIT images with engines
> (and what I'll do for providers).

Indeed, I tested locally and it works without them. Will remove.

> > +            # softhsm2-util cannot generate keys (only --import), so
use
> > +            # pkcs11-tool to generate the RSA keypair directly in the
token.
> > +            tools.run('pkcs11-tool', '--module', softhsm2_lib,
> > +                      '--token-label', 'x509-test', '--login',
'--pin', pin,
> > +                      '--keypairgen', '--key-type', 'rsa:2048',
> > +                      '--label', 'testkey', '--id', '01')
> > +
>
> Please use a file so we can run this test as fast as possible. We don't
> care if the key is truly private for tests. Can you use
> tools/binman/test/fit/rsa2048.key for example?

Will do.

>
> > +        entry_args = {
> > +            'keyfile': self.TestFile('security/key.key'),
>
> Please add a small comment that this is added to make sure we override
> the argument with x509-key-uri and that it has no other purpose than that.

Will add - the wording shifts slightly under the unified keyfile, since
there's no separate "override" to demonstrate; the test will confirm
keyfile accepts a pkcs11: URI. I'll keep an explicit comment along those
lines.

Thanks for reviewing!

Regards,

Sergio Prado


More information about the U-Boot mailing list