diff --git a/man/ukify.xml b/man/ukify.xml
index 659c6ed0a3..886e4522e4 100644
--- a/man/ukify.xml
+++ b/man/ukify.xml
@@ -99,7 +99,10 @@
the n-th boot phase path set will be signed by the n-th key. This can be used to build different trust
policies for different phases of the boot. In the config file, PCRPrivateKey=,
PCRPublicKey=, and Phases= are grouped into separate sections,
- describing separate boot phases.
+ describing separate boot phases. If SigningEngine=/
+ is specified, then the private keys arguments will be passed verbatim to OpenSSL as URIs, and the public
+ key arguments will be loaded as X.509 certificates, so that signing can be perfomed with an OpenSSL
+ engine.
If a SecureBoot signing key is provided via the
SecureBootPrivateKey=/ option, the resulting
diff --git a/src/ukify/test/test_ukify.py b/src/ukify/test/test_ukify.py
index ec466393d3..0e3f932890 100755
--- a/src/ukify/test/test_ukify.py
+++ b/src/ukify/test/test_ukify.py
@@ -120,7 +120,7 @@ def test_apply_config(tmp_path):
assert ns.sign_kernel is False
assert ns._groups == ['NAME']
- assert ns.pcr_private_keys == [pathlib.Path('some/path7')]
+ assert ns.pcr_private_keys == ['some/path7']
assert ns.pcr_public_keys == [pathlib.Path('some/path8')]
assert ns.phase_path_groups == [['enter-initrd:leave-initrd:sysinit:ready:shutdown:final']]
@@ -143,7 +143,7 @@ def test_apply_config(tmp_path):
assert ns.sign_kernel is False
assert ns._groups == ['NAME']
- assert ns.pcr_private_keys == [pathlib.Path('some/path7')]
+ assert ns.pcr_private_keys == ['some/path7']
assert ns.pcr_public_keys == [pathlib.Path('some/path8')]
assert ns.phase_path_groups == [['enter-initrd:leave-initrd:sysinit:ready:shutdown:final']]
@@ -189,7 +189,7 @@ def test_parse_args_many_deprecated():
assert opts.pcrpkey == pathlib.Path('PATH')
assert opts.uname == '1.2.3'
assert opts.stub == pathlib.Path('STUBPATH')
- assert opts.pcr_private_keys == [pathlib.Path('PKEY1')]
+ assert opts.pcr_private_keys == ['PKEY1']
assert opts.pcr_public_keys == [pathlib.Path('PKEY2')]
assert opts.pcr_banks == ['SHA1', 'SHA256']
assert opts.signing_engine == 'ENGINE'
@@ -235,7 +235,7 @@ def test_parse_args_many():
assert opts.pcrpkey == pathlib.Path('PATH')
assert opts.uname == '1.2.3'
assert opts.stub == pathlib.Path('STUBPATH')
- assert opts.pcr_private_keys == [pathlib.Path('PKEY1')]
+ assert opts.pcr_private_keys == ['PKEY1']
assert opts.pcr_public_keys == [pathlib.Path('PKEY2')]
assert opts.pcr_banks == ['SHA1', 'SHA256']
assert opts.signing_engine == 'ENGINE'
@@ -342,8 +342,7 @@ def test_config_priority(tmp_path):
assert opts.pcrpkey == pathlib.Path('PATH')
assert opts.uname == '1.2.3'
assert opts.stub == pathlib.Path('STUBPATH')
- assert opts.pcr_private_keys == [pathlib.Path('PKEY1'),
- pathlib.Path('some/path7')]
+ assert opts.pcr_private_keys == ['PKEY1', 'some/path7']
assert opts.pcr_public_keys == [pathlib.Path('PKEY2'),
pathlib.Path('some/path8')]
assert opts.pcr_banks == ['SHA1', 'SHA256']
diff --git a/src/ukify/ukify.py b/src/ukify/ukify.py
index 8ca93543b5..f7d08590d9 100755
--- a/src/ukify/ukify.py
+++ b/src/ukify/ukify.py
@@ -449,7 +449,7 @@ def check_cert_and_keys_nonexistent(opts):
*((priv_key, pub_key)
for priv_key, pub_key, _ in key_path_groups(opts)))
for path in paths:
- if path and path.exists():
+ if path and pathlib.Path(path).exists():
raise ValueError(f'{path} is present')
@@ -539,7 +539,11 @@ def call_systemd_measure(uki, linux, opts):
for priv_key, pub_key, group in key_path_groups(opts):
extra = [f'--private-key={priv_key}']
- if pub_key:
+ if opts.signing_engine is not None:
+ assert pub_key
+ extra += [f'--private-key-source=engine:{opts.signing_engine}']
+ extra += [f'--certificate={pub_key}']
+ elif pub_key:
extra += [f'--public-key={pub_key}']
extra += [f'--phase={phase_path}' for phase_path in group or ()]
@@ -728,11 +732,13 @@ def sbsign_sign(sbsign_tool, input_f, output_f, opts=None):
sbsign_tool,
'--key', opts.sb_key,
'--cert', opts.sb_cert,
- input_f,
- '--output', output_f,
]
if opts.signing_engine is not None:
sign_invocation += ['--engine', opts.signing_engine]
+ sign_invocation += [
+ input_f,
+ '--output', output_f,
+ ]
signer_sign(sign_invocation)
def find_pesign(opts=None):
@@ -820,7 +826,7 @@ def make_uki(opts):
pcrpkey = opts.pcr_public_keys[0]
elif opts.pcr_private_keys and len(opts.pcr_private_keys) == 1:
from cryptography.hazmat.primitives import serialization
- privkey = serialization.load_pem_private_key(opts.pcr_private_keys[0].read_bytes(), password=None)
+ privkey = serialization.load_pem_private_key(pathlib.Path(opts.pcr_private_keys[0]).read_bytes(), password=None)
pcrpkey = privkey.public_key().public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
@@ -1002,7 +1008,7 @@ def generate_keys(opts):
print(f'Writing private key for PCR signing to {priv_key}')
with temporary_umask(0o077):
- priv_key.write_bytes(priv_key_pem)
+ pathlib.Path(priv_key).write_bytes(priv_key_pem)
if pub_key:
print(f'Writing public key for PCR signing to {pub_key}')
pub_key.write_bytes(pub_key_pem)
@@ -1405,10 +1411,8 @@ CONFIG_ITEMS = [
ConfigItem(
'--pcr-private-key',
dest = 'pcr_private_keys',
- metavar = 'PATH',
- type = pathlib.Path,
action = 'append',
- help = 'private part of the keypair for signing PCR signatures',
+ help = 'private part of the keypair or engine-specific designation for signing PCR signatures',
config_key = 'PCRSignature:/PCRPrivateKey',
config_push = ConfigItem.config_set_group,
),
@@ -1418,7 +1422,7 @@ CONFIG_ITEMS = [
metavar = 'PATH',
type = pathlib.Path,
action = 'append',
- help = 'public part of the keypair for signing PCR signatures',
+ help = 'public part of the keypair or engine-specific designation for signing PCR signatures',
config_key = 'PCRSignature:/PCRPublicKey',
config_push = ConfigItem.config_set_group,
),