summaryrefslogtreecommitdiffstats
path: root/src/ukify/ukify.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/ukify/ukify.py')
-rwxr-xr-xsrc/ukify/ukify.py59
1 files changed, 43 insertions, 16 deletions
diff --git a/src/ukify/ukify.py b/src/ukify/ukify.py
index b0d0961..f1db9ba 100755
--- a/src/ukify/ukify.py
+++ b/src/ukify/ukify.py
@@ -51,7 +51,7 @@ from typing import (Any,
import pefile # type: ignore
-__version__ = '{{PROJECT_VERSION}} ({{GIT_VERSION}})'
+__version__ = '{{PROJECT_VERSION_FULL}} ({{VERSION_TAG}})'
EFI_ARCH_MAP = {
# host_arch glob : [efi_arch, 32_bit_efi_arch if mixed mode is supported]
@@ -68,7 +68,7 @@ EFI_ARCHES: list[str] = sum(EFI_ARCH_MAP.values(), [])
# Default configuration directories and file name.
# When the user does not specify one, the directories are searched in this order and the first file found is used.
-DEFAULT_CONFIG_DIRS = ['/run/systemd', '/etc/systemd', '/usr/local/lib/systemd', '/usr/lib/systemd']
+DEFAULT_CONFIG_DIRS = ['/etc/systemd', '/run/systemd', '/usr/local/lib/systemd', '/usr/lib/systemd']
DEFAULT_CONFIG_FILE = 'ukify.conf'
class Style:
@@ -236,7 +236,7 @@ class Uname:
@classmethod
def scrape_x86(cls, filename, opts=None):
# Based on https://gitlab.archlinux.org/archlinux/mkinitcpio/mkinitcpio/-/blob/master/functions#L136
- # and https://www.kernel.org/doc/html/latest/x86/boot.html#the-real-mode-kernel-header
+ # and https://docs.kernel.org/arch/x86/boot.html#the-real-mode-kernel-header
with open(filename, 'rb') as f:
f.seek(0x202)
magic = f.read(4)
@@ -303,6 +303,7 @@ class Uname:
DEFAULT_SECTIONS_TO_SHOW = {
'.linux' : 'binary',
'.initrd' : 'binary',
+ '.ucode' : 'binary',
'.splash' : 'binary',
'.dtb' : 'binary',
'.cmdline' : 'text',
@@ -449,7 +450,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 +540,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 +733,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):
@@ -818,9 +825,23 @@ def make_uki(opts):
if pcrpkey is None:
if opts.pcr_public_keys and len(opts.pcr_public_keys) == 1:
pcrpkey = opts.pcr_public_keys[0]
+ # If we are getting a certificate when using an engine, we need to convert it to public key format
+ if opts.signing_engine is not None and pathlib.Path(pcrpkey).exists():
+ from cryptography.hazmat.primitives import serialization
+ from cryptography.x509 import load_pem_x509_certificate
+
+ try:
+ cert = load_pem_x509_certificate(pathlib.Path(pcrpkey).read_bytes())
+ except ValueError:
+ raise ValueError(f'{pcrpkey} must be an X.509 certificate when signing with an engine')
+ else:
+ pcrpkey = cert.public_key().public_bytes(
+ encoding=serialization.Encoding.PEM,
+ format=serialization.PublicFormat.SubjectPublicKeyInfo,
+ )
elif opts.pcr_private_keys and len(opts.pcr_private_keys) == 1:
- import cryptography.hazmat.primitives.serialization as serialization
- privkey = serialization.load_pem_private_key(opts.pcr_private_keys[0].read_bytes(), password=None)
+ from cryptography.hazmat.primitives import serialization
+ 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,
@@ -835,6 +856,7 @@ def make_uki(opts):
('.splash', opts.splash, True ),
('.pcrpkey', pcrpkey, True ),
('.initrd', initrd, True ),
+ ('.ucode', opts.microcode, True ),
# linux shall be last to leave breathing room for decompression.
# We'll add it later.
@@ -897,7 +919,6 @@ uki-addon,1,UKI Addon,addon,1,https://www.freedesktop.org/software/systemd/man/l
print(f"Wrote {'signed' if sign_args_present else 'unsigned'} {opts.output}")
-
@contextlib.contextmanager
def temporary_umask(mask: int):
# Drop <mask> bits from umask
@@ -1008,7 +1029,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)
@@ -1261,6 +1282,14 @@ CONFIG_ITEMS = [
),
ConfigItem(
+ '--microcode',
+ metavar = 'UCODE',
+ type = pathlib.Path,
+ help = 'microcode file [.ucode section]',
+ config_key = 'UKI/Microcode',
+ ),
+
+ ConfigItem(
('--config', '-c'),
metavar = 'PATH',
type = pathlib.Path,
@@ -1411,10 +1440,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,
),
@@ -1424,7 +1451,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,
),
@@ -1619,7 +1646,7 @@ def finalize_options(opts):
opts.verb = 'build'
# Check that --pcr-public-key=, --pcr-private-key=, and --phases=
- # have either the same number of arguments are are not specified at all.
+ # have either the same number of arguments or are not specified at all.
n_pcr_pub = None if opts.pcr_public_keys is None else len(opts.pcr_public_keys)
n_pcr_priv = None if opts.pcr_private_keys is None else len(opts.pcr_private_keys)
n_phase_path_groups = None if opts.phase_path_groups is None else len(opts.phase_path_groups)