]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #29947 from poettering/srk-beefup
authorLuca Boccassi <bluca@debian.org>
Fri, 10 Nov 2023 16:47:46 +0000 (16:47 +0000)
committerGitHub <noreply@github.com>
Fri, 10 Nov 2023 16:47:46 +0000 (16:47 +0000)
tpm2: make SRK easily accessible for use with systemd-cryptenroll --tpm2-device-key=

man/systemd-analyze.xml
man/systemd-cryptenroll.xml
man/systemd-tpm2-setup.service.xml
src/analyze/analyze-srk.c [new file with mode: 0644]
src/analyze/analyze-srk.h [new file with mode: 0644]
src/analyze/analyze.c
src/analyze/meson.build
src/shared/tpm2-util.c
src/shared/tpm2-util.h
src/tpm2-setup/tpm2-setup.c
test/units/testsuite-70.cryptsetup.sh

index 1aaf03ac529009df74e087c50da8e19419f8bdd1..2f2873452ac2ab1ef804c7c816e50d27e019581d 100644 (file)
       <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> &gt;<arg choice="plain"><replaceable>FILE</replaceable></arg>
+    </cmdsynopsis>
   </refsynopsisdiv>
 
   <refsect1>
@@ -926,6 +931,16 @@ NR NAME                SHA256
 23 application-support 0000000000000000000000000000000000000000000000000000000000000000</programlisting>
       </example>
     </refsect2>
+
+    <refsect2>
+      <title><command>systemd-analyze srk &gt; <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 &gt; srk.tpm2b_public</programlisting>
+    </refsect2>
+
   </refsect1>
 
   <refsect1>
index b40d20223396b84766817cc1896d73b1e4a244fd..8fd885cb26427721ee8446d8e11b370e4d38f014 100644 (file)
         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 &gt; srk.tpm2b_public</programlisting>
 
         <xi:include href="version-info.xml" xpointer="v255"/></listitem>
       </varlistentry>
index c20fb1a14088330746c99ed11ac26e6262eb05ff..8c138950c769230404a8b3c431678cef34e5b09c 100644 (file)
 
     <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>
diff --git a/src/analyze/analyze-srk.c b/src/analyze/analyze-srk.c
new file mode 100644 (file)
index 0000000..3138246
--- /dev/null
@@ -0,0 +1,47 @@
+/* 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
+}
diff --git a/src/analyze/analyze-srk.h b/src/analyze/analyze-srk.h
new file mode 100644 (file)
index 0000000..2602835
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+int verb_srk(int argc, char *argv[], void *userdata);
index 1b96e8b69a4b6d22a6067196c0c7744888f82b27..d2be144f4f493061f36d79498e5f1fdf2c1ddecc 100644 (file)
@@ -32,6 +32,7 @@
 #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"
@@ -236,6 +237,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "  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"
@@ -646,6 +648,7 @@ static int run(int argc, char *argv[]) {
                 { "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               },
                 {}
         };
 
index 1a9b68f6d2a9fa22d7eadfdfdd3bd972c46595c9..a50544730b1668d1e6fa004bd0f42db629a415e8 100644 (file)
@@ -21,6 +21,7 @@ systemd_analyze_sources = files(
         'analyze-plot.c',
         'analyze-security.c',
         'analyze-service-watchdogs.c',
+        'analyze-srk.c',
         'analyze-syscall-filter.c',
         'analyze-time.c',
         'analyze-time-data.c',
index f3712c84962ab47f8701e60f9582601707f3938f..dcf26a6c035288ff28a05f06c17a5d8bd0dcb5c9 100644 (file)
@@ -2413,7 +2413,7 @@ static int tpm2_unmarshal_private(const void *data, size_t size, TPM2B_PRIVATE *
         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;
index e867976369efe32070ec385c71edc0d4ed43f129..505e0a822632002940255204b41935fc154e9eb3 100644 (file)
@@ -126,6 +126,7 @@ int tpm2_create_primary(Tpm2Context *c, const Tpm2Handle *session, const TPM2B_P
 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);
index 2f23fb162deca99db2d39c0a0aaa0cf86480f649..be34d166d7ae048d5effed8b305b451f4bf0ca1a 100644 (file)
@@ -24,6 +24,9 @@ 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"
 
+#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;
@@ -111,7 +114,8 @@ static int parse_argv(int argc, char *argv[]) {
 }
 
 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;
@@ -125,6 +129,10 @@ static void public_key_data_done(struct public_key_data *d) {
                 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);
@@ -192,7 +200,6 @@ static int load_public_key_disk(const char *path, struct public_key_data *ret) {
 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);
@@ -204,7 +211,7 @@ static int load_public_key_tpm2(struct public_key_data *ret) {
         r = tpm2_get_or_create_srk(
                         c,
                         /* session= */ NULL,
-                        &public,
+                        &data.public,
                         /* ret_name= */ NULL,
                         /* ret_qname= */ NULL,
                         NULL);
@@ -215,7 +222,7 @@ static int load_public_key_tpm2(struct public_key_data *ret) {
         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");
 
@@ -300,28 +307,64 @@ static int run(int argc, char *argv[]) {
                 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;
 }
 
index a1c6035e45b054e0f434b6bcc82dd8687134d9dd..1db425dfe8dfb5e5c14c319b65bb772064f2fc8c 100755 (executable)
@@ -135,6 +135,12 @@ if tpm_has_pcr sha256 12; then
     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