ConfigFeature,
DocFormat,
JsonEncoder,
+ KeySource,
ManifestFormat,
Network,
OutputFormat,
find_binary("sbsign", root=context.config.tools()) is not None
):
with open(output, "wb") as f:
+ cmd: list[PathString] = [
+ "sbsign",
+ "--key", context.config.secure_boot_key,
+ "--cert", context.config.secure_boot_certificate,
+ "--output", "/dev/stdout",
+ ]
+ options: list[PathString] = [
+ "--ro-bind", context.config.secure_boot_certificate, context.config.secure_boot_certificate,
+ "--ro-bind", input, input,
+ ]
+ if context.config.secure_boot_key_source.type == KeySource.Type.engine:
+ cmd += ["--engine", context.config.secure_boot_key_source.source]
+ if context.config.secure_boot_key.exists():
+ options += ["--ro-bind", context.config.secure_boot_key, context.config.secure_boot_key]
+ cmd += [input]
run(
- [
- "sbsign",
- "--key", context.config.secure_boot_key,
- "--cert", context.config.secure_boot_certificate,
- "--output", "/dev/stdout",
- input,
- ],
+ cmd,
stdout=f,
sandbox=context.sandbox(
- options=[
- "--ro-bind", context.config.secure_boot_key, context.config.secure_boot_key,
- "--ro-bind", context.config.secure_boot_certificate, context.config.secure_boot_certificate,
- "--ro-bind", input, input,
- ]
- ),
+ options=options,
+ devices=context.config.secure_boot_key_source.type != KeySource.Type.file,
+ )
)
elif (
context.config.secure_boot_sign_tool == SecureBootSignTool.pesign or
# We reuse the key for all secure boot databases to keep things simple.
for db in ["PK", "KEK", "db"]:
with umask(~0o600), open(keys / f"{db}.auth", "wb") as f:
+ cmd: list[PathString] = [
+ "sbvarsign",
+ "--attr",
+ "NON_VOLATILE,BOOTSERVICE_ACCESS,RUNTIME_ACCESS,TIME_BASED_AUTHENTICATED_WRITE_ACCESS",
+ "--key", context.config.secure_boot_key,
+ "--cert", context.config.secure_boot_certificate,
+ "--output", "/dev/stdout",
+ ]
+ options: list[PathString] = [
+ "--ro-bind",
+ context.config.secure_boot_certificate,
+ context.config.secure_boot_certificate,
+ "--ro-bind", context.workspace / "mkosi.esl", context.workspace / "mkosi.esl",
+ ]
+ if context.config.secure_boot_key_source.type == KeySource.Type.engine:
+ cmd += ["--engine", context.config.secure_boot_key_source.source]
+ if context.config.secure_boot_key.exists():
+ options += ["--ro-bind", context.config.secure_boot_key, context.config.secure_boot_key]
+ cmd += [db, context.workspace / "mkosi.esl"]
run(
- [
- "sbvarsign",
- "--attr",
- "NON_VOLATILE,BOOTSERVICE_ACCESS,RUNTIME_ACCESS,TIME_BASED_AUTHENTICATED_WRITE_ACCESS",
- "--key", context.config.secure_boot_key,
- "--cert", context.config.secure_boot_certificate,
- "--output", "/dev/stdout",
- db,
- context.workspace / "mkosi.esl",
- ],
+ cmd,
stdout=f,
sandbox=context.sandbox(
- options=[
- "--ro-bind", context.config.secure_boot_key, context.config.secure_boot_key,
- "--ro-bind",
- context.config.secure_boot_certificate,
- context.config.secure_boot_certificate,
- "--ro-bind", context.workspace / "mkosi.esl", context.workspace / "mkosi.esl",
- ],
+ options=options,
+ devices=context.config.secure_boot_key_source.type != KeySource.Type.file,
),
)
context.config.secure_boot_certificate,
]
options += [
- "--ro-bind", context.config.secure_boot_key, context.config.secure_boot_key,
"--ro-bind", context.config.secure_boot_certificate, context.config.secure_boot_certificate,
]
+ if context.config.secure_boot_key_source.type == KeySource.Type.engine:
+ cmd += ["--signing-engine", context.config.secure_boot_key_source.source]
+ if context.config.secure_boot_key.exists():
+ options += ["--ro-bind", context.config.secure_boot_key, context.config.secure_boot_key]
else:
pesign_prepare(context)
cmd += [
options += ["--ro-bind", initrd, initrd]
with complete_step(f"Generating unified kernel image for kernel version {kver}"):
- run(cmd, sandbox=context.sandbox(options=options))
+ run(
+ cmd,
+ sandbox=context.sandbox(
+ options=options,
+ devices=context.config.secure_boot_key_source.type != KeySource.Type.file,
+ ),
+ )
def want_efi(config: Config) -> bool:
return path
+def config_parse_key(value: Optional[str], old: Optional[str]) -> Optional[Path]:
+ if not value:
+ return None
+
+ return parse_path(value, secret=True) if Path(value).exists() else Path(value)
+
+
def make_tree_parser(absolute: bool = True) -> Callable[[str], ConfigTree]:
def parse_tree(value: str) -> ConfigTree:
src, sep, tgt = value.partition(':')
return max(old, new)
+@dataclasses.dataclass(frozen=True)
+class KeySource:
+ class Type(StrEnum):
+ file = enum.auto()
+ engine = enum.auto()
+
+ type: Type
+ source: str = ""
+
+ def __str__(self) -> str:
+ return f"{self.type}:{self.source}" if self.source else str(self.type)
+
+
+def config_parse_key_source(value: Optional[str], old: Optional[KeySource]) -> Optional[KeySource]:
+ if not value:
+ return old
+
+ typ, _, source = value.partition(":")
+ try:
+ type = KeySource.Type(typ)
+ except ValueError:
+ die(f"'{value}' is not a valid key source")
+
+ return KeySource(type=type, source=source)
+
+
@dataclasses.dataclass(frozen=True)
class ConfigSetting:
dest: str
secure_boot: bool
secure_boot_auto_enroll: bool
secure_boot_key: Optional[Path]
+ secure_boot_key_source: KeySource
secure_boot_certificate: Optional[Path]
secure_boot_sign_tool: SecureBootSignTool
verity_key: Optional[Path]
),
ConfigSetting(
dest="secure_boot_key",
- metavar="PATH",
+ metavar="KEY",
section="Validation",
- parse=config_make_path_parser(secret=True),
+ parse=config_parse_key,
paths=("mkosi.key",),
- help="UEFI SecureBoot private key in PEM format",
+ help="UEFI SecureBoot private key",
+ ),
+ ConfigSetting(
+ dest="secure_boot_key_source",
+ section="Validation",
+ metavar="SOURCE[:ENGINE]",
+ parse=config_parse_key_source,
+ default=KeySource(type=KeySource.Type.file),
+ help="The source to use to retrieve the secure boot signing key",
),
ConfigSetting(
dest="secure_boot_certificate",
UEFI SecureBoot: {yes_no(config.secure_boot)}
UEFI SecureBoot AutoEnroll: {yes_no(config.secure_boot_auto_enroll)}
SecureBoot Signing Key: {none_to_none(config.secure_boot_key)}
+ 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 Signing Key: {none_to_none(config.verity_key)}
) -> Optional[GenericVersion]:
return GenericVersion(version) if version is not None else None
+ def key_source_transformer(keysource: dict[str, Any], fieldtype: type[KeySource]) -> KeySource:
+ assert "type" in keysource
+ return KeySource(type=KeySource.Type(keysource["type"]), source=keysource.get("source", ""))
+
transformers = {
Path: path_transformer,
Optional[Path]: optional_path_transformer,
GenericVersion: generic_version_transformer,
Cacheonly: enum_transformer,
Network: enum_transformer,
+ KeySource: key_source_transformer,
}
def json_transformer(key: str, val: Any) -> Any: