Hi Wojciech,

On 1/20/26 9:12 AM, Wojciech Dubowik wrote:
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).

Signed-off-by: Wojciech Dubowik <[email protected]>
Reviewed-by: Simon Glass <[email protected]>
---
  tools/binman/ftest.py                         | 53 +++++++++++++++++++
  .../binman/test/351_capsule_signed_pkcs11.dts | 22 ++++++++
  2 files changed, 75 insertions(+)
  create mode 100644 tools/binman/test/351_capsule_signed_pkcs11.dts

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 21ec48d86fd1..a005a167e414 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,58 @@ 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')
+        tools.write_file(softhsm2_conf, data +
+                         f'\ndirectories.tokendir = \
+                         {softhsm2_tokens_dir}\n'.encode("utf-8"))
+

data is already in softhsm2_conf due to calling
self._MakeInputFile(f'{prefix}softhsm2.conf', data)
you can simply do the same I did in testFitSignPKCS11Simple and append to the file. Or you can append to data before you call _MakeInputFile().

+        p11_kit_config = configparser.ConfigParser()
+        out = tools.run('p11-kit', 'print-config')

Please create a bintool and call CheckBintool so we can skip the test if p11-kit isn't installed. It'll be a bit awkward because there's no --version, --help, to print the help text but not have a non-zero exit code.

+        p11_kit_config.read_string(out)
+        softhsm2_lib = p11_kit_config['softhsm2']['module']
+

We probably want to have some try..except here, or a more forgiving .get('softhsm2', {}).get('module')
and fail the test if we don't get a path?

+        os.environ['SOFTHSM2_CONF'] = softhsm2_conf

This is wrong, you'll be messing up with the environment of all tests being run in the same thread. You must use the "with unittest.mock.patch.dict('os.environ'," implementation I used in testFitSignPKCS11Simple.

+        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')
+
+        os.environ['PKCS11_MODULE_PATH'] = softhsm2_lib

Same issue as with SOFTHSM2_CONF, you must mock the environment and not write to it.

+        data = self._DoReadFile('351_capsule_signed_pkcs11.dts')
+
+        self._CheckCapsule(data, signed_capsule=True)
+
+        # Verify signed capsule
+        hdr = self._GetCapsuleHeaders(data)
+        monotonic_count = hdr['EFI_FIRMWARE_IMAGE_AUTH.MONOTONIC_COUNT']
+
+        with open(self._indir + '/capsule_input.bin', 'ab') as f:

Please use self._MakeInputFile() and prefix it with the name of the method so there's no possible name clash.

+            f.write(struct.pack('<Q', int(monotonic_count, 16)))
+
+        try:
+            tools.run('openssl', 'smime', '-verify', '-inform', 'DER',

This means you depend on openssl being present. Should we maybe do something like

openssl = bintool.Bintool.create('openssl')
self._CheckBintool(openssl)
[...]
openssl.run_cmd(['smime', ...])

to skip the test if it isn't installed?

+                      '-in', tools.get_output_dir() + 
'/capsule.efi-capsule.p7',

tools.get_output_filename('capsule.efi-capsule.p7')

+                      '-content', self._indir + '/capsule_input.bin',

Reuse the path created by self._MakeInputFile().

+                      '-CAfile', cert_file, '-no_check_time')
+        except ValueError:
+            self.assertIn('UEFI Capsule verification failed')
+

I don't think this is valid. https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertIn states you need 2 (or three) arguments, only one's provided here.

I'm assuming we don't need the try..except since the raised Exception will just stop (and fail) the execution of the test but continue with the other ones? Can you check (locally) by purposefully using the wrong key for example?

Cheers,
Quentin

Reply via email to