tpm2: make SRK easily accessible for use with systemd-cryptenroll --tpm2-device-key=
<arg choice="plain">pcrs</arg>
<arg choice="opt" rep="repeat"><replaceable>PCR</replaceable></arg>
</cmdsynopsis>
+ <cmdsynopsis>
+ <command>systemd-analyze</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ <arg choice="plain">srk</arg> ><arg choice="plain"><replaceable>FILE</replaceable></arg>
+ </cmdsynopsis>
</refsynopsisdiv>
<refsect1>
23 application-support 0000000000000000000000000000000000000000000000000000000000000000</programlisting>
</example>
</refsect2>
+
+ <refsect2>
+ <title><command>systemd-analyze srk > <replaceable>FILE</replaceable></command></title>
+
+ <para>This command reads the Storage Root Key (SRK) from the TPM2 device, and writes it in marshalled
+ TPM2B_PUBLIC format to stdout. Example:</para>
+
+ <programlisting>systemd-analyze srk > srk.tpm2b_public</programlisting>
+ </refsect2>
+
</refsect1>
<refsect1>
enrollment is calculated using the provided TPM2 key. This is useful in situations where the TPM2
security chip is not available at the time of enrollment.</para>
- <para>The key, in most cases, should be the Storage Root Key (SRK) from the TPM2 security chip. If a
- key from a different handle (not the SRK) is used, you must specify its handle index using
+ <para>The key, in most cases, should be the Storage Root Key (SRK) from a local TPM2 security
+ chip. If a key from a different handle (not the SRK) is used, you must specify its handle index using
<option>--tpm2-seal-key-handle=</option>.</para>
- <para>You may use tpm2-tss tools to get the SRK from the TPM2 security chip with <citerefentry
- project='mankier'><refentrytitle>tpm2_readpublic</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- for example:</para>
+ <para>The
+ <citerefentry><refentrytitle>systemd-tpm2-setup.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ service writes the SRK to <filename>/run/systemd/tpm2-srk-public-key.tpm2b_public</filename>
+ automatically during boot, in the correct format.</para>
- <programlisting>tpm2_readpublic -c 0x81000001 -o srk.pub</programlisting>
+ <para>Alternatively, you may use <command>systemd-analyze srk</command> to retrieve the SRK from the
+ TPM2 security chip explicitly. See
+ <citerefentry><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ for details. Example:</para>
+
+ <programlisting>systemd-analyze srk > srk.tpm2b_public</programlisting>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
</varlistentry>
<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>
+ <filename>/var/lib/systemd/tpm2-srk-public-key.pem</filename>. It will also store it in TPM2B_PUBLIC
+ format in <filename>/run/systemd/tpm2-srk-public-key.tpm2_public</filename> and
+ <filename>/var/lib/systemd/tpm2-srk-public-key.tpm2b_public</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
+ initrd), and writes the SRK public key to <filename>/run/systemd/tpm2-srk-public-key.*</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>
+ to <filename>/var/lib/systemd/tpm2-srk-public-key.*</filename>.</para>
</refsect1>
<refsect1>
<variablelist>
<varlistentry>
<term><filename>/run/systemd/tpm2-srk-public-key.pem</filename></term>
+ <term><filename>/run/systemd/tpm2-srk-public-key.tpm2b_public</filename></term>
- <listitem><para>The SRK public key in PEM format, written during early boot.</para>
+ <listitem><para>The SRK public key in PEM and TPM2B_PUBLIC format, written during early boot.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
</varlistentry>
<varlistentry>
<term><filename>/var/lib/systemd/tpm2-srk-public-key.pem</filename></term>
+ <term><filename>/var/lib/systemd/tpm2-srk-public-key.tpm2_public</filename></term>
- <listitem><para>The SRK public key in PEM format, written during later boot (once
+ <listitem><para>The SRK public key in PEM and TPM2B_PUBLIC format, written during later boot (once
<filename>/var/</filename> is available).</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "analyze.h"
+#include "analyze-srk.h"
+#include "tpm2-util.h"
+
+int verb_srk(int argc, char *argv[], void *userdata) {
+#if HAVE_TPM2
+ _cleanup_(tpm2_context_unrefp) Tpm2Context *c = NULL;
+ _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
+ int r;
+
+ r = tpm2_context_new(/* device= */ NULL, &c);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create TPM2 context: %m");
+
+ r = tpm2_get_srk(
+ c,
+ /* session= */ NULL,
+ &public,
+ /* ret_name= */ NULL,
+ /* ret_qname= */ NULL,
+ /* ret_handle= */ NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get SRK: %m");
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "No SRK stored so far.");
+
+ _cleanup_free_ void *marshalled = NULL;
+ size_t marshalled_size = 0;
+ r = tpm2_marshal_public(public, &marshalled, &marshalled_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to marshal SRK: %m");
+
+ if (isatty(STDOUT_FILENO))
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Refusing to write binary data to TTY, please redirect output to file.");
+
+ if (fwrite(marshalled, 1, marshalled_size, stdout) != marshalled_size)
+ return log_error_errno(errno, "Failed to write SRK to stdout: %m");
+
+ fflush(stdout);
+
+ return EXIT_SUCCESS;
+#else
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM2 support not available.");
+#endif
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+int verb_srk(int argc, char *argv[], void *userdata);
#include "analyze-plot.h"
#include "analyze-security.h"
#include "analyze-service-watchdogs.h"
+#include "analyze-srk.h"
#include "analyze-syscall-filter.h"
#include "analyze-time.h"
#include "analyze-time-data.h"
" malloc [D-BUS SERVICE...] Dump malloc stats of a D-Bus service\n"
" fdstore SERVICE... Show file descriptor store contents of service\n"
" pcrs [PCR...] Show TPM2 PCRs and their names\n"
+ " srk > FILE Write TPM2 SRK to stdout\n"
"\nOptions:\n"
" --recursive-errors=MODE Control which units are verified\n"
" --offline=BOOL Perform a security review on unit file(s)\n"
{ "fdstore", 2, VERB_ANY, 0, verb_fdstore },
{ "image-policy", 2, 2, 0, verb_image_policy },
{ "pcrs", VERB_ANY, VERB_ANY, 0, verb_pcrs },
+ { "srk", VERB_ANY, 1, 0, verb_srk },
{}
};
'analyze-plot.c',
'analyze-security.c',
'analyze-service-watchdogs.c',
+ 'analyze-srk.c',
'analyze-syscall-filter.c',
'analyze-time.c',
'analyze-time-data.c',
return 0;
}
-static int tpm2_marshal_public(const TPM2B_PUBLIC *public, void **ret, size_t *ret_size) {
+int tpm2_marshal_public(const TPM2B_PUBLIC *public, void **ret, size_t *ret_size) {
size_t max_size = sizeof(*public), blob_size = 0;
_cleanup_free_ void *blob = NULL;
TSS2_RC rc;
int tpm2_create(Tpm2Context *c, const Tpm2Handle *parent, const Tpm2Handle *session, const TPMT_PUBLIC *template, const TPMS_SENSITIVE_CREATE *sensitive, TPM2B_PUBLIC **ret_public, TPM2B_PRIVATE **ret_private);
int tpm2_create_loaded(Tpm2Context *c, const Tpm2Handle *parent, const Tpm2Handle *session, const TPMT_PUBLIC *template, const TPMS_SENSITIVE_CREATE *sensitive, TPM2B_PUBLIC **ret_public, TPM2B_PRIVATE **ret_private, Tpm2Handle **ret_handle);
int tpm2_load(Tpm2Context *c, const Tpm2Handle *parent, const Tpm2Handle *session, const TPM2B_PUBLIC *public, const TPM2B_PRIVATE *private, Tpm2Handle **ret_handle);
+int tpm2_marshal_public(const TPM2B_PUBLIC *public, void **ret, size_t *ret_size);
int tpm2_marshal_nv_public(const TPM2B_NV_PUBLIC *nv_public, void **ret, size_t *ret_size);
int tpm2_unmarshal_nv_public(const void *data, size_t size, TPM2B_NV_PUBLIC *ret_nv_public);
int tpm2_marshal_blob(const TPM2B_PUBLIC *public, const TPM2B_PRIVATE *private, const TPM2B_ENCRYPTED_SECRET *seed, void **ret_blob, size_t *ret_blob_size);
#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"
+#define TPM2_SRK_TPM2B_PUBLIC_PERSISTENT_PATH "/var/lib/systemd/tpm2-srk-public-key.tpm2b_public"
+#define TPM2_SRK_TPM2B_PUBLIC_RUNTIME_PATH "/run/systemd/tpm2-srk-public-key.tpm2b_public"
+
static int help(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *link = NULL;
int r;
}
struct public_key_data {
- EVP_PKEY *pkey;
+ EVP_PKEY *pkey; /* as OpenSSL object */
+ TPM2B_PUBLIC *public; /* in TPM2 format */
void *fingerprint;
size_t fingerprint_size;
char *fingerprint_hex;
EVP_PKEY_free(d->pkey);
d->pkey = NULL;
}
+ if (d->public) {
+ Esys_Freep(&d->public);
+ d->public = NULL;
+ }
d->fingerprint = mfree(d->fingerprint);
d->fingerprint_size = 0;
d->fingerprint_hex = mfree(d->fingerprint_hex);
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_get_or_create_srk(
c,
/* session= */ NULL,
- &public,
+ &data.public,
/* ret_name= */ NULL,
/* ret_qname= */ NULL,
NULL);
else
log_info("SRK already stored in the TPM.");
- r = tpm2_tpm2b_public_to_openssl_pkey(public, &data.pkey);
+ r = tpm2_tpm2b_public_to_openssl_pkey(data.public, &data.pkey);
if (r < 0)
return log_error_errno(r, "Failed to convert TPM2 SRK public key to OpenSSL public key: %m");
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);
+ const char *pem_path = arg_early ? TPM2_SRK_PEM_RUNTIME_PATH : TPM2_SRK_PEM_PERSISTENT_PATH;
+ (void) mkdir_parents(pem_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);
+ r = fopen_tmpfile_linkable(pem_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);
+ return log_error_errno(r, "Failed to open SRK public key file '%s' for writing: %m", pem_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);
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write SRK public key file '%s'.", pem_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);
+ return log_error_errno(errno, "Failed to adjust access mode of SRK public key file '%s' to 0444: %m", pem_path);
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to sync SRK key to disk: %m");
+
+ r = flink_tmpfile(f, t, pem_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", pem_path);
+
+ f = safe_fclose(f);
+ t = mfree(t);
+
+ log_info("SRK public key saved to '%s' in PEM format.", pem_path);
+
+ const char *tpm2b_public_path = arg_early ? TPM2_SRK_TPM2B_PUBLIC_RUNTIME_PATH : TPM2_SRK_TPM2B_PUBLIC_PERSISTENT_PATH;
+ (void) mkdir_parents(tpm2b_public_path, 0755);
+
+ /* Now also write this out in TPM2B_PUBLIC format */
+ r = fopen_tmpfile_linkable(tpm2b_public_path, O_WRONLY, &t, &f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to open SRK public key file '%s' for writing: %m", tpm2b_public_path);
+
+ _cleanup_free_ void *marshalled = NULL;
+ size_t marshalled_size = 0;
+ r = tpm2_marshal_public(tpm2_key.public, &marshalled, &marshalled_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to marshal TPM2_PUBLIC key.");
+
+ if (fwrite(marshalled, 1, marshalled_size, f) != marshalled_size)
+ return log_error_errno(errno, "Failed to write SRK public key file '%s'.", tpm2b_public_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", tpm2b_public_path);
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to sync SRK key to disk: %m");
- r = flink_tmpfile(f, t, path, LINK_TMPFILE_SYNC|LINK_TMPFILE_REPLACE);
+ r = flink_tmpfile(f, t, tpm2b_public_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);
+ return log_error_errno(r, "Failed to move SRK public key file to '%s': %m", tpm2b_public_path);
- log_info("SRK public key saved to '%s'.", path);
+ log_info("SRK public key saved to '%s' in TPM2B_PUBLIC format.", tpm2b_public_path);
return 0;
}
tpm2_pcrread -Q -o /tmp/pcr.dat sha256:12
CURRENT_PCR_VALUE=$(cat /sys/class/tpm/tpm0/pcr-sha256/12)
tpm2_readpublic -c 0x81000001 -o /tmp/srk.pub
+ systemd-analyze srk > /tmp/srk2.pub
+ cmp /tmp/srk.pub /tmp/srk2.pub
+ if [ -f /run/systemd/tpm2-srk-public-key.tpm2b_public ] ; then
+ cmp /tmp/srk.pub /run/systemd/tpm2-srk-public-key.tpm2b_public
+ fi
+
PASSWORD=passphrase systemd-cryptenroll --tpm2-device-key=/tmp/srk.pub --tpm2-pcrs="12:sha256=$CURRENT_PCR_VALUE" "$IMAGE"
systemd-cryptsetup attach test-volume "$IMAGE" - tpm2-device=auto,headless=1
systemd-cryptsetup detach test-volume