mirror of
https://github.com/systemd/systemd.git
synced 2025-03-13 00:58:27 +03:00
ukify: add --policy-digest option
Uses the newly added policy-digest verb of systemd-measure, for the same purpose: build a UKI and get digests for the .pcrsig section out, so that they can be offline signed and reattached
This commit is contained in:
parent
175cb87a1c
commit
606c5e7580
@ -209,6 +209,18 @@
|
||||
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--policy-digest</option></term>
|
||||
<term><option>--no-policy-digest</option></term>
|
||||
|
||||
<listitem><para>Enable or disable a call to
|
||||
<citerefentry><refentrytitle>systemd-measure</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
to print pre-calculated TPM2 policy digests. Useful for offline signing of PCR policies.
|
||||
Defaults to false.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--section=<replaceable>NAME</replaceable>:<replaceable>TEXT</replaceable>|<replaceable>@PATH</replaceable></option></term>
|
||||
<term><option>--section=<replaceable>NAME</replaceable>:text|binary<optional>@<replaceable>PATH</replaceable></optional></option></term>
|
||||
|
@ -242,6 +242,8 @@ def test_parse_args_many():
|
||||
'--output=OUTPUT',
|
||||
'--measure',
|
||||
'--no-measure',
|
||||
'--policy-digest',
|
||||
'--no-policy-digest',
|
||||
])
|
||||
assert opts.linux == pathlib.Path('/ARG1')
|
||||
assert opts.initrd == [pathlib.Path('/ARG2'), pathlib.Path('/ARG3 WITH SPACE')]
|
||||
@ -262,6 +264,7 @@ def test_parse_args_many():
|
||||
assert opts.tools == [pathlib.Path('TOOLZ/')]
|
||||
assert opts.output == pathlib.Path('OUTPUT')
|
||||
assert opts.measure is False
|
||||
assert opts.policy_digest is False
|
||||
|
||||
def test_parse_sections():
|
||||
opts = ukify.parse_args(
|
||||
|
@ -255,6 +255,7 @@ class UkifyConfig:
|
||||
pcr_public_keys: list[str]
|
||||
pcrpkey: Optional[Path]
|
||||
phase_path_groups: Optional[list[str]]
|
||||
policy_digest: bool
|
||||
profile: Union[str, Path, None]
|
||||
sb_cert: Union[str, Path, None]
|
||||
sb_cert_name: Optional[str]
|
||||
@ -751,7 +752,7 @@ def call_systemd_measure(uki: UKI, opts: UkifyConfig, profile_start: int = 0) ->
|
||||
|
||||
unique_to_measure[section.name] = section
|
||||
|
||||
if opts.measure:
|
||||
if opts.measure or opts.policy_digest:
|
||||
to_measure = unique_to_measure.copy()
|
||||
|
||||
for dtbauto in dtbauto_to_measure:
|
||||
@ -762,7 +763,7 @@ def call_systemd_measure(uki: UKI, opts: UkifyConfig, profile_start: int = 0) ->
|
||||
|
||||
cmd = [
|
||||
measure_tool,
|
||||
'calculate',
|
||||
'calculate' if opts.measure else 'policy-digest',
|
||||
'--json',
|
||||
opts.json,
|
||||
*(f'--{s.name.removeprefix(".")}={s.content}' for s in to_measure.values()),
|
||||
@ -772,6 +773,11 @@ def call_systemd_measure(uki: UKI, opts: UkifyConfig, profile_start: int = 0) ->
|
||||
*(f'--phase={phase_path}' for phase_path in itertools.chain.from_iterable(pp_groups)),
|
||||
]
|
||||
|
||||
# The JSON object will be used for offline signing, include the public key
|
||||
# so that the fingerprint is included too.
|
||||
if opts.policy_digest and opts.pcr_public_keys:
|
||||
cmd += [f'--public-key={opts.pcr_public_keys[0]}']
|
||||
|
||||
print('+', shell_join(cmd), file=sys.stderr)
|
||||
subprocess.check_call(cmd)
|
||||
|
||||
@ -1940,6 +1946,11 @@ CONFIG_ITEMS = [
|
||||
action=argparse.BooleanOptionalAction,
|
||||
help='print systemd-measure output for the UKI',
|
||||
),
|
||||
ConfigItem(
|
||||
'--policy-digest',
|
||||
action=argparse.BooleanOptionalAction,
|
||||
help='print systemd-measure policy digests for the UKI',
|
||||
),
|
||||
ConfigItem(
|
||||
'--json',
|
||||
choices=('pretty', 'short', 'off'),
|
||||
@ -2108,10 +2119,16 @@ def finalize_options(opts: argparse.Namespace) -> None:
|
||||
|
||||
# Check that --pcr-public-key=, --pcr-private-key=, and --phases=
|
||||
# have either the same number of arguments or are not specified at all.
|
||||
# But allow a single public key, for offline PCR signing, to pre-populate the JSON object
|
||||
# with the certificate's fingerprint.
|
||||
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)
|
||||
if n_pcr_pub is not None and n_pcr_pub != n_pcr_priv:
|
||||
if opts.policy_digest and n_pcr_priv is not None:
|
||||
raise ValueError('--pcr-private-key= cannot be specified with --policy-digest')
|
||||
if opts.policy_digest and (n_pcr_pub is None or n_pcr_pub != 1):
|
||||
raise ValueError('--policy-digest requires exactly one --pcr-public-key=')
|
||||
if n_pcr_pub is not None and n_pcr_priv is not None and n_pcr_pub != n_pcr_priv:
|
||||
raise ValueError('--pcr-public-key= specifications must match --pcr-private-key=')
|
||||
if n_phase_path_groups is not None and n_phase_path_groups != n_pcr_priv:
|
||||
raise ValueError('--phases= specifications must match --pcr-private-key=')
|
||||
|
Loading…
x
Reference in New Issue
Block a user