Skip to content

Commit

Permalink
Add Verity= feature
Browse files Browse the repository at this point in the history
This allows explicitly enabling/disabling use of verity for disk and
extension images as requested in #3113..
  • Loading branch information
DaanDeMeyer committed Oct 9, 2024
1 parent f6d858b commit 4f562c3
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 7 deletions.
61 changes: 54 additions & 7 deletions mkosi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2407,6 +2407,18 @@ def check_inputs(config: Config) -> None:
if config.secure_boot_key_source != config.sign_expected_pcr_key_source:
die("Secure boot key source and expected PCR signatures key source have to be the same")

if config.verity == ConfigFeature.enabled and not config.verity_key:
die(
"Verity= is enabled but no verity key is configured",
hint="Run mkosi genkey to generate a key/certificate pair",
)

if config.verity == ConfigFeature.enabled and not config.verity_certificate:
die(
"Verity= is enabled but no verity certificate is configured",
hint="Run mkosi genkey to generate a key/certificate pair",
)

for addon in config.pe_addons:
if not addon.output:
die(
Expand Down Expand Up @@ -2968,6 +2980,7 @@ def make_image(
skip: Sequence[str] = [],
split: bool = False,
tabs: bool = False,
verity: bool = False,
root: Optional[Path] = None,
definitions: Sequence[Path] = [],
) -> list[Partition]:
Expand Down Expand Up @@ -2999,7 +3012,10 @@ def make_image(
if context.config.passphrase:
cmdline += ["--key-file", workdir(context.config.passphrase)]
options += ["--ro-bind", context.config.passphrase, workdir(context.config.passphrase)]
if context.config.verity_key:
if verity:
assert context.config.verity_key
assert context.config.verity_certificate

if context.config.verity_key_source.type != KeySourceType.file:
cmdline += ["--private-key-source", str(context.config.verity_key_source)]
options += ["--bind-try", "/run/pcscd", "/run/pcscd"]
Expand All @@ -3008,7 +3024,7 @@ def make_image(
options += ["--ro-bind", context.config.verity_key, workdir(context.config.verity_key)]
else:
cmdline += ["--private-key", context.config.verity_key]
if context.config.verity_certificate:

cmdline += ["--certificate", workdir(context.config.verity_certificate)]
options += [
"--ro-bind", context.config.verity_certificate, workdir(context.config.verity_certificate),
Expand Down Expand Up @@ -3050,6 +3066,12 @@ def make_image(

partitions = [Partition.from_dict(d) for d in output]

if context.config.verity == ConfigFeature.enabled and not any(p.roothash for p in partitions):
die(
"Verity is explicitly enabled but no verity partitions found",
hint="Make sure to add verity partitions in mkosi.repart if building a disk image",
)

if split:
for p in partitions:
if p.split_path:
Expand All @@ -3058,6 +3080,12 @@ def make_image(
return partitions


def want_verity(config: Config) -> bool:
return config.verity == ConfigFeature.enabled or bool(
config.verity == ConfigFeature.auto and config.verity_key and config.verity_certificate
)


def make_disk(
context: Context,
msg: str,
Expand Down Expand Up @@ -3131,7 +3159,14 @@ def make_disk(
definitions = [defaults]

return make_image(
context, msg=msg, skip=skip, split=split, tabs=tabs, root=context.root, definitions=definitions
context,
msg=msg,
skip=skip,
split=split,
tabs=tabs,
verity=want_verity(context.config),
root=context.root,
definitions=definitions,
)


Expand Down Expand Up @@ -3275,7 +3310,8 @@ def make_esp(context: Context, uki: Path) -> list[Partition]:


def make_extension_image(context: Context, output: Path) -> None:
r = context.resources / f"repart/definitions/{context.config.output_format}.repart.d"
unsigned = "-unsigned" if not want_verity(context.config) else ""
r = context.resources / f"repart/definitions/{context.config.output_format}{unsigned}.repart.d"

cmdline: list[PathString] = [
"systemd-repart",
Expand Down Expand Up @@ -3304,15 +3340,18 @@ def make_extension_image(context: Context, output: Path) -> None:
if context.config.passphrase:
cmdline += ["--key-file", context.config.passphrase]
options += ["--ro-bind", context.config.passphrase, workdir(context.config.passphrase)]
if context.config.verity_key:
if want_verity(context.config):
assert context.config.verity_key
assert context.config.verity_certificate

if context.config.verity_key_source.type != KeySourceType.file:
cmdline += ["--private-key-source", str(context.config.verity_key_source)]
if context.config.verity_key.exists():
cmdline += ["--private-key", workdir(context.config.verity_key)]
options += ["--ro-bind", context.config.verity_key, workdir(context.config.verity_key)]
else:
cmdline += ["--private-key", context.config.verity_key]
if context.config.verity_certificate:

cmdline += ["--certificate", workdir(context.config.verity_certificate)]
options += [
"--ro-bind", context.config.verity_certificate, workdir(context.config.verity_certificate)
Expand Down Expand Up @@ -3341,8 +3380,16 @@ def make_extension_image(context: Context, output: Path) -> None:

logging.debug(json.dumps(j, indent=4))

partitions = [Partition.from_dict(d) for d in j]

if context.config.verity == ConfigFeature.enabled and not any(p.roothash for p in partitions):
die(
"Verity is explicitly enabled but no verity partitions found",
hint="Make sure to add verity partitions in mkosi.repart if building a disk image",
)

if context.config.split_artifacts:
for p in (Partition.from_dict(d) for d in j):
for p in partitions:
if p.split_path:
maybe_compress(context, context.config.compress_output, p.split_path)

Expand Down
9 changes: 9 additions & 0 deletions mkosi/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1666,6 +1666,7 @@ class Config:
secure_boot_key_source: KeySource
secure_boot_certificate: Optional[Path]
secure_boot_sign_tool: SecureBootSignTool
verity: ConfigFeature
verity_key: Optional[Path]
verity_key_source: KeySource
verity_certificate: Optional[Path]
Expand Down Expand Up @@ -2829,6 +2830,13 @@ def parse_ini(path: Path, only_sections: Collection[str] = ()) -> Iterator[tuple
choices=SecureBootSignTool.choices(),
help="Tool to use for signing PE binaries for secure boot",
),
ConfigSetting(
dest="verity",
section="Validation",
metavar="FEATURE",
parse=config_parse_feature,
help="Configure whether to enforce or disable verity partitions for disk images",
),
ConfigSetting(
dest="verity_key",
metavar="KEY",
Expand Down Expand Up @@ -4552,6 +4560,7 @@ def summary(config: Config) -> str:
SecureBoot Signing Key Source: {config.secure_boot_key_source}
SecureBoot Certificate: {none_to_none(config.secure_boot_certificate)}
SecureBoot Sign Tool: {config.secure_boot_sign_tool}
Verity: {config.verity}
Verity Signing Key: {none_to_none(config.verity_key)}
Verity Signing Key Source: {config.verity_key_source}
Verity Certificate: {none_to_none(config.verity_certificate)}
Expand Down
15 changes: 15 additions & 0 deletions mkosi/resources/man/mkosi.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -1130,6 +1130,21 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`,
If set to `auto`, either sbsign or pesign are used if available, with sbsign being preferred if both are
installed.

`Verity=`, `--verity=`
: Whether to enforce or disable verity for disk and extension images.
Takes a boolean value or `auto`. If enabled, a verity key and
certificate must be present and the build will fail if we don't
detect any verity partitions in the disk image produced by
systemd-repart. If disabled, verity partitions will be excluded from
disk images produced by systemd-repart even if the partition
definitions contain verity partitions. If set to `auto`, the verity
key and certificate will be passed to systemd-repart if available,
but the build won't fail if no verity partitions are found in the
disk image produced by systemd-repart.

: Note that explicitly disabling verity is not yet implemented for the
`disk` output and only works for extension images at the moment.

`VerityKey=`, `--verity-key=`
: Path to the PEM file containing the secret key for signing the verity signature, if a verity signature
partition is added with systemd-repart. When `VerityKeySource=` is specified, the input type depends on
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Partition]
Type=root
Format=erofs
CopyFiles=/etc/
Minimize=best
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Partition]
Type=root
Format=erofs
CopyFiles=/
Minimize=best
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Partition]
Type=root
Format=erofs
CopyFiles=/opt/
CopyFiles=/usr/
Minimize=best
2 changes: 2 additions & 0 deletions tests/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ def test_config() -> None:
"PROPERTY=VALUE"
],
"UseSubvolumes": "auto",
"Verity": "enabled",
"VerityCertificate": "/path/to/cert",
"VerityKey": null,
"VerityKeySource": {
Expand Down Expand Up @@ -550,6 +551,7 @@ def test_config() -> None:
unified_kernel_images=ConfigFeature.auto,
unit_properties=["PROPERTY=VALUE"],
use_subvolumes=ConfigFeature.auto,
verity=ConfigFeature.enabled,
verity_certificate=Path("/path/to/cert"),
verity_key=None,
verity_key_source=KeySource(type=KeySourceType.file),
Expand Down

0 comments on commit 4f562c3

Please sign in to comment.