Test pkcs11 URI support for UEFI capsule generation. Both public certificate and private key are used over pkcs11 protocol. Pkcs11-tool has been introduced as softhsm tool doesn't have functionality to import certificates in commonly distributed version (only in the latest).
Signed-off-by: Wojciech Dubowik <[email protected]> Reviewed-by: Simon Glass <[email protected]> --- tools/binman/btool/p11_kit.py | 21 ++++++ tools/binman/btool/pkcs11_tool.py | 21 ++++++ tools/binman/ftest.py | 73 +++++++++++++++++++ .../binman/test/351_capsule_signed_pkcs11.dts | 22 ++++++ 4 files changed, 137 insertions(+) create mode 100644 tools/binman/btool/p11_kit.py create mode 100644 tools/binman/btool/pkcs11_tool.py create mode 100644 tools/binman/test/351_capsule_signed_pkcs11.dts diff --git a/tools/binman/btool/p11_kit.py b/tools/binman/btool/p11_kit.py new file mode 100644 index 000000000000..9d8d5d848b44 --- /dev/null +++ b/tools/binman/btool/p11_kit.py @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright 2026 Mettler Toledo Technologies GmbH +# +"""Bintool implementation for p11-kit""" + +from binman import bintool + + +class Bintoolp11_kit(bintool.Bintool): + """p11-kit -- support tool for pkcs#11 libraries""" + def __init__(self, name): + super().__init__('p11-kit', + 'Pkcs11 library modules tool', + version_args='list modules') + + def fetch(self, method): + """Install p11-kit via APT """ + if method != bintool.FETCH_BIN: + return None + + return self.apt_install('p11-kit') diff --git a/tools/binman/btool/pkcs11_tool.py b/tools/binman/btool/pkcs11_tool.py new file mode 100644 index 000000000000..673c0ea0ac35 --- /dev/null +++ b/tools/binman/btool/pkcs11_tool.py @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright 2026 Mettler Toledo Technologies GmbH +# +"""Bintool implementation for pkcs11-tool""" + +from binman import bintool + + +class Bintoolpkcs11_tool(bintool.Bintool): + """pkcs11-tool -- support tool for managing pkcs#11 tokens""" + def __init__(self, name): + super().__init__('pkcs11-tool', + 'PKCS #11 tokens managing tool', + version_args='--show-info') + + def fetch(self, method): + """Install opensc via APT """ + if method != bintool.FETCH_BIN: + return None + + return self.apt_install('opensc') diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index a53e37f31b3e..d47364162188 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -7,6 +7,7 @@ # python -m unittest func_test.TestFunctional.testHelp import collections +import configparser import glob import gzip import hashlib @@ -7532,6 +7533,78 @@ fdt fdtmap Extract the devicetree blob from the fdtmap self._CheckCapsule(data, signed_capsule=True) + def testPkcs11SignedCapsuleGen(self): + """Test generation of EFI capsule (with PKCS11)""" + data = tools.read_file(self.TestFile("key.key")) + private_key = self._MakeInputFile("key.key", data) + data = tools.read_file(self.TestFile("key.pem")) + cert_file = self._MakeInputFile("key.crt", data) + + softhsm2_util = bintool.Bintool.create('softhsm2_util') + self._CheckBintool(softhsm2_util) + + pkcs11_tool = bintool.Bintool.create('pkcs11-tool') + self._CheckBintool(pkcs11_tool) + + prefix = "testPkcs11SignedCapsuleGen." + # Configure SoftHSMv2 + data = tools.read_file(self.TestFile('340_softhsm2.conf')) + softhsm2_conf = self._MakeInputFile(f'{prefix}softhsm2.conf', data) + softhsm2_tokens_dir = self._MakeInputDir(f'{prefix}softhsm2.tokens') + + with open(softhsm2_conf, 'a') as f: + f.write(f'directories.tokendir = {softhsm2_tokens_dir}\n') + + # Find the path to softhsm2 library + p11_kit = bintool.Bintool.create('p11-kit') + self._CheckBintool(p11_kit) + + p11_kit_config = configparser.ConfigParser() + out = tools.run('p11-kit', 'print-config') + p11_kit_config.read_string(out) + softhsm2_lib = p11_kit_config.get('softhsm2', 'module', + fallback=None) + self.assertIsNotNone(softhsm2_lib) + + with unittest.mock.patch.dict('os.environ', + {'SOFTHSM2_CONF': softhsm2_conf, + 'PKCS11_MODULE_PATH': softhsm2_lib}): + tools.run('softhsm2-util', '--init-token', '--free', '--label', + 'U-Boot token', '--pin', '1111', '--so-pin', + '222222') + tools.run('pkcs11-tool', '--module', softhsm2_lib, + '--write-object', cert_file, '--pin', '1111', + '--type', 'cert', '--id', '999999', '--label', + 'test_cert', '--login') + tools.run('softhsm2-util', '--import', private_key, '--token', + 'U-Boot token', '--label', 'test_key', '--id', '999999', + '--pin', '1111') + data = self._DoReadFile('351_capsule_signed_pkcs11.dts') + + self._CheckCapsule(data, signed_capsule=True) + + hdr = self._GetCapsuleHeaders(data) + monotonic_count = hdr['EFI_FIRMWARE_IMAGE_AUTH.MONOTONIC_COUNT'] + + # UEFI standard requires that signature is checked over payload followed + # by a monotonic count as little endian 64-bit integer. + sig_input = self._MakeInputFile("sig_input", EFI_CAPSULE_DATA) + with open(sig_input, 'ab') as f: + f.write(struct.pack('<Q', int(monotonic_count, 16))) + + # Verify dumped capsule signature dumped by meficapsule during + # generation + openssl = bintool.Bintool.create('openssl') + self._CheckBintool(openssl) + openssl_args = ['smime', '-verify', '-inform', 'DER', + '-in', tools.get_output_filename('capsule.efi-capsule.p7'), + '-content', sig_input, '-CAfile', cert_file, + '-no_check_time', + '-out', tools.get_output_filename('decoded-capsule.bin')] + result = openssl.run_cmd_result(*openssl_args) + self.assertIsNotNone(result.stdout) + self.assertIn('Verification successful', result.stderr) + def testCapsuleGenVersionSupport(self): """Test generation of EFI capsule with version support""" data = self._DoReadFile('313_capsule_version.dts') diff --git a/tools/binman/test/351_capsule_signed_pkcs11.dts b/tools/binman/test/351_capsule_signed_pkcs11.dts new file mode 100644 index 000000000000..bb87e18a15fe --- /dev/null +++ b/tools/binman/test/351_capsule_signed_pkcs11.dts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + binman { + efi-capsule { + image-index = <0x1>; + /* Image GUID for testing capsule update */ + image-guid = "binman-test"; + hardware-instance = <0x0>; + monotonic-count = <0x1>; + dump-signature; + private-key = "pkcs11:token=U-Boot%20token;object=test_key;type=private;pin-value=1111"; + public-key-cert = "pkcs11:token=U-Boot%20token;object=test_cert;type=cert;pin-value=1111"; + + blob { + filename = "capsule_input.bin"; + }; + }; + }; +}; -- 2.47.3

