mirror of
https://github.com/systemd/systemd.git
synced 2026-11-06 05:17:24 +00:00
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>