From 419b25ddcac39cf967555c7a2eaa274fbf1ad03c Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Sun, 11 Feb 2024 00:34:19 +0000 Subject: [PATCH] ukify: add support for engine signing of PCR signatures --- man/ukify.xml | 5 ++++- src/ukify/test/test_ukify.py | 11 +++++------ src/ukify/ukify.py | 24 ++++++++++++++---------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/man/ukify.xml b/man/ukify.xml index 659c6ed0a3f..886e4522e41 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 ec466393d3a..0e3f9328901 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 8ca93543b5d..f7d08590d93 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, ), -- 2.39.5