Files
systemd/src
Christian Brauner db8557d8a5 keyring-setup: add systemd-keyring-setup (#44114)
Lennart asked in #44114 to split the preparatory stuff out so it can
be merged in smaller PRs. So this is a stack of five, each based on
the one before it and each showing only its own commits:

1. #44323, the C helpers (merged)
2. #44324, support for programs written in Rust (merged)
3. #44420, bindings.h lists only the headers Rust code uses (merged)
4. #44325, the systemd_shared wrappers systemd-keyring-setup needs
(merged)
5. #44114, systemd-keyring-setup itself

This one is 5.

This adds systemd-keyring-setup which enrolls X.509 certificates from
the VOA hierarchy into the kernel's .dm-verity, .fs-verity and .bpf
keyrings at boot and seals them afterwards. It's the first program in
systemd written in Rust. The C prototype in #43549 was never merged, so
nothing is ported here.

The kernel has various keyrings that early userspace may choose to set
up. Right now it has the .fs-verity and .dm-verity keyrings and in the
next kernel it will also have a .bpf keyring.

All three keyrings accept X.509 certificates in DER form. The .dm-verity
and .bpf keyrings are inactive and restricted by default unless the
respective kernel command line options are passed that leave them
unrestricted. Both keyrings are ignored until they are restricted. IOW,
restricting them causes the kernel to use them for signature
verification. The .fs-verity keyring is always active and is taken into
account as soon as it contains a key.

The UAPI group published the File Hierarchy for the Verification of OS
Artifacts (VOA) specification (cf. [1]). systemd-keyring-setup reads the
certificates for each keyring from the kernel-keyring role with the
keyring as the context and the trust anchors from the
trust-anchor-kernel-keyring counterpart:

```
<load-path>/<os>/kernel-keyring/<context>/x509/<name>-certificate.pem
<load-path>/<os>/trust-anchor-kernel-keyring/<context>/x509/<name>-certificate.pem
```

The load paths in descending priority are /etc/voa, /run/voa,
/usr/local/share/voa and /usr/share/voa. `<os>` is the exact identifier
`ID[:VERSION_ID[:VARIANT_ID[:IMAGE_ID[:IMAGE_VERSION]]]]` and the bare
`ID`. `<context>` is dm-verity, fs-verity or bpf.

Examples for a vendor shipping verifiers on Debian:

```
/usr/share/voa/debian/kernel-keyring/dm-verity/x509/vendor-certificate.pem
/usr/share/voa/debian/kernel-keyring/fs-verity/x509/vendor-certificate.pem
/usr/share/voa/debian/kernel-keyring/bpf/x509/vendor-certificate.pem
```

A CA certificate as a trust anchor and an admin override in /etc for a
specific release:

```
/usr/share/voa/debian/trust-anchor-kernel-keyring/dm-verity/x509/vendor-ca-certificate.pem
/etc/voa/debian:13/kernel-keyring/dm-verity/x509/corp-certificate.pem
```

Masking works as everywhere in VOA via a /dev/null symlink under the
same file name in any load path:

```
/etc/voa/debian/kernel-keyring/dm-verity/x509/vendor-certificate.pem -> /dev/null
```

The lookup is anchored at a pinned root directory and drops verifiers
that somebody else could have tampered with. That's what CHASE_MAX_MODE
and the CONF_FILES_CHASE_* flags are for. The VOA lookup, the keyring
helpers and the X.509 helpers are all C in libsystemd-shared and the
Rust program calls into them.

After enrolling, the keyring is restricted to certificates signed by an
enrolled key and SetAttr is dropped from its permission mask. So neither
the restriction nor the mask can be changed anymore. Any keyring that's
still open is sealed at the end of a run, even when it's empty. The
binary may run in the initrd and on the host. A second run detects the
sealed keyring, skips certificates that are enrolled already and enrolls
the ones signed by an enrolled key. The service isn't enabled by
default.

Certificates can also be shipped as `keyring-setup.<keyring>.<name>`
system credentials (SMBIOS, ESP credential drop-ins, --set-credential
for the boot loader). This lets users avoid having to ship keys as part
of the initrd. We don't enroll them directly but follow the VOA spec
instead. They are placed into /run/voa first so masking, merging and
deduplication apply to them like to any other file:

```
/run/voa/debian/kernel-keyring/dm-verity/x509/corp-certificate.pem
```

A keyring-setup.os credential overrides the OS identifiers derived from
os-release. This is useful for generic initrds whose identity differs
from the host's.

The specification requires the extended key usage of a verifier to be
aligned with its purpose. The kernel has no concept of this. So
systemd-keyring-setup checks it.

TEST-98-KEYRING-SETUP boots with and without
dm_verity.keyring_unsealed=1 and the kernel verifies the signed test
image against the keyring that systemd-keyring-setup provisioned.
TEST-90 copes with a .dm-verity keyring that was sealed at boot.

[1]:
https://uapi-group.org/specifications/specs/file_hierarchy_for_the_verification_of_os_artifacts/

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-10-27 10:27:21 +01:00
..
2026-10-21 22:14:11 +02:00
2026-10-21 22:14:11 +02:00
2026-10-21 22:14:11 +02:00
2026-10-23 11:35:09 +09:00
2026-10-21 22:14:11 +02:00
2026-10-21 22:14:11 +02:00
2026-10-21 22:14:11 +02:00
2026-10-21 22:08:12 +02:00
2026-10-13 02:32:12 +09:00
2026-10-25 09:34:00 +09:00
2026-10-21 22:14:11 +02:00
2026-10-21 22:14:11 +02:00
2026-10-21 22:14:11 +02:00
2026-10-23 21:10:40 +09:00
…
2026-10-21 22:14:11 +02:00
2026-10-21 22:14:11 +02:00
2026-10-21 22:14:11 +02:00
2026-10-21 22:14:11 +02:00
2026-10-21 22:14:11 +02:00
2026-10-21 22:14:11 +02:00
2026-10-21 22:14:11 +02:00
2026-10-23 09:57:27 +02:00
2026-10-21 22:08:12 +02:00
2026-10-21 22:14:11 +02:00
2026-10-21 22:08:12 +02:00
2026-10-21 22:14:11 +02:00
2026-10-25 09:34:00 +09:00
2026-10-21 22:14:11 +02:00
2026-10-21 22:14:11 +02:00
2026-10-21 22:14:11 +02:00
2026-10-21 22:14:11 +02:00