From 2e64cb71b9c0160c335d8e52954149e078bba2fb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Sep 2023 21:25:53 +0200 Subject: [PATCH 1/2] tpm2-setup: add new early boot tool for initializing the SRK This adds an explicit service for initializing the TPM2 SRK. This is implicitly also done by systemd-cryptsetup, hence strictly speaking redundant, but doing this early has the benefit that we can parallelize this in a nicer way. This also write a copy of the SRK public key in PEM format to /run/ + /var/lib/, thus pinning the disk image to the TPM. Making the SRK public key is also useful for allowing easy offline encryption for a specific TPM. Sooner or later we should probably grow what this service does, the above is just the first step. For example, the service should probably offer the ability to reset the TPM (clear the owner hierarchy?) on a factory reset, if such a policy is needed. And we might want to install some default AK (?). Fixes: #27986 Also see: #22637 --- man/rules/meson.build | 4 + man/systemd-tpm2-setup.service.xml | 74 +++++ meson.build | 1 + src/shared/generator.c | 2 +- src/shared/tpm2-util.c | 8 +- src/shared/tpm2-util.h | 4 + src/tpm2-setup/meson.build | 16 ++ src/tpm2-setup/tpm2-setup.c | 327 ++++++++++++++++++++++ test/units/testsuite-70.sh | 9 + units/meson.build | 10 + units/systemd-tpm2-setup-early.service.in | 22 ++ units/systemd-tpm2-setup.service.in | 24 ++ 12 files changed, 496 insertions(+), 5 deletions(-) create mode 100644 man/systemd-tpm2-setup.service.xml create mode 100644 src/tpm2-setup/meson.build create mode 100644 src/tpm2-setup/tpm2-setup.c create mode 100644 units/systemd-tpm2-setup-early.service.in create mode 100644 units/systemd-tpm2-setup.service.in diff --git a/man/rules/meson.build b/man/rules/meson.build index 9a383b985ef..3454668cab9 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -1088,6 +1088,10 @@ manpages = [ 'systemd-tmpfiles-setup-dev.service', 'systemd-tmpfiles-setup.service'], ''], + ['systemd-tpm2-setup.service', + '8', + ['systemd-tpm2-setup', 'systemd-tpm2-setup-early.service'], + 'ENABLE_BOOTLOADER'], ['systemd-tty-ask-password-agent', '1', [], ''], ['systemd-udev-settle.service', '8', [], ''], ['systemd-udevd.service', diff --git a/man/systemd-tpm2-setup.service.xml b/man/systemd-tpm2-setup.service.xml new file mode 100644 index 00000000000..77502d50841 --- /dev/null +++ b/man/systemd-tpm2-setup.service.xml @@ -0,0 +1,74 @@ + + + + + + + + systemd-tpm2-setup.service + systemd + + + + systemd-tpm2-setup.service + 8 + + + + systemd-tpm2-setup.service + systemd-tpm2-setup-early.service + systemd-tpm2-setup + Set up the TPM2 Storage Root Key (SRK) at boot + + + + systemd-tpm2-setup.service + /usr/lib/systemd/systemd-tpm2-setup + + + + Description + + systemd-tpm2-setup.service and + systemd-tpm2-setup-early.service are services that generate the Storage Root Key + (SRK) if it hasn't been generated yet, and stores it in the TPM. + + The services will store the public key of the SRK key pair in a PEM file in + /run/systemd/tpm2-srk-public-key.pem and + /var/lib/systemd/tpm2-srk-public-key.pem. + + systemd-tpm2-setup-early.service runs very early at boot (possibly in the + initrd), and writes the SRK public key to /run/systemd/tpm2-srk-public-key.pem (as + /var/ is generally not accessible this early yet), while + systemd-tpm2-setup.service runs during a later boot phase and saves the public key + to /var/lib/systemd/tpm2-srk-public-key.pem. + + + + Files + + + + /run/systemd/tpm2-srk-public-key.pem + + The SRK public key in PEM format, written during early boot. + + + + /var/lib/systemd/tpm2-srk-public-key.pem + + The SRK public key in PEM format, written during later boot (once + /var/ is available). + + + + + + See Also + + systemd1 + + + diff --git a/meson.build b/meson.build index 90705b31583..44eac94fdf9 100644 --- a/meson.build +++ b/meson.build @@ -2186,6 +2186,7 @@ subdir('src/sysusers') subdir('src/sysv-generator') subdir('src/timedate') subdir('src/timesync') +subdir('src/tpm2-setup') subdir('src/tmpfiles') subdir('src/tty-ask-password-agent') subdir('src/update-done') diff --git a/src/shared/generator.c b/src/shared/generator.c index aced4949a9a..56265872691 100644 --- a/src/shared/generator.c +++ b/src/shared/generator.c @@ -741,7 +741,7 @@ int generator_write_cryptsetup_unit_section( fprintf(f, "\n" "DefaultDependencies=no\n" - "After=cryptsetup-pre.target systemd-udevd-kernel.socket\n" + "After=cryptsetup-pre.target systemd-udevd-kernel.socket systemd-tpm2-setup-early.service\n" "Before=blockdev@dev-mapper-%%i.target\n" "Wants=blockdev@dev-mapper-%%i.target\n" "IgnoreOnIsolate=true\n"); diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 64dcc5503ba..3374bd4f783 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -148,7 +148,7 @@ int dlopen_tpm2(void) { DLSYM_ARG(Tss2_MU_TPMT_PUBLIC_Marshal)); } -static void Esys_Freep(void *p) { +void Esys_Freep(void *p) { if (*(void**) p) sym_Esys_Free(*(void**) p); } @@ -1175,7 +1175,7 @@ static int tpm2_get_srk( } /* Get the SRK, creating one if needed. Returns 0 on success, or < 0 on error. */ -static int tpm2_get_or_create_srk( +int tpm2_get_or_create_srk( Tpm2Context *c, const Tpm2Handle *session, TPM2B_PUBLIC **ret_public, @@ -1189,7 +1189,7 @@ static int tpm2_get_or_create_srk( if (r < 0) return r; if (r == 1) - return 0; + return 0; /* 0 → SRK already set up */ /* No SRK, create and persist one */ TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), }; @@ -1223,7 +1223,7 @@ static int tpm2_get_or_create_srk( /* This should never happen. */ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "SRK we just persisted couldn't be found."); - return 0; + return 1; /* > 0 → SRK newly set up */ } /* Utility functions for TPMS_PCR_SELECTION. */ diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index 72533722931..8df41f001d7 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -67,6 +67,8 @@ typedef struct { #define _tpm2_handle(c, h) { .tpm2_context = (c), .esys_handle = (h), } static const Tpm2Handle TPM2_HANDLE_NONE = _tpm2_handle(NULL, ESYS_TR_NONE); +void Esys_Freep(void *p); + int tpm2_handle_new(Tpm2Context *context, Tpm2Handle **ret_handle); Tpm2Handle *tpm2_handle_free(Tpm2Handle *handle); DEFINE_TRIVIAL_CLEANUP_FUNC(Tpm2Handle*, tpm2_handle_free); @@ -188,6 +190,8 @@ int tpm2_calculate_sealing_policy(const Tpm2PCRValue *pcr_values, size_t n_pcr_v int tpm2_marshal_blob(const TPM2B_PUBLIC *public, const TPM2B_PRIVATE *private, void **ret_blob, size_t *ret_blob_size); int tpm2_unmarshal_blob(const void *blob, size_t blob_size, TPM2B_PUBLIC *ret_public, TPM2B_PRIVATE *ret_private); +int tpm2_get_or_create_srk(Tpm2Context *c, const Tpm2Handle *session, TPM2B_PUBLIC **ret_public, TPM2B_NAME **ret_name, TPM2B_NAME **ret_qname, Tpm2Handle **ret_handle); + int tpm2_seal(Tpm2Context *c, const TPM2B_DIGEST *policy, const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, uint16_t *ret_primary_alg, void **ret_srk_buf, size_t *ret_srk_buf_size); int tpm2_unseal(const char *device, uint32_t hash_pcr_mask, uint16_t pcr_bank, const void *pubkey, size_t pubkey_size, uint32_t pubkey_pcr_mask, JsonVariant *signature, const char *pin, uint16_t primary_alg, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, const void *srk_buf, size_t srk_buf_size, void **ret_secret, size_t *ret_secret_size); diff --git a/src/tpm2-setup/meson.build b/src/tpm2-setup/meson.build new file mode 100644 index 00000000000..c85721c98ee --- /dev/null +++ b/src/tpm2-setup/meson.build @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +executables += [ + libexec_template + { + 'name' : 'systemd-tpm2-setup', + 'sources' : files('tpm2-setup.c'), + 'conditions' : [ + 'ENABLE_BOOTLOADER', + 'HAVE_OPENSSL', + 'HAVE_TPM2', + ], + 'dependencies' : [ + libopenssl, + ], + }, +] diff --git a/src/tpm2-setup/tpm2-setup.c b/src/tpm2-setup/tpm2-setup.c new file mode 100644 index 00000000000..b88e7ec82f7 --- /dev/null +++ b/src/tpm2-setup/tpm2-setup.c @@ -0,0 +1,327 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include + +#include "build.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hexdecoct.h" +#include "main-func.h" +#include "mkdir.h" +#include "parse-util.h" +#include "pretty-print.h" +#include "terminal-util.h" +#include "tmpfile-util.h" +#include "tpm2-util.h" + +static char *arg_tpm2_device = NULL; +static bool arg_early = false; + +STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep); + +#define TPM2_SRK_PEM_PERSISTENT_PATH "/var/lib/systemd/tpm2-srk-public-key.pem" +#define TPM2_SRK_PEM_RUNTIME_PATH "/run/systemd/tpm2-srk-public-key.pem" + +static int help(int argc, char *argv[], void *userdata) { + _cleanup_free_ char *link = NULL; + int r; + + r = terminal_urlify_man("systemd-tpm2-setup", "8", &link); + if (r < 0) + return log_oom(); + + printf("%1$s [OPTIONS...] COMMAND\n" + "\n%5$sSet up the TPM2 Storage Root Key (SRK).%6$s\n" + "\n%3$sOptions:%4$s\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --tpm2-device=PATH\n" + " Pick TPM2 device\n" + " --early=BOOL Store SRK public key in /run/ rather than /var/lib/\n" + "\nSee the %2$s for details.\n", + program_invocation_short_name, + link, + ansi_underline(), + ansi_normal(), + ansi_highlight(), + ansi_normal()); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + enum { + ARG_VERSION = 0x100, + ARG_TPM2_DEVICE, + ARG_EARLY, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE }, + { "early", required_argument, NULL, ARG_EARLY }, + }; + + int c, r; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) + switch (c) { + + case 'h': + return help(0, NULL, NULL); + + case ARG_VERSION: + return version(); + + case ARG_TPM2_DEVICE: + if (streq(optarg, "list")) + return tpm2_list_devices(); + + if (free_and_strdup(&arg_tpm2_device, streq(optarg, "auto") ? NULL : optarg) < 0) + return log_oom(); + + break; + + case ARG_EARLY: + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse --early= argument: %s", optarg); + + arg_early = r; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached(); + } + + if (optind != argc) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program expects no argument."); + + return 1; +} + +struct public_key_data { + EVP_PKEY *pkey; + void *fingerprint; + size_t fingerprint_size; + char *fingerprint_hex; + char *path; +}; + +static void public_key_data_done(struct public_key_data *d) { + assert(d); + + if (d->pkey) { + EVP_PKEY_free(d->pkey); + d->pkey = NULL; + } + d->fingerprint = mfree(d->fingerprint); + d->fingerprint_size = 0; + d->fingerprint_hex = mfree(d->fingerprint_hex); + d->path = mfree(d->path); +} + +static int public_key_make_fingerprint(struct public_key_data *d) { + int r; + + assert(d); + assert(d->pkey); + assert(!d->fingerprint); + assert(!d->fingerprint_hex); + + r = pubkey_fingerprint(d->pkey, EVP_sha256(), &d->fingerprint, &d->fingerprint_size); + if (r < 0) + return log_error_errno(r, "Failed to calculate fingerprint of public key: %m"); + + d->fingerprint_hex = hexmem(d->fingerprint, d->fingerprint_size); + if (!d->fingerprint_hex) + return log_oom(); + + return 0; +} + +static int load_public_key_disk(const char *path, struct public_key_data *ret) { + _cleanup_(public_key_data_done) struct public_key_data data = {}; + _cleanup_free_ char *blob = NULL; + size_t blob_size; + int r; + + assert(path); + assert(ret); + + r = read_full_file(path, &blob, &blob_size); + if (r < 0) { + if (r != -ENOENT) + return log_error_errno(r, "Failed to read '%s': %m", path); + + log_debug("SRK public key file '%s' does not exist.", path); + } else { + log_debug("Loaded SRK public key from '%s'.", path); + + r = openssl_pkey_from_pem(blob, blob_size, &data.pkey); + if (r < 0) + return log_error_errno(r, "Failed to parse SRK public key file '%s': %m", path); + + r = public_key_make_fingerprint(&data); + if (r < 0) + return r; + + log_debug("Loaded SRK public key fingerprint: %s", data.fingerprint_hex); + } + + data.path = strdup(path); + if (!data.path) + return log_oom(); + + *ret = data; + data = (struct public_key_data) {}; + + return 0; +} + +static int load_public_key_tpm2(struct public_key_data *ret) { + _cleanup_(public_key_data_done) struct public_key_data data = {}; + _cleanup_(tpm2_context_unrefp) Tpm2Context *c = NULL; + _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL; + int r; + + assert(ret); + + r = tpm2_context_new(arg_tpm2_device, &c); + if (r < 0) + return r; + + r = tpm2_get_or_create_srk( + c, + /* session= */ NULL, + &public, + /* ret_name= */ NULL, + /* ret_qname= */ NULL, + NULL); + if (r < 0) + return r; + if (r > 0) + log_info("New SRK generated and stored in the TPM."); + else + log_info("SRK already stored in the TPM."); + + r = tpm2_tpm2b_public_to_openssl_pkey(public, &data.pkey); + if (r < 0) + return log_error_errno(r, "Failed to convert TPM2 SRK public key to OpenSSL public key: %m"); + + r = public_key_make_fingerprint(&data); + if (r < 0) + return r; + + log_info("SRK fingerprint is %s.", data.fingerprint_hex); + + *ret = data; + data = (struct public_key_data) {}; + + return 0; +} + +static int run(int argc, char *argv[]) { + int r; + + log_setup(); + + r = parse_argv(argc, argv); + if (r <= 0) + return r; + + umask(0022); + + _cleanup_(public_key_data_done) struct public_key_data runtime_key = {}, persistent_key = {}, tpm2_key = {}; + + r = load_public_key_disk(TPM2_SRK_PEM_RUNTIME_PATH, &runtime_key); + if (r < 0) + return r; + + if (!arg_early) { + r = load_public_key_disk(TPM2_SRK_PEM_PERSISTENT_PATH, &persistent_key); + if (r < 0) + return r; + + if (runtime_key.pkey && persistent_key.pkey && + memcmp_nn(runtime_key.fingerprint, runtime_key.fingerprint_size, + persistent_key.fingerprint, persistent_key.fingerprint_size) != 0) { + + /* One of those days we might want to add a stricter policy option here, that refuses + * to boot when the SRK changes. For now, let's just warn and proceed, in order not + * to break OS images that are moved around PCs. */ + + log_notice("Saved persistent SRK (%s) and runtime SRK differ (fingerprint %s vs. %s), updating persistent SRK.", + persistent_key.path, persistent_key.fingerprint_hex, runtime_key.fingerprint_hex); + + public_key_data_done(&persistent_key); + } + } + + r = load_public_key_tpm2(&tpm2_key); + if (r < 0) + return r; + + assert(tpm2_key.pkey); + + if (runtime_key.pkey) { + if (memcmp_nn(tpm2_key.fingerprint, tpm2_key.fingerprint_size, + runtime_key.fingerprint, runtime_key.fingerprint_size) != 0) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Saved runtime SRK differs from TPM SRK, refusing."); + + if (arg_early) { + log_info("SRK saved in '%s' matches SRK in TPM2.", runtime_key.path); + return 0; + } + } + + if (persistent_key.pkey) { + if (memcmp_nn(tpm2_key.fingerprint, tpm2_key.fingerprint_size, + persistent_key.fingerprint, persistent_key.fingerprint_size) == 0) { + log_info("SRK saved in '%s' matches SRK in TPM2.", persistent_key.path); + return 0; + } + + /* As above, we probably want a stricter policy option here, one day. */ + + log_notice("Saved persistent SRK (%s) and TPM SRK differ (fingerprint %s vs. %s), updating persistent SRK.", + persistent_key.path, persistent_key.fingerprint_hex, tpm2_key.fingerprint_hex); + + public_key_data_done(&persistent_key); + } + + const char *path = arg_early ? TPM2_SRK_PEM_RUNTIME_PATH : TPM2_SRK_PEM_PERSISTENT_PATH; + + (void) mkdir_parents(path, 0755); + + /* Write out public key (note that we only do that as a help to the user, we don't make use of this ever */ + _cleanup_(unlink_and_freep) char *t = NULL; + _cleanup_fclose_ FILE *f = NULL; + r = fopen_tmpfile_linkable(path, O_WRONLY, &t, &f); + if (r < 0) + return log_error_errno(r, "Failed to open SRK public key file '%s' for writing: %m", path); + + if (PEM_write_PUBKEY(f, tpm2_key.pkey) <= 0) + return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write SRK public key file '%s'.", path); + + if (fchmod(fileno(f), 0444) < 0) + return log_error_errno(errno, "Failed to adjust access mode of SRK public key file '%s' to 0444: %m", path); + + r = flink_tmpfile(f, t, path, LINK_TMPFILE_SYNC|LINK_TMPFILE_REPLACE); + if (r < 0) + return log_error_errno(r, "Failed to move SRK public key file to '%s': %m", path); + + log_info("SRK public key saved to '%s'.", path); + return 0; +} + +DEFINE_MAIN_FUNCTION(run); diff --git a/test/units/testsuite-70.sh b/test/units/testsuite-70.sh index 7f7183da08b..8358c48434a 100755 --- a/test/units/testsuite-70.sh +++ b/test/units/testsuite-70.sh @@ -5,6 +5,7 @@ set -o pipefail SD_MEASURE="/usr/lib/systemd/systemd-measure" SD_PCREXTEND="/usr/lib/systemd/systemd-pcrextend" +SD_TPM2SETUP="/usr/lib/systemd/systemd-tpm2-setup" export SYSTEMD_LOG_LEVEL=debug cryptsetup_has_token_plugin_support() { @@ -372,4 +373,12 @@ systemd-cryptenroll --tpm2-pcrs=boot-loader-code+boot-loader-config "$img" (! systemd-cryptenroll --wipe-slot=10240000 "$img") (! systemd-cryptenroll --fido2-device=auto --unlock-fido2-device=auto "$img") +# Run this, just to get sanitizer coverage. The tools should be idempotent, hence run the multiple times. +if [[ -x "$SD_TPM2SETUP" ]]; then + "$SD_TPM2SETUP" --early=yes + "$SD_TPM2SETUP" --early=yes + "$SD_TPM2SETUP" --early=no + "$SD_TPM2SETUP" --early=no +fi + touch /testok diff --git a/units/meson.build b/units/meson.build index 2fb87934b81..e1de2b4a6da 100644 --- a/units/meson.build +++ b/units/meson.build @@ -458,6 +458,16 @@ units = [ 'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_OPENSSL', 'HAVE_TPM2'], 'symlinks' : ['sysinit.target.wants/'], }, + { + 'file' : 'systemd-tpm2-setup.service.in', + 'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_OPENSSL', 'HAVE_TPM2'], + 'symlinks' : ['sysinit.target.wants/'], + }, + { + 'file' : 'systemd-tpm2-setup-early.service.in', + 'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_OPENSSL', 'HAVE_TPM2'], + 'symlinks' : ['sysinit.target.wants/'], + }, { 'file' : 'systemd-portabled.service.in', 'conditions' : ['ENABLE_PORTABLED'], diff --git a/units/systemd-tpm2-setup-early.service.in b/units/systemd-tpm2-setup-early.service.in new file mode 100644 index 00000000000..c1597ea3f9f --- /dev/null +++ b/units/systemd-tpm2-setup-early.service.in @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=TPM2 SRK Setup (Early) +Documentation=man:systemd-tpm2-setup.service(8) +DefaultDependencies=no +Conflicts=shutdown.target +Before=sysinit.target shutdown.target +ConditionSecurity=measured-uki +ConditionPathExists=!/run/systemd/tpm2-srk-public-key.pem + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart={{LIBEXECDIR}}/systemd-tpm2-setup --early=yes diff --git a/units/systemd-tpm2-setup.service.in b/units/systemd-tpm2-setup.service.in new file mode 100644 index 00000000000..6c99f3af0a6 --- /dev/null +++ b/units/systemd-tpm2-setup.service.in @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=TPM2 SRK Setup +Documentation=man:systemd-tpm2-setup.service(8) +DefaultDependencies=no +Conflicts=shutdown.target +After=systemd-tpm2-setup-early.service systemd-remount-fs.service +Before=sysinit.target shutdown.target +RequiresMountsFor=/var/lib/systemd/tpm2-srk-public-key.pem +ConditionSecurity=measured-uki +ConditionPathExists=!/etc/initrd-release + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart={{LIBEXECDIR}}/systemd-tpm2-setup From 1a9454a9420c7835fc8ee3508906b98d92f16f11 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 27 Sep 2023 09:33:48 +0200 Subject: [PATCH 2/2] update TODO --- TODO | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/TODO b/TODO index b084518aae1..408b799a2d6 100644 --- a/TODO +++ b/TODO @@ -186,6 +186,14 @@ Features: AllowPeerUser= + AllowPeerGroup= to allow trivially simple access control when invoked via socket as IPC services +* systemd-tpm2-setup should probably have a factory reset logic, i.e. when some + kernel command line option is set we reset the TPM (equivalent of tpm2_clear + -c owner?). + +* systemd-tpm2-setup should support a mode where we refuse booting if the SRK + changed. (Must be opt-in, to not break systems which are supposed to be + migratable between PCs) + * when systemd-sysext learns mutable /usr/ (and systemd-confext mutable /etc/) then allow them to store the result in a .v/ versioned subdir, for some basic snapshot logic