Test pkcs11 URI support for UEFI capsule generation. For simplicity only private key is defined in binman section as softhsm tool doesn't support certificate import (yet).
Add bintool support for p11-kit as it's needed in the test to find library path for softhsm2 module. Signed-off-by: Wojciech Dubowik <[email protected]> Reviewed-by: Simon Glass <[email protected]> --- tools/binman/btool/p11_kit.py | 21 ++++++ tools/binman/ftest.py | 66 +++++++++++++++++++ .../binman/test/351_capsule_signed_pkcs11.dts | 22 +++++++ 3 files changed, 109 insertions(+) create mode 100644 tools/binman/btool/p11_kit.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/ftest.py b/tools/binman/ftest.py index 21ec48d86fd1..a66030c7a56f 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,71 @@ 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) + + 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('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..ae93bf83936f --- /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 = "key.crt"; + + blob { + filename = "capsule_input.bin"; + }; + }; + }; +}; -- 2.47.3

