mirror of
https://github.com/systemd/systemd.git
synced 2024-11-23 18:23:32 +08:00
Merge pull request #29344 from poettering/tpm2-setup
tpm2-setup: set up TPM2 Storage Root Key (SRK) in a separate service
This commit is contained in:
commit
68849251a2
8
TODO
8
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
|
||||
|
@ -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',
|
||||
|
74
man/systemd-tpm2-setup.service.xml
Normal file
74
man/systemd-tpm2-setup.service.xml
Normal file
@ -0,0 +1,74 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
<refentry id="systemd-tpm2-setup.service" conditional='ENABLE_BOOTLOADER'
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-tpm2-setup.service</title>
|
||||
<productname>systemd</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-tpm2-setup.service</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-tpm2-setup.service</refname>
|
||||
<refname>systemd-tpm2-setup-early.service</refname>
|
||||
<refname>systemd-tpm2-setup</refname>
|
||||
<refpurpose>Set up the TPM2 Storage Root Key (SRK) at boot</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>systemd-tpm2-setup.service</filename></para>
|
||||
<para><filename>/usr/lib/systemd/systemd-tpm2-setup</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><filename>systemd-tpm2-setup.service</filename> and
|
||||
<filename>systemd-tpm2-setup-early.service</filename> are services that generate the Storage Root Key
|
||||
(SRK) if it hasn't been generated yet, and stores it in the TPM.</para>
|
||||
|
||||
<para>The services will store the public key of the SRK key pair in a PEM file in
|
||||
<filename>/run/systemd/tpm2-srk-public-key.pem</filename> and
|
||||
<filename>/var/lib/systemd/tpm2-srk-public-key.pem</filename>.</para>
|
||||
|
||||
<para><filename>systemd-tpm2-setup-early.service</filename> runs very early at boot (possibly in the
|
||||
initrd), and writes the SRK public key to <filename>/run/systemd/tpm2-srk-public-key.pem</filename> (as
|
||||
<filename>/var/</filename> is generally not accessible this early yet), while
|
||||
<filename>systemd-tpm2-setup.service</filename> runs during a later boot phase and saves the public key
|
||||
to <filename>/var/lib/systemd/tpm2-srk-public-key.pem</filename>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Files</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><filename>/run/systemd/tpm2-srk-public-key.pem</filename></term>
|
||||
|
||||
<listitem><para>The SRK public key in PEM format, written during early boot.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><filename>/var/lib/systemd/tpm2-srk-public-key.pem</filename></term>
|
||||
|
||||
<listitem><para>The SRK public key in PEM format, written during later boot (once
|
||||
<filename>/var/</filename> is available).</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
@ -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')
|
||||
|
@ -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");
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
||||
|
16
src/tpm2-setup/meson.build
Normal file
16
src/tpm2-setup/meson.build
Normal file
@ -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,
|
||||
],
|
||||
},
|
||||
]
|
327
src/tpm2-setup/tpm2-setup.c
Normal file
327
src/tpm2-setup/tpm2-setup.c
Normal file
@ -0,0 +1,327 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <getopt.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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);
|
@ -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
|
||||
|
@ -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'],
|
||||
|
22
units/systemd-tpm2-setup-early.service.in
Normal file
22
units/systemd-tpm2-setup-early.service.in
Normal file
@ -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
|
24
units/systemd-tpm2-setup.service.in
Normal file
24
units/systemd-tpm2-setup.service.in
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user